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 } 587