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 <[email protected]>
7  */
8 
9 #include <linux/export.h>
10 #include <linux/ftrace.h>
11 
12 #include <asm/stack_pointer.h>
13 #include <asm/stacktrace.h>
14 
15 struct return_address_data {
16 	unsigned int level;
17 	void *addr;
18 };
19 
20 static int save_return_addr(struct stackframe *frame, void *d)
21 {
22 	struct return_address_data *data = d;
23 
24 	if (!data->level) {
25 		data->addr = (void *)frame->pc;
26 		return 1;
27 	} else {
28 		--data->level;
29 		return 0;
30 	}
31 }
32 
33 void *return_address(unsigned int level)
34 {
35 	struct return_address_data data;
36 	struct stackframe frame;
37 
38 	data.level = level + 2;
39 	data.addr = NULL;
40 
41 	frame.fp = (unsigned long)__builtin_frame_address(0);
42 	frame.pc = (unsigned long)return_address; /* dummy */
43 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
44 	frame.graph = 0;
45 #endif
46 
47 	walk_stackframe(current, &frame, save_return_addr, &data);
48 
49 	if (!data.level)
50 		return data.addr;
51 	else
52 		return NULL;
53 }
54 EXPORT_SYMBOL_GPL(return_address);
55