aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVineet Gupta <vgupta@synopsys.com>2013-01-22 06:33:19 -0500
committerVineet Gupta <vgupta@synopsys.com>2013-02-15 12:46:03 -0500
commit854a0d95056c265d96cb449bc97bc5ef9bbed835 (patch)
tree798c834ae188bd570b861a47765fce8ed633f85a
parent41195d236e84458bebd4fdc218610a92231ac791 (diff)
ARC: DWARF2 .debug_frame based stack unwinder
-Originally written by Rajeshwar Ranga -Derived off of generic unwinder in 2.6.19 and adapted to ARC Signed-off-by: Vineet Gupta <vgupta@synopsys.com> Cc: Rajeshwar Ranga <rajeshwar.ranga@gmail.com>
-rw-r--r--arch/arc/Kconfig15
-rw-r--r--arch/arc/include/asm/module.h7
-rw-r--r--arch/arc/include/asm/unwind.h163
-rw-r--r--arch/arc/kernel/Makefile6
-rw-r--r--arch/arc/kernel/entry.S9
-rw-r--r--arch/arc/kernel/module.c58
-rw-r--r--arch/arc/kernel/setup.c3
-rw-r--r--arch/arc/kernel/unwind.c1329
-rw-r--r--arch/arc/kernel/vmlinux.lds.S23
9 files changed, 1612 insertions, 1 deletions
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index 52f5c072f6da..0979d8e6fc16 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -25,6 +25,7 @@ config ARC
25 select HAVE_ARCH_TRACEHOOK 25 select HAVE_ARCH_TRACEHOOK
26 select HAVE_GENERIC_HARDIRQS 26 select HAVE_GENERIC_HARDIRQS
27 select HAVE_MEMBLOCK 27 select HAVE_MEMBLOCK
28 select HAVE_MOD_ARCH_SPECIFIC if ARC_DW2_UNWIND
28 select HAVE_OPROFILE 29 select HAVE_OPROFILE
29 select IRQ_DOMAIN 30 select IRQ_DOMAIN
30 select MODULES_USE_ELF_RELA 31 select MODULES_USE_ELF_RELA
@@ -344,6 +345,20 @@ menuconfig ARC_DBG
344 bool "ARC debugging" 345 bool "ARC debugging"
345 default y 346 default y
346 347
348config ARC_DW2_UNWIND
349 bool "Enable DWARF specific kernel stack unwind"
350 depends on ARC_DBG
351 default y
352 select KALLSYMS
353 help
354 Compiles the kernel with DWARF unwind information and can be used
355 to get stack backtraces.
356
357 If you say Y here the resulting kernel image will be slightly larger
358 but not slower, and it will give very useful debugging information.
359 If you don't debug the kernel, you can say N, but we may not be able
360 to solve problems without frame unwind information
361
347config ARC_DBG_TLB_PARANOIA 362config ARC_DBG_TLB_PARANOIA
348 bool "Paranoia Checks in Low Level TLB Handlers" 363 bool "Paranoia Checks in Low Level TLB Handlers"
349 depends on ARC_DBG && !SMP 364 depends on ARC_DBG && !SMP
diff --git a/arch/arc/include/asm/module.h b/arch/arc/include/asm/module.h
index 234b4354e2b3..518222bb3f8e 100644
--- a/arch/arc/include/asm/module.h
+++ b/arch/arc/include/asm/module.h
@@ -14,6 +14,13 @@
14 14
15#include <asm-generic/module.h> 15#include <asm-generic/module.h>
16 16
17#ifdef CONFIG_ARC_DW2_UNWIND
18struct mod_arch_specific {
19 void *unw_info;
20 int unw_sec_idx;
21};
22#endif
23
17#define MODULE_PROC_FAMILY "ARC700" 24#define MODULE_PROC_FAMILY "ARC700"
18 25
19#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY 26#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY
diff --git a/arch/arc/include/asm/unwind.h b/arch/arc/include/asm/unwind.h
new file mode 100644
index 000000000000..7ca628b6ee2a
--- /dev/null
+++ b/arch/arc/include/asm/unwind.h
@@ -0,0 +1,163 @@
1/*
2 * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef _ASM_ARC_UNWIND_H
10#define _ASM_ARC_UNWIND_H
11
12#ifdef CONFIG_ARC_DW2_UNWIND
13
14#include <linux/sched.h>
15
16struct arc700_regs {
17 unsigned long r0;
18 unsigned long r1;
19 unsigned long r2;
20 unsigned long r3;
21 unsigned long r4;
22 unsigned long r5;
23 unsigned long r6;
24 unsigned long r7;
25 unsigned long r8;
26 unsigned long r9;
27 unsigned long r10;
28 unsigned long r11;
29 unsigned long r12;
30 unsigned long r13;
31 unsigned long r14;
32 unsigned long r15;
33 unsigned long r16;
34 unsigned long r17;
35 unsigned long r18;
36 unsigned long r19;
37 unsigned long r20;
38 unsigned long r21;
39 unsigned long r22;
40 unsigned long r23;
41 unsigned long r24;
42 unsigned long r25;
43 unsigned long r26;
44 unsigned long r27; /* fp */
45 unsigned long r28; /* sp */
46 unsigned long r29;
47 unsigned long r30;
48 unsigned long r31; /* blink */
49 unsigned long r63; /* pc */
50};
51
52struct unwind_frame_info {
53 struct arc700_regs regs;
54 struct task_struct *task;
55 unsigned call_frame:1;
56};
57
58#define UNW_PC(frame) ((frame)->regs.r63)
59#define UNW_SP(frame) ((frame)->regs.r28)
60#define UNW_BLINK(frame) ((frame)->regs.r31)
61
62/* Rajesh FIXME */
63#ifdef CONFIG_FRAME_POINTER
64#define UNW_FP(frame) ((frame)->regs.r27)
65#define FRAME_RETADDR_OFFSET 4
66#define FRAME_LINK_OFFSET 0
67#define STACK_BOTTOM_UNW(tsk) STACK_LIMIT((tsk)->thread.ksp)
68#define STACK_TOP_UNW(tsk) ((tsk)->thread.ksp)
69#else
70#define UNW_FP(frame) ((void)(frame), 0)
71#endif
72
73#define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1))
74
75#define UNW_REGISTER_INFO \
76 PTREGS_INFO(r0), \
77 PTREGS_INFO(r1), \
78 PTREGS_INFO(r2), \
79 PTREGS_INFO(r3), \
80 PTREGS_INFO(r4), \
81 PTREGS_INFO(r5), \
82 PTREGS_INFO(r6), \
83 PTREGS_INFO(r7), \
84 PTREGS_INFO(r8), \
85 PTREGS_INFO(r9), \
86 PTREGS_INFO(r10), \
87 PTREGS_INFO(r11), \
88 PTREGS_INFO(r12), \
89 PTREGS_INFO(r13), \
90 PTREGS_INFO(r14), \
91 PTREGS_INFO(r15), \
92 PTREGS_INFO(r16), \
93 PTREGS_INFO(r17), \
94 PTREGS_INFO(r18), \
95 PTREGS_INFO(r19), \
96 PTREGS_INFO(r20), \
97 PTREGS_INFO(r21), \
98 PTREGS_INFO(r22), \
99 PTREGS_INFO(r23), \
100 PTREGS_INFO(r24), \
101 PTREGS_INFO(r25), \
102 PTREGS_INFO(r26), \
103 PTREGS_INFO(r27), \
104 PTREGS_INFO(r28), \
105 PTREGS_INFO(r29), \
106 PTREGS_INFO(r30), \
107 PTREGS_INFO(r31), \
108 PTREGS_INFO(r63)
109
110#define UNW_DEFAULT_RA(raItem, dataAlign) \
111 ((raItem).where == Memory && !((raItem).value * (dataAlign) + 4))
112
113extern int arc_unwind(struct unwind_frame_info *frame);
114extern void arc_unwind_init(void);
115extern void arc_unwind_setup(void);
116extern void *unwind_add_table(struct module *module, const void *table_start,
117 unsigned long table_size);
118extern void unwind_remove_table(void *handle, int init_only);
119
120static inline int
121arch_unwind_init_running(struct unwind_frame_info *info,
122 int (*callback) (struct unwind_frame_info *info,
123 void *arg),
124 void *arg)
125{
126 return 0;
127}
128
129static inline int arch_unw_user_mode(const struct unwind_frame_info *info)
130{
131 return 0;
132}
133
134static inline void arch_unw_init_blocked(struct unwind_frame_info *info)
135{
136 return;
137}
138
139static inline void arch_unw_init_frame_info(struct unwind_frame_info *info,
140 struct pt_regs *regs)
141{
142 return;
143}
144
145#else
146
147#define UNW_PC(frame) ((void)(frame), 0)
148#define UNW_SP(frame) ((void)(frame), 0)
149#define UNW_FP(frame) ((void)(frame), 0)
150
151static inline void arc_unwind_init(void)
152{
153}
154
155static inline void arc_unwind_setup(void)
156{
157}
158#define unwind_add_table(a, b, c)
159#define unwind_remove_table(a, b)
160
161#endif /* CONFIG_ARC_DW2_UNWIND */
162
163#endif /* _ASM_ARC_UNWIND_H */
diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile
index 46c15ff97e97..38e4715f3349 100644
--- a/arch/arc/kernel/Makefile
+++ b/arch/arc/kernel/Makefile
@@ -14,10 +14,16 @@ obj-y += devtree.o
14 14
15obj-$(CONFIG_MODULES) += arcksyms.o module.o 15obj-$(CONFIG_MODULES) += arcksyms.o module.o
16obj-$(CONFIG_SMP) += smp.o 16obj-$(CONFIG_SMP) += smp.o
17obj-$(CONFIG_ARC_DW2_UNWIND) += unwind.o
17 18
18obj-$(CONFIG_ARC_FPU_SAVE_RESTORE) += fpu.o 19obj-$(CONFIG_ARC_FPU_SAVE_RESTORE) += fpu.o
19CFLAGS_fpu.o += -mdpfp 20CFLAGS_fpu.o += -mdpfp
20 21
22ifdef CONFIG_ARC_DW2_UNWIND
23CFLAGS_ctx_sw.o += -fno-omit-frame-pointer
24obj-y += ctx_sw.o
25else
21obj-y += ctx_sw_asm.o 26obj-y += ctx_sw_asm.o
27endif
22 28
23extra-y := vmlinux.lds head.o 29extra-y := vmlinux.lds head.o
diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S
index 3f6ce98fea11..021cfa46a1dc 100644
--- a/arch/arc/kernel/entry.S
+++ b/arch/arc/kernel/entry.S
@@ -815,3 +815,12 @@ ARC_ENTRY sys_clone_wrapper
815 815
816 b ret_from_system_call 816 b ret_from_system_call
817ARC_EXIT sys_clone_wrapper 817ARC_EXIT sys_clone_wrapper
818
819#ifdef CONFIG_ARC_DW2_UNWIND
820; Workaround for bug 94179 (STAR ):
821; Despite -fasynchronous-unwind-tables, linker is not making dwarf2 unwinder
822; section (.debug_frame) as loadable. So we force it here.
823; This also fixes STAR 9000487933 where the prev-workaround (objcopy --setflag)
824; would not work after a clean build due to kernel build system dependencies.
825.section .debug_frame, "wa",@progbits
826#endif
diff --git a/arch/arc/kernel/module.c b/arch/arc/kernel/module.c
index a1bb70d6e97d..cdd359352c0a 100644
--- a/arch/arc/kernel/module.c
+++ b/arch/arc/kernel/module.c
@@ -14,6 +14,7 @@
14#include <linux/slab.h> 14#include <linux/slab.h>
15#include <linux/fs.h> 15#include <linux/fs.h>
16#include <linux/string.h> 16#include <linux/string.h>
17#include <asm/unwind.h>
17 18
18static inline void arc_write_me(unsigned short *addr, unsigned long value) 19static inline void arc_write_me(unsigned short *addr, unsigned long value)
19{ 20{
@@ -21,6 +22,42 @@ static inline void arc_write_me(unsigned short *addr, unsigned long value)
21 *(addr + 1) = (value & 0xffff); 22 *(addr + 1) = (value & 0xffff);
22} 23}
23 24
25/* ARC specific section quirks - before relocation loop in generic loader
26 *
27 * For dwarf unwinding out of modules, this needs to
28 * 1. Ensure the .debug_frame is allocatable (ARC Linker bug: despite
29 * -fasynchronous-unwind-tables it doesn't).
30 * 2. Since we are iterating thru sec hdr tbl anyways, make a note of
31 * the exact section index, for later use.
32 */
33int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
34 char *secstr, struct module *mod)
35{
36#ifdef CONFIG_ARC_DW2_UNWIND
37 int i;
38
39 mod->arch.unw_sec_idx = 0;
40 mod->arch.unw_info = NULL;
41
42 for (i = 1; i < hdr->e_shnum; i++) {
43 if (strcmp(secstr+sechdrs[i].sh_name, ".debug_frame") == 0) {
44 sechdrs[i].sh_flags |= SHF_ALLOC;
45 mod->arch.unw_sec_idx = i;
46 break;
47 }
48 }
49#endif
50 return 0;
51}
52
53void module_arch_cleanup(struct module *mod)
54{
55#ifdef CONFIG_ARC_DW2_UNWIND
56 if (mod->arch.unw_info)
57 unwind_remove_table(mod->arch.unw_info, 0);
58#endif
59}
60
24int apply_relocate_add(Elf32_Shdr *sechdrs, 61int apply_relocate_add(Elf32_Shdr *sechdrs,
25 const char *strtab, 62 const char *strtab,
26 unsigned int symindex, /* sec index for sym tbl */ 63 unsigned int symindex, /* sec index for sym tbl */
@@ -85,3 +122,24 @@ relo_err:
85 return -ENOEXEC; 122 return -ENOEXEC;
86 123
87} 124}
125
126/* Just before lift off: After sections have been relocated, we add the
127 * dwarf section to unwinder table pool
128 * This couldn't be done in module_frob_arch_sections() because
129 * relocations had not been applied by then
130 */
131int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
132 struct module *mod)
133{
134#ifdef CONFIG_ARC_DW2_UNWIND
135 void *unw;
136 int unwsec = mod->arch.unw_sec_idx;
137
138 if (unwsec) {
139 unw = unwind_add_table(mod, (void *)sechdrs[unwsec].sh_addr,
140 sechdrs[unwsec].sh_size);
141 mod->arch.unw_info = unw;
142 }
143#endif
144 return 0;
145}
diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c
index 4026b5a004d2..6e3996cb9df9 100644
--- a/arch/arc/kernel/setup.c
+++ b/arch/arc/kernel/setup.c
@@ -23,6 +23,7 @@
23#include <asm/irq.h> 23#include <asm/irq.h>
24#include <asm/arcregs.h> 24#include <asm/arcregs.h>
25#include <asm/prom.h> 25#include <asm/prom.h>
26#include <asm/unwind.h>
26 27
27#define FIX_PTR(x) __asm__ __volatile__(";" : "+r"(x)) 28#define FIX_PTR(x) __asm__ __volatile__(";" : "+r"(x))
28 29
@@ -105,6 +106,8 @@ void __init setup_arch(char **cmdline_p)
105 conswitchp = &dummy_con; 106 conswitchp = &dummy_con;
106#endif 107#endif
107 108
109 arc_unwind_init();
110 arc_unwind_setup();
108} 111}
109 112
110/* 113/*
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c
new file mode 100644
index 000000000000..a8d02223da44
--- /dev/null
+++ b/arch/arc/kernel/unwind.c
@@ -0,0 +1,1329 @@
1/*
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>
5 *
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.
9 *
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.
14 */
15
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>
27
28extern char __start_unwind[], __end_unwind[];
29/* extern const u8 __start_unwind_hdr[], __end_unwind_hdr[];*/
30
31/* #define UNWIND_DEBUG */
32
33#ifdef UNWIND_DEBUG
34int dbg_unw;
35#define unw_debug(fmt, ...) \
36do { \
37 if (dbg_unw) \
38 pr_info(fmt, ##__VA_ARGS__); \
39} while (0);
40#else
41#define unw_debug(fmt, ...)
42#endif
43
44#define MAX_STACK_DEPTH 8
45
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) \
52 }
53#define PTREGS_INFO(f) EXTRA_INFO(regs.f)
54
55static const struct {
56 unsigned offs:BITS_PER_LONG / 2;
57 unsigned width:BITS_PER_LONG / 2;
58} reg_info[] = {
59UNW_REGISTER_INFO};
60
61#undef PTREGS_INFO
62#undef EXTRA_INFO
63
64#ifndef REG_INVALID
65#define REG_INVALID(r) (reg_info[r].width == 0)
66#endif
67
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
96
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
113
114typedef unsigned long uleb128_t;
115typedef signed long sleb128_t;
116
117static struct unwind_table {
118 struct {
119 unsigned long pc;
120 unsigned long range;
121 } core, init;
122 const void *address;
123 unsigned long size;
124 const unsigned char *header;
125 unsigned long hdrsz;
126 struct unwind_table *link;
127 const char *name;
128} root_table;
129
130struct unwind_item {
131 enum item_location {
132 Nowhere,
133 Memory,
134 Register,
135 Value
136 } where;
137 uleb128_t value;
138};
139
140struct unwind_state {
141 uleb128_t loc, org;
142 const u8 *cieStart, *cieEnd;
143 uleb128_t codeAlign;
144 sleb128_t dataAlign;
145 struct cfa {
146 uleb128_t reg, offs;
147 } cfa;
148 struct unwind_item regs[ARRAY_SIZE(reg_info)];
149 unsigned stackDepth:8;
150 unsigned version:8;
151 const u8 *label;
152 const u8 *stack[MAX_STACK_DEPTH];
153};
154
155static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 };
156
157static struct unwind_table *find_table(unsigned long pc)
158{
159 struct unwind_table *table;
160
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))
166 break;
167
168 return table;
169}
170
171static unsigned long read_pointer(const u8 **pLoc,
172 const void *end, signed ptrType);
173
174static 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)
179{
180 const u8 *ptr = header_start + 4;
181 const u8 *end = header_start + header_size;
182
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;
189
190 /* See if the linker provided table looks valid. */
191 if (header_size <= 4
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)
197 header_start = NULL;
198
199 table->hdrsz = header_size;
200 smp_wmb();
201 table->header = header_start;
202 table->link = NULL;
203 table->name = name;
204}
205
206void __init arc_unwind_init(void)
207{
208 init_unwind_table(&root_table, "kernel", _text, _end - _text, NULL, 0,
209 __start_unwind, __end_unwind - __start_unwind,
210 NULL, 0);
211 /*__start_unwind_hdr, __end_unwind_hdr - __start_unwind_hdr);*/
212}
213
214static const u32 bad_cie, not_fde;
215static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *);
216static signed fde_pointer_type(const u32 *cie);
217
218struct eh_frame_hdr_table_entry {
219 unsigned long start, fde;
220};
221
222static int cmp_eh_frame_hdr_table_entries(const void *p1, const void *p2)
223{
224 const struct eh_frame_hdr_table_entry *e1 = p1;
225 const struct eh_frame_hdr_table_entry *e2 = p2;
226
227 return (e1->start > e2->start) - (e1->start < e2->start);
228}
229
230static void swap_eh_frame_hdr_table_entries(void *p1, void *p2, int size)
231{
232 struct eh_frame_hdr_table_entry *e1 = p1;
233 struct eh_frame_hdr_table_entry *e2 = p2;
234 unsigned long v;
235
236 v = e1->start;
237 e1->start = e2->start;
238 e2->start = v;
239 v = e1->fde;
240 e1->fde = e2->fde;
241 e2->fde = v;
242}
243
244static void __init setup_unwind_table(struct unwind_table *table,
245 void *(*alloc) (unsigned long))
246{
247 const u8 *ptr;
248 unsigned long tableSize = table->size, hdrSize;
249 unsigned n;
250 const u32 *fde;
251 struct {
252 u8 version;
253 u8 eh_frame_ptr_enc;
254 u8 fde_count_enc;
255 u8 table_enc;
256 unsigned long eh_frame_ptr;
257 unsigned int fde_count;
258 struct eh_frame_hdr_table_entry table[];
259 } __attribute__ ((__packed__)) *header;
260
261 if (table->header)
262 return;
263
264 if (table->hdrsz)
265 pr_warn(".eh_frame_hdr for '%s' present but unusable\n",
266 table->name);
267
268 if (tableSize & (sizeof(*fde) - 1))
269 return;
270
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);
275 signed ptrType;
276
277 if (cie == &not_fde)
278 continue;
279 if (cie == NULL || cie == &bad_cie)
280 return;
281 ptrType = fde_pointer_type(cie);
282 if (ptrType < 0)
283 return;
284
285 ptr = (const u8 *)(fde + 2);
286 if (!read_pointer(&ptr, (const u8 *)(fde + 1) + *fde,
287 ptrType)) {
288 /* FIXME_Rajesh We have 4 instances of null addresses
289 * instead of the initial loc addr
290 * return;
291 */
292 }
293 ++n;
294 }
295
296 if (tableSize || !n)
297 return;
298
299 hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int)
300 + 2 * n * sizeof(unsigned long);
301 header = alloc(hdrSize);
302 if (!header)
303 return;
304 header->version = 1;
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;
312
313 BUILD_BUG_ON(offsetof(typeof(*header), table)
314 % __alignof(typeof(*header->table)));
315 for (fde = table->address, tableSize = table->size, n = 0;
316 tableSize;
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]);
320
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) +
326 *fde,
327 fde_pointer_type(cie));
328 header->table[n].fde = (unsigned long)fde;
329 ++n;
330 }
331 WARN_ON(n != header->fde_count);
332
333 sort(header->table,
334 n,
335 sizeof(*header->table),
336 cmp_eh_frame_hdr_table_entries, swap_eh_frame_hdr_table_entries);
337
338 table->hdrsz = hdrSize;
339 smp_wmb();
340 table->header = (const void *)header;
341}
342
343static void *__init balloc(unsigned long sz)
344{
345 return __alloc_bootmem_nopanic(sz,
346 sizeof(unsigned int),
347 __pa(MAX_DMA_ADDRESS));
348}
349
350void __init arc_unwind_setup(void)
351{
352 setup_unwind_table(&root_table, balloc);
353}
354
355#ifdef CONFIG_MODULES
356
357static struct unwind_table *last_table;
358
359/* Must be called with module_mutex held. */
360void *unwind_add_table(struct module *module, const void *table_start,
361 unsigned long table_size)
362{
363 struct unwind_table *table;
364
365 if (table_size <= 0)
366 return NULL;
367
368 table = kmalloc(sizeof(*table), GFP_KERNEL);
369 if (!table)
370 return NULL;
371
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,
376 NULL, 0);
377
378#ifdef UNWIND_DEBUG
379 unw_debug("Table added for [%s] %lx %lx\n",
380 module->name, table->core.pc, table->core.range);
381#endif
382 if (last_table)
383 last_table->link = table;
384 else
385 root_table.link = table;
386 last_table = table;
387
388 return table;
389}
390
391struct unlink_table_info {
392 struct unwind_table *table;
393 int init_only;
394};
395
396static int unlink_table(void *arg)
397{
398 struct unlink_table_info *info = arg;
399 struct unwind_table *table = info->table, *prev;
400
401 for (prev = &root_table; prev->link && prev->link != table;
402 prev = prev->link)
403 ;
404
405 if (prev->link) {
406 if (info->init_only) {
407 table->init.pc = 0;
408 table->init.range = 0;
409 info->table = NULL;
410 } else {
411 prev->link = table->link;
412 if (!prev->link)
413 last_table = prev;
414 }
415 } else
416 info->table = NULL;
417
418 return 0;
419}
420
421/* Must be called with module_mutex held. */
422void unwind_remove_table(void *handle, int init_only)
423{
424 struct unwind_table *table = handle;
425 struct unlink_table_info info;
426
427 if (!table || table == &root_table)
428 return;
429
430 if (init_only && table == last_table) {
431 table->init.pc = 0;
432 table->init.range = 0;
433 return;
434 }
435
436 info.table = table;
437 info.init_only = init_only;
438
439 unlink_table(&info); /* XXX: SMP */
440 kfree(table);
441}
442
443#endif /* CONFIG_MODULES */
444
445static uleb128_t get_uleb128(const u8 **pcur, const u8 *end)
446{
447 const u8 *cur = *pcur;
448 uleb128_t value;
449 unsigned shift;
450
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))) {
454 cur = end + 1;
455 break;
456 }
457 value |= (uleb128_t) (*cur & 0x7f) << shift;
458 if (!(*cur++ & 0x80))
459 break;
460 }
461 *pcur = cur;
462
463 return value;
464}
465
466static sleb128_t get_sleb128(const u8 **pcur, const u8 *end)
467{
468 const u8 *cur = *pcur;
469 sleb128_t value;
470 unsigned shift;
471
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))) {
475 cur = end + 1;
476 break;
477 }
478 value |= (sleb128_t) (*cur & 0x7f) << shift;
479 if (!(*cur & 0x80)) {
480 value |= -(*cur++ & 0x40) << shift;
481 break;
482 }
483 }
484 *pcur = cur;
485
486 return value;
487}
488
489static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *table)
490{
491 const u32 *cie;
492
493 if (!*fde || (*fde & (sizeof(*fde) - 1)))
494 return &bad_cie;
495
496 if (fde[1] == 0xffffffff)
497 return &not_fde; /* this is a CIE */
498
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 */
502
503 /* cie = fde + 1 - fde[1] / sizeof(*fde); */
504 cie = (u32 *) fde[1];
505
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 */
510 return cie;
511}
512
513static unsigned long read_pointer(const u8 **pLoc, const void *end,
514 signed ptrType)
515{
516 unsigned long value = 0;
517 union {
518 const u8 *p8;
519 const u16 *p16u;
520 const s16 *p16s;
521 const u32 *p32u;
522 const s32 *p32s;
523 const unsigned long *pul;
524 } ptr;
525
526 if (ptrType < 0 || ptrType == DW_EH_PE_omit)
527 return 0;
528 ptr.p8 = *pLoc;
529 switch (ptrType & DW_EH_PE_FORM) {
530 case DW_EH_PE_data2:
531 if (end < (const void *)(ptr.p16u + 1))
532 return 0;
533 if (ptrType & DW_EH_PE_signed)
534 value = get_unaligned((u16 *) ptr.p16s++);
535 else
536 value = get_unaligned((u16 *) ptr.p16u++);
537 break;
538 case DW_EH_PE_data4:
539#ifdef CONFIG_64BIT
540 if (end < (const void *)(ptr.p32u + 1))
541 return 0;
542 if (ptrType & DW_EH_PE_signed)
543 value = get_unaligned(ptr.p32s++);
544 else
545 value = get_unaligned(ptr.p32u++);
546 break;
547 case DW_EH_PE_data8:
548 BUILD_BUG_ON(sizeof(u64) != sizeof(value));
549#else
550 BUILD_BUG_ON(sizeof(u32) != sizeof(value));
551#endif
552 case DW_EH_PE_native:
553 if (end < (const void *)(ptr.pul + 1))
554 return 0;
555 value = get_unaligned((unsigned long *)ptr.pul++);
556 break;
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)
562 return 0;
563 break;
564 default:
565 return 0;
566 }
567 switch (ptrType & DW_EH_PE_ADJUST) {
568 case DW_EH_PE_abs:
569 break;
570 case DW_EH_PE_pcrel:
571 value += (unsigned long)*pLoc;
572 break;
573 default:
574 return 0;
575 }
576 if ((ptrType & DW_EH_PE_indirect)
577 && __get_user(value, (unsigned long __user *)value))
578 return 0;
579 *pLoc = ptr.p8;
580
581 return value;
582}
583
584static signed fde_pointer_type(const u32 *cie)
585{
586 const u8 *ptr = (const u8 *)(cie + 2);
587 unsigned version = *ptr;
588
589 if (version != 1)
590 return -1; /* unsupported */
591
592 if (*++ptr) {
593 const char *aug;
594 const u8 *end = (const u8 *)(cie + 1) + *cie;
595 uleb128_t len;
596
597 /* check if augmentation size is first (and thus present) */
598 if (*ptr != 'z')
599 return -1;
600
601 /* check if augmentation string is nul-terminated */
602 aug = (const void *)ptr;
603 ptr = memchr(aug, 0, end - ptr);
604 if (ptr == NULL)
605 return -1;
606
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 */
613
614 if (ptr + len < ptr || ptr + len > end)
615 return -1;
616
617 end = ptr + len;
618 while (*++aug) {
619 if (ptr >= end)
620 return -1;
621 switch (*aug) {
622 case 'L':
623 ++ptr;
624 break;
625 case 'P':{
626 signed ptrType = *ptr++;
627
628 if (!read_pointer(&ptr, end, ptrType)
629 || ptr > end)
630 return -1;
631 }
632 break;
633 case 'R':
634 return *ptr;
635 default:
636 return -1;
637 }
638 }
639 }
640 return DW_EH_PE_native | DW_EH_PE_abs;
641}
642
643static int advance_loc(unsigned long delta, struct unwind_state *state)
644{
645 state->loc += delta * state->codeAlign;
646
647 /* FIXME_Rajesh: Probably we are defining for the initial range as well;
648 return delta > 0;
649 */
650 unw_debug("delta %3lu => loc 0x%lx: ", delta, state->loc);
651 return 1;
652}
653
654static void set_rule(uleb128_t reg, enum item_location where, uleb128_t value,
655 struct unwind_state *state)
656{
657 if (reg < ARRAY_SIZE(state->regs)) {
658 state->regs[reg].where = where;
659 state->regs[reg].value = value;
660
661#ifdef UNWIND_DEBUG
662 unw_debug("r%lu: ", reg);
663 switch (where) {
664 case Nowhere:
665 unw_debug("s ");
666 break;
667 case Memory:
668 unw_debug("c(%lu) ", value);
669 break;
670 case Register:
671 unw_debug("r(%lu) ", value);
672 break;
673 case Value:
674 unw_debug("v(%lu) ", value);
675 break;
676 default:
677 break;
678 }
679#endif
680 }
681}
682
683static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
684 signed ptrType, struct unwind_state *state)
685{
686 union {
687 const u8 *p8;
688 const u16 *p16;
689 const u32 *p32;
690 } ptr;
691 int result = 1;
692 u8 opcode;
693
694 if (start != state->cieStart) {
695 state->loc = state->org;
696 result =
697 processCFI(state->cieStart, state->cieEnd, 0, ptrType,
698 state);
699 if (targetLoc == 0 && state->label == NULL)
700 return result;
701 }
702 for (ptr.p8 = start; result && ptr.p8 < end;) {
703 switch (*ptr.p8 >> 6) {
704 uleb128_t value;
705
706 case 0:
707 opcode = *ptr.p8++;
708
709 switch (opcode) {
710 case DW_CFA_nop:
711 unw_debug("cfa nop ");
712 break;
713 case DW_CFA_set_loc:
714 state->loc = read_pointer(&ptr.p8, end,
715 ptrType);
716 if (state->loc == 0)
717 result = 0;
718 unw_debug("cfa_set_loc: 0x%lx ", state->loc);
719 break;
720 case DW_CFA_advance_loc1:
721 unw_debug("\ncfa advance loc1:");
722 result = ptr.p8 < end
723 && advance_loc(*ptr.p8++, state);
724 break;
725 case DW_CFA_advance_loc2:
726 value = *ptr.p8++;
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);
732 break;
733 case DW_CFA_advance_loc4:
734 unw_debug("\ncfa advance loc4:");
735 result = ptr.p8 <= end + 4
736 && advance_loc(*ptr.p32++, state);
737 break;
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);
743 break;
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);
748 break;
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);
753 break;
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);
758 break;
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,
766 state);
767 break;
768 case DW_CFA_register:
769 unw_debug("cfa_register: ");
770 value = get_uleb128(&ptr.p8, end);
771 set_rule(value,
772 Register,
773 get_uleb128(&ptr.p8, end), state);
774 break;
775 case DW_CFA_remember_state:
776 unw_debug("cfa_remember_state: ");
777 if (ptr.p8 == state->label) {
778 state->label = NULL;
779 return 1;
780 }
781 if (state->stackDepth >= MAX_STACK_DEPTH)
782 return 0;
783 state->stack[state->stackDepth++] = ptr.p8;
784 break;
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;
790
791 state->label =
792 state->stack[state->stackDepth - 1];
793 memcpy(&state->cfa, &badCFA,
794 sizeof(state->cfa));
795 memset(state->regs, 0,
796 sizeof(state->regs));
797 state->stackDepth = 0;
798 result =
799 processCFI(start, end, 0, ptrType,
800 state);
801 state->loc = loc;
802 state->label = label;
803 } else
804 return 0;
805 break;
806 case DW_CFA_def_cfa:
807 state->cfa.reg = get_uleb128(&ptr.p8, end);
808 unw_debug("cfa_def_cfa: r%lu ", state->cfa.reg);
809 /*nobreak*/
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 ",
813 state->cfa.offs);
814 break;
815 case DW_CFA_def_cfa_sf:
816 state->cfa.reg = get_uleb128(&ptr.p8, end);
817 /*nobreak */
818 case DW_CFA_def_cfa_offset_sf:
819 state->cfa.offs = get_sleb128(&ptr.p8, end)
820 * state->dataAlign;
821 break;
822 case DW_CFA_def_cfa_register:
823 unw_debug("cfa_def_cfa_regsiter: ");
824 state->cfa.reg = get_uleb128(&ptr.p8, end);
825 break;
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);
831 break;
832 case DW_CFA_GNU_negative_offset_extended:
833 value = get_uleb128(&ptr.p8, end);
834 set_rule(value,
835 Memory,
836 (uleb128_t) 0 - get_uleb128(&ptr.p8,
837 end),
838 state);
839 break;
840 case DW_CFA_GNU_window_save:
841 default:
842 unw_debug("UNKNOW OPCODE 0x%x\n", opcode);
843 result = 0;
844 break;
845 }
846 break;
847 case 1:
848 unw_debug("\ncfa_adv_loc: ");
849 result = advance_loc(*ptr.p8++ & 0x3f, state);
850 break;
851 case 2:
852 unw_debug("cfa_offset: ");
853 value = *ptr.p8++ & 0x3f;
854 set_rule(value, Memory, get_uleb128(&ptr.p8, end),
855 state);
856 break;
857 case 3:
858 unw_debug("cfa_restore: ");
859 set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state);
860 break;
861 }
862
863 if (ptr.p8 > end)
864 result = 0;
865 if (result && targetLoc != 0 && targetLoc < state->loc)
866 return 1;
867 }
868
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));
874}
875
876/* Unwind to previous to frame. Returns 0 if successful, negative
877 * number in case of an error. */
878int arc_unwind(struct unwind_frame_info *frame)
879{
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;
885 unsigned i;
886 signed ptrType = -1;
887 uleb128_t retAddrReg = 0;
888 const struct unwind_table *table;
889 struct unwind_state state;
890 unsigned long *fptr;
891 unsigned long addr;
892
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),
896 UNW_FP(frame));
897
898 if (UNW_PC(frame) == 0)
899 return -EINVAL;
900
901#ifdef UNWIND_DEBUG
902 {
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);
907 unw_debug("\n");
908 }
909#endif
910
911 table = find_table(pc);
912 if (table != NULL
913 && !(table->size & (sizeof(*fde) - 1))) {
914 const u8 *hdr = table->header;
915 unsigned long tableSize;
916
917 smp_rmb();
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);
922 break;
923 case DW_EH_PE_data2:
924 tableSize = 2;
925 break;
926 case DW_EH_PE_data4:
927 tableSize = 4;
928 break;
929 case DW_EH_PE_data8:
930 tableSize = 8;
931 break;
932 default:
933 tableSize = 0;
934 break;
935 }
936 ptr = hdr + 4;
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))) {
943 do {
944 const u8 *cur =
945 ptr + (i / 2) * (2 * tableSize);
946
947 startLoc = read_pointer(&cur,
948 cur + tableSize,
949 hdr[3]);
950 if (pc < startLoc)
951 i /= 2;
952 else {
953 ptr = cur - tableSize;
954 i = (i + 1) / 2;
955 }
956 } while (startLoc && i > 1);
957 if (i == 1
958 && (startLoc = read_pointer(&ptr,
959 ptr + tableSize,
960 hdr[3])) != 0
961 && pc >= startLoc)
962 fde = (void *)read_pointer(&ptr,
963 ptr +
964 tableSize,
965 hdr[3]);
966 }
967 }
968
969 if (fde != NULL) {
970 cie = cie_for_fde(fde, table);
971 ptr = (const u8 *)(fde + 2);
972 if (cie != NULL
973 && cie != &bad_cie
974 && cie != &not_fde
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))
980 ptrType &=
981 DW_EH_PE_FORM | DW_EH_PE_signed;
982 endLoc =
983 startLoc + read_pointer(&ptr,
984 (const u8 *)(fde +
985 1) +
986 *fde, ptrType);
987 if (pc >= endLoc)
988 fde = NULL;
989 } else
990 fde = NULL;
991 }
992 if (fde == NULL) {
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) {
1000 cie = NULL;
1001 break;
1002 }
1003 if (cie == NULL
1004 || cie == &not_fde
1005 || (ptrType = fde_pointer_type(cie)) < 0)
1006 continue;
1007 ptr = (const u8 *)(fde + 2);
1008 startLoc = read_pointer(&ptr,
1009 (const u8 *)(fde + 1) +
1010 *fde, ptrType);
1011 if (!startLoc)
1012 continue;
1013 if (!(ptrType & DW_EH_PE_indirect))
1014 ptrType &=
1015 DW_EH_PE_FORM | DW_EH_PE_signed;
1016 endLoc =
1017 startLoc + read_pointer(&ptr,
1018 (const u8 *)(fde +
1019 1) +
1020 *fde, ptrType);
1021 if (pc >= startLoc && pc < endLoc)
1022 break;
1023 }
1024 }
1025 }
1026 if (cie != NULL) {
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 */
1034 else if (*++ptr) {
1035 /* check if augmentation size is first (thus present) */
1036 if (*ptr == 'z') {
1037 while (++ptr < end && *ptr) {
1038 switch (*ptr) {
1039 /* chk for ignorable or already handled
1040 * nul-terminated augmentation string */
1041 case 'L':
1042 case 'P':
1043 case 'R':
1044 continue;
1045 case 'S':
1046 frame->call_frame = 0;
1047 continue;
1048 default:
1049 break;
1050 }
1051 break;
1052 }
1053 }
1054 if (ptr >= end || *ptr)
1055 cie = NULL;
1056 }
1057 ++ptr;
1058 }
1059 if (cie != NULL) {
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)
1065 cie = NULL;
1066 else {
1067 retAddrReg =
1068 state.version <= 1 ? *ptr++ : get_uleb128(&ptr,
1069 end);
1070 unw_debug("CIE Frame Info:\n");
1071 unw_debug("return Address register 0x%lx\n",
1072 retAddrReg);
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);
1078
1079 ptr += augSize;
1080 }
1081 if (ptr > end || retAddrReg >= ARRAY_SIZE(reg_info)
1082 || REG_INVALID(retAddrReg)
1083 || reg_info[retAddrReg].width !=
1084 sizeof(unsigned long))
1085 cie = NULL;
1086 }
1087 }
1088 if (cie != NULL) {
1089 state.cieStart = ptr;
1090 ptr = state.cieEnd;
1091 state.cieEnd = end;
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);
1096
1097 if ((ptr += augSize) > end)
1098 fde = NULL;
1099 }
1100 }
1101 if (cie == NULL || fde == NULL) {
1102#ifdef CONFIG_FRAME_POINTER
1103 unsigned long top, bottom;
1104
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)
1110#else
1111 if (UNW_SP(frame) > top && UNW_FP(frame) >= UNW_SP(frame)
1112 && bottom > UNW_FP(frame)
1113#endif
1114 && !((UNW_SP(frame) | UNW_FP(frame))
1115 & (sizeof(unsigned long) - 1))) {
1116 unsigned long link;
1117
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)
1122#else
1123 && link > UNW_FP(frame) && link < bottom
1124#endif
1125 && !(link & (sizeof(link) - 1))
1126 && !__get_user(UNW_PC(frame),
1127 (unsigned long *)(UNW_FP(frame)
1128 + FRAME_RETADDR_OFFSET)))
1129 {
1130 UNW_SP(frame) =
1131 UNW_FP(frame) + FRAME_RETADDR_OFFSET
1132#if FRAME_RETADDR_OFFSET < 0
1133 -
1134#else
1135 +
1136#endif
1137 sizeof(UNW_PC(frame));
1138 UNW_FP(frame) = link;
1139 return 0;
1140 }
1141 }
1142#endif
1143 return -ENXIO;
1144 }
1145 state.org = startLoc;
1146 memcpy(&state.cfa, &badCFA, sizeof(state.cfa));
1147
1148 unw_debug("\nProcess instructions\n");
1149
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
1154 */
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))
1161 return -EIO;
1162
1163#ifdef UNWIND_DEBUG
1164 unw_debug("\n");
1165
1166 unw_debug("\nRegister State Based on the rules parsed from FDE:\n");
1167 for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
1168
1169 if (REG_INVALID(i))
1170 continue;
1171
1172 switch (state.regs[i].where) {
1173 case Nowhere:
1174 break;
1175 case Memory:
1176 unw_debug(" r%d: c(%lu),", i, state.regs[i].value);
1177 break;
1178 case Register:
1179 unw_debug(" r%d: r(%lu),", i, state.regs[i].value);
1180 break;
1181 case Value:
1182 unw_debug(" r%d: v(%lu),", i, state.regs[i].value);
1183 break;
1184 }
1185 }
1186
1187 unw_debug("\n");
1188#endif
1189
1190 /* update frame */
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;
1195#endif
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);
1202 }
1203
1204 unw_debug("\nCFA reg: 0x%lx, offset: 0x%lx => 0x%lx\n",
1205 state.cfa.reg, state.cfa.offs, cfa);
1206
1207 for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
1208 if (REG_INVALID(i)) {
1209 if (state.regs[i].where == Nowhere)
1210 continue;
1211 return -EIO;
1212 }
1213 switch (state.regs[i].where) {
1214 default:
1215 break;
1216 case Register:
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)
1221 return -EIO;
1222 switch (reg_info[state.regs[i].value].width) {
1223 case sizeof(u8):
1224 state.regs[i].value =
1225 FRAME_REG(state.regs[i].value, const u8);
1226 break;
1227 case sizeof(u16):
1228 state.regs[i].value =
1229 FRAME_REG(state.regs[i].value, const u16);
1230 break;
1231 case sizeof(u32):
1232 state.regs[i].value =
1233 FRAME_REG(state.regs[i].value, const u32);
1234 break;
1235#ifdef CONFIG_64BIT
1236 case sizeof(u64):
1237 state.regs[i].value =
1238 FRAME_REG(state.regs[i].value, const u64);
1239 break;
1240#endif
1241 default:
1242 return -EIO;
1243 }
1244 break;
1245 }
1246 }
1247
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++) {
1251
1252 if (REG_INVALID(i))
1253 continue;
1254 switch (state.regs[i].where) {
1255 case Nowhere:
1256 if (reg_info[i].width != sizeof(UNW_SP(frame))
1257 || &FRAME_REG(i, __typeof__(UNW_SP(frame)))
1258 != &UNW_SP(frame))
1259 continue;
1260 UNW_SP(frame) = cfa;
1261 break;
1262 case Register:
1263 switch (reg_info[i].width) {
1264 case sizeof(u8):
1265 FRAME_REG(i, u8) = state.regs[i].value;
1266 break;
1267 case sizeof(u16):
1268 FRAME_REG(i, u16) = state.regs[i].value;
1269 break;
1270 case sizeof(u32):
1271 FRAME_REG(i, u32) = state.regs[i].value;
1272 break;
1273#ifdef CONFIG_64BIT
1274 case sizeof(u64):
1275 FRAME_REG(i, u64) = state.regs[i].value;
1276 break;
1277#endif
1278 default:
1279 return -EIO;
1280 }
1281 break;
1282 case Value:
1283 if (reg_info[i].width != sizeof(unsigned long))
1284 return -EIO;
1285 FRAME_REG(i, unsigned long) = cfa + state.regs[i].value
1286 * state.dataAlign;
1287 break;
1288 case Memory:
1289 addr = cfa + state.regs[i].value * state.dataAlign;
1290
1291 if ((state.regs[i].value * state.dataAlign)
1292 % sizeof(unsigned long)
1293 || addr < startLoc
1294 || addr + sizeof(unsigned long) < addr
1295 || addr + sizeof(unsigned long) > endLoc)
1296 return -EIO;
1297
1298 switch (reg_info[i].width) {
1299 case sizeof(u8):
1300 __get_user(FRAME_REG(i, u8),
1301 (u8 __user *)addr);
1302 break;
1303 case sizeof(u16):
1304 __get_user(FRAME_REG(i, u16),
1305 (u16 __user *)addr);
1306 break;
1307 case sizeof(u32):
1308 __get_user(FRAME_REG(i, u32),
1309 (u32 __user *)addr);
1310 break;
1311#ifdef CONFIG_64BIT
1312 case sizeof(u64):
1313 __get_user(FRAME_REG(i, u64),
1314 (u64 __user *)addr);
1315 break;
1316#endif
1317 default:
1318 return -EIO;
1319 }
1320
1321 break;
1322 }
1323 unw_debug("r%d: 0x%lx ", i, *fptr);
1324 }
1325
1326 return 0;
1327#undef FRAME_REG
1328}
1329EXPORT_SYMBOL(arc_unwind);
diff --git a/arch/arc/kernel/vmlinux.lds.S b/arch/arc/kernel/vmlinux.lds.S
index 8c72bc37568b..303ea01c85c8 100644
--- a/arch/arc/kernel/vmlinux.lds.S
+++ b/arch/arc/kernel/vmlinux.lds.S
@@ -100,17 +100,38 @@ SECTIONS
100 100
101 BSS_SECTION(0, 0, 0) 101 BSS_SECTION(0, 0, 0)
102 102
103#ifdef CONFIG_ARC_DW2_UNWIND
104 . = ALIGN(PAGE_SIZE);
105 .debug_frame : {
106 __start_unwind = .;
107 *(.debug_frame)
108 __end_unwind = .;
109 }
110#else
111 /DISCARD/ : { *(.debug_frame) }
112#endif
113
103 NOTES 114 NOTES
104 115
105 . = ALIGN(PAGE_SIZE); 116 . = ALIGN(PAGE_SIZE);
106 _end = . ; 117 _end = . ;
107 118
108 STABS_DEBUG 119 STABS_DEBUG
109 DWARF_DEBUG
110 DISCARDS 120 DISCARDS
111 121
112 .arcextmap 0 : { 122 .arcextmap 0 : {
113 *(.gnu.linkonce.arcextmap.*) 123 *(.gnu.linkonce.arcextmap.*)
114 *(.arcextmap.*) 124 *(.arcextmap.*)
115 } 125 }
126
127 /* open-coded because we need .debug_frame seperately for unwinding */
128 .debug_aranges 0 : { *(.debug_aranges) }
129 .debug_pubnames 0 : { *(.debug_pubnames) }
130 .debug_info 0 : { *(.debug_info) }
131 .debug_abbrev 0 : { *(.debug_abbrev) }
132 .debug_line 0 : { *(.debug_line) }
133 .debug_str 0 : { *(.debug_str) }
134 .debug_loc 0 : { *(.debug_loc) }
135 .debug_macinfo 0 : { *(.debug_macinfo) }
136
116} 137}