Unverified Commit 68034138 authored by Zong Li's avatar Zong Li Committed by Palmer Dabbelt
Browse files

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: 10626c32 ("riscv/ftrace: Add basic support")
Cc: stable@vger.kernel.org
Reviewed-by: default avatarAlexandre Ghiti <alexghiti@rivosinc.com>
Signed-off-by: default avatarZong Li <zong.li@sifive.com>
Link: https://lore.kernel.org/r/20240202015102.26251-1-zong.li@sifive.com


Signed-off-by: default avatarPalmer Dabbelt <palmer@rivosinc.com>
parent 4af24146
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -25,6 +25,11 @@

#define ARCH_SUPPORTS_FTRACE_OPS 1
#ifndef __ASSEMBLY__

extern void *return_address(unsigned int level);

#define ftrace_return_address(n) return_address(n)

void MCOUNT_NAME(void);
static inline unsigned long ftrace_call_adjust(unsigned long addr)
{
+2 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ ifdef CONFIG_FTRACE
CFLAGS_REMOVE_ftrace.o	= $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_patch.o	= $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_sbi.o	= $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_return_address.o	= $(CC_FLAGS_FTRACE)
endif
CFLAGS_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	+= ptrace.o
obj-y	+= reset.o
obj-y	+= return_address.o
obj-y	+= setup.o
obj-y	+= signal.o
obj-y	+= syscall_table.o
+48 −0
Original line number Diff line number Diff line
// 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);