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)
  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 *ebp;
  52        unsigned long ret;
  53} __attribute__((packed));
  54
  55static struct frame_head *
  56dump_user_backtrace(struct frame_head * head)
  57{
  58        struct frame_head bufhead[2];
  59
  60        /* Also check accessibility of one struct frame_head beyond */
  61        if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
  62                return NULL;
  63        if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
  64                return NULL;
  65
  66        oprofile_add_trace(bufhead[0].ret);
  67
  68        /* frame pointers should strictly progress back up the stack
  69         * (towards higher addresses) */
  70        if (head >= bufhead[0].ebp)
  71                return NULL;
  72
  73        return bufhead[0].ebp;
  74}
  75
  76void
  77x86_backtrace(struct pt_regs * const regs, unsigned int depth)
  78{
  79        struct frame_head *head = (struct frame_head *)frame_pointer(regs);
  80        unsigned long stack = stack_pointer(regs);
  81
  82        if (!user_mode_vm(regs)) {
  83                if (depth)
  84                        dump_trace(NULL, regs, (unsigned long *)stack,
  85                                   &backtrace_ops, &depth);
  86                return;
  87        }
  88
  89        while (depth-- && head)
  90                head = dump_user_backtrace(head);
  91}
  92