]> asedeno.scripts.mit.edu Git - linux.git/blob - tools/bpf/bpftool/btf.c
Merge tag 'random_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel...
[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 #include <errno.h>
5 #include <fcntl.h>
6 #include <linux/err.h>
7 #include <stdbool.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <gelf.h>
12 #include <bpf.h>
13 #include <linux/btf.h>
14
15 #include "btf.h"
16 #include "json_writer.h"
17 #include "main.h"
18
19 static const char * const btf_kind_str[NR_BTF_KINDS] = {
20         [BTF_KIND_UNKN]         = "UNKNOWN",
21         [BTF_KIND_INT]          = "INT",
22         [BTF_KIND_PTR]          = "PTR",
23         [BTF_KIND_ARRAY]        = "ARRAY",
24         [BTF_KIND_STRUCT]       = "STRUCT",
25         [BTF_KIND_UNION]        = "UNION",
26         [BTF_KIND_ENUM]         = "ENUM",
27         [BTF_KIND_FWD]          = "FWD",
28         [BTF_KIND_TYPEDEF]      = "TYPEDEF",
29         [BTF_KIND_VOLATILE]     = "VOLATILE",
30         [BTF_KIND_CONST]        = "CONST",
31         [BTF_KIND_RESTRICT]     = "RESTRICT",
32         [BTF_KIND_FUNC]         = "FUNC",
33         [BTF_KIND_FUNC_PROTO]   = "FUNC_PROTO",
34         [BTF_KIND_VAR]          = "VAR",
35         [BTF_KIND_DATASEC]      = "DATASEC",
36 };
37
38 static const char *btf_int_enc_str(__u8 encoding)
39 {
40         switch (encoding) {
41         case 0:
42                 return "(none)";
43         case BTF_INT_SIGNED:
44                 return "SIGNED";
45         case BTF_INT_CHAR:
46                 return "CHAR";
47         case BTF_INT_BOOL:
48                 return "BOOL";
49         default:
50                 return "UNKN";
51         }
52 }
53
54 static const char *btf_var_linkage_str(__u32 linkage)
55 {
56         switch (linkage) {
57         case BTF_VAR_STATIC:
58                 return "static";
59         case BTF_VAR_GLOBAL_ALLOCATED:
60                 return "global-alloc";
61         default:
62                 return "(unknown)";
63         }
64 }
65
66 static const char *btf_str(const struct btf *btf, __u32 off)
67 {
68         if (!off)
69                 return "(anon)";
70         return btf__name_by_offset(btf, off) ? : "(invalid)";
71 }
72
73 static int dump_btf_type(const struct btf *btf, __u32 id,
74                          const struct btf_type *t)
75 {
76         json_writer_t *w = json_wtr;
77         int kind, safe_kind;
78
79         kind = BTF_INFO_KIND(t->info);
80         safe_kind = kind <= BTF_KIND_MAX ? kind : BTF_KIND_UNKN;
81
82         if (json_output) {
83                 jsonw_start_object(w);
84                 jsonw_uint_field(w, "id", id);
85                 jsonw_string_field(w, "kind", btf_kind_str[safe_kind]);
86                 jsonw_string_field(w, "name", btf_str(btf, t->name_off));
87         } else {
88                 printf("[%u] %s '%s'", id, btf_kind_str[safe_kind],
89                        btf_str(btf, t->name_off));
90         }
91
92         switch (BTF_INFO_KIND(t->info)) {
93         case BTF_KIND_INT: {
94                 __u32 v = *(__u32 *)(t + 1);
95                 const char *enc;
96
97                 enc = btf_int_enc_str(BTF_INT_ENCODING(v));
98
99                 if (json_output) {
100                         jsonw_uint_field(w, "size", t->size);
101                         jsonw_uint_field(w, "bits_offset", BTF_INT_OFFSET(v));
102                         jsonw_uint_field(w, "nr_bits", BTF_INT_BITS(v));
103                         jsonw_string_field(w, "encoding", enc);
104                 } else {
105                         printf(" size=%u bits_offset=%u nr_bits=%u encoding=%s",
106                                t->size, BTF_INT_OFFSET(v), BTF_INT_BITS(v),
107                                enc);
108                 }
109                 break;
110         }
111         case BTF_KIND_PTR:
112         case BTF_KIND_CONST:
113         case BTF_KIND_VOLATILE:
114         case BTF_KIND_RESTRICT:
115         case BTF_KIND_TYPEDEF:
116                 if (json_output)
117                         jsonw_uint_field(w, "type_id", t->type);
118                 else
119                         printf(" type_id=%u", t->type);
120                 break;
121         case BTF_KIND_ARRAY: {
122                 const struct btf_array *arr = (const void *)(t + 1);
123
124                 if (json_output) {
125                         jsonw_uint_field(w, "type_id", arr->type);
126                         jsonw_uint_field(w, "index_type_id", arr->index_type);
127                         jsonw_uint_field(w, "nr_elems", arr->nelems);
128                 } else {
129                         printf(" type_id=%u index_type_id=%u nr_elems=%u",
130                                arr->type, arr->index_type, arr->nelems);
131                 }
132                 break;
133         }
134         case BTF_KIND_STRUCT:
135         case BTF_KIND_UNION: {
136                 const struct btf_member *m = (const void *)(t + 1);
137                 __u16 vlen = BTF_INFO_VLEN(t->info);
138                 int i;
139
140                 if (json_output) {
141                         jsonw_uint_field(w, "size", t->size);
142                         jsonw_uint_field(w, "vlen", vlen);
143                         jsonw_name(w, "members");
144                         jsonw_start_array(w);
145                 } else {
146                         printf(" size=%u vlen=%u", t->size, vlen);
147                 }
148                 for (i = 0; i < vlen; i++, m++) {
149                         const char *name = btf_str(btf, m->name_off);
150                         __u32 bit_off, bit_sz;
151
152                         if (BTF_INFO_KFLAG(t->info)) {
153                                 bit_off = BTF_MEMBER_BIT_OFFSET(m->offset);
154                                 bit_sz = BTF_MEMBER_BITFIELD_SIZE(m->offset);
155                         } else {
156                                 bit_off = m->offset;
157                                 bit_sz = 0;
158                         }
159
160                         if (json_output) {
161                                 jsonw_start_object(w);
162                                 jsonw_string_field(w, "name", name);
163                                 jsonw_uint_field(w, "type_id", m->type);
164                                 jsonw_uint_field(w, "bits_offset", bit_off);
165                                 if (bit_sz) {
166                                         jsonw_uint_field(w, "bitfield_size",
167                                                          bit_sz);
168                                 }
169                                 jsonw_end_object(w);
170                         } else {
171                                 printf("\n\t'%s' type_id=%u bits_offset=%u",
172                                        name, m->type, bit_off);
173                                 if (bit_sz)
174                                         printf(" bitfield_size=%u", bit_sz);
175                         }
176                 }
177                 if (json_output)
178                         jsonw_end_array(w);
179                 break;
180         }
181         case BTF_KIND_ENUM: {
182                 const struct btf_enum *v = (const void *)(t + 1);
183                 __u16 vlen = BTF_INFO_VLEN(t->info);
184                 int i;
185
186                 if (json_output) {
187                         jsonw_uint_field(w, "size", t->size);
188                         jsonw_uint_field(w, "vlen", vlen);
189                         jsonw_name(w, "values");
190                         jsonw_start_array(w);
191                 } else {
192                         printf(" size=%u vlen=%u", t->size, vlen);
193                 }
194                 for (i = 0; i < vlen; i++, v++) {
195                         const char *name = btf_str(btf, v->name_off);
196
197                         if (json_output) {
198                                 jsonw_start_object(w);
199                                 jsonw_string_field(w, "name", name);
200                                 jsonw_uint_field(w, "val", v->val);
201                                 jsonw_end_object(w);
202                         } else {
203                                 printf("\n\t'%s' val=%u", name, v->val);
204                         }
205                 }
206                 if (json_output)
207                         jsonw_end_array(w);
208                 break;
209         }
210         case BTF_KIND_FWD: {
211                 const char *fwd_kind = BTF_INFO_KFLAG(t->info) ? "union"
212                                                                : "struct";
213
214                 if (json_output)
215                         jsonw_string_field(w, "fwd_kind", fwd_kind);
216                 else
217                         printf(" fwd_kind=%s", fwd_kind);
218                 break;
219         }
220         case BTF_KIND_FUNC:
221                 if (json_output)
222                         jsonw_uint_field(w, "type_id", t->type);
223                 else
224                         printf(" type_id=%u", t->type);
225                 break;
226         case BTF_KIND_FUNC_PROTO: {
227                 const struct btf_param *p = (const void *)(t + 1);
228                 __u16 vlen = BTF_INFO_VLEN(t->info);
229                 int i;
230
231                 if (json_output) {
232                         jsonw_uint_field(w, "ret_type_id", t->type);
233                         jsonw_uint_field(w, "vlen", vlen);
234                         jsonw_name(w, "params");
235                         jsonw_start_array(w);
236                 } else {
237                         printf(" ret_type_id=%u vlen=%u", t->type, vlen);
238                 }
239                 for (i = 0; i < vlen; i++, p++) {
240                         const char *name = btf_str(btf, p->name_off);
241
242                         if (json_output) {
243                                 jsonw_start_object(w);
244                                 jsonw_string_field(w, "name", name);
245                                 jsonw_uint_field(w, "type_id", p->type);
246                                 jsonw_end_object(w);
247                         } else {
248                                 printf("\n\t'%s' type_id=%u", name, p->type);
249                         }
250                 }
251                 if (json_output)
252                         jsonw_end_array(w);
253                 break;
254         }
255         case BTF_KIND_VAR: {
256                 const struct btf_var *v = (const void *)(t + 1);
257                 const char *linkage;
258
259                 linkage = btf_var_linkage_str(v->linkage);
260
261                 if (json_output) {
262                         jsonw_uint_field(w, "type_id", t->type);
263                         jsonw_string_field(w, "linkage", linkage);
264                 } else {
265                         printf(" type_id=%u, linkage=%s", t->type, linkage);
266                 }
267                 break;
268         }
269         case BTF_KIND_DATASEC: {
270                 const struct btf_var_secinfo *v = (const void *)(t+1);
271                 __u16 vlen = BTF_INFO_VLEN(t->info);
272                 int i;
273
274                 if (json_output) {
275                         jsonw_uint_field(w, "size", t->size);
276                         jsonw_uint_field(w, "vlen", vlen);
277                         jsonw_name(w, "vars");
278                         jsonw_start_array(w);
279                 } else {
280                         printf(" size=%u vlen=%u", t->size, vlen);
281                 }
282                 for (i = 0; i < vlen; i++, v++) {
283                         if (json_output) {
284                                 jsonw_start_object(w);
285                                 jsonw_uint_field(w, "type_id", v->type);
286                                 jsonw_uint_field(w, "offset", v->offset);
287                                 jsonw_uint_field(w, "size", v->size);
288                                 jsonw_end_object(w);
289                         } else {
290                                 printf("\n\ttype_id=%u offset=%u size=%u",
291                                        v->type, v->offset, v->size);
292                         }
293                 }
294                 if (json_output)
295                         jsonw_end_array(w);
296                 break;
297         }
298         default:
299                 break;
300         }
301
302         if (json_output)
303                 jsonw_end_object(json_wtr);
304         else
305                 printf("\n");
306
307         return 0;
308 }
309
310 static int dump_btf_raw(const struct btf *btf,
311                         __u32 *root_type_ids, int root_type_cnt)
312 {
313         const struct btf_type *t;
314         int i;
315
316         if (json_output) {
317                 jsonw_start_object(json_wtr);
318                 jsonw_name(json_wtr, "types");
319                 jsonw_start_array(json_wtr);
320         }
321
322         if (root_type_cnt) {
323                 for (i = 0; i < root_type_cnt; i++) {
324                         t = btf__type_by_id(btf, root_type_ids[i]);
325                         dump_btf_type(btf, root_type_ids[i], t);
326                 }
327         } else {
328                 int cnt = btf__get_nr_types(btf);
329
330                 for (i = 1; i <= cnt; i++) {
331                         t = btf__type_by_id(btf, i);
332                         dump_btf_type(btf, i, t);
333                 }
334         }
335
336         if (json_output) {
337                 jsonw_end_array(json_wtr);
338                 jsonw_end_object(json_wtr);
339         }
340         return 0;
341 }
342
343 static bool check_btf_endianness(GElf_Ehdr *ehdr)
344 {
345         static unsigned int const endian = 1;
346
347         switch (ehdr->e_ident[EI_DATA]) {
348         case ELFDATA2LSB:
349                 return *(unsigned char const *)&endian == 1;
350         case ELFDATA2MSB:
351                 return *(unsigned char const *)&endian == 0;
352         default:
353                 return 0;
354         }
355 }
356
357 static int btf_load_from_elf(const char *path, struct btf **btf)
358 {
359         int err = -1, fd = -1, idx = 0;
360         Elf_Data *btf_data = NULL;
361         Elf_Scn *scn = NULL;
362         Elf *elf = NULL;
363         GElf_Ehdr ehdr;
364
365         if (elf_version(EV_CURRENT) == EV_NONE) {
366                 p_err("failed to init libelf for %s", path);
367                 return -1;
368         }
369
370         fd = open(path, O_RDONLY);
371         if (fd < 0) {
372                 p_err("failed to open %s: %s", path, strerror(errno));
373                 return -1;
374         }
375
376         elf = elf_begin(fd, ELF_C_READ, NULL);
377         if (!elf) {
378                 p_err("failed to open %s as ELF file", path);
379                 goto done;
380         }
381         if (!gelf_getehdr(elf, &ehdr)) {
382                 p_err("failed to get EHDR from %s", path);
383                 goto done;
384         }
385         if (!check_btf_endianness(&ehdr)) {
386                 p_err("non-native ELF endianness is not supported");
387                 goto done;
388         }
389         if (!elf_rawdata(elf_getscn(elf, ehdr.e_shstrndx), NULL)) {
390                 p_err("failed to get e_shstrndx from %s\n", path);
391                 goto done;
392         }
393
394         while ((scn = elf_nextscn(elf, scn)) != NULL) {
395                 GElf_Shdr sh;
396                 char *name;
397
398                 idx++;
399                 if (gelf_getshdr(scn, &sh) != &sh) {
400                         p_err("failed to get section(%d) header from %s",
401                               idx, path);
402                         goto done;
403                 }
404                 name = elf_strptr(elf, ehdr.e_shstrndx, sh.sh_name);
405                 if (!name) {
406                         p_err("failed to get section(%d) name from %s",
407                               idx, path);
408                         goto done;
409                 }
410                 if (strcmp(name, BTF_ELF_SEC) == 0) {
411                         btf_data = elf_getdata(scn, 0);
412                         if (!btf_data) {
413                                 p_err("failed to get section(%d, %s) data from %s",
414                                       idx, name, path);
415                                 goto done;
416                         }
417                         break;
418                 }
419         }
420
421         if (!btf_data) {
422                 p_err("%s ELF section not found in %s", BTF_ELF_SEC, path);
423                 goto done;
424         }
425
426         *btf = btf__new(btf_data->d_buf, btf_data->d_size);
427         if (IS_ERR(*btf)) {
428                 err = PTR_ERR(*btf);
429                 *btf = NULL;
430                 p_err("failed to load BTF data from %s: %s",
431                       path, strerror(err));
432                 goto done;
433         }
434
435         err = 0;
436 done:
437         if (err) {
438                 if (*btf) {
439                         btf__free(*btf);
440                         *btf = NULL;
441                 }
442         }
443         if (elf)
444                 elf_end(elf);
445         close(fd);
446         return err;
447 }
448
449 static int do_dump(int argc, char **argv)
450 {
451         struct btf *btf = NULL;
452         __u32 root_type_ids[2];
453         int root_type_cnt = 0;
454         __u32 btf_id = -1;
455         const char *src;
456         int fd = -1;
457         int err;
458
459         if (!REQ_ARGS(2)) {
460                 usage();
461                 return -1;
462         }
463         src = GET_ARG();
464
465         if (is_prefix(src, "map")) {
466                 struct bpf_map_info info = {};
467                 __u32 len = sizeof(info);
468
469                 if (!REQ_ARGS(2)) {
470                         usage();
471                         return -1;
472                 }
473
474                 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
475                 if (fd < 0)
476                         return -1;
477
478                 btf_id = info.btf_id;
479                 if (argc && is_prefix(*argv, "key")) {
480                         root_type_ids[root_type_cnt++] = info.btf_key_type_id;
481                         NEXT_ARG();
482                 } else if (argc && is_prefix(*argv, "value")) {
483                         root_type_ids[root_type_cnt++] = info.btf_value_type_id;
484                         NEXT_ARG();
485                 } else if (argc && is_prefix(*argv, "all")) {
486                         NEXT_ARG();
487                 } else if (argc && is_prefix(*argv, "kv")) {
488                         root_type_ids[root_type_cnt++] = info.btf_key_type_id;
489                         root_type_ids[root_type_cnt++] = info.btf_value_type_id;
490                         NEXT_ARG();
491                 } else {
492                         root_type_ids[root_type_cnt++] = info.btf_key_type_id;
493                         root_type_ids[root_type_cnt++] = info.btf_value_type_id;
494                 }
495         } else if (is_prefix(src, "prog")) {
496                 struct bpf_prog_info info = {};
497                 __u32 len = sizeof(info);
498
499                 if (!REQ_ARGS(2)) {
500                         usage();
501                         return -1;
502                 }
503
504                 fd = prog_parse_fd(&argc, &argv);
505                 if (fd < 0)
506                         return -1;
507
508                 err = bpf_obj_get_info_by_fd(fd, &info, &len);
509                 if (err) {
510                         p_err("can't get prog info: %s", strerror(errno));
511                         goto done;
512                 }
513
514                 btf_id = info.btf_id;
515         } else if (is_prefix(src, "id")) {
516                 char *endptr;
517
518                 btf_id = strtoul(*argv, &endptr, 0);
519                 if (*endptr) {
520                         p_err("can't parse %s as ID", **argv);
521                         return -1;
522                 }
523                 NEXT_ARG();
524         } else if (is_prefix(src, "file")) {
525                 err = btf_load_from_elf(*argv, &btf);
526                 if (err)
527                         goto done;
528                 NEXT_ARG();
529         } else {
530                 err = -1;
531                 p_err("unrecognized BTF source specifier: '%s'", src);
532                 goto done;
533         }
534
535         if (!btf) {
536                 err = btf__get_from_id(btf_id, &btf);
537                 if (err) {
538                         p_err("get btf by id (%u): %s", btf_id, strerror(err));
539                         goto done;
540                 }
541                 if (!btf) {
542                         err = ENOENT;
543                         p_err("can't find btf with ID (%u)", btf_id);
544                         goto done;
545                 }
546         }
547
548         dump_btf_raw(btf, root_type_ids, root_type_cnt);
549
550 done:
551         close(fd);
552         btf__free(btf);
553         return err;
554 }
555
556 static int do_help(int argc, char **argv)
557 {
558         if (json_output) {
559                 jsonw_null(json_wtr);
560                 return 0;
561         }
562
563         fprintf(stderr,
564                 "Usage: %s btf dump BTF_SRC\n"
565                 "       %s btf help\n"
566                 "\n"
567                 "       BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"
568                 "       " HELP_SPEC_MAP "\n"
569                 "       " HELP_SPEC_PROGRAM "\n"
570                 "       " HELP_SPEC_OPTIONS "\n"
571                 "",
572                 bin_name, bin_name);
573
574         return 0;
575 }
576
577 static const struct cmd cmds[] = {
578         { "help",       do_help },
579         { "dump",       do_dump },
580         { 0 }
581 };
582
583 int do_btf(int argc, char **argv)
584 {
585         return cmd_select(cmds, argc, argv, do_help);
586 }