objtool: Add wide output for disassembly

Add the --wide option to provide a wide output when disassembling.
With this option, the disassembly of alternatives is displayed
side-by-side instead of one above the other.

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-30-alexandre.chartre@oracle.com
pull/1354/merge
Alexandre Chartre 2025-11-21 10:53:39 +01:00 committed by Peter Zijlstra
parent 07d70b271a
commit aff95e0d4e
3 changed files with 96 additions and 1 deletions

View File

@ -107,6 +107,7 @@ static const struct option check_options[] = {
OPT_STRING(0, "trace", &opts.trace, "func", "trace function validation"),
OPT_BOOLEAN('v', "verbose", &opts.verbose, "verbose warnings"),
OPT_BOOLEAN(0, "werror", &opts.werror, "return error on warnings"),
OPT_BOOLEAN(0, "wide", &opts.wide, "wide output"),
OPT_END(),
};

View File

@ -856,6 +856,95 @@ static int disas_alt_default(struct disas_context *dctx, struct disas_alt *dalt)
return 1;
}
/*
* For each alternative, if there is an instruction at the specified
* offset then print this instruction, otherwise print a blank entry.
* The offset is an offset from the start of the alternative.
*
* Return the offset for the next instructions to print, or -1 if all
* instructions have been printed.
*/
static int disas_alt_print_insn(struct disas_alt *dalts, int alt_count,
int insn_count, int offset)
{
struct disas_alt *dalt;
int offset_next;
char *str;
int i, j;
offset_next = -1;
for (i = 0; i < alt_count; i++) {
dalt = &dalts[i];
j = dalt->insn_idx;
if (j == -1) {
printf("| %-*s ", dalt->width, "");
continue;
}
if (dalt->insn[j].offset == offset) {
str = dalt->insn[j].str;
printf("| %-*s ", dalt->width, str ?: "");
if (++j < insn_count) {
dalt->insn_idx = j;
} else {
dalt->insn_idx = -1;
continue;
}
} else {
printf("| %-*s ", dalt->width, "");
}
if (dalt->insn[j].offset > 0 &&
(offset_next == -1 ||
(dalt->insn[j].offset < offset_next)))
offset_next = dalt->insn[j].offset;
}
printf("\n");
return offset_next;
}
/*
* Print all alternatives side-by-side.
*/
static void disas_alt_print_wide(char *alt_name, struct disas_alt *dalts, int alt_count,
int insn_count)
{
struct instruction *orig_insn;
int offset_next;
int offset;
int i;
orig_insn = dalts[0].orig_insn;
/*
* Print an header with the name of each alternative.
*/
disas_print_info(stdout, orig_insn, -2, NULL);
if (strlen(alt_name) > dalts[0].width)
dalts[0].width = strlen(alt_name);
printf("| %-*s ", dalts[0].width, alt_name);
for (i = 1; i < alt_count; i++)
printf("| %-*s ", dalts[i].width, dalts[i].name);
printf("\n");
/*
* Print instructions for each alternative.
*/
offset_next = 0;
do {
offset = offset_next;
disas_print(stdout, orig_insn->sec, orig_insn->offset + offset,
-2, NULL);
offset_next = disas_alt_print_insn(dalts, alt_count, insn_count,
offset);
} while (offset_next > offset);
}
/*
* Print all alternatives one above the other.
*/
@ -993,7 +1082,11 @@ static void *disas_alt(struct disas_context *dctx,
/*
* Print default and non-default alternatives.
*/
disas_alt_print_compact(alt_name, dalts, alt_count, insn_count);
if (opts.wide)
disas_alt_print_wide(alt_name, dalts, alt_count, insn_count);
else
disas_alt_print_compact(alt_name, dalts, alt_count, insn_count);
last_insn = orig_insn->alt_group ? orig_insn->alt_group->last_insn :
orig_insn;

View File

@ -45,6 +45,7 @@ struct opts {
const char *trace;
bool verbose;
bool werror;
bool wide;
};
extern struct opts opts;