mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
LoongArch: Use correct sp value to get graph addr in stack unwinders
The stack frame when function_graph enable like follows, --------- <- function sp_on_entry | | | FAKE_RA <- sp_on_entry - sizeof(pt_regs) + PT_R1 | --------- <- sp_on_entry - sizeof(pt_regs) So if we want to get the &FAKE_RA we should get sp_on_entry first. In the unwinder_prologue case, we can get the sp_on_entry as state->sp, because we try to calculate each CFA and the ra saved address. But in the unwinder_guess case, we cannot get it because we do not try to calculate the CFA. Although LoongArch have not fixed frame, the $ra is saved at CFA - 8 in most cases, we can try guess, too. As we store the pc in state, we not need to dereference state->sp, too. Signed-off-by: Jinyang He <hejinyang@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
This commit is contained in:
parent
429a9671f2
commit
5bb8d34449
@ -10,8 +10,6 @@
|
||||
#define FTRACE_REGS_PLT_IDX 1
|
||||
#define NR_FTRACE_PLTS 2
|
||||
|
||||
#define GRAPH_FAKE_OFFSET (sizeof(struct pt_regs) - offsetof(struct pt_regs, regs[1]))
|
||||
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
|
||||
#define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */
|
||||
|
@ -8,7 +8,9 @@
|
||||
#define _ASM_UNWIND_H
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/ftrace.h>
|
||||
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/stacktrace.h>
|
||||
|
||||
enum unwinder_type {
|
||||
@ -40,4 +42,12 @@ static inline bool unwind_error(struct unwind_state *state)
|
||||
return state->error;
|
||||
}
|
||||
|
||||
#define GRAPH_FAKE_OFFSET (sizeof(struct pt_regs) - offsetof(struct pt_regs, regs[1]))
|
||||
|
||||
static inline unsigned long unwind_graph_addr(struct unwind_state *state,
|
||||
unsigned long pc, unsigned long cfa)
|
||||
{
|
||||
return ftrace_graph_ret_addr(state->task, &state->graph_idx,
|
||||
pc, (unsigned long *)(cfa - GRAPH_FAKE_OFFSET));
|
||||
}
|
||||
#endif /* _ASM_UNWIND_H */
|
||||
|
@ -11,10 +11,8 @@ unsigned long unwind_get_return_address(struct unwind_state *state)
|
||||
{
|
||||
if (unwind_done(state))
|
||||
return 0;
|
||||
else if (state->first)
|
||||
return state->pc;
|
||||
|
||||
return *(unsigned long *)(state->sp);
|
||||
return state->pc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unwind_get_return_address);
|
||||
|
||||
@ -36,7 +34,7 @@ void unwind_start(struct unwind_state *state, struct task_struct *task,
|
||||
|
||||
state->task = task;
|
||||
state->first = true;
|
||||
|
||||
state->pc = unwind_graph_addr(state, state->pc, state->sp);
|
||||
get_stack_info(state->sp, state->task, &state->stack_info);
|
||||
|
||||
if (!unwind_done(state) && !__kernel_text_address(state->pc))
|
||||
@ -60,9 +58,8 @@ bool unwind_next_frame(struct unwind_state *state)
|
||||
state->sp < info->end;
|
||||
state->sp += sizeof(unsigned long)) {
|
||||
addr = *(unsigned long *)(state->sp);
|
||||
state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
|
||||
addr, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET));
|
||||
if (__kernel_text_address(addr))
|
||||
state->pc = unwind_graph_addr(state, addr, state->sp + 8);
|
||||
if (__kernel_text_address(state->pc))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -21,16 +21,10 @@ static inline void unwind_state_fixup(struct unwind_state *state)
|
||||
|
||||
unsigned long unwind_get_return_address(struct unwind_state *state)
|
||||
{
|
||||
|
||||
if (unwind_done(state))
|
||||
return 0;
|
||||
else if (state->type)
|
||||
return state->pc;
|
||||
else if (state->first)
|
||||
return state->pc;
|
||||
|
||||
return *(unsigned long *)(state->sp);
|
||||
|
||||
return state->pc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unwind_get_return_address);
|
||||
|
||||
@ -43,9 +37,8 @@ static bool unwind_by_guess(struct unwind_state *state)
|
||||
state->sp < info->end;
|
||||
state->sp += sizeof(unsigned long)) {
|
||||
addr = *(unsigned long *)(state->sp);
|
||||
state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
|
||||
addr, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET));
|
||||
if (__kernel_text_address(addr))
|
||||
state->pc = unwind_graph_addr(state, addr, state->sp + 8);
|
||||
if (__kernel_text_address(state->pc))
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -166,7 +159,7 @@ void unwind_start(struct unwind_state *state, struct task_struct *task,
|
||||
|
||||
state->task = task;
|
||||
state->first = true;
|
||||
|
||||
state->pc = unwind_graph_addr(state, state->pc, state->sp);
|
||||
get_stack_info(state->sp, state->task, &state->stack_info);
|
||||
|
||||
if (!unwind_done(state) && !__kernel_text_address(state->pc))
|
||||
@ -193,8 +186,7 @@ bool unwind_next_frame(struct unwind_state *state)
|
||||
|
||||
case UNWINDER_PROLOGUE:
|
||||
if (unwind_by_prologue(state)) {
|
||||
state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
|
||||
state->pc, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET));
|
||||
state->pc = unwind_graph_addr(state, state->pc, state->sp);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -209,8 +201,7 @@ bool unwind_next_frame(struct unwind_state *state)
|
||||
state->first = true;
|
||||
state->ra = regs->regs[1];
|
||||
state->sp = regs->regs[3];
|
||||
state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
|
||||
pc, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET));
|
||||
state->pc = pc;
|
||||
get_stack_info(state->sp, state->task, info);
|
||||
|
||||
return true;
|
||||
|
Loading…
Reference in New Issue
Block a user