]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
objtool: Add wide output for disassembly
authorAlexandre Chartre <alexandre.chartre@oracle.com>
Fri, 21 Nov 2025 09:53:39 +0000 (10:53 +0100)
committerPeter Zijlstra <peterz@infradead.org>
Mon, 24 Nov 2025 19:40:48 +0000 (20:40 +0100)
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
tools/objtool/builtin-check.c
tools/objtool/disas.c
tools/objtool/include/objtool/builtin.h

index a0371312fe55af9c48cc575627f6e444ede53df7..b780df5137152ef3fd3aa152fe45faaf9a85aa3f 100644 (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(),
 };
index a4f905eac4e639ed51e847fe4da6835a1005fbde..f04bc14bef39e42598bbb834dcdf65101ef8c808 100644 (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;
index e3af664864f300acc5fd28d0ea32a32004a5a21b..b9e229ed4dc057729f02a1070e6f026324517880 100644 (file)
@@ -45,6 +45,7 @@ struct opts {
        const char *trace;
        bool verbose;
        bool werror;
+       bool wide;
 };
 
 extern struct opts opts;