1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com> 4 */ 5 6 #define _GNU_SOURCE 7 #include <fnmatch.h> 8 9 #include <objtool/arch.h> 10 #include <objtool/check.h> 11 #include <objtool/disas.h> 12 #include <objtool/warn.h> 13 14 #include <bfd.h> 15 #include <linux/string.h> 16 #include <tools/dis-asm-compat.h> 17 18 /* 19 * Size of the buffer for storing the result of disassembling 20 * a single instruction. 21 */ 22 #define DISAS_RESULT_SIZE 1024 23 24 struct disas_context { 25 struct objtool_file *file; 26 struct instruction *insn; 27 char result[DISAS_RESULT_SIZE]; 28 disassembler_ftype disassembler; 29 struct disassemble_info info; 30 }; 31 32 /* 33 * Maximum number of alternatives 34 */ 35 #define DISAS_ALT_MAX 5 36 37 /* 38 * Maximum number of instructions per alternative 39 */ 40 #define DISAS_ALT_INSN_MAX 50 41 42 /* 43 * Information to disassemble an alternative 44 */ 45 struct disas_alt { 46 struct instruction *orig_insn; /* original instruction */ 47 struct alternative *alt; /* alternative or NULL if default code */ 48 char *name; /* name for this alternative */ 49 int width; /* formatting width */ 50 struct { 51 char *str; /* instruction string */ 52 int offset; /* instruction offset */ 53 } insn[DISAS_ALT_INSN_MAX]; /* alternative instructions */ 54 int insn_idx; /* index of the next instruction to print */ 55 }; 56 57 #define DALT_DEFAULT(dalt) (!(dalt)->alt) 58 #define DALT_INSN(dalt) (DALT_DEFAULT(dalt) ? (dalt)->orig_insn : (dalt)->alt->insn) 59 #define DALT_GROUP(dalt) (DALT_INSN(dalt)->alt_group) 60 #define DALT_ALTID(dalt) ((dalt)->orig_insn->offset) 61 62 /* 63 * Wrapper around asprintf() to allocate and format a string. 64 * Return the allocated string or NULL on error. 65 */ 66 static char *strfmt(const char *fmt, ...) 67 { 68 va_list ap; 69 char *str; 70 int rv; 71 72 va_start(ap, fmt); 73 rv = vasprintf(&str, fmt, ap); 74 va_end(ap); 75 76 return rv == -1 ? NULL : str; 77 } 78 79 static int sprint_name(char *str, const char *name, unsigned long offset) 80 { 81 int len; 82 83 if (offset) 84 len = sprintf(str, "%s+0x%lx", name, offset); 85 else 86 len = sprintf(str, "%s", name); 87 88 return len; 89 } 90 91 #define DINFO_FPRINTF(dinfo, ...) \ 92 ((*(dinfo)->fprintf_func)((dinfo)->stream, __VA_ARGS__)) 93 94 static int disas_result_fprintf(struct disas_context *dctx, 95 const char *fmt, va_list ap) 96 { 97 char *buf = dctx->result; 98 int avail, len; 99 100 len = strlen(buf); 101 if (len >= DISAS_RESULT_SIZE - 1) { 102 WARN_FUNC(dctx->insn->sec, dctx->insn->offset, 103 "disassembly buffer is full"); 104 return -1; 105 } 106 avail = DISAS_RESULT_SIZE - len; 107 108 len = vsnprintf(buf + len, avail, fmt, ap); 109 if (len < 0 || len >= avail) { 110 WARN_FUNC(dctx->insn->sec, dctx->insn->offset, 111 "disassembly buffer is truncated"); 112 return -1; 113 } 114 115 return 0; 116 } 117 118 static int disas_fprintf(void *stream, const char *fmt, ...) 119 { 120 va_list arg; 121 int rv; 122 123 va_start(arg, fmt); 124 rv = disas_result_fprintf(stream, fmt, arg); 125 va_end(arg); 126 127 return rv; 128 } 129 130 /* 131 * For init_disassemble_info_compat(). 132 */ 133 static int disas_fprintf_styled(void *stream, 134 enum disassembler_style style, 135 const char *fmt, ...) 136 { 137 va_list arg; 138 int rv; 139 140 va_start(arg, fmt); 141 rv = disas_result_fprintf(stream, fmt, arg); 142 va_end(arg); 143 144 return rv; 145 } 146 147 static void disas_print_addr_sym(struct section *sec, struct symbol *sym, 148 bfd_vma addr, struct disassemble_info *dinfo) 149 { 150 char symstr[1024]; 151 char *str; 152 153 if (sym) { 154 sprint_name(symstr, sym->name, addr - sym->offset); 155 DINFO_FPRINTF(dinfo, "0x%lx <%s>", addr, symstr); 156 } else { 157 str = offstr(sec, addr); 158 DINFO_FPRINTF(dinfo, "0x%lx <%s>", addr, str); 159 free(str); 160 } 161 } 162 163 static void disas_print_addr_noreloc(bfd_vma addr, 164 struct disassemble_info *dinfo) 165 { 166 struct disas_context *dctx = dinfo->application_data; 167 struct instruction *insn = dctx->insn; 168 struct symbol *sym = NULL; 169 170 if (insn->sym && addr >= insn->sym->offset && 171 addr < insn->sym->offset + insn->sym->len) { 172 sym = insn->sym; 173 } 174 175 disas_print_addr_sym(insn->sec, sym, addr, dinfo); 176 } 177 178 static void disas_print_addr_reloc(bfd_vma addr, struct disassemble_info *dinfo) 179 { 180 struct disas_context *dctx = dinfo->application_data; 181 struct instruction *insn = dctx->insn; 182 unsigned long offset; 183 struct reloc *reloc; 184 char symstr[1024]; 185 char *str; 186 187 reloc = find_reloc_by_dest_range(dctx->file->elf, insn->sec, 188 insn->offset, insn->len); 189 if (!reloc) { 190 /* 191 * There is no relocation for this instruction although 192 * the address to resolve points to the next instruction. 193 * So this is an effective reference to the next IP, for 194 * example: "lea 0x0(%rip),%rdi". The kernel can reference 195 * the next IP with _THIS_IP_ macro. 196 */ 197 DINFO_FPRINTF(dinfo, "0x%lx <_THIS_IP_>", addr); 198 return; 199 } 200 201 offset = arch_insn_adjusted_addend(insn, reloc); 202 203 /* 204 * If the relocation symbol is a section name (for example ".bss") 205 * then we try to further resolve the name. 206 */ 207 if (reloc->sym->type == STT_SECTION) { 208 str = offstr(reloc->sym->sec, reloc->sym->offset + offset); 209 DINFO_FPRINTF(dinfo, "0x%lx <%s>", addr, str); 210 free(str); 211 } else { 212 sprint_name(symstr, reloc->sym->name, offset); 213 DINFO_FPRINTF(dinfo, "0x%lx <%s>", addr, symstr); 214 } 215 } 216 217 /* 218 * Resolve an address into a "<symbol>+<offset>" string. 219 */ 220 static void disas_print_address(bfd_vma addr, struct disassemble_info *dinfo) 221 { 222 struct disas_context *dctx = dinfo->application_data; 223 struct instruction *insn = dctx->insn; 224 struct instruction *jump_dest; 225 struct symbol *sym; 226 bool is_reloc; 227 228 /* 229 * If the instruction is a call/jump and it references a 230 * destination then this is likely the address we are looking 231 * up. So check it first. 232 */ 233 jump_dest = insn->jump_dest; 234 if (jump_dest && jump_dest->sym && jump_dest->offset == addr) { 235 disas_print_addr_sym(jump_dest->sec, jump_dest->sym, 236 addr, dinfo); 237 return; 238 } 239 240 /* 241 * If the address points to the next instruction then there is 242 * probably a relocation. It can be a false positive when the 243 * current instruction is referencing the address of the next 244 * instruction. This particular case will be handled in 245 * disas_print_addr_reloc(). 246 */ 247 is_reloc = (addr == insn->offset + insn->len); 248 249 /* 250 * The call destination offset can be the address we are looking 251 * up, or 0 if there is a relocation. 252 */ 253 sym = insn_call_dest(insn); 254 if (sym && (sym->offset == addr || (sym->offset == 0 && is_reloc))) { 255 DINFO_FPRINTF(dinfo, "0x%lx <%s>", addr, sym->name); 256 return; 257 } 258 259 if (!is_reloc) 260 disas_print_addr_noreloc(addr, dinfo); 261 else 262 disas_print_addr_reloc(addr, dinfo); 263 } 264 265 /* 266 * Initialize disassemble info arch, mach (32 or 64-bit) and options. 267 */ 268 int disas_info_init(struct disassemble_info *dinfo, 269 int arch, int mach32, int mach64, 270 const char *options) 271 { 272 struct disas_context *dctx = dinfo->application_data; 273 struct objtool_file *file = dctx->file; 274 275 dinfo->arch = arch; 276 277 switch (file->elf->ehdr.e_ident[EI_CLASS]) { 278 case ELFCLASS32: 279 dinfo->mach = mach32; 280 break; 281 case ELFCLASS64: 282 dinfo->mach = mach64; 283 break; 284 default: 285 return -1; 286 } 287 288 dinfo->disassembler_options = options; 289 290 return 0; 291 } 292 293 struct disas_context *disas_context_create(struct objtool_file *file) 294 { 295 struct disas_context *dctx; 296 struct disassemble_info *dinfo; 297 int err; 298 299 dctx = malloc(sizeof(*dctx)); 300 if (!dctx) { 301 WARN("failed to allocate disassembly context"); 302 return NULL; 303 } 304 305 dctx->file = file; 306 dinfo = &dctx->info; 307 308 init_disassemble_info_compat(dinfo, dctx, 309 disas_fprintf, disas_fprintf_styled); 310 311 dinfo->read_memory_func = buffer_read_memory; 312 dinfo->print_address_func = disas_print_address; 313 dinfo->application_data = dctx; 314 315 /* 316 * bfd_openr() is not used to avoid doing ELF data processing 317 * and caching that has already being done. Here, we just need 318 * to identify the target file so we call an arch specific 319 * function to fill some disassemble info (arch, mach). 320 */ 321 322 dinfo->arch = bfd_arch_unknown; 323 dinfo->mach = 0; 324 325 err = arch_disas_info_init(dinfo); 326 if (err || dinfo->arch == bfd_arch_unknown || dinfo->mach == 0) { 327 WARN("failed to init disassembly arch"); 328 goto error; 329 } 330 331 dinfo->endian = (file->elf->ehdr.e_ident[EI_DATA] == ELFDATA2MSB) ? 332 BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE; 333 334 disassemble_init_for_target(dinfo); 335 336 dctx->disassembler = disassembler(dinfo->arch, 337 dinfo->endian == BFD_ENDIAN_BIG, 338 dinfo->mach, NULL); 339 if (!dctx->disassembler) { 340 WARN("failed to create disassembler function"); 341 goto error; 342 } 343 344 return dctx; 345 346 error: 347 free(dctx); 348 return NULL; 349 } 350 351 void disas_context_destroy(struct disas_context *dctx) 352 { 353 free(dctx); 354 } 355 356 char *disas_result(struct disas_context *dctx) 357 { 358 return dctx->result; 359 } 360 361 #define DISAS_INSN_OFFSET_SPACE 10 362 #define DISAS_INSN_SPACE 60 363 364 #define DISAS_PRINSN(dctx, insn, depth) \ 365 disas_print_insn(stdout, dctx, insn, depth, "\n") 366 367 /* 368 * Print a message in the instruction flow. If sec is not NULL then the 369 * address at the section offset is printed in addition of the message, 370 * otherwise only the message is printed. 371 */ 372 static int disas_vprint(FILE *stream, struct section *sec, unsigned long offset, 373 int depth, const char *format, va_list ap) 374 { 375 const char *addr_str; 376 int i, n; 377 int len; 378 379 len = sym_name_max_len + DISAS_INSN_OFFSET_SPACE; 380 if (depth < 0) { 381 len += depth; 382 depth = 0; 383 } 384 385 n = 0; 386 387 if (sec) { 388 addr_str = offstr(sec, offset); 389 n += fprintf(stream, "%6lx: %-*s ", offset, len, addr_str); 390 free((char *)addr_str); 391 } else { 392 len += DISAS_INSN_OFFSET_SPACE + 1; 393 n += fprintf(stream, "%-*s", len, ""); 394 } 395 396 /* print vertical bars to show the code flow */ 397 for (i = 0; i < depth; i++) 398 n += fprintf(stream, "| "); 399 400 if (format) 401 n += vfprintf(stream, format, ap); 402 403 return n; 404 } 405 406 static int disas_print(FILE *stream, struct section *sec, unsigned long offset, 407 int depth, const char *format, ...) 408 { 409 va_list args; 410 int len; 411 412 va_start(args, format); 413 len = disas_vprint(stream, sec, offset, depth, format, args); 414 va_end(args); 415 416 return len; 417 } 418 419 /* 420 * Print a message in the instruction flow. If insn is not NULL then 421 * the instruction address is printed in addition of the message, 422 * otherwise only the message is printed. In all cases, the instruction 423 * itself is not printed. 424 */ 425 void disas_print_info(FILE *stream, struct instruction *insn, int depth, 426 const char *format, ...) 427 { 428 struct section *sec; 429 unsigned long off; 430 va_list args; 431 432 if (insn) { 433 sec = insn->sec; 434 off = insn->offset; 435 } else { 436 sec = NULL; 437 off = 0; 438 } 439 440 va_start(args, format); 441 disas_vprint(stream, sec, off, depth, format, args); 442 va_end(args); 443 } 444 445 /* 446 * Print an instruction address (offset and function), the instruction itself 447 * and an optional message. 448 */ 449 void disas_print_insn(FILE *stream, struct disas_context *dctx, 450 struct instruction *insn, int depth, 451 const char *format, ...) 452 { 453 char fake_nop_insn[32]; 454 const char *insn_str; 455 bool fake_nop; 456 va_list args; 457 int len; 458 459 /* 460 * Alternative can insert a fake nop, sometimes with no 461 * associated section so nothing to disassemble. 462 */ 463 fake_nop = (!insn->sec && insn->type == INSN_NOP); 464 if (fake_nop) { 465 snprintf(fake_nop_insn, 32, "<fake nop> (%d bytes)", insn->len); 466 insn_str = fake_nop_insn; 467 } else { 468 disas_insn(dctx, insn); 469 insn_str = disas_result(dctx); 470 } 471 472 /* print the instruction */ 473 len = (depth + 1) * 2 < DISAS_INSN_SPACE ? DISAS_INSN_SPACE - (depth+1) * 2 : 1; 474 disas_print_info(stream, insn, depth, "%-*s", len, insn_str); 475 476 /* print message if any */ 477 if (!format) 478 return; 479 480 if (strcmp(format, "\n") == 0) { 481 fprintf(stream, "\n"); 482 return; 483 } 484 485 fprintf(stream, " - "); 486 va_start(args, format); 487 vfprintf(stream, format, args); 488 va_end(args); 489 } 490 491 /* 492 * Disassemble a single instruction. Return the size of the instruction. 493 */ 494 size_t disas_insn(struct disas_context *dctx, struct instruction *insn) 495 { 496 disassembler_ftype disasm = dctx->disassembler; 497 struct disassemble_info *dinfo = &dctx->info; 498 499 dctx->insn = insn; 500 dctx->result[0] = '\0'; 501 502 if (insn->type == INSN_NOP) { 503 DINFO_FPRINTF(dinfo, "nop%d", insn->len); 504 return insn->len; 505 } 506 507 /* 508 * Set the disassembler buffer to read data from the section 509 * containing the instruction to disassemble. 510 */ 511 dinfo->buffer = insn->sec->data->d_buf; 512 dinfo->buffer_vma = 0; 513 dinfo->buffer_length = insn->sec->sh.sh_size; 514 515 return disasm(insn->offset, &dctx->info); 516 } 517 518 static struct instruction *next_insn_same_alt(struct objtool_file *file, 519 struct alt_group *alt_grp, 520 struct instruction *insn) 521 { 522 if (alt_grp->last_insn == insn || alt_grp->nop == insn) 523 return NULL; 524 525 return next_insn_same_sec(file, insn); 526 } 527 528 #define alt_for_each_insn(file, alt_grp, insn) \ 529 for (insn = alt_grp->first_insn; \ 530 insn; \ 531 insn = next_insn_same_alt(file, alt_grp, insn)) 532 533 /* 534 * Provide a name for the type of alternatives present at the 535 * specified instruction. 536 * 537 * An instruction can have alternatives with different types, for 538 * example alternative instructions and an exception table. In that 539 * case the name for the alternative instructions type is used. 540 * 541 * Return NULL if the instruction as no alternative. 542 */ 543 const char *disas_alt_type_name(struct instruction *insn) 544 { 545 struct alternative *alt; 546 const char *name; 547 548 name = NULL; 549 for (alt = insn->alts; alt; alt = alt->next) { 550 if (alt->type == ALT_TYPE_INSTRUCTIONS) { 551 name = "alternative"; 552 break; 553 } 554 555 switch (alt->type) { 556 case ALT_TYPE_EX_TABLE: 557 name = "ex_table"; 558 break; 559 case ALT_TYPE_JUMP_TABLE: 560 name = "jump_table"; 561 break; 562 default: 563 name = "unknown"; 564 break; 565 } 566 } 567 568 return name; 569 } 570 571 /* 572 * Provide a name for an alternative. 573 */ 574 char *disas_alt_name(struct alternative *alt) 575 { 576 char *str = NULL; 577 578 switch (alt->type) { 579 580 case ALT_TYPE_EX_TABLE: 581 str = strdup("EXCEPTION"); 582 break; 583 584 case ALT_TYPE_JUMP_TABLE: 585 str = strdup("JUMP"); 586 break; 587 588 case ALT_TYPE_INSTRUCTIONS: 589 /* 590 * This is a non-default group alternative. Create a unique 591 * name using the offset of the first original and alternative 592 * instructions. 593 */ 594 asprintf(&str, "ALTERNATIVE %lx.%lx", 595 alt->insn->alt_group->orig_group->first_insn->offset, 596 alt->insn->alt_group->first_insn->offset); 597 break; 598 } 599 600 return str; 601 } 602 603 /* 604 * Initialize an alternative. The default alternative should be initialized 605 * with alt=NULL. 606 */ 607 static int disas_alt_init(struct disas_alt *dalt, 608 struct instruction *orig_insn, 609 struct alternative *alt) 610 { 611 dalt->orig_insn = orig_insn; 612 dalt->alt = alt; 613 dalt->insn_idx = 0; 614 dalt->name = alt ? disas_alt_name(alt) : strdup("DEFAULT"); 615 if (!dalt->name) 616 return -1; 617 dalt->width = strlen(dalt->name); 618 619 return 0; 620 } 621 622 static int disas_alt_add_insn(struct disas_alt *dalt, int index, char *insn_str, 623 int offset) 624 { 625 int len; 626 627 if (index >= DISAS_ALT_INSN_MAX) { 628 WARN("Alternative %lx.%s has more instructions than supported", 629 DALT_ALTID(dalt), dalt->name); 630 return -1; 631 } 632 633 len = strlen(insn_str); 634 dalt->insn[index].str = insn_str; 635 dalt->insn[index].offset = offset; 636 if (len > dalt->width) 637 dalt->width = len; 638 639 return 0; 640 } 641 642 /* 643 * Disassemble an alternative and store instructions in the disas_alt 644 * structure. Return the number of instructions in the alternative. 645 */ 646 static int disas_alt_group(struct disas_context *dctx, struct disas_alt *dalt) 647 { 648 struct objtool_file *file; 649 struct instruction *insn; 650 int offset; 651 char *str; 652 int count; 653 int err; 654 655 file = dctx->file; 656 count = 0; 657 offset = 0; 658 659 alt_for_each_insn(file, DALT_GROUP(dalt), insn) { 660 661 disas_insn(dctx, insn); 662 str = strdup(disas_result(dctx)); 663 if (!str) 664 return -1; 665 666 err = disas_alt_add_insn(dalt, count, str, offset); 667 if (err) 668 break; 669 offset += insn->len; 670 count++; 671 } 672 673 return count; 674 } 675 676 /* 677 * Disassemble the default alternative. 678 */ 679 static int disas_alt_default(struct disas_context *dctx, struct disas_alt *dalt) 680 { 681 char *str; 682 int err; 683 684 if (DALT_GROUP(dalt)) 685 return disas_alt_group(dctx, dalt); 686 687 /* 688 * Default alternative with no alt_group: this is the default 689 * code associated with either a jump table or an exception 690 * table and no other instruction alternatives. In that case 691 * the default alternative is made of a single instruction. 692 */ 693 disas_insn(dctx, dalt->orig_insn); 694 str = strdup(disas_result(dctx)); 695 if (!str) 696 return -1; 697 err = disas_alt_add_insn(dalt, 0, str, 0); 698 if (err) 699 return -1; 700 701 return 1; 702 } 703 704 /* 705 * Print all alternatives one above the other. 706 */ 707 static void disas_alt_print_compact(char *alt_name, struct disas_alt *dalts, 708 int alt_count, int insn_count) 709 { 710 struct instruction *orig_insn; 711 int i, j; 712 int len; 713 714 orig_insn = dalts[0].orig_insn; 715 716 len = disas_print(stdout, orig_insn->sec, orig_insn->offset, 0, NULL); 717 printf("%s\n", alt_name); 718 719 for (i = 0; i < alt_count; i++) { 720 printf("%*s= %s\n", len, "", dalts[i].name); 721 for (j = 0; j < insn_count; j++) { 722 if (!dalts[i].insn[j].str) 723 break; 724 disas_print(stdout, orig_insn->sec, 725 orig_insn->offset + dalts[i].insn[j].offset, 0, 726 "| %s\n", dalts[i].insn[j].str); 727 } 728 printf("%*s|\n", len, ""); 729 } 730 } 731 732 /* 733 * Disassemble an alternative. 734 * 735 * Return the last instruction in the default alternative so that 736 * disassembly can continue with the next instruction. Return NULL 737 * on error. 738 */ 739 static void *disas_alt(struct disas_context *dctx, 740 struct instruction *orig_insn) 741 { 742 struct disas_alt dalts[DISAS_ALT_MAX] = { 0 }; 743 struct instruction *last_insn = NULL; 744 struct alternative *alt; 745 struct disas_alt *dalt; 746 int insn_count = 0; 747 int alt_count = 0; 748 char *alt_name; 749 int count; 750 int i, j; 751 int err; 752 753 alt_name = strfmt("<%s.%lx>", disas_alt_type_name(orig_insn), 754 orig_insn->offset); 755 if (!alt_name) { 756 WARN("Failed to define name for alternative at instruction 0x%lx", 757 orig_insn->offset); 758 goto done; 759 } 760 761 /* 762 * Initialize and disassemble the default alternative. 763 */ 764 err = disas_alt_init(&dalts[0], orig_insn, NULL); 765 if (err) { 766 WARN("%s: failed to initialize default alternative", alt_name); 767 goto done; 768 } 769 770 insn_count = disas_alt_default(dctx, &dalts[0]); 771 if (insn_count < 0) { 772 WARN("%s: failed to disassemble default alternative", alt_name); 773 goto done; 774 } 775 776 /* 777 * Initialize and disassemble all other alternatives. 778 */ 779 i = 1; 780 for (alt = orig_insn->alts; alt; alt = alt->next) { 781 if (i >= DISAS_ALT_MAX) { 782 WARN("%s has more alternatives than supported", alt_name); 783 break; 784 } 785 dalt = &dalts[i]; 786 err = disas_alt_init(dalt, orig_insn, alt); 787 if (err) { 788 WARN("%s: failed to disassemble alternative", alt_name); 789 goto done; 790 } 791 792 /* 793 * Only group alternatives are supported at the moment. 794 */ 795 switch (dalt->alt->type) { 796 case ALT_TYPE_INSTRUCTIONS: 797 count = disas_alt_group(dctx, dalt); 798 break; 799 default: 800 count = 0; 801 } 802 if (count < 0) { 803 WARN("%s: failed to disassemble alternative %s", 804 alt_name, dalt->name); 805 goto done; 806 } 807 808 insn_count = count > insn_count ? count : insn_count; 809 i++; 810 } 811 alt_count = i; 812 813 /* 814 * Print default and non-default alternatives. 815 */ 816 disas_alt_print_compact(alt_name, dalts, alt_count, insn_count); 817 818 last_insn = orig_insn->alt_group ? orig_insn->alt_group->last_insn : 819 orig_insn; 820 821 done: 822 for (i = 0; i < alt_count; i++) { 823 free(dalts[i].name); 824 for (j = 0; j < insn_count; j++) 825 free(dalts[i].insn[j].str); 826 } 827 828 free(alt_name); 829 830 return last_insn; 831 } 832 833 /* 834 * Disassemble a function. 835 */ 836 static void disas_func(struct disas_context *dctx, struct symbol *func) 837 { 838 struct instruction *insn_start; 839 struct instruction *insn; 840 841 printf("%s:\n", func->name); 842 sym_for_each_insn(dctx->file, func, insn) { 843 if (insn->alts) { 844 insn_start = insn; 845 insn = disas_alt(dctx, insn); 846 if (insn) 847 continue; 848 /* 849 * There was an error with disassembling 850 * the alternative. Resume disassembling 851 * at the current instruction, this will 852 * disassemble the default alternative 853 * only and continue with the code after 854 * the alternative. 855 */ 856 insn = insn_start; 857 } 858 859 DISAS_PRINSN(dctx, insn, 0); 860 } 861 printf("\n"); 862 } 863 864 /* 865 * Disassemble all warned functions. 866 */ 867 void disas_warned_funcs(struct disas_context *dctx) 868 { 869 struct symbol *sym; 870 871 if (!dctx) 872 return; 873 874 for_each_sym(dctx->file->elf, sym) { 875 if (sym->warned) 876 disas_func(dctx, sym); 877 } 878 } 879 880 void disas_funcs(struct disas_context *dctx) 881 { 882 bool disas_all = !strcmp(opts.disas, "*"); 883 struct section *sec; 884 struct symbol *sym; 885 886 for_each_sec(dctx->file->elf, sec) { 887 888 if (!(sec->sh.sh_flags & SHF_EXECINSTR)) 889 continue; 890 891 sec_for_each_sym(sec, sym) { 892 /* 893 * If the function had a warning and the verbose 894 * option is used then the function was already 895 * disassemble. 896 */ 897 if (opts.verbose && sym->warned) 898 continue; 899 900 if (disas_all || fnmatch(opts.disas, sym->name, 0) == 0) 901 disas_func(dctx, sym); 902 } 903 } 904 } 905