Merge branch 'oprofile/urgent' into oprofile/core
[deliverable/linux.git] / arch / x86 / oprofile / backtrace.c
CommitLineData
1da177e4
LT
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>
c34d1b4d 15#include <asm/uaccess.h>
574a6042 16#include <asm/stacktrace.h>
1da177e4 17
574a6042
JB
18static void backtrace_warning_symbol(void *data, char *msg,
19 unsigned long symbol)
20{
21 /* Ignore warnings */
22}
1da177e4 23
574a6042 24static void backtrace_warning(void *data, char *msg)
30379440 25{
574a6042
JB
26 /* Ignore warnings */
27}
30379440 28
574a6042
JB
29static int backtrace_stack(void *data, char *name)
30{
31 /* Yes, we want all stacks */
32 return 0;
33}
30379440 34
bc850d6b 35static void backtrace_address(void *data, unsigned long addr, int reliable)
574a6042
JB
36{
37 unsigned int *depth = data;
38
39 if ((*depth)--)
40 oprofile_add_trace(addr);
30379440
GB
41}
42
574a6042 43static struct stacktrace_ops backtrace_ops = {
61c1917f
FW
44 .warning = backtrace_warning,
45 .warning_symbol = backtrace_warning_symbol,
46 .stack = backtrace_stack,
47 .address = backtrace_address,
48 .walk_stack = print_context_stack,
574a6042
JB
49};
50
51struct frame_head {
65ea5b03 52 struct frame_head *bp;
574a6042
JB
53 unsigned long ret;
54} __attribute__((packed));
55
0f019cc4 56static struct frame_head *dump_user_backtrace(struct frame_head *head)
1da177e4 57{
c34d1b4d 58 struct frame_head bufhead[2];
1da177e4 59
c34d1b4d
HD
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)))
1da177e4
LT
64 return NULL;
65
c34d1b4d 66 oprofile_add_trace(bufhead[0].ret);
1da177e4 67
c34d1b4d
HD
68 /* frame pointers should strictly progress back up the stack
69 * (towards higher addresses) */
65ea5b03 70 if (head >= bufhead[0].bp)
c34d1b4d 71 return NULL;
1da177e4 72
65ea5b03 73 return bufhead[0].bp;
1da177e4
LT
74}
75
1da177e4
LT
76void
77x86_backtrace(struct pt_regs * const regs, unsigned int depth)
78{
f1df280f 79 struct frame_head *head = (struct frame_head *)frame_pointer(regs);
1da177e4 80
fa1e1bdf 81 if (!user_mode_vm(regs)) {
7b6c6c77 82 unsigned long stack = kernel_stack_pointer(regs);
574a6042 83 if (depth)
5bc27dc2 84 dump_trace(NULL, regs, (unsigned long *)stack, 0,
574a6042 85 &backtrace_ops, &depth);
1da177e4
LT
86 return;
87 }
88
c34d1b4d 89 while (depth-- && head)
30379440 90 head = dump_user_backtrace(head);
1da177e4 91}
This page took 0.49671 seconds and 5 git commands to generate.