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