Skip to content

Commit

Permalink
arm64: stacktrace: Convert to ARCH_STACKWALK
Browse files Browse the repository at this point in the history
Historically architectures have had duplicated code in their stack trace
implementations for filtering what gets traced. In order to avoid this
duplication some generic code has been provided using a new interface
arch_stack_walk(), enabled by selecting ARCH_STACKWALK in Kconfig, which
factors all this out into the generic stack trace code. Convert arm64
to use this common infrastructure.

Signed-off-by: Mark Brown <broonie@kernel.org>
Reviewed-by: Miroslav Benes <mbenes@suse.cz>
Link: https://lore.kernel.org/r/20200914153409.25097-4-broonie@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
  • Loading branch information
Mark Brown authored and Will Deacon committed Sep 18, 2020
1 parent baa2cd4 commit 5fc57df
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 69 deletions.
1 change: 1 addition & 0 deletions arch/arm64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ config ARM64
select ARCH_HAS_SETUP_DMA_OPS
select ARCH_HAS_SET_DIRECT_MAP
select ARCH_HAS_SET_MEMORY
select ARCH_STACKWALK
select ARCH_HAS_STRICT_KERNEL_RWX
select ARCH_HAS_STRICT_MODULE_RWX
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
Expand Down
79 changes: 10 additions & 69 deletions arch/arm64/kernel/stacktrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,82 +133,23 @@ void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
NOKPROBE_SYMBOL(walk_stackframe);

#ifdef CONFIG_STACKTRACE
struct stack_trace_data {
struct stack_trace *trace;
unsigned int no_sched_functions;
unsigned int skip;
};

static bool save_trace(void *d, unsigned long addr)
void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
struct task_struct *task, struct pt_regs *regs)
{
struct stack_trace_data *data = d;
struct stack_trace *trace = data->trace;

if (data->no_sched_functions && in_sched_functions(addr))
return false;
if (data->skip) {
data->skip--;
return false;
}

trace->entries[trace->nr_entries++] = addr;

return trace->nr_entries >= trace->max_entries;
}

void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
{
struct stack_trace_data data;
struct stackframe frame;

data.trace = trace;
data.skip = trace->skip;
data.no_sched_functions = 0;

start_backtrace(&frame, regs->regs[29], regs->pc);
walk_stackframe(current, &frame, save_trace, &data);
}
EXPORT_SYMBOL_GPL(save_stack_trace_regs);

static noinline void __save_stack_trace(struct task_struct *tsk,
struct stack_trace *trace, unsigned int nosched)
{
struct stack_trace_data data;
struct stackframe frame;

if (!try_get_task_stack(tsk))
return;

data.trace = trace;
data.skip = trace->skip;
data.no_sched_functions = nosched;

if (tsk != current) {
start_backtrace(&frame, thread_saved_fp(tsk),
thread_saved_pc(tsk));
} else {
/* We don't want this function nor the caller */
data.skip += 2;
if (regs)
start_backtrace(&frame, regs->regs[29], regs->pc);
else if (task == current)
start_backtrace(&frame,
(unsigned long)__builtin_frame_address(0),
(unsigned long)__save_stack_trace);
}

walk_stackframe(tsk, &frame, save_trace, &data);
(unsigned long)arch_stack_walk);
else
start_backtrace(&frame, thread_saved_fp(task),
thread_saved_pc(task));

put_task_stack(tsk);
}

void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
{
__save_stack_trace(tsk, trace, 1);
}
EXPORT_SYMBOL_GPL(save_stack_trace_tsk);

void save_stack_trace(struct stack_trace *trace)
{
__save_stack_trace(current, trace, 0);
walk_stackframe(task, &frame, consume_entry, cookie);
}

EXPORT_SYMBOL_GPL(save_stack_trace);
#endif

0 comments on commit 5fc57df

Please sign in to comment.