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