blob: cad9d78312e00f6bd121146feceeb238a4fd9e86 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Kernel unwinding support
3 *
4 * (c) 2002-2004 Randolph Chung <tausq@debian.org>
5 *
6 * Derived partially from the IA64 implementation. The PA-RISC
7 * Runtime Architecture Document is also a useful reference to
8 * understand what is happening here
9 */
10
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/kernel.h>
12#include <linux/init.h>
Matthew Wilcoxe6fc0442006-12-15 09:34:36 -070013#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/slab.h>
15#include <linux/kallsyms.h>
16
17#include <asm/uaccess.h>
18#include <asm/assembly.h>
19
20#include <asm/unwind.h>
21
22/* #define DEBUG 1 */
23#ifdef DEBUG
24#define dbg(x...) printk(x)
25#else
26#define dbg(x...)
27#endif
28
Randolph Chunge0363062007-06-12 14:27:32 +080029#define KERNEL_START (KERNEL_BINARY_TEXT_START - 0x1000)
30
Linus Torvalds1da177e2005-04-16 15:20:36 -070031extern struct unwind_table_entry __start___unwind[];
32extern struct unwind_table_entry __stop___unwind[];
33
34static spinlock_t unwind_lock;
35/*
36 * the kernel unwind block is not dynamically allocated so that
37 * we can call unwind_init as early in the bootup process as
38 * possible (before the slab allocator is initialized)
39 */
Helge Deller8039de12006-01-10 20:35:03 -050040static struct unwind_table kernel_unwind_table __read_mostly;
Linus Torvalds1da177e2005-04-16 15:20:36 -070041static LIST_HEAD(unwind_tables);
42
43static inline const struct unwind_table_entry *
44find_unwind_entry_in_table(const struct unwind_table *table, unsigned long addr)
45{
46 const struct unwind_table_entry *e = NULL;
47 unsigned long lo, hi, mid;
48
49 lo = 0;
50 hi = table->length - 1;
51
52 while (lo <= hi) {
53 mid = (hi - lo) / 2 + lo;
54 e = &table->table[mid];
55 if (addr < e->region_start)
56 hi = mid - 1;
57 else if (addr > e->region_end)
58 lo = mid + 1;
59 else
60 return e;
61 }
62
63 return NULL;
64}
65
66static const struct unwind_table_entry *
67find_unwind_entry(unsigned long addr)
68{
69 struct unwind_table *table;
70 const struct unwind_table_entry *e = NULL;
71
72 if (addr >= kernel_unwind_table.start &&
73 addr <= kernel_unwind_table.end)
74 e = find_unwind_entry_in_table(&kernel_unwind_table, addr);
75 else
76 list_for_each_entry(table, &unwind_tables, list) {
77 if (addr >= table->start &&
78 addr <= table->end)
79 e = find_unwind_entry_in_table(table, addr);
80 if (e)
81 break;
82 }
83
84 return e;
85}
86
87static void
88unwind_table_init(struct unwind_table *table, const char *name,
89 unsigned long base_addr, unsigned long gp,
90 void *table_start, void *table_end)
91{
92 struct unwind_table_entry *start = table_start;
93 struct unwind_table_entry *end =
94 (struct unwind_table_entry *)table_end - 1;
95
96 table->name = name;
97 table->base_addr = base_addr;
98 table->gp = gp;
99 table->start = base_addr + start->region_start;
100 table->end = base_addr + end->region_end;
101 table->table = (struct unwind_table_entry *)table_start;
102 table->length = end - start + 1;
103 INIT_LIST_HEAD(&table->list);
104
105 for (; start <= end; start++) {
106 if (start < end &&
107 start->region_end > (start+1)->region_start) {
108 printk("WARNING: Out of order unwind entry! %p and %p\n", start, start+1);
109 }
110
111 start->region_start += base_addr;
112 start->region_end += base_addr;
113 }
114}
115
116static void
117unwind_table_sort(struct unwind_table_entry *start,
118 struct unwind_table_entry *finish)
119{
120 struct unwind_table_entry el, *p, *q;
121
122 for (p = start + 1; p < finish; ++p) {
123 if (p[0].region_start < p[-1].region_start) {
124 el = *p;
125 q = p;
126 do {
127 q[0] = q[-1];
128 --q;
129 } while (q > start &&
130 el.region_start < q[-1].region_start);
131 *q = el;
132 }
133 }
134}
135
136struct unwind_table *
137unwind_table_add(const char *name, unsigned long base_addr,
138 unsigned long gp,
139 void *start, void *end)
140{
141 struct unwind_table *table;
142 unsigned long flags;
143 struct unwind_table_entry *s = (struct unwind_table_entry *)start;
144 struct unwind_table_entry *e = (struct unwind_table_entry *)end;
145
146 unwind_table_sort(s, e);
147
148 table = kmalloc(sizeof(struct unwind_table), GFP_USER);
149 if (table == NULL)
150 return NULL;
151 unwind_table_init(table, name, base_addr, gp, start, end);
152 spin_lock_irqsave(&unwind_lock, flags);
153 list_add_tail(&table->list, &unwind_tables);
154 spin_unlock_irqrestore(&unwind_lock, flags);
155
156 return table;
157}
158
159void unwind_table_remove(struct unwind_table *table)
160{
161 unsigned long flags;
162
163 spin_lock_irqsave(&unwind_lock, flags);
164 list_del(&table->list);
165 spin_unlock_irqrestore(&unwind_lock, flags);
166
167 kfree(table);
168}
169
170/* Called from setup_arch to import the kernel unwind info */
171static int unwind_init(void)
172{
173 long start, stop;
174 register unsigned long gp __asm__ ("r27");
175
176 start = (long)&__start___unwind[0];
177 stop = (long)&__stop___unwind[0];
178
179 spin_lock_init(&unwind_lock);
180
181 printk("unwind_init: start = 0x%lx, end = 0x%lx, entries = %lu\n",
182 start, stop,
183 (stop - start) / sizeof(struct unwind_table_entry));
184
185 unwind_table_init(&kernel_unwind_table, "kernel", KERNEL_START,
186 gp,
187 &__start___unwind[0], &__stop___unwind[0]);
188#if 0
189 {
190 int i;
191 for (i = 0; i < 10; i++)
192 {
193 printk("region 0x%x-0x%x\n",
194 __start___unwind[i].region_start,
195 __start___unwind[i].region_end);
196 }
197 }
198#endif
199 return 0;
200}
201
202static void unwind_frame_regs(struct unwind_frame_info *info)
203{
204 const struct unwind_table_entry *e;
205 unsigned long npc;
206 unsigned int insn;
207 long frame_size = 0;
208 int looking_for_rp, rpoffset = 0;
209
210 e = find_unwind_entry(info->ip);
211 if (e == NULL) {
212 unsigned long sp;
213 extern char _stext[], _etext[];
214
215 dbg("Cannot find unwind entry for 0x%lx; forced unwinding\n", info->ip);
216
217#ifdef CONFIG_KALLSYMS
218 /* Handle some frequent special cases.... */
219 {
220 char symname[KSYM_NAME_LEN+1];
Kyle McMartincb957792007-05-30 02:24:28 -0400221 char *modname;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
Kyle McMartincb957792007-05-30 02:24:28 -0400223 kallsyms_lookup(info->ip, NULL, NULL, &modname,
224 symname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
226 dbg("info->ip = 0x%lx, name = %s\n", info->ip, symname);
227
228 if (strcmp(symname, "_switch_to_ret") == 0) {
229 info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE;
230 info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET);
231 dbg("_switch_to_ret @ %lx - setting "
232 "prev_sp=%lx prev_ip=%lx\n",
233 info->ip, info->prev_sp,
234 info->prev_ip);
235 return;
236 } else if (strcmp(symname, "ret_from_kernel_thread") == 0 ||
237 strcmp(symname, "syscall_exit") == 0) {
238 info->prev_ip = info->prev_sp = 0;
239 return;
240 }
241 }
242#endif
243
244 /* Since we are doing the unwinding blind, we don't know if
245 we are adjusting the stack correctly or extracting the rp
246 correctly. The rp is checked to see if it belongs to the
247 kernel text section, if not we assume we don't have a
248 correct stack frame and we continue to unwind the stack.
249 This is not quite correct, and will fail for loadable
250 modules. */
251 sp = info->sp & ~63;
252 do {
253 unsigned long tmp;
254
255 info->prev_sp = sp - 64;
256 info->prev_ip = 0;
257 if (get_user(tmp, (unsigned long *)(info->prev_sp - RP_OFFSET)))
258 break;
259 info->prev_ip = tmp;
260 sp = info->prev_sp;
261 } while (info->prev_ip < (unsigned long)_stext ||
262 info->prev_ip > (unsigned long)_etext);
263
264 info->rp = 0;
265
266 dbg("analyzing func @ %lx with no unwind info, setting "
267 "prev_sp=%lx prev_ip=%lx\n", info->ip,
268 info->prev_sp, info->prev_ip);
269 } else {
270 dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, "
271 "Save_RP = %d, Millicode = %d size = %u\n",
272 e->region_start, e->region_end, e->Save_SP, e->Save_RP,
273 e->Millicode, e->Total_frame_size);
274
275 looking_for_rp = e->Save_RP;
276
277 for (npc = e->region_start;
278 (frame_size < (e->Total_frame_size << 3) ||
279 looking_for_rp) &&
280 npc < info->ip;
281 npc += 4) {
282
283 insn = *(unsigned int *)npc;
284
285 if ((insn & 0xffffc000) == 0x37de0000 ||
286 (insn & 0xffe00000) == 0x6fc00000) {
287 /* ldo X(sp), sp, or stwm X,D(sp) */
288 frame_size += (insn & 0x1 ? -1 << 13 : 0) |
289 ((insn & 0x3fff) >> 1);
290 dbg("analyzing func @ %lx, insn=%08x @ "
291 "%lx, frame_size = %ld\n", info->ip,
292 insn, npc, frame_size);
293 } else if ((insn & 0xffe00008) == 0x73c00008) {
294 /* std,ma X,D(sp) */
295 frame_size += (insn & 0x1 ? -1 << 13 : 0) |
296 (((insn >> 4) & 0x3ff) << 3);
297 dbg("analyzing func @ %lx, insn=%08x @ "
298 "%lx, frame_size = %ld\n", info->ip,
299 insn, npc, frame_size);
300 } else if (insn == 0x6bc23fd9) {
301 /* stw rp,-20(sp) */
302 rpoffset = 20;
303 looking_for_rp = 0;
304 dbg("analyzing func @ %lx, insn=stw rp,"
305 "-20(sp) @ %lx\n", info->ip, npc);
306 } else if (insn == 0x0fc212c1) {
307 /* std rp,-16(sr0,sp) */
308 rpoffset = 16;
309 looking_for_rp = 0;
310 dbg("analyzing func @ %lx, insn=std rp,"
311 "-16(sp) @ %lx\n", info->ip, npc);
312 }
313 }
314
315 info->prev_sp = info->sp - frame_size;
316 if (e->Millicode)
317 info->rp = info->r31;
318 else if (rpoffset)
319 info->rp = *(unsigned long *)(info->prev_sp - rpoffset);
320 info->prev_ip = info->rp;
321 info->rp = 0;
322
323 dbg("analyzing func @ %lx, setting prev_sp=%lx "
324 "prev_ip=%lx npc=%lx\n", info->ip, info->prev_sp,
325 info->prev_ip, npc);
326 }
327}
328
329void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t,
330 struct pt_regs *regs)
331{
332 memset(info, 0, sizeof(struct unwind_frame_info));
333 info->t = t;
334 info->sp = regs->gr[30];
335 info->ip = regs->iaoq[0];
336 info->rp = regs->gr[2];
337 info->r31 = regs->gr[31];
338
339 dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n",
340 t ? (int)t->pid : -1, info->sp, info->ip);
341}
342
343void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t)
344{
345 struct pt_regs *r = &t->thread.regs;
346 struct pt_regs *r2;
347
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800348 r2 = kmalloc(sizeof(struct pt_regs), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 if (!r2)
350 return;
351 *r2 = *r;
352 r2->gr[30] = r->ksp;
353 r2->iaoq[0] = r->kpc;
354 unwind_frame_init(info, t, r2);
355 kfree(r2);
356}
357
358void unwind_frame_init_running(struct unwind_frame_info *info, struct pt_regs *regs)
359{
360 unwind_frame_init(info, current, regs);
361}
362
363int unwind_once(struct unwind_frame_info *next_frame)
364{
365 unwind_frame_regs(next_frame);
366
367 if (next_frame->prev_sp == 0 ||
368 next_frame->prev_ip == 0)
369 return -1;
370
371 next_frame->sp = next_frame->prev_sp;
372 next_frame->ip = next_frame->prev_ip;
373 next_frame->prev_sp = 0;
374 next_frame->prev_ip = 0;
375
376 dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n",
377 next_frame->t ? (int)next_frame->t->pid : -1,
378 next_frame->sp, next_frame->ip);
379
380 return 0;
381}
382
383int unwind_to_user(struct unwind_frame_info *info)
384{
385 int ret;
386
387 do {
388 ret = unwind_once(info);
389 } while (!ret && !(info->ip & 3));
390
391 return ret;
392}
393
394module_init(unwind_init);