aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@novell.com>2006-06-26 07:57:28 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-26 13:48:17 -0400
commit4552d5dc08b79868829b4be8951b29b07284753f (patch)
tree7b25695b4c0e1917fc80e8dd4bc494de36320ccc /kernel
parent2b28592b07223d7fc0691ce3fe57d495dc9cbe3a (diff)
[PATCH] x86_64: reliable stack trace support
These are the generic bits needed to enable reliable stack traces based on Dwarf2-like (.eh_frame) unwind information. Subsequent patches will enable x86-64 and i386 to make use of this. Thanks to Andi Kleen and Ingo Molnar, who pointed out several possibilities for improvement. Signed-off-by: Jan Beulich <jbeulich@novell.com> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile1
-rw-r--r--kernel/module.c16
-rw-r--r--kernel/unwind.c915
3 files changed, 931 insertions, 1 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index f6ef00f4f90f..a31276e190f5 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
21obj-$(CONFIG_UID16) += uid16.o 21obj-$(CONFIG_UID16) += uid16.o
22obj-$(CONFIG_MODULES) += module.o 22obj-$(CONFIG_MODULES) += module.o
23obj-$(CONFIG_KALLSYMS) += kallsyms.o 23obj-$(CONFIG_KALLSYMS) += kallsyms.o
24obj-$(CONFIG_STACK_UNWIND) += unwind.o
24obj-$(CONFIG_PM) += power/ 25obj-$(CONFIG_PM) += power/
25obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o 26obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
26obj-$(CONFIG_KEXEC) += kexec.o 27obj-$(CONFIG_KEXEC) += kexec.o
diff --git a/kernel/module.c b/kernel/module.c
index d75275de1c28..08811e26ac9d 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -40,6 +40,7 @@
40#include <linux/string.h> 40#include <linux/string.h>
41#include <linux/sched.h> 41#include <linux/sched.h>
42#include <linux/mutex.h> 42#include <linux/mutex.h>
43#include <linux/unwind.h>
43#include <asm/uaccess.h> 44#include <asm/uaccess.h>
44#include <asm/semaphore.h> 45#include <asm/semaphore.h>
45#include <asm/cacheflush.h> 46#include <asm/cacheflush.h>
@@ -1051,6 +1052,8 @@ static void free_module(struct module *mod)
1051 remove_sect_attrs(mod); 1052 remove_sect_attrs(mod);
1052 mod_kobject_remove(mod); 1053 mod_kobject_remove(mod);
1053 1054
1055 unwind_remove_table(mod->unwind_info, 0);
1056
1054 /* Arch-specific cleanup. */ 1057 /* Arch-specific cleanup. */
1055 module_arch_cleanup(mod); 1058 module_arch_cleanup(mod);
1056 1059
@@ -1412,7 +1415,7 @@ static struct module *load_module(void __user *umod,
1412 unsigned int i, symindex = 0, strindex = 0, setupindex, exindex, 1415 unsigned int i, symindex = 0, strindex = 0, setupindex, exindex,
1413 exportindex, modindex, obsparmindex, infoindex, gplindex, 1416 exportindex, modindex, obsparmindex, infoindex, gplindex,
1414 crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex, 1417 crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex,
1415 gplfuturecrcindex; 1418 gplfuturecrcindex, unwindex = 0;
1416 struct module *mod; 1419 struct module *mod;
1417 long err = 0; 1420 long err = 0;
1418 void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ 1421 void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -1502,6 +1505,9 @@ static struct module *load_module(void __user *umod,
1502 versindex = find_sec(hdr, sechdrs, secstrings, "__versions"); 1505 versindex = find_sec(hdr, sechdrs, secstrings, "__versions");
1503 infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo"); 1506 infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo");
1504 pcpuindex = find_pcpusec(hdr, sechdrs, secstrings); 1507 pcpuindex = find_pcpusec(hdr, sechdrs, secstrings);
1508#ifdef ARCH_UNWIND_SECTION_NAME
1509 unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME);
1510#endif
1505 1511
1506 /* Don't keep modinfo section */ 1512 /* Don't keep modinfo section */
1507 sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC; 1513 sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
@@ -1510,6 +1516,8 @@ static struct module *load_module(void __user *umod,
1510 sechdrs[symindex].sh_flags |= SHF_ALLOC; 1516 sechdrs[symindex].sh_flags |= SHF_ALLOC;
1511 sechdrs[strindex].sh_flags |= SHF_ALLOC; 1517 sechdrs[strindex].sh_flags |= SHF_ALLOC;
1512#endif 1518#endif
1519 if (unwindex)
1520 sechdrs[unwindex].sh_flags |= SHF_ALLOC;
1513 1521
1514 /* Check module struct version now, before we try to use module. */ 1522 /* Check module struct version now, before we try to use module. */
1515 if (!check_modstruct_version(sechdrs, versindex, mod)) { 1523 if (!check_modstruct_version(sechdrs, versindex, mod)) {
@@ -1738,6 +1746,11 @@ static struct module *load_module(void __user *umod,
1738 goto arch_cleanup; 1746 goto arch_cleanup;
1739 add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); 1747 add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
1740 1748
1749 /* Size of section 0 is 0, so this works well if no unwind info. */
1750 mod->unwind_info = unwind_add_table(mod,
1751 (void *)sechdrs[unwindex].sh_addr,
1752 sechdrs[unwindex].sh_size);
1753
1741 /* Get rid of temporary copy */ 1754 /* Get rid of temporary copy */
1742 vfree(hdr); 1755 vfree(hdr);
1743 1756
@@ -1836,6 +1849,7 @@ sys_init_module(void __user *umod,
1836 mod->state = MODULE_STATE_LIVE; 1849 mod->state = MODULE_STATE_LIVE;
1837 /* Drop initial reference. */ 1850 /* Drop initial reference. */
1838 module_put(mod); 1851 module_put(mod);
1852 unwind_remove_table(mod->unwind_info, 1);
1839 module_free(mod, mod->module_init); 1853 module_free(mod, mod->module_init);
1840 mod->module_init = NULL; 1854 mod->module_init = NULL;
1841 mod->init_size = 0; 1855 mod->init_size = 0;
diff --git a/kernel/unwind.c b/kernel/unwind.c
new file mode 100644
index 000000000000..d36bcd3ad3b5
--- /dev/null
+++ b/kernel/unwind.c
@@ -0,0 +1,915 @@
1/*
2 * Copyright (C) 2002-2006 Novell, Inc.
3 * Jan Beulich <jbeulich@novell.com>
4 * This code is released under version 2 of the GNU GPL.
5 *
6 * A simple API for unwinding kernel stacks. This is used for
7 * debugging and error reporting purposes. The kernel doesn't need
8 * full-blown stack unwinding with all the bells and whistles, so there
9 * is not much point in implementing the full Dwarf2 unwind API.
10 */
11
12#include <linux/unwind.h>
13#include <linux/module.h>
14#include <linux/delay.h>
15#include <linux/stop_machine.h>
16#include <asm/sections.h>
17#include <asm/uaccess.h>
18#include <asm/unaligned.h>
19
20extern char __start_unwind[], __end_unwind[];
21
22#define MAX_STACK_DEPTH 8
23
24#define EXTRA_INFO(f) { \
25 BUILD_BUG_ON_ZERO(offsetof(struct unwind_frame_info, f) \
26 % FIELD_SIZEOF(struct unwind_frame_info, f)) \
27 + offsetof(struct unwind_frame_info, f) \
28 / FIELD_SIZEOF(struct unwind_frame_info, f), \
29 FIELD_SIZEOF(struct unwind_frame_info, f) \
30 }
31#define PTREGS_INFO(f) EXTRA_INFO(regs.f)
32
33static const struct {
34 unsigned offs:BITS_PER_LONG / 2;
35 unsigned width:BITS_PER_LONG / 2;
36} reg_info[] = {
37 UNW_REGISTER_INFO
38};
39
40#undef PTREGS_INFO
41#undef EXTRA_INFO
42
43#ifndef REG_INVALID
44#define REG_INVALID(r) (reg_info[r].width == 0)
45#endif
46
47#define DW_CFA_nop 0x00
48#define DW_CFA_set_loc 0x01
49#define DW_CFA_advance_loc1 0x02
50#define DW_CFA_advance_loc2 0x03
51#define DW_CFA_advance_loc4 0x04
52#define DW_CFA_offset_extended 0x05
53#define DW_CFA_restore_extended 0x06
54#define DW_CFA_undefined 0x07
55#define DW_CFA_same_value 0x08
56#define DW_CFA_register 0x09
57#define DW_CFA_remember_state 0x0a
58#define DW_CFA_restore_state 0x0b
59#define DW_CFA_def_cfa 0x0c
60#define DW_CFA_def_cfa_register 0x0d
61#define DW_CFA_def_cfa_offset 0x0e
62#define DW_CFA_def_cfa_expression 0x0f
63#define DW_CFA_expression 0x10
64#define DW_CFA_offset_extended_sf 0x11
65#define DW_CFA_def_cfa_sf 0x12
66#define DW_CFA_def_cfa_offset_sf 0x13
67#define DW_CFA_val_offset 0x14
68#define DW_CFA_val_offset_sf 0x15
69#define DW_CFA_val_expression 0x16
70#define DW_CFA_lo_user 0x1c
71#define DW_CFA_GNU_window_save 0x2d
72#define DW_CFA_GNU_args_size 0x2e
73#define DW_CFA_GNU_negative_offset_extended 0x2f
74#define DW_CFA_hi_user 0x3f
75
76#define DW_EH_PE_FORM 0x07
77#define DW_EH_PE_native 0x00
78#define DW_EH_PE_leb128 0x01
79#define DW_EH_PE_data2 0x02
80#define DW_EH_PE_data4 0x03
81#define DW_EH_PE_data8 0x04
82#define DW_EH_PE_signed 0x08
83#define DW_EH_PE_ADJUST 0x70
84#define DW_EH_PE_abs 0x00
85#define DW_EH_PE_pcrel 0x10
86#define DW_EH_PE_textrel 0x20
87#define DW_EH_PE_datarel 0x30
88#define DW_EH_PE_funcrel 0x40
89#define DW_EH_PE_aligned 0x50
90#define DW_EH_PE_indirect 0x80
91#define DW_EH_PE_omit 0xff
92
93typedef unsigned long uleb128_t;
94typedef signed long sleb128_t;
95
96static struct unwind_table {
97 struct {
98 unsigned long pc;
99 unsigned long range;
100 } core, init;
101 const void *address;
102 unsigned long size;
103 struct unwind_table *link;
104 const char *name;
105} root_table, *last_table;
106
107struct unwind_item {
108 enum item_location {
109 Nowhere,
110 Memory,
111 Register,
112 Value
113 } where;
114 uleb128_t value;
115};
116
117struct unwind_state {
118 uleb128_t loc, org;
119 const u8 *cieStart, *cieEnd;
120 uleb128_t codeAlign;
121 sleb128_t dataAlign;
122 struct cfa {
123 uleb128_t reg, offs;
124 } cfa;
125 struct unwind_item regs[ARRAY_SIZE(reg_info)];
126 unsigned stackDepth:8;
127 unsigned version:8;
128 const u8 *label;
129 const u8 *stack[MAX_STACK_DEPTH];
130};
131
132static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 };
133
134static struct unwind_table *find_table(unsigned long pc)
135{
136 struct unwind_table *table;
137
138 for (table = &root_table; table; table = table->link)
139 if ((pc >= table->core.pc
140 && pc < table->core.pc + table->core.range)
141 || (pc >= table->init.pc
142 && pc < table->init.pc + table->init.range))
143 break;
144
145 return table;
146}
147
148static void init_unwind_table(struct unwind_table *table,
149 const char *name,
150 const void *core_start,
151 unsigned long core_size,
152 const void *init_start,
153 unsigned long init_size,
154 const void *table_start,
155 unsigned long table_size)
156{
157 table->core.pc = (unsigned long)core_start;
158 table->core.range = core_size;
159 table->init.pc = (unsigned long)init_start;
160 table->init.range = init_size;
161 table->address = table_start;
162 table->size = table_size;
163 table->link = NULL;
164 table->name = name;
165}
166
167void __init unwind_init(void)
168{
169 init_unwind_table(&root_table, "kernel",
170 _text, _end - _text,
171 NULL, 0,
172 __start_unwind, __end_unwind - __start_unwind);
173}
174
175/* Must be called with module_mutex held. */
176void *unwind_add_table(struct module *module,
177 const void *table_start,
178 unsigned long table_size)
179{
180 struct unwind_table *table;
181
182 if (table_size <= 0)
183 return NULL;
184
185 table = kmalloc(sizeof(*table), GFP_KERNEL);
186 if (!table)
187 return NULL;
188
189 init_unwind_table(table, module->name,
190 module->module_core, module->core_size,
191 module->module_init, module->init_size,
192 table_start, table_size);
193
194 if (last_table)
195 last_table->link = table;
196 else
197 root_table.link = table;
198 last_table = table;
199
200 return table;
201}
202
203struct unlink_table_info
204{
205 struct unwind_table *table;
206 int init_only;
207};
208
209static int unlink_table(void *arg)
210{
211 struct unlink_table_info *info = arg;
212 struct unwind_table *table = info->table, *prev;
213
214 for (prev = &root_table; prev->link && prev->link != table; prev = prev->link)
215 ;
216
217 if (prev->link) {
218 if (info->init_only) {
219 table->init.pc = 0;
220 table->init.range = 0;
221 info->table = NULL;
222 } else {
223 prev->link = table->link;
224 if (!prev->link)
225 last_table = prev;
226 }
227 } else
228 info->table = NULL;
229
230 return 0;
231}
232
233/* Must be called with module_mutex held. */
234void unwind_remove_table(void *handle, int init_only)
235{
236 struct unwind_table *table = handle;
237 struct unlink_table_info info;
238
239 if (!table || table == &root_table)
240 return;
241
242 if (init_only && table == last_table) {
243 table->init.pc = 0;
244 table->init.range = 0;
245 return;
246 }
247
248 info.table = table;
249 info.init_only = init_only;
250 stop_machine_run(unlink_table, &info, NR_CPUS);
251
252 if (info.table)
253 kfree(table);
254}
255
256static uleb128_t get_uleb128(const u8 **pcur, const u8 *end)
257{
258 const u8 *cur = *pcur;
259 uleb128_t value;
260 unsigned shift;
261
262 for (shift = 0, value = 0; cur < end; shift += 7) {
263 if (shift + 7 > 8 * sizeof(value)
264 && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
265 cur = end + 1;
266 break;
267 }
268 value |= (uleb128_t)(*cur & 0x7f) << shift;
269 if (!(*cur++ & 0x80))
270 break;
271 }
272 *pcur = cur;
273
274 return value;
275}
276
277static sleb128_t get_sleb128(const u8 **pcur, const u8 *end)
278{
279 const u8 *cur = *pcur;
280 sleb128_t value;
281 unsigned shift;
282
283 for (shift = 0, value = 0; cur < end; shift += 7) {
284 if (shift + 7 > 8 * sizeof(value)
285 && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
286 cur = end + 1;
287 break;
288 }
289 value |= (sleb128_t)(*cur & 0x7f) << shift;
290 if (!(*cur & 0x80)) {
291 value |= -(*cur++ & 0x40) << shift;
292 break;
293 }
294 }
295 *pcur = cur;
296
297 return value;
298}
299
300static unsigned long read_pointer(const u8 **pLoc,
301 const void *end,
302 signed ptrType)
303{
304 unsigned long value = 0;
305 union {
306 const u8 *p8;
307 const u16 *p16u;
308 const s16 *p16s;
309 const u32 *p32u;
310 const s32 *p32s;
311 const unsigned long *pul;
312 } ptr;
313
314 if (ptrType < 0 || ptrType == DW_EH_PE_omit)
315 return 0;
316 ptr.p8 = *pLoc;
317 switch(ptrType & DW_EH_PE_FORM) {
318 case DW_EH_PE_data2:
319 if (end < (const void *)(ptr.p16u + 1))
320 return 0;
321 if(ptrType & DW_EH_PE_signed)
322 value = get_unaligned(ptr.p16s++);
323 else
324 value = get_unaligned(ptr.p16u++);
325 break;
326 case DW_EH_PE_data4:
327#ifdef CONFIG_64BIT
328 if (end < (const void *)(ptr.p32u + 1))
329 return 0;
330 if(ptrType & DW_EH_PE_signed)
331 value = get_unaligned(ptr.p32s++);
332 else
333 value = get_unaligned(ptr.p32u++);
334 break;
335 case DW_EH_PE_data8:
336 BUILD_BUG_ON(sizeof(u64) != sizeof(value));
337#else
338 BUILD_BUG_ON(sizeof(u32) != sizeof(value));
339#endif
340 case DW_EH_PE_native:
341 if (end < (const void *)(ptr.pul + 1))
342 return 0;
343 value = get_unaligned(ptr.pul++);
344 break;
345 case DW_EH_PE_leb128:
346 BUILD_BUG_ON(sizeof(uleb128_t) > sizeof(value));
347 value = ptrType & DW_EH_PE_signed
348 ? get_sleb128(&ptr.p8, end)
349 : get_uleb128(&ptr.p8, end);
350 if ((const void *)ptr.p8 > end)
351 return 0;
352 break;
353 default:
354 return 0;
355 }
356 switch(ptrType & DW_EH_PE_ADJUST) {
357 case DW_EH_PE_abs:
358 break;
359 case DW_EH_PE_pcrel:
360 value += (unsigned long)*pLoc;
361 break;
362 default:
363 return 0;
364 }
365 if ((ptrType & DW_EH_PE_indirect)
366 && __get_user(value, (unsigned long *)value))
367 return 0;
368 *pLoc = ptr.p8;
369
370 return value;
371}
372
373static signed fde_pointer_type(const u32 *cie)
374{
375 const u8 *ptr = (const u8 *)(cie + 2);
376 unsigned version = *ptr;
377
378 if (version != 1)
379 return -1; /* unsupported */
380 if (*++ptr) {
381 const char *aug;
382 const u8 *end = (const u8 *)(cie + 1) + *cie;
383 uleb128_t len;
384
385 /* check if augmentation size is first (and thus present) */
386 if (*ptr != 'z')
387 return -1;
388 /* check if augmentation string is nul-terminated */
389 if ((ptr = memchr(aug = (const void *)ptr, 0, end - ptr)) == NULL)
390 return -1;
391 ++ptr; /* skip terminator */
392 get_uleb128(&ptr, end); /* skip code alignment */
393 get_sleb128(&ptr, end); /* skip data alignment */
394 /* skip return address column */
395 version <= 1 ? (void)++ptr : (void)get_uleb128(&ptr, end);
396 len = get_uleb128(&ptr, end); /* augmentation length */
397 if (ptr + len < ptr || ptr + len > end)
398 return -1;
399 end = ptr + len;
400 while (*++aug) {
401 if (ptr >= end)
402 return -1;
403 switch(*aug) {
404 case 'L':
405 ++ptr;
406 break;
407 case 'P': {
408 signed ptrType = *ptr++;
409
410 if (!read_pointer(&ptr, end, ptrType) || ptr > end)
411 return -1;
412 }
413 break;
414 case 'R':
415 return *ptr;
416 default:
417 return -1;
418 }
419 }
420 }
421 return DW_EH_PE_native|DW_EH_PE_abs;
422}
423
424static int advance_loc(unsigned long delta, struct unwind_state *state)
425{
426 state->loc += delta * state->codeAlign;
427
428 return delta > 0;
429}
430
431static void set_rule(uleb128_t reg,
432 enum item_location where,
433 uleb128_t value,
434 struct unwind_state *state)
435{
436 if (reg < ARRAY_SIZE(state->regs)) {
437 state->regs[reg].where = where;
438 state->regs[reg].value = value;
439 }
440}
441
442static int processCFI(const u8 *start,
443 const u8 *end,
444 unsigned long targetLoc,
445 signed ptrType,
446 struct unwind_state *state)
447{
448 union {
449 const u8 *p8;
450 const u16 *p16;
451 const u32 *p32;
452 } ptr;
453 int result = 1;
454
455 if (start != state->cieStart) {
456 state->loc = state->org;
457 result = processCFI(state->cieStart, state->cieEnd, 0, ptrType, state);
458 if (targetLoc == 0 && state->label == NULL)
459 return result;
460 }
461 for (ptr.p8 = start; result && ptr.p8 < end; ) {
462 switch(*ptr.p8 >> 6) {
463 uleb128_t value;
464
465 case 0:
466 switch(*ptr.p8++) {
467 case DW_CFA_nop:
468 break;
469 case DW_CFA_set_loc:
470 if ((state->loc = read_pointer(&ptr.p8, end, ptrType)) == 0)
471 result = 0;
472 break;
473 case DW_CFA_advance_loc1:
474 result = ptr.p8 < end && advance_loc(*ptr.p8++, state);
475 break;
476 case DW_CFA_advance_loc2:
477 result = ptr.p8 <= end + 2
478 && advance_loc(*ptr.p16++, state);
479 break;
480 case DW_CFA_advance_loc4:
481 result = ptr.p8 <= end + 4
482 && advance_loc(*ptr.p32++, state);
483 break;
484 case DW_CFA_offset_extended:
485 value = get_uleb128(&ptr.p8, end);
486 set_rule(value, Memory, get_uleb128(&ptr.p8, end), state);
487 break;
488 case DW_CFA_val_offset:
489 value = get_uleb128(&ptr.p8, end);
490 set_rule(value, Value, get_uleb128(&ptr.p8, end), state);
491 break;
492 case DW_CFA_offset_extended_sf:
493 value = get_uleb128(&ptr.p8, end);
494 set_rule(value, Memory, get_sleb128(&ptr.p8, end), state);
495 break;
496 case DW_CFA_val_offset_sf:
497 value = get_uleb128(&ptr.p8, end);
498 set_rule(value, Value, get_sleb128(&ptr.p8, end), state);
499 break;
500 case DW_CFA_restore_extended:
501 case DW_CFA_undefined:
502 case DW_CFA_same_value:
503 set_rule(get_uleb128(&ptr.p8, end), Nowhere, 0, state);
504 break;
505 case DW_CFA_register:
506 value = get_uleb128(&ptr.p8, end);
507 set_rule(value,
508 Register,
509 get_uleb128(&ptr.p8, end), state);
510 break;
511 case DW_CFA_remember_state:
512 if (ptr.p8 == state->label) {
513 state->label = NULL;
514 return 1;
515 }
516 if (state->stackDepth >= MAX_STACK_DEPTH)
517 return 0;
518 state->stack[state->stackDepth++] = ptr.p8;
519 break;
520 case DW_CFA_restore_state:
521 if (state->stackDepth) {
522 const uleb128_t loc = state->loc;
523 const u8 *label = state->label;
524
525 state->label = state->stack[state->stackDepth - 1];
526 memcpy(&state->cfa, &badCFA, sizeof(state->cfa));
527 memset(state->regs, 0, sizeof(state->regs));
528 state->stackDepth = 0;
529 result = processCFI(start, end, 0, ptrType, state);
530 state->loc = loc;
531 state->label = label;
532 } else
533 return 0;
534 break;
535 case DW_CFA_def_cfa:
536 state->cfa.reg = get_uleb128(&ptr.p8, end);
537 /*nobreak*/
538 case DW_CFA_def_cfa_offset:
539 state->cfa.offs = get_uleb128(&ptr.p8, end);
540 break;
541 case DW_CFA_def_cfa_sf:
542 state->cfa.reg = get_uleb128(&ptr.p8, end);
543 /*nobreak*/
544 case DW_CFA_def_cfa_offset_sf:
545 state->cfa.offs = get_sleb128(&ptr.p8, end)
546 * state->dataAlign;
547 break;
548 case DW_CFA_def_cfa_register:
549 state->cfa.reg = get_uleb128(&ptr.p8, end);
550 break;
551 /*todo case DW_CFA_def_cfa_expression: */
552 /*todo case DW_CFA_expression: */
553 /*todo case DW_CFA_val_expression: */
554 case DW_CFA_GNU_args_size:
555 get_uleb128(&ptr.p8, end);
556 break;
557 case DW_CFA_GNU_negative_offset_extended:
558 value = get_uleb128(&ptr.p8, end);
559 set_rule(value,
560 Memory,
561 (uleb128_t)0 - get_uleb128(&ptr.p8, end), state);
562 break;
563 case DW_CFA_GNU_window_save:
564 default:
565 result = 0;
566 break;
567 }
568 break;
569 case 1:
570 result = advance_loc(*ptr.p8++ & 0x3f, state);
571 break;
572 case 2:
573 value = *ptr.p8++ & 0x3f;
574 set_rule(value, Memory, get_uleb128(&ptr.p8, end), state);
575 break;
576 case 3:
577 set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state);
578 break;
579 }
580 if (ptr.p8 > end)
581 result = 0;
582 if (result && targetLoc != 0 && targetLoc < state->loc)
583 return 1;
584 }
585
586 return result
587 && ptr.p8 == end
588 && (targetLoc == 0
589 || (/*todo While in theory this should apply, gcc in practice omits
590 everything past the function prolog, and hence the location
591 never reaches the end of the function.
592 targetLoc < state->loc &&*/ state->label == NULL));
593}
594
595/* Unwind to previous to frame. Returns 0 if successful, negative
596 * number in case of an error. */
597int unwind(struct unwind_frame_info *frame)
598{
599#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
600 const u32 *fde = NULL, *cie = NULL;
601 const u8 *ptr = NULL, *end = NULL;
602 unsigned long startLoc = 0, endLoc = 0, cfa;
603 unsigned i;
604 signed ptrType = -1;
605 uleb128_t retAddrReg = 0;
606 struct unwind_table *table;
607 struct unwind_state state;
608
609 if (UNW_PC(frame) == 0)
610 return -EINVAL;
611 if ((table = find_table(UNW_PC(frame))) != NULL
612 && !(table->size & (sizeof(*fde) - 1))) {
613 unsigned long tableSize = table->size;
614
615 for (fde = table->address;
616 tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde;
617 tableSize -= sizeof(*fde) + *fde,
618 fde += 1 + *fde / sizeof(*fde)) {
619 if (!*fde || (*fde & (sizeof(*fde) - 1)))
620 break;
621 if (!fde[1])
622 continue; /* this is a CIE */
623 if ((fde[1] & (sizeof(*fde) - 1))
624 || fde[1] > (unsigned long)(fde + 1)
625 - (unsigned long)table->address)
626 continue; /* this is not a valid FDE */
627 cie = fde + 1 - fde[1] / sizeof(*fde);
628 if (*cie <= sizeof(*cie) + 4
629 || *cie >= fde[1] - sizeof(*fde)
630 || (*cie & (sizeof(*cie) - 1))
631 || cie[1]
632 || (ptrType = fde_pointer_type(cie)) < 0) {
633 cie = NULL; /* this is not a (valid) CIE */
634 continue;
635 }
636 ptr = (const u8 *)(fde + 2);
637 startLoc = read_pointer(&ptr,
638 (const u8 *)(fde + 1) + *fde,
639 ptrType);
640 endLoc = startLoc
641 + read_pointer(&ptr,
642 (const u8 *)(fde + 1) + *fde,
643 ptrType & DW_EH_PE_indirect
644 ? ptrType
645 : ptrType & (DW_EH_PE_FORM|DW_EH_PE_signed));
646 if (UNW_PC(frame) >= startLoc && UNW_PC(frame) < endLoc)
647 break;
648 cie = NULL;
649 }
650 }
651 if (cie != NULL) {
652 memset(&state, 0, sizeof(state));
653 state.cieEnd = ptr; /* keep here temporarily */
654 ptr = (const u8 *)(cie + 2);
655 end = (const u8 *)(cie + 1) + *cie;
656 if ((state.version = *ptr) != 1)
657 cie = NULL; /* unsupported version */
658 else if (*++ptr) {
659 /* check if augmentation size is first (and thus present) */
660 if (*ptr == 'z') {
661 /* check for ignorable (or already handled)
662 * nul-terminated augmentation string */
663 while (++ptr < end && *ptr)
664 if (strchr("LPR", *ptr) == NULL)
665 break;
666 }
667 if (ptr >= end || *ptr)
668 cie = NULL;
669 }
670 ++ptr;
671 }
672 if (cie != NULL) {
673 /* get code aligment factor */
674 state.codeAlign = get_uleb128(&ptr, end);
675 /* get data aligment factor */
676 state.dataAlign = get_sleb128(&ptr, end);
677 if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end)
678 cie = NULL;
679 else {
680 retAddrReg = state.version <= 1 ? *ptr++ : get_uleb128(&ptr, end);
681 /* skip augmentation */
682 if (((const char *)(cie + 2))[1] == 'z')
683 ptr += get_uleb128(&ptr, end);
684 if (ptr > end
685 || retAddrReg >= ARRAY_SIZE(reg_info)
686 || REG_INVALID(retAddrReg)
687 || reg_info[retAddrReg].width != sizeof(unsigned long))
688 cie = NULL;
689 }
690 }
691 if (cie != NULL) {
692 state.cieStart = ptr;
693 ptr = state.cieEnd;
694 state.cieEnd = end;
695 end = (const u8 *)(fde + 1) + *fde;
696 /* skip augmentation */
697 if (((const char *)(cie + 2))[1] == 'z') {
698 uleb128_t augSize = get_uleb128(&ptr, end);
699
700 if ((ptr += augSize) > end)
701 fde = NULL;
702 }
703 }
704 if (cie == NULL || fde == NULL) {
705#ifdef CONFIG_FRAME_POINTER
706 unsigned long top, bottom;
707#endif
708
709#ifdef CONFIG_FRAME_POINTER
710 top = STACK_TOP(frame->task);
711 bottom = STACK_BOTTOM(frame->task);
712# if FRAME_RETADDR_OFFSET < 0
713 if (UNW_SP(frame) < top
714 && UNW_FP(frame) <= UNW_SP(frame)
715 && bottom < UNW_FP(frame)
716# else
717 if (UNW_SP(frame) > top
718 && UNW_FP(frame) >= UNW_SP(frame)
719 && bottom > UNW_FP(frame)
720# endif
721 && !((UNW_SP(frame) | UNW_FP(frame))
722 & (sizeof(unsigned long) - 1))) {
723 unsigned long link;
724
725 if (!__get_user(link,
726 (unsigned long *)(UNW_FP(frame)
727 + FRAME_LINK_OFFSET))
728# if FRAME_RETADDR_OFFSET < 0
729 && link > bottom && link < UNW_FP(frame)
730# else
731 && link > UNW_FP(frame) && link < bottom
732# endif
733 && !(link & (sizeof(link) - 1))
734 && !__get_user(UNW_PC(frame),
735 (unsigned long *)(UNW_FP(frame)
736 + FRAME_RETADDR_OFFSET))) {
737 UNW_SP(frame) = UNW_FP(frame) + FRAME_RETADDR_OFFSET
738# if FRAME_RETADDR_OFFSET < 0
739 -
740# else
741 +
742# endif
743 sizeof(UNW_PC(frame));
744 UNW_FP(frame) = link;
745 return 0;
746 }
747 }
748#endif
749 return -ENXIO;
750 }
751 state.org = startLoc;
752 memcpy(&state.cfa, &badCFA, sizeof(state.cfa));
753 /* process instructions */
754 if (!processCFI(ptr, end, UNW_PC(frame), ptrType, &state)
755 || state.loc > endLoc
756 || state.regs[retAddrReg].where == Nowhere
757 || state.cfa.reg >= ARRAY_SIZE(reg_info)
758 || reg_info[state.cfa.reg].width != sizeof(unsigned long)
759 || state.cfa.offs % sizeof(unsigned long))
760 return -EIO;
761 /* update frame */
762 cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs;
763 startLoc = min((unsigned long)UNW_SP(frame), cfa);
764 endLoc = max((unsigned long)UNW_SP(frame), cfa);
765 if (STACK_LIMIT(startLoc) != STACK_LIMIT(endLoc)) {
766 startLoc = min(STACK_LIMIT(cfa), cfa);
767 endLoc = max(STACK_LIMIT(cfa), cfa);
768 }
769#ifndef CONFIG_64BIT
770# define CASES CASE(8); CASE(16); CASE(32)
771#else
772# define CASES CASE(8); CASE(16); CASE(32); CASE(64)
773#endif
774 for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
775 if (REG_INVALID(i)) {
776 if (state.regs[i].where == Nowhere)
777 continue;
778 return -EIO;
779 }
780 switch(state.regs[i].where) {
781 default:
782 break;
783 case Register:
784 if (state.regs[i].value >= ARRAY_SIZE(reg_info)
785 || REG_INVALID(state.regs[i].value)
786 || reg_info[i].width > reg_info[state.regs[i].value].width)
787 return -EIO;
788 switch(reg_info[state.regs[i].value].width) {
789#define CASE(n) \
790 case sizeof(u##n): \
791 state.regs[i].value = FRAME_REG(state.regs[i].value, \
792 const u##n); \
793 break
794 CASES;
795#undef CASE
796 default:
797 return -EIO;
798 }
799 break;
800 }
801 }
802 for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
803 if (REG_INVALID(i))
804 continue;
805 switch(state.regs[i].where) {
806 case Nowhere:
807 if (reg_info[i].width != sizeof(UNW_SP(frame))
808 || &FRAME_REG(i, __typeof__(UNW_SP(frame)))
809 != &UNW_SP(frame))
810 continue;
811 UNW_SP(frame) = cfa;
812 break;
813 case Register:
814 switch(reg_info[i].width) {
815#define CASE(n) case sizeof(u##n): \
816 FRAME_REG(i, u##n) = state.regs[i].value; \
817 break
818 CASES;
819#undef CASE
820 default:
821 return -EIO;
822 }
823 break;
824 case Value:
825 if (reg_info[i].width != sizeof(unsigned long))
826 return -EIO;
827 FRAME_REG(i, unsigned long) = cfa + state.regs[i].value
828 * state.dataAlign;
829 break;
830 case Memory: {
831 unsigned long addr = cfa + state.regs[i].value
832 * state.dataAlign;
833
834 if ((state.regs[i].value * state.dataAlign)
835 % sizeof(unsigned long)
836 || addr < startLoc
837 || addr + sizeof(unsigned long) < addr
838 || addr + sizeof(unsigned long) > endLoc)
839 return -EIO;
840 switch(reg_info[i].width) {
841#define CASE(n) case sizeof(u##n): \
842 __get_user(FRAME_REG(i, u##n), (u##n *)addr); \
843 break
844 CASES;
845#undef CASE
846 default:
847 return -EIO;
848 }
849 }
850 break;
851 }
852 }
853
854 return 0;
855#undef CASES
856#undef FRAME_REG
857}
858EXPORT_SYMBOL(unwind);
859
860int unwind_init_frame_info(struct unwind_frame_info *info,
861 struct task_struct *tsk,
862 /*const*/ struct pt_regs *regs)
863{
864 info->task = tsk;
865 arch_unw_init_frame_info(info, regs);
866
867 return 0;
868}
869EXPORT_SYMBOL(unwind_init_frame_info);
870
871/*
872 * Prepare to unwind a blocked task.
873 */
874int unwind_init_blocked(struct unwind_frame_info *info,
875 struct task_struct *tsk)
876{
877 info->task = tsk;
878 arch_unw_init_blocked(info);
879
880 return 0;
881}
882EXPORT_SYMBOL(unwind_init_blocked);
883
884/*
885 * Prepare to unwind the currently running thread.
886 */
887int unwind_init_running(struct unwind_frame_info *info,
888 asmlinkage void (*callback)(struct unwind_frame_info *,
889 void *arg),
890 void *arg)
891{
892 info->task = current;
893 arch_unwind_init_running(info, callback, arg);
894
895 return 0;
896}
897EXPORT_SYMBOL(unwind_init_running);
898
899/*
900 * Unwind until the return pointer is in user-land (or until an error
901 * occurs). Returns 0 if successful, negative number in case of
902 * error.
903 */
904int unwind_to_user(struct unwind_frame_info *info)
905{
906 while (!arch_unw_user_mode(info)) {
907 int err = unwind(info);
908
909 if (err < 0)
910 return err;
911 }
912
913 return 0;
914}
915EXPORT_SYMBOL(unwind_to_user);