Skip to content

Commit cb20311

Browse files
committed
Merge branch 'for-next/stacktrace' into for-next/core
* for-next/stacktrace: arm64: Copy the task argument to unwind_state arm64: Split unwind_init() arm64: stacktrace: use non-atomic __set_bit arm64: kasan: do not instrument stacktrace.c
2 parents 0f05dad + 82a592c commit cb20311

File tree

2 files changed

+80
-24
lines changed

2 files changed

+80
-24
lines changed

arch/arm64/kernel/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ CFLAGS_REMOVE_return_address.o = $(CC_FLAGS_FTRACE)
1414
CFLAGS_REMOVE_syscall.o = -fstack-protector -fstack-protector-strong
1515
CFLAGS_syscall.o += -fno-stack-protector
1616

17+
# When KASAN is enabled, a stack trace is recorded for every alloc/free, which
18+
# can significantly impact performance. Avoid instrumenting the stack trace
19+
# collection code to minimize this impact.
20+
KASAN_SANITIZE_stacktrace.o := n
21+
1722
# It's not safe to invoke KCOV when portions of the kernel environment aren't
1823
# available or are out-of-sync with HW state. Since `noinstr` doesn't always
1924
# inhibit KCOV instrumentation, disable it for the entire compilation unit.

arch/arm64/kernel/stacktrace.c

Lines changed: 75 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
* @kr_cur: When KRETPROBES is selected, holds the kretprobe instance
3939
* associated with the most recently encountered replacement lr
4040
* value.
41+
*
42+
* @task: The task being unwound.
4143
*/
4244
struct unwind_state {
4345
unsigned long fp;
@@ -48,13 +50,13 @@ struct unwind_state {
4850
#ifdef CONFIG_KRETPROBES
4951
struct llist_node *kr_cur;
5052
#endif
53+
struct task_struct *task;
5154
};
5255

53-
static notrace void unwind_init(struct unwind_state *state, unsigned long fp,
54-
unsigned long pc)
56+
static void unwind_init_common(struct unwind_state *state,
57+
struct task_struct *task)
5558
{
56-
state->fp = fp;
57-
state->pc = pc;
59+
state->task = task;
5860
#ifdef CONFIG_KRETPROBES
5961
state->kr_cur = NULL;
6062
#endif
@@ -72,7 +74,57 @@ static notrace void unwind_init(struct unwind_state *state, unsigned long fp,
7274
state->prev_fp = 0;
7375
state->prev_type = STACK_TYPE_UNKNOWN;
7476
}
75-
NOKPROBE_SYMBOL(unwind_init);
77+
78+
/*
79+
* Start an unwind from a pt_regs.
80+
*
81+
* The unwind will begin at the PC within the regs.
82+
*
83+
* The regs must be on a stack currently owned by the calling task.
84+
*/
85+
static inline void unwind_init_from_regs(struct unwind_state *state,
86+
struct pt_regs *regs)
87+
{
88+
unwind_init_common(state, current);
89+
90+
state->fp = regs->regs[29];
91+
state->pc = regs->pc;
92+
}
93+
94+
/*
95+
* Start an unwind from a caller.
96+
*
97+
* The unwind will begin at the caller of whichever function this is inlined
98+
* into.
99+
*
100+
* The function which invokes this must be noinline.
101+
*/
102+
static __always_inline void unwind_init_from_caller(struct unwind_state *state)
103+
{
104+
unwind_init_common(state, current);
105+
106+
state->fp = (unsigned long)__builtin_frame_address(1);
107+
state->pc = (unsigned long)__builtin_return_address(0);
108+
}
109+
110+
/*
111+
* Start an unwind from a blocked task.
112+
*
113+
* The unwind will begin at the blocked tasks saved PC (i.e. the caller of
114+
* cpu_switch_to()).
115+
*
116+
* The caller should ensure the task is blocked in cpu_switch_to() for the
117+
* duration of the unwind, or the unwind will be bogus. It is never valid to
118+
* call this for the current task.
119+
*/
120+
static inline void unwind_init_from_task(struct unwind_state *state,
121+
struct task_struct *task)
122+
{
123+
unwind_init_common(state, task);
124+
125+
state->fp = thread_saved_fp(task);
126+
state->pc = thread_saved_pc(task);
127+
}
76128

77129
/*
78130
* Unwind from one frame record (A) to the next frame record (B).
@@ -81,9 +133,9 @@ NOKPROBE_SYMBOL(unwind_init);
81133
* records (e.g. a cycle), determined based on the location and fp value of A
82134
* and the location (but not the fp value) of B.
83135
*/
84-
static int notrace unwind_next(struct task_struct *tsk,
85-
struct unwind_state *state)
136+
static int notrace unwind_next(struct unwind_state *state)
86137
{
138+
struct task_struct *tsk = state->task;
87139
unsigned long fp = state->fp;
88140
struct stack_info info;
89141

@@ -117,15 +169,15 @@ static int notrace unwind_next(struct task_struct *tsk,
117169
if (fp <= state->prev_fp)
118170
return -EINVAL;
119171
} else {
120-
set_bit(state->prev_type, state->stacks_done);
172+
__set_bit(state->prev_type, state->stacks_done);
121173
}
122174

123175
/*
124176
* Record this frame record's values and location. The prev_fp and
125177
* prev_type are only meaningful to the next unwind_next() invocation.
126178
*/
127-
state->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp));
128-
state->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 8));
179+
state->fp = READ_ONCE(*(unsigned long *)(fp));
180+
state->pc = READ_ONCE(*(unsigned long *)(fp + 8));
129181
state->prev_fp = fp;
130182
state->prev_type = info.type;
131183

@@ -157,16 +209,15 @@ static int notrace unwind_next(struct task_struct *tsk,
157209
}
158210
NOKPROBE_SYMBOL(unwind_next);
159211

160-
static void notrace unwind(struct task_struct *tsk,
161-
struct unwind_state *state,
212+
static void notrace unwind(struct unwind_state *state,
162213
stack_trace_consume_fn consume_entry, void *cookie)
163214
{
164215
while (1) {
165216
int ret;
166217

167218
if (!consume_entry(cookie, state->pc))
168219
break;
169-
ret = unwind_next(tsk, state);
220+
ret = unwind_next(state);
170221
if (ret < 0)
171222
break;
172223
}
@@ -212,15 +263,15 @@ noinline notrace void arch_stack_walk(stack_trace_consume_fn consume_entry,
212263
{
213264
struct unwind_state state;
214265

215-
if (regs)
216-
unwind_init(&state, regs->regs[29], regs->pc);
217-
else if (task == current)
218-
unwind_init(&state,
219-
(unsigned long)__builtin_frame_address(1),
220-
(unsigned long)__builtin_return_address(0));
221-
else
222-
unwind_init(&state, thread_saved_fp(task),
223-
thread_saved_pc(task));
224-
225-
unwind(task, &state, consume_entry, cookie);
266+
if (regs) {
267+
if (task != current)
268+
return;
269+
unwind_init_from_regs(&state, regs);
270+
} else if (task == current) {
271+
unwind_init_from_caller(&state);
272+
} else {
273+
unwind_init_from_task(&state, task);
274+
}
275+
276+
unwind(&state, consume_entry, cookie);
226277
}

0 commit comments

Comments
 (0)