Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

objtool: Disassemble group alternatives

When using the --disas option, disassemble all group alternatives.
Jump tables and exception tables (which are handled as alternatives)
are not disassembled at the moment.

Signed-off-by: Alexandre Chartre <alexandre.chartre@oracle.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Josh Poimboeuf <jpoimboe@kernel.org>
Link: https://patch.msgid.link/20251121095340.464045-21-alexandre.chartre@oracle.com

authored by

Alexandre Chartre and committed by
Peter Zijlstra
a4f15996 87343e66

+149 -17
+149 -17
tools/objtool/disas.c
··· 47 47 struct alternative *alt; /* alternative or NULL if default code */ 48 48 char *name; /* name for this alternative */ 49 49 int width; /* formatting width */ 50 + char *insn[DISAS_ALT_INSN_MAX]; /* alternative instructions */ 50 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) 51 57 52 58 /* 53 59 * Wrapper around asprintf() to allocate and format a string. ··· 512 506 return disasm(insn->offset, &dctx->info); 513 507 } 514 508 509 + static struct instruction *next_insn_same_alt(struct objtool_file *file, 510 + struct alt_group *alt_grp, 511 + struct instruction *insn) 512 + { 513 + if (alt_grp->last_insn == insn || alt_grp->nop == insn) 514 + return NULL; 515 + 516 + return next_insn_same_sec(file, insn); 517 + } 518 + 519 + #define alt_for_each_insn(file, alt_grp, insn) \ 520 + for (insn = alt_grp->first_insn; \ 521 + insn; \ 522 + insn = next_insn_same_alt(file, alt_grp, insn)) 523 + 515 524 /* 516 525 * Provide a name for the type of alternatives present at the 517 526 * specified instruction. ··· 615 594 return 0; 616 595 } 617 596 597 + static int disas_alt_add_insn(struct disas_alt *dalt, int index, char *insn_str) 598 + { 599 + int len; 600 + 601 + if (index >= DISAS_ALT_INSN_MAX) { 602 + WARN("Alternative %lx.%s has more instructions than supported", 603 + DALT_ALTID(dalt), dalt->name); 604 + return -1; 605 + } 606 + 607 + len = strlen(insn_str); 608 + dalt->insn[index] = insn_str; 609 + if (len > dalt->width) 610 + dalt->width = len; 611 + 612 + return 0; 613 + } 614 + 615 + /* 616 + * Disassemble an alternative and store instructions in the disas_alt 617 + * structure. Return the number of instructions in the alternative. 618 + */ 619 + static int disas_alt_group(struct disas_context *dctx, struct disas_alt *dalt) 620 + { 621 + struct objtool_file *file; 622 + struct instruction *insn; 623 + char *str; 624 + int count; 625 + int err; 626 + 627 + file = dctx->file; 628 + count = 0; 629 + 630 + alt_for_each_insn(file, DALT_GROUP(dalt), insn) { 631 + 632 + disas_insn(dctx, insn); 633 + str = strdup(disas_result(dctx)); 634 + if (!str) 635 + return -1; 636 + 637 + err = disas_alt_add_insn(dalt, count, str); 638 + if (err) 639 + break; 640 + count++; 641 + } 642 + 643 + return count; 644 + } 645 + 646 + /* 647 + * Disassemble the default alternative. 648 + */ 649 + static int disas_alt_default(struct disas_context *dctx, struct disas_alt *dalt) 650 + { 651 + char *str; 652 + int err; 653 + 654 + if (DALT_GROUP(dalt)) 655 + return disas_alt_group(dctx, dalt); 656 + 657 + /* 658 + * Default alternative with no alt_group: this is the default 659 + * code associated with either a jump table or an exception 660 + * table and no other instruction alternatives. In that case 661 + * the default alternative is made of a single instruction. 662 + */ 663 + disas_insn(dctx, dalt->orig_insn); 664 + str = strdup(disas_result(dctx)); 665 + if (!str) 666 + return -1; 667 + err = disas_alt_add_insn(dalt, 0, str); 668 + if (err) 669 + return -1; 670 + 671 + return 1; 672 + } 673 + 618 674 /* 619 675 * Print all alternatives one above the other. 620 676 */ 621 677 static void disas_alt_print_compact(char *alt_name, struct disas_alt *dalts, 622 - int alt_count) 678 + int alt_count, int insn_count) 623 679 { 624 680 struct instruction *orig_insn; 681 + int i, j; 625 682 int len; 626 - int i; 627 683 628 684 orig_insn = dalts[0].orig_insn; 629 685 630 686 len = disas_print(stdout, orig_insn->sec, orig_insn->offset, 0, NULL); 631 687 printf("%s\n", alt_name); 632 688 633 - for (i = 0; i < alt_count; i++) 689 + for (i = 0; i < alt_count; i++) { 634 690 printf("%*s= %s\n", len, "", dalts[i].name); 691 + for (j = 0; j < insn_count; j++) { 692 + if (!dalts[i].insn[j]) 693 + break; 694 + printf("%*s| %s\n", len, "", dalts[i].insn[j]); 695 + } 696 + printf("%*s|\n", len, ""); 697 + } 635 698 } 636 699 637 700 /* ··· 729 624 struct instruction *orig_insn) 730 625 { 731 626 struct disas_alt dalts[DISAS_ALT_MAX] = { 0 }; 627 + struct instruction *last_insn = NULL; 732 628 struct alternative *alt; 629 + struct disas_alt *dalt; 630 + int insn_count = 0; 733 631 int alt_count = 0; 734 632 char *alt_name; 633 + int count; 634 + int i, j; 735 635 int err; 736 - int i; 737 636 738 637 alt_name = strfmt("<%s.%lx>", disas_alt_type_name(orig_insn), 739 638 orig_insn->offset); ··· 748 639 } 749 640 750 641 /* 751 - * Initialize the default alternative. 642 + * Initialize and disassemble the default alternative. 752 643 */ 753 644 err = disas_alt_init(&dalts[0], orig_insn, NULL); 754 645 if (err) { ··· 756 647 goto done; 757 648 } 758 649 650 + insn_count = disas_alt_default(dctx, &dalts[0]); 651 + if (insn_count < 0) { 652 + WARN("%s: failed to disassemble default alternative", alt_name); 653 + goto done; 654 + } 655 + 759 656 /* 760 - * Initialize all other alternatives. 657 + * Initialize and disassemble all other alternatives. 761 658 */ 762 659 i = 1; 763 660 for (alt = orig_insn->alts; alt; alt = alt->next) { ··· 771 656 WARN("%s has more alternatives than supported", alt_name); 772 657 break; 773 658 } 774 - err = disas_alt_init(&dalts[i], orig_insn, alt); 659 + dalt = &dalts[i]; 660 + err = disas_alt_init(dalt, orig_insn, alt); 775 661 if (err) { 776 662 WARN("%s: failed to disassemble alternative", alt_name); 777 663 goto done; 778 664 } 779 665 666 + /* 667 + * Only group alternatives are supported at the moment. 668 + */ 669 + switch (dalt->alt->type) { 670 + case ALT_TYPE_INSTRUCTIONS: 671 + count = disas_alt_group(dctx, dalt); 672 + break; 673 + default: 674 + count = 0; 675 + } 676 + if (count < 0) { 677 + WARN("%s: failed to disassemble alternative %s", 678 + alt_name, dalt->name); 679 + goto done; 680 + } 681 + 682 + insn_count = count > insn_count ? count : insn_count; 780 683 i++; 781 684 } 782 685 alt_count = i; 783 686 784 687 /* 785 688 * Print default and non-default alternatives. 786 - * 787 - * At the moment, this just prints an header for each alternative. 788 689 */ 789 - disas_alt_print_compact(alt_name, dalts, alt_count); 690 + disas_alt_print_compact(alt_name, dalts, alt_count, insn_count); 691 + 692 + last_insn = orig_insn->alt_group ? orig_insn->alt_group->last_insn : 693 + orig_insn; 790 694 791 695 done: 792 - for (i = 0; i < alt_count; i++) 696 + for (i = 0; i < alt_count; i++) { 793 697 free(dalts[i].name); 698 + for (j = 0; j < insn_count; j++) 699 + free(dalts[i].insn[j]); 700 + } 794 701 795 702 free(alt_name); 796 703 797 - /* 798 - * Currently we are not disassembling any alternative but just 799 - * printing alternative names. Return NULL to have disas_func() 800 - * resume the disassembly with the default alternative. 801 - */ 802 - return NULL; 704 + return last_insn; 803 705 } 804 706 805 707 /*