From d4e28c48a98ab8461dc1d97674107d107fc0f9fb Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 29 Sep 2010 10:46:47 -0400 Subject: [PATCH] --- yaml --- r: 211908 b: refs/heads/master c: f6dedecc37164a58bb80ae2ed9d204669ffc4850 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/arch/x86/oprofile/backtrace.c | 53 +++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index 3fa35b8ff1da..6e2c79de9037 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 40c6b3cb64cd1d02322df5f729cca25084580f40 +refs/heads/master: f6dedecc37164a58bb80ae2ed9d204669ffc4850 diff --git a/trunk/arch/x86/oprofile/backtrace.c b/trunk/arch/x86/oprofile/backtrace.c index d640a86198b1..2d49d4e19a36 100644 --- a/trunk/arch/x86/oprofile/backtrace.c +++ b/trunk/arch/x86/oprofile/backtrace.c @@ -14,6 +14,7 @@ #include #include #include +#include static void backtrace_warning_symbol(void *data, char *msg, unsigned long symbol) @@ -48,6 +49,55 @@ static struct stacktrace_ops backtrace_ops = { .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) { struct stack_frame bufhead[2]; @@ -81,6 +131,9 @@ x86_backtrace(struct pt_regs * const regs, unsigned int depth) return; } + if (x86_backtrace_32(regs, depth)) + return; + while (depth-- && head) head = dump_user_backtrace(head); }