wireless: move crypto constants to ieee80211.h
[linux-2.6.git] / arch / xtensa / oprofile / backtrace.c
blob5f03a593d84f9000d6db447f599f40af7048af42
1 /**
2 * @file backtrace.c
4 * @remark Copyright 2008 Tensilica Inc.
5 * @remark Read the file COPYING
7 */
9 #include <linux/oprofile.h>
10 #include <linux/sched.h>
11 #include <linux/mm.h>
12 #include <asm/ptrace.h>
13 #include <asm/uaccess.h>
14 #include <asm/traps.h>
16 /* Address of common_exception_return, used to check the
17 * transition from kernel to user space.
19 extern int common_exception_return;
21 /* A struct that maps to the part of the frame containing the a0 and
22 * a1 registers.
24 struct frame_start {
25 unsigned long a0;
26 unsigned long a1;
29 static void xtensa_backtrace_user(struct pt_regs *regs, unsigned int depth)
31 unsigned long windowstart = regs->windowstart;
32 unsigned long windowbase = regs->windowbase;
33 unsigned long a0 = regs->areg[0];
34 unsigned long a1 = regs->areg[1];
35 unsigned long pc = MAKE_PC_FROM_RA(a0, regs->pc);
36 int index;
38 /* First add the current PC to the trace. */
39 if (pc != 0 && pc <= TASK_SIZE)
40 oprofile_add_trace(pc);
41 else
42 return;
44 /* Two steps:
46 * 1. Look through the register window for the
47 * previous PCs in the call trace.
49 * 2. Look on the stack.
52 /* Step 1. */
53 /* Rotate WINDOWSTART to move the bit corresponding to
54 * the current window to the bit #0.
56 windowstart = (windowstart << WSBITS | windowstart) >> windowbase;
58 /* Look for bits that are set, they correspond to
59 * valid windows.
61 for (index = WSBITS - 1; (index > 0) && depth; depth--, index--)
62 if (windowstart & (1 << index)) {
63 /* Read a0 and a1 from the
64 * corresponding position in AREGs.
66 a0 = regs->areg[index * 4];
67 a1 = regs->areg[index * 4 + 1];
68 /* Get the PC from a0 and a1. */
69 pc = MAKE_PC_FROM_RA(a0, pc);
71 /* Add the PC to the trace. */
72 if (pc != 0 && pc <= TASK_SIZE)
73 oprofile_add_trace(pc);
74 else
75 return;
78 /* Step 2. */
79 /* We are done with the register window, we need to
80 * look through the stack.
82 if (depth > 0) {
83 /* Start from the a1 register. */
84 /* a1 = regs->areg[1]; */
85 while (a0 != 0 && depth--) {
87 struct frame_start frame_start;
88 /* Get the location for a1, a0 for the
89 * previous frame from the current a1.
91 unsigned long *psp = (unsigned long *)a1;
92 psp -= 4;
94 /* Check if the region is OK to access. */
95 if (!access_ok(VERIFY_READ, psp, sizeof(frame_start)))
96 return;
97 /* Copy a1, a0 from user space stack frame. */
98 if (__copy_from_user_inatomic(&frame_start, psp,
99 sizeof(frame_start)))
100 return;
102 a0 = frame_start.a0;
103 a1 = frame_start.a1;
104 pc = MAKE_PC_FROM_RA(a0, pc);
106 if (pc != 0 && pc <= TASK_SIZE)
107 oprofile_add_trace(pc);
108 else
109 return;
114 static void xtensa_backtrace_kernel(struct pt_regs *regs, unsigned int depth)
116 unsigned long pc = regs->pc;
117 unsigned long *psp;
118 unsigned long sp_start, sp_end;
119 unsigned long a0 = regs->areg[0];
120 unsigned long a1 = regs->areg[1];
122 sp_start = a1 & ~(THREAD_SIZE-1);
123 sp_end = sp_start + THREAD_SIZE;
125 /* Spill the register window to the stack first. */
126 spill_registers();
128 /* Read the stack frames one by one and create the PC
129 * from the a0 and a1 registers saved there.
131 while (a1 > sp_start && a1 < sp_end && depth--) {
132 pc = MAKE_PC_FROM_RA(a0, pc);
134 /* Add the PC to the trace. */
135 oprofile_add_trace(pc);
136 if (pc == (unsigned long) &common_exception_return) {
137 regs = (struct pt_regs *)a1;
138 if (user_mode(regs)) {
139 pc = regs->pc;
140 if (pc != 0 && pc <= TASK_SIZE)
141 oprofile_add_trace(pc);
142 else
143 return;
144 return xtensa_backtrace_user(regs, depth);
146 a0 = regs->areg[0];
147 a1 = regs->areg[1];
148 continue;
151 psp = (unsigned long *)a1;
153 a0 = *(psp - 4);
154 a1 = *(psp - 3);
156 if (a1 <= (unsigned long)psp)
157 return;
160 return;
163 void xtensa_backtrace(struct pt_regs * const regs, unsigned int depth)
165 if (user_mode(regs))
166 xtensa_backtrace_user(regs, depth);
167 else
168 xtensa_backtrace_kernel(regs, depth);