From: Alexandre Chartre <alexandre.chartre@oracle.com>
To: linux-kernel@vger.kernel.org, mingo@kernel.org,
jpoimboe@kernel.org, peterz@infradead.org
Cc: alexandre.chartre@oracle.com
Subject: [RFC PATCH v2 17/17] objtool: Disassemble all alternatives when using --disas
Date: Thu, 19 Jun 2025 16:56:59 +0200 [thread overview]
Message-ID: <20250619145659.1377970-18-alexandre.chartre@oracle.com> (raw)
In-Reply-To: <20250619145659.1377970-1-alexandre.chartre@oracle.com>
When using the --disas action, disassemble all code alternatives
instead of only the default alternative.
Signed-off-by: Alexandre Chartre <alexandre.chartre@oracle.com>
---
tools/objtool/check.c | 8 --
tools/objtool/disas.c | 152 +++++++++++++++++++++++++-
tools/objtool/include/objtool/check.h | 8 ++
3 files changed, 154 insertions(+), 14 deletions(-)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index c7a70d47f104..fa66c8c6bf21 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -25,11 +25,6 @@
#include <linux/static_call_types.h>
#include <linux/string.h>
-struct alternative {
- struct alternative *next;
- struct instruction *insn;
-};
-
static unsigned long nr_cfi, nr_cfi_reused, nr_cfi_cache;
static struct cfi_init_state initial_func_cfi;
@@ -131,9 +126,6 @@ static struct instruction *prev_insn_same_sym(struct objtool_file *file,
insn && insn->offset >= sym->offset; \
insn = prev_insn_same_sec(file, insn))
-#define sec_for_each_insn_from(file, insn) \
- for (; insn; insn = next_insn_same_sec(file, insn))
-
#define sec_for_each_insn_continue(file, insn) \
for (insn = next_insn_same_sec(file, insn); insn; \
insn = next_insn_same_sec(file, insn))
diff --git a/tools/objtool/disas.c b/tools/objtool/disas.c
index 97d506afdf45..9c202feee493 100644
--- a/tools/objtool/disas.c
+++ b/tools/objtool/disas.c
@@ -266,6 +266,12 @@ char *disas_result(struct disas_context *dctx)
#define DISAS_INSN_OFFSET_SPACE 10
#define DISAS_INSN_SPACE 60
+#define DISAS_PRINFO(insn, depth, format, ...) \
+ disas_print_info(stdout, insn, depth, format "\n", ##__VA_ARGS__)
+
+#define DISAS_PRINSN(dctx, insn, depth) \
+ disas_print_insn(stdout, dctx, insn, depth, "\n")
+
/*
* Print a message in the instruction flow. If insn is not NULL then
* the instruction address is printed in addition of the message,
@@ -345,6 +351,82 @@ void disas_print_insn(FILE *stream, struct disas_context *dctx,
va_end(args);
}
+static void disas_group_alt(struct disas_context *dctx,
+ struct instruction *orig_insn)
+{
+ struct instruction *insn;
+ struct alternative *alt;
+ struct symbol *func;
+ int i, count;
+ int alt_id;
+
+ func = orig_insn->sym;
+ alt_id = orig_insn->offset;
+
+ count = 0;
+ for (alt = orig_insn->alts; alt; alt = alt->next) {
+ if (!alt->insn->alt_group)
+ /* jump alternative */
+ continue;
+
+ if (func && alt->insn->sec == func->sec)
+ /* exception handler */
+ continue;
+
+ /* count group alternatives, including fake nop */
+ count++;
+ }
+
+ i = 1;
+ for (alt = orig_insn->alts; alt; alt = alt->next) {
+
+ if (!alt->insn->alt_group)
+ continue;
+
+ /*
+ * If the alternative instruction is in the same section
+ * as the original instruction then that's an exception
+ * handling i.e. branch to the alternative instruction if
+ * there is an exception.
+ */
+ if (func && alt->insn->sec == func->sec) {
+ DISAS_PRINFO(NULL, 0,
+ "<alternative.%x> exception handler - begin", alt_id);
+ DISAS_PRINFO(orig_insn, 1, "jmp %lx <%s+0x%lx>",
+ alt->insn->offset, func->name,
+ alt->insn->offset - func->offset);
+ DISAS_PRINFO(NULL, 0,
+ "<alternative.%x> exception handler - end", alt_id);
+ continue;
+ }
+
+ DISAS_PRINFO(NULL, 0,
+ "<alternative.%x> %d/%d - begin", alt_id, i, count);
+
+ insn = alt->insn->alt_group->first_insn;
+
+ sec_for_each_insn_from(dctx->file, insn) {
+
+ if (insn->alts) {
+ DISAS_PRINFO(insn, 0,
+ "alt group: ignore nested alternative (not supported)");
+ }
+
+ DISAS_PRINSN(dctx, insn, 1);
+
+ if (insn == insn->alt_group->last_insn ||
+ insn == insn->alt_group->nop)
+ break;
+
+ insn = next_insn_same_sec(dctx->file, insn);
+ }
+
+ DISAS_PRINFO(NULL, 0,
+ "<alternative.%x> %d/%d end", alt_id, i, count);
+ i++;
+ }
+}
+
/*
* Disassemble a single instruction. Return the size of the instruction.
*/
@@ -367,21 +449,79 @@ size_t disas_insn(struct disas_context *dctx, struct instruction *insn)
return disasm(insn->offset, &dctx->info);
}
+static void disas_jump_alt(struct disas_context *dctx, struct instruction *insn)
+{
+ struct instruction *alt_insn;
+ struct symbol *func;
+ int alt_id;
+
+ func = insn->sym;
+ alt_id = insn->offset;
+
+ DISAS_PRINFO(NULL, 0, "<jump alternative.%x> default", alt_id);
+ DISAS_PRINSN(dctx, insn, 1);
+
+ alt_insn = insn->alts->insn;
+ if (!alt_insn) {
+ WARN_INSN(insn, "no jump alternative");
+ return;
+ }
+
+ DISAS_PRINFO(NULL, 0, "<jump alternative.%x> else", alt_id);
+
+ if (insn->type == INSN_NOP) {
+ DISAS_PRINFO(insn, 1, "jmp %lx <%s+0x%lx>",
+ alt_insn->offset, func->name,
+ alt_insn->offset - func->offset);
+ } else {
+ DISAS_PRINFO(insn, 1, "nop%d", insn->len);
+ }
+
+ DISAS_PRINFO(NULL, 0, "<jump alternative.%x> end", alt_id);
+
+ if (insn->alts->next)
+ WARN_INSN(insn, "more than one jump alternatives\n");
+}
+
/*
* Disassemble a function.
*/
static void disas_func(struct disas_context *dctx, struct symbol *func)
{
+ struct instruction *alt = NULL;
struct instruction *insn;
- size_t addr;
+ int alt_id = 0;
+ int depth = 0;
printf("%s:\n", func->name);
sym_for_each_insn(dctx->file, func, insn) {
- addr = insn->offset;
- disas_insn(dctx, insn);
- printf(" %6lx: %s+0x%-6lx %s\n",
- addr, func->name, addr - func->offset,
- disas_result(dctx));
+
+ if (insn->alts) {
+ if (alt) {
+ DISAS_PRINFO(insn, 0,
+ "alt default: ignore nested alternative (not supported)");
+ } else if (insn->alt_group) {
+ alt = insn;
+ alt_id = alt->offset;
+ DISAS_PRINFO(NULL, 0,
+ "<alternative.%x> default - begin", alt_id);
+ depth = 1;
+ } else {
+ disas_jump_alt(dctx, insn);
+ continue;
+ }
+ }
+
+ DISAS_PRINSN(dctx, insn, depth);
+
+ if (alt && (alt->alt_group->last_insn == insn ||
+ alt->alt_group->nop == insn)) {
+ DISAS_PRINFO(NULL, 0,
+ "<alternative.%x> default - end", alt_id);
+ disas_group_alt(dctx, alt);
+ alt = NULL;
+ depth = 0;
+ }
}
printf("\n");
}
diff --git a/tools/objtool/include/objtool/check.h b/tools/objtool/include/objtool/check.h
index e5f97acb6252..748ee7631021 100644
--- a/tools/objtool/include/objtool/check.h
+++ b/tools/objtool/include/objtool/check.h
@@ -38,6 +38,11 @@ struct alt_group {
bool ignore;
};
+struct alternative {
+ struct alternative *next;
+ struct instruction *insn;
+};
+
#define INSN_CHUNK_BITS 8
#define INSN_CHUNK_SIZE (1 << INSN_CHUNK_BITS)
#define INSN_CHUNK_MAX (INSN_CHUNK_SIZE - 1)
@@ -135,6 +140,9 @@ struct instruction *next_insn_same_sec(struct objtool_file *file, struct instruc
insn && insn->sec == _sec; \
insn = next_insn_same_sec(file, insn))
+#define sec_for_each_insn_from(file, insn) \
+ for (; insn; insn = next_insn_same_sec(file, insn))
+
#define sym_for_each_insn(file, sym, insn) \
for (insn = find_insn(file, sym->sec, sym->offset); \
insn && insn->offset < sym->offset + sym->len; \
--
2.43.5
next prev parent reply other threads:[~2025-06-19 14:57 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-19 14:56 [RFC PATCH v2 00/17] objtool: Function validation tracing Alexandre Chartre
2025-06-19 14:56 ` [RFC PATCH v2 01/17] objtool: Move disassembly functions to a separated file Alexandre Chartre
2025-06-19 14:56 ` [RFC PATCH v2 02/17] objtool: Create disassembly context Alexandre Chartre
2025-09-23 22:23 ` Josh Poimboeuf
2025-06-19 14:56 ` [RFC PATCH v2 03/17] objtool: Disassemble code with libopcodes instead of running objdump Alexandre Chartre
2025-06-19 14:56 ` [RFC PATCH v2 04/17] tool build: Remove annoying newline in build output Alexandre Chartre
2025-06-19 14:56 ` [RFC PATCH v2 05/17] objtool: Print symbol during disassembly Alexandre Chartre
2025-06-19 14:56 ` [RFC PATCH v2 06/17] objtool: Improve offstr() output Alexandre Chartre
2025-09-23 22:23 ` Josh Poimboeuf
2025-06-19 14:56 ` [RFC PATCH v2 07/17] objtool: Store instruction disassembly result Alexandre Chartre
2025-06-19 14:56 ` [RFC PATCH v2 08/17] objtool: Disassemble instruction on warning or backtrace Alexandre Chartre
2025-06-19 14:56 ` [RFC PATCH v2 09/17] objtool: Extract code to validate instruction from the validate branch loop Alexandre Chartre
2025-06-19 14:56 ` [RFC PATCH v2 10/17] objtool: Record symbol name max length Alexandre Chartre
2025-06-19 14:56 ` [RFC PATCH v2 11/17] objtool: Add option to trace function validation Alexandre Chartre
2025-09-23 22:25 ` Josh Poimboeuf
2025-06-19 14:56 ` [RFC PATCH v2 12/17] objtool: Trace instruction state changes during " Alexandre Chartre
2025-06-19 14:56 ` [RFC PATCH v2 13/17] objtool: Improve register reporting " Alexandre Chartre
2025-06-19 14:56 ` [RFC PATCH v2 14/17] objtool: Improve tracing of alternative instructions Alexandre Chartre
2025-06-19 14:56 ` [RFC PATCH v2 15/17] objtool: Do not validate IBT for .return_sites and .call_sites Alexandre Chartre
2025-06-19 14:56 ` [RFC PATCH v2 16/17] objtool: Add the --disas=<function-pattern> action Alexandre Chartre
2025-06-19 14:56 ` Alexandre Chartre [this message]
2025-09-23 22:33 ` [RFC PATCH v2 00/17] objtool: Function validation tracing Josh Poimboeuf
2025-09-24 9:25 ` Alexandre Chartre
2025-09-24 7:36 ` Peter Zijlstra
2025-09-24 7:42 ` Peter Zijlstra
2025-09-24 10:08 ` Peter Zijlstra
2025-09-24 10:10 ` Peter Zijlstra
2025-09-24 10:52 ` Alexandre Chartre
2025-09-24 10:58 ` Peter Zijlstra
2025-09-24 11:45 ` Peter Zijlstra
2025-09-24 11:57 ` Alexandre Chartre
2025-09-24 9:17 ` Peter Zijlstra
2025-09-24 9:50 ` Alexandre Chartre
2025-09-24 9:57 ` Peter Zijlstra
2025-09-24 9:37 ` Alexandre Chartre
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250619145659.1377970-18-alexandre.chartre@oracle.com \
--to=alexandre.chartre@oracle.com \
--cc=jpoimboe@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@kernel.org \
--cc=peterz@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®