![Mark Rutland](/assets/img/avatar_default.png)
We define current_stack_pointer in <asm/thread_info.h>, though other files and header relying upon it do not have this necessary include, and are thus fragile to changes in the header soup. Subsequent patches will affect the header soup such that directly including <asm/thread_info.h> may result in a circular header include in some of these cases, so we can't simply include <asm/thread_info.h>. Instead, factor current_thread_info into its own header, and have all existing users include this explicitly. Signed-off-by: Mark Rutland <mark.rutland@arm.com> Tested-by: Laura Abbott <labbott@redhat.com> Cc: Will Deacon <will.deacon@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
59 lines
1.2 KiB
C
59 lines
1.2 KiB
C
/*
|
|
* arch/arm64/kernel/return_address.c
|
|
*
|
|
* Copyright (C) 2013 Linaro Limited
|
|
* Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
#include <linux/export.h>
|
|
#include <linux/ftrace.h>
|
|
|
|
#include <asm/stack_pointer.h>
|
|
#include <asm/stacktrace.h>
|
|
|
|
struct return_address_data {
|
|
unsigned int level;
|
|
void *addr;
|
|
};
|
|
|
|
static int save_return_addr(struct stackframe *frame, void *d)
|
|
{
|
|
struct return_address_data *data = d;
|
|
|
|
if (!data->level) {
|
|
data->addr = (void *)frame->pc;
|
|
return 1;
|
|
} else {
|
|
--data->level;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void *return_address(unsigned int level)
|
|
{
|
|
struct return_address_data data;
|
|
struct stackframe frame;
|
|
|
|
data.level = level + 2;
|
|
data.addr = NULL;
|
|
|
|
frame.fp = (unsigned long)__builtin_frame_address(0);
|
|
frame.sp = current_stack_pointer;
|
|
frame.pc = (unsigned long)return_address; /* dummy */
|
|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
|
frame.graph = current->curr_ret_stack;
|
|
#endif
|
|
|
|
walk_stackframe(current, &frame, save_return_addr, &data);
|
|
|
|
if (!data.level)
|
|
return data.addr;
|
|
else
|
|
return NULL;
|
|
}
|
|
EXPORT_SYMBOL_GPL(return_address);
|