diff options
Diffstat (limited to 'arch/blackfin/kernel/dumpstack.c')
-rw-r--r-- | arch/blackfin/kernel/dumpstack.c | 181 |
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 | */ | ||
19 | static 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 | |||
42 | void 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 | } | ||
168 | EXPORT_SYMBOL(show_stack); | ||
169 | |||
170 | void 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 | } | ||
181 | EXPORT_SYMBOL(dump_stack); | ||