[PATCH] x86/unwind: fix oprofile module link error

From: Josh Poimboeuf
Date: Thu Oct 06 2016 - 01:29:25 EST


When compiling on x86 with CONFIG_OPROFILE=m and CONFIG_FRAME_POINTER=n,
the oprofile module fails to link:

ERROR: ftrace_graph_ret_addr" [arch/x86/oprofile/oprofile.ko] undefined!

The problem was introduced when oprofile was converted to use the new
x86 unwinder. When frame pointers are disabled, the "guess" unwinder's
unwind_get_return_address() is an inline function which calls
ftrace_graph_ret_addr(), which is not exported.

Fix it by converting the "guess" version of unwind_get_return_address()
to an exported out-of-line function, just like its frame pointer
counterpart.

Fixes: ec2ad9ccf12d ("oprofile/x86: Convert x86_backtrace() to use the new unwinder")
Reported-by: Karl Beldan <karl.beldan@xxxxxxxxx>
Signed-off-by: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
---
arch/x86/include/asm/unwind.h | 14 ++------------
arch/x86/kernel/unwind_guess.c | 10 ++++++++++
2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/arch/x86/include/asm/unwind.h b/arch/x86/include/asm/unwind.h
index c4b6d1c..46de9ac 100644
--- a/arch/x86/include/asm/unwind.h
+++ b/arch/x86/include/asm/unwind.h
@@ -23,6 +23,8 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task,

bool unwind_next_frame(struct unwind_state *state);

+unsigned long unwind_get_return_address(struct unwind_state *state);
+
static inline bool unwind_done(struct unwind_state *state)
{
return state->stack_info.type == STACK_TYPE_UNKNOWN;
@@ -48,8 +50,6 @@ unsigned long *unwind_get_return_address_ptr(struct unwind_state *state)
return state->bp + 1;
}

-unsigned long unwind_get_return_address(struct unwind_state *state);
-
#else /* !CONFIG_FRAME_POINTER */

static inline
@@ -58,16 +58,6 @@ unsigned long *unwind_get_return_address_ptr(struct unwind_state *state)
return NULL;
}

-static inline
-unsigned long unwind_get_return_address(struct unwind_state *state)
-{
- if (unwind_done(state))
- return 0;
-
- return ftrace_graph_ret_addr(state->task, &state->graph_idx,
- *state->sp, state->sp);
-}
-
#endif /* CONFIG_FRAME_POINTER */

#endif /* _ASM_X86_UNWIND_H */
diff --git a/arch/x86/kernel/unwind_guess.c b/arch/x86/kernel/unwind_guess.c
index b5a834c..9298993 100644
--- a/arch/x86/kernel/unwind_guess.c
+++ b/arch/x86/kernel/unwind_guess.c
@@ -5,6 +5,16 @@
#include <asm/stacktrace.h>
#include <asm/unwind.h>

+unsigned long unwind_get_return_address(struct unwind_state *state)
+{
+ if (unwind_done(state))
+ return 0;
+
+ return ftrace_graph_ret_addr(state->task, &state->graph_idx,
+ *state->sp, state->sp);
+}
+EXPORT_SYMBOL_GPL(unwind_get_return_address);
+
bool unwind_next_frame(struct unwind_state *state)
{
struct stack_info *info = &state->stack_info;
--
2.7.4