Commit a51ac524 authored by Qing Zhang's avatar Qing Zhang Committed by Huacai Chen

LoongArch/ftrace: Add HAVE_FUNCTION_GRAPH_RET_ADDR_PTR support

ftrace_graph_ret_addr() can be called by stack unwinding code to convert
a found stack return address ('ret') to its original value, in case the
function graph tracer has modified it to be 'return_to_handler'. If the
hasn't been modified, the unchanged value of 'ret' is returned.
Signed-off-by: default avatarQing Zhang <zhangqing@loongson.cn>
Signed-off-by: default avatarHuacai Chen <chenhuacai@loongson.cn>
parent ac7127e1
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#ifndef _ASM_LOONGARCH_FTRACE_H #ifndef _ASM_LOONGARCH_FTRACE_H
#define _ASM_LOONGARCH_FTRACE_H #define _ASM_LOONGARCH_FTRACE_H
#define GRAPH_FAKE_OFFSET (sizeof(struct pt_regs) - offsetof(struct pt_regs, regs[1]))
#ifdef CONFIG_FUNCTION_TRACER #ifdef CONFIG_FUNCTION_TRACER
#define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */ #define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */
...@@ -24,6 +26,7 @@ struct dyn_ftrace; ...@@ -24,6 +26,7 @@ struct dyn_ftrace;
struct dyn_arch_ftrace { }; struct dyn_arch_ftrace { };
#define ARCH_SUPPORTS_FTRACE_OPS 1 #define ARCH_SUPPORTS_FTRACE_OPS 1
#define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
#define ftrace_init_nop ftrace_init_nop #define ftrace_init_nop ftrace_init_nop
int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec); int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
......
...@@ -21,6 +21,7 @@ struct unwind_state { ...@@ -21,6 +21,7 @@ struct unwind_state {
struct stack_info stack_info; struct stack_info stack_info;
struct task_struct *task; struct task_struct *task;
bool first, error, is_ftrace; bool first, error, is_ftrace;
int graph_idx;
unsigned long sp, pc, ra; unsigned long sp, pc, ra;
}; };
......
...@@ -135,7 +135,7 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent) ...@@ -135,7 +135,7 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent)
old = *parent; old = *parent;
if (!function_graph_enter(old, self_addr, 0, NULL)) if (!function_graph_enter(old, self_addr, 0, parent))
*parent = return_hooker; *parent = return_hooker;
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* Copyright (C) 2022 Loongson Technology Corporation Limited * Copyright (C) 2022 Loongson Technology Corporation Limited
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/ftrace.h>
#include <asm/unwind.h> #include <asm/unwind.h>
...@@ -53,7 +54,8 @@ bool unwind_next_frame(struct unwind_state *state) ...@@ -53,7 +54,8 @@ bool unwind_next_frame(struct unwind_state *state)
state->sp < info->end; state->sp < info->end;
state->sp += sizeof(unsigned long)) { state->sp += sizeof(unsigned long)) {
addr = *(unsigned long *)(state->sp); 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)) if (__kernel_text_address(addr))
return true; return true;
} }
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
/* /*
* Copyright (C) 2022 Loongson Technology Corporation Limited * Copyright (C) 2022 Loongson Technology Corporation Limited
*/ */
#include <linux/ftrace.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <asm/inst.h> #include <asm/inst.h>
...@@ -42,6 +43,8 @@ static bool unwind_by_guess(struct unwind_state *state) ...@@ -42,6 +43,8 @@ static bool unwind_by_guess(struct unwind_state *state)
state->sp < info->end; state->sp < info->end;
state->sp += sizeof(unsigned long)) { state->sp += sizeof(unsigned long)) {
addr = *(unsigned long *)(state->sp); 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)) if (__kernel_text_address(addr))
return true; return true;
} }
...@@ -174,8 +177,11 @@ bool unwind_next_frame(struct unwind_state *state) ...@@ -174,8 +177,11 @@ bool unwind_next_frame(struct unwind_state *state)
break; break;
case UNWINDER_PROLOGUE: case UNWINDER_PROLOGUE:
if (unwind_by_prologue(state)) 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));
return true; return true;
}
if (info->type == STACK_TYPE_IRQ && if (info->type == STACK_TYPE_IRQ &&
info->end == state->sp) { info->end == state->sp) {
...@@ -185,10 +191,11 @@ bool unwind_next_frame(struct unwind_state *state) ...@@ -185,10 +191,11 @@ bool unwind_next_frame(struct unwind_state *state)
if (user_mode(regs) || !__kernel_text_address(pc)) if (user_mode(regs) || !__kernel_text_address(pc))
return false; return false;
state->pc = pc;
state->sp = regs->regs[3];
state->ra = regs->regs[1];
state->first = true; 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));
get_stack_info(state->sp, state->task, info); get_stack_info(state->sp, state->task, info);
return true; return true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment