162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 262306a36Sopenharmony_ci/* Copyright (C) 2019 Facebook */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <errno.h> 562306a36Sopenharmony_ci#include <fcntl.h> 662306a36Sopenharmony_ci#include <linux/err.h> 762306a36Sopenharmony_ci#include <stdbool.h> 862306a36Sopenharmony_ci#include <stdio.h> 962306a36Sopenharmony_ci#include <string.h> 1062306a36Sopenharmony_ci#include <unistd.h> 1162306a36Sopenharmony_ci#include <linux/btf.h> 1262306a36Sopenharmony_ci#include <sys/types.h> 1362306a36Sopenharmony_ci#include <sys/stat.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <bpf/bpf.h> 1662306a36Sopenharmony_ci#include <bpf/btf.h> 1762306a36Sopenharmony_ci#include <bpf/hashmap.h> 1862306a36Sopenharmony_ci#include <bpf/libbpf.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "json_writer.h" 2162306a36Sopenharmony_ci#include "main.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic const char * const btf_kind_str[NR_BTF_KINDS] = { 2462306a36Sopenharmony_ci [BTF_KIND_UNKN] = "UNKNOWN", 2562306a36Sopenharmony_ci [BTF_KIND_INT] = "INT", 2662306a36Sopenharmony_ci [BTF_KIND_PTR] = "PTR", 2762306a36Sopenharmony_ci [BTF_KIND_ARRAY] = "ARRAY", 2862306a36Sopenharmony_ci [BTF_KIND_STRUCT] = "STRUCT", 2962306a36Sopenharmony_ci [BTF_KIND_UNION] = "UNION", 3062306a36Sopenharmony_ci [BTF_KIND_ENUM] = "ENUM", 3162306a36Sopenharmony_ci [BTF_KIND_FWD] = "FWD", 3262306a36Sopenharmony_ci [BTF_KIND_TYPEDEF] = "TYPEDEF", 3362306a36Sopenharmony_ci [BTF_KIND_VOLATILE] = "VOLATILE", 3462306a36Sopenharmony_ci [BTF_KIND_CONST] = "CONST", 3562306a36Sopenharmony_ci [BTF_KIND_RESTRICT] = "RESTRICT", 3662306a36Sopenharmony_ci [BTF_KIND_FUNC] = "FUNC", 3762306a36Sopenharmony_ci [BTF_KIND_FUNC_PROTO] = "FUNC_PROTO", 3862306a36Sopenharmony_ci [BTF_KIND_VAR] = "VAR", 3962306a36Sopenharmony_ci [BTF_KIND_DATASEC] = "DATASEC", 4062306a36Sopenharmony_ci [BTF_KIND_FLOAT] = "FLOAT", 4162306a36Sopenharmony_ci [BTF_KIND_DECL_TAG] = "DECL_TAG", 4262306a36Sopenharmony_ci [BTF_KIND_TYPE_TAG] = "TYPE_TAG", 4362306a36Sopenharmony_ci [BTF_KIND_ENUM64] = "ENUM64", 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic const char *btf_int_enc_str(__u8 encoding) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci switch (encoding) { 4962306a36Sopenharmony_ci case 0: 5062306a36Sopenharmony_ci return "(none)"; 5162306a36Sopenharmony_ci case BTF_INT_SIGNED: 5262306a36Sopenharmony_ci return "SIGNED"; 5362306a36Sopenharmony_ci case BTF_INT_CHAR: 5462306a36Sopenharmony_ci return "CHAR"; 5562306a36Sopenharmony_ci case BTF_INT_BOOL: 5662306a36Sopenharmony_ci return "BOOL"; 5762306a36Sopenharmony_ci default: 5862306a36Sopenharmony_ci return "UNKN"; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic const char *btf_var_linkage_str(__u32 linkage) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci switch (linkage) { 6562306a36Sopenharmony_ci case BTF_VAR_STATIC: 6662306a36Sopenharmony_ci return "static"; 6762306a36Sopenharmony_ci case BTF_VAR_GLOBAL_ALLOCATED: 6862306a36Sopenharmony_ci return "global"; 6962306a36Sopenharmony_ci case BTF_VAR_GLOBAL_EXTERN: 7062306a36Sopenharmony_ci return "extern"; 7162306a36Sopenharmony_ci default: 7262306a36Sopenharmony_ci return "(unknown)"; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic const char *btf_func_linkage_str(const struct btf_type *t) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci switch (btf_vlen(t)) { 7962306a36Sopenharmony_ci case BTF_FUNC_STATIC: 8062306a36Sopenharmony_ci return "static"; 8162306a36Sopenharmony_ci case BTF_FUNC_GLOBAL: 8262306a36Sopenharmony_ci return "global"; 8362306a36Sopenharmony_ci case BTF_FUNC_EXTERN: 8462306a36Sopenharmony_ci return "extern"; 8562306a36Sopenharmony_ci default: 8662306a36Sopenharmony_ci return "(unknown)"; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic const char *btf_str(const struct btf *btf, __u32 off) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci if (!off) 9362306a36Sopenharmony_ci return "(anon)"; 9462306a36Sopenharmony_ci return btf__name_by_offset(btf, off) ? : "(invalid)"; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int btf_kind_safe(int kind) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci return kind <= BTF_KIND_MAX ? kind : BTF_KIND_UNKN; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic int dump_btf_type(const struct btf *btf, __u32 id, 10362306a36Sopenharmony_ci const struct btf_type *t) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci json_writer_t *w = json_wtr; 10662306a36Sopenharmony_ci int kind = btf_kind(t); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (json_output) { 10962306a36Sopenharmony_ci jsonw_start_object(w); 11062306a36Sopenharmony_ci jsonw_uint_field(w, "id", id); 11162306a36Sopenharmony_ci jsonw_string_field(w, "kind", btf_kind_str[btf_kind_safe(kind)]); 11262306a36Sopenharmony_ci jsonw_string_field(w, "name", btf_str(btf, t->name_off)); 11362306a36Sopenharmony_ci } else { 11462306a36Sopenharmony_ci printf("[%u] %s '%s'", id, btf_kind_str[btf_kind_safe(kind)], 11562306a36Sopenharmony_ci btf_str(btf, t->name_off)); 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci switch (kind) { 11962306a36Sopenharmony_ci case BTF_KIND_INT: { 12062306a36Sopenharmony_ci __u32 v = *(__u32 *)(t + 1); 12162306a36Sopenharmony_ci const char *enc; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci enc = btf_int_enc_str(BTF_INT_ENCODING(v)); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (json_output) { 12662306a36Sopenharmony_ci jsonw_uint_field(w, "size", t->size); 12762306a36Sopenharmony_ci jsonw_uint_field(w, "bits_offset", BTF_INT_OFFSET(v)); 12862306a36Sopenharmony_ci jsonw_uint_field(w, "nr_bits", BTF_INT_BITS(v)); 12962306a36Sopenharmony_ci jsonw_string_field(w, "encoding", enc); 13062306a36Sopenharmony_ci } else { 13162306a36Sopenharmony_ci printf(" size=%u bits_offset=%u nr_bits=%u encoding=%s", 13262306a36Sopenharmony_ci t->size, BTF_INT_OFFSET(v), BTF_INT_BITS(v), 13362306a36Sopenharmony_ci enc); 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci break; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci case BTF_KIND_PTR: 13862306a36Sopenharmony_ci case BTF_KIND_CONST: 13962306a36Sopenharmony_ci case BTF_KIND_VOLATILE: 14062306a36Sopenharmony_ci case BTF_KIND_RESTRICT: 14162306a36Sopenharmony_ci case BTF_KIND_TYPEDEF: 14262306a36Sopenharmony_ci case BTF_KIND_TYPE_TAG: 14362306a36Sopenharmony_ci if (json_output) 14462306a36Sopenharmony_ci jsonw_uint_field(w, "type_id", t->type); 14562306a36Sopenharmony_ci else 14662306a36Sopenharmony_ci printf(" type_id=%u", t->type); 14762306a36Sopenharmony_ci break; 14862306a36Sopenharmony_ci case BTF_KIND_ARRAY: { 14962306a36Sopenharmony_ci const struct btf_array *arr = (const void *)(t + 1); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (json_output) { 15262306a36Sopenharmony_ci jsonw_uint_field(w, "type_id", arr->type); 15362306a36Sopenharmony_ci jsonw_uint_field(w, "index_type_id", arr->index_type); 15462306a36Sopenharmony_ci jsonw_uint_field(w, "nr_elems", arr->nelems); 15562306a36Sopenharmony_ci } else { 15662306a36Sopenharmony_ci printf(" type_id=%u index_type_id=%u nr_elems=%u", 15762306a36Sopenharmony_ci arr->type, arr->index_type, arr->nelems); 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci break; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci case BTF_KIND_STRUCT: 16262306a36Sopenharmony_ci case BTF_KIND_UNION: { 16362306a36Sopenharmony_ci const struct btf_member *m = (const void *)(t + 1); 16462306a36Sopenharmony_ci __u16 vlen = BTF_INFO_VLEN(t->info); 16562306a36Sopenharmony_ci int i; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (json_output) { 16862306a36Sopenharmony_ci jsonw_uint_field(w, "size", t->size); 16962306a36Sopenharmony_ci jsonw_uint_field(w, "vlen", vlen); 17062306a36Sopenharmony_ci jsonw_name(w, "members"); 17162306a36Sopenharmony_ci jsonw_start_array(w); 17262306a36Sopenharmony_ci } else { 17362306a36Sopenharmony_ci printf(" size=%u vlen=%u", t->size, vlen); 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci for (i = 0; i < vlen; i++, m++) { 17662306a36Sopenharmony_ci const char *name = btf_str(btf, m->name_off); 17762306a36Sopenharmony_ci __u32 bit_off, bit_sz; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (BTF_INFO_KFLAG(t->info)) { 18062306a36Sopenharmony_ci bit_off = BTF_MEMBER_BIT_OFFSET(m->offset); 18162306a36Sopenharmony_ci bit_sz = BTF_MEMBER_BITFIELD_SIZE(m->offset); 18262306a36Sopenharmony_ci } else { 18362306a36Sopenharmony_ci bit_off = m->offset; 18462306a36Sopenharmony_ci bit_sz = 0; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (json_output) { 18862306a36Sopenharmony_ci jsonw_start_object(w); 18962306a36Sopenharmony_ci jsonw_string_field(w, "name", name); 19062306a36Sopenharmony_ci jsonw_uint_field(w, "type_id", m->type); 19162306a36Sopenharmony_ci jsonw_uint_field(w, "bits_offset", bit_off); 19262306a36Sopenharmony_ci if (bit_sz) { 19362306a36Sopenharmony_ci jsonw_uint_field(w, "bitfield_size", 19462306a36Sopenharmony_ci bit_sz); 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci jsonw_end_object(w); 19762306a36Sopenharmony_ci } else { 19862306a36Sopenharmony_ci printf("\n\t'%s' type_id=%u bits_offset=%u", 19962306a36Sopenharmony_ci name, m->type, bit_off); 20062306a36Sopenharmony_ci if (bit_sz) 20162306a36Sopenharmony_ci printf(" bitfield_size=%u", bit_sz); 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci if (json_output) 20562306a36Sopenharmony_ci jsonw_end_array(w); 20662306a36Sopenharmony_ci break; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci case BTF_KIND_ENUM: { 20962306a36Sopenharmony_ci const struct btf_enum *v = (const void *)(t + 1); 21062306a36Sopenharmony_ci __u16 vlen = BTF_INFO_VLEN(t->info); 21162306a36Sopenharmony_ci const char *encoding; 21262306a36Sopenharmony_ci int i; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED"; 21562306a36Sopenharmony_ci if (json_output) { 21662306a36Sopenharmony_ci jsonw_string_field(w, "encoding", encoding); 21762306a36Sopenharmony_ci jsonw_uint_field(w, "size", t->size); 21862306a36Sopenharmony_ci jsonw_uint_field(w, "vlen", vlen); 21962306a36Sopenharmony_ci jsonw_name(w, "values"); 22062306a36Sopenharmony_ci jsonw_start_array(w); 22162306a36Sopenharmony_ci } else { 22262306a36Sopenharmony_ci printf(" encoding=%s size=%u vlen=%u", encoding, t->size, vlen); 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci for (i = 0; i < vlen; i++, v++) { 22562306a36Sopenharmony_ci const char *name = btf_str(btf, v->name_off); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (json_output) { 22862306a36Sopenharmony_ci jsonw_start_object(w); 22962306a36Sopenharmony_ci jsonw_string_field(w, "name", name); 23062306a36Sopenharmony_ci if (btf_kflag(t)) 23162306a36Sopenharmony_ci jsonw_int_field(w, "val", v->val); 23262306a36Sopenharmony_ci else 23362306a36Sopenharmony_ci jsonw_uint_field(w, "val", v->val); 23462306a36Sopenharmony_ci jsonw_end_object(w); 23562306a36Sopenharmony_ci } else { 23662306a36Sopenharmony_ci if (btf_kflag(t)) 23762306a36Sopenharmony_ci printf("\n\t'%s' val=%d", name, v->val); 23862306a36Sopenharmony_ci else 23962306a36Sopenharmony_ci printf("\n\t'%s' val=%u", name, v->val); 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci if (json_output) 24362306a36Sopenharmony_ci jsonw_end_array(w); 24462306a36Sopenharmony_ci break; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci case BTF_KIND_ENUM64: { 24762306a36Sopenharmony_ci const struct btf_enum64 *v = btf_enum64(t); 24862306a36Sopenharmony_ci __u16 vlen = btf_vlen(t); 24962306a36Sopenharmony_ci const char *encoding; 25062306a36Sopenharmony_ci int i; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED"; 25362306a36Sopenharmony_ci if (json_output) { 25462306a36Sopenharmony_ci jsonw_string_field(w, "encoding", encoding); 25562306a36Sopenharmony_ci jsonw_uint_field(w, "size", t->size); 25662306a36Sopenharmony_ci jsonw_uint_field(w, "vlen", vlen); 25762306a36Sopenharmony_ci jsonw_name(w, "values"); 25862306a36Sopenharmony_ci jsonw_start_array(w); 25962306a36Sopenharmony_ci } else { 26062306a36Sopenharmony_ci printf(" encoding=%s size=%u vlen=%u", encoding, t->size, vlen); 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci for (i = 0; i < vlen; i++, v++) { 26362306a36Sopenharmony_ci const char *name = btf_str(btf, v->name_off); 26462306a36Sopenharmony_ci __u64 val = ((__u64)v->val_hi32 << 32) | v->val_lo32; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (json_output) { 26762306a36Sopenharmony_ci jsonw_start_object(w); 26862306a36Sopenharmony_ci jsonw_string_field(w, "name", name); 26962306a36Sopenharmony_ci if (btf_kflag(t)) 27062306a36Sopenharmony_ci jsonw_int_field(w, "val", val); 27162306a36Sopenharmony_ci else 27262306a36Sopenharmony_ci jsonw_uint_field(w, "val", val); 27362306a36Sopenharmony_ci jsonw_end_object(w); 27462306a36Sopenharmony_ci } else { 27562306a36Sopenharmony_ci if (btf_kflag(t)) 27662306a36Sopenharmony_ci printf("\n\t'%s' val=%lldLL", name, 27762306a36Sopenharmony_ci (unsigned long long)val); 27862306a36Sopenharmony_ci else 27962306a36Sopenharmony_ci printf("\n\t'%s' val=%lluULL", name, 28062306a36Sopenharmony_ci (unsigned long long)val); 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci if (json_output) 28462306a36Sopenharmony_ci jsonw_end_array(w); 28562306a36Sopenharmony_ci break; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci case BTF_KIND_FWD: { 28862306a36Sopenharmony_ci const char *fwd_kind = BTF_INFO_KFLAG(t->info) ? "union" 28962306a36Sopenharmony_ci : "struct"; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (json_output) 29262306a36Sopenharmony_ci jsonw_string_field(w, "fwd_kind", fwd_kind); 29362306a36Sopenharmony_ci else 29462306a36Sopenharmony_ci printf(" fwd_kind=%s", fwd_kind); 29562306a36Sopenharmony_ci break; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci case BTF_KIND_FUNC: { 29862306a36Sopenharmony_ci const char *linkage = btf_func_linkage_str(t); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (json_output) { 30162306a36Sopenharmony_ci jsonw_uint_field(w, "type_id", t->type); 30262306a36Sopenharmony_ci jsonw_string_field(w, "linkage", linkage); 30362306a36Sopenharmony_ci } else { 30462306a36Sopenharmony_ci printf(" type_id=%u linkage=%s", t->type, linkage); 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci break; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci case BTF_KIND_FUNC_PROTO: { 30962306a36Sopenharmony_ci const struct btf_param *p = (const void *)(t + 1); 31062306a36Sopenharmony_ci __u16 vlen = BTF_INFO_VLEN(t->info); 31162306a36Sopenharmony_ci int i; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (json_output) { 31462306a36Sopenharmony_ci jsonw_uint_field(w, "ret_type_id", t->type); 31562306a36Sopenharmony_ci jsonw_uint_field(w, "vlen", vlen); 31662306a36Sopenharmony_ci jsonw_name(w, "params"); 31762306a36Sopenharmony_ci jsonw_start_array(w); 31862306a36Sopenharmony_ci } else { 31962306a36Sopenharmony_ci printf(" ret_type_id=%u vlen=%u", t->type, vlen); 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci for (i = 0; i < vlen; i++, p++) { 32262306a36Sopenharmony_ci const char *name = btf_str(btf, p->name_off); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (json_output) { 32562306a36Sopenharmony_ci jsonw_start_object(w); 32662306a36Sopenharmony_ci jsonw_string_field(w, "name", name); 32762306a36Sopenharmony_ci jsonw_uint_field(w, "type_id", p->type); 32862306a36Sopenharmony_ci jsonw_end_object(w); 32962306a36Sopenharmony_ci } else { 33062306a36Sopenharmony_ci printf("\n\t'%s' type_id=%u", name, p->type); 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci if (json_output) 33462306a36Sopenharmony_ci jsonw_end_array(w); 33562306a36Sopenharmony_ci break; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci case BTF_KIND_VAR: { 33862306a36Sopenharmony_ci const struct btf_var *v = (const void *)(t + 1); 33962306a36Sopenharmony_ci const char *linkage; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci linkage = btf_var_linkage_str(v->linkage); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (json_output) { 34462306a36Sopenharmony_ci jsonw_uint_field(w, "type_id", t->type); 34562306a36Sopenharmony_ci jsonw_string_field(w, "linkage", linkage); 34662306a36Sopenharmony_ci } else { 34762306a36Sopenharmony_ci printf(" type_id=%u, linkage=%s", t->type, linkage); 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci break; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci case BTF_KIND_DATASEC: { 35262306a36Sopenharmony_ci const struct btf_var_secinfo *v = (const void *)(t + 1); 35362306a36Sopenharmony_ci const struct btf_type *vt; 35462306a36Sopenharmony_ci __u16 vlen = BTF_INFO_VLEN(t->info); 35562306a36Sopenharmony_ci int i; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (json_output) { 35862306a36Sopenharmony_ci jsonw_uint_field(w, "size", t->size); 35962306a36Sopenharmony_ci jsonw_uint_field(w, "vlen", vlen); 36062306a36Sopenharmony_ci jsonw_name(w, "vars"); 36162306a36Sopenharmony_ci jsonw_start_array(w); 36262306a36Sopenharmony_ci } else { 36362306a36Sopenharmony_ci printf(" size=%u vlen=%u", t->size, vlen); 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci for (i = 0; i < vlen; i++, v++) { 36662306a36Sopenharmony_ci if (json_output) { 36762306a36Sopenharmony_ci jsonw_start_object(w); 36862306a36Sopenharmony_ci jsonw_uint_field(w, "type_id", v->type); 36962306a36Sopenharmony_ci jsonw_uint_field(w, "offset", v->offset); 37062306a36Sopenharmony_ci jsonw_uint_field(w, "size", v->size); 37162306a36Sopenharmony_ci jsonw_end_object(w); 37262306a36Sopenharmony_ci } else { 37362306a36Sopenharmony_ci printf("\n\ttype_id=%u offset=%u size=%u", 37462306a36Sopenharmony_ci v->type, v->offset, v->size); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (v->type < btf__type_cnt(btf)) { 37762306a36Sopenharmony_ci vt = btf__type_by_id(btf, v->type); 37862306a36Sopenharmony_ci printf(" (%s '%s')", 37962306a36Sopenharmony_ci btf_kind_str[btf_kind_safe(btf_kind(vt))], 38062306a36Sopenharmony_ci btf_str(btf, vt->name_off)); 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci if (json_output) 38562306a36Sopenharmony_ci jsonw_end_array(w); 38662306a36Sopenharmony_ci break; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci case BTF_KIND_FLOAT: { 38962306a36Sopenharmony_ci if (json_output) 39062306a36Sopenharmony_ci jsonw_uint_field(w, "size", t->size); 39162306a36Sopenharmony_ci else 39262306a36Sopenharmony_ci printf(" size=%u", t->size); 39362306a36Sopenharmony_ci break; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci case BTF_KIND_DECL_TAG: { 39662306a36Sopenharmony_ci const struct btf_decl_tag *tag = (const void *)(t + 1); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (json_output) { 39962306a36Sopenharmony_ci jsonw_uint_field(w, "type_id", t->type); 40062306a36Sopenharmony_ci jsonw_int_field(w, "component_idx", tag->component_idx); 40162306a36Sopenharmony_ci } else { 40262306a36Sopenharmony_ci printf(" type_id=%u component_idx=%d", t->type, tag->component_idx); 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci break; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci default: 40762306a36Sopenharmony_ci break; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci if (json_output) 41162306a36Sopenharmony_ci jsonw_end_object(json_wtr); 41262306a36Sopenharmony_ci else 41362306a36Sopenharmony_ci printf("\n"); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci return 0; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic int dump_btf_raw(const struct btf *btf, 41962306a36Sopenharmony_ci __u32 *root_type_ids, int root_type_cnt) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci const struct btf_type *t; 42262306a36Sopenharmony_ci int i; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci if (json_output) { 42562306a36Sopenharmony_ci jsonw_start_object(json_wtr); 42662306a36Sopenharmony_ci jsonw_name(json_wtr, "types"); 42762306a36Sopenharmony_ci jsonw_start_array(json_wtr); 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (root_type_cnt) { 43162306a36Sopenharmony_ci for (i = 0; i < root_type_cnt; i++) { 43262306a36Sopenharmony_ci t = btf__type_by_id(btf, root_type_ids[i]); 43362306a36Sopenharmony_ci dump_btf_type(btf, root_type_ids[i], t); 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci } else { 43662306a36Sopenharmony_ci const struct btf *base; 43762306a36Sopenharmony_ci int cnt = btf__type_cnt(btf); 43862306a36Sopenharmony_ci int start_id = 1; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci base = btf__base_btf(btf); 44162306a36Sopenharmony_ci if (base) 44262306a36Sopenharmony_ci start_id = btf__type_cnt(base); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci for (i = start_id; i < cnt; i++) { 44562306a36Sopenharmony_ci t = btf__type_by_id(btf, i); 44662306a36Sopenharmony_ci dump_btf_type(btf, i, t); 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if (json_output) { 45162306a36Sopenharmony_ci jsonw_end_array(json_wtr); 45262306a36Sopenharmony_ci jsonw_end_object(json_wtr); 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci return 0; 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic void __printf(2, 0) btf_dump_printf(void *ctx, 45862306a36Sopenharmony_ci const char *fmt, va_list args) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci vfprintf(stdout, fmt, args); 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic int dump_btf_c(const struct btf *btf, 46462306a36Sopenharmony_ci __u32 *root_type_ids, int root_type_cnt) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci struct btf_dump *d; 46762306a36Sopenharmony_ci int err = 0, i; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci d = btf_dump__new(btf, btf_dump_printf, NULL, NULL); 47062306a36Sopenharmony_ci if (!d) 47162306a36Sopenharmony_ci return -errno; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci printf("#ifndef __VMLINUX_H__\n"); 47462306a36Sopenharmony_ci printf("#define __VMLINUX_H__\n"); 47562306a36Sopenharmony_ci printf("\n"); 47662306a36Sopenharmony_ci printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n"); 47762306a36Sopenharmony_ci printf("#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n"); 47862306a36Sopenharmony_ci printf("#endif\n\n"); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (root_type_cnt) { 48162306a36Sopenharmony_ci for (i = 0; i < root_type_cnt; i++) { 48262306a36Sopenharmony_ci err = btf_dump__dump_type(d, root_type_ids[i]); 48362306a36Sopenharmony_ci if (err) 48462306a36Sopenharmony_ci goto done; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci } else { 48762306a36Sopenharmony_ci int cnt = btf__type_cnt(btf); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci for (i = 1; i < cnt; i++) { 49062306a36Sopenharmony_ci err = btf_dump__dump_type(d, i); 49162306a36Sopenharmony_ci if (err) 49262306a36Sopenharmony_ci goto done; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n"); 49762306a36Sopenharmony_ci printf("#pragma clang attribute pop\n"); 49862306a36Sopenharmony_ci printf("#endif\n"); 49962306a36Sopenharmony_ci printf("\n"); 50062306a36Sopenharmony_ci printf("#endif /* __VMLINUX_H__ */\n"); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cidone: 50362306a36Sopenharmony_ci btf_dump__free(d); 50462306a36Sopenharmony_ci return err; 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistatic const char sysfs_vmlinux[] = "/sys/kernel/btf/vmlinux"; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic struct btf *get_vmlinux_btf_from_sysfs(void) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci struct btf *base; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci base = btf__parse(sysfs_vmlinux, NULL); 51462306a36Sopenharmony_ci if (!base) 51562306a36Sopenharmony_ci p_err("failed to parse vmlinux BTF at '%s': %d\n", 51662306a36Sopenharmony_ci sysfs_vmlinux, -errno); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci return base; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci#define BTF_NAME_BUFF_LEN 64 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic bool btf_is_kernel_module(__u32 btf_id) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct bpf_btf_info btf_info = {}; 52662306a36Sopenharmony_ci char btf_name[BTF_NAME_BUFF_LEN]; 52762306a36Sopenharmony_ci int btf_fd; 52862306a36Sopenharmony_ci __u32 len; 52962306a36Sopenharmony_ci int err; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci btf_fd = bpf_btf_get_fd_by_id(btf_id); 53262306a36Sopenharmony_ci if (btf_fd < 0) { 53362306a36Sopenharmony_ci p_err("can't get BTF object by id (%u): %s", btf_id, strerror(errno)); 53462306a36Sopenharmony_ci return false; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci len = sizeof(btf_info); 53862306a36Sopenharmony_ci btf_info.name = ptr_to_u64(btf_name); 53962306a36Sopenharmony_ci btf_info.name_len = sizeof(btf_name); 54062306a36Sopenharmony_ci err = bpf_btf_get_info_by_fd(btf_fd, &btf_info, &len); 54162306a36Sopenharmony_ci close(btf_fd); 54262306a36Sopenharmony_ci if (err) { 54362306a36Sopenharmony_ci p_err("can't get BTF (ID %u) object info: %s", btf_id, strerror(errno)); 54462306a36Sopenharmony_ci return false; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci return btf_info.kernel_btf && strncmp(btf_name, "vmlinux", sizeof(btf_name)) != 0; 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistatic int do_dump(int argc, char **argv) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct btf *btf = NULL, *base = NULL; 55362306a36Sopenharmony_ci __u32 root_type_ids[2]; 55462306a36Sopenharmony_ci int root_type_cnt = 0; 55562306a36Sopenharmony_ci bool dump_c = false; 55662306a36Sopenharmony_ci __u32 btf_id = -1; 55762306a36Sopenharmony_ci const char *src; 55862306a36Sopenharmony_ci int fd = -1; 55962306a36Sopenharmony_ci int err = 0; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (!REQ_ARGS(2)) { 56262306a36Sopenharmony_ci usage(); 56362306a36Sopenharmony_ci return -1; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci src = GET_ARG(); 56662306a36Sopenharmony_ci if (is_prefix(src, "map")) { 56762306a36Sopenharmony_ci struct bpf_map_info info = {}; 56862306a36Sopenharmony_ci __u32 len = sizeof(info); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (!REQ_ARGS(2)) { 57162306a36Sopenharmony_ci usage(); 57262306a36Sopenharmony_ci return -1; 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 57662306a36Sopenharmony_ci if (fd < 0) 57762306a36Sopenharmony_ci return -1; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci btf_id = info.btf_id; 58062306a36Sopenharmony_ci if (argc && is_prefix(*argv, "key")) { 58162306a36Sopenharmony_ci root_type_ids[root_type_cnt++] = info.btf_key_type_id; 58262306a36Sopenharmony_ci NEXT_ARG(); 58362306a36Sopenharmony_ci } else if (argc && is_prefix(*argv, "value")) { 58462306a36Sopenharmony_ci root_type_ids[root_type_cnt++] = info.btf_value_type_id; 58562306a36Sopenharmony_ci NEXT_ARG(); 58662306a36Sopenharmony_ci } else if (argc && is_prefix(*argv, "all")) { 58762306a36Sopenharmony_ci NEXT_ARG(); 58862306a36Sopenharmony_ci } else if (argc && is_prefix(*argv, "kv")) { 58962306a36Sopenharmony_ci root_type_ids[root_type_cnt++] = info.btf_key_type_id; 59062306a36Sopenharmony_ci root_type_ids[root_type_cnt++] = info.btf_value_type_id; 59162306a36Sopenharmony_ci NEXT_ARG(); 59262306a36Sopenharmony_ci } else { 59362306a36Sopenharmony_ci root_type_ids[root_type_cnt++] = info.btf_key_type_id; 59462306a36Sopenharmony_ci root_type_ids[root_type_cnt++] = info.btf_value_type_id; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci } else if (is_prefix(src, "prog")) { 59762306a36Sopenharmony_ci struct bpf_prog_info info = {}; 59862306a36Sopenharmony_ci __u32 len = sizeof(info); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (!REQ_ARGS(2)) { 60162306a36Sopenharmony_ci usage(); 60262306a36Sopenharmony_ci return -1; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci fd = prog_parse_fd(&argc, &argv); 60662306a36Sopenharmony_ci if (fd < 0) 60762306a36Sopenharmony_ci return -1; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci err = bpf_prog_get_info_by_fd(fd, &info, &len); 61062306a36Sopenharmony_ci if (err) { 61162306a36Sopenharmony_ci p_err("can't get prog info: %s", strerror(errno)); 61262306a36Sopenharmony_ci goto done; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci btf_id = info.btf_id; 61662306a36Sopenharmony_ci } else if (is_prefix(src, "id")) { 61762306a36Sopenharmony_ci char *endptr; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci btf_id = strtoul(*argv, &endptr, 0); 62062306a36Sopenharmony_ci if (*endptr) { 62162306a36Sopenharmony_ci p_err("can't parse %s as ID", *argv); 62262306a36Sopenharmony_ci return -1; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci NEXT_ARG(); 62562306a36Sopenharmony_ci } else if (is_prefix(src, "file")) { 62662306a36Sopenharmony_ci const char sysfs_prefix[] = "/sys/kernel/btf/"; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (!base_btf && 62962306a36Sopenharmony_ci strncmp(*argv, sysfs_prefix, sizeof(sysfs_prefix) - 1) == 0 && 63062306a36Sopenharmony_ci strcmp(*argv, sysfs_vmlinux) != 0) 63162306a36Sopenharmony_ci base = get_vmlinux_btf_from_sysfs(); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci btf = btf__parse_split(*argv, base ?: base_btf); 63462306a36Sopenharmony_ci if (!btf) { 63562306a36Sopenharmony_ci err = -errno; 63662306a36Sopenharmony_ci p_err("failed to load BTF from %s: %s", 63762306a36Sopenharmony_ci *argv, strerror(errno)); 63862306a36Sopenharmony_ci goto done; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci NEXT_ARG(); 64162306a36Sopenharmony_ci } else { 64262306a36Sopenharmony_ci err = -1; 64362306a36Sopenharmony_ci p_err("unrecognized BTF source specifier: '%s'", src); 64462306a36Sopenharmony_ci goto done; 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci while (argc) { 64862306a36Sopenharmony_ci if (is_prefix(*argv, "format")) { 64962306a36Sopenharmony_ci NEXT_ARG(); 65062306a36Sopenharmony_ci if (argc < 1) { 65162306a36Sopenharmony_ci p_err("expecting value for 'format' option\n"); 65262306a36Sopenharmony_ci err = -EINVAL; 65362306a36Sopenharmony_ci goto done; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci if (strcmp(*argv, "c") == 0) { 65662306a36Sopenharmony_ci dump_c = true; 65762306a36Sopenharmony_ci } else if (strcmp(*argv, "raw") == 0) { 65862306a36Sopenharmony_ci dump_c = false; 65962306a36Sopenharmony_ci } else { 66062306a36Sopenharmony_ci p_err("unrecognized format specifier: '%s', possible values: raw, c", 66162306a36Sopenharmony_ci *argv); 66262306a36Sopenharmony_ci err = -EINVAL; 66362306a36Sopenharmony_ci goto done; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci NEXT_ARG(); 66662306a36Sopenharmony_ci } else { 66762306a36Sopenharmony_ci p_err("unrecognized option: '%s'", *argv); 66862306a36Sopenharmony_ci err = -EINVAL; 66962306a36Sopenharmony_ci goto done; 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (!btf) { 67462306a36Sopenharmony_ci if (!base_btf && btf_is_kernel_module(btf_id)) { 67562306a36Sopenharmony_ci p_info("Warning: valid base BTF was not specified with -B option, falling back to standard base BTF (%s)", 67662306a36Sopenharmony_ci sysfs_vmlinux); 67762306a36Sopenharmony_ci base_btf = get_vmlinux_btf_from_sysfs(); 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci btf = btf__load_from_kernel_by_id_split(btf_id, base_btf); 68162306a36Sopenharmony_ci if (!btf) { 68262306a36Sopenharmony_ci err = -errno; 68362306a36Sopenharmony_ci p_err("get btf by id (%u): %s", btf_id, strerror(errno)); 68462306a36Sopenharmony_ci goto done; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci if (dump_c) { 68962306a36Sopenharmony_ci if (json_output) { 69062306a36Sopenharmony_ci p_err("JSON output for C-syntax dump is not supported"); 69162306a36Sopenharmony_ci err = -ENOTSUP; 69262306a36Sopenharmony_ci goto done; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci err = dump_btf_c(btf, root_type_ids, root_type_cnt); 69562306a36Sopenharmony_ci } else { 69662306a36Sopenharmony_ci err = dump_btf_raw(btf, root_type_ids, root_type_cnt); 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cidone: 70062306a36Sopenharmony_ci close(fd); 70162306a36Sopenharmony_ci btf__free(btf); 70262306a36Sopenharmony_ci btf__free(base); 70362306a36Sopenharmony_ci return err; 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic int btf_parse_fd(int *argc, char ***argv) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci unsigned int id; 70962306a36Sopenharmony_ci char *endptr; 71062306a36Sopenharmony_ci int fd; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci if (!is_prefix(*argv[0], "id")) { 71362306a36Sopenharmony_ci p_err("expected 'id', got: '%s'?", **argv); 71462306a36Sopenharmony_ci return -1; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci NEXT_ARGP(); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci id = strtoul(**argv, &endptr, 0); 71962306a36Sopenharmony_ci if (*endptr) { 72062306a36Sopenharmony_ci p_err("can't parse %s as ID", **argv); 72162306a36Sopenharmony_ci return -1; 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci NEXT_ARGP(); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci fd = bpf_btf_get_fd_by_id(id); 72662306a36Sopenharmony_ci if (fd < 0) 72762306a36Sopenharmony_ci p_err("can't get BTF object by id (%u): %s", 72862306a36Sopenharmony_ci id, strerror(errno)); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci return fd; 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic int 73462306a36Sopenharmony_cibuild_btf_type_table(struct hashmap *tab, enum bpf_obj_type type, 73562306a36Sopenharmony_ci void *info, __u32 *len) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci static const char * const names[] = { 73862306a36Sopenharmony_ci [BPF_OBJ_UNKNOWN] = "unknown", 73962306a36Sopenharmony_ci [BPF_OBJ_PROG] = "prog", 74062306a36Sopenharmony_ci [BPF_OBJ_MAP] = "map", 74162306a36Sopenharmony_ci }; 74262306a36Sopenharmony_ci __u32 btf_id, id = 0; 74362306a36Sopenharmony_ci int err; 74462306a36Sopenharmony_ci int fd; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci while (true) { 74762306a36Sopenharmony_ci switch (type) { 74862306a36Sopenharmony_ci case BPF_OBJ_PROG: 74962306a36Sopenharmony_ci err = bpf_prog_get_next_id(id, &id); 75062306a36Sopenharmony_ci break; 75162306a36Sopenharmony_ci case BPF_OBJ_MAP: 75262306a36Sopenharmony_ci err = bpf_map_get_next_id(id, &id); 75362306a36Sopenharmony_ci break; 75462306a36Sopenharmony_ci default: 75562306a36Sopenharmony_ci err = -1; 75662306a36Sopenharmony_ci p_err("unexpected object type: %d", type); 75762306a36Sopenharmony_ci goto err_free; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci if (err) { 76062306a36Sopenharmony_ci if (errno == ENOENT) { 76162306a36Sopenharmony_ci err = 0; 76262306a36Sopenharmony_ci break; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci p_err("can't get next %s: %s%s", names[type], 76562306a36Sopenharmony_ci strerror(errno), 76662306a36Sopenharmony_ci errno == EINVAL ? " -- kernel too old?" : ""); 76762306a36Sopenharmony_ci goto err_free; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci switch (type) { 77162306a36Sopenharmony_ci case BPF_OBJ_PROG: 77262306a36Sopenharmony_ci fd = bpf_prog_get_fd_by_id(id); 77362306a36Sopenharmony_ci break; 77462306a36Sopenharmony_ci case BPF_OBJ_MAP: 77562306a36Sopenharmony_ci fd = bpf_map_get_fd_by_id(id); 77662306a36Sopenharmony_ci break; 77762306a36Sopenharmony_ci default: 77862306a36Sopenharmony_ci err = -1; 77962306a36Sopenharmony_ci p_err("unexpected object type: %d", type); 78062306a36Sopenharmony_ci goto err_free; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci if (fd < 0) { 78362306a36Sopenharmony_ci if (errno == ENOENT) 78462306a36Sopenharmony_ci continue; 78562306a36Sopenharmony_ci p_err("can't get %s by id (%u): %s", names[type], id, 78662306a36Sopenharmony_ci strerror(errno)); 78762306a36Sopenharmony_ci err = -1; 78862306a36Sopenharmony_ci goto err_free; 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci memset(info, 0, *len); 79262306a36Sopenharmony_ci if (type == BPF_OBJ_PROG) 79362306a36Sopenharmony_ci err = bpf_prog_get_info_by_fd(fd, info, len); 79462306a36Sopenharmony_ci else 79562306a36Sopenharmony_ci err = bpf_map_get_info_by_fd(fd, info, len); 79662306a36Sopenharmony_ci close(fd); 79762306a36Sopenharmony_ci if (err) { 79862306a36Sopenharmony_ci p_err("can't get %s info: %s", names[type], 79962306a36Sopenharmony_ci strerror(errno)); 80062306a36Sopenharmony_ci goto err_free; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci switch (type) { 80462306a36Sopenharmony_ci case BPF_OBJ_PROG: 80562306a36Sopenharmony_ci btf_id = ((struct bpf_prog_info *)info)->btf_id; 80662306a36Sopenharmony_ci break; 80762306a36Sopenharmony_ci case BPF_OBJ_MAP: 80862306a36Sopenharmony_ci btf_id = ((struct bpf_map_info *)info)->btf_id; 80962306a36Sopenharmony_ci break; 81062306a36Sopenharmony_ci default: 81162306a36Sopenharmony_ci err = -1; 81262306a36Sopenharmony_ci p_err("unexpected object type: %d", type); 81362306a36Sopenharmony_ci goto err_free; 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci if (!btf_id) 81662306a36Sopenharmony_ci continue; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci err = hashmap__append(tab, btf_id, id); 81962306a36Sopenharmony_ci if (err) { 82062306a36Sopenharmony_ci p_err("failed to append entry to hashmap for BTF ID %u, object ID %u: %s", 82162306a36Sopenharmony_ci btf_id, id, strerror(-err)); 82262306a36Sopenharmony_ci goto err_free; 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci return 0; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_cierr_free: 82962306a36Sopenharmony_ci hashmap__free(tab); 83062306a36Sopenharmony_ci return err; 83162306a36Sopenharmony_ci} 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_cistatic int 83462306a36Sopenharmony_cibuild_btf_tables(struct hashmap *btf_prog_table, 83562306a36Sopenharmony_ci struct hashmap *btf_map_table) 83662306a36Sopenharmony_ci{ 83762306a36Sopenharmony_ci struct bpf_prog_info prog_info; 83862306a36Sopenharmony_ci __u32 prog_len = sizeof(prog_info); 83962306a36Sopenharmony_ci struct bpf_map_info map_info; 84062306a36Sopenharmony_ci __u32 map_len = sizeof(map_info); 84162306a36Sopenharmony_ci int err = 0; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci err = build_btf_type_table(btf_prog_table, BPF_OBJ_PROG, &prog_info, 84462306a36Sopenharmony_ci &prog_len); 84562306a36Sopenharmony_ci if (err) 84662306a36Sopenharmony_ci return err; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci err = build_btf_type_table(btf_map_table, BPF_OBJ_MAP, &map_info, 84962306a36Sopenharmony_ci &map_len); 85062306a36Sopenharmony_ci if (err) { 85162306a36Sopenharmony_ci hashmap__free(btf_prog_table); 85262306a36Sopenharmony_ci return err; 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci return 0; 85662306a36Sopenharmony_ci} 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistatic void 85962306a36Sopenharmony_cishow_btf_plain(struct bpf_btf_info *info, int fd, 86062306a36Sopenharmony_ci struct hashmap *btf_prog_table, 86162306a36Sopenharmony_ci struct hashmap *btf_map_table) 86262306a36Sopenharmony_ci{ 86362306a36Sopenharmony_ci struct hashmap_entry *entry; 86462306a36Sopenharmony_ci const char *name = u64_to_ptr(info->name); 86562306a36Sopenharmony_ci int n; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci printf("%u: ", info->id); 86862306a36Sopenharmony_ci if (info->kernel_btf) 86962306a36Sopenharmony_ci printf("name [%s] ", name); 87062306a36Sopenharmony_ci else if (name && name[0]) 87162306a36Sopenharmony_ci printf("name %s ", name); 87262306a36Sopenharmony_ci else 87362306a36Sopenharmony_ci printf("name <anon> "); 87462306a36Sopenharmony_ci printf("size %uB", info->btf_size); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci n = 0; 87762306a36Sopenharmony_ci hashmap__for_each_key_entry(btf_prog_table, entry, info->id) { 87862306a36Sopenharmony_ci printf("%s%lu", n++ == 0 ? " prog_ids " : ",", entry->value); 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci n = 0; 88262306a36Sopenharmony_ci hashmap__for_each_key_entry(btf_map_table, entry, info->id) { 88362306a36Sopenharmony_ci printf("%s%lu", n++ == 0 ? " map_ids " : ",", entry->value); 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci emit_obj_refs_plain(refs_table, info->id, "\n\tpids "); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci printf("\n"); 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic void 89262306a36Sopenharmony_cishow_btf_json(struct bpf_btf_info *info, int fd, 89362306a36Sopenharmony_ci struct hashmap *btf_prog_table, 89462306a36Sopenharmony_ci struct hashmap *btf_map_table) 89562306a36Sopenharmony_ci{ 89662306a36Sopenharmony_ci struct hashmap_entry *entry; 89762306a36Sopenharmony_ci const char *name = u64_to_ptr(info->name); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci jsonw_start_object(json_wtr); /* btf object */ 90062306a36Sopenharmony_ci jsonw_uint_field(json_wtr, "id", info->id); 90162306a36Sopenharmony_ci jsonw_uint_field(json_wtr, "size", info->btf_size); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci jsonw_name(json_wtr, "prog_ids"); 90462306a36Sopenharmony_ci jsonw_start_array(json_wtr); /* prog_ids */ 90562306a36Sopenharmony_ci hashmap__for_each_key_entry(btf_prog_table, entry, info->id) { 90662306a36Sopenharmony_ci jsonw_uint(json_wtr, entry->value); 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci jsonw_end_array(json_wtr); /* prog_ids */ 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci jsonw_name(json_wtr, "map_ids"); 91162306a36Sopenharmony_ci jsonw_start_array(json_wtr); /* map_ids */ 91262306a36Sopenharmony_ci hashmap__for_each_key_entry(btf_map_table, entry, info->id) { 91362306a36Sopenharmony_ci jsonw_uint(json_wtr, entry->value); 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci jsonw_end_array(json_wtr); /* map_ids */ 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci emit_obj_refs_json(refs_table, info->id, json_wtr); /* pids */ 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci jsonw_bool_field(json_wtr, "kernel", info->kernel_btf); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci if (name && name[0]) 92262306a36Sopenharmony_ci jsonw_string_field(json_wtr, "name", name); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci jsonw_end_object(json_wtr); /* btf object */ 92562306a36Sopenharmony_ci} 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_cistatic int 92862306a36Sopenharmony_cishow_btf(int fd, struct hashmap *btf_prog_table, 92962306a36Sopenharmony_ci struct hashmap *btf_map_table) 93062306a36Sopenharmony_ci{ 93162306a36Sopenharmony_ci struct bpf_btf_info info; 93262306a36Sopenharmony_ci __u32 len = sizeof(info); 93362306a36Sopenharmony_ci char name[64]; 93462306a36Sopenharmony_ci int err; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci memset(&info, 0, sizeof(info)); 93762306a36Sopenharmony_ci err = bpf_btf_get_info_by_fd(fd, &info, &len); 93862306a36Sopenharmony_ci if (err) { 93962306a36Sopenharmony_ci p_err("can't get BTF object info: %s", strerror(errno)); 94062306a36Sopenharmony_ci return -1; 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci /* if kernel support emitting BTF object name, pass name pointer */ 94362306a36Sopenharmony_ci if (info.name_len) { 94462306a36Sopenharmony_ci memset(&info, 0, sizeof(info)); 94562306a36Sopenharmony_ci info.name_len = sizeof(name); 94662306a36Sopenharmony_ci info.name = ptr_to_u64(name); 94762306a36Sopenharmony_ci len = sizeof(info); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci err = bpf_btf_get_info_by_fd(fd, &info, &len); 95062306a36Sopenharmony_ci if (err) { 95162306a36Sopenharmony_ci p_err("can't get BTF object info: %s", strerror(errno)); 95262306a36Sopenharmony_ci return -1; 95362306a36Sopenharmony_ci } 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci if (json_output) 95762306a36Sopenharmony_ci show_btf_json(&info, fd, btf_prog_table, btf_map_table); 95862306a36Sopenharmony_ci else 95962306a36Sopenharmony_ci show_btf_plain(&info, fd, btf_prog_table, btf_map_table); 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci return 0; 96262306a36Sopenharmony_ci} 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_cistatic int do_show(int argc, char **argv) 96562306a36Sopenharmony_ci{ 96662306a36Sopenharmony_ci struct hashmap *btf_prog_table; 96762306a36Sopenharmony_ci struct hashmap *btf_map_table; 96862306a36Sopenharmony_ci int err, fd = -1; 96962306a36Sopenharmony_ci __u32 id = 0; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci if (argc == 2) { 97262306a36Sopenharmony_ci fd = btf_parse_fd(&argc, &argv); 97362306a36Sopenharmony_ci if (fd < 0) 97462306a36Sopenharmony_ci return -1; 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci if (argc) { 97862306a36Sopenharmony_ci if (fd >= 0) 97962306a36Sopenharmony_ci close(fd); 98062306a36Sopenharmony_ci return BAD_ARG(); 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci btf_prog_table = hashmap__new(hash_fn_for_key_as_id, 98462306a36Sopenharmony_ci equal_fn_for_key_as_id, NULL); 98562306a36Sopenharmony_ci btf_map_table = hashmap__new(hash_fn_for_key_as_id, 98662306a36Sopenharmony_ci equal_fn_for_key_as_id, NULL); 98762306a36Sopenharmony_ci if (IS_ERR(btf_prog_table) || IS_ERR(btf_map_table)) { 98862306a36Sopenharmony_ci hashmap__free(btf_prog_table); 98962306a36Sopenharmony_ci hashmap__free(btf_map_table); 99062306a36Sopenharmony_ci if (fd >= 0) 99162306a36Sopenharmony_ci close(fd); 99262306a36Sopenharmony_ci p_err("failed to create hashmap for object references"); 99362306a36Sopenharmony_ci return -1; 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci err = build_btf_tables(btf_prog_table, btf_map_table); 99662306a36Sopenharmony_ci if (err) { 99762306a36Sopenharmony_ci if (fd >= 0) 99862306a36Sopenharmony_ci close(fd); 99962306a36Sopenharmony_ci return err; 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci build_obj_refs_table(&refs_table, BPF_OBJ_BTF); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci if (fd >= 0) { 100462306a36Sopenharmony_ci err = show_btf(fd, btf_prog_table, btf_map_table); 100562306a36Sopenharmony_ci close(fd); 100662306a36Sopenharmony_ci goto exit_free; 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (json_output) 101062306a36Sopenharmony_ci jsonw_start_array(json_wtr); /* root array */ 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci while (true) { 101362306a36Sopenharmony_ci err = bpf_btf_get_next_id(id, &id); 101462306a36Sopenharmony_ci if (err) { 101562306a36Sopenharmony_ci if (errno == ENOENT) { 101662306a36Sopenharmony_ci err = 0; 101762306a36Sopenharmony_ci break; 101862306a36Sopenharmony_ci } 101962306a36Sopenharmony_ci p_err("can't get next BTF object: %s%s", 102062306a36Sopenharmony_ci strerror(errno), 102162306a36Sopenharmony_ci errno == EINVAL ? " -- kernel too old?" : ""); 102262306a36Sopenharmony_ci err = -1; 102362306a36Sopenharmony_ci break; 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci fd = bpf_btf_get_fd_by_id(id); 102762306a36Sopenharmony_ci if (fd < 0) { 102862306a36Sopenharmony_ci if (errno == ENOENT) 102962306a36Sopenharmony_ci continue; 103062306a36Sopenharmony_ci p_err("can't get BTF object by id (%u): %s", 103162306a36Sopenharmony_ci id, strerror(errno)); 103262306a36Sopenharmony_ci err = -1; 103362306a36Sopenharmony_ci break; 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci err = show_btf(fd, btf_prog_table, btf_map_table); 103762306a36Sopenharmony_ci close(fd); 103862306a36Sopenharmony_ci if (err) 103962306a36Sopenharmony_ci break; 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci if (json_output) 104362306a36Sopenharmony_ci jsonw_end_array(json_wtr); /* root array */ 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ciexit_free: 104662306a36Sopenharmony_ci hashmap__free(btf_prog_table); 104762306a36Sopenharmony_ci hashmap__free(btf_map_table); 104862306a36Sopenharmony_ci delete_obj_refs_table(refs_table); 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci return err; 105162306a36Sopenharmony_ci} 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_cistatic int do_help(int argc, char **argv) 105462306a36Sopenharmony_ci{ 105562306a36Sopenharmony_ci if (json_output) { 105662306a36Sopenharmony_ci jsonw_null(json_wtr); 105762306a36Sopenharmony_ci return 0; 105862306a36Sopenharmony_ci } 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci fprintf(stderr, 106162306a36Sopenharmony_ci "Usage: %1$s %2$s { show | list } [id BTF_ID]\n" 106262306a36Sopenharmony_ci " %1$s %2$s dump BTF_SRC [format FORMAT]\n" 106362306a36Sopenharmony_ci " %1$s %2$s help\n" 106462306a36Sopenharmony_ci "\n" 106562306a36Sopenharmony_ci " BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n" 106662306a36Sopenharmony_ci " FORMAT := { raw | c }\n" 106762306a36Sopenharmony_ci " " HELP_SPEC_MAP "\n" 106862306a36Sopenharmony_ci " " HELP_SPEC_PROGRAM "\n" 106962306a36Sopenharmony_ci " " HELP_SPEC_OPTIONS " |\n" 107062306a36Sopenharmony_ci " {-B|--base-btf} }\n" 107162306a36Sopenharmony_ci "", 107262306a36Sopenharmony_ci bin_name, "btf"); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci return 0; 107562306a36Sopenharmony_ci} 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_cistatic const struct cmd cmds[] = { 107862306a36Sopenharmony_ci { "show", do_show }, 107962306a36Sopenharmony_ci { "list", do_show }, 108062306a36Sopenharmony_ci { "help", do_help }, 108162306a36Sopenharmony_ci { "dump", do_dump }, 108262306a36Sopenharmony_ci { 0 } 108362306a36Sopenharmony_ci}; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ciint do_btf(int argc, char **argv) 108662306a36Sopenharmony_ci{ 108762306a36Sopenharmony_ci return cmd_select(cmds, argc, argv, do_help); 108862306a36Sopenharmony_ci} 1089