0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/export.h>
0009 #include <linux/ftrace.h>
0010 #include <linux/sched.h>
0011
0012 #include <asm/stacktrace.h>
0013
0014 struct return_address_data {
0015 unsigned int level;
0016 void *addr;
0017 };
0018
0019 static int save_return_addr(struct stackframe *frame, void *d)
0020 {
0021 struct return_address_data *data = d;
0022
0023 if (!data->level) {
0024 data->addr = (void *)frame->pc;
0025
0026 return 1;
0027 } else {
0028 --data->level;
0029 return 0;
0030 }
0031 }
0032
0033 void *return_address(unsigned int level)
0034 {
0035 struct return_address_data data;
0036 struct stackframe frame;
0037
0038 data.level = level + 2;
0039 data.addr = NULL;
0040
0041 frame.fp = (unsigned long)__builtin_frame_address(0);
0042 frame.sp = current_stack_pointer;
0043 frame.lr = (unsigned long)__builtin_return_address(0);
0044 here:
0045 frame.pc = (unsigned long)&&here;
0046 #ifdef CONFIG_KRETPROBES
0047 frame.kr_cur = NULL;
0048 frame.tsk = current;
0049 #endif
0050
0051 walk_stackframe(&frame, save_return_addr, &data);
0052
0053 if (!data.level)
0054 return data.addr;
0055 else
0056 return NULL;
0057 }
0058
0059 EXPORT_SYMBOL_GPL(return_address);