Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only 2 : : /* 3 : : * arch/arm/kernel/return_address.c 4 : : * 5 : : * Copyright (C) 2009 Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> 6 : : * for Pengutronix 7 : : */ 8 : : #include <linux/export.h> 9 : : #include <linux/ftrace.h> 10 : : 11 : : #if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) 12 : : #include <linux/sched.h> 13 : : 14 : : #include <asm/stacktrace.h> 15 : : 16 : : struct return_address_data { 17 : : unsigned int level; 18 : : void *addr; 19 : : }; 20 : : 21 : 3 : static int save_return_addr(struct stackframe *frame, void *d) 22 : : { 23 : : struct return_address_data *data = d; 24 : : 25 : 3 : if (!data->level) { 26 : 3 : data->addr = (void *)frame->pc; 27 : : 28 : 3 : return 1; 29 : : } else { 30 : 3 : --data->level; 31 : 3 : return 0; 32 : : } 33 : : } 34 : : 35 : 3 : void *return_address(unsigned int level) 36 : : { 37 : : struct return_address_data data; 38 : : struct stackframe frame; 39 : : 40 : 3 : data.level = level + 2; 41 : 3 : data.addr = NULL; 42 : : 43 : 3 : frame.fp = (unsigned long)__builtin_frame_address(0); 44 : 3 : frame.sp = current_stack_pointer; 45 : 3 : frame.lr = (unsigned long)__builtin_return_address(0); 46 : 3 : frame.pc = (unsigned long)return_address; 47 : : 48 : 3 : walk_stackframe(&frame, save_return_addr, &data); 49 : : 50 : 3 : if (!data.level) 51 : 3 : return data.addr; 52 : : else 53 : : return NULL; 54 : : } 55 : : 56 : : #endif /* if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) */ 57 : : 58 : : EXPORT_SYMBOL_GPL(return_address);