]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
LoongArch/ftrace: Add HAVE_FUNCTION_GRAPH_RET_ADDR_PTR support
authorQing Zhang <zhangqing@loongson.cn>
Sat, 10 Dec 2022 14:40:21 +0000 (22:40 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Wed, 14 Dec 2022 00:41:54 +0000 (08:41 +0800)
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: Qing Zhang <zhangqing@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
arch/loongarch/include/asm/ftrace.h
arch/loongarch/include/asm/unwind.h
arch/loongarch/kernel/ftrace_dyn.c
arch/loongarch/kernel/unwind_guess.c
arch/loongarch/kernel/unwind_prologue.c

index ee7feface27a6cee568240356ef0e0302aa2234f..8c7d137e4871bfbda0267af43ccf720b612fd06a 100644 (file)
@@ -6,6 +6,8 @@
 #ifndef _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
 
 #define MCOUNT_INSN_SIZE 4             /* sizeof mcount call */
@@ -24,6 +26,7 @@ struct dyn_ftrace;
 struct dyn_arch_ftrace { };
 
 #define ARCH_SUPPORTS_FTRACE_OPS 1
+#define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
 
 #define ftrace_init_nop ftrace_init_nop
 int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
index a51eec00efb856385cd6339c44ce67045ce8883b..f2b52b9ea93d2862d69e9e7f1075f6e1bcfee619 100644 (file)
@@ -21,6 +21,7 @@ struct unwind_state {
        struct stack_info stack_info;
        struct task_struct *task;
        bool first, error, is_ftrace;
+       int graph_idx;
        unsigned long sp, pc, ra;
 };
 
index 439ba829b9fd9e14ff874a47d13f265a263c48e7..e23c3be29baab0f49ed854a77a867d362f88ea13 100644 (file)
@@ -135,7 +135,7 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent)
 
        old = *parent;
 
-       if (!function_graph_enter(old, self_addr, 0, NULL))
+       if (!function_graph_enter(old, self_addr, 0, parent))
                *parent = return_hooker;
 }
 
index 5afa6064d73e45b4b99524072861fdbc0fc38974..e2d2e4f3001f490a76762ad336fbcf696c4bbfe3 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (C) 2022 Loongson Technology Corporation Limited
  */
 #include <linux/kernel.h>
+#include <linux/ftrace.h>
 
 #include <asm/unwind.h>
 
@@ -53,7 +54,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))
                                return true;
                }
index 46fe344d7fba8d213e977bbcf2b0d7e20504c4d0..0f8d1451ebb848d8a88f8a5c9405903a8d4c93c0 100644 (file)
@@ -2,6 +2,7 @@
 /*
  * Copyright (C) 2022 Loongson Technology Corporation Limited
  */
+#include <linux/ftrace.h>
 #include <linux/kallsyms.h>
 
 #include <asm/inst.h>
@@ -42,6 +43,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))
                        return true;
        }
@@ -174,8 +177,11 @@ bool unwind_next_frame(struct unwind_state *state)
                        break;
 
                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;
+                       }
 
                        if (info->type == STACK_TYPE_IRQ &&
                                info->end == state->sp) {
@@ -185,10 +191,11 @@ bool unwind_next_frame(struct unwind_state *state)
                                if (user_mode(regs) || !__kernel_text_address(pc))
                                        return false;
 
-                               state->pc = pc;
-                               state->sp = regs->regs[3];
-                               state->ra = regs->regs[1];
                                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);
 
                                return true;