2 * Copyright (C) 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
3 * Copyright (C) 2002-2006 Novell, Inc.
4 * Jan Beulich <jbeulich@novell.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * A simple API for unwinding kernel stacks. This is used for
11 * debugging and error reporting purposes. The kernel doesn't need
12 * full-blown stack unwinding with all the bells and whistles, so there
13 * is not much point in implementing the full Dwarf2 unwind API.
16 #include <linux/sched.h>
17 #include <linux/module.h>
18 #include <linux/bootmem.h>
19 #include <linux/sort.h>
20 #include <linux/slab.h>
21 #include <linux/stop_machine.h>
22 #include <linux/uaccess.h>
23 #include <linux/ptrace.h>
24 #include <asm/sections.h>
25 #include <asm/unaligned.h>
26 #include <asm/unwind.h>
28 extern char __start_unwind
[], __end_unwind
[];
29 /* extern const u8 __start_unwind_hdr[], __end_unwind_hdr[];*/
31 /* #define UNWIND_DEBUG */
35 #define unw_debug(fmt, ...) \
38 pr_info(fmt, ##__VA_ARGS__); \
41 #define unw_debug(fmt, ...)
44 #define MAX_STACK_DEPTH 8
46 #define EXTRA_INFO(f) { \
47 BUILD_BUG_ON_ZERO(offsetof(struct unwind_frame_info, f) \
48 % FIELD_SIZEOF(struct unwind_frame_info, f)) \
49 + offsetof(struct unwind_frame_info, f) \
50 / FIELD_SIZEOF(struct unwind_frame_info, f), \
51 FIELD_SIZEOF(struct unwind_frame_info, f) \
53 #define PTREGS_INFO(f) EXTRA_INFO(regs.f)
56 unsigned offs
:BITS_PER_LONG
/ 2;
57 unsigned width
:BITS_PER_LONG
/ 2;
65 #define REG_INVALID(r) (reg_info[r].width == 0)
68 #define DW_CFA_nop 0x00
69 #define DW_CFA_set_loc 0x01
70 #define DW_CFA_advance_loc1 0x02
71 #define DW_CFA_advance_loc2 0x03
72 #define DW_CFA_advance_loc4 0x04
73 #define DW_CFA_offset_extended 0x05
74 #define DW_CFA_restore_extended 0x06
75 #define DW_CFA_undefined 0x07
76 #define DW_CFA_same_value 0x08
77 #define DW_CFA_register 0x09
78 #define DW_CFA_remember_state 0x0a
79 #define DW_CFA_restore_state 0x0b
80 #define DW_CFA_def_cfa 0x0c
81 #define DW_CFA_def_cfa_register 0x0d
82 #define DW_CFA_def_cfa_offset 0x0e
83 #define DW_CFA_def_cfa_expression 0x0f
84 #define DW_CFA_expression 0x10
85 #define DW_CFA_offset_extended_sf 0x11
86 #define DW_CFA_def_cfa_sf 0x12
87 #define DW_CFA_def_cfa_offset_sf 0x13
88 #define DW_CFA_val_offset 0x14
89 #define DW_CFA_val_offset_sf 0x15
90 #define DW_CFA_val_expression 0x16
91 #define DW_CFA_lo_user 0x1c
92 #define DW_CFA_GNU_window_save 0x2d
93 #define DW_CFA_GNU_args_size 0x2e
94 #define DW_CFA_GNU_negative_offset_extended 0x2f
95 #define DW_CFA_hi_user 0x3f
97 #define DW_EH_PE_FORM 0x07
98 #define DW_EH_PE_native 0x00
99 #define DW_EH_PE_leb128 0x01
100 #define DW_EH_PE_data2 0x02
101 #define DW_EH_PE_data4 0x03
102 #define DW_EH_PE_data8 0x04
103 #define DW_EH_PE_signed 0x08
104 #define DW_EH_PE_ADJUST 0x70
105 #define DW_EH_PE_abs 0x00
106 #define DW_EH_PE_pcrel 0x10
107 #define DW_EH_PE_textrel 0x20
108 #define DW_EH_PE_datarel 0x30
109 #define DW_EH_PE_funcrel 0x40
110 #define DW_EH_PE_aligned 0x50
111 #define DW_EH_PE_indirect 0x80
112 #define DW_EH_PE_omit 0xff
114 typedef unsigned long uleb128_t
;
115 typedef signed long sleb128_t
;
117 static struct unwind_table
{
124 const unsigned char *header
;
126 struct unwind_table
*link
;
140 struct unwind_state
{
142 const u8
*cieStart
, *cieEnd
;
148 struct unwind_item regs
[ARRAY_SIZE(reg_info
)];
149 unsigned stackDepth
:8;
152 const u8
*stack
[MAX_STACK_DEPTH
];
155 static const struct cfa badCFA
= { ARRAY_SIZE(reg_info
), 1 };
157 static struct unwind_table
*find_table(unsigned long pc
)
159 struct unwind_table
*table
;
161 for (table
= &root_table
; table
; table
= table
->link
)
162 if ((pc
>= table
->core
.pc
163 && pc
< table
->core
.pc
+ table
->core
.range
)
164 || (pc
>= table
->init
.pc
165 && pc
< table
->init
.pc
+ table
->init
.range
))
171 static unsigned long read_pointer(const u8
**pLoc
,
172 const void *end
, signed ptrType
);
174 static void init_unwind_table(struct unwind_table
*table
, const char *name
,
175 const void *core_start
, unsigned long core_size
,
176 const void *init_start
, unsigned long init_size
,
177 const void *table_start
, unsigned long table_size
,
178 const u8
*header_start
, unsigned long header_size
)
180 const u8
*ptr
= header_start
+ 4;
181 const u8
*end
= header_start
+ header_size
;
183 table
->core
.pc
= (unsigned long)core_start
;
184 table
->core
.range
= core_size
;
185 table
->init
.pc
= (unsigned long)init_start
;
186 table
->init
.range
= init_size
;
187 table
->address
= table_start
;
188 table
->size
= table_size
;
190 /* See if the linker provided table looks valid. */
192 || header_start
[0] != 1
193 || (void *)read_pointer(&ptr
, end
, header_start
[1]) != table_start
194 || header_start
[2] == DW_EH_PE_omit
195 || read_pointer(&ptr
, end
, header_start
[2]) <= 0
196 || header_start
[3] == DW_EH_PE_omit
)
199 table
->hdrsz
= header_size
;
201 table
->header
= header_start
;
206 void __init
arc_unwind_init(void)
208 init_unwind_table(&root_table
, "kernel", _text
, _end
- _text
, NULL
, 0,
209 __start_unwind
, __end_unwind
- __start_unwind
,
211 /*__start_unwind_hdr, __end_unwind_hdr - __start_unwind_hdr);*/
214 static const u32 bad_cie
, not_fde
;
215 static const u32
*cie_for_fde(const u32
*fde
, const struct unwind_table
*);
216 static signed fde_pointer_type(const u32
*cie
);
218 struct eh_frame_hdr_table_entry
{
219 unsigned long start
, fde
;
222 static int cmp_eh_frame_hdr_table_entries(const void *p1
, const void *p2
)
224 const struct eh_frame_hdr_table_entry
*e1
= p1
;
225 const struct eh_frame_hdr_table_entry
*e2
= p2
;
227 return (e1
->start
> e2
->start
) - (e1
->start
< e2
->start
);
230 static void swap_eh_frame_hdr_table_entries(void *p1
, void *p2
, int size
)
232 struct eh_frame_hdr_table_entry
*e1
= p1
;
233 struct eh_frame_hdr_table_entry
*e2
= p2
;
237 e1
->start
= e2
->start
;
244 static void __init
setup_unwind_table(struct unwind_table
*table
,
245 void *(*alloc
) (unsigned long))
248 unsigned long tableSize
= table
->size
, hdrSize
;
256 unsigned long eh_frame_ptr
;
257 unsigned int fde_count
;
258 struct eh_frame_hdr_table_entry table
[];
259 } __attribute__ ((__packed__
)) *header
;
265 pr_warn(".eh_frame_hdr for '%s' present but unusable\n",
268 if (tableSize
& (sizeof(*fde
) - 1))
271 for (fde
= table
->address
, n
= 0;
272 tableSize
> sizeof(*fde
) && tableSize
- sizeof(*fde
) >= *fde
;
273 tableSize
-= sizeof(*fde
) + *fde
, fde
+= 1 + *fde
/ sizeof(*fde
)) {
274 const u32
*cie
= cie_for_fde(fde
, table
);
279 if (cie
== NULL
|| cie
== &bad_cie
)
281 ptrType
= fde_pointer_type(cie
);
285 ptr
= (const u8
*)(fde
+ 2);
286 if (!read_pointer(&ptr
, (const u8
*)(fde
+ 1) + *fde
,
288 /* FIXME_Rajesh We have 4 instances of null addresses
289 * instead of the initial loc addr
299 hdrSize
= 4 + sizeof(unsigned long) + sizeof(unsigned int)
300 + 2 * n
* sizeof(unsigned long);
301 header
= alloc(hdrSize
);
305 header
->eh_frame_ptr_enc
= DW_EH_PE_abs
| DW_EH_PE_native
;
306 header
->fde_count_enc
= DW_EH_PE_abs
| DW_EH_PE_data4
;
307 header
->table_enc
= DW_EH_PE_abs
| DW_EH_PE_native
;
308 put_unaligned((unsigned long)table
->address
, &header
->eh_frame_ptr
);
309 BUILD_BUG_ON(offsetof(typeof(*header
), fde_count
)
310 % __alignof(typeof(header
->fde_count
)));
311 header
->fde_count
= n
;
313 BUILD_BUG_ON(offsetof(typeof(*header
), table
)
314 % __alignof(typeof(*header
->table
)));
315 for (fde
= table
->address
, tableSize
= table
->size
, n
= 0;
317 tableSize
-= sizeof(*fde
) + *fde
, fde
+= 1 + *fde
/ sizeof(*fde
)) {
318 /* const u32 *cie = fde + 1 - fde[1] / sizeof(*fde); */
319 const u32
*cie
= (const u32
*)(fde
[1]);
321 if (fde
[1] == 0xffffffff)
322 continue; /* this is a CIE */
323 ptr
= (const u8
*)(fde
+ 2);
324 header
->table
[n
].start
= read_pointer(&ptr
,
325 (const u8
*)(fde
+ 1) +
327 fde_pointer_type(cie
));
328 header
->table
[n
].fde
= (unsigned long)fde
;
331 WARN_ON(n
!= header
->fde_count
);
335 sizeof(*header
->table
),
336 cmp_eh_frame_hdr_table_entries
, swap_eh_frame_hdr_table_entries
);
338 table
->hdrsz
= hdrSize
;
340 table
->header
= (const void *)header
;
343 static void *__init
balloc(unsigned long sz
)
345 return __alloc_bootmem_nopanic(sz
,
346 sizeof(unsigned int),
347 __pa(MAX_DMA_ADDRESS
));
350 void __init
arc_unwind_setup(void)
352 setup_unwind_table(&root_table
, balloc
);
355 #ifdef CONFIG_MODULES
357 static struct unwind_table
*last_table
;
359 /* Must be called with module_mutex held. */
360 void *unwind_add_table(struct module
*module
, const void *table_start
,
361 unsigned long table_size
)
363 struct unwind_table
*table
;
368 table
= kmalloc(sizeof(*table
), GFP_KERNEL
);
372 init_unwind_table(table
, module
->name
,
373 module
->module_core
, module
->core_size
,
374 module
->module_init
, module
->init_size
,
375 table_start
, table_size
,
379 unw_debug("Table added for [%s] %lx %lx\n",
380 module
->name
, table
->core
.pc
, table
->core
.range
);
383 last_table
->link
= table
;
385 root_table
.link
= table
;
391 struct unlink_table_info
{
392 struct unwind_table
*table
;
396 static int unlink_table(void *arg
)
398 struct unlink_table_info
*info
= arg
;
399 struct unwind_table
*table
= info
->table
, *prev
;
401 for (prev
= &root_table
; prev
->link
&& prev
->link
!= table
;
406 if (info
->init_only
) {
408 table
->init
.range
= 0;
411 prev
->link
= table
->link
;
421 /* Must be called with module_mutex held. */
422 void unwind_remove_table(void *handle
, int init_only
)
424 struct unwind_table
*table
= handle
;
425 struct unlink_table_info info
;
427 if (!table
|| table
== &root_table
)
430 if (init_only
&& table
== last_table
) {
432 table
->init
.range
= 0;
437 info
.init_only
= init_only
;
439 unlink_table(&info
); /* XXX: SMP */
443 #endif /* CONFIG_MODULES */
445 static uleb128_t
get_uleb128(const u8
**pcur
, const u8
*end
)
447 const u8
*cur
= *pcur
;
451 for (shift
= 0, value
= 0; cur
< end
; shift
+= 7) {
452 if (shift
+ 7 > 8 * sizeof(value
)
453 && (*cur
& 0x7fU
) >= (1U << (8 * sizeof(value
) - shift
))) {
457 value
|= (uleb128_t
) (*cur
& 0x7f) << shift
;
458 if (!(*cur
++ & 0x80))
466 static sleb128_t
get_sleb128(const u8
**pcur
, const u8
*end
)
468 const u8
*cur
= *pcur
;
472 for (shift
= 0, value
= 0; cur
< end
; shift
+= 7) {
473 if (shift
+ 7 > 8 * sizeof(value
)
474 && (*cur
& 0x7fU
) >= (1U << (8 * sizeof(value
) - shift
))) {
478 value
|= (sleb128_t
) (*cur
& 0x7f) << shift
;
479 if (!(*cur
& 0x80)) {
480 value
|= -(*cur
++ & 0x40) << shift
;
489 static const u32
*cie_for_fde(const u32
*fde
, const struct unwind_table
*table
)
493 if (!*fde
|| (*fde
& (sizeof(*fde
) - 1)))
496 if (fde
[1] == 0xffffffff)
497 return ¬_fde
; /* this is a CIE */
499 if ((fde
[1] & (sizeof(*fde
) - 1)))
500 /* || fde[1] > (unsigned long)(fde + 1) - (unsigned long)table->address) */
501 return NULL
; /* this is not a valid FDE */
503 /* cie = fde + 1 - fde[1] / sizeof(*fde); */
504 cie
= (u32
*) fde
[1];
506 if (*cie
<= sizeof(*cie
) + 4 || *cie
>= fde
[1] - sizeof(*fde
)
507 || (*cie
& (sizeof(*cie
) - 1))
508 || (cie
[1] != 0xffffffff))
509 return NULL
; /* this is not a (valid) CIE */
513 static unsigned long read_pointer(const u8
**pLoc
, const void *end
,
516 unsigned long value
= 0;
523 const unsigned long *pul
;
526 if (ptrType
< 0 || ptrType
== DW_EH_PE_omit
)
529 switch (ptrType
& DW_EH_PE_FORM
) {
531 if (end
< (const void *)(ptr
.p16u
+ 1))
533 if (ptrType
& DW_EH_PE_signed
)
534 value
= get_unaligned((u16
*) ptr
.p16s
++);
536 value
= get_unaligned((u16
*) ptr
.p16u
++);
540 if (end
< (const void *)(ptr
.p32u
+ 1))
542 if (ptrType
& DW_EH_PE_signed
)
543 value
= get_unaligned(ptr
.p32s
++);
545 value
= get_unaligned(ptr
.p32u
++);
548 BUILD_BUG_ON(sizeof(u64
) != sizeof(value
));
550 BUILD_BUG_ON(sizeof(u32
) != sizeof(value
));
552 case DW_EH_PE_native
:
553 if (end
< (const void *)(ptr
.pul
+ 1))
555 value
= get_unaligned((unsigned long *)ptr
.pul
++);
557 case DW_EH_PE_leb128
:
558 BUILD_BUG_ON(sizeof(uleb128_t
) > sizeof(value
));
559 value
= ptrType
& DW_EH_PE_signed
? get_sleb128(&ptr
.p8
, end
)
560 : get_uleb128(&ptr
.p8
, end
);
561 if ((const void *)ptr
.p8
> end
)
567 switch (ptrType
& DW_EH_PE_ADJUST
) {
571 value
+= (unsigned long)*pLoc
;
576 if ((ptrType
& DW_EH_PE_indirect
)
577 && __get_user(value
, (unsigned long __user
*)value
))
584 static signed fde_pointer_type(const u32
*cie
)
586 const u8
*ptr
= (const u8
*)(cie
+ 2);
587 unsigned version
= *ptr
;
590 return -1; /* unsupported */
594 const u8
*end
= (const u8
*)(cie
+ 1) + *cie
;
597 /* check if augmentation size is first (and thus present) */
601 /* check if augmentation string is nul-terminated */
602 aug
= (const void *)ptr
;
603 ptr
= memchr(aug
, 0, end
- ptr
);
607 ++ptr
; /* skip terminator */
608 get_uleb128(&ptr
, end
); /* skip code alignment */
609 get_sleb128(&ptr
, end
); /* skip data alignment */
610 /* skip return address column */
611 version
<= 1 ? (void) ++ptr
: (void)get_uleb128(&ptr
, end
);
612 len
= get_uleb128(&ptr
, end
); /* augmentation length */
614 if (ptr
+ len
< ptr
|| ptr
+ len
> end
)
626 signed ptrType
= *ptr
++;
628 if (!read_pointer(&ptr
, end
, ptrType
)
640 return DW_EH_PE_native
| DW_EH_PE_abs
;
643 static int advance_loc(unsigned long delta
, struct unwind_state
*state
)
645 state
->loc
+= delta
* state
->codeAlign
;
647 /* FIXME_Rajesh: Probably we are defining for the initial range as well;
650 unw_debug("delta %3lu => loc 0x%lx: ", delta
, state
->loc
);
654 static void set_rule(uleb128_t reg
, enum item_location where
, uleb128_t value
,
655 struct unwind_state
*state
)
657 if (reg
< ARRAY_SIZE(state
->regs
)) {
658 state
->regs
[reg
].where
= where
;
659 state
->regs
[reg
].value
= value
;
662 unw_debug("r%lu: ", reg
);
668 unw_debug("c(%lu) ", value
);
671 unw_debug("r(%lu) ", value
);
674 unw_debug("v(%lu) ", value
);
683 static int processCFI(const u8
*start
, const u8
*end
, unsigned long targetLoc
,
684 signed ptrType
, struct unwind_state
*state
)
694 if (start
!= state
->cieStart
) {
695 state
->loc
= state
->org
;
697 processCFI(state
->cieStart
, state
->cieEnd
, 0, ptrType
,
699 if (targetLoc
== 0 && state
->label
== NULL
)
702 for (ptr
.p8
= start
; result
&& ptr
.p8
< end
;) {
703 switch (*ptr
.p8
>> 6) {
711 unw_debug("cfa nop ");
714 state
->loc
= read_pointer(&ptr
.p8
, end
,
718 unw_debug("cfa_set_loc: 0x%lx ", state
->loc
);
720 case DW_CFA_advance_loc1
:
721 unw_debug("\ncfa advance loc1:");
722 result
= ptr
.p8
< end
723 && advance_loc(*ptr
.p8
++, state
);
725 case DW_CFA_advance_loc2
:
727 value
+= *ptr
.p8
++ << 8;
728 unw_debug("\ncfa advance loc2:");
729 result
= ptr
.p8
<= end
+ 2
730 /* && advance_loc(*ptr.p16++, state); */
731 && advance_loc(value
, state
);
733 case DW_CFA_advance_loc4
:
734 unw_debug("\ncfa advance loc4:");
735 result
= ptr
.p8
<= end
+ 4
736 && advance_loc(*ptr
.p32
++, state
);
738 case DW_CFA_offset_extended
:
739 value
= get_uleb128(&ptr
.p8
, end
);
740 unw_debug("cfa_offset_extended: ");
741 set_rule(value
, Memory
,
742 get_uleb128(&ptr
.p8
, end
), state
);
744 case DW_CFA_val_offset
:
745 value
= get_uleb128(&ptr
.p8
, end
);
746 set_rule(value
, Value
,
747 get_uleb128(&ptr
.p8
, end
), state
);
749 case DW_CFA_offset_extended_sf
:
750 value
= get_uleb128(&ptr
.p8
, end
);
751 set_rule(value
, Memory
,
752 get_sleb128(&ptr
.p8
, end
), state
);
754 case DW_CFA_val_offset_sf
:
755 value
= get_uleb128(&ptr
.p8
, end
);
756 set_rule(value
, Value
,
757 get_sleb128(&ptr
.p8
, end
), state
);
759 case DW_CFA_restore_extended
:
760 unw_debug("cfa_restore_extended: ");
761 case DW_CFA_undefined
:
762 unw_debug("cfa_undefined: ");
763 case DW_CFA_same_value
:
764 unw_debug("cfa_same_value: ");
765 set_rule(get_uleb128(&ptr
.p8
, end
), Nowhere
, 0,
768 case DW_CFA_register
:
769 unw_debug("cfa_register: ");
770 value
= get_uleb128(&ptr
.p8
, end
);
773 get_uleb128(&ptr
.p8
, end
), state
);
775 case DW_CFA_remember_state
:
776 unw_debug("cfa_remember_state: ");
777 if (ptr
.p8
== state
->label
) {
781 if (state
->stackDepth
>= MAX_STACK_DEPTH
)
783 state
->stack
[state
->stackDepth
++] = ptr
.p8
;
785 case DW_CFA_restore_state
:
786 unw_debug("cfa_restore_state: ");
787 if (state
->stackDepth
) {
788 const uleb128_t loc
= state
->loc
;
789 const u8
*label
= state
->label
;
792 state
->stack
[state
->stackDepth
- 1];
793 memcpy(&state
->cfa
, &badCFA
,
795 memset(state
->regs
, 0,
796 sizeof(state
->regs
));
797 state
->stackDepth
= 0;
799 processCFI(start
, end
, 0, ptrType
,
802 state
->label
= label
;
807 state
->cfa
.reg
= get_uleb128(&ptr
.p8
, end
);
808 unw_debug("cfa_def_cfa: r%lu ", state
->cfa
.reg
);
810 case DW_CFA_def_cfa_offset
:
811 state
->cfa
.offs
= get_uleb128(&ptr
.p8
, end
);
812 unw_debug("cfa_def_cfa_offset: 0x%lx ",
815 case DW_CFA_def_cfa_sf
:
816 state
->cfa
.reg
= get_uleb128(&ptr
.p8
, end
);
818 case DW_CFA_def_cfa_offset_sf
:
819 state
->cfa
.offs
= get_sleb128(&ptr
.p8
, end
)
822 case DW_CFA_def_cfa_register
:
823 unw_debug("cfa_def_cfa_regsiter: ");
824 state
->cfa
.reg
= get_uleb128(&ptr
.p8
, end
);
826 /*todo case DW_CFA_def_cfa_expression: */
827 /*todo case DW_CFA_expression: */
828 /*todo case DW_CFA_val_expression: */
829 case DW_CFA_GNU_args_size
:
830 get_uleb128(&ptr
.p8
, end
);
832 case DW_CFA_GNU_negative_offset_extended
:
833 value
= get_uleb128(&ptr
.p8
, end
);
836 (uleb128_t
) 0 - get_uleb128(&ptr
.p8
,
840 case DW_CFA_GNU_window_save
:
842 unw_debug("UNKNOW OPCODE 0x%x\n", opcode
);
848 unw_debug("\ncfa_adv_loc: ");
849 result
= advance_loc(*ptr
.p8
++ & 0x3f, state
);
852 unw_debug("cfa_offset: ");
853 value
= *ptr
.p8
++ & 0x3f;
854 set_rule(value
, Memory
, get_uleb128(&ptr
.p8
, end
),
858 unw_debug("cfa_restore: ");
859 set_rule(*ptr
.p8
++ & 0x3f, Nowhere
, 0, state
);
865 if (result
&& targetLoc
!= 0 && targetLoc
< state
->loc
)
869 return result
&& ptr
.p8
== end
&& (targetLoc
== 0 || (
870 /*todo While in theory this should apply, gcc in practice omits
871 everything past the function prolog, and hence the location
872 never reaches the end of the function.
873 targetLoc < state->loc && */ state
->label
== NULL
));
876 /* Unwind to previous to frame. Returns 0 if successful, negative
877 * number in case of an error. */
878 int arc_unwind(struct unwind_frame_info
*frame
)
880 #define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
881 const u32
*fde
= NULL
, *cie
= NULL
;
882 const u8
*ptr
= NULL
, *end
= NULL
;
883 unsigned long pc
= UNW_PC(frame
) - frame
->call_frame
;
884 unsigned long startLoc
= 0, endLoc
= 0, cfa
;
887 uleb128_t retAddrReg
= 0;
888 const struct unwind_table
*table
;
889 struct unwind_state state
;
893 unw_debug("\n\nUNWIND FRAME:\n");
894 unw_debug("PC: 0x%lx BLINK: 0x%lx, SP: 0x%lx, FP: 0x%x\n",
895 UNW_PC(frame
), UNW_BLINK(frame
), UNW_SP(frame
),
898 if (UNW_PC(frame
) == 0)
903 unsigned long *sptr
= (unsigned long *)UNW_SP(frame
);
904 unw_debug("\nStack Dump:\n");
905 for (i
= 0; i
< 20; i
++, sptr
++)
906 unw_debug("0x%p: 0x%lx\n", sptr
, *sptr
);
911 table
= find_table(pc
);
913 && !(table
->size
& (sizeof(*fde
) - 1))) {
914 const u8
*hdr
= table
->header
;
915 unsigned long tableSize
;
918 if (hdr
&& hdr
[0] == 1) {
919 switch (hdr
[3] & DW_EH_PE_FORM
) {
920 case DW_EH_PE_native
:
921 tableSize
= sizeof(unsigned long);
937 end
= hdr
+ table
->hdrsz
;
938 if (tableSize
&& read_pointer(&ptr
, end
, hdr
[1])
939 == (unsigned long)table
->address
940 && (i
= read_pointer(&ptr
, end
, hdr
[2])) > 0
941 && i
== (end
- ptr
) / (2 * tableSize
)
942 && !((end
- ptr
) % (2 * tableSize
))) {
945 ptr
+ (i
/ 2) * (2 * tableSize
);
947 startLoc
= read_pointer(&cur
,
953 ptr
= cur
- tableSize
;
956 } while (startLoc
&& i
> 1);
958 && (startLoc
= read_pointer(&ptr
,
962 fde
= (void *)read_pointer(&ptr
,
970 cie
= cie_for_fde(fde
, table
);
971 ptr
= (const u8
*)(fde
+ 2);
975 && (ptrType
= fde_pointer_type(cie
)) >= 0
976 && read_pointer(&ptr
,
977 (const u8
*)(fde
+ 1) + *fde
,
978 ptrType
) == startLoc
) {
979 if (!(ptrType
& DW_EH_PE_indirect
))
981 DW_EH_PE_FORM
| DW_EH_PE_signed
;
983 startLoc
+ read_pointer(&ptr
,
993 for (fde
= table
->address
, tableSize
= table
->size
;
994 cie
= NULL
, tableSize
> sizeof(*fde
)
995 && tableSize
- sizeof(*fde
) >= *fde
;
996 tableSize
-= sizeof(*fde
) + *fde
,
997 fde
+= 1 + *fde
/ sizeof(*fde
)) {
998 cie
= cie_for_fde(fde
, table
);
999 if (cie
== &bad_cie
) {
1005 || (ptrType
= fde_pointer_type(cie
)) < 0)
1007 ptr
= (const u8
*)(fde
+ 2);
1008 startLoc
= read_pointer(&ptr
,
1009 (const u8
*)(fde
+ 1) +
1013 if (!(ptrType
& DW_EH_PE_indirect
))
1015 DW_EH_PE_FORM
| DW_EH_PE_signed
;
1017 startLoc
+ read_pointer(&ptr
,
1021 if (pc
>= startLoc
&& pc
< endLoc
)
1027 memset(&state
, 0, sizeof(state
));
1028 state
.cieEnd
= ptr
; /* keep here temporarily */
1029 ptr
= (const u8
*)(cie
+ 2);
1030 end
= (const u8
*)(cie
+ 1) + *cie
;
1031 frame
->call_frame
= 1;
1032 if ((state
.version
= *ptr
) != 1)
1033 cie
= NULL
; /* unsupported version */
1035 /* check if augmentation size is first (thus present) */
1037 while (++ptr
< end
&& *ptr
) {
1039 /* chk for ignorable or already handled
1040 * nul-terminated augmentation string */
1046 frame
->call_frame
= 0;
1054 if (ptr
>= end
|| *ptr
)
1060 /* get code aligment factor */
1061 state
.codeAlign
= get_uleb128(&ptr
, end
);
1062 /* get data aligment factor */
1063 state
.dataAlign
= get_sleb128(&ptr
, end
);
1064 if (state
.codeAlign
== 0 || state
.dataAlign
== 0 || ptr
>= end
)
1068 state
.version
<= 1 ? *ptr
++ : get_uleb128(&ptr
,
1070 unw_debug("CIE Frame Info:\n");
1071 unw_debug("return Address register 0x%lx\n",
1073 unw_debug("data Align: %ld\n", state
.dataAlign
);
1074 unw_debug("code Align: %lu\n", state
.codeAlign
);
1075 /* skip augmentation */
1076 if (((const char *)(cie
+ 2))[1] == 'z') {
1077 uleb128_t augSize
= get_uleb128(&ptr
, end
);
1081 if (ptr
> end
|| retAddrReg
>= ARRAY_SIZE(reg_info
)
1082 || REG_INVALID(retAddrReg
)
1083 || reg_info
[retAddrReg
].width
!=
1084 sizeof(unsigned long))
1089 state
.cieStart
= ptr
;
1092 end
= (const u8
*)(fde
+ 1) + *fde
;
1093 /* skip augmentation */
1094 if (((const char *)(cie
+ 2))[1] == 'z') {
1095 uleb128_t augSize
= get_uleb128(&ptr
, end
);
1097 if ((ptr
+= augSize
) > end
)
1101 if (cie
== NULL
|| fde
== NULL
) {
1102 #ifdef CONFIG_FRAME_POINTER
1103 unsigned long top
, bottom
;
1105 top
= STACK_TOP_UNW(frame
->task
);
1106 bottom
= STACK_BOTTOM_UNW(frame
->task
);
1107 #if FRAME_RETADDR_OFFSET < 0
1108 if (UNW_SP(frame
) < top
&& UNW_FP(frame
) <= UNW_SP(frame
)
1109 && bottom
< UNW_FP(frame
)
1111 if (UNW_SP(frame
) > top
&& UNW_FP(frame
) >= UNW_SP(frame
)
1112 && bottom
> UNW_FP(frame
)
1114 && !((UNW_SP(frame
) | UNW_FP(frame
))
1115 & (sizeof(unsigned long) - 1))) {
1118 if (!__get_user(link
, (unsigned long *)
1119 (UNW_FP(frame
) + FRAME_LINK_OFFSET
))
1120 #if FRAME_RETADDR_OFFSET < 0
1121 && link
> bottom
&& link
< UNW_FP(frame
)
1123 && link
> UNW_FP(frame
) && link
< bottom
1125 && !(link
& (sizeof(link
) - 1))
1126 && !__get_user(UNW_PC(frame
),
1127 (unsigned long *)(UNW_FP(frame
)
1128 + FRAME_RETADDR_OFFSET
)))
1131 UNW_FP(frame
) + FRAME_RETADDR_OFFSET
1132 #if FRAME_RETADDR_OFFSET < 0
1137 sizeof(UNW_PC(frame
));
1138 UNW_FP(frame
) = link
;
1145 state
.org
= startLoc
;
1146 memcpy(&state
.cfa
, &badCFA
, sizeof(state
.cfa
));
1148 unw_debug("\nProcess instructions\n");
1150 /* process instructions
1151 * For ARC, we optimize by having blink(retAddrReg) with
1152 * the sameValue in the leaf function, so we should not check
1153 * state.regs[retAddrReg].where == Nowhere
1155 if (!processCFI(ptr
, end
, pc
, ptrType
, &state
)
1156 || state
.loc
> endLoc
1157 /* || state.regs[retAddrReg].where == Nowhere */
1158 || state
.cfa
.reg
>= ARRAY_SIZE(reg_info
)
1159 || reg_info
[state
.cfa
.reg
].width
!= sizeof(unsigned long)
1160 || state
.cfa
.offs
% sizeof(unsigned long))
1166 unw_debug("\nRegister State Based on the rules parsed from FDE:\n");
1167 for (i
= 0; i
< ARRAY_SIZE(state
.regs
); ++i
) {
1172 switch (state
.regs
[i
].where
) {
1176 unw_debug(" r%d: c(%lu),", i
, state
.regs
[i
].value
);
1179 unw_debug(" r%d: r(%lu),", i
, state
.regs
[i
].value
);
1182 unw_debug(" r%d: v(%lu),", i
, state
.regs
[i
].value
);
1191 #ifndef CONFIG_AS_CFI_SIGNAL_FRAME
1192 if (frame
->call_frame
1193 && !UNW_DEFAULT_RA(state
.regs
[retAddrReg
], state
.dataAlign
))
1194 frame
->call_frame
= 0;
1196 cfa
= FRAME_REG(state
.cfa
.reg
, unsigned long) + state
.cfa
.offs
;
1197 startLoc
= min_t(unsigned long, UNW_SP(frame
), cfa
);
1198 endLoc
= max_t(unsigned long, UNW_SP(frame
), cfa
);
1199 if (STACK_LIMIT(startLoc
) != STACK_LIMIT(endLoc
)) {
1200 startLoc
= min(STACK_LIMIT(cfa
), cfa
);
1201 endLoc
= max(STACK_LIMIT(cfa
), cfa
);
1204 unw_debug("\nCFA reg: 0x%lx, offset: 0x%lx => 0x%lx\n",
1205 state
.cfa
.reg
, state
.cfa
.offs
, cfa
);
1207 for (i
= 0; i
< ARRAY_SIZE(state
.regs
); ++i
) {
1208 if (REG_INVALID(i
)) {
1209 if (state
.regs
[i
].where
== Nowhere
)
1213 switch (state
.regs
[i
].where
) {
1217 if (state
.regs
[i
].value
>= ARRAY_SIZE(reg_info
)
1218 || REG_INVALID(state
.regs
[i
].value
)
1219 || reg_info
[i
].width
>
1220 reg_info
[state
.regs
[i
].value
].width
)
1222 switch (reg_info
[state
.regs
[i
].value
].width
) {
1224 state
.regs
[i
].value
=
1225 FRAME_REG(state
.regs
[i
].value
, const u8
);
1228 state
.regs
[i
].value
=
1229 FRAME_REG(state
.regs
[i
].value
, const u16
);
1232 state
.regs
[i
].value
=
1233 FRAME_REG(state
.regs
[i
].value
, const u32
);
1237 state
.regs
[i
].value
=
1238 FRAME_REG(state
.regs
[i
].value
, const u64
);
1248 unw_debug("\nRegister state after evaluation with realtime Stack:\n");
1249 fptr
= (unsigned long *)(&frame
->regs
);
1250 for (i
= 0; i
< ARRAY_SIZE(state
.regs
); ++i
, fptr
++) {
1254 switch (state
.regs
[i
].where
) {
1256 if (reg_info
[i
].width
!= sizeof(UNW_SP(frame
))
1257 || &FRAME_REG(i
, __typeof__(UNW_SP(frame
)))
1260 UNW_SP(frame
) = cfa
;
1263 switch (reg_info
[i
].width
) {
1265 FRAME_REG(i
, u8
) = state
.regs
[i
].value
;
1268 FRAME_REG(i
, u16
) = state
.regs
[i
].value
;
1271 FRAME_REG(i
, u32
) = state
.regs
[i
].value
;
1275 FRAME_REG(i
, u64
) = state
.regs
[i
].value
;
1283 if (reg_info
[i
].width
!= sizeof(unsigned long))
1285 FRAME_REG(i
, unsigned long) = cfa
+ state
.regs
[i
].value
1289 addr
= cfa
+ state
.regs
[i
].value
* state
.dataAlign
;
1291 if ((state
.regs
[i
].value
* state
.dataAlign
)
1292 % sizeof(unsigned long)
1294 || addr
+ sizeof(unsigned long) < addr
1295 || addr
+ sizeof(unsigned long) > endLoc
)
1298 switch (reg_info
[i
].width
) {
1300 __get_user(FRAME_REG(i
, u8
),
1304 __get_user(FRAME_REG(i
, u16
),
1305 (u16 __user
*)addr
);
1308 __get_user(FRAME_REG(i
, u32
),
1309 (u32 __user
*)addr
);
1313 __get_user(FRAME_REG(i
, u64
),
1314 (u64 __user
*)addr
);
1323 unw_debug("r%d: 0x%lx ", i
, *fptr
);
1329 EXPORT_SYMBOL(arc_unwind
);