1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * This code come from arch/arm64/kernel/return_address.c
4 *
5 * Copyright (C) 2023 SiFive.
6 */
7
8#include <linux/export.h>
9#include <linux/kprobes.h>
10#include <linux/stacktrace.h>
11
12struct return_address_data {
13	unsigned int level;
14	void *addr;
15};
16
17static bool save_return_addr(void *d, unsigned long pc)
18{
19	struct return_address_data *data = d;
20
21	if (!data->level) {
22		data->addr = (void *)pc;
23		return false;
24	}
25
26	--data->level;
27
28	return true;
29}
30NOKPROBE_SYMBOL(save_return_addr);
31
32noinline void *return_address(unsigned int level)
33{
34	struct return_address_data data;
35
36	data.level = level + 3;
37	data.addr = NULL;
38
39	arch_stack_walk(save_return_addr, &data, current, NULL);
40
41	if (!data.level)
42		return data.addr;
43	else
44		return NULL;
45
46}
47EXPORT_SYMBOL_GPL(return_address);
48NOKPROBE_SYMBOL(return_address);
49