btf.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342
  1. // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
  2. /* Copyright (C) 2019 Facebook */
  3. #include <errno.h>
  4. #include <fcntl.h>
  5. #include <linux/err.h>
  6. #include <stdbool.h>
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <unistd.h>
  10. #include <linux/btf.h>
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #include <bpf/bpf.h>
  14. #include <bpf/btf.h>
  15. #include <bpf/hashmap.h>
  16. #include <bpf/libbpf.h>
  17. #include "json_writer.h"
  18. #include "main.h"
  19. #define KFUNC_DECL_TAG "bpf_kfunc"
  20. static const char * const btf_kind_str[NR_BTF_KINDS] = {
  21. [BTF_KIND_UNKN] = "UNKNOWN",
  22. [BTF_KIND_INT] = "INT",
  23. [BTF_KIND_PTR] = "PTR",
  24. [BTF_KIND_ARRAY] = "ARRAY",
  25. [BTF_KIND_STRUCT] = "STRUCT",
  26. [BTF_KIND_UNION] = "UNION",
  27. [BTF_KIND_ENUM] = "ENUM",
  28. [BTF_KIND_FWD] = "FWD",
  29. [BTF_KIND_TYPEDEF] = "TYPEDEF",
  30. [BTF_KIND_VOLATILE] = "VOLATILE",
  31. [BTF_KIND_CONST] = "CONST",
  32. [BTF_KIND_RESTRICT] = "RESTRICT",
  33. [BTF_KIND_FUNC] = "FUNC",
  34. [BTF_KIND_FUNC_PROTO] = "FUNC_PROTO",
  35. [BTF_KIND_VAR] = "VAR",
  36. [BTF_KIND_DATASEC] = "DATASEC",
  37. [BTF_KIND_FLOAT] = "FLOAT",
  38. [BTF_KIND_DECL_TAG] = "DECL_TAG",
  39. [BTF_KIND_TYPE_TAG] = "TYPE_TAG",
  40. [BTF_KIND_ENUM64] = "ENUM64",
  41. };
  42. struct sort_datum {
  43. int index;
  44. int type_rank;
  45. const char *sort_name;
  46. const char *own_name;
  47. __u64 disambig_hash;
  48. };
  49. static const char *btf_int_enc_str(__u8 encoding)
  50. {
  51. switch (encoding) {
  52. case 0:
  53. return "(none)";
  54. case BTF_INT_SIGNED:
  55. return "SIGNED";
  56. case BTF_INT_CHAR:
  57. return "CHAR";
  58. case BTF_INT_BOOL:
  59. return "BOOL";
  60. default:
  61. return "UNKN";
  62. }
  63. }
  64. static const char *btf_var_linkage_str(__u32 linkage)
  65. {
  66. switch (linkage) {
  67. case BTF_VAR_STATIC:
  68. return "static";
  69. case BTF_VAR_GLOBAL_ALLOCATED:
  70. return "global";
  71. case BTF_VAR_GLOBAL_EXTERN:
  72. return "extern";
  73. default:
  74. return "(unknown)";
  75. }
  76. }
  77. static const char *btf_func_linkage_str(const struct btf_type *t)
  78. {
  79. switch (btf_vlen(t)) {
  80. case BTF_FUNC_STATIC:
  81. return "static";
  82. case BTF_FUNC_GLOBAL:
  83. return "global";
  84. case BTF_FUNC_EXTERN:
  85. return "extern";
  86. default:
  87. return "(unknown)";
  88. }
  89. }
  90. static const char *btf_str(const struct btf *btf, __u32 off)
  91. {
  92. if (!off)
  93. return "(anon)";
  94. return btf__name_by_offset(btf, off) ? : "(invalid)";
  95. }
  96. static int btf_kind_safe(int kind)
  97. {
  98. return kind <= BTF_KIND_MAX ? kind : BTF_KIND_UNKN;
  99. }
  100. static int dump_btf_type(const struct btf *btf, __u32 id,
  101. const struct btf_type *t)
  102. {
  103. json_writer_t *w = json_wtr;
  104. int kind = btf_kind(t);
  105. if (json_output) {
  106. jsonw_start_object(w);
  107. jsonw_uint_field(w, "id", id);
  108. jsonw_string_field(w, "kind", btf_kind_str[btf_kind_safe(kind)]);
  109. jsonw_string_field(w, "name", btf_str(btf, t->name_off));
  110. } else {
  111. printf("[%u] %s '%s'", id, btf_kind_str[btf_kind_safe(kind)],
  112. btf_str(btf, t->name_off));
  113. }
  114. switch (kind) {
  115. case BTF_KIND_INT: {
  116. __u32 v = *(__u32 *)(t + 1);
  117. const char *enc;
  118. enc = btf_int_enc_str(BTF_INT_ENCODING(v));
  119. if (json_output) {
  120. jsonw_uint_field(w, "size", t->size);
  121. jsonw_uint_field(w, "bits_offset", BTF_INT_OFFSET(v));
  122. jsonw_uint_field(w, "nr_bits", BTF_INT_BITS(v));
  123. jsonw_string_field(w, "encoding", enc);
  124. } else {
  125. printf(" size=%u bits_offset=%u nr_bits=%u encoding=%s",
  126. t->size, BTF_INT_OFFSET(v), BTF_INT_BITS(v),
  127. enc);
  128. }
  129. break;
  130. }
  131. case BTF_KIND_PTR:
  132. case BTF_KIND_CONST:
  133. case BTF_KIND_VOLATILE:
  134. case BTF_KIND_RESTRICT:
  135. case BTF_KIND_TYPEDEF:
  136. case BTF_KIND_TYPE_TAG:
  137. if (json_output)
  138. jsonw_uint_field(w, "type_id", t->type);
  139. else
  140. printf(" type_id=%u", t->type);
  141. break;
  142. case BTF_KIND_ARRAY: {
  143. const struct btf_array *arr = (const void *)(t + 1);
  144. if (json_output) {
  145. jsonw_uint_field(w, "type_id", arr->type);
  146. jsonw_uint_field(w, "index_type_id", arr->index_type);
  147. jsonw_uint_field(w, "nr_elems", arr->nelems);
  148. } else {
  149. printf(" type_id=%u index_type_id=%u nr_elems=%u",
  150. arr->type, arr->index_type, arr->nelems);
  151. }
  152. break;
  153. }
  154. case BTF_KIND_STRUCT:
  155. case BTF_KIND_UNION: {
  156. const struct btf_member *m = (const void *)(t + 1);
  157. __u16 vlen = BTF_INFO_VLEN(t->info);
  158. int i;
  159. if (json_output) {
  160. jsonw_uint_field(w, "size", t->size);
  161. jsonw_uint_field(w, "vlen", vlen);
  162. jsonw_name(w, "members");
  163. jsonw_start_array(w);
  164. } else {
  165. printf(" size=%u vlen=%u", t->size, vlen);
  166. }
  167. for (i = 0; i < vlen; i++, m++) {
  168. const char *name = btf_str(btf, m->name_off);
  169. __u32 bit_off, bit_sz;
  170. if (BTF_INFO_KFLAG(t->info)) {
  171. bit_off = BTF_MEMBER_BIT_OFFSET(m->offset);
  172. bit_sz = BTF_MEMBER_BITFIELD_SIZE(m->offset);
  173. } else {
  174. bit_off = m->offset;
  175. bit_sz = 0;
  176. }
  177. if (json_output) {
  178. jsonw_start_object(w);
  179. jsonw_string_field(w, "name", name);
  180. jsonw_uint_field(w, "type_id", m->type);
  181. jsonw_uint_field(w, "bits_offset", bit_off);
  182. if (bit_sz) {
  183. jsonw_uint_field(w, "bitfield_size",
  184. bit_sz);
  185. }
  186. jsonw_end_object(w);
  187. } else {
  188. printf("\n\t'%s' type_id=%u bits_offset=%u",
  189. name, m->type, bit_off);
  190. if (bit_sz)
  191. printf(" bitfield_size=%u", bit_sz);
  192. }
  193. }
  194. if (json_output)
  195. jsonw_end_array(w);
  196. break;
  197. }
  198. case BTF_KIND_ENUM: {
  199. const struct btf_enum *v = (const void *)(t + 1);
  200. __u16 vlen = BTF_INFO_VLEN(t->info);
  201. const char *encoding;
  202. int i;
  203. encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";
  204. if (json_output) {
  205. jsonw_string_field(w, "encoding", encoding);
  206. jsonw_uint_field(w, "size", t->size);
  207. jsonw_uint_field(w, "vlen", vlen);
  208. jsonw_name(w, "values");
  209. jsonw_start_array(w);
  210. } else {
  211. printf(" encoding=%s size=%u vlen=%u", encoding, t->size, vlen);
  212. }
  213. for (i = 0; i < vlen; i++, v++) {
  214. const char *name = btf_str(btf, v->name_off);
  215. if (json_output) {
  216. jsonw_start_object(w);
  217. jsonw_string_field(w, "name", name);
  218. if (btf_kflag(t))
  219. jsonw_int_field(w, "val", v->val);
  220. else
  221. jsonw_uint_field(w, "val", v->val);
  222. jsonw_end_object(w);
  223. } else {
  224. if (btf_kflag(t))
  225. printf("\n\t'%s' val=%d", name, v->val);
  226. else
  227. printf("\n\t'%s' val=%u", name, v->val);
  228. }
  229. }
  230. if (json_output)
  231. jsonw_end_array(w);
  232. break;
  233. }
  234. case BTF_KIND_ENUM64: {
  235. const struct btf_enum64 *v = btf_enum64(t);
  236. __u16 vlen = btf_vlen(t);
  237. const char *encoding;
  238. int i;
  239. encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";
  240. if (json_output) {
  241. jsonw_string_field(w, "encoding", encoding);
  242. jsonw_uint_field(w, "size", t->size);
  243. jsonw_uint_field(w, "vlen", vlen);
  244. jsonw_name(w, "values");
  245. jsonw_start_array(w);
  246. } else {
  247. printf(" encoding=%s size=%u vlen=%u", encoding, t->size, vlen);
  248. }
  249. for (i = 0; i < vlen; i++, v++) {
  250. const char *name = btf_str(btf, v->name_off);
  251. __u64 val = ((__u64)v->val_hi32 << 32) | v->val_lo32;
  252. if (json_output) {
  253. jsonw_start_object(w);
  254. jsonw_string_field(w, "name", name);
  255. if (btf_kflag(t))
  256. jsonw_int_field(w, "val", val);
  257. else
  258. jsonw_uint_field(w, "val", val);
  259. jsonw_end_object(w);
  260. } else {
  261. if (btf_kflag(t))
  262. printf("\n\t'%s' val=%lldLL", name,
  263. (unsigned long long)val);
  264. else
  265. printf("\n\t'%s' val=%lluULL", name,
  266. (unsigned long long)val);
  267. }
  268. }
  269. if (json_output)
  270. jsonw_end_array(w);
  271. break;
  272. }
  273. case BTF_KIND_FWD: {
  274. const char *fwd_kind = BTF_INFO_KFLAG(t->info) ? "union"
  275. : "struct";
  276. if (json_output)
  277. jsonw_string_field(w, "fwd_kind", fwd_kind);
  278. else
  279. printf(" fwd_kind=%s", fwd_kind);
  280. break;
  281. }
  282. case BTF_KIND_FUNC: {
  283. const char *linkage = btf_func_linkage_str(t);
  284. if (json_output) {
  285. jsonw_uint_field(w, "type_id", t->type);
  286. jsonw_string_field(w, "linkage", linkage);
  287. } else {
  288. printf(" type_id=%u linkage=%s", t->type, linkage);
  289. }
  290. break;
  291. }
  292. case BTF_KIND_FUNC_PROTO: {
  293. const struct btf_param *p = (const void *)(t + 1);
  294. __u16 vlen = BTF_INFO_VLEN(t->info);
  295. int i;
  296. if (json_output) {
  297. jsonw_uint_field(w, "ret_type_id", t->type);
  298. jsonw_uint_field(w, "vlen", vlen);
  299. jsonw_name(w, "params");
  300. jsonw_start_array(w);
  301. } else {
  302. printf(" ret_type_id=%u vlen=%u", t->type, vlen);
  303. }
  304. for (i = 0; i < vlen; i++, p++) {
  305. const char *name = btf_str(btf, p->name_off);
  306. if (json_output) {
  307. jsonw_start_object(w);
  308. jsonw_string_field(w, "name", name);
  309. jsonw_uint_field(w, "type_id", p->type);
  310. jsonw_end_object(w);
  311. } else {
  312. printf("\n\t'%s' type_id=%u", name, p->type);
  313. }
  314. }
  315. if (json_output)
  316. jsonw_end_array(w);
  317. break;
  318. }
  319. case BTF_KIND_VAR: {
  320. const struct btf_var *v = (const void *)(t + 1);
  321. const char *linkage;
  322. linkage = btf_var_linkage_str(v->linkage);
  323. if (json_output) {
  324. jsonw_uint_field(w, "type_id", t->type);
  325. jsonw_string_field(w, "linkage", linkage);
  326. } else {
  327. printf(" type_id=%u, linkage=%s", t->type, linkage);
  328. }
  329. break;
  330. }
  331. case BTF_KIND_DATASEC: {
  332. const struct btf_var_secinfo *v = (const void *)(t + 1);
  333. const struct btf_type *vt;
  334. __u16 vlen = BTF_INFO_VLEN(t->info);
  335. int i;
  336. if (json_output) {
  337. jsonw_uint_field(w, "size", t->size);
  338. jsonw_uint_field(w, "vlen", vlen);
  339. jsonw_name(w, "vars");
  340. jsonw_start_array(w);
  341. } else {
  342. printf(" size=%u vlen=%u", t->size, vlen);
  343. }
  344. for (i = 0; i < vlen; i++, v++) {
  345. if (json_output) {
  346. jsonw_start_object(w);
  347. jsonw_uint_field(w, "type_id", v->type);
  348. jsonw_uint_field(w, "offset", v->offset);
  349. jsonw_uint_field(w, "size", v->size);
  350. jsonw_end_object(w);
  351. } else {
  352. printf("\n\ttype_id=%u offset=%u size=%u",
  353. v->type, v->offset, v->size);
  354. if (v->type < btf__type_cnt(btf)) {
  355. vt = btf__type_by_id(btf, v->type);
  356. printf(" (%s '%s')",
  357. btf_kind_str[btf_kind_safe(btf_kind(vt))],
  358. btf_str(btf, vt->name_off));
  359. }
  360. }
  361. }
  362. if (json_output)
  363. jsonw_end_array(w);
  364. break;
  365. }
  366. case BTF_KIND_FLOAT: {
  367. if (json_output)
  368. jsonw_uint_field(w, "size", t->size);
  369. else
  370. printf(" size=%u", t->size);
  371. break;
  372. }
  373. case BTF_KIND_DECL_TAG: {
  374. const struct btf_decl_tag *tag = (const void *)(t + 1);
  375. if (json_output) {
  376. jsonw_uint_field(w, "type_id", t->type);
  377. jsonw_int_field(w, "component_idx", tag->component_idx);
  378. } else {
  379. printf(" type_id=%u component_idx=%d", t->type, tag->component_idx);
  380. }
  381. break;
  382. }
  383. default:
  384. break;
  385. }
  386. if (json_output)
  387. jsonw_end_object(json_wtr);
  388. else
  389. printf("\n");
  390. return 0;
  391. }
  392. static int dump_btf_raw(const struct btf *btf,
  393. __u32 *root_type_ids, int root_type_cnt)
  394. {
  395. const struct btf_type *t;
  396. int i;
  397. if (json_output) {
  398. jsonw_start_object(json_wtr);
  399. jsonw_name(json_wtr, "types");
  400. jsonw_start_array(json_wtr);
  401. }
  402. if (root_type_cnt) {
  403. for (i = 0; i < root_type_cnt; i++) {
  404. t = btf__type_by_id(btf, root_type_ids[i]);
  405. dump_btf_type(btf, root_type_ids[i], t);
  406. }
  407. } else {
  408. const struct btf *base;
  409. int cnt = btf__type_cnt(btf);
  410. int start_id = 1;
  411. base = btf__base_btf(btf);
  412. if (base)
  413. start_id = btf__type_cnt(base);
  414. for (i = start_id; i < cnt; i++) {
  415. t = btf__type_by_id(btf, i);
  416. dump_btf_type(btf, i, t);
  417. }
  418. }
  419. if (json_output) {
  420. jsonw_end_array(json_wtr);
  421. jsonw_end_object(json_wtr);
  422. }
  423. return 0;
  424. }
  425. static int dump_btf_kfuncs(struct btf_dump *d, const struct btf *btf)
  426. {
  427. LIBBPF_OPTS(btf_dump_emit_type_decl_opts, opts);
  428. int cnt = btf__type_cnt(btf);
  429. int i;
  430. printf("\n/* BPF kfuncs */\n");
  431. printf("#ifndef BPF_NO_KFUNC_PROTOTYPES\n");
  432. for (i = 1; i < cnt; i++) {
  433. const struct btf_type *t = btf__type_by_id(btf, i);
  434. const char *name;
  435. int err;
  436. if (!btf_is_decl_tag(t))
  437. continue;
  438. if (btf_decl_tag(t)->component_idx != -1)
  439. continue;
  440. name = btf__name_by_offset(btf, t->name_off);
  441. if (strncmp(name, KFUNC_DECL_TAG, sizeof(KFUNC_DECL_TAG)))
  442. continue;
  443. t = btf__type_by_id(btf, t->type);
  444. if (!btf_is_func(t))
  445. continue;
  446. printf("extern ");
  447. opts.field_name = btf__name_by_offset(btf, t->name_off);
  448. err = btf_dump__emit_type_decl(d, t->type, &opts);
  449. if (err)
  450. return err;
  451. printf(" __weak __ksym;\n");
  452. }
  453. printf("#endif\n\n");
  454. return 0;
  455. }
  456. static void __printf(2, 0) btf_dump_printf(void *ctx,
  457. const char *fmt, va_list args)
  458. {
  459. vfprintf(stdout, fmt, args);
  460. }
  461. static int btf_type_rank(const struct btf *btf, __u32 index, bool has_name)
  462. {
  463. const struct btf_type *t = btf__type_by_id(btf, index);
  464. const int kind = btf_kind(t);
  465. const int max_rank = 10;
  466. if (t->name_off)
  467. has_name = true;
  468. switch (kind) {
  469. case BTF_KIND_ENUM:
  470. case BTF_KIND_ENUM64:
  471. return has_name ? 1 : 0;
  472. case BTF_KIND_INT:
  473. case BTF_KIND_FLOAT:
  474. return 2;
  475. case BTF_KIND_STRUCT:
  476. case BTF_KIND_UNION:
  477. return has_name ? 3 : max_rank;
  478. case BTF_KIND_FUNC_PROTO:
  479. return has_name ? 4 : max_rank;
  480. case BTF_KIND_ARRAY:
  481. if (has_name)
  482. return btf_type_rank(btf, btf_array(t)->type, has_name);
  483. return max_rank;
  484. case BTF_KIND_TYPE_TAG:
  485. case BTF_KIND_CONST:
  486. case BTF_KIND_PTR:
  487. case BTF_KIND_VOLATILE:
  488. case BTF_KIND_RESTRICT:
  489. case BTF_KIND_TYPEDEF:
  490. case BTF_KIND_DECL_TAG:
  491. if (has_name)
  492. return btf_type_rank(btf, t->type, has_name);
  493. return max_rank;
  494. default:
  495. return max_rank;
  496. }
  497. }
  498. static const char *btf_type_sort_name(const struct btf *btf, __u32 index, bool from_ref)
  499. {
  500. const struct btf_type *t = btf__type_by_id(btf, index);
  501. switch (btf_kind(t)) {
  502. case BTF_KIND_ENUM:
  503. case BTF_KIND_ENUM64: {
  504. int name_off = t->name_off;
  505. if (!from_ref && !name_off && btf_vlen(t))
  506. name_off = btf_kind(t) == BTF_KIND_ENUM64 ?
  507. btf_enum64(t)->name_off :
  508. btf_enum(t)->name_off;
  509. return btf__name_by_offset(btf, name_off);
  510. }
  511. case BTF_KIND_ARRAY:
  512. return btf_type_sort_name(btf, btf_array(t)->type, true);
  513. case BTF_KIND_TYPE_TAG:
  514. case BTF_KIND_CONST:
  515. case BTF_KIND_PTR:
  516. case BTF_KIND_VOLATILE:
  517. case BTF_KIND_RESTRICT:
  518. case BTF_KIND_TYPEDEF:
  519. case BTF_KIND_DECL_TAG:
  520. return btf_type_sort_name(btf, t->type, true);
  521. default:
  522. return btf__name_by_offset(btf, t->name_off);
  523. }
  524. return NULL;
  525. }
  526. static __u64 hasher(__u64 hash, __u64 val)
  527. {
  528. return hash * 31 + val;
  529. }
  530. static __u64 btf_name_hasher(__u64 hash, const struct btf *btf, __u32 name_off)
  531. {
  532. if (!name_off)
  533. return hash;
  534. return hasher(hash, str_hash(btf__name_by_offset(btf, name_off)));
  535. }
  536. static __u64 btf_type_disambig_hash(const struct btf *btf, __u32 id, bool include_members)
  537. {
  538. const struct btf_type *t = btf__type_by_id(btf, id);
  539. int i;
  540. size_t hash = 0;
  541. hash = btf_name_hasher(hash, btf, t->name_off);
  542. switch (btf_kind(t)) {
  543. case BTF_KIND_ENUM:
  544. case BTF_KIND_ENUM64:
  545. for (i = 0; i < btf_vlen(t); i++) {
  546. __u32 name_off = btf_is_enum(t) ?
  547. btf_enum(t)[i].name_off :
  548. btf_enum64(t)[i].name_off;
  549. hash = btf_name_hasher(hash, btf, name_off);
  550. }
  551. break;
  552. case BTF_KIND_STRUCT:
  553. case BTF_KIND_UNION:
  554. if (!include_members)
  555. break;
  556. for (i = 0; i < btf_vlen(t); i++) {
  557. const struct btf_member *m = btf_members(t) + i;
  558. hash = btf_name_hasher(hash, btf, m->name_off);
  559. /* resolve field type's name and hash it as well */
  560. hash = hasher(hash, btf_type_disambig_hash(btf, m->type, false));
  561. }
  562. break;
  563. case BTF_KIND_TYPE_TAG:
  564. case BTF_KIND_CONST:
  565. case BTF_KIND_PTR:
  566. case BTF_KIND_VOLATILE:
  567. case BTF_KIND_RESTRICT:
  568. case BTF_KIND_TYPEDEF:
  569. case BTF_KIND_DECL_TAG:
  570. hash = hasher(hash, btf_type_disambig_hash(btf, t->type, include_members));
  571. break;
  572. case BTF_KIND_ARRAY: {
  573. struct btf_array *arr = btf_array(t);
  574. hash = hasher(hash, arr->nelems);
  575. hash = hasher(hash, btf_type_disambig_hash(btf, arr->type, include_members));
  576. break;
  577. }
  578. default:
  579. break;
  580. }
  581. return hash;
  582. }
  583. static int btf_type_compare(const void *left, const void *right)
  584. {
  585. const struct sort_datum *d1 = (const struct sort_datum *)left;
  586. const struct sort_datum *d2 = (const struct sort_datum *)right;
  587. int r;
  588. r = d1->type_rank - d2->type_rank;
  589. r = r ?: strcmp(d1->sort_name, d2->sort_name);
  590. r = r ?: strcmp(d1->own_name, d2->own_name);
  591. if (r)
  592. return r;
  593. if (d1->disambig_hash != d2->disambig_hash)
  594. return d1->disambig_hash < d2->disambig_hash ? -1 : 1;
  595. return d1->index - d2->index;
  596. }
  597. static struct sort_datum *sort_btf_c(const struct btf *btf)
  598. {
  599. struct sort_datum *datums;
  600. int n;
  601. n = btf__type_cnt(btf);
  602. datums = malloc(sizeof(struct sort_datum) * n);
  603. if (!datums)
  604. return NULL;
  605. for (int i = 0; i < n; ++i) {
  606. struct sort_datum *d = datums + i;
  607. const struct btf_type *t = btf__type_by_id(btf, i);
  608. d->index = i;
  609. d->type_rank = btf_type_rank(btf, i, false);
  610. d->sort_name = btf_type_sort_name(btf, i, false);
  611. d->own_name = btf__name_by_offset(btf, t->name_off);
  612. d->disambig_hash = btf_type_disambig_hash(btf, i, true);
  613. }
  614. qsort(datums, n, sizeof(struct sort_datum), btf_type_compare);
  615. return datums;
  616. }
  617. static int dump_btf_c(const struct btf *btf,
  618. __u32 *root_type_ids, int root_type_cnt, bool sort_dump)
  619. {
  620. struct sort_datum *datums = NULL;
  621. struct btf_dump *d;
  622. int err = 0, i;
  623. d = btf_dump__new(btf, btf_dump_printf, NULL, NULL);
  624. if (!d)
  625. return -errno;
  626. printf("#ifndef __VMLINUX_H__\n");
  627. printf("#define __VMLINUX_H__\n");
  628. printf("\n");
  629. printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
  630. printf("#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n");
  631. printf("#endif\n\n");
  632. printf("#ifndef __ksym\n");
  633. printf("#define __ksym __attribute__((section(\".ksyms\")))\n");
  634. printf("#endif\n\n");
  635. printf("#ifndef __weak\n");
  636. printf("#define __weak __attribute__((weak))\n");
  637. printf("#endif\n\n");
  638. if (root_type_cnt) {
  639. for (i = 0; i < root_type_cnt; i++) {
  640. err = btf_dump__dump_type(d, root_type_ids[i]);
  641. if (err)
  642. goto done;
  643. }
  644. } else {
  645. int cnt = btf__type_cnt(btf);
  646. if (sort_dump)
  647. datums = sort_btf_c(btf);
  648. for (i = 1; i < cnt; i++) {
  649. int idx = datums ? datums[i].index : i;
  650. err = btf_dump__dump_type(d, idx);
  651. if (err)
  652. goto done;
  653. }
  654. err = dump_btf_kfuncs(d, btf);
  655. if (err)
  656. goto done;
  657. }
  658. printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
  659. printf("#pragma clang attribute pop\n");
  660. printf("#endif\n");
  661. printf("\n");
  662. printf("#endif /* __VMLINUX_H__ */\n");
  663. done:
  664. free(datums);
  665. btf_dump__free(d);
  666. return err;
  667. }
  668. static const char sysfs_vmlinux[] = "/sys/kernel/btf/vmlinux";
  669. static struct btf *get_vmlinux_btf_from_sysfs(void)
  670. {
  671. struct btf *base;
  672. base = btf__parse(sysfs_vmlinux, NULL);
  673. if (!base)
  674. p_err("failed to parse vmlinux BTF at '%s': %d\n",
  675. sysfs_vmlinux, -errno);
  676. return base;
  677. }
  678. #define BTF_NAME_BUFF_LEN 64
  679. static bool btf_is_kernel_module(__u32 btf_id)
  680. {
  681. struct bpf_btf_info btf_info = {};
  682. char btf_name[BTF_NAME_BUFF_LEN];
  683. int btf_fd;
  684. __u32 len;
  685. int err;
  686. btf_fd = bpf_btf_get_fd_by_id(btf_id);
  687. if (btf_fd < 0) {
  688. p_err("can't get BTF object by id (%u): %s", btf_id, strerror(errno));
  689. return false;
  690. }
  691. len = sizeof(btf_info);
  692. btf_info.name = ptr_to_u64(btf_name);
  693. btf_info.name_len = sizeof(btf_name);
  694. err = bpf_btf_get_info_by_fd(btf_fd, &btf_info, &len);
  695. close(btf_fd);
  696. if (err) {
  697. p_err("can't get BTF (ID %u) object info: %s", btf_id, strerror(errno));
  698. return false;
  699. }
  700. return btf_info.kernel_btf && strncmp(btf_name, "vmlinux", sizeof(btf_name)) != 0;
  701. }
  702. static int do_dump(int argc, char **argv)
  703. {
  704. bool dump_c = false, sort_dump_c = true;
  705. struct btf *btf = NULL, *base = NULL;
  706. __u32 root_type_ids[2];
  707. int root_type_cnt = 0;
  708. __u32 btf_id = -1;
  709. const char *src;
  710. int fd = -1;
  711. int err = 0;
  712. if (!REQ_ARGS(2)) {
  713. usage();
  714. return -1;
  715. }
  716. src = GET_ARG();
  717. if (is_prefix(src, "map")) {
  718. struct bpf_map_info info = {};
  719. __u32 len = sizeof(info);
  720. if (!REQ_ARGS(2)) {
  721. usage();
  722. return -1;
  723. }
  724. fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
  725. if (fd < 0)
  726. return -1;
  727. btf_id = info.btf_id;
  728. if (argc && is_prefix(*argv, "key")) {
  729. root_type_ids[root_type_cnt++] = info.btf_key_type_id;
  730. NEXT_ARG();
  731. } else if (argc && is_prefix(*argv, "value")) {
  732. root_type_ids[root_type_cnt++] = info.btf_value_type_id;
  733. NEXT_ARG();
  734. } else if (argc && is_prefix(*argv, "all")) {
  735. NEXT_ARG();
  736. } else if (argc && is_prefix(*argv, "kv")) {
  737. root_type_ids[root_type_cnt++] = info.btf_key_type_id;
  738. root_type_ids[root_type_cnt++] = info.btf_value_type_id;
  739. NEXT_ARG();
  740. } else {
  741. root_type_ids[root_type_cnt++] = info.btf_key_type_id;
  742. root_type_ids[root_type_cnt++] = info.btf_value_type_id;
  743. }
  744. } else if (is_prefix(src, "prog")) {
  745. struct bpf_prog_info info = {};
  746. __u32 len = sizeof(info);
  747. if (!REQ_ARGS(2)) {
  748. usage();
  749. return -1;
  750. }
  751. fd = prog_parse_fd(&argc, &argv);
  752. if (fd < 0)
  753. return -1;
  754. err = bpf_prog_get_info_by_fd(fd, &info, &len);
  755. if (err) {
  756. p_err("can't get prog info: %s", strerror(errno));
  757. goto done;
  758. }
  759. btf_id = info.btf_id;
  760. } else if (is_prefix(src, "id")) {
  761. char *endptr;
  762. btf_id = strtoul(*argv, &endptr, 0);
  763. if (*endptr) {
  764. p_err("can't parse %s as ID", *argv);
  765. return -1;
  766. }
  767. NEXT_ARG();
  768. } else if (is_prefix(src, "file")) {
  769. const char sysfs_prefix[] = "/sys/kernel/btf/";
  770. if (!base_btf &&
  771. strncmp(*argv, sysfs_prefix, sizeof(sysfs_prefix) - 1) == 0 &&
  772. strcmp(*argv, sysfs_vmlinux) != 0)
  773. base = get_vmlinux_btf_from_sysfs();
  774. btf = btf__parse_split(*argv, base ?: base_btf);
  775. if (!btf) {
  776. err = -errno;
  777. p_err("failed to load BTF from %s: %s",
  778. *argv, strerror(errno));
  779. goto done;
  780. }
  781. NEXT_ARG();
  782. } else {
  783. err = -1;
  784. p_err("unrecognized BTF source specifier: '%s'", src);
  785. goto done;
  786. }
  787. while (argc) {
  788. if (is_prefix(*argv, "format")) {
  789. NEXT_ARG();
  790. if (argc < 1) {
  791. p_err("expecting value for 'format' option\n");
  792. err = -EINVAL;
  793. goto done;
  794. }
  795. if (strcmp(*argv, "c") == 0) {
  796. dump_c = true;
  797. } else if (strcmp(*argv, "raw") == 0) {
  798. dump_c = false;
  799. } else {
  800. p_err("unrecognized format specifier: '%s', possible values: raw, c",
  801. *argv);
  802. err = -EINVAL;
  803. goto done;
  804. }
  805. NEXT_ARG();
  806. } else if (is_prefix(*argv, "unsorted")) {
  807. sort_dump_c = false;
  808. NEXT_ARG();
  809. } else {
  810. p_err("unrecognized option: '%s'", *argv);
  811. err = -EINVAL;
  812. goto done;
  813. }
  814. }
  815. if (!btf) {
  816. if (!base_btf && btf_is_kernel_module(btf_id)) {
  817. p_info("Warning: valid base BTF was not specified with -B option, falling back to standard base BTF (%s)",
  818. sysfs_vmlinux);
  819. base_btf = get_vmlinux_btf_from_sysfs();
  820. }
  821. btf = btf__load_from_kernel_by_id_split(btf_id, base_btf);
  822. if (!btf) {
  823. err = -errno;
  824. p_err("get btf by id (%u): %s", btf_id, strerror(errno));
  825. goto done;
  826. }
  827. }
  828. if (dump_c) {
  829. if (json_output) {
  830. p_err("JSON output for C-syntax dump is not supported");
  831. err = -ENOTSUP;
  832. goto done;
  833. }
  834. err = dump_btf_c(btf, root_type_ids, root_type_cnt, sort_dump_c);
  835. } else {
  836. err = dump_btf_raw(btf, root_type_ids, root_type_cnt);
  837. }
  838. done:
  839. close(fd);
  840. btf__free(btf);
  841. btf__free(base);
  842. return err;
  843. }
  844. static int btf_parse_fd(int *argc, char ***argv)
  845. {
  846. unsigned int id;
  847. char *endptr;
  848. int fd;
  849. if (!is_prefix(*argv[0], "id")) {
  850. p_err("expected 'id', got: '%s'?", **argv);
  851. return -1;
  852. }
  853. NEXT_ARGP();
  854. id = strtoul(**argv, &endptr, 0);
  855. if (*endptr) {
  856. p_err("can't parse %s as ID", **argv);
  857. return -1;
  858. }
  859. NEXT_ARGP();
  860. fd = bpf_btf_get_fd_by_id(id);
  861. if (fd < 0)
  862. p_err("can't get BTF object by id (%u): %s",
  863. id, strerror(errno));
  864. return fd;
  865. }
  866. static int
  867. build_btf_type_table(struct hashmap *tab, enum bpf_obj_type type,
  868. void *info, __u32 *len)
  869. {
  870. static const char * const names[] = {
  871. [BPF_OBJ_UNKNOWN] = "unknown",
  872. [BPF_OBJ_PROG] = "prog",
  873. [BPF_OBJ_MAP] = "map",
  874. };
  875. __u32 btf_id, id = 0;
  876. int err;
  877. int fd;
  878. while (true) {
  879. switch (type) {
  880. case BPF_OBJ_PROG:
  881. err = bpf_prog_get_next_id(id, &id);
  882. break;
  883. case BPF_OBJ_MAP:
  884. err = bpf_map_get_next_id(id, &id);
  885. break;
  886. default:
  887. err = -1;
  888. p_err("unexpected object type: %d", type);
  889. goto err_free;
  890. }
  891. if (err) {
  892. if (errno == ENOENT) {
  893. err = 0;
  894. break;
  895. }
  896. p_err("can't get next %s: %s%s", names[type],
  897. strerror(errno),
  898. errno == EINVAL ? " -- kernel too old?" : "");
  899. goto err_free;
  900. }
  901. switch (type) {
  902. case BPF_OBJ_PROG:
  903. fd = bpf_prog_get_fd_by_id(id);
  904. break;
  905. case BPF_OBJ_MAP:
  906. fd = bpf_map_get_fd_by_id(id);
  907. break;
  908. default:
  909. err = -1;
  910. p_err("unexpected object type: %d", type);
  911. goto err_free;
  912. }
  913. if (fd < 0) {
  914. if (errno == ENOENT)
  915. continue;
  916. p_err("can't get %s by id (%u): %s", names[type], id,
  917. strerror(errno));
  918. err = -1;
  919. goto err_free;
  920. }
  921. memset(info, 0, *len);
  922. if (type == BPF_OBJ_PROG)
  923. err = bpf_prog_get_info_by_fd(fd, info, len);
  924. else
  925. err = bpf_map_get_info_by_fd(fd, info, len);
  926. close(fd);
  927. if (err) {
  928. p_err("can't get %s info: %s", names[type],
  929. strerror(errno));
  930. goto err_free;
  931. }
  932. switch (type) {
  933. case BPF_OBJ_PROG:
  934. btf_id = ((struct bpf_prog_info *)info)->btf_id;
  935. break;
  936. case BPF_OBJ_MAP:
  937. btf_id = ((struct bpf_map_info *)info)->btf_id;
  938. break;
  939. default:
  940. err = -1;
  941. p_err("unexpected object type: %d", type);
  942. goto err_free;
  943. }
  944. if (!btf_id)
  945. continue;
  946. err = hashmap__append(tab, btf_id, id);
  947. if (err) {
  948. p_err("failed to append entry to hashmap for BTF ID %u, object ID %u: %s",
  949. btf_id, id, strerror(-err));
  950. goto err_free;
  951. }
  952. }
  953. return 0;
  954. err_free:
  955. hashmap__free(tab);
  956. return err;
  957. }
  958. static int
  959. build_btf_tables(struct hashmap *btf_prog_table,
  960. struct hashmap *btf_map_table)
  961. {
  962. struct bpf_prog_info prog_info;
  963. __u32 prog_len = sizeof(prog_info);
  964. struct bpf_map_info map_info;
  965. __u32 map_len = sizeof(map_info);
  966. int err = 0;
  967. err = build_btf_type_table(btf_prog_table, BPF_OBJ_PROG, &prog_info,
  968. &prog_len);
  969. if (err)
  970. return err;
  971. err = build_btf_type_table(btf_map_table, BPF_OBJ_MAP, &map_info,
  972. &map_len);
  973. if (err) {
  974. hashmap__free(btf_prog_table);
  975. return err;
  976. }
  977. return 0;
  978. }
  979. static void
  980. show_btf_plain(struct bpf_btf_info *info, int fd,
  981. struct hashmap *btf_prog_table,
  982. struct hashmap *btf_map_table)
  983. {
  984. struct hashmap_entry *entry;
  985. const char *name = u64_to_ptr(info->name);
  986. int n;
  987. printf("%u: ", info->id);
  988. if (info->kernel_btf)
  989. printf("name [%s] ", name);
  990. else if (name && name[0])
  991. printf("name %s ", name);
  992. else
  993. printf("name <anon> ");
  994. printf("size %uB", info->btf_size);
  995. n = 0;
  996. hashmap__for_each_key_entry(btf_prog_table, entry, info->id) {
  997. printf("%s%lu", n++ == 0 ? " prog_ids " : ",", entry->value);
  998. }
  999. n = 0;
  1000. hashmap__for_each_key_entry(btf_map_table, entry, info->id) {
  1001. printf("%s%lu", n++ == 0 ? " map_ids " : ",", entry->value);
  1002. }
  1003. emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
  1004. printf("\n");
  1005. }
  1006. static void
  1007. show_btf_json(struct bpf_btf_info *info, int fd,
  1008. struct hashmap *btf_prog_table,
  1009. struct hashmap *btf_map_table)
  1010. {
  1011. struct hashmap_entry *entry;
  1012. const char *name = u64_to_ptr(info->name);
  1013. jsonw_start_object(json_wtr); /* btf object */
  1014. jsonw_uint_field(json_wtr, "id", info->id);
  1015. jsonw_uint_field(json_wtr, "size", info->btf_size);
  1016. jsonw_name(json_wtr, "prog_ids");
  1017. jsonw_start_array(json_wtr); /* prog_ids */
  1018. hashmap__for_each_key_entry(btf_prog_table, entry, info->id) {
  1019. jsonw_uint(json_wtr, entry->value);
  1020. }
  1021. jsonw_end_array(json_wtr); /* prog_ids */
  1022. jsonw_name(json_wtr, "map_ids");
  1023. jsonw_start_array(json_wtr); /* map_ids */
  1024. hashmap__for_each_key_entry(btf_map_table, entry, info->id) {
  1025. jsonw_uint(json_wtr, entry->value);
  1026. }
  1027. jsonw_end_array(json_wtr); /* map_ids */
  1028. emit_obj_refs_json(refs_table, info->id, json_wtr); /* pids */
  1029. jsonw_bool_field(json_wtr, "kernel", info->kernel_btf);
  1030. if (name && name[0])
  1031. jsonw_string_field(json_wtr, "name", name);
  1032. jsonw_end_object(json_wtr); /* btf object */
  1033. }
  1034. static int
  1035. show_btf(int fd, struct hashmap *btf_prog_table,
  1036. struct hashmap *btf_map_table)
  1037. {
  1038. struct bpf_btf_info info;
  1039. __u32 len = sizeof(info);
  1040. char name[64];
  1041. int err;
  1042. memset(&info, 0, sizeof(info));
  1043. err = bpf_btf_get_info_by_fd(fd, &info, &len);
  1044. if (err) {
  1045. p_err("can't get BTF object info: %s", strerror(errno));
  1046. return -1;
  1047. }
  1048. /* if kernel support emitting BTF object name, pass name pointer */
  1049. if (info.name_len) {
  1050. memset(&info, 0, sizeof(info));
  1051. info.name_len = sizeof(name);
  1052. info.name = ptr_to_u64(name);
  1053. len = sizeof(info);
  1054. err = bpf_btf_get_info_by_fd(fd, &info, &len);
  1055. if (err) {
  1056. p_err("can't get BTF object info: %s", strerror(errno));
  1057. return -1;
  1058. }
  1059. }
  1060. if (json_output)
  1061. show_btf_json(&info, fd, btf_prog_table, btf_map_table);
  1062. else
  1063. show_btf_plain(&info, fd, btf_prog_table, btf_map_table);
  1064. return 0;
  1065. }
  1066. static int do_show(int argc, char **argv)
  1067. {
  1068. struct hashmap *btf_prog_table;
  1069. struct hashmap *btf_map_table;
  1070. int err, fd = -1;
  1071. __u32 id = 0;
  1072. if (argc == 2) {
  1073. fd = btf_parse_fd(&argc, &argv);
  1074. if (fd < 0)
  1075. return -1;
  1076. }
  1077. if (argc) {
  1078. if (fd >= 0)
  1079. close(fd);
  1080. return BAD_ARG();
  1081. }
  1082. btf_prog_table = hashmap__new(hash_fn_for_key_as_id,
  1083. equal_fn_for_key_as_id, NULL);
  1084. btf_map_table = hashmap__new(hash_fn_for_key_as_id,
  1085. equal_fn_for_key_as_id, NULL);
  1086. if (IS_ERR(btf_prog_table) || IS_ERR(btf_map_table)) {
  1087. hashmap__free(btf_prog_table);
  1088. hashmap__free(btf_map_table);
  1089. if (fd >= 0)
  1090. close(fd);
  1091. p_err("failed to create hashmap for object references");
  1092. return -1;
  1093. }
  1094. err = build_btf_tables(btf_prog_table, btf_map_table);
  1095. if (err) {
  1096. if (fd >= 0)
  1097. close(fd);
  1098. return err;
  1099. }
  1100. build_obj_refs_table(&refs_table, BPF_OBJ_BTF);
  1101. if (fd >= 0) {
  1102. err = show_btf(fd, btf_prog_table, btf_map_table);
  1103. close(fd);
  1104. goto exit_free;
  1105. }
  1106. if (json_output)
  1107. jsonw_start_array(json_wtr); /* root array */
  1108. while (true) {
  1109. err = bpf_btf_get_next_id(id, &id);
  1110. if (err) {
  1111. if (errno == ENOENT) {
  1112. err = 0;
  1113. break;
  1114. }
  1115. p_err("can't get next BTF object: %s%s",
  1116. strerror(errno),
  1117. errno == EINVAL ? " -- kernel too old?" : "");
  1118. err = -1;
  1119. break;
  1120. }
  1121. fd = bpf_btf_get_fd_by_id(id);
  1122. if (fd < 0) {
  1123. if (errno == ENOENT)
  1124. continue;
  1125. p_err("can't get BTF object by id (%u): %s",
  1126. id, strerror(errno));
  1127. err = -1;
  1128. break;
  1129. }
  1130. err = show_btf(fd, btf_prog_table, btf_map_table);
  1131. close(fd);
  1132. if (err)
  1133. break;
  1134. }
  1135. if (json_output)
  1136. jsonw_end_array(json_wtr); /* root array */
  1137. exit_free:
  1138. hashmap__free(btf_prog_table);
  1139. hashmap__free(btf_map_table);
  1140. delete_obj_refs_table(refs_table);
  1141. return err;
  1142. }
  1143. static int do_help(int argc, char **argv)
  1144. {
  1145. if (json_output) {
  1146. jsonw_null(json_wtr);
  1147. return 0;
  1148. }
  1149. fprintf(stderr,
  1150. "Usage: %1$s %2$s { show | list } [id BTF_ID]\n"
  1151. " %1$s %2$s dump BTF_SRC [format FORMAT]\n"
  1152. " %1$s %2$s help\n"
  1153. "\n"
  1154. " BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"
  1155. " FORMAT := { raw | c [unsorted] }\n"
  1156. " " HELP_SPEC_MAP "\n"
  1157. " " HELP_SPEC_PROGRAM "\n"
  1158. " " HELP_SPEC_OPTIONS " |\n"
  1159. " {-B|--base-btf} }\n"
  1160. "",
  1161. bin_name, "btf");
  1162. return 0;
  1163. }
  1164. static const struct cmd cmds[] = {
  1165. { "show", do_show },
  1166. { "list", do_show },
  1167. { "help", do_help },
  1168. { "dump", do_dump },
  1169. { 0 }
  1170. };
  1171. int do_btf(int argc, char **argv)
  1172. {
  1173. return cmd_select(cmds, argc, argv, do_help);
  1174. }