Commit f6dedecc37164a58bb80ae2ed9d204669ffc4850

Authored by Jiri Olsa
Committed by Robert Richter
1 parent 40c6b3cb64

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: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Robert Richter <robert.richter@amd.com>

Showing 1 changed file with 53 additions and 0 deletions Side-by-side Diff

arch/x86/oprofile/backtrace.c
... ... @@ -14,6 +14,7 @@
14 14 #include <asm/ptrace.h>
15 15 #include <asm/uaccess.h>
16 16 #include <asm/stacktrace.h>
  17 +#include <linux/compat.h>
17 18  
18 19 static void backtrace_warning_symbol(void *data, char *msg,
19 20 unsigned long symbol)
... ... @@ -48,6 +49,55 @@
48 49 .walk_stack = print_context_stack,
49 50 };
50 51  
  52 +#ifdef CONFIG_COMPAT
  53 +static struct stack_frame_ia32 *
  54 +dump_user_backtrace_32(struct stack_frame_ia32 *head)
  55 +{
  56 + struct stack_frame_ia32 bufhead[2];
  57 + struct stack_frame_ia32 *fp;
  58 +
  59 + /* Also check accessibility of one struct frame_head beyond */
  60 + if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
  61 + return NULL;
  62 + if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
  63 + return NULL;
  64 +
  65 + fp = (struct stack_frame_ia32 *) compat_ptr(bufhead[0].next_frame);
  66 +
  67 + oprofile_add_trace(bufhead[0].return_address);
  68 +
  69 + /* frame pointers should strictly progress back up the stack
  70 + * (towards higher addresses) */
  71 + if (head >= fp)
  72 + return NULL;
  73 +
  74 + return fp;
  75 +}
  76 +
  77 +static inline int
  78 +x86_backtrace_32(struct pt_regs * const regs, unsigned int depth)
  79 +{
  80 + struct stack_frame_ia32 *head;
  81 +
  82 + /* User process is 32-bit */
  83 + if (!current || !test_thread_flag(TIF_IA32))
  84 + return 0;
  85 +
  86 + head = (struct stack_frame_ia32 *) regs->bp;
  87 + while (depth-- && head)
  88 + head = dump_user_backtrace_32(head);
  89 +
  90 + return 1;
  91 +}
  92 +
  93 +#else
  94 +static inline int
  95 +x86_backtrace_32(struct pt_regs * const regs, unsigned int depth)
  96 +{
  97 + return 0;
  98 +}
  99 +#endif /* CONFIG_COMPAT */
  100 +
51 101 static struct stack_frame *dump_user_backtrace(struct stack_frame *head)
52 102 {
53 103 struct stack_frame bufhead[2];
... ... @@ -80,6 +130,9 @@
80 130 &backtrace_ops, &depth);
81 131 return;
82 132 }
  133 +
  134 + if (x86_backtrace_32(regs, depth))
  135 + return;
83 136  
84 137 while (depth-- && head)
85 138 head = dump_user_backtrace(head);