aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/kernel/dumpstack.c
diff options
context:
space:
mode:
authorRobin Getz <robin.getz@analog.com>2010-03-11 11:24:18 -0500
committerMike Frysinger <vapier@gentoo.org>2010-05-21 09:40:17 -0400
commit2a12c4632db1c0c548a7023e63869b27c7789a92 (patch)
tree518ec2b9379886d5fe7301cf3d5eed959f0452ca /arch/blackfin/kernel/dumpstack.c
parentbb84dbf69b0730fcc78c275f900ed74b2b8453a5 (diff)
Blackfin: split kernel/traps.c
The current kernel/traps.c file has grown a bit unwieldy as more debugging functionality has been added over time, so split it up into more logical files. There should be no functional changes here, just minor whitespace tweaking. This should make future extensions easier to manage. Signed-off-by: Robin Getz <robin.getz@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'arch/blackfin/kernel/dumpstack.c')
-rw-r--r--arch/blackfin/kernel/dumpstack.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/arch/blackfin/kernel/dumpstack.c b/arch/blackfin/kernel/dumpstack.c
new file mode 100644
index 000000000000..e81392c9d1db
--- /dev/null
+++ b/arch/blackfin/kernel/dumpstack.c
@@ -0,0 +1,181 @@
1/* Provide basic stack dumping functions
2 *
3 * Copyright 2004-2009 Analog Devices Inc.
4 *
5 * Licensed under the GPL-2 or later
6 */
7
8#include <linux/kernel.h>
9#include <linux/thread_info.h>
10#include <linux/mm.h>
11#include <linux/uaccess.h>
12#include <linux/module.h>
13#include <asm/trace.h>
14
15/*
16 * Checks to see if the address pointed to is either a
17 * 16-bit CALL instruction, or a 32-bit CALL instruction
18 */
19static bool is_bfin_call(unsigned short *addr)
20{
21 unsigned short opcode = 0, *ins_addr;
22 ins_addr = (unsigned short *)addr;
23
24 if (!get_instruction(&opcode, ins_addr))
25 return false;
26
27 if ((opcode >= 0x0060 && opcode <= 0x0067) ||
28 (opcode >= 0x0070 && opcode <= 0x0077))
29 return true;
30
31 ins_addr--;
32 if (!get_instruction(&opcode, ins_addr))
33 return false;
34
35 if (opcode >= 0xE300 && opcode <= 0xE3FF)
36 return true;
37
38 return false;
39
40}
41
42void show_stack(struct task_struct *task, unsigned long *stack)
43{
44#ifdef CONFIG_PRINTK
45 unsigned int *addr, *endstack, *fp = 0, *frame;
46 unsigned short *ins_addr;
47 char buf[150];
48 unsigned int i, j, ret_addr, frame_no = 0;
49
50 /*
51 * If we have been passed a specific stack, use that one otherwise
52 * if we have been passed a task structure, use that, otherwise
53 * use the stack of where the variable "stack" exists
54 */
55
56 if (stack == NULL) {
57 if (task) {
58 /* We know this is a kernel stack, so this is the start/end */
59 stack = (unsigned long *)task->thread.ksp;
60 endstack = (unsigned int *)(((unsigned int)(stack) & ~(THREAD_SIZE - 1)) + THREAD_SIZE);
61 } else {
62 /* print out the existing stack info */
63 stack = (unsigned long *)&stack;
64 endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack);
65 }
66 } else
67 endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack);
68
69 printk(KERN_NOTICE "Stack info:\n");
70 decode_address(buf, (unsigned int)stack);
71 printk(KERN_NOTICE " SP: [0x%p] %s\n", stack, buf);
72
73 if (!access_ok(VERIFY_READ, stack, (unsigned int)endstack - (unsigned int)stack)) {
74 printk(KERN_NOTICE "Invalid stack pointer\n");
75 return;
76 }
77
78 /* First thing is to look for a frame pointer */
79 for (addr = (unsigned int *)((unsigned int)stack & ~0xF); addr < endstack; addr++) {
80 if (*addr & 0x1)
81 continue;
82 ins_addr = (unsigned short *)*addr;
83 ins_addr--;
84 if (is_bfin_call(ins_addr))
85 fp = addr - 1;
86
87 if (fp) {
88 /* Let's check to see if it is a frame pointer */
89 while (fp >= (addr - 1) && fp < endstack
90 && fp && ((unsigned int) fp & 0x3) == 0)
91 fp = (unsigned int *)*fp;
92 if (fp == 0 || fp == endstack) {
93 fp = addr - 1;
94 break;
95 }
96 fp = 0;
97 }
98 }
99 if (fp) {
100 frame = fp;
101 printk(KERN_NOTICE " FP: (0x%p)\n", fp);
102 } else
103 frame = 0;
104
105 /*
106 * Now that we think we know where things are, we
107 * walk the stack again, this time printing things out
108 * incase there is no frame pointer, we still look for
109 * valid return addresses
110 */
111
112 /* First time print out data, next time, print out symbols */
113 for (j = 0; j <= 1; j++) {
114 if (j)
115 printk(KERN_NOTICE "Return addresses in stack:\n");
116 else
117 printk(KERN_NOTICE " Memory from 0x%08lx to %p", ((long unsigned int)stack & ~0xF), endstack);
118
119 fp = frame;
120 frame_no = 0;
121
122 for (addr = (unsigned int *)((unsigned int)stack & ~0xF), i = 0;
123 addr < endstack; addr++, i++) {
124
125 ret_addr = 0;
126 if (!j && i % 8 == 0)
127 printk(KERN_NOTICE "%p:", addr);
128
129 /* if it is an odd address, or zero, just skip it */
130 if (*addr & 0x1 || !*addr)
131 goto print;
132
133 ins_addr = (unsigned short *)*addr;
134
135 /* Go back one instruction, and see if it is a CALL */
136 ins_addr--;
137 ret_addr = is_bfin_call(ins_addr);
138 print:
139 if (!j && stack == (unsigned long *)addr)
140 printk("[%08x]", *addr);
141 else if (ret_addr)
142 if (j) {
143 decode_address(buf, (unsigned int)*addr);
144 if (frame == addr) {
145 printk(KERN_NOTICE " frame %2i : %s\n", frame_no, buf);
146 continue;
147 }
148 printk(KERN_NOTICE " address : %s\n", buf);
149 } else
150 printk("<%08x>", *addr);
151 else if (fp == addr) {
152 if (j)
153 frame = addr+1;
154 else
155 printk("(%08x)", *addr);
156
157 fp = (unsigned int *)*addr;
158 frame_no++;
159
160 } else if (!j)
161 printk(" %08x ", *addr);
162 }
163 if (!j)
164 printk("\n");
165 }
166#endif
167}
168EXPORT_SYMBOL(show_stack);
169
170void dump_stack(void)
171{
172 unsigned long stack;
173#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
174 int tflags;
175#endif
176 trace_buffer_save(tflags);
177 dump_bfin_trace_buffer();
178 show_stack(current, &stack);
179 trace_buffer_restore(tflags);
180}
181EXPORT_SYMBOL(dump_stack);