riscv: add CALLER_ADDRx support
CALLER_ADDRx returns caller's address at specified level, they are used
for several tracers. These macros eventually use
__builtin_return_address(n) to get the caller's address if arch doesn't
define their own implementation.
In RISC-V, __builtin_return_address(n) only works when n == 0, we need
to walk the stack frame to get the caller's address at specified level.
data.level started from 'level + 3' due to the call flow of getting
caller's address in RISC-V implementation. If we don't have additional
three iteration, the level is corresponding to follows:
callsite -> return_address -> arch_stack_walk -> walk_stackframe
| | | |
level 3 level 2 level 1 level 0
Fixes: 10626c32e3
("riscv/ftrace: Add basic support")
Cc: stable@vger.kernel.org
Reviewed-by: Alexandre Ghiti <alexghiti@rivosinc.com>
Signed-off-by: Zong Li <zong.li@sifive.com>
Link: https://lore.kernel.org/r/20240202015102.26251-1-zong.li@sifive.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
This commit is contained in:
parent
4af24146aa
commit
680341382d
@ -25,6 +25,11 @@
|
|||||||
|
|
||||||
#define ARCH_SUPPORTS_FTRACE_OPS 1
|
#define ARCH_SUPPORTS_FTRACE_OPS 1
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
|
extern void *return_address(unsigned int level);
|
||||||
|
|
||||||
|
#define ftrace_return_address(n) return_address(n)
|
||||||
|
|
||||||
void MCOUNT_NAME(void);
|
void MCOUNT_NAME(void);
|
||||||
static inline unsigned long ftrace_call_adjust(unsigned long addr)
|
static inline unsigned long ftrace_call_adjust(unsigned long addr)
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,7 @@ ifdef CONFIG_FTRACE
|
|||||||
CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
|
CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
|
||||||
CFLAGS_REMOVE_patch.o = $(CC_FLAGS_FTRACE)
|
CFLAGS_REMOVE_patch.o = $(CC_FLAGS_FTRACE)
|
||||||
CFLAGS_REMOVE_sbi.o = $(CC_FLAGS_FTRACE)
|
CFLAGS_REMOVE_sbi.o = $(CC_FLAGS_FTRACE)
|
||||||
|
CFLAGS_REMOVE_return_address.o = $(CC_FLAGS_FTRACE)
|
||||||
endif
|
endif
|
||||||
CFLAGS_syscall_table.o += $(call cc-option,-Wno-override-init,)
|
CFLAGS_syscall_table.o += $(call cc-option,-Wno-override-init,)
|
||||||
CFLAGS_compat_syscall_table.o += $(call cc-option,-Wno-override-init,)
|
CFLAGS_compat_syscall_table.o += $(call cc-option,-Wno-override-init,)
|
||||||
@ -46,6 +47,7 @@ obj-y += irq.o
|
|||||||
obj-y += process.o
|
obj-y += process.o
|
||||||
obj-y += ptrace.o
|
obj-y += ptrace.o
|
||||||
obj-y += reset.o
|
obj-y += reset.o
|
||||||
|
obj-y += return_address.o
|
||||||
obj-y += setup.o
|
obj-y += setup.o
|
||||||
obj-y += signal.o
|
obj-y += signal.o
|
||||||
obj-y += syscall_table.o
|
obj-y += syscall_table.o
|
||||||
|
48
arch/riscv/kernel/return_address.c
Normal file
48
arch/riscv/kernel/return_address.c
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* This code come from arch/arm64/kernel/return_address.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 SiFive.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/export.h>
|
||||||
|
#include <linux/kprobes.h>
|
||||||
|
#include <linux/stacktrace.h>
|
||||||
|
|
||||||
|
struct return_address_data {
|
||||||
|
unsigned int level;
|
||||||
|
void *addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool save_return_addr(void *d, unsigned long pc)
|
||||||
|
{
|
||||||
|
struct return_address_data *data = d;
|
||||||
|
|
||||||
|
if (!data->level) {
|
||||||
|
data->addr = (void *)pc;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
--data->level;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(save_return_addr);
|
||||||
|
|
||||||
|
noinline void *return_address(unsigned int level)
|
||||||
|
{
|
||||||
|
struct return_address_data data;
|
||||||
|
|
||||||
|
data.level = level + 3;
|
||||||
|
data.addr = NULL;
|
||||||
|
|
||||||
|
arch_stack_walk(save_return_addr, &data, current, NULL);
|
||||||
|
|
||||||
|
if (!data.level)
|
||||||
|
return data.addr;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(return_address);
|
||||||
|
NOKPROBE_SYMBOL(return_address);
|
Loading…
Reference in New Issue
Block a user