Commit f6dedecc authored by Jiri Olsa's avatar Jiri Olsa Committed by Robert Richter

oprofile, x86: Adding backtrace dump for 32bit process in compat mode

This patch implements the oprofile backtrace  generation for 32 bit
applications running in the 64bit environment (compat mode).

With this change it's possible to get backtrace for 32bits applications
under the 64bits environment using oprofile's callgraph options.

opcontrol --setup -c ...
opreport -l -cg ...
Signed-off-by: default avatarJiri Olsa <jolsa@redhat.com>
Signed-off-by: default avatarRobert Richter <robert.richter@amd.com>
parent 40c6b3cb
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/stacktrace.h> #include <asm/stacktrace.h>
#include <linux/compat.h>
static void backtrace_warning_symbol(void *data, char *msg, static void backtrace_warning_symbol(void *data, char *msg,
unsigned long symbol) unsigned long symbol)
...@@ -48,6 +49,55 @@ static struct stacktrace_ops backtrace_ops = { ...@@ -48,6 +49,55 @@ static struct stacktrace_ops backtrace_ops = {
.walk_stack = print_context_stack, .walk_stack = print_context_stack,
}; };
#ifdef CONFIG_COMPAT
static struct stack_frame_ia32 *
dump_user_backtrace_32(struct stack_frame_ia32 *head)
{
struct stack_frame_ia32 bufhead[2];
struct stack_frame_ia32 *fp;
/* Also check accessibility of one struct frame_head beyond */
if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
return NULL;
if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
return NULL;
fp = (struct stack_frame_ia32 *) compat_ptr(bufhead[0].next_frame);
oprofile_add_trace(bufhead[0].return_address);
/* frame pointers should strictly progress back up the stack
* (towards higher addresses) */
if (head >= fp)
return NULL;
return fp;
}
static inline int
x86_backtrace_32(struct pt_regs * const regs, unsigned int depth)
{
struct stack_frame_ia32 *head;
/* User process is 32-bit */
if (!current || !test_thread_flag(TIF_IA32))
return 0;
head = (struct stack_frame_ia32 *) regs->bp;
while (depth-- && head)
head = dump_user_backtrace_32(head);
return 1;
}
#else
static inline int
x86_backtrace_32(struct pt_regs * const regs, unsigned int depth)
{
return 0;
}
#endif /* CONFIG_COMPAT */
static struct stack_frame *dump_user_backtrace(struct stack_frame *head) static struct stack_frame *dump_user_backtrace(struct stack_frame *head)
{ {
struct stack_frame bufhead[2]; struct stack_frame bufhead[2];
...@@ -81,6 +131,9 @@ x86_backtrace(struct pt_regs * const regs, unsigned int depth) ...@@ -81,6 +131,9 @@ x86_backtrace(struct pt_regs * const regs, unsigned int depth)
return; return;
} }
if (x86_backtrace_32(regs, depth))
return;
while (depth-- && head) while (depth-- && head)
head = dump_user_backtrace(head); head = dump_user_backtrace(head);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment