linux/arch/x86/oprofile/backtrace.c
<<
>>
Prefs
   1/**
   2 * @file backtrace.c
   3 *
   4 * @remark Copyright 2002 OProfile authors
   5 * @remark Read the file COPYING
   6 *
   7 * @author John Levon
   8 * @author David Smith
   9 */
  10
  11#include <linux/oprofile.h>
  12#include <linux/sched.h>
  13#include <linux/mm.h>
  14#include <linux/compat.h>
  15#include <linux/uaccess.h>
  16
  17#include <asm/ptrace.h>
  18#include <asm/stacktrace.h>
  19
  20static int backtrace_stack(void *data, char *name)
  21{
  22        /* Yes, we want all stacks */
  23        return 0;
  24}
  25
  26static void backtrace_address(void *data, unsigned long addr, int reliable)
  27{
  28        unsigned int *depth = data;
  29
  30        if ((*depth)--)
  31                oprofile_add_trace(addr);
  32}
  33
  34static struct stacktrace_ops backtrace_ops = {
  35        .stack          = backtrace_stack,
  36        .address        = backtrace_address,
  37        .walk_stack     = print_context_stack,
  38};
  39
  40#ifdef CONFIG_COMPAT
  41static struct stack_frame_ia32 *
  42dump_user_backtrace_32(struct stack_frame_ia32 *head)
  43{
  44        /* Also check accessibility of one struct frame_head beyond: */
  45        struct stack_frame_ia32 bufhead[2];
  46        struct stack_frame_ia32 *fp;
  47        unsigned long bytes;
  48
  49        bytes = copy_from_user_nmi(bufhead, head, sizeof(bufhead));
  50        if (bytes != sizeof(bufhead))
  51                return NULL;
  52
  53        fp = (struct stack_frame_ia32 *) compat_ptr(bufhead[0].next_frame);
  54
  55        oprofile_add_trace(bufhead[0].return_address);
  56
  57        /* frame pointers should strictly progress back up the stack
  58        * (towards higher addresses) */
  59        if (head >= fp)
  60                return NULL;
  61
  62        return fp;
  63}
  64
  65static inline int
  66x86_backtrace_32(struct pt_regs * const regs, unsigned int depth)
  67{
  68        struct stack_frame_ia32 *head;
  69
  70        /* User process is IA32 */
  71        if (!current || !test_thread_flag(TIF_IA32))
  72                return 0;
  73
  74        head = (struct stack_frame_ia32 *) regs->bp;
  75        while (depth-- && head)
  76                head = dump_user_backtrace_32(head);
  77
  78        return 1;
  79}
  80
  81#else
  82static inline int
  83x86_backtrace_32(struct pt_regs * const regs, unsigned int depth)
  84{
  85        return 0;
  86}
  87#endif /* CONFIG_COMPAT */
  88
  89static struct stack_frame *dump_user_backtrace(struct stack_frame *head)
  90{
  91        /* Also check accessibility of one struct frame_head beyond: */
  92        struct stack_frame bufhead[2];
  93        unsigned long bytes;
  94
  95        bytes = copy_from_user_nmi(bufhead, head, sizeof(bufhead));
  96        if (bytes != sizeof(bufhead))
  97                return NULL;
  98
  99        oprofile_add_trace(bufhead[0].return_address);
 100
 101        /* frame pointers should strictly progress back up the stack
 102         * (towards higher addresses) */
 103        if (head >= bufhead[0].next_frame)
 104                return NULL;
 105
 106        return bufhead[0].next_frame;
 107}
 108
 109void
 110x86_backtrace(struct pt_regs * const regs, unsigned int depth)
 111{
 112        struct stack_frame *head = (struct stack_frame *)frame_pointer(regs);
 113
 114        if (!user_mode_vm(regs)) {
 115                unsigned long stack = kernel_stack_pointer(regs);
 116                if (depth)
 117                        dump_trace(NULL, regs, (unsigned long *)stack, 0,
 118                                   &backtrace_ops, &depth);
 119                return;
 120        }
 121
 122        if (x86_backtrace_32(regs, depth))
 123                return;
 124
 125        while (depth-- && head)
 126                head = dump_user_backtrace(head);
 127}
 128