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 <asm/ptrace.h>
  15#include <asm/uaccess.h>
  16#include <asm/stacktrace.h>
  17
  18static void backtrace_warning_symbol(void *data, char *msg,
  19                                     unsigned long symbol)
  20{
  21        /* Ignore warnings */
  22}
  23
  24static void backtrace_warning(void *data, char *msg)
  25{
  26        /* Ignore warnings */
  27}
  28
  29static int backtrace_stack(void *data, char *name)
  30{
  31        /* Yes, we want all stacks */
  32        return 0;
  33}
  34
  35static void backtrace_address(void *data, unsigned long addr, int reliable)
  36{
  37        unsigned int *depth = data;
  38
  39        if ((*depth)--)
  40                oprofile_add_trace(addr);
  41}
  42
  43static struct stacktrace_ops backtrace_ops = {
  44        .warning = backtrace_warning,
  45        .warning_symbol = backtrace_warning_symbol,
  46        .stack = backtrace_stack,
  47        .address = backtrace_address,
  48};
  49
  50struct frame_head {
  51        struct frame_head *bp;
  52        unsigned long ret;
  53} __attribute__((packed));
  54
  55static struct frame_head *dump_user_backtrace(struct frame_head *head)
  56{
  57        struct frame_head bufhead[2];
  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        oprofile_add_trace(bufhead[0].ret);
  66
  67        /* frame pointers should strictly progress back up the stack
  68         * (towards higher addresses) */
  69        if (head >= bufhead[0].bp)
  70                return NULL;
  71
  72        return bufhead[0].bp;
  73}
  74
  75void
  76x86_backtrace(struct pt_regs * const regs, unsigned int depth)
  77{
  78        struct frame_head *head = (struct frame_head *)frame_pointer(regs);
  79
  80        if (!user_mode_vm(regs)) {
  81                unsigned long stack = kernel_stack_pointer(regs);
  82                if (depth)
  83                        dump_trace(NULL, regs, (unsigned long *)stack, 0,
  84                                   &backtrace_ops, &depth);
  85                return;
  86        }
  87
  88        while (depth-- && head)
  89                head = dump_user_backtrace(head);
  90}
  91