1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * arch/arm64/kernel/return_address.c
4  *
5  * Copyright (C) 2013 Linaro Limited
6  * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
7  */
8 
9 #include <linux/export.h>
10 #include <linux/ftrace.h>
11 #include <linux/kprobes.h>
12 
13 #include <asm/stack_pointer.h>
14 #include <asm/stacktrace.h>
15 
16 struct return_address_data {
17 	unsigned int level;
18 	void *addr;
19 };
20 
21 static int save_return_addr(struct stackframe *frame, void *d)
22 {
23 	struct return_address_data *data = d;
24 
25 	if (!data->level) {
26 		data->addr = (void *)frame->pc;
27 		return 1;
28 	} else {
29 		--data->level;
30 		return 0;
31 	}
32 }
33 NOKPROBE_SYMBOL(save_return_addr);
34 
35 void *return_address(unsigned int level)
36 {
37 	struct return_address_data data;
38 	struct stackframe frame;
39 
40 	data.level = level + 2;
41 	data.addr = NULL;
42 
43 	start_backtrace(&frame,
44 			(unsigned long)__builtin_frame_address(0),
45 			(unsigned long)return_address);
46 	walk_stackframe(current, &frame, save_return_addr, &data);
47 
48 	if (!data.level)
49 		return data.addr;
50 	else
51 		return NULL;
52 }
53 EXPORT_SYMBOL_GPL(return_address);
54 NOKPROBE_SYMBOL(return_address);
55