1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 /* Copyright (c) 2018 Facebook */ 3 4 #include <ctype.h> 5 #include <stdio.h> /* for (FILE *) used by json_writer */ 6 #include <string.h> 7 #include <asm/byteorder.h> 8 #include <linux/bitops.h> 9 #include <linux/btf.h> 10 #include <linux/err.h> 11 12 #include "btf.h" 13 #include "json_writer.h" 14 #include "main.h" 15 16 #define BITS_PER_BYTE_MASK (BITS_PER_BYTE - 1) 17 #define BITS_PER_BYTE_MASKED(bits) ((bits) & BITS_PER_BYTE_MASK) 18 #define BITS_ROUNDDOWN_BYTES(bits) ((bits) >> 3) 19 #define BITS_ROUNDUP_BYTES(bits) \ 20 (BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits)) 21 22 static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id, 23 __u8 bit_offset, const void *data); 24 25 static void btf_dumper_ptr(const void *data, json_writer_t *jw, 26 bool is_plain_text) 27 { 28 if (is_plain_text) 29 jsonw_printf(jw, "%p", data); 30 else 31 jsonw_printf(jw, "%lu", *(unsigned long *)data); 32 } 33 34 static int btf_dumper_modifier(const struct btf_dumper *d, __u32 type_id, 35 __u8 bit_offset, const void *data) 36 { 37 int actual_type_id; 38 39 actual_type_id = btf__resolve_type(d->btf, type_id); 40 if (actual_type_id < 0) 41 return actual_type_id; 42 43 return btf_dumper_do_type(d, actual_type_id, bit_offset, data); 44 } 45 46 static void btf_dumper_enum(const void *data, json_writer_t *jw) 47 { 48 jsonw_printf(jw, "%d", *(int *)data); 49 } 50 51 static int btf_dumper_array(const struct btf_dumper *d, __u32 type_id, 52 const void *data) 53 { 54 const struct btf_type *t = btf__type_by_id(d->btf, type_id); 55 struct btf_array *arr = (struct btf_array *)(t + 1); 56 long long elem_size; 57 int ret = 0; 58 __u32 i; 59 60 elem_size = btf__resolve_size(d->btf, arr->type); 61 if (elem_size < 0) 62 return elem_size; 63 64 jsonw_start_array(d->jw); 65 for (i = 0; i < arr->nelems; i++) { 66 ret = btf_dumper_do_type(d, arr->type, 0, 67 data + i * elem_size); 68 if (ret) 69 break; 70 } 71 72 jsonw_end_array(d->jw); 73 return ret; 74 } 75 76 static void btf_int128_print(json_writer_t *jw, const void *data, 77 bool is_plain_text) 78 { 79 /* data points to a __int128 number. 80 * Suppose 81 * int128_num = *(__int128 *)data; 82 * The below formulas shows what upper_num and lower_num represents: 83 * upper_num = int128_num >> 64; 84 * lower_num = int128_num & 0xffffffffFFFFFFFFULL; 85 */ 86 __u64 upper_num, lower_num; 87 88 #ifdef __BIG_ENDIAN_BITFIELD 89 upper_num = *(__u64 *)data; 90 lower_num = *(__u64 *)(data + 8); 91 #else 92 upper_num = *(__u64 *)(data + 8); 93 lower_num = *(__u64 *)data; 94 #endif 95 96 if (is_plain_text) { 97 if (upper_num == 0) 98 jsonw_printf(jw, "0x%llx", lower_num); 99 else 100 jsonw_printf(jw, "0x%llx%016llx", upper_num, lower_num); 101 } else { 102 if (upper_num == 0) 103 jsonw_printf(jw, "\"0x%llx\"", lower_num); 104 else 105 jsonw_printf(jw, "\"0x%llx%016llx\"", upper_num, lower_num); 106 } 107 } 108 109 static void btf_int128_shift(__u64 *print_num, u16 left_shift_bits, 110 u16 right_shift_bits) 111 { 112 __u64 upper_num, lower_num; 113 114 #ifdef __BIG_ENDIAN_BITFIELD 115 upper_num = print_num[0]; 116 lower_num = print_num[1]; 117 #else 118 upper_num = print_num[1]; 119 lower_num = print_num[0]; 120 #endif 121 122 /* shake out un-needed bits by shift/or operations */ 123 if (left_shift_bits >= 64) { 124 upper_num = lower_num << (left_shift_bits - 64); 125 lower_num = 0; 126 } else { 127 upper_num = (upper_num << left_shift_bits) | 128 (lower_num >> (64 - left_shift_bits)); 129 lower_num = lower_num << left_shift_bits; 130 } 131 132 if (right_shift_bits >= 64) { 133 lower_num = upper_num >> (right_shift_bits - 64); 134 upper_num = 0; 135 } else { 136 lower_num = (lower_num >> right_shift_bits) | 137 (upper_num << (64 - right_shift_bits)); 138 upper_num = upper_num >> right_shift_bits; 139 } 140 141 #ifdef __BIG_ENDIAN_BITFIELD 142 print_num[0] = upper_num; 143 print_num[1] = lower_num; 144 #else 145 print_num[0] = lower_num; 146 print_num[1] = upper_num; 147 #endif 148 } 149 150 static void btf_dumper_bitfield(__u32 nr_bits, __u8 bit_offset, 151 const void *data, json_writer_t *jw, 152 bool is_plain_text) 153 { 154 int left_shift_bits, right_shift_bits; 155 __u64 print_num[2] = {}; 156 int bytes_to_copy; 157 int bits_to_copy; 158 159 bits_to_copy = bit_offset + nr_bits; 160 bytes_to_copy = BITS_ROUNDUP_BYTES(bits_to_copy); 161 162 memcpy(print_num, data, bytes_to_copy); 163 #if defined(__BIG_ENDIAN_BITFIELD) 164 left_shift_bits = bit_offset; 165 #elif defined(__LITTLE_ENDIAN_BITFIELD) 166 left_shift_bits = 128 - bits_to_copy; 167 #else 168 #error neither big nor little endian 169 #endif 170 right_shift_bits = 128 - nr_bits; 171 172 btf_int128_shift(print_num, left_shift_bits, right_shift_bits); 173 btf_int128_print(jw, print_num, is_plain_text); 174 } 175 176 177 static void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset, 178 const void *data, json_writer_t *jw, 179 bool is_plain_text) 180 { 181 int nr_bits = BTF_INT_BITS(int_type); 182 int total_bits_offset; 183 184 /* bits_offset is at most 7. 185 * BTF_INT_OFFSET() cannot exceed 128 bits. 186 */ 187 total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type); 188 data += BITS_ROUNDDOWN_BYTES(total_bits_offset); 189 bit_offset = BITS_PER_BYTE_MASKED(total_bits_offset); 190 btf_dumper_bitfield(nr_bits, bit_offset, data, jw, 191 is_plain_text); 192 } 193 194 static int btf_dumper_int(const struct btf_type *t, __u8 bit_offset, 195 const void *data, json_writer_t *jw, 196 bool is_plain_text) 197 { 198 __u32 *int_type; 199 __u32 nr_bits; 200 201 int_type = (__u32 *)(t + 1); 202 nr_bits = BTF_INT_BITS(*int_type); 203 /* if this is bit field */ 204 if (bit_offset || BTF_INT_OFFSET(*int_type) || 205 BITS_PER_BYTE_MASKED(nr_bits)) { 206 btf_dumper_int_bits(*int_type, bit_offset, data, jw, 207 is_plain_text); 208 return 0; 209 } 210 211 if (nr_bits == 128) { 212 btf_int128_print(jw, data, is_plain_text); 213 return 0; 214 } 215 216 switch (BTF_INT_ENCODING(*int_type)) { 217 case 0: 218 if (BTF_INT_BITS(*int_type) == 64) 219 jsonw_printf(jw, "%llu", *(__u64 *)data); 220 else if (BTF_INT_BITS(*int_type) == 32) 221 jsonw_printf(jw, "%u", *(__u32 *)data); 222 else if (BTF_INT_BITS(*int_type) == 16) 223 jsonw_printf(jw, "%hu", *(__u16 *)data); 224 else if (BTF_INT_BITS(*int_type) == 8) 225 jsonw_printf(jw, "%hhu", *(__u8 *)data); 226 else 227 btf_dumper_int_bits(*int_type, bit_offset, data, jw, 228 is_plain_text); 229 break; 230 case BTF_INT_SIGNED: 231 if (BTF_INT_BITS(*int_type) == 64) 232 jsonw_printf(jw, "%lld", *(long long *)data); 233 else if (BTF_INT_BITS(*int_type) == 32) 234 jsonw_printf(jw, "%d", *(int *)data); 235 else if (BTF_INT_BITS(*int_type) == 16) 236 jsonw_printf(jw, "%hd", *(short *)data); 237 else if (BTF_INT_BITS(*int_type) == 8) 238 jsonw_printf(jw, "%hhd", *(char *)data); 239 else 240 btf_dumper_int_bits(*int_type, bit_offset, data, jw, 241 is_plain_text); 242 break; 243 case BTF_INT_CHAR: 244 if (isprint(*(char *)data)) 245 jsonw_printf(jw, "\"%c\"", *(char *)data); 246 else 247 if (is_plain_text) 248 jsonw_printf(jw, "0x%hhx", *(char *)data); 249 else 250 jsonw_printf(jw, "\"\\u00%02hhx\"", 251 *(char *)data); 252 break; 253 case BTF_INT_BOOL: 254 jsonw_bool(jw, *(int *)data); 255 break; 256 default: 257 /* shouldn't happen */ 258 return -EINVAL; 259 } 260 261 return 0; 262 } 263 264 static int btf_dumper_struct(const struct btf_dumper *d, __u32 type_id, 265 const void *data) 266 { 267 const struct btf_type *t; 268 struct btf_member *m; 269 const void *data_off; 270 int kind_flag; 271 int ret = 0; 272 int i, vlen; 273 274 t = btf__type_by_id(d->btf, type_id); 275 if (!t) 276 return -EINVAL; 277 278 kind_flag = BTF_INFO_KFLAG(t->info); 279 vlen = BTF_INFO_VLEN(t->info); 280 jsonw_start_object(d->jw); 281 m = (struct btf_member *)(t + 1); 282 283 for (i = 0; i < vlen; i++) { 284 __u32 bit_offset = m[i].offset; 285 __u32 bitfield_size = 0; 286 287 if (kind_flag) { 288 bitfield_size = BTF_MEMBER_BITFIELD_SIZE(bit_offset); 289 bit_offset = BTF_MEMBER_BIT_OFFSET(bit_offset); 290 } 291 292 jsonw_name(d->jw, btf__name_by_offset(d->btf, m[i].name_off)); 293 data_off = data + BITS_ROUNDDOWN_BYTES(bit_offset); 294 if (bitfield_size) { 295 btf_dumper_bitfield(bitfield_size, 296 BITS_PER_BYTE_MASKED(bit_offset), 297 data_off, d->jw, d->is_plain_text); 298 } else { 299 ret = btf_dumper_do_type(d, m[i].type, 300 BITS_PER_BYTE_MASKED(bit_offset), 301 data_off); 302 if (ret) 303 break; 304 } 305 } 306 307 jsonw_end_object(d->jw); 308 309 return ret; 310 } 311 312 static int btf_dumper_var(const struct btf_dumper *d, __u32 type_id, 313 __u8 bit_offset, const void *data) 314 { 315 const struct btf_type *t = btf__type_by_id(d->btf, type_id); 316 int ret; 317 318 jsonw_start_object(d->jw); 319 jsonw_name(d->jw, btf__name_by_offset(d->btf, t->name_off)); 320 ret = btf_dumper_do_type(d, t->type, bit_offset, data); 321 jsonw_end_object(d->jw); 322 323 return ret; 324 } 325 326 static int btf_dumper_datasec(const struct btf_dumper *d, __u32 type_id, 327 const void *data) 328 { 329 struct btf_var_secinfo *vsi; 330 const struct btf_type *t; 331 int ret = 0, i, vlen; 332 333 t = btf__type_by_id(d->btf, type_id); 334 if (!t) 335 return -EINVAL; 336 337 vlen = BTF_INFO_VLEN(t->info); 338 vsi = (struct btf_var_secinfo *)(t + 1); 339 340 jsonw_start_object(d->jw); 341 jsonw_name(d->jw, btf__name_by_offset(d->btf, t->name_off)); 342 jsonw_start_array(d->jw); 343 for (i = 0; i < vlen; i++) { 344 ret = btf_dumper_do_type(d, vsi[i].type, 0, data + vsi[i].offset); 345 if (ret) 346 break; 347 } 348 jsonw_end_array(d->jw); 349 jsonw_end_object(d->jw); 350 351 return ret; 352 } 353 354 static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id, 355 __u8 bit_offset, const void *data) 356 { 357 const struct btf_type *t = btf__type_by_id(d->btf, type_id); 358 359 switch (BTF_INFO_KIND(t->info)) { 360 case BTF_KIND_INT: 361 return btf_dumper_int(t, bit_offset, data, d->jw, 362 d->is_plain_text); 363 case BTF_KIND_STRUCT: 364 case BTF_KIND_UNION: 365 return btf_dumper_struct(d, type_id, data); 366 case BTF_KIND_ARRAY: 367 return btf_dumper_array(d, type_id, data); 368 case BTF_KIND_ENUM: 369 btf_dumper_enum(data, d->jw); 370 return 0; 371 case BTF_KIND_PTR: 372 btf_dumper_ptr(data, d->jw, d->is_plain_text); 373 return 0; 374 case BTF_KIND_UNKN: 375 jsonw_printf(d->jw, "(unknown)"); 376 return 0; 377 case BTF_KIND_FWD: 378 /* map key or value can't be forward */ 379 jsonw_printf(d->jw, "(fwd-kind-invalid)"); 380 return -EINVAL; 381 case BTF_KIND_TYPEDEF: 382 case BTF_KIND_VOLATILE: 383 case BTF_KIND_CONST: 384 case BTF_KIND_RESTRICT: 385 return btf_dumper_modifier(d, type_id, bit_offset, data); 386 case BTF_KIND_VAR: 387 return btf_dumper_var(d, type_id, bit_offset, data); 388 case BTF_KIND_DATASEC: 389 return btf_dumper_datasec(d, type_id, data); 390 default: 391 jsonw_printf(d->jw, "(unsupported-kind"); 392 return -EINVAL; 393 } 394 } 395 396 int btf_dumper_type(const struct btf_dumper *d, __u32 type_id, 397 const void *data) 398 { 399 return btf_dumper_do_type(d, type_id, 0, data); 400 } 401 402 #define BTF_PRINT_ARG(...) \ 403 do { \ 404 pos += snprintf(func_sig + pos, size - pos, \ 405 __VA_ARGS__); \ 406 if (pos >= size) \ 407 return -1; \ 408 } while (0) 409 #define BTF_PRINT_TYPE(type) \ 410 do { \ 411 pos = __btf_dumper_type_only(btf, type, func_sig, \ 412 pos, size); \ 413 if (pos == -1) \ 414 return -1; \ 415 } while (0) 416 417 static int btf_dump_func(const struct btf *btf, char *func_sig, 418 const struct btf_type *func_proto, 419 const struct btf_type *func, int pos, int size); 420 421 static int __btf_dumper_type_only(const struct btf *btf, __u32 type_id, 422 char *func_sig, int pos, int size) 423 { 424 const struct btf_type *proto_type; 425 const struct btf_array *array; 426 const struct btf_var *var; 427 const struct btf_type *t; 428 429 if (!type_id) { 430 BTF_PRINT_ARG("void "); 431 return pos; 432 } 433 434 t = btf__type_by_id(btf, type_id); 435 436 switch (BTF_INFO_KIND(t->info)) { 437 case BTF_KIND_INT: 438 case BTF_KIND_TYPEDEF: 439 BTF_PRINT_ARG("%s ", btf__name_by_offset(btf, t->name_off)); 440 break; 441 case BTF_KIND_STRUCT: 442 BTF_PRINT_ARG("struct %s ", 443 btf__name_by_offset(btf, t->name_off)); 444 break; 445 case BTF_KIND_UNION: 446 BTF_PRINT_ARG("union %s ", 447 btf__name_by_offset(btf, t->name_off)); 448 break; 449 case BTF_KIND_ENUM: 450 BTF_PRINT_ARG("enum %s ", 451 btf__name_by_offset(btf, t->name_off)); 452 break; 453 case BTF_KIND_ARRAY: 454 array = (struct btf_array *)(t + 1); 455 BTF_PRINT_TYPE(array->type); 456 BTF_PRINT_ARG("[%d]", array->nelems); 457 break; 458 case BTF_KIND_PTR: 459 BTF_PRINT_TYPE(t->type); 460 BTF_PRINT_ARG("* "); 461 break; 462 case BTF_KIND_FWD: 463 BTF_PRINT_ARG("%s %s ", 464 BTF_INFO_KFLAG(t->info) ? "union" : "struct", 465 btf__name_by_offset(btf, t->name_off)); 466 break; 467 case BTF_KIND_VOLATILE: 468 BTF_PRINT_ARG("volatile "); 469 BTF_PRINT_TYPE(t->type); 470 break; 471 case BTF_KIND_CONST: 472 BTF_PRINT_ARG("const "); 473 BTF_PRINT_TYPE(t->type); 474 break; 475 case BTF_KIND_RESTRICT: 476 BTF_PRINT_ARG("restrict "); 477 BTF_PRINT_TYPE(t->type); 478 break; 479 case BTF_KIND_FUNC_PROTO: 480 pos = btf_dump_func(btf, func_sig, t, NULL, pos, size); 481 if (pos == -1) 482 return -1; 483 break; 484 case BTF_KIND_FUNC: 485 proto_type = btf__type_by_id(btf, t->type); 486 pos = btf_dump_func(btf, func_sig, proto_type, t, pos, size); 487 if (pos == -1) 488 return -1; 489 break; 490 case BTF_KIND_VAR: 491 var = (struct btf_var *)(t + 1); 492 if (var->linkage == BTF_VAR_STATIC) 493 BTF_PRINT_ARG("static "); 494 BTF_PRINT_TYPE(t->type); 495 BTF_PRINT_ARG(" %s", 496 btf__name_by_offset(btf, t->name_off)); 497 break; 498 case BTF_KIND_DATASEC: 499 BTF_PRINT_ARG("section (\"%s\") ", 500 btf__name_by_offset(btf, t->name_off)); 501 break; 502 case BTF_KIND_UNKN: 503 default: 504 return -1; 505 } 506 507 return pos; 508 } 509 510 static int btf_dump_func(const struct btf *btf, char *func_sig, 511 const struct btf_type *func_proto, 512 const struct btf_type *func, int pos, int size) 513 { 514 int i, vlen; 515 516 BTF_PRINT_TYPE(func_proto->type); 517 if (func) 518 BTF_PRINT_ARG("%s(", btf__name_by_offset(btf, func->name_off)); 519 else 520 BTF_PRINT_ARG("("); 521 vlen = BTF_INFO_VLEN(func_proto->info); 522 for (i = 0; i < vlen; i++) { 523 struct btf_param *arg = &((struct btf_param *)(func_proto + 1))[i]; 524 525 if (i) 526 BTF_PRINT_ARG(", "); 527 if (arg->type) { 528 BTF_PRINT_TYPE(arg->type); 529 BTF_PRINT_ARG("%s", 530 btf__name_by_offset(btf, arg->name_off)); 531 } else { 532 BTF_PRINT_ARG("..."); 533 } 534 } 535 BTF_PRINT_ARG(")"); 536 537 return pos; 538 } 539 540 void btf_dumper_type_only(const struct btf *btf, __u32 type_id, char *func_sig, 541 int size) 542 { 543 int err; 544 545 func_sig[0] = '\0'; 546 if (!btf) 547 return; 548 549 err = __btf_dumper_type_only(btf, type_id, func_sig, 0, size); 550 if (err < 0) 551 func_sig[0] = '\0'; 552 } 553 554 static const char *ltrim(const char *s) 555 { 556 while (isspace(*s)) 557 s++; 558 559 return s; 560 } 561 562 void btf_dump_linfo_plain(const struct btf *btf, 563 const struct bpf_line_info *linfo, 564 const char *prefix, bool linum) 565 { 566 const char *line = btf__name_by_offset(btf, linfo->line_off); 567 568 if (!line) 569 return; 570 line = ltrim(line); 571 572 if (!prefix) 573 prefix = ""; 574 575 if (linum) { 576 const char *file = btf__name_by_offset(btf, linfo->file_name_off); 577 578 /* More forgiving on file because linum option is 579 * expected to provide more info than the already 580 * available src line. 581 */ 582 if (!file) 583 file = ""; 584 585 printf("%s%s [file:%s line_num:%u line_col:%u]\n", 586 prefix, line, file, 587 BPF_LINE_INFO_LINE_NUM(linfo->line_col), 588 BPF_LINE_INFO_LINE_COL(linfo->line_col)); 589 } else { 590 printf("%s%s\n", prefix, line); 591 } 592 } 593 594 void btf_dump_linfo_json(const struct btf *btf, 595 const struct bpf_line_info *linfo, bool linum) 596 { 597 const char *line = btf__name_by_offset(btf, linfo->line_off); 598 599 if (line) 600 jsonw_string_field(json_wtr, "src", ltrim(line)); 601 602 if (linum) { 603 const char *file = btf__name_by_offset(btf, linfo->file_name_off); 604 605 if (file) 606 jsonw_string_field(json_wtr, "file", file); 607 608 if (BPF_LINE_INFO_LINE_NUM(linfo->line_col)) 609 jsonw_int_field(json_wtr, "line_num", 610 BPF_LINE_INFO_LINE_NUM(linfo->line_col)); 611 612 if (BPF_LINE_INFO_LINE_COL(linfo->line_col)) 613 jsonw_int_field(json_wtr, "line_col", 614 BPF_LINE_INFO_LINE_COL(linfo->line_col)); 615 } 616 } 617