Skip to content

Commit 350c7ab

Browse files
achartrePeter Zijlstra
authored andcommitted
objtool: Improve tracing of alternative instructions
When tracing function validation, improve the reporting of alternative instruction by more clearly showing the different alternatives beginning and end. 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-16-alexandre.chartre@oracle.com
1 parent 9b580ac commit 350c7ab

3 files changed

Lines changed: 125 additions & 13 deletions

File tree

tools/objtool/check.c

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3564,7 +3564,7 @@ static bool skip_alt_group(struct instruction *insn)
35643564

35653565
/* ANNOTATE_IGNORE_ALTERNATIVE */
35663566
if (insn->alt_group->ignore) {
3567-
TRACE_INSN(insn, "alt group ignored");
3567+
TRACE_ALT(insn, "alt group ignored");
35683568
return true;
35693569
}
35703570

@@ -3680,8 +3680,9 @@ static int validate_insn(struct objtool_file *file, struct symbol *func,
36803680
struct instruction *prev_insn, struct instruction *next_insn,
36813681
bool *dead_end)
36823682
{
3683-
/* prev_state is not used if there is no disassembly support */
3683+
/* prev_state and alt_name are not used if there is no disassembly support */
36843684
struct insn_state prev_state __maybe_unused;
3685+
char *alt_name __maybe_unused = NULL;
36853686
struct alternative *alt;
36863687
u8 visited;
36873688
int ret;
@@ -3768,23 +3769,16 @@ static int validate_insn(struct objtool_file *file, struct symbol *func,
37683769
return 1;
37693770

37703771
if (insn->alts) {
3771-
int i, num_alts;
3772-
3773-
num_alts = 0;
3774-
for (alt = insn->alts; alt; alt = alt->next)
3775-
num_alts++;
3776-
3777-
i = 1;
37783772
for (alt = insn->alts; alt; alt = alt->next) {
3779-
TRACE_INSN(insn, "alternative %d/%d", i, num_alts);
3773+
TRACE_ALT_BEGIN(insn, alt, alt_name);
37803774
ret = validate_branch(file, func, alt->insn, *statep);
3775+
TRACE_ALT_END(insn, alt, alt_name);
37813776
if (ret) {
37823777
BT_INSN(insn, "(alt)");
37833778
return ret;
37843779
}
3785-
i++;
37863780
}
3787-
TRACE_INSN(insn, "alternative DEFAULT");
3781+
TRACE_ALT_INFO_NOADDR(insn, "/ ", "DEFAULT");
37883782
}
37893783

37903784
if (skip_alt_group(insn))

tools/objtool/include/objtool/trace.h

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,26 @@ extern int trace_depth;
1919
fprintf(stderr, fmt, ##__VA_ARGS__); \
2020
})
2121

22+
/*
23+
* Print the instruction address and a message. The instruction
24+
* itself is not printed.
25+
*/
26+
#define TRACE_ADDR(insn, fmt, ...) \
27+
({ \
28+
if (trace) { \
29+
disas_print_info(stderr, insn, trace_depth - 1, \
30+
fmt "\n", ##__VA_ARGS__); \
31+
} \
32+
})
33+
34+
/*
35+
* Print the instruction address, the instruction and a message.
36+
*/
2237
#define TRACE_INSN(insn, fmt, ...) \
2338
({ \
2439
if (trace) { \
2540
disas_print_insn(stderr, objtool_disas_ctx, \
26-
insn, trace_depth - 1, \
41+
insn, trace_depth - 1, \
2742
fmt, ##__VA_ARGS__); \
2843
fprintf(stderr, "\n"); \
2944
insn->trace = 1; \
@@ -36,6 +51,37 @@ extern int trace_depth;
3651
trace_insn_state(insn, sprev, snext); \
3752
})
3853

54+
#define TRACE_ALT_FMT(pfx, fmt) pfx "<%s.%lx> " fmt
55+
#define TRACE_ALT_ARG(insn) disas_alt_type_name(insn), (insn)->offset
56+
57+
#define TRACE_ALT(insn, fmt, ...) \
58+
TRACE_INSN(insn, TRACE_ALT_FMT("", fmt), \
59+
TRACE_ALT_ARG(insn), ##__VA_ARGS__)
60+
61+
#define TRACE_ALT_INFO(insn, pfx, fmt, ...) \
62+
TRACE_ADDR(insn, TRACE_ALT_FMT(pfx, fmt), \
63+
TRACE_ALT_ARG(insn), ##__VA_ARGS__)
64+
65+
#define TRACE_ALT_INFO_NOADDR(insn, pfx, fmt, ...) \
66+
TRACE_ADDR(NULL, TRACE_ALT_FMT(pfx, fmt), \
67+
TRACE_ALT_ARG(insn), ##__VA_ARGS__)
68+
69+
#define TRACE_ALT_BEGIN(insn, alt, alt_name) \
70+
({ \
71+
if (trace) { \
72+
alt_name = disas_alt_name(alt); \
73+
trace_alt_begin(insn, alt, alt_name); \
74+
} \
75+
})
76+
77+
#define TRACE_ALT_END(insn, alt, alt_name) \
78+
({ \
79+
if (trace) { \
80+
trace_alt_end(insn, alt, alt_name); \
81+
free(alt_name); \
82+
} \
83+
})
84+
3985
static inline void trace_enable(void)
4086
{
4187
trace = true;
@@ -61,17 +107,34 @@ static inline void trace_depth_dec(void)
61107

62108
void trace_insn_state(struct instruction *insn, struct insn_state *sprev,
63109
struct insn_state *snext);
110+
void trace_alt_begin(struct instruction *orig_insn, struct alternative *alt,
111+
char *alt_name);
112+
void trace_alt_end(struct instruction *orig_insn, struct alternative *alt,
113+
char *alt_name);
64114

65115
#else /* DISAS */
66116

67117
#define TRACE(fmt, ...) ({})
118+
#define TRACE_ADDR(insn, fmt, ...) ({})
68119
#define TRACE_INSN(insn, fmt, ...) ({})
69120
#define TRACE_INSN_STATE(insn, sprev, snext) ({})
121+
#define TRACE_ALT(insn, fmt, ...) ({})
122+
#define TRACE_ALT_INFO(insn, fmt, ...) ({})
123+
#define TRACE_ALT_INFO_NOADDR(insn, fmt, ...) ({})
124+
#define TRACE_ALT_BEGIN(insn, alt, alt_name) ({})
125+
#define TRACE_ALT_END(insn, alt, alt_name) ({})
126+
70127

71128
static inline void trace_enable(void) {}
72129
static inline void trace_disable(void) {}
73130
static inline void trace_depth_inc(void) {}
74131
static inline void trace_depth_dec(void) {}
132+
static inline void trace_alt_begin(struct instruction *orig_insn,
133+
struct alternative *alt,
134+
char *alt_name) {};
135+
static inline void trace_alt_end(struct instruction *orig_insn,
136+
struct alternative *alt,
137+
char *alt_name) {};
75138

76139
#endif
77140

tools/objtool/trace.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,58 @@ void trace_insn_state(struct instruction *insn, struct insn_state *sprev,
146146

147147
insn->trace = 1;
148148
}
149+
150+
void trace_alt_begin(struct instruction *orig_insn, struct alternative *alt,
151+
char *alt_name)
152+
{
153+
struct instruction *alt_insn;
154+
char suffix[2];
155+
156+
alt_insn = alt->insn;
157+
158+
if (alt->type == ALT_TYPE_EX_TABLE) {
159+
/*
160+
* When there is an exception table then the instruction
161+
* at the original location is executed but it can cause
162+
* an exception. In that case, the execution will be
163+
* redirected to the alternative instruction.
164+
*
165+
* The instruction at the original location can have
166+
* instruction alternatives, so we just print the location
167+
* of the instruction that can cause the exception and
168+
* not the instruction itself.
169+
*/
170+
TRACE_ALT_INFO_NOADDR(orig_insn, "/ ", "%s for instruction at 0x%lx <%s+0x%lx>",
171+
alt_name,
172+
orig_insn->offset, orig_insn->sym->name,
173+
orig_insn->offset - orig_insn->sym->offset);
174+
} else {
175+
TRACE_ALT_INFO_NOADDR(orig_insn, "/ ", "%s", alt_name);
176+
}
177+
178+
if (alt->type == ALT_TYPE_JUMP_TABLE) {
179+
/*
180+
* For a jump alternative, if the default instruction is
181+
* a NOP then it is replaced with the jmp instruction,
182+
* otherwise it is replaced with a NOP instruction.
183+
*/
184+
trace_depth++;
185+
if (orig_insn->type == INSN_NOP) {
186+
suffix[0] = (orig_insn->len == 5) ? 'q' : '\0';
187+
TRACE_ADDR(orig_insn, "jmp%-3s %lx <%s+0x%lx>", suffix,
188+
alt_insn->offset, alt_insn->sym->name,
189+
alt_insn->offset - alt_insn->sym->offset);
190+
} else {
191+
TRACE_ADDR(orig_insn, "nop%d", orig_insn->len);
192+
trace_depth--;
193+
}
194+
}
195+
}
196+
197+
void trace_alt_end(struct instruction *orig_insn, struct alternative *alt,
198+
char *alt_name)
199+
{
200+
if (alt->type == ALT_TYPE_JUMP_TABLE && orig_insn->type == INSN_NOP)
201+
trace_depth--;
202+
TRACE_ALT_INFO_NOADDR(orig_insn, "\\ ", "%s", alt_name);
203+
}

0 commit comments

Comments
 (0)