2019-04-26 06:30:08 +08:00
|
|
|
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
|
|
|
/* Copyright (C) 2019 Facebook */
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <linux/err.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <linux/btf.h>
|
2019-10-24 21:30:25 +08:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2019-04-26 06:30:08 +08:00
|
|
|
|
2021-10-24 04:51:53 +08:00
|
|
|
#include <bpf/bpf.h>
|
|
|
|
#include <bpf/btf.h>
|
|
|
|
#include <bpf/hashmap.h>
|
|
|
|
#include <bpf/libbpf.h>
|
|
|
|
|
2019-04-26 06:30:08 +08:00
|
|
|
#include "json_writer.h"
|
|
|
|
#include "main.h"
|
|
|
|
|
|
|
|
static const char * const btf_kind_str[NR_BTF_KINDS] = {
|
|
|
|
[BTF_KIND_UNKN] = "UNKNOWN",
|
|
|
|
[BTF_KIND_INT] = "INT",
|
|
|
|
[BTF_KIND_PTR] = "PTR",
|
|
|
|
[BTF_KIND_ARRAY] = "ARRAY",
|
|
|
|
[BTF_KIND_STRUCT] = "STRUCT",
|
|
|
|
[BTF_KIND_UNION] = "UNION",
|
|
|
|
[BTF_KIND_ENUM] = "ENUM",
|
|
|
|
[BTF_KIND_FWD] = "FWD",
|
|
|
|
[BTF_KIND_TYPEDEF] = "TYPEDEF",
|
|
|
|
[BTF_KIND_VOLATILE] = "VOLATILE",
|
|
|
|
[BTF_KIND_CONST] = "CONST",
|
|
|
|
[BTF_KIND_RESTRICT] = "RESTRICT",
|
|
|
|
[BTF_KIND_FUNC] = "FUNC",
|
|
|
|
[BTF_KIND_FUNC_PROTO] = "FUNC_PROTO",
|
|
|
|
[BTF_KIND_VAR] = "VAR",
|
|
|
|
[BTF_KIND_DATASEC] = "DATASEC",
|
2021-02-27 04:22:50 +08:00
|
|
|
[BTF_KIND_FLOAT] = "FLOAT",
|
2021-10-13 00:48:38 +08:00
|
|
|
[BTF_KIND_DECL_TAG] = "DECL_TAG",
|
2021-11-12 09:26:20 +08:00
|
|
|
[BTF_KIND_TYPE_TAG] = "TYPE_TAG",
|
2022-06-07 14:26:52 +08:00
|
|
|
[BTF_KIND_ENUM64] = "ENUM64",
|
2019-04-26 06:30:08 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static const char *btf_int_enc_str(__u8 encoding)
|
|
|
|
{
|
|
|
|
switch (encoding) {
|
|
|
|
case 0:
|
|
|
|
return "(none)";
|
|
|
|
case BTF_INT_SIGNED:
|
|
|
|
return "SIGNED";
|
|
|
|
case BTF_INT_CHAR:
|
|
|
|
return "CHAR";
|
|
|
|
case BTF_INT_BOOL:
|
|
|
|
return "BOOL";
|
|
|
|
default:
|
|
|
|
return "UNKN";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *btf_var_linkage_str(__u32 linkage)
|
|
|
|
{
|
|
|
|
switch (linkage) {
|
|
|
|
case BTF_VAR_STATIC:
|
|
|
|
return "static";
|
|
|
|
case BTF_VAR_GLOBAL_ALLOCATED:
|
2021-04-24 02:13:31 +08:00
|
|
|
return "global";
|
|
|
|
case BTF_VAR_GLOBAL_EXTERN:
|
|
|
|
return "extern";
|
2019-04-26 06:30:08 +08:00
|
|
|
default:
|
|
|
|
return "(unknown)";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-24 13:43:17 +08:00
|
|
|
static const char *btf_func_linkage_str(const struct btf_type *t)
|
|
|
|
{
|
|
|
|
switch (btf_vlen(t)) {
|
|
|
|
case BTF_FUNC_STATIC:
|
|
|
|
return "static";
|
|
|
|
case BTF_FUNC_GLOBAL:
|
|
|
|
return "global";
|
|
|
|
case BTF_FUNC_EXTERN:
|
|
|
|
return "extern";
|
|
|
|
default:
|
|
|
|
return "(unknown)";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-26 06:30:08 +08:00
|
|
|
static const char *btf_str(const struct btf *btf, __u32 off)
|
|
|
|
{
|
|
|
|
if (!off)
|
|
|
|
return "(anon)";
|
|
|
|
return btf__name_by_offset(btf, off) ? : "(invalid)";
|
|
|
|
}
|
|
|
|
|
2021-04-24 02:13:32 +08:00
|
|
|
static int btf_kind_safe(int kind)
|
|
|
|
{
|
|
|
|
return kind <= BTF_KIND_MAX ? kind : BTF_KIND_UNKN;
|
|
|
|
}
|
|
|
|
|
2019-04-26 06:30:08 +08:00
|
|
|
static int dump_btf_type(const struct btf *btf, __u32 id,
|
|
|
|
const struct btf_type *t)
|
|
|
|
{
|
|
|
|
json_writer_t *w = json_wtr;
|
2021-04-24 02:13:32 +08:00
|
|
|
int kind = btf_kind(t);
|
2019-04-26 06:30:08 +08:00
|
|
|
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_start_object(w);
|
|
|
|
jsonw_uint_field(w, "id", id);
|
2021-04-24 02:13:32 +08:00
|
|
|
jsonw_string_field(w, "kind", btf_kind_str[btf_kind_safe(kind)]);
|
2019-04-26 06:30:08 +08:00
|
|
|
jsonw_string_field(w, "name", btf_str(btf, t->name_off));
|
|
|
|
} else {
|
2021-04-24 02:13:32 +08:00
|
|
|
printf("[%u] %s '%s'", id, btf_kind_str[btf_kind_safe(kind)],
|
2019-04-26 06:30:08 +08:00
|
|
|
btf_str(btf, t->name_off));
|
|
|
|
}
|
|
|
|
|
2021-04-24 02:13:32 +08:00
|
|
|
switch (kind) {
|
2019-04-26 06:30:08 +08:00
|
|
|
case BTF_KIND_INT: {
|
|
|
|
__u32 v = *(__u32 *)(t + 1);
|
|
|
|
const char *enc;
|
|
|
|
|
|
|
|
enc = btf_int_enc_str(BTF_INT_ENCODING(v));
|
|
|
|
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_uint_field(w, "size", t->size);
|
|
|
|
jsonw_uint_field(w, "bits_offset", BTF_INT_OFFSET(v));
|
|
|
|
jsonw_uint_field(w, "nr_bits", BTF_INT_BITS(v));
|
|
|
|
jsonw_string_field(w, "encoding", enc);
|
|
|
|
} else {
|
|
|
|
printf(" size=%u bits_offset=%u nr_bits=%u encoding=%s",
|
|
|
|
t->size, BTF_INT_OFFSET(v), BTF_INT_BITS(v),
|
|
|
|
enc);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case BTF_KIND_PTR:
|
|
|
|
case BTF_KIND_CONST:
|
|
|
|
case BTF_KIND_VOLATILE:
|
|
|
|
case BTF_KIND_RESTRICT:
|
|
|
|
case BTF_KIND_TYPEDEF:
|
2021-11-12 09:26:20 +08:00
|
|
|
case BTF_KIND_TYPE_TAG:
|
2019-04-26 06:30:08 +08:00
|
|
|
if (json_output)
|
|
|
|
jsonw_uint_field(w, "type_id", t->type);
|
|
|
|
else
|
|
|
|
printf(" type_id=%u", t->type);
|
|
|
|
break;
|
|
|
|
case BTF_KIND_ARRAY: {
|
|
|
|
const struct btf_array *arr = (const void *)(t + 1);
|
|
|
|
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_uint_field(w, "type_id", arr->type);
|
|
|
|
jsonw_uint_field(w, "index_type_id", arr->index_type);
|
|
|
|
jsonw_uint_field(w, "nr_elems", arr->nelems);
|
|
|
|
} else {
|
|
|
|
printf(" type_id=%u index_type_id=%u nr_elems=%u",
|
|
|
|
arr->type, arr->index_type, arr->nelems);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case BTF_KIND_STRUCT:
|
|
|
|
case BTF_KIND_UNION: {
|
|
|
|
const struct btf_member *m = (const void *)(t + 1);
|
|
|
|
__u16 vlen = BTF_INFO_VLEN(t->info);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_uint_field(w, "size", t->size);
|
|
|
|
jsonw_uint_field(w, "vlen", vlen);
|
|
|
|
jsonw_name(w, "members");
|
|
|
|
jsonw_start_array(w);
|
|
|
|
} else {
|
|
|
|
printf(" size=%u vlen=%u", t->size, vlen);
|
|
|
|
}
|
|
|
|
for (i = 0; i < vlen; i++, m++) {
|
|
|
|
const char *name = btf_str(btf, m->name_off);
|
|
|
|
__u32 bit_off, bit_sz;
|
|
|
|
|
|
|
|
if (BTF_INFO_KFLAG(t->info)) {
|
|
|
|
bit_off = BTF_MEMBER_BIT_OFFSET(m->offset);
|
|
|
|
bit_sz = BTF_MEMBER_BITFIELD_SIZE(m->offset);
|
|
|
|
} else {
|
|
|
|
bit_off = m->offset;
|
|
|
|
bit_sz = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_start_object(w);
|
|
|
|
jsonw_string_field(w, "name", name);
|
|
|
|
jsonw_uint_field(w, "type_id", m->type);
|
|
|
|
jsonw_uint_field(w, "bits_offset", bit_off);
|
|
|
|
if (bit_sz) {
|
|
|
|
jsonw_uint_field(w, "bitfield_size",
|
|
|
|
bit_sz);
|
|
|
|
}
|
|
|
|
jsonw_end_object(w);
|
|
|
|
} else {
|
|
|
|
printf("\n\t'%s' type_id=%u bits_offset=%u",
|
|
|
|
name, m->type, bit_off);
|
|
|
|
if (bit_sz)
|
|
|
|
printf(" bitfield_size=%u", bit_sz);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (json_output)
|
|
|
|
jsonw_end_array(w);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case BTF_KIND_ENUM: {
|
|
|
|
const struct btf_enum *v = (const void *)(t + 1);
|
|
|
|
__u16 vlen = BTF_INFO_VLEN(t->info);
|
2022-06-07 14:26:52 +08:00
|
|
|
const char *encoding;
|
2019-04-26 06:30:08 +08:00
|
|
|
int i;
|
|
|
|
|
2022-06-07 14:26:52 +08:00
|
|
|
encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";
|
2019-04-26 06:30:08 +08:00
|
|
|
if (json_output) {
|
2022-06-07 14:26:52 +08:00
|
|
|
jsonw_string_field(w, "encoding", encoding);
|
2019-04-26 06:30:08 +08:00
|
|
|
jsonw_uint_field(w, "size", t->size);
|
|
|
|
jsonw_uint_field(w, "vlen", vlen);
|
|
|
|
jsonw_name(w, "values");
|
|
|
|
jsonw_start_array(w);
|
|
|
|
} else {
|
2022-06-07 14:26:52 +08:00
|
|
|
printf(" encoding=%s size=%u vlen=%u", encoding, t->size, vlen);
|
|
|
|
}
|
|
|
|
for (i = 0; i < vlen; i++, v++) {
|
|
|
|
const char *name = btf_str(btf, v->name_off);
|
|
|
|
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_start_object(w);
|
|
|
|
jsonw_string_field(w, "name", name);
|
|
|
|
if (btf_kflag(t))
|
|
|
|
jsonw_int_field(w, "val", v->val);
|
|
|
|
else
|
|
|
|
jsonw_uint_field(w, "val", v->val);
|
|
|
|
jsonw_end_object(w);
|
|
|
|
} else {
|
|
|
|
if (btf_kflag(t))
|
|
|
|
printf("\n\t'%s' val=%d", name, v->val);
|
|
|
|
else
|
|
|
|
printf("\n\t'%s' val=%u", name, v->val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (json_output)
|
|
|
|
jsonw_end_array(w);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case BTF_KIND_ENUM64: {
|
|
|
|
const struct btf_enum64 *v = btf_enum64(t);
|
|
|
|
__u16 vlen = btf_vlen(t);
|
|
|
|
const char *encoding;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_string_field(w, "encoding", encoding);
|
|
|
|
jsonw_uint_field(w, "size", t->size);
|
|
|
|
jsonw_uint_field(w, "vlen", vlen);
|
|
|
|
jsonw_name(w, "values");
|
|
|
|
jsonw_start_array(w);
|
|
|
|
} else {
|
|
|
|
printf(" encoding=%s size=%u vlen=%u", encoding, t->size, vlen);
|
2019-04-26 06:30:08 +08:00
|
|
|
}
|
|
|
|
for (i = 0; i < vlen; i++, v++) {
|
|
|
|
const char *name = btf_str(btf, v->name_off);
|
2022-06-07 14:26:52 +08:00
|
|
|
__u64 val = ((__u64)v->val_hi32 << 32) | v->val_lo32;
|
2019-04-26 06:30:08 +08:00
|
|
|
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_start_object(w);
|
|
|
|
jsonw_string_field(w, "name", name);
|
2022-06-07 14:26:52 +08:00
|
|
|
if (btf_kflag(t))
|
|
|
|
jsonw_int_field(w, "val", val);
|
|
|
|
else
|
|
|
|
jsonw_uint_field(w, "val", val);
|
2019-04-26 06:30:08 +08:00
|
|
|
jsonw_end_object(w);
|
|
|
|
} else {
|
2022-06-07 14:26:52 +08:00
|
|
|
if (btf_kflag(t))
|
|
|
|
printf("\n\t'%s' val=%lldLL", name,
|
|
|
|
(unsigned long long)val);
|
|
|
|
else
|
|
|
|
printf("\n\t'%s' val=%lluULL", name,
|
|
|
|
(unsigned long long)val);
|
2019-04-26 06:30:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (json_output)
|
|
|
|
jsonw_end_array(w);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case BTF_KIND_FWD: {
|
2019-05-17 14:21:29 +08:00
|
|
|
const char *fwd_kind = BTF_INFO_KFLAG(t->info) ? "union"
|
|
|
|
: "struct";
|
2019-04-26 06:30:08 +08:00
|
|
|
|
|
|
|
if (json_output)
|
|
|
|
jsonw_string_field(w, "fwd_kind", fwd_kind);
|
|
|
|
else
|
|
|
|
printf(" fwd_kind=%s", fwd_kind);
|
|
|
|
break;
|
|
|
|
}
|
2020-01-24 13:43:17 +08:00
|
|
|
case BTF_KIND_FUNC: {
|
|
|
|
const char *linkage = btf_func_linkage_str(t);
|
|
|
|
|
|
|
|
if (json_output) {
|
2019-04-26 06:30:08 +08:00
|
|
|
jsonw_uint_field(w, "type_id", t->type);
|
2020-01-24 13:43:17 +08:00
|
|
|
jsonw_string_field(w, "linkage", linkage);
|
|
|
|
} else {
|
|
|
|
printf(" type_id=%u linkage=%s", t->type, linkage);
|
|
|
|
}
|
2019-04-26 06:30:08 +08:00
|
|
|
break;
|
2020-01-24 13:43:17 +08:00
|
|
|
}
|
2019-04-26 06:30:08 +08:00
|
|
|
case BTF_KIND_FUNC_PROTO: {
|
|
|
|
const struct btf_param *p = (const void *)(t + 1);
|
|
|
|
__u16 vlen = BTF_INFO_VLEN(t->info);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_uint_field(w, "ret_type_id", t->type);
|
|
|
|
jsonw_uint_field(w, "vlen", vlen);
|
|
|
|
jsonw_name(w, "params");
|
|
|
|
jsonw_start_array(w);
|
|
|
|
} else {
|
|
|
|
printf(" ret_type_id=%u vlen=%u", t->type, vlen);
|
|
|
|
}
|
|
|
|
for (i = 0; i < vlen; i++, p++) {
|
|
|
|
const char *name = btf_str(btf, p->name_off);
|
|
|
|
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_start_object(w);
|
|
|
|
jsonw_string_field(w, "name", name);
|
|
|
|
jsonw_uint_field(w, "type_id", p->type);
|
|
|
|
jsonw_end_object(w);
|
|
|
|
} else {
|
|
|
|
printf("\n\t'%s' type_id=%u", name, p->type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (json_output)
|
|
|
|
jsonw_end_array(w);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case BTF_KIND_VAR: {
|
|
|
|
const struct btf_var *v = (const void *)(t + 1);
|
|
|
|
const char *linkage;
|
|
|
|
|
|
|
|
linkage = btf_var_linkage_str(v->linkage);
|
|
|
|
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_uint_field(w, "type_id", t->type);
|
|
|
|
jsonw_string_field(w, "linkage", linkage);
|
|
|
|
} else {
|
|
|
|
printf(" type_id=%u, linkage=%s", t->type, linkage);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case BTF_KIND_DATASEC: {
|
2021-04-24 02:13:32 +08:00
|
|
|
const struct btf_var_secinfo *v = (const void *)(t + 1);
|
|
|
|
const struct btf_type *vt;
|
2019-04-26 06:30:08 +08:00
|
|
|
__u16 vlen = BTF_INFO_VLEN(t->info);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_uint_field(w, "size", t->size);
|
|
|
|
jsonw_uint_field(w, "vlen", vlen);
|
|
|
|
jsonw_name(w, "vars");
|
|
|
|
jsonw_start_array(w);
|
|
|
|
} else {
|
|
|
|
printf(" size=%u vlen=%u", t->size, vlen);
|
|
|
|
}
|
|
|
|
for (i = 0; i < vlen; i++, v++) {
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_start_object(w);
|
|
|
|
jsonw_uint_field(w, "type_id", v->type);
|
|
|
|
jsonw_uint_field(w, "offset", v->offset);
|
|
|
|
jsonw_uint_field(w, "size", v->size);
|
|
|
|
jsonw_end_object(w);
|
|
|
|
} else {
|
|
|
|
printf("\n\ttype_id=%u offset=%u size=%u",
|
|
|
|
v->type, v->offset, v->size);
|
2021-04-24 02:13:32 +08:00
|
|
|
|
2021-10-22 21:06:22 +08:00
|
|
|
if (v->type < btf__type_cnt(btf)) {
|
2021-04-24 02:13:32 +08:00
|
|
|
vt = btf__type_by_id(btf, v->type);
|
|
|
|
printf(" (%s '%s')",
|
|
|
|
btf_kind_str[btf_kind_safe(btf_kind(vt))],
|
|
|
|
btf_str(btf, vt->name_off));
|
|
|
|
}
|
2019-04-26 06:30:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (json_output)
|
|
|
|
jsonw_end_array(w);
|
|
|
|
break;
|
|
|
|
}
|
2021-02-27 04:22:50 +08:00
|
|
|
case BTF_KIND_FLOAT: {
|
|
|
|
if (json_output)
|
|
|
|
jsonw_uint_field(w, "size", t->size);
|
|
|
|
else
|
|
|
|
printf(" size=%u", t->size);
|
|
|
|
break;
|
|
|
|
}
|
2021-10-13 00:48:38 +08:00
|
|
|
case BTF_KIND_DECL_TAG: {
|
|
|
|
const struct btf_decl_tag *tag = (const void *)(t + 1);
|
2021-09-15 06:30:31 +08:00
|
|
|
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_uint_field(w, "type_id", t->type);
|
|
|
|
jsonw_int_field(w, "component_idx", tag->component_idx);
|
|
|
|
} else {
|
|
|
|
printf(" type_id=%u component_idx=%d", t->type, tag->component_idx);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2019-04-26 06:30:08 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (json_output)
|
|
|
|
jsonw_end_object(json_wtr);
|
|
|
|
else
|
|
|
|
printf("\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dump_btf_raw(const struct btf *btf,
|
|
|
|
__u32 *root_type_ids, int root_type_cnt)
|
|
|
|
{
|
|
|
|
const struct btf_type *t;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_start_object(json_wtr);
|
|
|
|
jsonw_name(json_wtr, "types");
|
|
|
|
jsonw_start_array(json_wtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (root_type_cnt) {
|
|
|
|
for (i = 0; i < root_type_cnt; i++) {
|
|
|
|
t = btf__type_by_id(btf, root_type_ids[i]);
|
|
|
|
dump_btf_type(btf, root_type_ids[i], t);
|
|
|
|
}
|
|
|
|
} else {
|
2020-12-02 14:52:43 +08:00
|
|
|
const struct btf *base;
|
2021-10-22 21:06:22 +08:00
|
|
|
int cnt = btf__type_cnt(btf);
|
2020-11-05 12:34:01 +08:00
|
|
|
int start_id = 1;
|
2019-04-26 06:30:08 +08:00
|
|
|
|
2020-12-02 14:52:43 +08:00
|
|
|
base = btf__base_btf(btf);
|
|
|
|
if (base)
|
2021-10-22 21:06:22 +08:00
|
|
|
start_id = btf__type_cnt(base);
|
2020-11-05 12:34:01 +08:00
|
|
|
|
2021-10-22 21:06:22 +08:00
|
|
|
for (i = start_id; i < cnt; i++) {
|
2019-04-26 06:30:08 +08:00
|
|
|
t = btf__type_by_id(btf, i);
|
|
|
|
dump_btf_type(btf, i, t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_end_array(json_wtr);
|
|
|
|
jsonw_end_object(json_wtr);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-25 02:59:05 +08:00
|
|
|
static void __printf(2, 0) btf_dump_printf(void *ctx,
|
|
|
|
const char *fmt, va_list args)
|
|
|
|
{
|
|
|
|
vfprintf(stdout, fmt, args);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dump_btf_c(const struct btf *btf,
|
|
|
|
__u32 *root_type_ids, int root_type_cnt)
|
|
|
|
{
|
|
|
|
struct btf_dump *d;
|
|
|
|
int err = 0, i;
|
|
|
|
|
2021-11-11 13:36:24 +08:00
|
|
|
d = btf_dump__new(btf, btf_dump_printf, NULL, NULL);
|
2022-11-20 19:26:32 +08:00
|
|
|
if (!d)
|
|
|
|
return -errno;
|
2019-05-25 02:59:05 +08:00
|
|
|
|
2020-03-01 07:11:09 +08:00
|
|
|
printf("#ifndef __VMLINUX_H__\n");
|
|
|
|
printf("#define __VMLINUX_H__\n");
|
|
|
|
printf("\n");
|
2020-01-13 15:31:41 +08:00
|
|
|
printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
|
|
|
|
printf("#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n");
|
|
|
|
printf("#endif\n\n");
|
|
|
|
|
2019-05-25 02:59:05 +08:00
|
|
|
if (root_type_cnt) {
|
|
|
|
for (i = 0; i < root_type_cnt; i++) {
|
|
|
|
err = btf_dump__dump_type(d, root_type_ids[i]);
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
} else {
|
2021-10-22 21:06:22 +08:00
|
|
|
int cnt = btf__type_cnt(btf);
|
2019-05-25 02:59:05 +08:00
|
|
|
|
2021-10-22 21:06:22 +08:00
|
|
|
for (i = 1; i < cnt; i++) {
|
2019-05-25 02:59:05 +08:00
|
|
|
err = btf_dump__dump_type(d, i);
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-13 15:31:41 +08:00
|
|
|
printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
|
|
|
|
printf("#pragma clang attribute pop\n");
|
|
|
|
printf("#endif\n");
|
2020-03-01 07:11:09 +08:00
|
|
|
printf("\n");
|
|
|
|
printf("#endif /* __VMLINUX_H__ */\n");
|
2020-01-13 15:31:41 +08:00
|
|
|
|
2019-05-25 02:59:05 +08:00
|
|
|
done:
|
|
|
|
btf_dump__free(d);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2022-05-13 20:17:43 +08:00
|
|
|
static const char sysfs_vmlinux[] = "/sys/kernel/btf/vmlinux";
|
|
|
|
|
|
|
|
static struct btf *get_vmlinux_btf_from_sysfs(void)
|
|
|
|
{
|
|
|
|
struct btf *base;
|
|
|
|
|
|
|
|
base = btf__parse(sysfs_vmlinux, NULL);
|
2022-11-20 19:26:32 +08:00
|
|
|
if (!base)
|
|
|
|
p_err("failed to parse vmlinux BTF at '%s': %d\n",
|
|
|
|
sysfs_vmlinux, -errno);
|
2022-05-13 20:17:43 +08:00
|
|
|
|
|
|
|
return base;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define BTF_NAME_BUFF_LEN 64
|
|
|
|
|
|
|
|
static bool btf_is_kernel_module(__u32 btf_id)
|
|
|
|
{
|
|
|
|
struct bpf_btf_info btf_info = {};
|
|
|
|
char btf_name[BTF_NAME_BUFF_LEN];
|
|
|
|
int btf_fd;
|
|
|
|
__u32 len;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
btf_fd = bpf_btf_get_fd_by_id(btf_id);
|
|
|
|
if (btf_fd < 0) {
|
|
|
|
p_err("can't get BTF object by id (%u): %s", btf_id, strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = sizeof(btf_info);
|
|
|
|
btf_info.name = ptr_to_u64(btf_name);
|
|
|
|
btf_info.name_len = sizeof(btf_name);
|
|
|
|
err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len);
|
|
|
|
close(btf_fd);
|
|
|
|
if (err) {
|
|
|
|
p_err("can't get BTF (ID %u) object info: %s", btf_id, strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return btf_info.kernel_btf && strncmp(btf_name, "vmlinux", sizeof(btf_name)) != 0;
|
|
|
|
}
|
|
|
|
|
2019-04-26 06:30:08 +08:00
|
|
|
static int do_dump(int argc, char **argv)
|
|
|
|
{
|
2020-12-02 14:52:43 +08:00
|
|
|
struct btf *btf = NULL, *base = NULL;
|
2019-04-26 06:30:08 +08:00
|
|
|
__u32 root_type_ids[2];
|
|
|
|
int root_type_cnt = 0;
|
2019-05-25 02:59:05 +08:00
|
|
|
bool dump_c = false;
|
2019-04-26 06:30:08 +08:00
|
|
|
__u32 btf_id = -1;
|
|
|
|
const char *src;
|
|
|
|
int fd = -1;
|
2022-11-20 19:26:32 +08:00
|
|
|
int err = 0;
|
2019-04-26 06:30:08 +08:00
|
|
|
|
|
|
|
if (!REQ_ARGS(2)) {
|
|
|
|
usage();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
src = GET_ARG();
|
|
|
|
if (is_prefix(src, "map")) {
|
|
|
|
struct bpf_map_info info = {};
|
|
|
|
__u32 len = sizeof(info);
|
|
|
|
|
|
|
|
if (!REQ_ARGS(2)) {
|
|
|
|
usage();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
btf_id = info.btf_id;
|
|
|
|
if (argc && is_prefix(*argv, "key")) {
|
|
|
|
root_type_ids[root_type_cnt++] = info.btf_key_type_id;
|
|
|
|
NEXT_ARG();
|
|
|
|
} else if (argc && is_prefix(*argv, "value")) {
|
|
|
|
root_type_ids[root_type_cnt++] = info.btf_value_type_id;
|
|
|
|
NEXT_ARG();
|
|
|
|
} else if (argc && is_prefix(*argv, "all")) {
|
|
|
|
NEXT_ARG();
|
|
|
|
} else if (argc && is_prefix(*argv, "kv")) {
|
|
|
|
root_type_ids[root_type_cnt++] = info.btf_key_type_id;
|
|
|
|
root_type_ids[root_type_cnt++] = info.btf_value_type_id;
|
|
|
|
NEXT_ARG();
|
|
|
|
} else {
|
|
|
|
root_type_ids[root_type_cnt++] = info.btf_key_type_id;
|
|
|
|
root_type_ids[root_type_cnt++] = info.btf_value_type_id;
|
|
|
|
}
|
|
|
|
} else if (is_prefix(src, "prog")) {
|
|
|
|
struct bpf_prog_info info = {};
|
|
|
|
__u32 len = sizeof(info);
|
|
|
|
|
|
|
|
if (!REQ_ARGS(2)) {
|
|
|
|
usage();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = prog_parse_fd(&argc, &argv);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
err = bpf_obj_get_info_by_fd(fd, &info, &len);
|
|
|
|
if (err) {
|
|
|
|
p_err("can't get prog info: %s", strerror(errno));
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
btf_id = info.btf_id;
|
|
|
|
} else if (is_prefix(src, "id")) {
|
|
|
|
char *endptr;
|
|
|
|
|
|
|
|
btf_id = strtoul(*argv, &endptr, 0);
|
|
|
|
if (*endptr) {
|
2019-08-15 22:32:17 +08:00
|
|
|
p_err("can't parse %s as ID", *argv);
|
2019-04-26 06:30:08 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
NEXT_ARG();
|
|
|
|
} else if (is_prefix(src, "file")) {
|
2020-12-02 14:52:43 +08:00
|
|
|
const char sysfs_prefix[] = "/sys/kernel/btf/";
|
|
|
|
|
|
|
|
if (!base_btf &&
|
|
|
|
strncmp(*argv, sysfs_prefix, sizeof(sysfs_prefix) - 1) == 0 &&
|
2022-05-13 20:17:43 +08:00
|
|
|
strcmp(*argv, sysfs_vmlinux) != 0)
|
|
|
|
base = get_vmlinux_btf_from_sysfs();
|
2020-12-02 14:52:43 +08:00
|
|
|
|
|
|
|
btf = btf__parse_split(*argv, base ?: base_btf);
|
2022-09-28 16:09:32 +08:00
|
|
|
if (!btf) {
|
2022-11-20 19:26:32 +08:00
|
|
|
err = -errno;
|
2020-01-20 21:06:46 +08:00
|
|
|
p_err("failed to load BTF from %s: %s",
|
2022-09-28 16:09:32 +08:00
|
|
|
*argv, strerror(errno));
|
2019-04-26 06:30:08 +08:00
|
|
|
goto done;
|
2019-05-25 02:58:58 +08:00
|
|
|
}
|
2019-04-26 06:30:08 +08:00
|
|
|
NEXT_ARG();
|
|
|
|
} else {
|
|
|
|
err = -1;
|
|
|
|
p_err("unrecognized BTF source specifier: '%s'", src);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2019-05-25 02:59:05 +08:00
|
|
|
while (argc) {
|
|
|
|
if (is_prefix(*argv, "format")) {
|
|
|
|
NEXT_ARG();
|
|
|
|
if (argc < 1) {
|
|
|
|
p_err("expecting value for 'format' option\n");
|
2021-03-14 05:09:18 +08:00
|
|
|
err = -EINVAL;
|
2019-05-25 02:59:05 +08:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
if (strcmp(*argv, "c") == 0) {
|
|
|
|
dump_c = true;
|
|
|
|
} else if (strcmp(*argv, "raw") == 0) {
|
|
|
|
dump_c = false;
|
|
|
|
} else {
|
|
|
|
p_err("unrecognized format specifier: '%s', possible values: raw, c",
|
|
|
|
*argv);
|
2021-03-14 05:09:18 +08:00
|
|
|
err = -EINVAL;
|
2019-05-25 02:59:05 +08:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
NEXT_ARG();
|
|
|
|
} else {
|
|
|
|
p_err("unrecognized option: '%s'", *argv);
|
2021-03-14 05:09:18 +08:00
|
|
|
err = -EINVAL;
|
2019-05-25 02:59:05 +08:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-26 06:30:08 +08:00
|
|
|
if (!btf) {
|
2022-05-13 20:17:43 +08:00
|
|
|
if (!base_btf && btf_is_kernel_module(btf_id)) {
|
|
|
|
p_info("Warning: valid base BTF was not specified with -B option, falling back to standard base BTF (%s)",
|
|
|
|
sysfs_vmlinux);
|
|
|
|
base_btf = get_vmlinux_btf_from_sysfs();
|
|
|
|
}
|
|
|
|
|
2021-07-30 00:20:28 +08:00
|
|
|
btf = btf__load_from_kernel_by_id_split(btf_id, base_btf);
|
2022-09-28 16:09:32 +08:00
|
|
|
if (!btf) {
|
2022-11-20 19:26:32 +08:00
|
|
|
err = -errno;
|
2022-09-28 16:09:32 +08:00
|
|
|
p_err("get btf by id (%u): %s", btf_id, strerror(errno));
|
2019-04-26 06:30:08 +08:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-25 02:59:05 +08:00
|
|
|
if (dump_c) {
|
|
|
|
if (json_output) {
|
|
|
|
p_err("JSON output for C-syntax dump is not supported");
|
|
|
|
err = -ENOTSUP;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
err = dump_btf_c(btf, root_type_ids, root_type_cnt);
|
|
|
|
} else {
|
|
|
|
err = dump_btf_raw(btf, root_type_ids, root_type_cnt);
|
|
|
|
}
|
2019-04-26 06:30:08 +08:00
|
|
|
|
|
|
|
done:
|
|
|
|
close(fd);
|
|
|
|
btf__free(btf);
|
2020-12-02 14:52:43 +08:00
|
|
|
btf__free(base);
|
2019-04-26 06:30:08 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2019-08-20 17:31:54 +08:00
|
|
|
static int btf_parse_fd(int *argc, char ***argv)
|
|
|
|
{
|
|
|
|
unsigned int id;
|
|
|
|
char *endptr;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if (!is_prefix(*argv[0], "id")) {
|
|
|
|
p_err("expected 'id', got: '%s'?", **argv);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
id = strtoul(**argv, &endptr, 0);
|
|
|
|
if (*endptr) {
|
|
|
|
p_err("can't parse %s as ID", **argv);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
fd = bpf_btf_get_fd_by_id(id);
|
|
|
|
if (fd < 0)
|
|
|
|
p_err("can't get BTF object by id (%u): %s",
|
|
|
|
id, strerror(errno));
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2021-10-24 04:51:53 +08:00
|
|
|
build_btf_type_table(struct hashmap *tab, enum bpf_obj_type type,
|
2019-08-20 17:31:54 +08:00
|
|
|
void *info, __u32 *len)
|
|
|
|
{
|
|
|
|
static const char * const names[] = {
|
|
|
|
[BPF_OBJ_UNKNOWN] = "unknown",
|
|
|
|
[BPF_OBJ_PROG] = "prog",
|
|
|
|
[BPF_OBJ_MAP] = "map",
|
|
|
|
};
|
|
|
|
__u32 btf_id, id = 0;
|
|
|
|
int err;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
switch (type) {
|
|
|
|
case BPF_OBJ_PROG:
|
|
|
|
err = bpf_prog_get_next_id(id, &id);
|
|
|
|
break;
|
|
|
|
case BPF_OBJ_MAP:
|
|
|
|
err = bpf_map_get_next_id(id, &id);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
err = -1;
|
|
|
|
p_err("unexpected object type: %d", type);
|
|
|
|
goto err_free;
|
|
|
|
}
|
|
|
|
if (err) {
|
|
|
|
if (errno == ENOENT) {
|
|
|
|
err = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
p_err("can't get next %s: %s%s", names[type],
|
|
|
|
strerror(errno),
|
|
|
|
errno == EINVAL ? " -- kernel too old?" : "");
|
|
|
|
goto err_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case BPF_OBJ_PROG:
|
|
|
|
fd = bpf_prog_get_fd_by_id(id);
|
|
|
|
break;
|
|
|
|
case BPF_OBJ_MAP:
|
|
|
|
fd = bpf_map_get_fd_by_id(id);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
err = -1;
|
|
|
|
p_err("unexpected object type: %d", type);
|
|
|
|
goto err_free;
|
|
|
|
}
|
|
|
|
if (fd < 0) {
|
|
|
|
if (errno == ENOENT)
|
|
|
|
continue;
|
|
|
|
p_err("can't get %s by id (%u): %s", names[type], id,
|
|
|
|
strerror(errno));
|
|
|
|
err = -1;
|
|
|
|
goto err_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(info, 0, *len);
|
|
|
|
err = bpf_obj_get_info_by_fd(fd, info, len);
|
|
|
|
close(fd);
|
|
|
|
if (err) {
|
|
|
|
p_err("can't get %s info: %s", names[type],
|
|
|
|
strerror(errno));
|
|
|
|
goto err_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case BPF_OBJ_PROG:
|
|
|
|
btf_id = ((struct bpf_prog_info *)info)->btf_id;
|
|
|
|
break;
|
|
|
|
case BPF_OBJ_MAP:
|
|
|
|
btf_id = ((struct bpf_map_info *)info)->btf_id;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
err = -1;
|
|
|
|
p_err("unexpected object type: %d", type);
|
|
|
|
goto err_free;
|
|
|
|
}
|
|
|
|
if (!btf_id)
|
|
|
|
continue;
|
|
|
|
|
libbpf: Hashmap interface update to allow both long and void* keys/values
An update for libbpf's hashmap interface from void* -> void* to a
polymorphic one, allowing both long and void* keys and values.
This simplifies many use cases in libbpf as hashmaps there are mostly
integer to integer.
Perf copies hashmap implementation from libbpf and has to be
updated as well.
Changes to libbpf, selftests/bpf and perf are packed as a single
commit to avoid compilation issues with any future bisect.
Polymorphic interface is acheived by hiding hashmap interface
functions behind auxiliary macros that take care of necessary
type casts, for example:
#define hashmap_cast_ptr(p) \
({ \
_Static_assert((p) == NULL || sizeof(*(p)) == sizeof(long),\
#p " pointee should be a long-sized integer or a pointer"); \
(long *)(p); \
})
bool hashmap_find(const struct hashmap *map, long key, long *value);
#define hashmap__find(map, key, value) \
hashmap_find((map), (long)(key), hashmap_cast_ptr(value))
- hashmap__find macro casts key and value parameters to long
and long* respectively
- hashmap_cast_ptr ensures that value pointer points to a memory
of appropriate size.
This hack was suggested by Andrii Nakryiko in [1].
This is a follow up for [2].
[1] https://lore.kernel.org/bpf/CAEf4BzZ8KFneEJxFAaNCCFPGqp20hSpS2aCj76uRk3-qZUH5xg@mail.gmail.com/
[2] https://lore.kernel.org/bpf/af1facf9-7bc8-8a3d-0db4-7b3f333589a2@meta.com/T/#m65b28f1d6d969fcd318b556db6a3ad499a42607d
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20221109142611.879983-2-eddyz87@gmail.com
2022-11-09 22:26:09 +08:00
|
|
|
err = hashmap__append(tab, btf_id, id);
|
2021-10-24 04:51:53 +08:00
|
|
|
if (err) {
|
|
|
|
p_err("failed to append entry to hashmap for BTF ID %u, object ID %u: %s",
|
2022-09-28 16:09:32 +08:00
|
|
|
btf_id, id, strerror(-err));
|
2019-08-20 17:31:54 +08:00
|
|
|
goto err_free;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_free:
|
2021-10-24 04:51:53 +08:00
|
|
|
hashmap__free(tab);
|
2019-08-20 17:31:54 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2021-10-24 04:51:53 +08:00
|
|
|
build_btf_tables(struct hashmap *btf_prog_table,
|
|
|
|
struct hashmap *btf_map_table)
|
2019-08-20 17:31:54 +08:00
|
|
|
{
|
|
|
|
struct bpf_prog_info prog_info;
|
|
|
|
__u32 prog_len = sizeof(prog_info);
|
|
|
|
struct bpf_map_info map_info;
|
|
|
|
__u32 map_len = sizeof(map_info);
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
err = build_btf_type_table(btf_prog_table, BPF_OBJ_PROG, &prog_info,
|
|
|
|
&prog_len);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = build_btf_type_table(btf_map_table, BPF_OBJ_MAP, &map_info,
|
|
|
|
&map_len);
|
|
|
|
if (err) {
|
2021-10-24 04:51:53 +08:00
|
|
|
hashmap__free(btf_prog_table);
|
2019-08-20 17:31:54 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
show_btf_plain(struct bpf_btf_info *info, int fd,
|
2021-10-24 04:51:53 +08:00
|
|
|
struct hashmap *btf_prog_table,
|
|
|
|
struct hashmap *btf_map_table)
|
2019-08-20 17:31:54 +08:00
|
|
|
{
|
2021-10-24 04:51:53 +08:00
|
|
|
struct hashmap_entry *entry;
|
tools/bpftool: Add support for in-kernel and named BTF in `btf show`
Display vmlinux BTF name and kernel module names when listing available BTFs
on the system.
In human-readable output mode, module BTFs are reported with "name
[module-name]", while vmlinux BTF will be reported as "name [vmlinux]".
Square brackets are added by bpftool and follow kernel convention when
displaying modules in human-readable text outputs.
[vmuser@archvm bpf]$ sudo ../../../bpf/bpftool/bpftool btf s
1: name [vmlinux] size 4082281B
6: size 2365B prog_ids 8,6 map_ids 3
7: name [button] size 46895B
8: name [pcspkr] size 42328B
9: name [serio_raw] size 39375B
10: name [floppy] size 57185B
11: name [i2c_core] size 76186B
12: name [crc32c_intel] size 16036B
13: name [i2c_piix4] size 50497B
14: name [irqbypass] size 14124B
15: name [kvm] size 197985B
16: name [kvm_intel] size 123564B
17: name [cryptd] size 42466B
18: name [crypto_simd] size 17187B
19: name [glue_helper] size 39205B
20: name [aesni_intel] size 41034B
25: size 36150B
pids bpftool(2519)
In JSON mode, two fields (boolean "kernel" and string "name") are reported for
each BTF object. vmlinux BTF is reported with name "vmlinux" (kernel itself
returns and empty name for vmlinux BTF).
[vmuser@archvm bpf]$ sudo ../../../bpf/bpftool/bpftool btf s -jp
[{
"id": 1,
"size": 4082281,
"prog_ids": [],
"map_ids": [],
"kernel": true,
"name": "vmlinux"
},{
"id": 6,
"size": 2365,
"prog_ids": [8,6
],
"map_ids": [3
],
"kernel": false
},{
"id": 7,
"size": 46895,
"prog_ids": [],
"map_ids": [],
"kernel": true,
"name": "button"
},{
...
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Tested-by: Alan Maguire <alan.maguire@oracle.com>
Link: https://lore.kernel.org/bpf/20201110011932.3201430-6-andrii@kernel.org
2020-11-10 09:19:32 +08:00
|
|
|
const char *name = u64_to_ptr(info->name);
|
2019-08-20 17:31:54 +08:00
|
|
|
int n;
|
|
|
|
|
|
|
|
printf("%u: ", info->id);
|
tools/bpftool: Add support for in-kernel and named BTF in `btf show`
Display vmlinux BTF name and kernel module names when listing available BTFs
on the system.
In human-readable output mode, module BTFs are reported with "name
[module-name]", while vmlinux BTF will be reported as "name [vmlinux]".
Square brackets are added by bpftool and follow kernel convention when
displaying modules in human-readable text outputs.
[vmuser@archvm bpf]$ sudo ../../../bpf/bpftool/bpftool btf s
1: name [vmlinux] size 4082281B
6: size 2365B prog_ids 8,6 map_ids 3
7: name [button] size 46895B
8: name [pcspkr] size 42328B
9: name [serio_raw] size 39375B
10: name [floppy] size 57185B
11: name [i2c_core] size 76186B
12: name [crc32c_intel] size 16036B
13: name [i2c_piix4] size 50497B
14: name [irqbypass] size 14124B
15: name [kvm] size 197985B
16: name [kvm_intel] size 123564B
17: name [cryptd] size 42466B
18: name [crypto_simd] size 17187B
19: name [glue_helper] size 39205B
20: name [aesni_intel] size 41034B
25: size 36150B
pids bpftool(2519)
In JSON mode, two fields (boolean "kernel" and string "name") are reported for
each BTF object. vmlinux BTF is reported with name "vmlinux" (kernel itself
returns and empty name for vmlinux BTF).
[vmuser@archvm bpf]$ sudo ../../../bpf/bpftool/bpftool btf s -jp
[{
"id": 1,
"size": 4082281,
"prog_ids": [],
"map_ids": [],
"kernel": true,
"name": "vmlinux"
},{
"id": 6,
"size": 2365,
"prog_ids": [8,6
],
"map_ids": [3
],
"kernel": false
},{
"id": 7,
"size": 46895,
"prog_ids": [],
"map_ids": [],
"kernel": true,
"name": "button"
},{
...
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Tested-by: Alan Maguire <alan.maguire@oracle.com>
Link: https://lore.kernel.org/bpf/20201110011932.3201430-6-andrii@kernel.org
2020-11-10 09:19:32 +08:00
|
|
|
if (info->kernel_btf)
|
|
|
|
printf("name [%s] ", name);
|
|
|
|
else if (name && name[0])
|
|
|
|
printf("name %s ", name);
|
2020-12-02 14:52:41 +08:00
|
|
|
else
|
|
|
|
printf("name <anon> ");
|
2019-08-20 17:31:54 +08:00
|
|
|
printf("size %uB", info->btf_size);
|
|
|
|
|
|
|
|
n = 0;
|
libbpf: Hashmap interface update to allow both long and void* keys/values
An update for libbpf's hashmap interface from void* -> void* to a
polymorphic one, allowing both long and void* keys and values.
This simplifies many use cases in libbpf as hashmaps there are mostly
integer to integer.
Perf copies hashmap implementation from libbpf and has to be
updated as well.
Changes to libbpf, selftests/bpf and perf are packed as a single
commit to avoid compilation issues with any future bisect.
Polymorphic interface is acheived by hiding hashmap interface
functions behind auxiliary macros that take care of necessary
type casts, for example:
#define hashmap_cast_ptr(p) \
({ \
_Static_assert((p) == NULL || sizeof(*(p)) == sizeof(long),\
#p " pointee should be a long-sized integer or a pointer"); \
(long *)(p); \
})
bool hashmap_find(const struct hashmap *map, long key, long *value);
#define hashmap__find(map, key, value) \
hashmap_find((map), (long)(key), hashmap_cast_ptr(value))
- hashmap__find macro casts key and value parameters to long
and long* respectively
- hashmap_cast_ptr ensures that value pointer points to a memory
of appropriate size.
This hack was suggested by Andrii Nakryiko in [1].
This is a follow up for [2].
[1] https://lore.kernel.org/bpf/CAEf4BzZ8KFneEJxFAaNCCFPGqp20hSpS2aCj76uRk3-qZUH5xg@mail.gmail.com/
[2] https://lore.kernel.org/bpf/af1facf9-7bc8-8a3d-0db4-7b3f333589a2@meta.com/T/#m65b28f1d6d969fcd318b556db6a3ad499a42607d
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20221109142611.879983-2-eddyz87@gmail.com
2022-11-09 22:26:09 +08:00
|
|
|
hashmap__for_each_key_entry(btf_prog_table, entry, info->id) {
|
|
|
|
printf("%s%lu", n++ == 0 ? " prog_ids " : ",", entry->value);
|
2019-08-20 17:31:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
n = 0;
|
libbpf: Hashmap interface update to allow both long and void* keys/values
An update for libbpf's hashmap interface from void* -> void* to a
polymorphic one, allowing both long and void* keys and values.
This simplifies many use cases in libbpf as hashmaps there are mostly
integer to integer.
Perf copies hashmap implementation from libbpf and has to be
updated as well.
Changes to libbpf, selftests/bpf and perf are packed as a single
commit to avoid compilation issues with any future bisect.
Polymorphic interface is acheived by hiding hashmap interface
functions behind auxiliary macros that take care of necessary
type casts, for example:
#define hashmap_cast_ptr(p) \
({ \
_Static_assert((p) == NULL || sizeof(*(p)) == sizeof(long),\
#p " pointee should be a long-sized integer or a pointer"); \
(long *)(p); \
})
bool hashmap_find(const struct hashmap *map, long key, long *value);
#define hashmap__find(map, key, value) \
hashmap_find((map), (long)(key), hashmap_cast_ptr(value))
- hashmap__find macro casts key and value parameters to long
and long* respectively
- hashmap_cast_ptr ensures that value pointer points to a memory
of appropriate size.
This hack was suggested by Andrii Nakryiko in [1].
This is a follow up for [2].
[1] https://lore.kernel.org/bpf/CAEf4BzZ8KFneEJxFAaNCCFPGqp20hSpS2aCj76uRk3-qZUH5xg@mail.gmail.com/
[2] https://lore.kernel.org/bpf/af1facf9-7bc8-8a3d-0db4-7b3f333589a2@meta.com/T/#m65b28f1d6d969fcd318b556db6a3ad499a42607d
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20221109142611.879983-2-eddyz87@gmail.com
2022-11-09 22:26:09 +08:00
|
|
|
hashmap__for_each_key_entry(btf_map_table, entry, info->id) {
|
|
|
|
printf("%s%lu", n++ == 0 ? " map_ids " : ",", entry->value);
|
2019-08-20 17:31:54 +08:00
|
|
|
}
|
2021-10-24 04:51:53 +08:00
|
|
|
|
bpftool: Switch to libbpf's hashmap for PIDs/names references
In order to show PIDs and names for processes holding references to BPF
programs, maps, links, or BTF objects, bpftool creates hash maps to
store all relevant information. This commit is part of a set that
transitions from the kernel's hash map implementation to the one coming
with libbpf.
The motivation is to make bpftool less dependent of kernel headers, to
ease the path to a potential out-of-tree mirror, like libbpf has.
This is the third and final step of the transition, in which we convert
the hash maps used for storing the information about the processes
holding references to BPF objects (programs, maps, links, BTF), and at
last we drop the inclusion of tools/include/linux/hashtable.h.
Note: Checkpatch complains about the use of __weak declarations, and the
missing empty lines after the bunch of empty function declarations when
compiling without the BPF skeletons (none of these were introduced in
this patch). We want to keep things as they are, and the reports should
be safe to ignore.
Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20211023205154.6710-6-quentin@isovalent.com
2021-10-24 04:51:54 +08:00
|
|
|
emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
|
2019-08-20 17:31:54 +08:00
|
|
|
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
show_btf_json(struct bpf_btf_info *info, int fd,
|
2021-10-24 04:51:53 +08:00
|
|
|
struct hashmap *btf_prog_table,
|
|
|
|
struct hashmap *btf_map_table)
|
2019-08-20 17:31:54 +08:00
|
|
|
{
|
2021-10-24 04:51:53 +08:00
|
|
|
struct hashmap_entry *entry;
|
tools/bpftool: Add support for in-kernel and named BTF in `btf show`
Display vmlinux BTF name and kernel module names when listing available BTFs
on the system.
In human-readable output mode, module BTFs are reported with "name
[module-name]", while vmlinux BTF will be reported as "name [vmlinux]".
Square brackets are added by bpftool and follow kernel convention when
displaying modules in human-readable text outputs.
[vmuser@archvm bpf]$ sudo ../../../bpf/bpftool/bpftool btf s
1: name [vmlinux] size 4082281B
6: size 2365B prog_ids 8,6 map_ids 3
7: name [button] size 46895B
8: name [pcspkr] size 42328B
9: name [serio_raw] size 39375B
10: name [floppy] size 57185B
11: name [i2c_core] size 76186B
12: name [crc32c_intel] size 16036B
13: name [i2c_piix4] size 50497B
14: name [irqbypass] size 14124B
15: name [kvm] size 197985B
16: name [kvm_intel] size 123564B
17: name [cryptd] size 42466B
18: name [crypto_simd] size 17187B
19: name [glue_helper] size 39205B
20: name [aesni_intel] size 41034B
25: size 36150B
pids bpftool(2519)
In JSON mode, two fields (boolean "kernel" and string "name") are reported for
each BTF object. vmlinux BTF is reported with name "vmlinux" (kernel itself
returns and empty name for vmlinux BTF).
[vmuser@archvm bpf]$ sudo ../../../bpf/bpftool/bpftool btf s -jp
[{
"id": 1,
"size": 4082281,
"prog_ids": [],
"map_ids": [],
"kernel": true,
"name": "vmlinux"
},{
"id": 6,
"size": 2365,
"prog_ids": [8,6
],
"map_ids": [3
],
"kernel": false
},{
"id": 7,
"size": 46895,
"prog_ids": [],
"map_ids": [],
"kernel": true,
"name": "button"
},{
...
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Tested-by: Alan Maguire <alan.maguire@oracle.com>
Link: https://lore.kernel.org/bpf/20201110011932.3201430-6-andrii@kernel.org
2020-11-10 09:19:32 +08:00
|
|
|
const char *name = u64_to_ptr(info->name);
|
2019-08-20 17:31:54 +08:00
|
|
|
|
|
|
|
jsonw_start_object(json_wtr); /* btf object */
|
|
|
|
jsonw_uint_field(json_wtr, "id", info->id);
|
|
|
|
jsonw_uint_field(json_wtr, "size", info->btf_size);
|
|
|
|
|
|
|
|
jsonw_name(json_wtr, "prog_ids");
|
|
|
|
jsonw_start_array(json_wtr); /* prog_ids */
|
libbpf: Hashmap interface update to allow both long and void* keys/values
An update for libbpf's hashmap interface from void* -> void* to a
polymorphic one, allowing both long and void* keys and values.
This simplifies many use cases in libbpf as hashmaps there are mostly
integer to integer.
Perf copies hashmap implementation from libbpf and has to be
updated as well.
Changes to libbpf, selftests/bpf and perf are packed as a single
commit to avoid compilation issues with any future bisect.
Polymorphic interface is acheived by hiding hashmap interface
functions behind auxiliary macros that take care of necessary
type casts, for example:
#define hashmap_cast_ptr(p) \
({ \
_Static_assert((p) == NULL || sizeof(*(p)) == sizeof(long),\
#p " pointee should be a long-sized integer or a pointer"); \
(long *)(p); \
})
bool hashmap_find(const struct hashmap *map, long key, long *value);
#define hashmap__find(map, key, value) \
hashmap_find((map), (long)(key), hashmap_cast_ptr(value))
- hashmap__find macro casts key and value parameters to long
and long* respectively
- hashmap_cast_ptr ensures that value pointer points to a memory
of appropriate size.
This hack was suggested by Andrii Nakryiko in [1].
This is a follow up for [2].
[1] https://lore.kernel.org/bpf/CAEf4BzZ8KFneEJxFAaNCCFPGqp20hSpS2aCj76uRk3-qZUH5xg@mail.gmail.com/
[2] https://lore.kernel.org/bpf/af1facf9-7bc8-8a3d-0db4-7b3f333589a2@meta.com/T/#m65b28f1d6d969fcd318b556db6a3ad499a42607d
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20221109142611.879983-2-eddyz87@gmail.com
2022-11-09 22:26:09 +08:00
|
|
|
hashmap__for_each_key_entry(btf_prog_table, entry, info->id) {
|
|
|
|
jsonw_uint(json_wtr, entry->value);
|
2019-08-20 17:31:54 +08:00
|
|
|
}
|
|
|
|
jsonw_end_array(json_wtr); /* prog_ids */
|
|
|
|
|
|
|
|
jsonw_name(json_wtr, "map_ids");
|
|
|
|
jsonw_start_array(json_wtr); /* map_ids */
|
libbpf: Hashmap interface update to allow both long and void* keys/values
An update for libbpf's hashmap interface from void* -> void* to a
polymorphic one, allowing both long and void* keys and values.
This simplifies many use cases in libbpf as hashmaps there are mostly
integer to integer.
Perf copies hashmap implementation from libbpf and has to be
updated as well.
Changes to libbpf, selftests/bpf and perf are packed as a single
commit to avoid compilation issues with any future bisect.
Polymorphic interface is acheived by hiding hashmap interface
functions behind auxiliary macros that take care of necessary
type casts, for example:
#define hashmap_cast_ptr(p) \
({ \
_Static_assert((p) == NULL || sizeof(*(p)) == sizeof(long),\
#p " pointee should be a long-sized integer or a pointer"); \
(long *)(p); \
})
bool hashmap_find(const struct hashmap *map, long key, long *value);
#define hashmap__find(map, key, value) \
hashmap_find((map), (long)(key), hashmap_cast_ptr(value))
- hashmap__find macro casts key and value parameters to long
and long* respectively
- hashmap_cast_ptr ensures that value pointer points to a memory
of appropriate size.
This hack was suggested by Andrii Nakryiko in [1].
This is a follow up for [2].
[1] https://lore.kernel.org/bpf/CAEf4BzZ8KFneEJxFAaNCCFPGqp20hSpS2aCj76uRk3-qZUH5xg@mail.gmail.com/
[2] https://lore.kernel.org/bpf/af1facf9-7bc8-8a3d-0db4-7b3f333589a2@meta.com/T/#m65b28f1d6d969fcd318b556db6a3ad499a42607d
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20221109142611.879983-2-eddyz87@gmail.com
2022-11-09 22:26:09 +08:00
|
|
|
hashmap__for_each_key_entry(btf_map_table, entry, info->id) {
|
|
|
|
jsonw_uint(json_wtr, entry->value);
|
2019-08-20 17:31:54 +08:00
|
|
|
}
|
|
|
|
jsonw_end_array(json_wtr); /* map_ids */
|
tools/bpftool: Show info for processes holding BPF map/prog/link/btf FDs
Add bpf_iter-based way to find all the processes that hold open FDs against
BPF object (map, prog, link, btf). bpftool always attempts to discover this,
but will silently give up if kernel doesn't yet support bpf_iter BPF programs.
Process name and PID are emitted for each process (task group).
Sample output for each of 4 BPF objects:
$ sudo ./bpftool prog show
2694: cgroup_device tag 8c42dee26e8cd4c2 gpl
loaded_at 2020-06-16T15:34:32-0700 uid 0
xlated 648B jited 409B memlock 4096B
pids systemd(1)
2907: cgroup_skb name egress tag 9ad187367cf2b9e8 gpl
loaded_at 2020-06-16T18:06:54-0700 uid 0
xlated 48B jited 59B memlock 4096B map_ids 2436
btf_id 1202
pids test_progs(2238417), test_progs(2238445)
$ sudo ./bpftool map show
2436: array name test_cgr.bss flags 0x400
key 4B value 8B max_entries 1 memlock 8192B
btf_id 1202
pids test_progs(2238417), test_progs(2238445)
2445: array name pid_iter.rodata flags 0x480
key 4B value 4B max_entries 1 memlock 8192B
btf_id 1214 frozen
pids bpftool(2239612)
$ sudo ./bpftool link show
61: cgroup prog 2908
cgroup_id 375301 attach_type egress
pids test_progs(2238417), test_progs(2238445)
62: cgroup prog 2908
cgroup_id 375344 attach_type egress
pids test_progs(2238417), test_progs(2238445)
$ sudo ./bpftool btf show
1202: size 1527B prog_ids 2908,2907 map_ids 2436
pids test_progs(2238417), test_progs(2238445)
1242: size 34684B
pids bpftool(2258892)
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Reviewed-by: Quentin Monnet <quentin@isovalent.com>
Link: https://lore.kernel.org/bpf/20200619231703.738941-9-andriin@fb.com
2020-06-20 07:17:02 +08:00
|
|
|
|
bpftool: Switch to libbpf's hashmap for PIDs/names references
In order to show PIDs and names for processes holding references to BPF
programs, maps, links, or BTF objects, bpftool creates hash maps to
store all relevant information. This commit is part of a set that
transitions from the kernel's hash map implementation to the one coming
with libbpf.
The motivation is to make bpftool less dependent of kernel headers, to
ease the path to a potential out-of-tree mirror, like libbpf has.
This is the third and final step of the transition, in which we convert
the hash maps used for storing the information about the processes
holding references to BPF objects (programs, maps, links, BTF), and at
last we drop the inclusion of tools/include/linux/hashtable.h.
Note: Checkpatch complains about the use of __weak declarations, and the
missing empty lines after the bunch of empty function declarations when
compiling without the BPF skeletons (none of these were introduced in
this patch). We want to keep things as they are, and the reports should
be safe to ignore.
Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20211023205154.6710-6-quentin@isovalent.com
2021-10-24 04:51:54 +08:00
|
|
|
emit_obj_refs_json(refs_table, info->id, json_wtr); /* pids */
|
tools/bpftool: Show info for processes holding BPF map/prog/link/btf FDs
Add bpf_iter-based way to find all the processes that hold open FDs against
BPF object (map, prog, link, btf). bpftool always attempts to discover this,
but will silently give up if kernel doesn't yet support bpf_iter BPF programs.
Process name and PID are emitted for each process (task group).
Sample output for each of 4 BPF objects:
$ sudo ./bpftool prog show
2694: cgroup_device tag 8c42dee26e8cd4c2 gpl
loaded_at 2020-06-16T15:34:32-0700 uid 0
xlated 648B jited 409B memlock 4096B
pids systemd(1)
2907: cgroup_skb name egress tag 9ad187367cf2b9e8 gpl
loaded_at 2020-06-16T18:06:54-0700 uid 0
xlated 48B jited 59B memlock 4096B map_ids 2436
btf_id 1202
pids test_progs(2238417), test_progs(2238445)
$ sudo ./bpftool map show
2436: array name test_cgr.bss flags 0x400
key 4B value 8B max_entries 1 memlock 8192B
btf_id 1202
pids test_progs(2238417), test_progs(2238445)
2445: array name pid_iter.rodata flags 0x480
key 4B value 4B max_entries 1 memlock 8192B
btf_id 1214 frozen
pids bpftool(2239612)
$ sudo ./bpftool link show
61: cgroup prog 2908
cgroup_id 375301 attach_type egress
pids test_progs(2238417), test_progs(2238445)
62: cgroup prog 2908
cgroup_id 375344 attach_type egress
pids test_progs(2238417), test_progs(2238445)
$ sudo ./bpftool btf show
1202: size 1527B prog_ids 2908,2907 map_ids 2436
pids test_progs(2238417), test_progs(2238445)
1242: size 34684B
pids bpftool(2258892)
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Reviewed-by: Quentin Monnet <quentin@isovalent.com>
Link: https://lore.kernel.org/bpf/20200619231703.738941-9-andriin@fb.com
2020-06-20 07:17:02 +08:00
|
|
|
|
tools/bpftool: Add support for in-kernel and named BTF in `btf show`
Display vmlinux BTF name and kernel module names when listing available BTFs
on the system.
In human-readable output mode, module BTFs are reported with "name
[module-name]", while vmlinux BTF will be reported as "name [vmlinux]".
Square brackets are added by bpftool and follow kernel convention when
displaying modules in human-readable text outputs.
[vmuser@archvm bpf]$ sudo ../../../bpf/bpftool/bpftool btf s
1: name [vmlinux] size 4082281B
6: size 2365B prog_ids 8,6 map_ids 3
7: name [button] size 46895B
8: name [pcspkr] size 42328B
9: name [serio_raw] size 39375B
10: name [floppy] size 57185B
11: name [i2c_core] size 76186B
12: name [crc32c_intel] size 16036B
13: name [i2c_piix4] size 50497B
14: name [irqbypass] size 14124B
15: name [kvm] size 197985B
16: name [kvm_intel] size 123564B
17: name [cryptd] size 42466B
18: name [crypto_simd] size 17187B
19: name [glue_helper] size 39205B
20: name [aesni_intel] size 41034B
25: size 36150B
pids bpftool(2519)
In JSON mode, two fields (boolean "kernel" and string "name") are reported for
each BTF object. vmlinux BTF is reported with name "vmlinux" (kernel itself
returns and empty name for vmlinux BTF).
[vmuser@archvm bpf]$ sudo ../../../bpf/bpftool/bpftool btf s -jp
[{
"id": 1,
"size": 4082281,
"prog_ids": [],
"map_ids": [],
"kernel": true,
"name": "vmlinux"
},{
"id": 6,
"size": 2365,
"prog_ids": [8,6
],
"map_ids": [3
],
"kernel": false
},{
"id": 7,
"size": 46895,
"prog_ids": [],
"map_ids": [],
"kernel": true,
"name": "button"
},{
...
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Tested-by: Alan Maguire <alan.maguire@oracle.com>
Link: https://lore.kernel.org/bpf/20201110011932.3201430-6-andrii@kernel.org
2020-11-10 09:19:32 +08:00
|
|
|
jsonw_bool_field(json_wtr, "kernel", info->kernel_btf);
|
|
|
|
|
|
|
|
if (name && name[0])
|
|
|
|
jsonw_string_field(json_wtr, "name", name);
|
|
|
|
|
2019-08-20 17:31:54 +08:00
|
|
|
jsonw_end_object(json_wtr); /* btf object */
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2021-10-24 04:51:53 +08:00
|
|
|
show_btf(int fd, struct hashmap *btf_prog_table,
|
|
|
|
struct hashmap *btf_map_table)
|
2019-08-20 17:31:54 +08:00
|
|
|
{
|
tools/bpftool: Add support for in-kernel and named BTF in `btf show`
Display vmlinux BTF name and kernel module names when listing available BTFs
on the system.
In human-readable output mode, module BTFs are reported with "name
[module-name]", while vmlinux BTF will be reported as "name [vmlinux]".
Square brackets are added by bpftool and follow kernel convention when
displaying modules in human-readable text outputs.
[vmuser@archvm bpf]$ sudo ../../../bpf/bpftool/bpftool btf s
1: name [vmlinux] size 4082281B
6: size 2365B prog_ids 8,6 map_ids 3
7: name [button] size 46895B
8: name [pcspkr] size 42328B
9: name [serio_raw] size 39375B
10: name [floppy] size 57185B
11: name [i2c_core] size 76186B
12: name [crc32c_intel] size 16036B
13: name [i2c_piix4] size 50497B
14: name [irqbypass] size 14124B
15: name [kvm] size 197985B
16: name [kvm_intel] size 123564B
17: name [cryptd] size 42466B
18: name [crypto_simd] size 17187B
19: name [glue_helper] size 39205B
20: name [aesni_intel] size 41034B
25: size 36150B
pids bpftool(2519)
In JSON mode, two fields (boolean "kernel" and string "name") are reported for
each BTF object. vmlinux BTF is reported with name "vmlinux" (kernel itself
returns and empty name for vmlinux BTF).
[vmuser@archvm bpf]$ sudo ../../../bpf/bpftool/bpftool btf s -jp
[{
"id": 1,
"size": 4082281,
"prog_ids": [],
"map_ids": [],
"kernel": true,
"name": "vmlinux"
},{
"id": 6,
"size": 2365,
"prog_ids": [8,6
],
"map_ids": [3
],
"kernel": false
},{
"id": 7,
"size": 46895,
"prog_ids": [],
"map_ids": [],
"kernel": true,
"name": "button"
},{
...
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Tested-by: Alan Maguire <alan.maguire@oracle.com>
Link: https://lore.kernel.org/bpf/20201110011932.3201430-6-andrii@kernel.org
2020-11-10 09:19:32 +08:00
|
|
|
struct bpf_btf_info info;
|
2019-08-20 17:31:54 +08:00
|
|
|
__u32 len = sizeof(info);
|
tools/bpftool: Add support for in-kernel and named BTF in `btf show`
Display vmlinux BTF name and kernel module names when listing available BTFs
on the system.
In human-readable output mode, module BTFs are reported with "name
[module-name]", while vmlinux BTF will be reported as "name [vmlinux]".
Square brackets are added by bpftool and follow kernel convention when
displaying modules in human-readable text outputs.
[vmuser@archvm bpf]$ sudo ../../../bpf/bpftool/bpftool btf s
1: name [vmlinux] size 4082281B
6: size 2365B prog_ids 8,6 map_ids 3
7: name [button] size 46895B
8: name [pcspkr] size 42328B
9: name [serio_raw] size 39375B
10: name [floppy] size 57185B
11: name [i2c_core] size 76186B
12: name [crc32c_intel] size 16036B
13: name [i2c_piix4] size 50497B
14: name [irqbypass] size 14124B
15: name [kvm] size 197985B
16: name [kvm_intel] size 123564B
17: name [cryptd] size 42466B
18: name [crypto_simd] size 17187B
19: name [glue_helper] size 39205B
20: name [aesni_intel] size 41034B
25: size 36150B
pids bpftool(2519)
In JSON mode, two fields (boolean "kernel" and string "name") are reported for
each BTF object. vmlinux BTF is reported with name "vmlinux" (kernel itself
returns and empty name for vmlinux BTF).
[vmuser@archvm bpf]$ sudo ../../../bpf/bpftool/bpftool btf s -jp
[{
"id": 1,
"size": 4082281,
"prog_ids": [],
"map_ids": [],
"kernel": true,
"name": "vmlinux"
},{
"id": 6,
"size": 2365,
"prog_ids": [8,6
],
"map_ids": [3
],
"kernel": false
},{
"id": 7,
"size": 46895,
"prog_ids": [],
"map_ids": [],
"kernel": true,
"name": "button"
},{
...
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Tested-by: Alan Maguire <alan.maguire@oracle.com>
Link: https://lore.kernel.org/bpf/20201110011932.3201430-6-andrii@kernel.org
2020-11-10 09:19:32 +08:00
|
|
|
char name[64];
|
2019-08-20 17:31:54 +08:00
|
|
|
int err;
|
|
|
|
|
tools/bpftool: Add support for in-kernel and named BTF in `btf show`
Display vmlinux BTF name and kernel module names when listing available BTFs
on the system.
In human-readable output mode, module BTFs are reported with "name
[module-name]", while vmlinux BTF will be reported as "name [vmlinux]".
Square brackets are added by bpftool and follow kernel convention when
displaying modules in human-readable text outputs.
[vmuser@archvm bpf]$ sudo ../../../bpf/bpftool/bpftool btf s
1: name [vmlinux] size 4082281B
6: size 2365B prog_ids 8,6 map_ids 3
7: name [button] size 46895B
8: name [pcspkr] size 42328B
9: name [serio_raw] size 39375B
10: name [floppy] size 57185B
11: name [i2c_core] size 76186B
12: name [crc32c_intel] size 16036B
13: name [i2c_piix4] size 50497B
14: name [irqbypass] size 14124B
15: name [kvm] size 197985B
16: name [kvm_intel] size 123564B
17: name [cryptd] size 42466B
18: name [crypto_simd] size 17187B
19: name [glue_helper] size 39205B
20: name [aesni_intel] size 41034B
25: size 36150B
pids bpftool(2519)
In JSON mode, two fields (boolean "kernel" and string "name") are reported for
each BTF object. vmlinux BTF is reported with name "vmlinux" (kernel itself
returns and empty name for vmlinux BTF).
[vmuser@archvm bpf]$ sudo ../../../bpf/bpftool/bpftool btf s -jp
[{
"id": 1,
"size": 4082281,
"prog_ids": [],
"map_ids": [],
"kernel": true,
"name": "vmlinux"
},{
"id": 6,
"size": 2365,
"prog_ids": [8,6
],
"map_ids": [3
],
"kernel": false
},{
"id": 7,
"size": 46895,
"prog_ids": [],
"map_ids": [],
"kernel": true,
"name": "button"
},{
...
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Tested-by: Alan Maguire <alan.maguire@oracle.com>
Link: https://lore.kernel.org/bpf/20201110011932.3201430-6-andrii@kernel.org
2020-11-10 09:19:32 +08:00
|
|
|
memset(&info, 0, sizeof(info));
|
2019-08-20 17:31:54 +08:00
|
|
|
err = bpf_obj_get_info_by_fd(fd, &info, &len);
|
|
|
|
if (err) {
|
|
|
|
p_err("can't get BTF object info: %s", strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
tools/bpftool: Add support for in-kernel and named BTF in `btf show`
Display vmlinux BTF name and kernel module names when listing available BTFs
on the system.
In human-readable output mode, module BTFs are reported with "name
[module-name]", while vmlinux BTF will be reported as "name [vmlinux]".
Square brackets are added by bpftool and follow kernel convention when
displaying modules in human-readable text outputs.
[vmuser@archvm bpf]$ sudo ../../../bpf/bpftool/bpftool btf s
1: name [vmlinux] size 4082281B
6: size 2365B prog_ids 8,6 map_ids 3
7: name [button] size 46895B
8: name [pcspkr] size 42328B
9: name [serio_raw] size 39375B
10: name [floppy] size 57185B
11: name [i2c_core] size 76186B
12: name [crc32c_intel] size 16036B
13: name [i2c_piix4] size 50497B
14: name [irqbypass] size 14124B
15: name [kvm] size 197985B
16: name [kvm_intel] size 123564B
17: name [cryptd] size 42466B
18: name [crypto_simd] size 17187B
19: name [glue_helper] size 39205B
20: name [aesni_intel] size 41034B
25: size 36150B
pids bpftool(2519)
In JSON mode, two fields (boolean "kernel" and string "name") are reported for
each BTF object. vmlinux BTF is reported with name "vmlinux" (kernel itself
returns and empty name for vmlinux BTF).
[vmuser@archvm bpf]$ sudo ../../../bpf/bpftool/bpftool btf s -jp
[{
"id": 1,
"size": 4082281,
"prog_ids": [],
"map_ids": [],
"kernel": true,
"name": "vmlinux"
},{
"id": 6,
"size": 2365,
"prog_ids": [8,6
],
"map_ids": [3
],
"kernel": false
},{
"id": 7,
"size": 46895,
"prog_ids": [],
"map_ids": [],
"kernel": true,
"name": "button"
},{
...
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Tested-by: Alan Maguire <alan.maguire@oracle.com>
Link: https://lore.kernel.org/bpf/20201110011932.3201430-6-andrii@kernel.org
2020-11-10 09:19:32 +08:00
|
|
|
/* if kernel support emitting BTF object name, pass name pointer */
|
|
|
|
if (info.name_len) {
|
|
|
|
memset(&info, 0, sizeof(info));
|
|
|
|
info.name_len = sizeof(name);
|
|
|
|
info.name = ptr_to_u64(name);
|
|
|
|
len = sizeof(info);
|
|
|
|
|
|
|
|
err = bpf_obj_get_info_by_fd(fd, &info, &len);
|
|
|
|
if (err) {
|
|
|
|
p_err("can't get BTF object info: %s", strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2019-08-20 17:31:54 +08:00
|
|
|
|
|
|
|
if (json_output)
|
|
|
|
show_btf_json(&info, fd, btf_prog_table, btf_map_table);
|
|
|
|
else
|
|
|
|
show_btf_plain(&info, fd, btf_prog_table, btf_map_table);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int do_show(int argc, char **argv)
|
|
|
|
{
|
2021-10-24 04:51:53 +08:00
|
|
|
struct hashmap *btf_prog_table;
|
|
|
|
struct hashmap *btf_map_table;
|
2019-08-20 17:31:54 +08:00
|
|
|
int err, fd = -1;
|
|
|
|
__u32 id = 0;
|
|
|
|
|
|
|
|
if (argc == 2) {
|
|
|
|
fd = btf_parse_fd(&argc, &argv);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc) {
|
|
|
|
if (fd >= 0)
|
|
|
|
close(fd);
|
|
|
|
return BAD_ARG();
|
|
|
|
}
|
|
|
|
|
2021-10-24 04:51:53 +08:00
|
|
|
btf_prog_table = hashmap__new(hash_fn_for_key_as_id,
|
|
|
|
equal_fn_for_key_as_id, NULL);
|
|
|
|
btf_map_table = hashmap__new(hash_fn_for_key_as_id,
|
|
|
|
equal_fn_for_key_as_id, NULL);
|
2022-01-07 23:26:20 +08:00
|
|
|
if (IS_ERR(btf_prog_table) || IS_ERR(btf_map_table)) {
|
2021-10-24 04:51:53 +08:00
|
|
|
hashmap__free(btf_prog_table);
|
|
|
|
hashmap__free(btf_map_table);
|
|
|
|
if (fd >= 0)
|
|
|
|
close(fd);
|
|
|
|
p_err("failed to create hashmap for object references");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
err = build_btf_tables(btf_prog_table, btf_map_table);
|
2019-08-20 17:31:54 +08:00
|
|
|
if (err) {
|
|
|
|
if (fd >= 0)
|
|
|
|
close(fd);
|
|
|
|
return err;
|
|
|
|
}
|
tools/bpftool: Show info for processes holding BPF map/prog/link/btf FDs
Add bpf_iter-based way to find all the processes that hold open FDs against
BPF object (map, prog, link, btf). bpftool always attempts to discover this,
but will silently give up if kernel doesn't yet support bpf_iter BPF programs.
Process name and PID are emitted for each process (task group).
Sample output for each of 4 BPF objects:
$ sudo ./bpftool prog show
2694: cgroup_device tag 8c42dee26e8cd4c2 gpl
loaded_at 2020-06-16T15:34:32-0700 uid 0
xlated 648B jited 409B memlock 4096B
pids systemd(1)
2907: cgroup_skb name egress tag 9ad187367cf2b9e8 gpl
loaded_at 2020-06-16T18:06:54-0700 uid 0
xlated 48B jited 59B memlock 4096B map_ids 2436
btf_id 1202
pids test_progs(2238417), test_progs(2238445)
$ sudo ./bpftool map show
2436: array name test_cgr.bss flags 0x400
key 4B value 8B max_entries 1 memlock 8192B
btf_id 1202
pids test_progs(2238417), test_progs(2238445)
2445: array name pid_iter.rodata flags 0x480
key 4B value 4B max_entries 1 memlock 8192B
btf_id 1214 frozen
pids bpftool(2239612)
$ sudo ./bpftool link show
61: cgroup prog 2908
cgroup_id 375301 attach_type egress
pids test_progs(2238417), test_progs(2238445)
62: cgroup prog 2908
cgroup_id 375344 attach_type egress
pids test_progs(2238417), test_progs(2238445)
$ sudo ./bpftool btf show
1202: size 1527B prog_ids 2908,2907 map_ids 2436
pids test_progs(2238417), test_progs(2238445)
1242: size 34684B
pids bpftool(2258892)
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Reviewed-by: Quentin Monnet <quentin@isovalent.com>
Link: https://lore.kernel.org/bpf/20200619231703.738941-9-andriin@fb.com
2020-06-20 07:17:02 +08:00
|
|
|
build_obj_refs_table(&refs_table, BPF_OBJ_BTF);
|
2019-08-20 17:31:54 +08:00
|
|
|
|
|
|
|
if (fd >= 0) {
|
2021-10-24 04:51:53 +08:00
|
|
|
err = show_btf(fd, btf_prog_table, btf_map_table);
|
2019-08-20 17:31:54 +08:00
|
|
|
close(fd);
|
|
|
|
goto exit_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (json_output)
|
|
|
|
jsonw_start_array(json_wtr); /* root array */
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
err = bpf_btf_get_next_id(id, &id);
|
|
|
|
if (err) {
|
|
|
|
if (errno == ENOENT) {
|
|
|
|
err = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
p_err("can't get next BTF object: %s%s",
|
|
|
|
strerror(errno),
|
|
|
|
errno == EINVAL ? " -- kernel too old?" : "");
|
|
|
|
err = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = bpf_btf_get_fd_by_id(id);
|
|
|
|
if (fd < 0) {
|
|
|
|
if (errno == ENOENT)
|
|
|
|
continue;
|
|
|
|
p_err("can't get BTF object by id (%u): %s",
|
|
|
|
id, strerror(errno));
|
|
|
|
err = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-10-24 04:51:53 +08:00
|
|
|
err = show_btf(fd, btf_prog_table, btf_map_table);
|
2019-08-20 17:31:54 +08:00
|
|
|
close(fd);
|
|
|
|
if (err)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (json_output)
|
|
|
|
jsonw_end_array(json_wtr); /* root array */
|
|
|
|
|
|
|
|
exit_free:
|
2021-10-24 04:51:53 +08:00
|
|
|
hashmap__free(btf_prog_table);
|
|
|
|
hashmap__free(btf_map_table);
|
bpftool: Switch to libbpf's hashmap for PIDs/names references
In order to show PIDs and names for processes holding references to BPF
programs, maps, links, or BTF objects, bpftool creates hash maps to
store all relevant information. This commit is part of a set that
transitions from the kernel's hash map implementation to the one coming
with libbpf.
The motivation is to make bpftool less dependent of kernel headers, to
ease the path to a potential out-of-tree mirror, like libbpf has.
This is the third and final step of the transition, in which we convert
the hash maps used for storing the information about the processes
holding references to BPF objects (programs, maps, links, BTF), and at
last we drop the inclusion of tools/include/linux/hashtable.h.
Note: Checkpatch complains about the use of __weak declarations, and the
missing empty lines after the bunch of empty function declarations when
compiling without the BPF skeletons (none of these were introduced in
this patch). We want to keep things as they are, and the reports should
be safe to ignore.
Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20211023205154.6710-6-quentin@isovalent.com
2021-10-24 04:51:54 +08:00
|
|
|
delete_obj_refs_table(refs_table);
|
2019-08-20 17:31:54 +08:00
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2019-04-26 06:30:08 +08:00
|
|
|
static int do_help(int argc, char **argv)
|
|
|
|
{
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_null(json_wtr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr,
|
2020-05-23 09:07:51 +08:00
|
|
|
"Usage: %1$s %2$s { show | list } [id BTF_ID]\n"
|
|
|
|
" %1$s %2$s dump BTF_SRC [format FORMAT]\n"
|
|
|
|
" %1$s %2$s help\n"
|
2019-04-26 06:30:08 +08:00
|
|
|
"\n"
|
|
|
|
" BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"
|
2019-05-25 02:59:05 +08:00
|
|
|
" FORMAT := { raw | c }\n"
|
2019-04-26 06:30:08 +08:00
|
|
|
" " HELP_SPEC_MAP "\n"
|
|
|
|
" " HELP_SPEC_PROGRAM "\n"
|
2021-07-31 05:54:34 +08:00
|
|
|
" " HELP_SPEC_OPTIONS " |\n"
|
|
|
|
" {-B|--base-btf} }\n"
|
2019-04-26 06:30:08 +08:00
|
|
|
"",
|
2020-05-23 09:07:51 +08:00
|
|
|
bin_name, "btf");
|
2019-04-26 06:30:08 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct cmd cmds[] = {
|
2019-08-20 17:31:54 +08:00
|
|
|
{ "show", do_show },
|
|
|
|
{ "list", do_show },
|
2019-04-26 06:30:08 +08:00
|
|
|
{ "help", do_help },
|
|
|
|
{ "dump", do_dump },
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
int do_btf(int argc, char **argv)
|
|
|
|
{
|
|
|
|
return cmd_select(cmds, argc, argv, do_help);
|
|
|
|
}
|