From 9b580accac003767a461bf52d738ad1ab4e8ccfa Mon Sep 17 00:00:00 2001 From: Alexandre Chartre Date: Fri, 21 Nov 2025 10:53:24 +0100 Subject: [PATCH] objtool: Add functions to better name alternatives Add the disas_alt_name() and disas_alt_type_name() to provide a name and a type name for an alternative. This will be used to better name alternatives when tracing their execution. Signed-off-by: Alexandre Chartre Signed-off-by: Peter Zijlstra (Intel) Acked-by: Josh Poimboeuf Link: https://patch.msgid.link/20251121095340.464045-15-alexandre.chartre@oracle.com --- tools/objtool/disas.c | 72 +++++++++++++++++++++++++++ tools/objtool/include/objtool/disas.h | 12 +++++ 2 files changed, 84 insertions(+) diff --git a/tools/objtool/disas.c b/tools/objtool/disas.c index 0ca6e6c8559fd..b53be240825da 100644 --- a/tools/objtool/disas.c +++ b/tools/objtool/disas.c @@ -3,6 +3,8 @@ * Copyright (C) 2015-2017 Josh Poimboeuf */ +#define _GNU_SOURCE + #include #include #include @@ -450,6 +452,76 @@ size_t disas_insn(struct disas_context *dctx, struct instruction *insn) return disasm(insn->offset, &dctx->info); } +/* + * Provide a name for the type of alternatives present at the + * specified instruction. + * + * An instruction can have alternatives with different types, for + * example alternative instructions and an exception table. In that + * case the name for the alternative instructions type is used. + * + * Return NULL if the instruction as no alternative. + */ +const char *disas_alt_type_name(struct instruction *insn) +{ + struct alternative *alt; + const char *name; + + name = NULL; + for (alt = insn->alts; alt; alt = alt->next) { + if (alt->type == ALT_TYPE_INSTRUCTIONS) { + name = "alternative"; + break; + } + + switch (alt->type) { + case ALT_TYPE_EX_TABLE: + name = "ex_table"; + break; + case ALT_TYPE_JUMP_TABLE: + name = "jump_table"; + break; + default: + name = "unknown"; + break; + } + } + + return name; +} + +/* + * Provide a name for an alternative. + */ +char *disas_alt_name(struct alternative *alt) +{ + char *str = NULL; + + switch (alt->type) { + + case ALT_TYPE_EX_TABLE: + str = strdup("EXCEPTION"); + break; + + case ALT_TYPE_JUMP_TABLE: + str = strdup("JUMP"); + break; + + case ALT_TYPE_INSTRUCTIONS: + /* + * This is a non-default group alternative. Create a unique + * name using the offset of the first original and alternative + * instructions. + */ + asprintf(&str, "ALTERNATIVE %lx.%lx", + alt->insn->alt_group->orig_group->first_insn->offset, + alt->insn->alt_group->first_insn->offset); + break; + } + + return str; +} + /* * Disassemble a function. */ diff --git a/tools/objtool/include/objtool/disas.h b/tools/objtool/include/objtool/disas.h index 5db75d06f2197..8959d4c455622 100644 --- a/tools/objtool/include/objtool/disas.h +++ b/tools/objtool/include/objtool/disas.h @@ -6,6 +6,7 @@ #ifndef _DISAS_H #define _DISAS_H +struct alternative; struct disas_context; struct disassemble_info; @@ -24,6 +25,8 @@ void disas_print_info(FILE *stream, struct instruction *insn, int depth, void disas_print_insn(FILE *stream, struct disas_context *dctx, struct instruction *insn, int depth, const char *format, ...); +char *disas_alt_name(struct alternative *alt); +const char *disas_alt_type_name(struct instruction *insn); #else /* DISAS */ @@ -61,6 +64,15 @@ static inline void disas_print_info(FILE *stream, struct instruction *insn, static inline void disas_print_insn(FILE *stream, struct disas_context *dctx, struct instruction *insn, int depth, const char *format, ...) {} +static inline char *disas_alt_name(struct alternative *alt) +{ + return NULL; +} + +static inline const char *disas_alt_type_name(struct instruction *insn) +{ + return NULL; +} #endif /* DISAS */ -- 2.47.3