mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
89 lines
2.1 KiB
89 lines
2.1 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
#include <linux/sched.h> |
|
#include <linux/sched/debug.h> |
|
#include <linux/stacktrace.h> |
|
#include <linux/thread_info.h> |
|
#include <linux/ftrace.h> |
|
#include <linux/export.h> |
|
#include <asm/ptrace.h> |
|
#include <asm/stacktrace.h> |
|
|
|
#include "kstack.h" |
|
|
|
static void __save_stack_trace(struct thread_info *tp, |
|
struct stack_trace *trace, |
|
bool skip_sched) |
|
{ |
|
unsigned long ksp, fp; |
|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER |
|
struct task_struct *t; |
|
int graph = 0; |
|
#endif |
|
|
|
if (tp == current_thread_info()) { |
|
stack_trace_flush(); |
|
__asm__ __volatile__("mov %%fp, %0" : "=r" (ksp)); |
|
} else { |
|
ksp = tp->ksp; |
|
} |
|
|
|
fp = ksp + STACK_BIAS; |
|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER |
|
t = tp->task; |
|
#endif |
|
do { |
|
struct sparc_stackf *sf; |
|
struct pt_regs *regs; |
|
unsigned long pc; |
|
|
|
if (!kstack_valid(tp, fp)) |
|
break; |
|
|
|
sf = (struct sparc_stackf *) fp; |
|
regs = (struct pt_regs *) (sf + 1); |
|
|
|
if (kstack_is_trap_frame(tp, regs)) { |
|
if (!(regs->tstate & TSTATE_PRIV)) |
|
break; |
|
pc = regs->tpc; |
|
fp = regs->u_regs[UREG_I6] + STACK_BIAS; |
|
} else { |
|
pc = sf->callers_pc; |
|
fp = (unsigned long)sf->fp + STACK_BIAS; |
|
} |
|
|
|
if (trace->skip > 0) |
|
trace->skip--; |
|
else if (!skip_sched || !in_sched_functions(pc)) { |
|
trace->entries[trace->nr_entries++] = pc; |
|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER |
|
if ((pc + 8UL) == (unsigned long) &return_to_handler) { |
|
struct ftrace_ret_stack *ret_stack; |
|
ret_stack = ftrace_graph_get_ret_stack(t, |
|
graph); |
|
if (ret_stack) { |
|
pc = ret_stack->ret; |
|
if (trace->nr_entries < |
|
trace->max_entries) |
|
trace->entries[trace->nr_entries++] = pc; |
|
graph++; |
|
} |
|
} |
|
#endif |
|
} |
|
} while (trace->nr_entries < trace->max_entries); |
|
} |
|
|
|
void save_stack_trace(struct stack_trace *trace) |
|
{ |
|
__save_stack_trace(current_thread_info(), trace, false); |
|
} |
|
EXPORT_SYMBOL_GPL(save_stack_trace); |
|
|
|
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) |
|
{ |
|
struct thread_info *tp = task_thread_info(tsk); |
|
|
|
__save_stack_trace(tp, trace, true); |
|
} |
|
EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
|
|
|