Skip to content

Commit f05a4a4

Browse files
mrutland-armctmarinas
authored andcommitted
arm64: stacktrace: split unwind_consume_stack()
When unwinding stacks, we use unwind_consume_stack() to both find whether an object (e.g. a frame record) is on an accessible stack *and* to update the stack boundaries. This works fine today since we only care about one type of object which does not overlap other objects. In subsequent patches we'll want to check whether an object (e.g a frame record) is on the stack and follow this up by accessing a larger object containing the first (e.g. a pt_regs with an embedded frame record). To make that pattern easier to implement, this patch reworks unwind_find_next_stack() and unwind_consume_stack() so that the former can be used to check if an object is on any accessible stack, and the latter is purely used to update the stack boundaries. As unwind_find_next_stack() is modified to also check the stack currently being unwound, it is renamed to unwind_find_stack(). There should be no functional change as a result of this patch. Signed-off-by: Mark Rutland <mark.rutland@arm.com> Reviewed-by: Mark Brown <broonie@kernel.org> Reviewed-by: Miroslav Benes <mbenes@suse.cz> Reviewed-by: Puranjay Mohan <puranjay12@gmail.com> Cc: Ard Biesheuvel <ardb@kernel.org> Cc: Josh Poimboeuf <jpoimboe@kernel.org> Cc: Kalesh Singh <kaleshsingh@google.com> Cc: Madhavan T. Venkataraman <madvenka@linux.microsoft.com> Cc: Marc Zyngier <maz@kernel.org> Cc: Will Deacon <will@kernel.org> Link: https://lore.kernel.org/r/20241017092538.1859841-10-mark.rutland@arm.com Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
1 parent 8094df1 commit f05a4a4

File tree

1 file changed

+39
-29
lines changed
  • arch/arm64/include/asm/stacktrace

1 file changed

+39
-29
lines changed

arch/arm64/include/asm/stacktrace/common.h

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,27 @@ static inline void unwind_init_common(struct unwind_state *state)
6060
state->stack = stackinfo_get_unknown();
6161
}
6262

63-
static struct stack_info *unwind_find_next_stack(const struct unwind_state *state,
64-
unsigned long sp,
65-
unsigned long size)
63+
/**
64+
* unwind_find_stack() - Find the accessible stack which entirely contains an
65+
* object.
66+
*
67+
* @state: the current unwind state.
68+
* @sp: the base address of the object.
69+
* @size: the size of the object.
70+
*
71+
* Return: a pointer to the relevant stack_info if found; NULL otherwise.
72+
*/
73+
static struct stack_info *unwind_find_stack(struct unwind_state *state,
74+
unsigned long sp,
75+
unsigned long size)
6676
{
67-
for (int i = 0; i < state->nr_stacks; i++) {
68-
struct stack_info *info = &state->stacks[i];
77+
struct stack_info *info = &state->stack;
6978

79+
if (stackinfo_on_stack(info, sp, size))
80+
return info;
81+
82+
for (int i = 0; i < state->nr_stacks; i++) {
83+
info = &state->stacks[i];
7084
if (stackinfo_on_stack(info, sp, size))
7185
return info;
7286
}
@@ -75,36 +89,31 @@ static struct stack_info *unwind_find_next_stack(const struct unwind_state *stat
7589
}
7690

7791
/**
78-
* unwind_consume_stack() - Check if an object is on an accessible stack,
79-
* updating stack boundaries so that future unwind steps cannot consume this
80-
* object again.
92+
* unwind_consume_stack() - Update stack boundaries so that future unwind steps
93+
* cannot consume this object again.
8194
*
8295
* @state: the current unwind state.
96+
* @info: the stack_info of the stack containing the object.
8397
* @sp: the base address of the object.
8498
* @size: the size of the object.
8599
*
86100
* Return: 0 upon success, an error code otherwise.
87101
*/
88-
static inline int unwind_consume_stack(struct unwind_state *state,
89-
unsigned long sp,
90-
unsigned long size)
102+
static inline void unwind_consume_stack(struct unwind_state *state,
103+
struct stack_info *info,
104+
unsigned long sp,
105+
unsigned long size)
91106
{
92-
struct stack_info *next;
93-
94-
if (stackinfo_on_stack(&state->stack, sp, size))
95-
goto found;
96-
97-
next = unwind_find_next_stack(state, sp, size);
98-
if (!next)
99-
return -EINVAL;
107+
struct stack_info tmp;
100108

101109
/*
102110
* Stack transitions are strictly one-way, and once we've
103111
* transitioned from one stack to another, it's never valid to
104112
* unwind back to the old stack.
105113
*
106-
* Remove the current stack from the list of stacks so that it cannot
107-
* be found on a subsequent transition.
114+
* Destroy the old stack info so that it cannot be found upon a
115+
* subsequent transition. If the stack has not changed, we'll
116+
* immediately restore the current stack info.
108117
*
109118
* Note that stacks can nest in several valid orders, e.g.
110119
*
@@ -115,16 +124,15 @@ static inline int unwind_consume_stack(struct unwind_state *state,
115124
* ... so we do not check the specific order of stack
116125
* transitions.
117126
*/
118-
state->stack = *next;
119-
*next = stackinfo_get_unknown();
127+
tmp = *info;
128+
*info = stackinfo_get_unknown();
129+
state->stack = tmp;
120130

121-
found:
122131
/*
123132
* Future unwind steps can only consume stack above this frame record.
124133
* Update the current stack to start immediately above it.
125134
*/
126135
state->stack.low = sp + size;
127-
return 0;
128136
}
129137

130138
/**
@@ -137,16 +145,18 @@ static inline int unwind_consume_stack(struct unwind_state *state,
137145
static inline int
138146
unwind_next_frame_record(struct unwind_state *state)
139147
{
148+
struct stack_info *info;
140149
struct frame_record *record;
141150
unsigned long fp = state->fp;
142-
int err;
143151

144152
if (fp & 0x7)
145153
return -EINVAL;
146154

147-
err = unwind_consume_stack(state, fp, sizeof(*record));
148-
if (err)
149-
return err;
155+
info = unwind_find_stack(state, fp, sizeof(*record));
156+
if (!info)
157+
return -EINVAL;
158+
159+
unwind_consume_stack(state, info, fp, sizeof(*record));
150160

151161
/*
152162
* Record this frame record's values.

0 commit comments

Comments
 (0)