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.
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.
12 #include <linux/unwind.h>
13 #include <linux/module.h>
14 #include <linux/bootmem.h>
15 #include <linux/sort.h>
16 #include <linux/stop_machine.h>
17 #include <asm/sections.h>
18 #include <asm/uaccess.h>
19 #include <asm/unaligned.h>
21 extern char __start_unwind
[], __end_unwind
[];
22 extern const u8 __start_unwind_hdr
[], __end_unwind_hdr
[];
24 #define MAX_STACK_DEPTH 8
26 #define EXTRA_INFO(f) { \
27 BUILD_BUG_ON_ZERO(offsetof(struct unwind_frame_info, f) \
28 % FIELD_SIZEOF(struct unwind_frame_info, f)) \
29 + offsetof(struct unwind_frame_info, f) \
30 / FIELD_SIZEOF(struct unwind_frame_info, f), \
31 FIELD_SIZEOF(struct unwind_frame_info, f) \
33 #define PTREGS_INFO(f) EXTRA_INFO(regs.f)
36 unsigned offs
:BITS_PER_LONG
/ 2;
37 unsigned width
:BITS_PER_LONG
/ 2;
46 #define REG_INVALID(r) (reg_info[r].width == 0)
49 #define DW_CFA_nop 0x00
50 #define DW_CFA_set_loc 0x01
51 #define DW_CFA_advance_loc1 0x02
52 #define DW_CFA_advance_loc2 0x03
53 #define DW_CFA_advance_loc4 0x04
54 #define DW_CFA_offset_extended 0x05
55 #define DW_CFA_restore_extended 0x06
56 #define DW_CFA_undefined 0x07
57 #define DW_CFA_same_value 0x08
58 #define DW_CFA_register 0x09
59 #define DW_CFA_remember_state 0x0a
60 #define DW_CFA_restore_state 0x0b
61 #define DW_CFA_def_cfa 0x0c
62 #define DW_CFA_def_cfa_register 0x0d
63 #define DW_CFA_def_cfa_offset 0x0e
64 #define DW_CFA_def_cfa_expression 0x0f
65 #define DW_CFA_expression 0x10
66 #define DW_CFA_offset_extended_sf 0x11
67 #define DW_CFA_def_cfa_sf 0x12
68 #define DW_CFA_def_cfa_offset_sf 0x13
69 #define DW_CFA_val_offset 0x14
70 #define DW_CFA_val_offset_sf 0x15
71 #define DW_CFA_val_expression 0x16
72 #define DW_CFA_lo_user 0x1c
73 #define DW_CFA_GNU_window_save 0x2d
74 #define DW_CFA_GNU_args_size 0x2e
75 #define DW_CFA_GNU_negative_offset_extended 0x2f
76 #define DW_CFA_hi_user 0x3f
78 #define DW_EH_PE_FORM 0x07
79 #define DW_EH_PE_native 0x00
80 #define DW_EH_PE_leb128 0x01
81 #define DW_EH_PE_data2 0x02
82 #define DW_EH_PE_data4 0x03
83 #define DW_EH_PE_data8 0x04
84 #define DW_EH_PE_signed 0x08
85 #define DW_EH_PE_ADJUST 0x70
86 #define DW_EH_PE_abs 0x00
87 #define DW_EH_PE_pcrel 0x10
88 #define DW_EH_PE_textrel 0x20
89 #define DW_EH_PE_datarel 0x30
90 #define DW_EH_PE_funcrel 0x40
91 #define DW_EH_PE_aligned 0x50
92 #define DW_EH_PE_indirect 0x80
93 #define DW_EH_PE_omit 0xff
95 typedef unsigned long uleb128_t
;
96 typedef signed long sleb128_t
;
98 static struct unwind_table
{
105 const unsigned char *header
;
107 struct unwind_table
*link
;
121 struct unwind_state
{
123 const u8
*cieStart
, *cieEnd
;
129 struct unwind_item regs
[ARRAY_SIZE(reg_info
)];
130 unsigned stackDepth
:8;
133 const u8
*stack
[MAX_STACK_DEPTH
];
136 static const struct cfa badCFA
= { ARRAY_SIZE(reg_info
), 1 };
138 static struct unwind_table
*find_table(unsigned long pc
)
140 struct unwind_table
*table
;
142 for (table
= &root_table
; table
; table
= table
->link
)
143 if ((pc
>= table
->core
.pc
144 && pc
< table
->core
.pc
+ table
->core
.range
)
145 || (pc
>= table
->init
.pc
146 && pc
< table
->init
.pc
+ table
->init
.range
))
152 static unsigned long read_pointer(const u8
**pLoc
,
156 static void init_unwind_table(struct unwind_table
*table
,
158 const void *core_start
,
159 unsigned long core_size
,
160 const void *init_start
,
161 unsigned long init_size
,
162 const void *table_start
,
163 unsigned long table_size
,
164 const u8
*header_start
,
165 unsigned long header_size
)
167 const u8
*ptr
= header_start
+ 4;
168 const u8
*end
= header_start
+ header_size
;
170 table
->core
.pc
= (unsigned long)core_start
;
171 table
->core
.range
= core_size
;
172 table
->init
.pc
= (unsigned long)init_start
;
173 table
->init
.range
= init_size
;
174 table
->address
= table_start
;
175 table
->size
= table_size
;
176 /* See if the linker provided table looks valid. */
178 || header_start
[0] != 1
179 || (void *)read_pointer(&ptr
, end
, header_start
[1]) != table_start
180 || header_start
[2] == DW_EH_PE_omit
181 || read_pointer(&ptr
, end
, header_start
[2]) <= 0
182 || header_start
[3] == DW_EH_PE_omit
)
184 table
->hdrsz
= header_size
;
186 table
->header
= header_start
;
191 void __init
unwind_init(void)
193 init_unwind_table(&root_table
, "kernel",
196 __start_unwind
, __end_unwind
- __start_unwind
,
197 __start_unwind_hdr
, __end_unwind_hdr
- __start_unwind_hdr
);
200 static const u32 bad_cie
, not_fde
;
201 static const u32
*cie_for_fde(const u32
*fde
, const struct unwind_table
*);
202 static signed fde_pointer_type(const u32
*cie
);
204 struct eh_frame_hdr_table_entry
{
205 unsigned long start
, fde
;
208 static int cmp_eh_frame_hdr_table_entries(const void *p1
, const void *p2
)
210 const struct eh_frame_hdr_table_entry
*e1
= p1
;
211 const struct eh_frame_hdr_table_entry
*e2
= p2
;
213 return (e1
->start
> e2
->start
) - (e1
->start
< e2
->start
);
216 static void swap_eh_frame_hdr_table_entries(void *p1
, void *p2
, int size
)
218 struct eh_frame_hdr_table_entry
*e1
= p1
;
219 struct eh_frame_hdr_table_entry
*e2
= p2
;
223 e1
->start
= e2
->start
;
230 static void __init
setup_unwind_table(struct unwind_table
*table
,
231 void *(*alloc
)(unsigned long))
234 unsigned long tableSize
= table
->size
, hdrSize
;
242 unsigned long eh_frame_ptr
;
243 unsigned int fde_count
;
244 struct eh_frame_hdr_table_entry table
[];
245 } __attribute__((__packed__
)) *header
;
251 printk(KERN_WARNING
".eh_frame_hdr for '%s' present but unusable\n",
254 if (tableSize
& (sizeof(*fde
) - 1))
257 for (fde
= table
->address
, n
= 0;
258 tableSize
> sizeof(*fde
) && tableSize
- sizeof(*fde
) >= *fde
;
259 tableSize
-= sizeof(*fde
) + *fde
, fde
+= 1 + *fde
/ sizeof(*fde
)) {
260 const u32
*cie
= cie_for_fde(fde
, table
);
267 || (ptrType
= fde_pointer_type(cie
)) < 0)
269 ptr
= (const u8
*)(fde
+ 2);
270 if (!read_pointer(&ptr
,
271 (const u8
*)(fde
+ 1) + *fde
,
280 hdrSize
= 4 + sizeof(unsigned long) + sizeof(unsigned int)
281 + 2 * n
* sizeof(unsigned long);
282 header
= alloc(hdrSize
);
286 header
->eh_frame_ptr_enc
= DW_EH_PE_abs
|DW_EH_PE_native
;
287 header
->fde_count_enc
= DW_EH_PE_abs
|DW_EH_PE_data4
;
288 header
->table_enc
= DW_EH_PE_abs
|DW_EH_PE_native
;
289 put_unaligned((unsigned long)table
->address
, &header
->eh_frame_ptr
);
290 BUILD_BUG_ON(offsetof(typeof(*header
), fde_count
)
291 % __alignof(typeof(header
->fde_count
)));
292 header
->fde_count
= n
;
294 BUILD_BUG_ON(offsetof(typeof(*header
), table
)
295 % __alignof(typeof(*header
->table
)));
296 for (fde
= table
->address
, tableSize
= table
->size
, n
= 0;
298 tableSize
-= sizeof(*fde
) + *fde
, fde
+= 1 + *fde
/ sizeof(*fde
)) {
299 const u32
*cie
= fde
+ 1 - fde
[1] / sizeof(*fde
);
302 continue; /* this is a CIE */
303 ptr
= (const u8
*)(fde
+ 2);
304 header
->table
[n
].start
= read_pointer(&ptr
,
305 (const u8
*)(fde
+ 1) + *fde
,
306 fde_pointer_type(cie
));
307 header
->table
[n
].fde
= (unsigned long)fde
;
310 WARN_ON(n
!= header
->fde_count
);
314 sizeof(*header
->table
),
315 cmp_eh_frame_hdr_table_entries
,
316 swap_eh_frame_hdr_table_entries
);
318 table
->hdrsz
= hdrSize
;
320 table
->header
= (const void *)header
;
323 static void *__init
balloc(unsigned long sz
)
325 return __alloc_bootmem_nopanic(sz
,
326 sizeof(unsigned int),
327 __pa(MAX_DMA_ADDRESS
));
330 void __init
unwind_setup(void)
332 setup_unwind_table(&root_table
, balloc
);
335 #ifdef CONFIG_MODULES
337 static struct unwind_table
*last_table
;
339 /* Must be called with module_mutex held. */
340 void *unwind_add_table(struct module
*module
,
341 const void *table_start
,
342 unsigned long table_size
)
344 struct unwind_table
*table
;
349 table
= kmalloc(sizeof(*table
), GFP_KERNEL
);
353 init_unwind_table(table
, module
->name
,
354 module
->module_core
, module
->core_size
,
355 module
->module_init
, module
->init_size
,
356 table_start
, table_size
,
360 last_table
->link
= table
;
362 root_table
.link
= table
;
368 struct unlink_table_info
370 struct unwind_table
*table
;
374 static int unlink_table(void *arg
)
376 struct unlink_table_info
*info
= arg
;
377 struct unwind_table
*table
= info
->table
, *prev
;
379 for (prev
= &root_table
; prev
->link
&& prev
->link
!= table
; prev
= prev
->link
)
383 if (info
->init_only
) {
385 table
->init
.range
= 0;
388 prev
->link
= table
->link
;
398 /* Must be called with module_mutex held. */
399 void unwind_remove_table(void *handle
, int init_only
)
401 struct unwind_table
*table
= handle
;
402 struct unlink_table_info info
;
404 if (!table
|| table
== &root_table
)
407 if (init_only
&& table
== last_table
) {
409 table
->init
.range
= 0;
414 info
.init_only
= init_only
;
415 stop_machine_run(unlink_table
, &info
, NR_CPUS
);
421 #endif /* CONFIG_MODULES */
423 static uleb128_t
get_uleb128(const u8
**pcur
, const u8
*end
)
425 const u8
*cur
= *pcur
;
429 for (shift
= 0, value
= 0; cur
< end
; shift
+= 7) {
430 if (shift
+ 7 > 8 * sizeof(value
)
431 && (*cur
& 0x7fU
) >= (1U << (8 * sizeof(value
) - shift
))) {
435 value
|= (uleb128_t
)(*cur
& 0x7f) << shift
;
436 if (!(*cur
++ & 0x80))
444 static sleb128_t
get_sleb128(const u8
**pcur
, const u8
*end
)
446 const u8
*cur
= *pcur
;
450 for (shift
= 0, value
= 0; cur
< end
; shift
+= 7) {
451 if (shift
+ 7 > 8 * sizeof(value
)
452 && (*cur
& 0x7fU
) >= (1U << (8 * sizeof(value
) - shift
))) {
456 value
|= (sleb128_t
)(*cur
& 0x7f) << shift
;
457 if (!(*cur
& 0x80)) {
458 value
|= -(*cur
++ & 0x40) << shift
;
467 static const u32
*cie_for_fde(const u32
*fde
, const struct unwind_table
*table
)
471 if (!*fde
|| (*fde
& (sizeof(*fde
) - 1)))
474 return ¬_fde
; /* this is a CIE */
475 if ((fde
[1] & (sizeof(*fde
) - 1))
476 || fde
[1] > (unsigned long)(fde
+ 1) - (unsigned long)table
->address
)
477 return NULL
; /* this is not a valid FDE */
478 cie
= fde
+ 1 - fde
[1] / sizeof(*fde
);
479 if (*cie
<= sizeof(*cie
) + 4
480 || *cie
>= fde
[1] - sizeof(*fde
)
481 || (*cie
& (sizeof(*cie
) - 1))
483 return NULL
; /* this is not a (valid) CIE */
487 static unsigned long read_pointer(const u8
**pLoc
,
491 unsigned long value
= 0;
498 const unsigned long *pul
;
501 if (ptrType
< 0 || ptrType
== DW_EH_PE_omit
)
504 switch(ptrType
& DW_EH_PE_FORM
) {
506 if (end
< (const void *)(ptr
.p16u
+ 1))
508 if(ptrType
& DW_EH_PE_signed
)
509 value
= get_unaligned(ptr
.p16s
++);
511 value
= get_unaligned(ptr
.p16u
++);
515 if (end
< (const void *)(ptr
.p32u
+ 1))
517 if(ptrType
& DW_EH_PE_signed
)
518 value
= get_unaligned(ptr
.p32s
++);
520 value
= get_unaligned(ptr
.p32u
++);
523 BUILD_BUG_ON(sizeof(u64
) != sizeof(value
));
525 BUILD_BUG_ON(sizeof(u32
) != sizeof(value
));
527 case DW_EH_PE_native
:
528 if (end
< (const void *)(ptr
.pul
+ 1))
530 value
= get_unaligned(ptr
.pul
++);
532 case DW_EH_PE_leb128
:
533 BUILD_BUG_ON(sizeof(uleb128_t
) > sizeof(value
));
534 value
= ptrType
& DW_EH_PE_signed
535 ? get_sleb128(&ptr
.p8
, end
)
536 : get_uleb128(&ptr
.p8
, end
);
537 if ((const void *)ptr
.p8
> end
)
543 switch(ptrType
& DW_EH_PE_ADJUST
) {
547 value
+= (unsigned long)*pLoc
;
552 if ((ptrType
& DW_EH_PE_indirect
)
553 && __get_user(value
, (unsigned long *)value
))
560 static signed fde_pointer_type(const u32
*cie
)
562 const u8
*ptr
= (const u8
*)(cie
+ 2);
563 unsigned version
= *ptr
;
566 return -1; /* unsupported */
569 const u8
*end
= (const u8
*)(cie
+ 1) + *cie
;
572 /* check if augmentation size is first (and thus present) */
575 /* check if augmentation string is nul-terminated */
576 if ((ptr
= memchr(aug
= (const void *)ptr
, 0, end
- ptr
)) == NULL
)
578 ++ptr
; /* skip terminator */
579 get_uleb128(&ptr
, end
); /* skip code alignment */
580 get_sleb128(&ptr
, end
); /* skip data alignment */
581 /* skip return address column */
582 version
<= 1 ? (void)++ptr
: (void)get_uleb128(&ptr
, end
);
583 len
= get_uleb128(&ptr
, end
); /* augmentation length */
584 if (ptr
+ len
< ptr
|| ptr
+ len
> end
)
595 signed ptrType
= *ptr
++;
597 if (!read_pointer(&ptr
, end
, ptrType
) || ptr
> end
)
608 return DW_EH_PE_native
|DW_EH_PE_abs
;
611 static int advance_loc(unsigned long delta
, struct unwind_state
*state
)
613 state
->loc
+= delta
* state
->codeAlign
;
618 static void set_rule(uleb128_t reg
,
619 enum item_location where
,
621 struct unwind_state
*state
)
623 if (reg
< ARRAY_SIZE(state
->regs
)) {
624 state
->regs
[reg
].where
= where
;
625 state
->regs
[reg
].value
= value
;
629 static int processCFI(const u8
*start
,
631 unsigned long targetLoc
,
633 struct unwind_state
*state
)
642 if (start
!= state
->cieStart
) {
643 state
->loc
= state
->org
;
644 result
= processCFI(state
->cieStart
, state
->cieEnd
, 0, ptrType
, state
);
645 if (targetLoc
== 0 && state
->label
== NULL
)
648 for (ptr
.p8
= start
; result
&& ptr
.p8
< end
; ) {
649 switch(*ptr
.p8
>> 6) {
657 if ((state
->loc
= read_pointer(&ptr
.p8
, end
, ptrType
)) == 0)
660 case DW_CFA_advance_loc1
:
661 result
= ptr
.p8
< end
&& advance_loc(*ptr
.p8
++, state
);
663 case DW_CFA_advance_loc2
:
664 result
= ptr
.p8
<= end
+ 2
665 && advance_loc(*ptr
.p16
++, state
);
667 case DW_CFA_advance_loc4
:
668 result
= ptr
.p8
<= end
+ 4
669 && advance_loc(*ptr
.p32
++, state
);
671 case DW_CFA_offset_extended
:
672 value
= get_uleb128(&ptr
.p8
, end
);
673 set_rule(value
, Memory
, get_uleb128(&ptr
.p8
, end
), state
);
675 case DW_CFA_val_offset
:
676 value
= get_uleb128(&ptr
.p8
, end
);
677 set_rule(value
, Value
, get_uleb128(&ptr
.p8
, end
), state
);
679 case DW_CFA_offset_extended_sf
:
680 value
= get_uleb128(&ptr
.p8
, end
);
681 set_rule(value
, Memory
, get_sleb128(&ptr
.p8
, end
), state
);
683 case DW_CFA_val_offset_sf
:
684 value
= get_uleb128(&ptr
.p8
, end
);
685 set_rule(value
, Value
, get_sleb128(&ptr
.p8
, end
), state
);
687 case DW_CFA_restore_extended
:
688 case DW_CFA_undefined
:
689 case DW_CFA_same_value
:
690 set_rule(get_uleb128(&ptr
.p8
, end
), Nowhere
, 0, state
);
692 case DW_CFA_register
:
693 value
= get_uleb128(&ptr
.p8
, end
);
696 get_uleb128(&ptr
.p8
, end
), state
);
698 case DW_CFA_remember_state
:
699 if (ptr
.p8
== state
->label
) {
703 if (state
->stackDepth
>= MAX_STACK_DEPTH
)
705 state
->stack
[state
->stackDepth
++] = ptr
.p8
;
707 case DW_CFA_restore_state
:
708 if (state
->stackDepth
) {
709 const uleb128_t loc
= state
->loc
;
710 const u8
*label
= state
->label
;
712 state
->label
= state
->stack
[state
->stackDepth
- 1];
713 memcpy(&state
->cfa
, &badCFA
, sizeof(state
->cfa
));
714 memset(state
->regs
, 0, sizeof(state
->regs
));
715 state
->stackDepth
= 0;
716 result
= processCFI(start
, end
, 0, ptrType
, state
);
718 state
->label
= label
;
723 state
->cfa
.reg
= get_uleb128(&ptr
.p8
, end
);
725 case DW_CFA_def_cfa_offset
:
726 state
->cfa
.offs
= get_uleb128(&ptr
.p8
, end
);
728 case DW_CFA_def_cfa_sf
:
729 state
->cfa
.reg
= get_uleb128(&ptr
.p8
, end
);
731 case DW_CFA_def_cfa_offset_sf
:
732 state
->cfa
.offs
= get_sleb128(&ptr
.p8
, end
)
735 case DW_CFA_def_cfa_register
:
736 state
->cfa
.reg
= get_uleb128(&ptr
.p8
, end
);
738 /*todo case DW_CFA_def_cfa_expression: */
739 /*todo case DW_CFA_expression: */
740 /*todo case DW_CFA_val_expression: */
741 case DW_CFA_GNU_args_size
:
742 get_uleb128(&ptr
.p8
, end
);
744 case DW_CFA_GNU_negative_offset_extended
:
745 value
= get_uleb128(&ptr
.p8
, end
);
748 (uleb128_t
)0 - get_uleb128(&ptr
.p8
, end
), state
);
750 case DW_CFA_GNU_window_save
:
757 result
= advance_loc(*ptr
.p8
++ & 0x3f, state
);
760 value
= *ptr
.p8
++ & 0x3f;
761 set_rule(value
, Memory
, get_uleb128(&ptr
.p8
, end
), state
);
764 set_rule(*ptr
.p8
++ & 0x3f, Nowhere
, 0, state
);
769 if (result
&& targetLoc
!= 0 && targetLoc
< state
->loc
)
776 || (/*todo While in theory this should apply, gcc in practice omits
777 everything past the function prolog, and hence the location
778 never reaches the end of the function.
779 targetLoc < state->loc &&*/ state
->label
== NULL
));
782 /* Unwind to previous to frame. Returns 0 if successful, negative
783 * number in case of an error. */
784 int unwind(struct unwind_frame_info
*frame
)
786 #define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
787 const u32
*fde
= NULL
, *cie
= NULL
;
788 const u8
*ptr
= NULL
, *end
= NULL
;
789 unsigned long pc
= UNW_PC(frame
) - frame
->call_frame
;
790 unsigned long startLoc
= 0, endLoc
= 0, cfa
;
793 uleb128_t retAddrReg
= 0;
794 const struct unwind_table
*table
;
795 struct unwind_state state
;
797 if (UNW_PC(frame
) == 0)
799 if ((table
= find_table(pc
)) != NULL
800 && !(table
->size
& (sizeof(*fde
) - 1))) {
801 const u8
*hdr
= table
->header
;
802 unsigned long tableSize
;
805 if (hdr
&& hdr
[0] == 1) {
806 switch(hdr
[3] & DW_EH_PE_FORM
) {
807 case DW_EH_PE_native
: tableSize
= sizeof(unsigned long); break;
808 case DW_EH_PE_data2
: tableSize
= 2; break;
809 case DW_EH_PE_data4
: tableSize
= 4; break;
810 case DW_EH_PE_data8
: tableSize
= 8; break;
811 default: tableSize
= 0; break;
814 end
= hdr
+ table
->hdrsz
;
816 && read_pointer(&ptr
, end
, hdr
[1])
817 == (unsigned long)table
->address
818 && (i
= read_pointer(&ptr
, end
, hdr
[2])) > 0
819 && i
== (end
- ptr
) / (2 * tableSize
)
820 && !((end
- ptr
) % (2 * tableSize
))) {
822 const u8
*cur
= ptr
+ (i
/ 2) * (2 * tableSize
);
824 startLoc
= read_pointer(&cur
,
830 ptr
= cur
- tableSize
;
833 } while (startLoc
&& i
> 1);
835 && (startLoc
= read_pointer(&ptr
,
839 fde
= (void *)read_pointer(&ptr
,
846 cie
= cie_for_fde(fde
, table
);
847 ptr
= (const u8
*)(fde
+ 2);
851 && (ptrType
= fde_pointer_type(cie
)) >= 0
852 && read_pointer(&ptr
,
853 (const u8
*)(fde
+ 1) + *fde
,
854 ptrType
) == startLoc
) {
855 if (!(ptrType
& DW_EH_PE_indirect
))
856 ptrType
&= DW_EH_PE_FORM
|DW_EH_PE_signed
;
859 (const u8
*)(fde
+ 1) + *fde
,
867 for (fde
= table
->address
, tableSize
= table
->size
;
868 cie
= NULL
, tableSize
> sizeof(*fde
)
869 && tableSize
- sizeof(*fde
) >= *fde
;
870 tableSize
-= sizeof(*fde
) + *fde
,
871 fde
+= 1 + *fde
/ sizeof(*fde
)) {
872 cie
= cie_for_fde(fde
, table
);
873 if (cie
== &bad_cie
) {
879 || (ptrType
= fde_pointer_type(cie
)) < 0)
881 ptr
= (const u8
*)(fde
+ 2);
882 startLoc
= read_pointer(&ptr
,
883 (const u8
*)(fde
+ 1) + *fde
,
887 if (!(ptrType
& DW_EH_PE_indirect
))
888 ptrType
&= DW_EH_PE_FORM
|DW_EH_PE_signed
;
891 (const u8
*)(fde
+ 1) + *fde
,
893 if (pc
>= startLoc
&& pc
< endLoc
)
899 memset(&state
, 0, sizeof(state
));
900 state
.cieEnd
= ptr
; /* keep here temporarily */
901 ptr
= (const u8
*)(cie
+ 2);
902 end
= (const u8
*)(cie
+ 1) + *cie
;
903 frame
->call_frame
= 1;
904 if ((state
.version
= *ptr
) != 1)
905 cie
= NULL
; /* unsupported version */
907 /* check if augmentation size is first (and thus present) */
909 while (++ptr
< end
&& *ptr
) {
911 /* check for ignorable (or already handled)
912 * nul-terminated augmentation string */
918 frame
->call_frame
= 0;
926 if (ptr
>= end
|| *ptr
)
932 /* get code aligment factor */
933 state
.codeAlign
= get_uleb128(&ptr
, end
);
934 /* get data aligment factor */
935 state
.dataAlign
= get_sleb128(&ptr
, end
);
936 if (state
.codeAlign
== 0 || state
.dataAlign
== 0 || ptr
>= end
)
939 retAddrReg
= state
.version
<= 1 ? *ptr
++ : get_uleb128(&ptr
, end
);
940 /* skip augmentation */
941 if (((const char *)(cie
+ 2))[1] == 'z') {
942 uleb128_t augSize
= get_uleb128(&ptr
, end
);
947 || retAddrReg
>= ARRAY_SIZE(reg_info
)
948 || REG_INVALID(retAddrReg
)
949 || reg_info
[retAddrReg
].width
!= sizeof(unsigned long))
954 state
.cieStart
= ptr
;
957 end
= (const u8
*)(fde
+ 1) + *fde
;
958 /* skip augmentation */
959 if (((const char *)(cie
+ 2))[1] == 'z') {
960 uleb128_t augSize
= get_uleb128(&ptr
, end
);
962 if ((ptr
+= augSize
) > end
)
966 if (cie
== NULL
|| fde
== NULL
) {
967 #ifdef CONFIG_FRAME_POINTER
968 unsigned long top
, bottom
;
970 top
= STACK_TOP(frame
->task
);
971 bottom
= STACK_BOTTOM(frame
->task
);
972 # if FRAME_RETADDR_OFFSET < 0
973 if (UNW_SP(frame
) < top
974 && UNW_FP(frame
) <= UNW_SP(frame
)
975 && bottom
< UNW_FP(frame
)
977 if (UNW_SP(frame
) > top
978 && UNW_FP(frame
) >= UNW_SP(frame
)
979 && bottom
> UNW_FP(frame
)
981 && !((UNW_SP(frame
) | UNW_FP(frame
))
982 & (sizeof(unsigned long) - 1))) {
985 if (!__get_user(link
,
986 (unsigned long *)(UNW_FP(frame
)
987 + FRAME_LINK_OFFSET
))
988 # if FRAME_RETADDR_OFFSET < 0
989 && link
> bottom
&& link
< UNW_FP(frame
)
991 && link
> UNW_FP(frame
) && link
< bottom
993 && !(link
& (sizeof(link
) - 1))
994 && !__get_user(UNW_PC(frame
),
995 (unsigned long *)(UNW_FP(frame
)
996 + FRAME_RETADDR_OFFSET
))) {
997 UNW_SP(frame
) = UNW_FP(frame
) + FRAME_RETADDR_OFFSET
998 # if FRAME_RETADDR_OFFSET < 0
1003 sizeof(UNW_PC(frame
));
1004 UNW_FP(frame
) = link
;
1011 state
.org
= startLoc
;
1012 memcpy(&state
.cfa
, &badCFA
, sizeof(state
.cfa
));
1013 /* process instructions */
1014 if (!processCFI(ptr
, end
, pc
, ptrType
, &state
)
1015 || state
.loc
> endLoc
1016 || state
.regs
[retAddrReg
].where
== Nowhere
1017 || state
.cfa
.reg
>= ARRAY_SIZE(reg_info
)
1018 || reg_info
[state
.cfa
.reg
].width
!= sizeof(unsigned long)
1019 || state
.cfa
.offs
% sizeof(unsigned long))
1022 #ifndef CONFIG_AS_CFI_SIGNAL_FRAME
1023 if(frame
->call_frame
1024 && !UNW_DEFAULT_RA(state
.regs
[retAddrReg
], state
.dataAlign
))
1025 frame
->call_frame
= 0;
1027 cfa
= FRAME_REG(state
.cfa
.reg
, unsigned long) + state
.cfa
.offs
;
1028 startLoc
= min((unsigned long)UNW_SP(frame
), cfa
);
1029 endLoc
= max((unsigned long)UNW_SP(frame
), cfa
);
1030 if (STACK_LIMIT(startLoc
) != STACK_LIMIT(endLoc
)) {
1031 startLoc
= min(STACK_LIMIT(cfa
), cfa
);
1032 endLoc
= max(STACK_LIMIT(cfa
), cfa
);
1034 #ifndef CONFIG_64BIT
1035 # define CASES CASE(8); CASE(16); CASE(32)
1037 # define CASES CASE(8); CASE(16); CASE(32); CASE(64)
1039 for (i
= 0; i
< ARRAY_SIZE(state
.regs
); ++i
) {
1040 if (REG_INVALID(i
)) {
1041 if (state
.regs
[i
].where
== Nowhere
)
1045 switch(state
.regs
[i
].where
) {
1049 if (state
.regs
[i
].value
>= ARRAY_SIZE(reg_info
)
1050 || REG_INVALID(state
.regs
[i
].value
)
1051 || reg_info
[i
].width
> reg_info
[state
.regs
[i
].value
].width
)
1053 switch(reg_info
[state
.regs
[i
].value
].width
) {
1055 case sizeof(u##n): \
1056 state.regs[i].value = FRAME_REG(state.regs[i].value, \
1067 for (i
= 0; i
< ARRAY_SIZE(state
.regs
); ++i
) {
1070 switch(state
.regs
[i
].where
) {
1072 if (reg_info
[i
].width
!= sizeof(UNW_SP(frame
))
1073 || &FRAME_REG(i
, __typeof__(UNW_SP(frame
)))
1076 UNW_SP(frame
) = cfa
;
1079 switch(reg_info
[i
].width
) {
1080 #define CASE(n) case sizeof(u##n): \
1081 FRAME_REG(i, u##n) = state.regs[i].value; \
1090 if (reg_info
[i
].width
!= sizeof(unsigned long))
1092 FRAME_REG(i
, unsigned long) = cfa
+ state
.regs
[i
].value
1096 unsigned long addr
= cfa
+ state
.regs
[i
].value
1099 if ((state
.regs
[i
].value
* state
.dataAlign
)
1100 % sizeof(unsigned long)
1102 || addr
+ sizeof(unsigned long) < addr
1103 || addr
+ sizeof(unsigned long) > endLoc
)
1105 switch(reg_info
[i
].width
) {
1106 #define CASE(n) case sizeof(u##n): \
1107 __get_user(FRAME_REG(i, u##n), (u##n *)addr); \
1123 EXPORT_SYMBOL(unwind
);
1125 int unwind_init_frame_info(struct unwind_frame_info
*info
,
1126 struct task_struct
*tsk
,
1127 /*const*/ struct pt_regs
*regs
)
1130 info
->call_frame
= 0;
1131 arch_unw_init_frame_info(info
, regs
);
1135 EXPORT_SYMBOL(unwind_init_frame_info
);
1138 * Prepare to unwind a blocked task.
1140 int unwind_init_blocked(struct unwind_frame_info
*info
,
1141 struct task_struct
*tsk
)
1144 info
->call_frame
= 0;
1145 arch_unw_init_blocked(info
);
1149 EXPORT_SYMBOL(unwind_init_blocked
);
1152 * Prepare to unwind the currently running thread.
1154 int unwind_init_running(struct unwind_frame_info
*info
,
1155 asmlinkage
int (*callback
)(struct unwind_frame_info
*,
1159 info
->task
= current
;
1160 info
->call_frame
= 0;
1162 return arch_unwind_init_running(info
, callback
, arg
);
1164 EXPORT_SYMBOL(unwind_init_running
);
1167 * Unwind until the return pointer is in user-land (or until an error
1168 * occurs). Returns 0 if successful, negative number in case of
1171 int unwind_to_user(struct unwind_frame_info
*info
)
1173 while (!arch_unw_user_mode(info
)) {
1174 int err
= unwind(info
);
1182 EXPORT_SYMBOL(unwind_to_user
);