• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/arch/x86/oprofile/
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	.walk_stack	= print_context_stack,
49};
50
51struct frame_head {
52	struct frame_head *bp;
53	unsigned long ret;
54} __attribute__((packed));
55
56static struct frame_head *dump_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].bp)
71		return NULL;
72
73	return bufhead[0].bp;
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
81	if (!user_mode_vm(regs)) {
82		unsigned long stack = kernel_stack_pointer(regs);
83		if (depth)
84			dump_trace(NULL, regs, (unsigned long *)stack, 0,
85				   &backtrace_ops, &depth);
86		return;
87	}
88
89	while (depth-- && head)
90		head = dump_user_backtrace(head);
91}
92