root/tools/bpf/bpftool/btf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. btf_int_enc_str
  2. btf_var_linkage_str
  3. btf_str
  4. dump_btf_type
  5. dump_btf_raw
  6. __printf
  7. dump_btf_c
  8. do_dump
  9. btf_parse_fd
  10. delete_btf_table
  11. build_btf_type_table
  12. build_btf_tables
  13. show_btf_plain
  14. show_btf_json
  15. show_btf
  16. do_show
  17. do_help
  18. do_btf

   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 <bpf.h>
  12 #include <libbpf.h>
  13 #include <linux/btf.h>
  14 #include <linux/hashtable.h>
  15 
  16 #include "btf.h"
  17 #include "json_writer.h"
  18 #include "main.h"
  19 
  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 };
  38 
  39 struct btf_attach_table {
  40         DECLARE_HASHTABLE(table, 16);
  41 };
  42 
  43 struct btf_attach_point {
  44         __u32 obj_id;
  45         __u32 btf_id;
  46         struct hlist_node hash;
  47 };
  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 
  65 static const char *btf_var_linkage_str(__u32 linkage)
  66 {
  67         switch (linkage) {
  68         case BTF_VAR_STATIC:
  69                 return "static";
  70         case BTF_VAR_GLOBAL_ALLOCATED:
  71                 return "global-alloc";
  72         default:
  73                 return "(unknown)";
  74         }
  75 }
  76 
  77 static const char *btf_str(const struct btf *btf, __u32 off)
  78 {
  79         if (!off)
  80                 return "(anon)";
  81         return btf__name_by_offset(btf, off) ? : "(invalid)";
  82 }
  83 
  84 static int dump_btf_type(const struct btf *btf, __u32 id,
  85                          const struct btf_type *t)
  86 {
  87         json_writer_t *w = json_wtr;
  88         int kind, safe_kind;
  89 
  90         kind = BTF_INFO_KIND(t->info);
  91         safe_kind = kind <= BTF_KIND_MAX ? kind : BTF_KIND_UNKN;
  92 
  93         if (json_output) {
  94                 jsonw_start_object(w);
  95                 jsonw_uint_field(w, "id", id);
  96                 jsonw_string_field(w, "kind", btf_kind_str[safe_kind]);
  97                 jsonw_string_field(w, "name", btf_str(btf, t->name_off));
  98         } else {
  99                 printf("[%u] %s '%s'", id, btf_kind_str[safe_kind],
 100                        btf_str(btf, t->name_off));
 101         }
 102 
 103         switch (BTF_INFO_KIND(t->info)) {
 104         case BTF_KIND_INT: {
 105                 __u32 v = *(__u32 *)(t + 1);
 106                 const char *enc;
 107 
 108                 enc = btf_int_enc_str(BTF_INT_ENCODING(v));
 109 
 110                 if (json_output) {
 111                         jsonw_uint_field(w, "size", t->size);
 112                         jsonw_uint_field(w, "bits_offset", BTF_INT_OFFSET(v));
 113                         jsonw_uint_field(w, "nr_bits", BTF_INT_BITS(v));
 114                         jsonw_string_field(w, "encoding", enc);
 115                 } else {
 116                         printf(" size=%u bits_offset=%u nr_bits=%u encoding=%s",
 117                                t->size, BTF_INT_OFFSET(v), BTF_INT_BITS(v),
 118                                enc);
 119                 }
 120                 break;
 121         }
 122         case BTF_KIND_PTR:
 123         case BTF_KIND_CONST:
 124         case BTF_KIND_VOLATILE:
 125         case BTF_KIND_RESTRICT:
 126         case BTF_KIND_TYPEDEF:
 127                 if (json_output)
 128                         jsonw_uint_field(w, "type_id", t->type);
 129                 else
 130                         printf(" type_id=%u", t->type);
 131                 break;
 132         case BTF_KIND_ARRAY: {
 133                 const struct btf_array *arr = (const void *)(t + 1);
 134 
 135                 if (json_output) {
 136                         jsonw_uint_field(w, "type_id", arr->type);
 137                         jsonw_uint_field(w, "index_type_id", arr->index_type);
 138                         jsonw_uint_field(w, "nr_elems", arr->nelems);
 139                 } else {
 140                         printf(" type_id=%u index_type_id=%u nr_elems=%u",
 141                                arr->type, arr->index_type, arr->nelems);
 142                 }
 143                 break;
 144         }
 145         case BTF_KIND_STRUCT:
 146         case BTF_KIND_UNION: {
 147                 const struct btf_member *m = (const void *)(t + 1);
 148                 __u16 vlen = BTF_INFO_VLEN(t->info);
 149                 int i;
 150 
 151                 if (json_output) {
 152                         jsonw_uint_field(w, "size", t->size);
 153                         jsonw_uint_field(w, "vlen", vlen);
 154                         jsonw_name(w, "members");
 155                         jsonw_start_array(w);
 156                 } else {
 157                         printf(" size=%u vlen=%u", t->size, vlen);
 158                 }
 159                 for (i = 0; i < vlen; i++, m++) {
 160                         const char *name = btf_str(btf, m->name_off);
 161                         __u32 bit_off, bit_sz;
 162 
 163                         if (BTF_INFO_KFLAG(t->info)) {
 164                                 bit_off = BTF_MEMBER_BIT_OFFSET(m->offset);
 165                                 bit_sz = BTF_MEMBER_BITFIELD_SIZE(m->offset);
 166                         } else {
 167                                 bit_off = m->offset;
 168                                 bit_sz = 0;
 169                         }
 170 
 171                         if (json_output) {
 172                                 jsonw_start_object(w);
 173                                 jsonw_string_field(w, "name", name);
 174                                 jsonw_uint_field(w, "type_id", m->type);
 175                                 jsonw_uint_field(w, "bits_offset", bit_off);
 176                                 if (bit_sz) {
 177                                         jsonw_uint_field(w, "bitfield_size",
 178                                                          bit_sz);
 179                                 }
 180                                 jsonw_end_object(w);
 181                         } else {
 182                                 printf("\n\t'%s' type_id=%u bits_offset=%u",
 183                                        name, m->type, bit_off);
 184                                 if (bit_sz)
 185                                         printf(" bitfield_size=%u", bit_sz);
 186                         }
 187                 }
 188                 if (json_output)
 189                         jsonw_end_array(w);
 190                 break;
 191         }
 192         case BTF_KIND_ENUM: {
 193                 const struct btf_enum *v = (const void *)(t + 1);
 194                 __u16 vlen = BTF_INFO_VLEN(t->info);
 195                 int i;
 196 
 197                 if (json_output) {
 198                         jsonw_uint_field(w, "size", t->size);
 199                         jsonw_uint_field(w, "vlen", vlen);
 200                         jsonw_name(w, "values");
 201                         jsonw_start_array(w);
 202                 } else {
 203                         printf(" size=%u vlen=%u", t->size, vlen);
 204                 }
 205                 for (i = 0; i < vlen; i++, v++) {
 206                         const char *name = btf_str(btf, v->name_off);
 207 
 208                         if (json_output) {
 209                                 jsonw_start_object(w);
 210                                 jsonw_string_field(w, "name", name);
 211                                 jsonw_uint_field(w, "val", v->val);
 212                                 jsonw_end_object(w);
 213                         } else {
 214                                 printf("\n\t'%s' val=%u", name, v->val);
 215                         }
 216                 }
 217                 if (json_output)
 218                         jsonw_end_array(w);
 219                 break;
 220         }
 221         case BTF_KIND_FWD: {
 222                 const char *fwd_kind = BTF_INFO_KFLAG(t->info) ? "union"
 223                                                                : "struct";
 224 
 225                 if (json_output)
 226                         jsonw_string_field(w, "fwd_kind", fwd_kind);
 227                 else
 228                         printf(" fwd_kind=%s", fwd_kind);
 229                 break;
 230         }
 231         case BTF_KIND_FUNC:
 232                 if (json_output)
 233                         jsonw_uint_field(w, "type_id", t->type);
 234                 else
 235                         printf(" type_id=%u", t->type);
 236                 break;
 237         case BTF_KIND_FUNC_PROTO: {
 238                 const struct btf_param *p = (const void *)(t + 1);
 239                 __u16 vlen = BTF_INFO_VLEN(t->info);
 240                 int i;
 241 
 242                 if (json_output) {
 243                         jsonw_uint_field(w, "ret_type_id", t->type);
 244                         jsonw_uint_field(w, "vlen", vlen);
 245                         jsonw_name(w, "params");
 246                         jsonw_start_array(w);
 247                 } else {
 248                         printf(" ret_type_id=%u vlen=%u", t->type, vlen);
 249                 }
 250                 for (i = 0; i < vlen; i++, p++) {
 251                         const char *name = btf_str(btf, p->name_off);
 252 
 253                         if (json_output) {
 254                                 jsonw_start_object(w);
 255                                 jsonw_string_field(w, "name", name);
 256                                 jsonw_uint_field(w, "type_id", p->type);
 257                                 jsonw_end_object(w);
 258                         } else {
 259                                 printf("\n\t'%s' type_id=%u", name, p->type);
 260                         }
 261                 }
 262                 if (json_output)
 263                         jsonw_end_array(w);
 264                 break;
 265         }
 266         case BTF_KIND_VAR: {
 267                 const struct btf_var *v = (const void *)(t + 1);
 268                 const char *linkage;
 269 
 270                 linkage = btf_var_linkage_str(v->linkage);
 271 
 272                 if (json_output) {
 273                         jsonw_uint_field(w, "type_id", t->type);
 274                         jsonw_string_field(w, "linkage", linkage);
 275                 } else {
 276                         printf(" type_id=%u, linkage=%s", t->type, linkage);
 277                 }
 278                 break;
 279         }
 280         case BTF_KIND_DATASEC: {
 281                 const struct btf_var_secinfo *v = (const void *)(t+1);
 282                 __u16 vlen = BTF_INFO_VLEN(t->info);
 283                 int i;
 284 
 285                 if (json_output) {
 286                         jsonw_uint_field(w, "size", t->size);
 287                         jsonw_uint_field(w, "vlen", vlen);
 288                         jsonw_name(w, "vars");
 289                         jsonw_start_array(w);
 290                 } else {
 291                         printf(" size=%u vlen=%u", t->size, vlen);
 292                 }
 293                 for (i = 0; i < vlen; i++, v++) {
 294                         if (json_output) {
 295                                 jsonw_start_object(w);
 296                                 jsonw_uint_field(w, "type_id", v->type);
 297                                 jsonw_uint_field(w, "offset", v->offset);
 298                                 jsonw_uint_field(w, "size", v->size);
 299                                 jsonw_end_object(w);
 300                         } else {
 301                                 printf("\n\ttype_id=%u offset=%u size=%u",
 302                                        v->type, v->offset, v->size);
 303                         }
 304                 }
 305                 if (json_output)
 306                         jsonw_end_array(w);
 307                 break;
 308         }
 309         default:
 310                 break;
 311         }
 312 
 313         if (json_output)
 314                 jsonw_end_object(json_wtr);
 315         else
 316                 printf("\n");
 317 
 318         return 0;
 319 }
 320 
 321 static int dump_btf_raw(const struct btf *btf,
 322                         __u32 *root_type_ids, int root_type_cnt)
 323 {
 324         const struct btf_type *t;
 325         int i;
 326 
 327         if (json_output) {
 328                 jsonw_start_object(json_wtr);
 329                 jsonw_name(json_wtr, "types");
 330                 jsonw_start_array(json_wtr);
 331         }
 332 
 333         if (root_type_cnt) {
 334                 for (i = 0; i < root_type_cnt; i++) {
 335                         t = btf__type_by_id(btf, root_type_ids[i]);
 336                         dump_btf_type(btf, root_type_ids[i], t);
 337                 }
 338         } else {
 339                 int cnt = btf__get_nr_types(btf);
 340 
 341                 for (i = 1; i <= cnt; i++) {
 342                         t = btf__type_by_id(btf, i);
 343                         dump_btf_type(btf, i, t);
 344                 }
 345         }
 346 
 347         if (json_output) {
 348                 jsonw_end_array(json_wtr);
 349                 jsonw_end_object(json_wtr);
 350         }
 351         return 0;
 352 }
 353 
 354 static void __printf(2, 0) btf_dump_printf(void *ctx,
 355                                            const char *fmt, va_list args)
 356 {
 357         vfprintf(stdout, fmt, args);
 358 }
 359 
 360 static int dump_btf_c(const struct btf *btf,
 361                       __u32 *root_type_ids, int root_type_cnt)
 362 {
 363         struct btf_dump *d;
 364         int err = 0, i;
 365 
 366         d = btf_dump__new(btf, NULL, NULL, btf_dump_printf);
 367         if (IS_ERR(d))
 368                 return PTR_ERR(d);
 369 
 370         if (root_type_cnt) {
 371                 for (i = 0; i < root_type_cnt; i++) {
 372                         err = btf_dump__dump_type(d, root_type_ids[i]);
 373                         if (err)
 374                                 goto done;
 375                 }
 376         } else {
 377                 int cnt = btf__get_nr_types(btf);
 378 
 379                 for (i = 1; i <= cnt; i++) {
 380                         err = btf_dump__dump_type(d, i);
 381                         if (err)
 382                                 goto done;
 383                 }
 384         }
 385 
 386 done:
 387         btf_dump__free(d);
 388         return err;
 389 }
 390 
 391 static int do_dump(int argc, char **argv)
 392 {
 393         struct btf *btf = NULL;
 394         __u32 root_type_ids[2];
 395         int root_type_cnt = 0;
 396         bool dump_c = false;
 397         __u32 btf_id = -1;
 398         const char *src;
 399         int fd = -1;
 400         int err;
 401 
 402         if (!REQ_ARGS(2)) {
 403                 usage();
 404                 return -1;
 405         }
 406         src = GET_ARG();
 407 
 408         if (is_prefix(src, "map")) {
 409                 struct bpf_map_info info = {};
 410                 __u32 len = sizeof(info);
 411 
 412                 if (!REQ_ARGS(2)) {
 413                         usage();
 414                         return -1;
 415                 }
 416 
 417                 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
 418                 if (fd < 0)
 419                         return -1;
 420 
 421                 btf_id = info.btf_id;
 422                 if (argc && is_prefix(*argv, "key")) {
 423                         root_type_ids[root_type_cnt++] = info.btf_key_type_id;
 424                         NEXT_ARG();
 425                 } else if (argc && is_prefix(*argv, "value")) {
 426                         root_type_ids[root_type_cnt++] = info.btf_value_type_id;
 427                         NEXT_ARG();
 428                 } else if (argc && is_prefix(*argv, "all")) {
 429                         NEXT_ARG();
 430                 } else if (argc && is_prefix(*argv, "kv")) {
 431                         root_type_ids[root_type_cnt++] = info.btf_key_type_id;
 432                         root_type_ids[root_type_cnt++] = info.btf_value_type_id;
 433                         NEXT_ARG();
 434                 } else {
 435                         root_type_ids[root_type_cnt++] = info.btf_key_type_id;
 436                         root_type_ids[root_type_cnt++] = info.btf_value_type_id;
 437                 }
 438         } else if (is_prefix(src, "prog")) {
 439                 struct bpf_prog_info info = {};
 440                 __u32 len = sizeof(info);
 441 
 442                 if (!REQ_ARGS(2)) {
 443                         usage();
 444                         return -1;
 445                 }
 446 
 447                 fd = prog_parse_fd(&argc, &argv);
 448                 if (fd < 0)
 449                         return -1;
 450 
 451                 err = bpf_obj_get_info_by_fd(fd, &info, &len);
 452                 if (err) {
 453                         p_err("can't get prog info: %s", strerror(errno));
 454                         goto done;
 455                 }
 456 
 457                 btf_id = info.btf_id;
 458         } else if (is_prefix(src, "id")) {
 459                 char *endptr;
 460 
 461                 btf_id = strtoul(*argv, &endptr, 0);
 462                 if (*endptr) {
 463                         p_err("can't parse %s as ID", *argv);
 464                         return -1;
 465                 }
 466                 NEXT_ARG();
 467         } else if (is_prefix(src, "file")) {
 468                 btf = btf__parse_elf(*argv, NULL);
 469                 if (IS_ERR(btf)) {
 470                         err = PTR_ERR(btf);
 471                         btf = NULL;
 472                         p_err("failed to load BTF from %s: %s", 
 473                               *argv, strerror(err));
 474                         goto done;
 475                 }
 476                 NEXT_ARG();
 477         } else {
 478                 err = -1;
 479                 p_err("unrecognized BTF source specifier: '%s'", src);
 480                 goto done;
 481         }
 482 
 483         while (argc) {
 484                 if (is_prefix(*argv, "format")) {
 485                         NEXT_ARG();
 486                         if (argc < 1) {
 487                                 p_err("expecting value for 'format' option\n");
 488                                 goto done;
 489                         }
 490                         if (strcmp(*argv, "c") == 0) {
 491                                 dump_c = true;
 492                         } else if (strcmp(*argv, "raw") == 0) {
 493                                 dump_c = false;
 494                         } else {
 495                                 p_err("unrecognized format specifier: '%s', possible values: raw, c",
 496                                       *argv);
 497                                 goto done;
 498                         }
 499                         NEXT_ARG();
 500                 } else {
 501                         p_err("unrecognized option: '%s'", *argv);
 502                         goto done;
 503                 }
 504         }
 505 
 506         if (!btf) {
 507                 err = btf__get_from_id(btf_id, &btf);
 508                 if (err) {
 509                         p_err("get btf by id (%u): %s", btf_id, strerror(err));
 510                         goto done;
 511                 }
 512                 if (!btf) {
 513                         err = ENOENT;
 514                         p_err("can't find btf with ID (%u)", btf_id);
 515                         goto done;
 516                 }
 517         }
 518 
 519         if (dump_c) {
 520                 if (json_output) {
 521                         p_err("JSON output for C-syntax dump is not supported");
 522                         err = -ENOTSUP;
 523                         goto done;
 524                 }
 525                 err = dump_btf_c(btf, root_type_ids, root_type_cnt);
 526         } else {
 527                 err = dump_btf_raw(btf, root_type_ids, root_type_cnt);
 528         }
 529 
 530 done:
 531         close(fd);
 532         btf__free(btf);
 533         return err;
 534 }
 535 
 536 static int btf_parse_fd(int *argc, char ***argv)
 537 {
 538         unsigned int id;
 539         char *endptr;
 540         int fd;
 541 
 542         if (!is_prefix(*argv[0], "id")) {
 543                 p_err("expected 'id', got: '%s'?", **argv);
 544                 return -1;
 545         }
 546         NEXT_ARGP();
 547 
 548         id = strtoul(**argv, &endptr, 0);
 549         if (*endptr) {
 550                 p_err("can't parse %s as ID", **argv);
 551                 return -1;
 552         }
 553         NEXT_ARGP();
 554 
 555         fd = bpf_btf_get_fd_by_id(id);
 556         if (fd < 0)
 557                 p_err("can't get BTF object by id (%u): %s",
 558                       id, strerror(errno));
 559 
 560         return fd;
 561 }
 562 
 563 static void delete_btf_table(struct btf_attach_table *tab)
 564 {
 565         struct btf_attach_point *obj;
 566         struct hlist_node *tmp;
 567 
 568         unsigned int bkt;
 569 
 570         hash_for_each_safe(tab->table, bkt, tmp, obj, hash) {
 571                 hash_del(&obj->hash);
 572                 free(obj);
 573         }
 574 }
 575 
 576 static int
 577 build_btf_type_table(struct btf_attach_table *tab, enum bpf_obj_type type,
 578                      void *info, __u32 *len)
 579 {
 580         static const char * const names[] = {
 581                 [BPF_OBJ_UNKNOWN]       = "unknown",
 582                 [BPF_OBJ_PROG]          = "prog",
 583                 [BPF_OBJ_MAP]           = "map",
 584         };
 585         struct btf_attach_point *obj_node;
 586         __u32 btf_id, id = 0;
 587         int err;
 588         int fd;
 589 
 590         while (true) {
 591                 switch (type) {
 592                 case BPF_OBJ_PROG:
 593                         err = bpf_prog_get_next_id(id, &id);
 594                         break;
 595                 case BPF_OBJ_MAP:
 596                         err = bpf_map_get_next_id(id, &id);
 597                         break;
 598                 default:
 599                         err = -1;
 600                         p_err("unexpected object type: %d", type);
 601                         goto err_free;
 602                 }
 603                 if (err) {
 604                         if (errno == ENOENT) {
 605                                 err = 0;
 606                                 break;
 607                         }
 608                         p_err("can't get next %s: %s%s", names[type],
 609                               strerror(errno),
 610                               errno == EINVAL ? " -- kernel too old?" : "");
 611                         goto err_free;
 612                 }
 613 
 614                 switch (type) {
 615                 case BPF_OBJ_PROG:
 616                         fd = bpf_prog_get_fd_by_id(id);
 617                         break;
 618                 case BPF_OBJ_MAP:
 619                         fd = bpf_map_get_fd_by_id(id);
 620                         break;
 621                 default:
 622                         err = -1;
 623                         p_err("unexpected object type: %d", type);
 624                         goto err_free;
 625                 }
 626                 if (fd < 0) {
 627                         if (errno == ENOENT)
 628                                 continue;
 629                         p_err("can't get %s by id (%u): %s", names[type], id,
 630                               strerror(errno));
 631                         err = -1;
 632                         goto err_free;
 633                 }
 634 
 635                 memset(info, 0, *len);
 636                 err = bpf_obj_get_info_by_fd(fd, info, len);
 637                 close(fd);
 638                 if (err) {
 639                         p_err("can't get %s info: %s", names[type],
 640                               strerror(errno));
 641                         goto err_free;
 642                 }
 643 
 644                 switch (type) {
 645                 case BPF_OBJ_PROG:
 646                         btf_id = ((struct bpf_prog_info *)info)->btf_id;
 647                         break;
 648                 case BPF_OBJ_MAP:
 649                         btf_id = ((struct bpf_map_info *)info)->btf_id;
 650                         break;
 651                 default:
 652                         err = -1;
 653                         p_err("unexpected object type: %d", type);
 654                         goto err_free;
 655                 }
 656                 if (!btf_id)
 657                         continue;
 658 
 659                 obj_node = calloc(1, sizeof(*obj_node));
 660                 if (!obj_node) {
 661                         p_err("failed to allocate memory: %s", strerror(errno));
 662                         goto err_free;
 663                 }
 664 
 665                 obj_node->obj_id = id;
 666                 obj_node->btf_id = btf_id;
 667                 hash_add(tab->table, &obj_node->hash, obj_node->btf_id);
 668         }
 669 
 670         return 0;
 671 
 672 err_free:
 673         delete_btf_table(tab);
 674         return err;
 675 }
 676 
 677 static int
 678 build_btf_tables(struct btf_attach_table *btf_prog_table,
 679                  struct btf_attach_table *btf_map_table)
 680 {
 681         struct bpf_prog_info prog_info;
 682         __u32 prog_len = sizeof(prog_info);
 683         struct bpf_map_info map_info;
 684         __u32 map_len = sizeof(map_info);
 685         int err = 0;
 686 
 687         err = build_btf_type_table(btf_prog_table, BPF_OBJ_PROG, &prog_info,
 688                                    &prog_len);
 689         if (err)
 690                 return err;
 691 
 692         err = build_btf_type_table(btf_map_table, BPF_OBJ_MAP, &map_info,
 693                                    &map_len);
 694         if (err) {
 695                 delete_btf_table(btf_prog_table);
 696                 return err;
 697         }
 698 
 699         return 0;
 700 }
 701 
 702 static void
 703 show_btf_plain(struct bpf_btf_info *info, int fd,
 704                struct btf_attach_table *btf_prog_table,
 705                struct btf_attach_table *btf_map_table)
 706 {
 707         struct btf_attach_point *obj;
 708         int n;
 709 
 710         printf("%u: ", info->id);
 711         printf("size %uB", info->btf_size);
 712 
 713         n = 0;
 714         hash_for_each_possible(btf_prog_table->table, obj, hash, info->id) {
 715                 if (obj->btf_id == info->id)
 716                         printf("%s%u", n++ == 0 ? "  prog_ids " : ",",
 717                                obj->obj_id);
 718         }
 719 
 720         n = 0;
 721         hash_for_each_possible(btf_map_table->table, obj, hash, info->id) {
 722                 if (obj->btf_id == info->id)
 723                         printf("%s%u", n++ == 0 ? "  map_ids " : ",",
 724                                obj->obj_id);
 725         }
 726 
 727         printf("\n");
 728 }
 729 
 730 static void
 731 show_btf_json(struct bpf_btf_info *info, int fd,
 732               struct btf_attach_table *btf_prog_table,
 733               struct btf_attach_table *btf_map_table)
 734 {
 735         struct btf_attach_point *obj;
 736 
 737         jsonw_start_object(json_wtr);   /* btf object */
 738         jsonw_uint_field(json_wtr, "id", info->id);
 739         jsonw_uint_field(json_wtr, "size", info->btf_size);
 740 
 741         jsonw_name(json_wtr, "prog_ids");
 742         jsonw_start_array(json_wtr);    /* prog_ids */
 743         hash_for_each_possible(btf_prog_table->table, obj, hash,
 744                                info->id) {
 745                 if (obj->btf_id == info->id)
 746                         jsonw_uint(json_wtr, obj->obj_id);
 747         }
 748         jsonw_end_array(json_wtr);      /* prog_ids */
 749 
 750         jsonw_name(json_wtr, "map_ids");
 751         jsonw_start_array(json_wtr);    /* map_ids */
 752         hash_for_each_possible(btf_map_table->table, obj, hash,
 753                                info->id) {
 754                 if (obj->btf_id == info->id)
 755                         jsonw_uint(json_wtr, obj->obj_id);
 756         }
 757         jsonw_end_array(json_wtr);      /* map_ids */
 758         jsonw_end_object(json_wtr);     /* btf object */
 759 }
 760 
 761 static int
 762 show_btf(int fd, struct btf_attach_table *btf_prog_table,
 763          struct btf_attach_table *btf_map_table)
 764 {
 765         struct bpf_btf_info info = {};
 766         __u32 len = sizeof(info);
 767         int err;
 768 
 769         err = bpf_obj_get_info_by_fd(fd, &info, &len);
 770         if (err) {
 771                 p_err("can't get BTF object info: %s", strerror(errno));
 772                 return -1;
 773         }
 774 
 775         if (json_output)
 776                 show_btf_json(&info, fd, btf_prog_table, btf_map_table);
 777         else
 778                 show_btf_plain(&info, fd, btf_prog_table, btf_map_table);
 779 
 780         return 0;
 781 }
 782 
 783 static int do_show(int argc, char **argv)
 784 {
 785         struct btf_attach_table btf_prog_table;
 786         struct btf_attach_table btf_map_table;
 787         int err, fd = -1;
 788         __u32 id = 0;
 789 
 790         if (argc == 2) {
 791                 fd = btf_parse_fd(&argc, &argv);
 792                 if (fd < 0)
 793                         return -1;
 794         }
 795 
 796         if (argc) {
 797                 if (fd >= 0)
 798                         close(fd);
 799                 return BAD_ARG();
 800         }
 801 
 802         hash_init(btf_prog_table.table);
 803         hash_init(btf_map_table.table);
 804         err = build_btf_tables(&btf_prog_table, &btf_map_table);
 805         if (err) {
 806                 if (fd >= 0)
 807                         close(fd);
 808                 return err;
 809         }
 810 
 811         if (fd >= 0) {
 812                 err = show_btf(fd, &btf_prog_table, &btf_map_table);
 813                 close(fd);
 814                 goto exit_free;
 815         }
 816 
 817         if (json_output)
 818                 jsonw_start_array(json_wtr);    /* root array */
 819 
 820         while (true) {
 821                 err = bpf_btf_get_next_id(id, &id);
 822                 if (err) {
 823                         if (errno == ENOENT) {
 824                                 err = 0;
 825                                 break;
 826                         }
 827                         p_err("can't get next BTF object: %s%s",
 828                               strerror(errno),
 829                               errno == EINVAL ? " -- kernel too old?" : "");
 830                         err = -1;
 831                         break;
 832                 }
 833 
 834                 fd = bpf_btf_get_fd_by_id(id);
 835                 if (fd < 0) {
 836                         if (errno == ENOENT)
 837                                 continue;
 838                         p_err("can't get BTF object by id (%u): %s",
 839                               id, strerror(errno));
 840                         err = -1;
 841                         break;
 842                 }
 843 
 844                 err = show_btf(fd, &btf_prog_table, &btf_map_table);
 845                 close(fd);
 846                 if (err)
 847                         break;
 848         }
 849 
 850         if (json_output)
 851                 jsonw_end_array(json_wtr);      /* root array */
 852 
 853 exit_free:
 854         delete_btf_table(&btf_prog_table);
 855         delete_btf_table(&btf_map_table);
 856 
 857         return err;
 858 }
 859 
 860 static int do_help(int argc, char **argv)
 861 {
 862         if (json_output) {
 863                 jsonw_null(json_wtr);
 864                 return 0;
 865         }
 866 
 867         fprintf(stderr,
 868                 "Usage: %s btf { show | list } [id BTF_ID]\n"
 869                 "       %s btf dump BTF_SRC [format FORMAT]\n"
 870                 "       %s btf help\n"
 871                 "\n"
 872                 "       BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"
 873                 "       FORMAT  := { raw | c }\n"
 874                 "       " HELP_SPEC_MAP "\n"
 875                 "       " HELP_SPEC_PROGRAM "\n"
 876                 "       " HELP_SPEC_OPTIONS "\n"
 877                 "",
 878                 bin_name, bin_name, bin_name);
 879 
 880         return 0;
 881 }
 882 
 883 static const struct cmd cmds[] = {
 884         { "show",       do_show },
 885         { "list",       do_show },
 886         { "help",       do_help },
 887         { "dump",       do_dump },
 888         { 0 }
 889 };
 890 
 891 int do_btf(int argc, char **argv)
 892 {
 893         return cmd_select(cmds, argc, argv, do_help);
 894 }

/* [<][>][^][v][top][bottom][index][help] */