Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 106 additions & 13 deletions tools/bpf/bpftool/btf_dumper.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <linux/err.h>
#include <bpf/btf.h>
#include <bpf/bpf.h>
#include <errno.h>
#include <arpa/inet.h>

#include "json_writer.h"
#include "main.h"
Expand Down Expand Up @@ -132,18 +134,6 @@ static void btf_dumper_ptr(const struct btf_dumper *d,
jsonw_printf(d->jw, "%lu", value);
}

static int btf_dumper_modifier(const struct btf_dumper *d, __u32 type_id,
__u8 bit_offset, const void *data)
{
int actual_type_id;

actual_type_id = btf__resolve_type(d->btf, type_id);
if (actual_type_id < 0)
return actual_type_id;

return btf_dumper_do_type(d, actual_type_id, bit_offset, data);
}

static int btf_dumper_enum(const struct btf_dumper *d,
const struct btf_type *t,
const void *data)
Expand Down Expand Up @@ -556,6 +546,36 @@ static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
__u8 bit_offset, const void *data)
{
const struct btf_type *t = btf__type_by_id(d->btf, type_id);
char addr[INET6_ADDRSTRLEN];

if (!t)
return -errno;

switch ((bit_offset == 0 && d->fmt_tags) ? d->fmt_tags[type_id] :
BTF_FMT_DEFAULT) {
case BTF_FMT_BE16:
jsonw_printf(d->jw, "\"%d\"",
be16_to_cpu(*(const __be16 *)data));
return 0;
case BTF_FMT_BE32:
jsonw_printf(d->jw, "\"%u\"",
be32_to_cpu(*(const __be32 *)data));
return 0;
case BTF_FMT_BE64:
jsonw_printf(d->jw, "\"%lu\"",
be64_to_cpu(*(const __be64 *)data));
return 0;
case BTF_FMT_IP4:
jsonw_string(d->jw,
inet_ntop(AF_INET, data, addr, sizeof(addr)));
return 0;
case BTF_FMT_IP6:
jsonw_string(d->jw,
inet_ntop(AF_INET6, data, addr, sizeof(addr)));
return 0;
default:
break;
}

switch (BTF_INFO_KIND(t->info)) {
case BTF_KIND_INT:
Expand Down Expand Up @@ -584,7 +604,7 @@ static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
case BTF_KIND_VOLATILE:
case BTF_KIND_CONST:
case BTF_KIND_RESTRICT:
return btf_dumper_modifier(d, type_id, bit_offset, data);
return btf_dumper_do_type(d, t->type, bit_offset, data);
case BTF_KIND_VAR:
return btf_dumper_var(d, type_id, bit_offset, data);
case BTF_KIND_DATASEC:
Expand All @@ -595,6 +615,79 @@ static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
}
}

enum btf_fmt_tag *btf_fmt_tags_get(const struct btf *btf)
{
int n = btf__type_cnt(btf);
enum btf_fmt_tag *tags = calloc(n, sizeof(tags[0]));

if (!tags)
return NULL;

for (int i = 1; i < n; i++) {
const struct btf_type *t = btf__type_by_id(btf, i);
const struct btf_decl_tag *tag;
const char *name;
__s64 size;

if (!t)
goto err_free;
if (btf_kind(t) != BTF_KIND_DECL_TAG)
continue;

tag = (const void *)(t + 1);
if (tag->component_idx != -1)
continue;

name = btf__name_by_offset(btf, t->name_off);
if (!name)
goto err_free;

#define BTF_FMT_TAG_PREFIX "user:fmt:"
if (strncmp(name, BTF_FMT_TAG_PREFIX,
sizeof(BTF_FMT_TAG_PREFIX) - 1))
continue;

size = btf__resolve_size(btf, t->type);
if (size < 0)
continue; // could be a forward decl

if (btf_kind(btf__type_by_id(btf, t->type)) == BTF_KIND_VAR)
continue;

name += sizeof(BTF_FMT_TAG_PREFIX) - 1;
if (!strcmp(name, "be")) {
switch (size) {
case 2:
tags[t->type] = BTF_FMT_BE16;
break;
case 4:
tags[t->type] = BTF_FMT_BE32;
break;
case 8:
tags[t->type] = BTF_FMT_BE64;
break;
default:
break;
}
} else if (!strcmp(name, "ip")) {
switch (size) {
case 4:
tags[t->type] = BTF_FMT_IP4;
break;
case 16:
tags[t->type] = BTF_FMT_IP6;
break;
default:
break;
}
}
}
return tags;
err_free:
free(tags);
return NULL;
}

int btf_dumper_type(const struct btf_dumper *d, __u32 type_id,
const void *data)
{
Expand Down
12 changes: 12 additions & 0 deletions tools/bpf/bpftool/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,20 @@ unsigned int get_possible_cpus(void);
const char *
ifindex_to_arch(__u32 ifindex, __u64 ns_dev, __u64 ns_ino, const char **opt);

enum btf_fmt_tag {
BTF_FMT_DEFAULT = 0,
BTF_FMT_BE16,
BTF_FMT_BE32,
BTF_FMT_BE64,
BTF_FMT_IP4,
BTF_FMT_IP6,
};

enum btf_fmt_tag *btf_fmt_tags_get(const struct btf *btf);

struct btf_dumper {
const struct btf *btf;
const enum btf_fmt_tag *fmt_tags;
json_writer_t *jw;
bool is_plain_text;
bool prog_id_as_func_ptr;
Expand Down
7 changes: 6 additions & 1 deletion tools/bpf/bpftool/map.c
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,7 @@ static int do_show(int argc, char **argv)

static int dump_map_elem(int fd, void *key, void *value,
struct bpf_map_info *map_info, struct btf *btf,
const enum btf_fmt_tag *fmt_tags,
json_writer_t *btf_wtr)
{
if (bpf_map_lookup_elem(fd, key, value)) {
Expand All @@ -756,6 +757,7 @@ static int dump_map_elem(int fd, void *key, void *value,
} else if (btf) {
struct btf_dumper d = {
.btf = btf,
.fmt_tags = fmt_tags,
.jw = btf_wtr,
.is_plain_text = true,
};
Expand Down Expand Up @@ -829,6 +831,7 @@ map_dump(int fd, struct bpf_map_info *info, json_writer_t *wtr,
void *key, *value, *prev_key;
unsigned int num_elems = 0;
struct btf *btf = NULL;
enum btf_fmt_tag *fmt_tags = NULL;
int err;

key = malloc(info->key_size);
Expand All @@ -846,6 +849,7 @@ map_dump(int fd, struct bpf_map_info *info, json_writer_t *wtr,
if (err) {
goto exit_free;
}
fmt_tags = btf_fmt_tags_get(btf);

if (show_header) {
jsonw_start_object(wtr); /* map object */
Expand All @@ -872,7 +876,7 @@ map_dump(int fd, struct bpf_map_info *info, json_writer_t *wtr,
err = 0;
break;
}
if (!dump_map_elem(fd, key, value, info, btf, wtr))
if (!dump_map_elem(fd, key, value, info, btf, fmt_tags, wtr))
num_elems++;
prev_key = key;
}
Expand All @@ -891,6 +895,7 @@ map_dump(int fd, struct bpf_map_info *info, json_writer_t *wtr,
free(value);
close(fd);
free_map_kv_btf(btf);
free(fmt_tags);

return err;
}
Expand Down
Loading