xref: /openbmc/linux/arch/arc/kernel/unwind.c (revision 26fb3dae)
1854a0d95SVineet Gupta /*
2854a0d95SVineet Gupta  * Copyright (C) 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
3854a0d95SVineet Gupta  * Copyright (C) 2002-2006 Novell, Inc.
4854a0d95SVineet Gupta  *	Jan Beulich <jbeulich@novell.com>
5854a0d95SVineet Gupta  *
6854a0d95SVineet Gupta  * This program is free software; you can redistribute it and/or modify
7854a0d95SVineet Gupta  * it under the terms of the GNU General Public License version 2 as
8854a0d95SVineet Gupta  * published by the Free Software Foundation.
9854a0d95SVineet Gupta  *
10854a0d95SVineet Gupta  * A simple API for unwinding kernel stacks.  This is used for
11854a0d95SVineet Gupta  * debugging and error reporting purposes.  The kernel doesn't need
12854a0d95SVineet Gupta  * full-blown stack unwinding with all the bells and whistles, so there
13854a0d95SVineet Gupta  * is not much point in implementing the full Dwarf2 unwind API.
14854a0d95SVineet Gupta  */
15854a0d95SVineet Gupta 
16854a0d95SVineet Gupta #include <linux/sched.h>
17854a0d95SVineet Gupta #include <linux/module.h>
1857c8a661SMike Rapoport #include <linux/memblock.h>
19854a0d95SVineet Gupta #include <linux/sort.h>
20854a0d95SVineet Gupta #include <linux/slab.h>
21854a0d95SVineet Gupta #include <linux/stop_machine.h>
22854a0d95SVineet Gupta #include <linux/uaccess.h>
23854a0d95SVineet Gupta #include <linux/ptrace.h>
24854a0d95SVineet Gupta #include <asm/sections.h>
25854a0d95SVineet Gupta #include <asm/unaligned.h>
26854a0d95SVineet Gupta #include <asm/unwind.h>
27854a0d95SVineet Gupta 
28854a0d95SVineet Gupta extern char __start_unwind[], __end_unwind[];
29854a0d95SVineet Gupta /* extern const u8 __start_unwind_hdr[], __end_unwind_hdr[];*/
30854a0d95SVineet Gupta 
31854a0d95SVineet Gupta /* #define UNWIND_DEBUG */
32854a0d95SVineet Gupta 
33854a0d95SVineet Gupta #ifdef UNWIND_DEBUG
34854a0d95SVineet Gupta int dbg_unw;
35854a0d95SVineet Gupta #define unw_debug(fmt, ...)			\
36854a0d95SVineet Gupta do {						\
37854a0d95SVineet Gupta 	if (dbg_unw)				\
38854a0d95SVineet Gupta 		pr_info(fmt, ##__VA_ARGS__);	\
39854a0d95SVineet Gupta } while (0);
40854a0d95SVineet Gupta #else
41854a0d95SVineet Gupta #define unw_debug(fmt, ...)
42854a0d95SVineet Gupta #endif
43854a0d95SVineet Gupta 
44854a0d95SVineet Gupta #define MAX_STACK_DEPTH 8
45854a0d95SVineet Gupta 
46854a0d95SVineet Gupta #define EXTRA_INFO(f) { \
47854a0d95SVineet Gupta 		BUILD_BUG_ON_ZERO(offsetof(struct unwind_frame_info, f) \
48854a0d95SVineet Gupta 				% FIELD_SIZEOF(struct unwind_frame_info, f)) \
49854a0d95SVineet Gupta 				+ offsetof(struct unwind_frame_info, f) \
50854a0d95SVineet Gupta 				/ FIELD_SIZEOF(struct unwind_frame_info, f), \
51854a0d95SVineet Gupta 				FIELD_SIZEOF(struct unwind_frame_info, f) \
52854a0d95SVineet Gupta 	}
53854a0d95SVineet Gupta #define PTREGS_INFO(f) EXTRA_INFO(regs.f)
54854a0d95SVineet Gupta 
55854a0d95SVineet Gupta static const struct {
56854a0d95SVineet Gupta 	unsigned offs:BITS_PER_LONG / 2;
57854a0d95SVineet Gupta 	unsigned width:BITS_PER_LONG / 2;
58854a0d95SVineet Gupta } reg_info[] = {
59854a0d95SVineet Gupta UNW_REGISTER_INFO};
60854a0d95SVineet Gupta 
61854a0d95SVineet Gupta #undef PTREGS_INFO
62854a0d95SVineet Gupta #undef EXTRA_INFO
63854a0d95SVineet Gupta 
64854a0d95SVineet Gupta #ifndef REG_INVALID
65854a0d95SVineet Gupta #define REG_INVALID(r) (reg_info[r].width == 0)
66854a0d95SVineet Gupta #endif
67854a0d95SVineet Gupta 
68854a0d95SVineet Gupta #define DW_CFA_nop                          0x00
69854a0d95SVineet Gupta #define DW_CFA_set_loc                      0x01
70854a0d95SVineet Gupta #define DW_CFA_advance_loc1                 0x02
71854a0d95SVineet Gupta #define DW_CFA_advance_loc2                 0x03
72854a0d95SVineet Gupta #define DW_CFA_advance_loc4                 0x04
73854a0d95SVineet Gupta #define DW_CFA_offset_extended              0x05
74854a0d95SVineet Gupta #define DW_CFA_restore_extended             0x06
75854a0d95SVineet Gupta #define DW_CFA_undefined                    0x07
76854a0d95SVineet Gupta #define DW_CFA_same_value                   0x08
77854a0d95SVineet Gupta #define DW_CFA_register                     0x09
78854a0d95SVineet Gupta #define DW_CFA_remember_state               0x0a
79854a0d95SVineet Gupta #define DW_CFA_restore_state                0x0b
80854a0d95SVineet Gupta #define DW_CFA_def_cfa                      0x0c
81854a0d95SVineet Gupta #define DW_CFA_def_cfa_register             0x0d
82854a0d95SVineet Gupta #define DW_CFA_def_cfa_offset               0x0e
83854a0d95SVineet Gupta #define DW_CFA_def_cfa_expression           0x0f
84854a0d95SVineet Gupta #define DW_CFA_expression                   0x10
85854a0d95SVineet Gupta #define DW_CFA_offset_extended_sf           0x11
86854a0d95SVineet Gupta #define DW_CFA_def_cfa_sf                   0x12
87854a0d95SVineet Gupta #define DW_CFA_def_cfa_offset_sf            0x13
88854a0d95SVineet Gupta #define DW_CFA_val_offset                   0x14
89854a0d95SVineet Gupta #define DW_CFA_val_offset_sf                0x15
90854a0d95SVineet Gupta #define DW_CFA_val_expression               0x16
91854a0d95SVineet Gupta #define DW_CFA_lo_user                      0x1c
92854a0d95SVineet Gupta #define DW_CFA_GNU_window_save              0x2d
93854a0d95SVineet Gupta #define DW_CFA_GNU_args_size                0x2e
94854a0d95SVineet Gupta #define DW_CFA_GNU_negative_offset_extended 0x2f
95854a0d95SVineet Gupta #define DW_CFA_hi_user                      0x3f
96854a0d95SVineet Gupta 
97854a0d95SVineet Gupta #define DW_EH_PE_FORM     0x07
98854a0d95SVineet Gupta #define DW_EH_PE_native   0x00
99854a0d95SVineet Gupta #define DW_EH_PE_leb128   0x01
100854a0d95SVineet Gupta #define DW_EH_PE_data2    0x02
101854a0d95SVineet Gupta #define DW_EH_PE_data4    0x03
102854a0d95SVineet Gupta #define DW_EH_PE_data8    0x04
103854a0d95SVineet Gupta #define DW_EH_PE_signed   0x08
104854a0d95SVineet Gupta #define DW_EH_PE_ADJUST   0x70
105854a0d95SVineet Gupta #define DW_EH_PE_abs      0x00
106854a0d95SVineet Gupta #define DW_EH_PE_pcrel    0x10
107854a0d95SVineet Gupta #define DW_EH_PE_textrel  0x20
108854a0d95SVineet Gupta #define DW_EH_PE_datarel  0x30
109854a0d95SVineet Gupta #define DW_EH_PE_funcrel  0x40
110854a0d95SVineet Gupta #define DW_EH_PE_aligned  0x50
111854a0d95SVineet Gupta #define DW_EH_PE_indirect 0x80
112854a0d95SVineet Gupta #define DW_EH_PE_omit     0xff
113854a0d95SVineet Gupta 
1146716dbbdSVineet Gupta #define CIE_ID	0
115d040876bSVineet Gupta 
116854a0d95SVineet Gupta typedef unsigned long uleb128_t;
117854a0d95SVineet Gupta typedef signed long sleb128_t;
118854a0d95SVineet Gupta 
119854a0d95SVineet Gupta static struct unwind_table {
120854a0d95SVineet Gupta 	struct {
121854a0d95SVineet Gupta 		unsigned long pc;
122854a0d95SVineet Gupta 		unsigned long range;
123854a0d95SVineet Gupta 	} core, init;
124854a0d95SVineet Gupta 	const void *address;
125854a0d95SVineet Gupta 	unsigned long size;
126854a0d95SVineet Gupta 	const unsigned char *header;
127854a0d95SVineet Gupta 	unsigned long hdrsz;
128854a0d95SVineet Gupta 	struct unwind_table *link;
129854a0d95SVineet Gupta 	const char *name;
130854a0d95SVineet Gupta } root_table;
131854a0d95SVineet Gupta 
132854a0d95SVineet Gupta struct unwind_item {
133854a0d95SVineet Gupta 	enum item_location {
134854a0d95SVineet Gupta 		Nowhere,
135854a0d95SVineet Gupta 		Memory,
136854a0d95SVineet Gupta 		Register,
137854a0d95SVineet Gupta 		Value
138854a0d95SVineet Gupta 	} where;
139854a0d95SVineet Gupta 	uleb128_t value;
140854a0d95SVineet Gupta };
141854a0d95SVineet Gupta 
142854a0d95SVineet Gupta struct unwind_state {
143854a0d95SVineet Gupta 	uleb128_t loc, org;
144854a0d95SVineet Gupta 	const u8 *cieStart, *cieEnd;
145854a0d95SVineet Gupta 	uleb128_t codeAlign;
146854a0d95SVineet Gupta 	sleb128_t dataAlign;
147854a0d95SVineet Gupta 	struct cfa {
148854a0d95SVineet Gupta 		uleb128_t reg, offs;
149854a0d95SVineet Gupta 	} cfa;
150854a0d95SVineet Gupta 	struct unwind_item regs[ARRAY_SIZE(reg_info)];
151854a0d95SVineet Gupta 	unsigned stackDepth:8;
152854a0d95SVineet Gupta 	unsigned version:8;
153854a0d95SVineet Gupta 	const u8 *label;
154854a0d95SVineet Gupta 	const u8 *stack[MAX_STACK_DEPTH];
155854a0d95SVineet Gupta };
156854a0d95SVineet Gupta 
157854a0d95SVineet Gupta static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 };
158854a0d95SVineet Gupta 
159854a0d95SVineet Gupta static struct unwind_table *find_table(unsigned long pc)
160854a0d95SVineet Gupta {
161854a0d95SVineet Gupta 	struct unwind_table *table;
162854a0d95SVineet Gupta 
163854a0d95SVineet Gupta 	for (table = &root_table; table; table = table->link)
164854a0d95SVineet Gupta 		if ((pc >= table->core.pc
165854a0d95SVineet Gupta 		     && pc < table->core.pc + table->core.range)
166854a0d95SVineet Gupta 		    || (pc >= table->init.pc
167854a0d95SVineet Gupta 			&& pc < table->init.pc + table->init.range))
168854a0d95SVineet Gupta 			break;
169854a0d95SVineet Gupta 
170854a0d95SVineet Gupta 	return table;
171854a0d95SVineet Gupta }
172854a0d95SVineet Gupta 
173854a0d95SVineet Gupta static unsigned long read_pointer(const u8 **pLoc,
174854a0d95SVineet Gupta 				  const void *end, signed ptrType);
175bc79c9a7SVineet Gupta static void init_unwind_hdr(struct unwind_table *table,
176bc79c9a7SVineet Gupta 			    void *(*alloc) (unsigned long));
177bc79c9a7SVineet Gupta 
178bc79c9a7SVineet Gupta /*
179bc79c9a7SVineet Gupta  * wrappers for header alloc (vs. calling one vs. other at call site)
180bc79c9a7SVineet Gupta  * to elide section mismatches warnings
181bc79c9a7SVineet Gupta  */
182bc79c9a7SVineet Gupta static void *__init unw_hdr_alloc_early(unsigned long sz)
183bc79c9a7SVineet Gupta {
18426fb3daeSMike Rapoport 	return memblock_alloc_from(sz, sizeof(unsigned int), MAX_DMA_ADDRESS);
185bc79c9a7SVineet Gupta }
186bc79c9a7SVineet Gupta 
187bc79c9a7SVineet Gupta static void *unw_hdr_alloc(unsigned long sz)
188bc79c9a7SVineet Gupta {
189bc79c9a7SVineet Gupta 	return kmalloc(sz, GFP_KERNEL);
190bc79c9a7SVineet Gupta }
191854a0d95SVineet Gupta 
192854a0d95SVineet Gupta static void init_unwind_table(struct unwind_table *table, const char *name,
193854a0d95SVineet Gupta 			      const void *core_start, unsigned long core_size,
194854a0d95SVineet Gupta 			      const void *init_start, unsigned long init_size,
195854a0d95SVineet Gupta 			      const void *table_start, unsigned long table_size,
196854a0d95SVineet Gupta 			      const u8 *header_start, unsigned long header_size)
197854a0d95SVineet Gupta {
198854a0d95SVineet Gupta 	const u8 *ptr = header_start + 4;
199854a0d95SVineet Gupta 	const u8 *end = header_start + header_size;
200854a0d95SVineet Gupta 
201854a0d95SVineet Gupta 	table->core.pc = (unsigned long)core_start;
202854a0d95SVineet Gupta 	table->core.range = core_size;
203854a0d95SVineet Gupta 	table->init.pc = (unsigned long)init_start;
204854a0d95SVineet Gupta 	table->init.range = init_size;
205854a0d95SVineet Gupta 	table->address = table_start;
206854a0d95SVineet Gupta 	table->size = table_size;
207854a0d95SVineet Gupta 
208854a0d95SVineet Gupta 	/* See if the linker provided table looks valid. */
209854a0d95SVineet Gupta 	if (header_size <= 4
210854a0d95SVineet Gupta 	    || header_start[0] != 1
211854a0d95SVineet Gupta 	    || (void *)read_pointer(&ptr, end, header_start[1]) != table_start
212854a0d95SVineet Gupta 	    || header_start[2] == DW_EH_PE_omit
213854a0d95SVineet Gupta 	    || read_pointer(&ptr, end, header_start[2]) <= 0
214854a0d95SVineet Gupta 	    || header_start[3] == DW_EH_PE_omit)
215854a0d95SVineet Gupta 		header_start = NULL;
216854a0d95SVineet Gupta 
217854a0d95SVineet Gupta 	table->hdrsz = header_size;
218854a0d95SVineet Gupta 	smp_wmb();
219854a0d95SVineet Gupta 	table->header = header_start;
220854a0d95SVineet Gupta 	table->link = NULL;
221854a0d95SVineet Gupta 	table->name = name;
222854a0d95SVineet Gupta }
223854a0d95SVineet Gupta 
224854a0d95SVineet Gupta void __init arc_unwind_init(void)
225854a0d95SVineet Gupta {
226854a0d95SVineet Gupta 	init_unwind_table(&root_table, "kernel", _text, _end - _text, NULL, 0,
227854a0d95SVineet Gupta 			  __start_unwind, __end_unwind - __start_unwind,
228854a0d95SVineet Gupta 			  NULL, 0);
229854a0d95SVineet Gupta 	  /*__start_unwind_hdr, __end_unwind_hdr - __start_unwind_hdr);*/
230bc79c9a7SVineet Gupta 
231bc79c9a7SVineet Gupta 	init_unwind_hdr(&root_table, unw_hdr_alloc_early);
232854a0d95SVineet Gupta }
233854a0d95SVineet Gupta 
234854a0d95SVineet Gupta static const u32 bad_cie, not_fde;
235854a0d95SVineet Gupta static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *);
236d040876bSVineet Gupta static const u32 *__cie_for_fde(const u32 *fde);
237854a0d95SVineet Gupta static signed fde_pointer_type(const u32 *cie);
238854a0d95SVineet Gupta 
239854a0d95SVineet Gupta struct eh_frame_hdr_table_entry {
240854a0d95SVineet Gupta 	unsigned long start, fde;
241854a0d95SVineet Gupta };
242854a0d95SVineet Gupta 
243854a0d95SVineet Gupta static int cmp_eh_frame_hdr_table_entries(const void *p1, const void *p2)
244854a0d95SVineet Gupta {
245854a0d95SVineet Gupta 	const struct eh_frame_hdr_table_entry *e1 = p1;
246854a0d95SVineet Gupta 	const struct eh_frame_hdr_table_entry *e2 = p2;
247854a0d95SVineet Gupta 
248854a0d95SVineet Gupta 	return (e1->start > e2->start) - (e1->start < e2->start);
249854a0d95SVineet Gupta }
250854a0d95SVineet Gupta 
251854a0d95SVineet Gupta static void swap_eh_frame_hdr_table_entries(void *p1, void *p2, int size)
252854a0d95SVineet Gupta {
253854a0d95SVineet Gupta 	struct eh_frame_hdr_table_entry *e1 = p1;
254854a0d95SVineet Gupta 	struct eh_frame_hdr_table_entry *e2 = p2;
255854a0d95SVineet Gupta 	unsigned long v;
256854a0d95SVineet Gupta 
257854a0d95SVineet Gupta 	v = e1->start;
258854a0d95SVineet Gupta 	e1->start = e2->start;
259854a0d95SVineet Gupta 	e2->start = v;
260854a0d95SVineet Gupta 	v = e1->fde;
261854a0d95SVineet Gupta 	e1->fde = e2->fde;
262854a0d95SVineet Gupta 	e2->fde = v;
263854a0d95SVineet Gupta }
264854a0d95SVineet Gupta 
265bc79c9a7SVineet Gupta static void init_unwind_hdr(struct unwind_table *table,
266854a0d95SVineet Gupta 			    void *(*alloc) (unsigned long))
267854a0d95SVineet Gupta {
268854a0d95SVineet Gupta 	const u8 *ptr;
269854a0d95SVineet Gupta 	unsigned long tableSize = table->size, hdrSize;
270854a0d95SVineet Gupta 	unsigned n;
271854a0d95SVineet Gupta 	const u32 *fde;
272854a0d95SVineet Gupta 	struct {
273854a0d95SVineet Gupta 		u8 version;
274854a0d95SVineet Gupta 		u8 eh_frame_ptr_enc;
275854a0d95SVineet Gupta 		u8 fde_count_enc;
276854a0d95SVineet Gupta 		u8 table_enc;
277854a0d95SVineet Gupta 		unsigned long eh_frame_ptr;
278854a0d95SVineet Gupta 		unsigned int fde_count;
279854a0d95SVineet Gupta 		struct eh_frame_hdr_table_entry table[];
280854a0d95SVineet Gupta 	} __attribute__ ((__packed__)) *header;
281854a0d95SVineet Gupta 
282854a0d95SVineet Gupta 	if (table->header)
283854a0d95SVineet Gupta 		return;
284854a0d95SVineet Gupta 
285854a0d95SVineet Gupta 	if (table->hdrsz)
286854a0d95SVineet Gupta 		pr_warn(".eh_frame_hdr for '%s' present but unusable\n",
287854a0d95SVineet Gupta 			table->name);
288854a0d95SVineet Gupta 
289854a0d95SVineet Gupta 	if (tableSize & (sizeof(*fde) - 1))
290854a0d95SVineet Gupta 		return;
291854a0d95SVineet Gupta 
292854a0d95SVineet Gupta 	for (fde = table->address, n = 0;
293854a0d95SVineet Gupta 	     tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde;
294854a0d95SVineet Gupta 	     tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
295854a0d95SVineet Gupta 		const u32 *cie = cie_for_fde(fde, table);
296854a0d95SVineet Gupta 		signed ptrType;
297854a0d95SVineet Gupta 
2982d64affcSVineet Gupta 		if (cie == &not_fde)
299854a0d95SVineet Gupta 			continue;
300854a0d95SVineet Gupta 		if (cie == NULL || cie == &bad_cie)
3016b538db7SVineet Gupta 			goto ret_err;
302854a0d95SVineet Gupta 		ptrType = fde_pointer_type(cie);
303854a0d95SVineet Gupta 		if (ptrType < 0)
3046b538db7SVineet Gupta 			goto ret_err;
305854a0d95SVineet Gupta 
306854a0d95SVineet Gupta 		ptr = (const u8 *)(fde + 2);
307854a0d95SVineet Gupta 		if (!read_pointer(&ptr, (const u8 *)(fde + 1) + *fde,
308854a0d95SVineet Gupta 								ptrType)) {
309854a0d95SVineet Gupta 			/* FIXME_Rajesh We have 4 instances of null addresses
310854a0d95SVineet Gupta 			 * instead of the initial loc addr
311854a0d95SVineet Gupta 			 * return;
312854a0d95SVineet Gupta 			 */
313baadb8fdSVineet Gupta 			WARN(1, "unwinder: FDE->initial_location NULL %p\n",
314baadb8fdSVineet Gupta 				(const u8 *)(fde + 1) + *fde);
315854a0d95SVineet Gupta 		}
316854a0d95SVineet Gupta 		++n;
317854a0d95SVineet Gupta 	}
318854a0d95SVineet Gupta 
319854a0d95SVineet Gupta 	if (tableSize || !n)
3206b538db7SVineet Gupta 		goto ret_err;
321854a0d95SVineet Gupta 
322854a0d95SVineet Gupta 	hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int)
323854a0d95SVineet Gupta 	    + 2 * n * sizeof(unsigned long);
324bc79c9a7SVineet Gupta 
325854a0d95SVineet Gupta 	header = alloc(hdrSize);
326854a0d95SVineet Gupta 	if (!header)
3276b538db7SVineet Gupta 		goto ret_err;
328bc79c9a7SVineet Gupta 
329854a0d95SVineet Gupta 	header->version = 1;
330854a0d95SVineet Gupta 	header->eh_frame_ptr_enc = DW_EH_PE_abs | DW_EH_PE_native;
331854a0d95SVineet Gupta 	header->fde_count_enc = DW_EH_PE_abs | DW_EH_PE_data4;
332854a0d95SVineet Gupta 	header->table_enc = DW_EH_PE_abs | DW_EH_PE_native;
333854a0d95SVineet Gupta 	put_unaligned((unsigned long)table->address, &header->eh_frame_ptr);
334854a0d95SVineet Gupta 	BUILD_BUG_ON(offsetof(typeof(*header), fde_count)
335854a0d95SVineet Gupta 		     % __alignof(typeof(header->fde_count)));
336854a0d95SVineet Gupta 	header->fde_count = n;
337854a0d95SVineet Gupta 
338854a0d95SVineet Gupta 	BUILD_BUG_ON(offsetof(typeof(*header), table)
339854a0d95SVineet Gupta 		     % __alignof(typeof(*header->table)));
340854a0d95SVineet Gupta 	for (fde = table->address, tableSize = table->size, n = 0;
341854a0d95SVineet Gupta 	     tableSize;
342854a0d95SVineet Gupta 	     tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
343d040876bSVineet Gupta 		const u32 *cie = __cie_for_fde(fde);
344854a0d95SVineet Gupta 
345d040876bSVineet Gupta 		if (fde[1] == CIE_ID)
346854a0d95SVineet Gupta 			continue;	/* this is a CIE */
347854a0d95SVineet Gupta 		ptr = (const u8 *)(fde + 2);
348854a0d95SVineet Gupta 		header->table[n].start = read_pointer(&ptr,
349854a0d95SVineet Gupta 						      (const u8 *)(fde + 1) +
350854a0d95SVineet Gupta 						      *fde,
351854a0d95SVineet Gupta 						      fde_pointer_type(cie));
352854a0d95SVineet Gupta 		header->table[n].fde = (unsigned long)fde;
353854a0d95SVineet Gupta 		++n;
354854a0d95SVineet Gupta 	}
355854a0d95SVineet Gupta 	WARN_ON(n != header->fde_count);
356854a0d95SVineet Gupta 
357854a0d95SVineet Gupta 	sort(header->table,
358854a0d95SVineet Gupta 	     n,
359854a0d95SVineet Gupta 	     sizeof(*header->table),
360854a0d95SVineet Gupta 	     cmp_eh_frame_hdr_table_entries, swap_eh_frame_hdr_table_entries);
361854a0d95SVineet Gupta 
362854a0d95SVineet Gupta 	table->hdrsz = hdrSize;
363854a0d95SVineet Gupta 	smp_wmb();
364854a0d95SVineet Gupta 	table->header = (const void *)header;
3656b538db7SVineet Gupta 	return;
3666b538db7SVineet Gupta 
3676b538db7SVineet Gupta ret_err:
368ed7158baSIngo Molnar 	panic("Attention !!! Dwarf FDE parsing errors\n");
369854a0d95SVineet Gupta }
370854a0d95SVineet Gupta 
371854a0d95SVineet Gupta #ifdef CONFIG_MODULES
372854a0d95SVineet Gupta 
373854a0d95SVineet Gupta static struct unwind_table *last_table;
374854a0d95SVineet Gupta 
375854a0d95SVineet Gupta /* Must be called with module_mutex held. */
376854a0d95SVineet Gupta void *unwind_add_table(struct module *module, const void *table_start,
377854a0d95SVineet Gupta 		       unsigned long table_size)
378854a0d95SVineet Gupta {
379854a0d95SVineet Gupta 	struct unwind_table *table;
380854a0d95SVineet Gupta 
381854a0d95SVineet Gupta 	if (table_size <= 0)
382854a0d95SVineet Gupta 		return NULL;
383854a0d95SVineet Gupta 
384854a0d95SVineet Gupta 	table = kmalloc(sizeof(*table), GFP_KERNEL);
385854a0d95SVineet Gupta 	if (!table)
386854a0d95SVineet Gupta 		return NULL;
387854a0d95SVineet Gupta 
388854a0d95SVineet Gupta 	init_unwind_table(table, module->name,
3897523e4dcSRusty Russell 			  module->core_layout.base, module->core_layout.size,
3907523e4dcSRusty Russell 			  module->init_layout.base, module->init_layout.size,
391854a0d95SVineet Gupta 			  table_start, table_size,
392854a0d95SVineet Gupta 			  NULL, 0);
393854a0d95SVineet Gupta 
394bc79c9a7SVineet Gupta 	init_unwind_hdr(table, unw_hdr_alloc);
395bc79c9a7SVineet Gupta 
396854a0d95SVineet Gupta #ifdef UNWIND_DEBUG
397854a0d95SVineet Gupta 	unw_debug("Table added for [%s] %lx %lx\n",
398854a0d95SVineet Gupta 		module->name, table->core.pc, table->core.range);
399854a0d95SVineet Gupta #endif
400854a0d95SVineet Gupta 	if (last_table)
401854a0d95SVineet Gupta 		last_table->link = table;
402854a0d95SVineet Gupta 	else
403854a0d95SVineet Gupta 		root_table.link = table;
404854a0d95SVineet Gupta 	last_table = table;
405854a0d95SVineet Gupta 
406854a0d95SVineet Gupta 	return table;
407854a0d95SVineet Gupta }
408854a0d95SVineet Gupta 
409854a0d95SVineet Gupta struct unlink_table_info {
410854a0d95SVineet Gupta 	struct unwind_table *table;
411854a0d95SVineet Gupta 	int init_only;
412854a0d95SVineet Gupta };
413854a0d95SVineet Gupta 
414854a0d95SVineet Gupta static int unlink_table(void *arg)
415854a0d95SVineet Gupta {
416854a0d95SVineet Gupta 	struct unlink_table_info *info = arg;
417854a0d95SVineet Gupta 	struct unwind_table *table = info->table, *prev;
418854a0d95SVineet Gupta 
419854a0d95SVineet Gupta 	for (prev = &root_table; prev->link && prev->link != table;
420854a0d95SVineet Gupta 	     prev = prev->link)
421854a0d95SVineet Gupta 		;
422854a0d95SVineet Gupta 
423854a0d95SVineet Gupta 	if (prev->link) {
424854a0d95SVineet Gupta 		if (info->init_only) {
425854a0d95SVineet Gupta 			table->init.pc = 0;
426854a0d95SVineet Gupta 			table->init.range = 0;
427854a0d95SVineet Gupta 			info->table = NULL;
428854a0d95SVineet Gupta 		} else {
429854a0d95SVineet Gupta 			prev->link = table->link;
430854a0d95SVineet Gupta 			if (!prev->link)
431854a0d95SVineet Gupta 				last_table = prev;
432854a0d95SVineet Gupta 		}
433854a0d95SVineet Gupta 	} else
434854a0d95SVineet Gupta 		info->table = NULL;
435854a0d95SVineet Gupta 
436854a0d95SVineet Gupta 	return 0;
437854a0d95SVineet Gupta }
438854a0d95SVineet Gupta 
439854a0d95SVineet Gupta /* Must be called with module_mutex held. */
440854a0d95SVineet Gupta void unwind_remove_table(void *handle, int init_only)
441854a0d95SVineet Gupta {
442854a0d95SVineet Gupta 	struct unwind_table *table = handle;
443854a0d95SVineet Gupta 	struct unlink_table_info info;
444854a0d95SVineet Gupta 
445854a0d95SVineet Gupta 	if (!table || table == &root_table)
446854a0d95SVineet Gupta 		return;
447854a0d95SVineet Gupta 
448854a0d95SVineet Gupta 	if (init_only && table == last_table) {
449854a0d95SVineet Gupta 		table->init.pc = 0;
450854a0d95SVineet Gupta 		table->init.range = 0;
451854a0d95SVineet Gupta 		return;
452854a0d95SVineet Gupta 	}
453854a0d95SVineet Gupta 
454854a0d95SVineet Gupta 	info.table = table;
455854a0d95SVineet Gupta 	info.init_only = init_only;
456854a0d95SVineet Gupta 
457854a0d95SVineet Gupta 	unlink_table(&info); /* XXX: SMP */
458bc79c9a7SVineet Gupta 	kfree(table->header);
459854a0d95SVineet Gupta 	kfree(table);
460854a0d95SVineet Gupta }
461854a0d95SVineet Gupta 
462854a0d95SVineet Gupta #endif /* CONFIG_MODULES */
463854a0d95SVineet Gupta 
464854a0d95SVineet Gupta static uleb128_t get_uleb128(const u8 **pcur, const u8 *end)
465854a0d95SVineet Gupta {
466854a0d95SVineet Gupta 	const u8 *cur = *pcur;
467854a0d95SVineet Gupta 	uleb128_t value;
468854a0d95SVineet Gupta 	unsigned shift;
469854a0d95SVineet Gupta 
470854a0d95SVineet Gupta 	for (shift = 0, value = 0; cur < end; shift += 7) {
471854a0d95SVineet Gupta 		if (shift + 7 > 8 * sizeof(value)
472854a0d95SVineet Gupta 		    && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
473854a0d95SVineet Gupta 			cur = end + 1;
474854a0d95SVineet Gupta 			break;
475854a0d95SVineet Gupta 		}
476854a0d95SVineet Gupta 		value |= (uleb128_t) (*cur & 0x7f) << shift;
477854a0d95SVineet Gupta 		if (!(*cur++ & 0x80))
478854a0d95SVineet Gupta 			break;
479854a0d95SVineet Gupta 	}
480854a0d95SVineet Gupta 	*pcur = cur;
481854a0d95SVineet Gupta 
482854a0d95SVineet Gupta 	return value;
483854a0d95SVineet Gupta }
484854a0d95SVineet Gupta 
485854a0d95SVineet Gupta static sleb128_t get_sleb128(const u8 **pcur, const u8 *end)
486854a0d95SVineet Gupta {
487854a0d95SVineet Gupta 	const u8 *cur = *pcur;
488854a0d95SVineet Gupta 	sleb128_t value;
489854a0d95SVineet Gupta 	unsigned shift;
490854a0d95SVineet Gupta 
491854a0d95SVineet Gupta 	for (shift = 0, value = 0; cur < end; shift += 7) {
492854a0d95SVineet Gupta 		if (shift + 7 > 8 * sizeof(value)
493854a0d95SVineet Gupta 		    && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
494854a0d95SVineet Gupta 			cur = end + 1;
495854a0d95SVineet Gupta 			break;
496854a0d95SVineet Gupta 		}
497854a0d95SVineet Gupta 		value |= (sleb128_t) (*cur & 0x7f) << shift;
498854a0d95SVineet Gupta 		if (!(*cur & 0x80)) {
499854a0d95SVineet Gupta 			value |= -(*cur++ & 0x40) << shift;
500854a0d95SVineet Gupta 			break;
501854a0d95SVineet Gupta 		}
502854a0d95SVineet Gupta 	}
503854a0d95SVineet Gupta 	*pcur = cur;
504854a0d95SVineet Gupta 
505854a0d95SVineet Gupta 	return value;
506854a0d95SVineet Gupta }
507854a0d95SVineet Gupta 
508d040876bSVineet Gupta static const u32 *__cie_for_fde(const u32 *fde)
509d040876bSVineet Gupta {
510d040876bSVineet Gupta 	const u32 *cie;
511d040876bSVineet Gupta 
5126716dbbdSVineet Gupta 	cie = fde + 1 - fde[1] / sizeof(*fde);
513d040876bSVineet Gupta 
514d040876bSVineet Gupta 	return cie;
515d040876bSVineet Gupta }
516d040876bSVineet Gupta 
517854a0d95SVineet Gupta static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *table)
518854a0d95SVineet Gupta {
519854a0d95SVineet Gupta 	const u32 *cie;
520854a0d95SVineet Gupta 
521854a0d95SVineet Gupta 	if (!*fde || (*fde & (sizeof(*fde) - 1)))
522854a0d95SVineet Gupta 		return &bad_cie;
523854a0d95SVineet Gupta 
524d040876bSVineet Gupta 	if (fde[1] == CIE_ID)
525854a0d95SVineet Gupta 		return &not_fde;	/* this is a CIE */
526854a0d95SVineet Gupta 
527854a0d95SVineet Gupta 	if ((fde[1] & (sizeof(*fde) - 1)))
528854a0d95SVineet Gupta /* || fde[1] > (unsigned long)(fde + 1) - (unsigned long)table->address) */
529854a0d95SVineet Gupta 		return NULL;	/* this is not a valid FDE */
530854a0d95SVineet Gupta 
531d040876bSVineet Gupta 	cie = __cie_for_fde(fde);
532854a0d95SVineet Gupta 
533854a0d95SVineet Gupta 	if (*cie <= sizeof(*cie) + 4 || *cie >= fde[1] - sizeof(*fde)
534854a0d95SVineet Gupta 	    || (*cie & (sizeof(*cie) - 1))
535d040876bSVineet Gupta 	    || (cie[1] != CIE_ID))
536854a0d95SVineet Gupta 		return NULL;	/* this is not a (valid) CIE */
537854a0d95SVineet Gupta 	return cie;
538854a0d95SVineet Gupta }
539854a0d95SVineet Gupta 
540854a0d95SVineet Gupta static unsigned long read_pointer(const u8 **pLoc, const void *end,
541854a0d95SVineet Gupta 				  signed ptrType)
542854a0d95SVineet Gupta {
543854a0d95SVineet Gupta 	unsigned long value = 0;
544854a0d95SVineet Gupta 	union {
545854a0d95SVineet Gupta 		const u8 *p8;
546854a0d95SVineet Gupta 		const u16 *p16u;
547854a0d95SVineet Gupta 		const s16 *p16s;
548854a0d95SVineet Gupta 		const u32 *p32u;
549854a0d95SVineet Gupta 		const s32 *p32s;
550854a0d95SVineet Gupta 		const unsigned long *pul;
551854a0d95SVineet Gupta 	} ptr;
552854a0d95SVineet Gupta 
553854a0d95SVineet Gupta 	if (ptrType < 0 || ptrType == DW_EH_PE_omit)
554854a0d95SVineet Gupta 		return 0;
555854a0d95SVineet Gupta 	ptr.p8 = *pLoc;
556854a0d95SVineet Gupta 	switch (ptrType & DW_EH_PE_FORM) {
557854a0d95SVineet Gupta 	case DW_EH_PE_data2:
558854a0d95SVineet Gupta 		if (end < (const void *)(ptr.p16u + 1))
559854a0d95SVineet Gupta 			return 0;
560854a0d95SVineet Gupta 		if (ptrType & DW_EH_PE_signed)
561854a0d95SVineet Gupta 			value = get_unaligned((u16 *) ptr.p16s++);
562854a0d95SVineet Gupta 		else
563854a0d95SVineet Gupta 			value = get_unaligned((u16 *) ptr.p16u++);
564854a0d95SVineet Gupta 		break;
565854a0d95SVineet Gupta 	case DW_EH_PE_data4:
566854a0d95SVineet Gupta #ifdef CONFIG_64BIT
567854a0d95SVineet Gupta 		if (end < (const void *)(ptr.p32u + 1))
568854a0d95SVineet Gupta 			return 0;
569854a0d95SVineet Gupta 		if (ptrType & DW_EH_PE_signed)
570854a0d95SVineet Gupta 			value = get_unaligned(ptr.p32s++);
571854a0d95SVineet Gupta 		else
572854a0d95SVineet Gupta 			value = get_unaligned(ptr.p32u++);
573854a0d95SVineet Gupta 		break;
574854a0d95SVineet Gupta 	case DW_EH_PE_data8:
575854a0d95SVineet Gupta 		BUILD_BUG_ON(sizeof(u64) != sizeof(value));
576854a0d95SVineet Gupta #else
577854a0d95SVineet Gupta 		BUILD_BUG_ON(sizeof(u32) != sizeof(value));
578854a0d95SVineet Gupta #endif
579854a0d95SVineet Gupta 	case DW_EH_PE_native:
580854a0d95SVineet Gupta 		if (end < (const void *)(ptr.pul + 1))
581854a0d95SVineet Gupta 			return 0;
582854a0d95SVineet Gupta 		value = get_unaligned((unsigned long *)ptr.pul++);
583854a0d95SVineet Gupta 		break;
584854a0d95SVineet Gupta 	case DW_EH_PE_leb128:
585854a0d95SVineet Gupta 		BUILD_BUG_ON(sizeof(uleb128_t) > sizeof(value));
586854a0d95SVineet Gupta 		value = ptrType & DW_EH_PE_signed ? get_sleb128(&ptr.p8, end)
587854a0d95SVineet Gupta 		    : get_uleb128(&ptr.p8, end);
588854a0d95SVineet Gupta 		if ((const void *)ptr.p8 > end)
589854a0d95SVineet Gupta 			return 0;
590854a0d95SVineet Gupta 		break;
591854a0d95SVineet Gupta 	default:
592854a0d95SVineet Gupta 		return 0;
593854a0d95SVineet Gupta 	}
594854a0d95SVineet Gupta 	switch (ptrType & DW_EH_PE_ADJUST) {
595854a0d95SVineet Gupta 	case DW_EH_PE_abs:
596854a0d95SVineet Gupta 		break;
597854a0d95SVineet Gupta 	case DW_EH_PE_pcrel:
598854a0d95SVineet Gupta 		value += (unsigned long)*pLoc;
599854a0d95SVineet Gupta 		break;
600854a0d95SVineet Gupta 	default:
601854a0d95SVineet Gupta 		return 0;
602854a0d95SVineet Gupta 	}
603854a0d95SVineet Gupta 	if ((ptrType & DW_EH_PE_indirect)
604854a0d95SVineet Gupta 	    && __get_user(value, (unsigned long __user *)value))
605854a0d95SVineet Gupta 		return 0;
606854a0d95SVineet Gupta 	*pLoc = ptr.p8;
607854a0d95SVineet Gupta 
608854a0d95SVineet Gupta 	return value;
609854a0d95SVineet Gupta }
610854a0d95SVineet Gupta 
611854a0d95SVineet Gupta static signed fde_pointer_type(const u32 *cie)
612854a0d95SVineet Gupta {
613854a0d95SVineet Gupta 	const u8 *ptr = (const u8 *)(cie + 2);
614854a0d95SVineet Gupta 	unsigned version = *ptr;
615854a0d95SVineet Gupta 
616854a0d95SVineet Gupta 	if (*++ptr) {
617854a0d95SVineet Gupta 		const char *aug;
618854a0d95SVineet Gupta 		const u8 *end = (const u8 *)(cie + 1) + *cie;
619854a0d95SVineet Gupta 		uleb128_t len;
620854a0d95SVineet Gupta 
621854a0d95SVineet Gupta 		/* check if augmentation size is first (and thus present) */
622854a0d95SVineet Gupta 		if (*ptr != 'z')
623854a0d95SVineet Gupta 			return -1;
624854a0d95SVineet Gupta 
625854a0d95SVineet Gupta 		/* check if augmentation string is nul-terminated */
626854a0d95SVineet Gupta 		aug = (const void *)ptr;
627854a0d95SVineet Gupta 		ptr = memchr(aug, 0, end - ptr);
628854a0d95SVineet Gupta 		if (ptr == NULL)
629854a0d95SVineet Gupta 			return -1;
630854a0d95SVineet Gupta 
631854a0d95SVineet Gupta 		++ptr;		/* skip terminator */
632854a0d95SVineet Gupta 		get_uleb128(&ptr, end);	/* skip code alignment */
633854a0d95SVineet Gupta 		get_sleb128(&ptr, end);	/* skip data alignment */
634854a0d95SVineet Gupta 		/* skip return address column */
635854a0d95SVineet Gupta 		version <= 1 ? (void) ++ptr : (void)get_uleb128(&ptr, end);
636854a0d95SVineet Gupta 		len = get_uleb128(&ptr, end);	/* augmentation length */
637854a0d95SVineet Gupta 
638854a0d95SVineet Gupta 		if (ptr + len < ptr || ptr + len > end)
639854a0d95SVineet Gupta 			return -1;
640854a0d95SVineet Gupta 
641854a0d95SVineet Gupta 		end = ptr + len;
642854a0d95SVineet Gupta 		while (*++aug) {
643854a0d95SVineet Gupta 			if (ptr >= end)
644854a0d95SVineet Gupta 				return -1;
645854a0d95SVineet Gupta 			switch (*aug) {
646854a0d95SVineet Gupta 			case 'L':
647854a0d95SVineet Gupta 				++ptr;
648854a0d95SVineet Gupta 				break;
649854a0d95SVineet Gupta 			case 'P':{
650854a0d95SVineet Gupta 					signed ptrType = *ptr++;
651854a0d95SVineet Gupta 
652854a0d95SVineet Gupta 					if (!read_pointer(&ptr, end, ptrType)
653854a0d95SVineet Gupta 					    || ptr > end)
654854a0d95SVineet Gupta 						return -1;
655854a0d95SVineet Gupta 				}
656854a0d95SVineet Gupta 				break;
657854a0d95SVineet Gupta 			case 'R':
658854a0d95SVineet Gupta 				return *ptr;
659854a0d95SVineet Gupta 			default:
660854a0d95SVineet Gupta 				return -1;
661854a0d95SVineet Gupta 			}
662854a0d95SVineet Gupta 		}
663854a0d95SVineet Gupta 	}
664854a0d95SVineet Gupta 	return DW_EH_PE_native | DW_EH_PE_abs;
665854a0d95SVineet Gupta }
666854a0d95SVineet Gupta 
667854a0d95SVineet Gupta static int advance_loc(unsigned long delta, struct unwind_state *state)
668854a0d95SVineet Gupta {
669854a0d95SVineet Gupta 	state->loc += delta * state->codeAlign;
670854a0d95SVineet Gupta 
671854a0d95SVineet Gupta 	/* FIXME_Rajesh: Probably we are defining for the initial range as well;
672854a0d95SVineet Gupta 	   return delta > 0;
673854a0d95SVineet Gupta 	 */
674854a0d95SVineet Gupta 	unw_debug("delta %3lu => loc 0x%lx: ", delta, state->loc);
675854a0d95SVineet Gupta 	return 1;
676854a0d95SVineet Gupta }
677854a0d95SVineet Gupta 
678854a0d95SVineet Gupta static void set_rule(uleb128_t reg, enum item_location where, uleb128_t value,
679854a0d95SVineet Gupta 		     struct unwind_state *state)
680854a0d95SVineet Gupta {
681854a0d95SVineet Gupta 	if (reg < ARRAY_SIZE(state->regs)) {
682854a0d95SVineet Gupta 		state->regs[reg].where = where;
683854a0d95SVineet Gupta 		state->regs[reg].value = value;
684854a0d95SVineet Gupta 
685854a0d95SVineet Gupta #ifdef UNWIND_DEBUG
686854a0d95SVineet Gupta 		unw_debug("r%lu: ", reg);
687854a0d95SVineet Gupta 		switch (where) {
688854a0d95SVineet Gupta 		case Nowhere:
689854a0d95SVineet Gupta 			unw_debug("s ");
690854a0d95SVineet Gupta 			break;
691854a0d95SVineet Gupta 		case Memory:
692854a0d95SVineet Gupta 			unw_debug("c(%lu) ", value);
693854a0d95SVineet Gupta 			break;
694854a0d95SVineet Gupta 		case Register:
695854a0d95SVineet Gupta 			unw_debug("r(%lu) ", value);
696854a0d95SVineet Gupta 			break;
697854a0d95SVineet Gupta 		case Value:
698854a0d95SVineet Gupta 			unw_debug("v(%lu) ", value);
699854a0d95SVineet Gupta 			break;
700854a0d95SVineet Gupta 		default:
701854a0d95SVineet Gupta 			break;
702854a0d95SVineet Gupta 		}
703854a0d95SVineet Gupta #endif
704854a0d95SVineet Gupta 	}
705854a0d95SVineet Gupta }
706854a0d95SVineet Gupta 
707854a0d95SVineet Gupta static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
708854a0d95SVineet Gupta 		      signed ptrType, struct unwind_state *state)
709854a0d95SVineet Gupta {
710854a0d95SVineet Gupta 	union {
711854a0d95SVineet Gupta 		const u8 *p8;
712854a0d95SVineet Gupta 		const u16 *p16;
713854a0d95SVineet Gupta 		const u32 *p32;
714854a0d95SVineet Gupta 	} ptr;
715854a0d95SVineet Gupta 	int result = 1;
716854a0d95SVineet Gupta 	u8 opcode;
717854a0d95SVineet Gupta 
718854a0d95SVineet Gupta 	if (start != state->cieStart) {
719854a0d95SVineet Gupta 		state->loc = state->org;
720854a0d95SVineet Gupta 		result =
721854a0d95SVineet Gupta 		    processCFI(state->cieStart, state->cieEnd, 0, ptrType,
722854a0d95SVineet Gupta 			       state);
723854a0d95SVineet Gupta 		if (targetLoc == 0 && state->label == NULL)
724854a0d95SVineet Gupta 			return result;
725854a0d95SVineet Gupta 	}
726854a0d95SVineet Gupta 	for (ptr.p8 = start; result && ptr.p8 < end;) {
727854a0d95SVineet Gupta 		switch (*ptr.p8 >> 6) {
728854a0d95SVineet Gupta 			uleb128_t value;
729854a0d95SVineet Gupta 
730854a0d95SVineet Gupta 		case 0:
731854a0d95SVineet Gupta 			opcode = *ptr.p8++;
732854a0d95SVineet Gupta 
733854a0d95SVineet Gupta 			switch (opcode) {
734854a0d95SVineet Gupta 			case DW_CFA_nop:
735854a0d95SVineet Gupta 				unw_debug("cfa nop ");
736854a0d95SVineet Gupta 				break;
737854a0d95SVineet Gupta 			case DW_CFA_set_loc:
738854a0d95SVineet Gupta 				state->loc = read_pointer(&ptr.p8, end,
739854a0d95SVineet Gupta 							  ptrType);
740854a0d95SVineet Gupta 				if (state->loc == 0)
741854a0d95SVineet Gupta 					result = 0;
742854a0d95SVineet Gupta 				unw_debug("cfa_set_loc: 0x%lx ", state->loc);
743854a0d95SVineet Gupta 				break;
744854a0d95SVineet Gupta 			case DW_CFA_advance_loc1:
745854a0d95SVineet Gupta 				unw_debug("\ncfa advance loc1:");
746854a0d95SVineet Gupta 				result = ptr.p8 < end
747854a0d95SVineet Gupta 				    && advance_loc(*ptr.p8++, state);
748854a0d95SVineet Gupta 				break;
749854a0d95SVineet Gupta 			case DW_CFA_advance_loc2:
750854a0d95SVineet Gupta 				value = *ptr.p8++;
751854a0d95SVineet Gupta 				value += *ptr.p8++ << 8;
752854a0d95SVineet Gupta 				unw_debug("\ncfa advance loc2:");
753854a0d95SVineet Gupta 				result = ptr.p8 <= end + 2
754854a0d95SVineet Gupta 				    /* && advance_loc(*ptr.p16++, state); */
755854a0d95SVineet Gupta 				    && advance_loc(value, state);
756854a0d95SVineet Gupta 				break;
757854a0d95SVineet Gupta 			case DW_CFA_advance_loc4:
758854a0d95SVineet Gupta 				unw_debug("\ncfa advance loc4:");
759854a0d95SVineet Gupta 				result = ptr.p8 <= end + 4
760854a0d95SVineet Gupta 				    && advance_loc(*ptr.p32++, state);
761854a0d95SVineet Gupta 				break;
762854a0d95SVineet Gupta 			case DW_CFA_offset_extended:
763854a0d95SVineet Gupta 				value = get_uleb128(&ptr.p8, end);
764854a0d95SVineet Gupta 				unw_debug("cfa_offset_extended: ");
765854a0d95SVineet Gupta 				set_rule(value, Memory,
766854a0d95SVineet Gupta 					 get_uleb128(&ptr.p8, end), state);
767854a0d95SVineet Gupta 				break;
768854a0d95SVineet Gupta 			case DW_CFA_val_offset:
769854a0d95SVineet Gupta 				value = get_uleb128(&ptr.p8, end);
770854a0d95SVineet Gupta 				set_rule(value, Value,
771854a0d95SVineet Gupta 					 get_uleb128(&ptr.p8, end), state);
772854a0d95SVineet Gupta 				break;
773854a0d95SVineet Gupta 			case DW_CFA_offset_extended_sf:
774854a0d95SVineet Gupta 				value = get_uleb128(&ptr.p8, end);
775854a0d95SVineet Gupta 				set_rule(value, Memory,
776854a0d95SVineet Gupta 					 get_sleb128(&ptr.p8, end), state);
777854a0d95SVineet Gupta 				break;
778854a0d95SVineet Gupta 			case DW_CFA_val_offset_sf:
779854a0d95SVineet Gupta 				value = get_uleb128(&ptr.p8, end);
780854a0d95SVineet Gupta 				set_rule(value, Value,
781854a0d95SVineet Gupta 					 get_sleb128(&ptr.p8, end), state);
782854a0d95SVineet Gupta 				break;
783854a0d95SVineet Gupta 			case DW_CFA_restore_extended:
784854a0d95SVineet Gupta 				unw_debug("cfa_restore_extended: ");
785854a0d95SVineet Gupta 			case DW_CFA_undefined:
786854a0d95SVineet Gupta 				unw_debug("cfa_undefined: ");
787854a0d95SVineet Gupta 			case DW_CFA_same_value:
788854a0d95SVineet Gupta 				unw_debug("cfa_same_value: ");
789854a0d95SVineet Gupta 				set_rule(get_uleb128(&ptr.p8, end), Nowhere, 0,
790854a0d95SVineet Gupta 					 state);
791854a0d95SVineet Gupta 				break;
792854a0d95SVineet Gupta 			case DW_CFA_register:
793854a0d95SVineet Gupta 				unw_debug("cfa_register: ");
794854a0d95SVineet Gupta 				value = get_uleb128(&ptr.p8, end);
795854a0d95SVineet Gupta 				set_rule(value,
796854a0d95SVineet Gupta 					 Register,
797854a0d95SVineet Gupta 					 get_uleb128(&ptr.p8, end), state);
798854a0d95SVineet Gupta 				break;
799854a0d95SVineet Gupta 			case DW_CFA_remember_state:
800854a0d95SVineet Gupta 				unw_debug("cfa_remember_state: ");
801854a0d95SVineet Gupta 				if (ptr.p8 == state->label) {
802854a0d95SVineet Gupta 					state->label = NULL;
803854a0d95SVineet Gupta 					return 1;
804854a0d95SVineet Gupta 				}
805854a0d95SVineet Gupta 				if (state->stackDepth >= MAX_STACK_DEPTH)
806854a0d95SVineet Gupta 					return 0;
807854a0d95SVineet Gupta 				state->stack[state->stackDepth++] = ptr.p8;
808854a0d95SVineet Gupta 				break;
809854a0d95SVineet Gupta 			case DW_CFA_restore_state:
810854a0d95SVineet Gupta 				unw_debug("cfa_restore_state: ");
811854a0d95SVineet Gupta 				if (state->stackDepth) {
812854a0d95SVineet Gupta 					const uleb128_t loc = state->loc;
813854a0d95SVineet Gupta 					const u8 *label = state->label;
814854a0d95SVineet Gupta 
815854a0d95SVineet Gupta 					state->label =
816854a0d95SVineet Gupta 					    state->stack[state->stackDepth - 1];
817854a0d95SVineet Gupta 					memcpy(&state->cfa, &badCFA,
818854a0d95SVineet Gupta 					       sizeof(state->cfa));
819854a0d95SVineet Gupta 					memset(state->regs, 0,
820854a0d95SVineet Gupta 					       sizeof(state->regs));
821854a0d95SVineet Gupta 					state->stackDepth = 0;
822854a0d95SVineet Gupta 					result =
823854a0d95SVineet Gupta 					    processCFI(start, end, 0, ptrType,
824854a0d95SVineet Gupta 						       state);
825854a0d95SVineet Gupta 					state->loc = loc;
826854a0d95SVineet Gupta 					state->label = label;
827854a0d95SVineet Gupta 				} else
828854a0d95SVineet Gupta 					return 0;
829854a0d95SVineet Gupta 				break;
830854a0d95SVineet Gupta 			case DW_CFA_def_cfa:
831854a0d95SVineet Gupta 				state->cfa.reg = get_uleb128(&ptr.p8, end);
832854a0d95SVineet Gupta 				unw_debug("cfa_def_cfa: r%lu ", state->cfa.reg);
833854a0d95SVineet Gupta 				/*nobreak*/
834854a0d95SVineet Gupta 			case DW_CFA_def_cfa_offset:
835854a0d95SVineet Gupta 				state->cfa.offs = get_uleb128(&ptr.p8, end);
836854a0d95SVineet Gupta 				unw_debug("cfa_def_cfa_offset: 0x%lx ",
837854a0d95SVineet Gupta 					  state->cfa.offs);
838854a0d95SVineet Gupta 				break;
839854a0d95SVineet Gupta 			case DW_CFA_def_cfa_sf:
840854a0d95SVineet Gupta 				state->cfa.reg = get_uleb128(&ptr.p8, end);
841854a0d95SVineet Gupta 				/*nobreak */
842854a0d95SVineet Gupta 			case DW_CFA_def_cfa_offset_sf:
843854a0d95SVineet Gupta 				state->cfa.offs = get_sleb128(&ptr.p8, end)
844854a0d95SVineet Gupta 				    * state->dataAlign;
845854a0d95SVineet Gupta 				break;
846854a0d95SVineet Gupta 			case DW_CFA_def_cfa_register:
847ad61dd30SStephen Boyd 				unw_debug("cfa_def_cfa_register: ");
848854a0d95SVineet Gupta 				state->cfa.reg = get_uleb128(&ptr.p8, end);
849854a0d95SVineet Gupta 				break;
850854a0d95SVineet Gupta 				/*todo case DW_CFA_def_cfa_expression: */
851854a0d95SVineet Gupta 				/*todo case DW_CFA_expression: */
852854a0d95SVineet Gupta 				/*todo case DW_CFA_val_expression: */
853854a0d95SVineet Gupta 			case DW_CFA_GNU_args_size:
854854a0d95SVineet Gupta 				get_uleb128(&ptr.p8, end);
855854a0d95SVineet Gupta 				break;
856854a0d95SVineet Gupta 			case DW_CFA_GNU_negative_offset_extended:
857854a0d95SVineet Gupta 				value = get_uleb128(&ptr.p8, end);
858854a0d95SVineet Gupta 				set_rule(value,
859854a0d95SVineet Gupta 					 Memory,
860854a0d95SVineet Gupta 					 (uleb128_t) 0 - get_uleb128(&ptr.p8,
861854a0d95SVineet Gupta 								     end),
862854a0d95SVineet Gupta 					 state);
863854a0d95SVineet Gupta 				break;
864854a0d95SVineet Gupta 			case DW_CFA_GNU_window_save:
865854a0d95SVineet Gupta 			default:
866d939be3aSMasanari Iida 				unw_debug("UNKNOWN OPCODE 0x%x\n", opcode);
867854a0d95SVineet Gupta 				result = 0;
868854a0d95SVineet Gupta 				break;
869854a0d95SVineet Gupta 			}
870854a0d95SVineet Gupta 			break;
871854a0d95SVineet Gupta 		case 1:
872854a0d95SVineet Gupta 			unw_debug("\ncfa_adv_loc: ");
873854a0d95SVineet Gupta 			result = advance_loc(*ptr.p8++ & 0x3f, state);
874854a0d95SVineet Gupta 			break;
875854a0d95SVineet Gupta 		case 2:
876854a0d95SVineet Gupta 			unw_debug("cfa_offset: ");
877854a0d95SVineet Gupta 			value = *ptr.p8++ & 0x3f;
878854a0d95SVineet Gupta 			set_rule(value, Memory, get_uleb128(&ptr.p8, end),
879854a0d95SVineet Gupta 				 state);
880854a0d95SVineet Gupta 			break;
881854a0d95SVineet Gupta 		case 3:
882854a0d95SVineet Gupta 			unw_debug("cfa_restore: ");
883854a0d95SVineet Gupta 			set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state);
884854a0d95SVineet Gupta 			break;
885854a0d95SVineet Gupta 		}
886854a0d95SVineet Gupta 
887854a0d95SVineet Gupta 		if (ptr.p8 > end)
888854a0d95SVineet Gupta 			result = 0;
889854a0d95SVineet Gupta 		if (result && targetLoc != 0 && targetLoc < state->loc)
890854a0d95SVineet Gupta 			return 1;
891854a0d95SVineet Gupta 	}
892854a0d95SVineet Gupta 
893854a0d95SVineet Gupta 	return result && ptr.p8 == end && (targetLoc == 0 || (
894854a0d95SVineet Gupta 		/*todo While in theory this should apply, gcc in practice omits
895854a0d95SVineet Gupta 		  everything past the function prolog, and hence the location
896854a0d95SVineet Gupta 		  never reaches the end of the function.
897854a0d95SVineet Gupta 		targetLoc < state->loc && */  state->label == NULL));
898854a0d95SVineet Gupta }
899854a0d95SVineet Gupta 
900854a0d95SVineet Gupta /* Unwind to previous to frame.  Returns 0 if successful, negative
901854a0d95SVineet Gupta  * number in case of an error. */
902854a0d95SVineet Gupta int arc_unwind(struct unwind_frame_info *frame)
903854a0d95SVineet Gupta {
904854a0d95SVineet Gupta #define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
905854a0d95SVineet Gupta 	const u32 *fde = NULL, *cie = NULL;
906854a0d95SVineet Gupta 	const u8 *ptr = NULL, *end = NULL;
907854a0d95SVineet Gupta 	unsigned long pc = UNW_PC(frame) - frame->call_frame;
908854a0d95SVineet Gupta 	unsigned long startLoc = 0, endLoc = 0, cfa;
909854a0d95SVineet Gupta 	unsigned i;
910854a0d95SVineet Gupta 	signed ptrType = -1;
911854a0d95SVineet Gupta 	uleb128_t retAddrReg = 0;
912854a0d95SVineet Gupta 	const struct unwind_table *table;
913854a0d95SVineet Gupta 	struct unwind_state state;
914854a0d95SVineet Gupta 	unsigned long *fptr;
915854a0d95SVineet Gupta 	unsigned long addr;
916854a0d95SVineet Gupta 
917854a0d95SVineet Gupta 	unw_debug("\n\nUNWIND FRAME:\n");
918854a0d95SVineet Gupta 	unw_debug("PC: 0x%lx BLINK: 0x%lx, SP: 0x%lx, FP: 0x%x\n",
919854a0d95SVineet Gupta 		  UNW_PC(frame), UNW_BLINK(frame), UNW_SP(frame),
920854a0d95SVineet Gupta 		  UNW_FP(frame));
921854a0d95SVineet Gupta 
922854a0d95SVineet Gupta 	if (UNW_PC(frame) == 0)
923854a0d95SVineet Gupta 		return -EINVAL;
924854a0d95SVineet Gupta 
925854a0d95SVineet Gupta #ifdef UNWIND_DEBUG
926854a0d95SVineet Gupta 	{
927854a0d95SVineet Gupta 		unsigned long *sptr = (unsigned long *)UNW_SP(frame);
928854a0d95SVineet Gupta 		unw_debug("\nStack Dump:\n");
929854a0d95SVineet Gupta 		for (i = 0; i < 20; i++, sptr++)
930854a0d95SVineet Gupta 			unw_debug("0x%p:  0x%lx\n", sptr, *sptr);
931854a0d95SVineet Gupta 		unw_debug("\n");
932854a0d95SVineet Gupta 	}
933854a0d95SVineet Gupta #endif
934854a0d95SVineet Gupta 
935854a0d95SVineet Gupta 	table = find_table(pc);
936854a0d95SVineet Gupta 	if (table != NULL
937854a0d95SVineet Gupta 	    && !(table->size & (sizeof(*fde) - 1))) {
938854a0d95SVineet Gupta 		const u8 *hdr = table->header;
939854a0d95SVineet Gupta 		unsigned long tableSize;
940854a0d95SVineet Gupta 
941854a0d95SVineet Gupta 		smp_rmb();
942854a0d95SVineet Gupta 		if (hdr && hdr[0] == 1) {
943854a0d95SVineet Gupta 			switch (hdr[3] & DW_EH_PE_FORM) {
944854a0d95SVineet Gupta 			case DW_EH_PE_native:
945854a0d95SVineet Gupta 				tableSize = sizeof(unsigned long);
946854a0d95SVineet Gupta 				break;
947854a0d95SVineet Gupta 			case DW_EH_PE_data2:
948854a0d95SVineet Gupta 				tableSize = 2;
949854a0d95SVineet Gupta 				break;
950854a0d95SVineet Gupta 			case DW_EH_PE_data4:
951854a0d95SVineet Gupta 				tableSize = 4;
952854a0d95SVineet Gupta 				break;
953854a0d95SVineet Gupta 			case DW_EH_PE_data8:
954854a0d95SVineet Gupta 				tableSize = 8;
955854a0d95SVineet Gupta 				break;
956854a0d95SVineet Gupta 			default:
957854a0d95SVineet Gupta 				tableSize = 0;
958854a0d95SVineet Gupta 				break;
959854a0d95SVineet Gupta 			}
960854a0d95SVineet Gupta 			ptr = hdr + 4;
961854a0d95SVineet Gupta 			end = hdr + table->hdrsz;
962854a0d95SVineet Gupta 			if (tableSize && read_pointer(&ptr, end, hdr[1])
963854a0d95SVineet Gupta 			    == (unsigned long)table->address
964854a0d95SVineet Gupta 			    && (i = read_pointer(&ptr, end, hdr[2])) > 0
965854a0d95SVineet Gupta 			    && i == (end - ptr) / (2 * tableSize)
966854a0d95SVineet Gupta 			    && !((end - ptr) % (2 * tableSize))) {
967854a0d95SVineet Gupta 				do {
968854a0d95SVineet Gupta 					const u8 *cur =
969854a0d95SVineet Gupta 					    ptr + (i / 2) * (2 * tableSize);
970854a0d95SVineet Gupta 
971854a0d95SVineet Gupta 					startLoc = read_pointer(&cur,
972854a0d95SVineet Gupta 								cur + tableSize,
973854a0d95SVineet Gupta 								hdr[3]);
974854a0d95SVineet Gupta 					if (pc < startLoc)
975854a0d95SVineet Gupta 						i /= 2;
976854a0d95SVineet Gupta 					else {
977854a0d95SVineet Gupta 						ptr = cur - tableSize;
978854a0d95SVineet Gupta 						i = (i + 1) / 2;
979854a0d95SVineet Gupta 					}
980854a0d95SVineet Gupta 				} while (startLoc && i > 1);
981854a0d95SVineet Gupta 				if (i == 1
982854a0d95SVineet Gupta 				    && (startLoc = read_pointer(&ptr,
983854a0d95SVineet Gupta 								ptr + tableSize,
984854a0d95SVineet Gupta 								hdr[3])) != 0
985854a0d95SVineet Gupta 				    && pc >= startLoc)
986854a0d95SVineet Gupta 					fde = (void *)read_pointer(&ptr,
987854a0d95SVineet Gupta 								   ptr +
988854a0d95SVineet Gupta 								   tableSize,
989854a0d95SVineet Gupta 								   hdr[3]);
990854a0d95SVineet Gupta 			}
991854a0d95SVineet Gupta 		}
992854a0d95SVineet Gupta 
993854a0d95SVineet Gupta 		if (fde != NULL) {
994854a0d95SVineet Gupta 			cie = cie_for_fde(fde, table);
995854a0d95SVineet Gupta 			ptr = (const u8 *)(fde + 2);
996854a0d95SVineet Gupta 			if (cie != NULL
997854a0d95SVineet Gupta 			    && cie != &bad_cie
998854a0d95SVineet Gupta 			    && cie != &not_fde
999854a0d95SVineet Gupta 			    && (ptrType = fde_pointer_type(cie)) >= 0
1000854a0d95SVineet Gupta 			    && read_pointer(&ptr,
1001854a0d95SVineet Gupta 					    (const u8 *)(fde + 1) + *fde,
1002854a0d95SVineet Gupta 					    ptrType) == startLoc) {
1003854a0d95SVineet Gupta 				if (!(ptrType & DW_EH_PE_indirect))
1004854a0d95SVineet Gupta 					ptrType &=
1005854a0d95SVineet Gupta 					    DW_EH_PE_FORM | DW_EH_PE_signed;
1006854a0d95SVineet Gupta 				endLoc =
1007854a0d95SVineet Gupta 				    startLoc + read_pointer(&ptr,
1008854a0d95SVineet Gupta 							    (const u8 *)(fde +
1009854a0d95SVineet Gupta 									 1) +
1010854a0d95SVineet Gupta 							    *fde, ptrType);
10112e22502cSVineet Gupta 				if (pc >= endLoc) {
1012854a0d95SVineet Gupta 					fde = NULL;
1013854a0d95SVineet Gupta 					cie = NULL;
1014854a0d95SVineet Gupta 				}
10152e22502cSVineet Gupta 			} else {
10162e22502cSVineet Gupta 				fde = NULL;
10172e22502cSVineet Gupta 				cie = NULL;
1018854a0d95SVineet Gupta 			}
1019854a0d95SVineet Gupta 		}
1020854a0d95SVineet Gupta 	}
1021854a0d95SVineet Gupta 	if (cie != NULL) {
1022854a0d95SVineet Gupta 		memset(&state, 0, sizeof(state));
1023854a0d95SVineet Gupta 		state.cieEnd = ptr;	/* keep here temporarily */
1024854a0d95SVineet Gupta 		ptr = (const u8 *)(cie + 2);
1025854a0d95SVineet Gupta 		end = (const u8 *)(cie + 1) + *cie;
1026854a0d95SVineet Gupta 		frame->call_frame = 1;
10276d0d5060SVineet Gupta 		if (*++ptr) {
1028854a0d95SVineet Gupta 			/* check if augmentation size is first (thus present) */
1029854a0d95SVineet Gupta 			if (*ptr == 'z') {
1030854a0d95SVineet Gupta 				while (++ptr < end && *ptr) {
1031854a0d95SVineet Gupta 					switch (*ptr) {
1032854a0d95SVineet Gupta 					/* chk for ignorable or already handled
1033854a0d95SVineet Gupta 					 * nul-terminated augmentation string */
1034854a0d95SVineet Gupta 					case 'L':
1035854a0d95SVineet Gupta 					case 'P':
1036854a0d95SVineet Gupta 					case 'R':
1037854a0d95SVineet Gupta 						continue;
1038854a0d95SVineet Gupta 					case 'S':
1039854a0d95SVineet Gupta 						frame->call_frame = 0;
1040854a0d95SVineet Gupta 						continue;
1041854a0d95SVineet Gupta 					default:
1042854a0d95SVineet Gupta 						break;
1043854a0d95SVineet Gupta 					}
1044854a0d95SVineet Gupta 					break;
1045854a0d95SVineet Gupta 				}
1046854a0d95SVineet Gupta 			}
1047854a0d95SVineet Gupta 			if (ptr >= end || *ptr)
1048854a0d95SVineet Gupta 				cie = NULL;
1049854a0d95SVineet Gupta 		}
1050854a0d95SVineet Gupta 		++ptr;
1051854a0d95SVineet Gupta 	}
1052854a0d95SVineet Gupta 	if (cie != NULL) {
1053550116d2SMasahiro Yamada 		/* get code alignment factor */
1054854a0d95SVineet Gupta 		state.codeAlign = get_uleb128(&ptr, end);
1055550116d2SMasahiro Yamada 		/* get data alignment factor */
1056854a0d95SVineet Gupta 		state.dataAlign = get_sleb128(&ptr, end);
1057854a0d95SVineet Gupta 		if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end)
1058854a0d95SVineet Gupta 			cie = NULL;
1059854a0d95SVineet Gupta 		else {
1060854a0d95SVineet Gupta 			retAddrReg =
1061854a0d95SVineet Gupta 			    state.version <= 1 ? *ptr++ : get_uleb128(&ptr,
1062854a0d95SVineet Gupta 								      end);
1063854a0d95SVineet Gupta 			unw_debug("CIE Frame Info:\n");
1064854a0d95SVineet Gupta 			unw_debug("return Address register 0x%lx\n",
1065854a0d95SVineet Gupta 				  retAddrReg);
1066854a0d95SVineet Gupta 			unw_debug("data Align: %ld\n", state.dataAlign);
1067854a0d95SVineet Gupta 			unw_debug("code Align: %lu\n", state.codeAlign);
1068854a0d95SVineet Gupta 			/* skip augmentation */
1069854a0d95SVineet Gupta 			if (((const char *)(cie + 2))[1] == 'z') {
1070854a0d95SVineet Gupta 				uleb128_t augSize = get_uleb128(&ptr, end);
1071854a0d95SVineet Gupta 
1072854a0d95SVineet Gupta 				ptr += augSize;
1073854a0d95SVineet Gupta 			}
1074854a0d95SVineet Gupta 			if (ptr > end || retAddrReg >= ARRAY_SIZE(reg_info)
1075854a0d95SVineet Gupta 			    || REG_INVALID(retAddrReg)
1076854a0d95SVineet Gupta 			    || reg_info[retAddrReg].width !=
1077854a0d95SVineet Gupta 			    sizeof(unsigned long))
1078854a0d95SVineet Gupta 				cie = NULL;
1079854a0d95SVineet Gupta 		}
1080854a0d95SVineet Gupta 	}
1081854a0d95SVineet Gupta 	if (cie != NULL) {
1082854a0d95SVineet Gupta 		state.cieStart = ptr;
1083854a0d95SVineet Gupta 		ptr = state.cieEnd;
1084854a0d95SVineet Gupta 		state.cieEnd = end;
1085854a0d95SVineet Gupta 		end = (const u8 *)(fde + 1) + *fde;
1086854a0d95SVineet Gupta 		/* skip augmentation */
1087854a0d95SVineet Gupta 		if (((const char *)(cie + 2))[1] == 'z') {
1088854a0d95SVineet Gupta 			uleb128_t augSize = get_uleb128(&ptr, end);
1089854a0d95SVineet Gupta 
1090854a0d95SVineet Gupta 			if ((ptr += augSize) > end)
1091854a0d95SVineet Gupta 				fde = NULL;
1092854a0d95SVineet Gupta 		}
1093854a0d95SVineet Gupta 	}
1094854a0d95SVineet Gupta 	if (cie == NULL || fde == NULL) {
1095854a0d95SVineet Gupta #ifdef CONFIG_FRAME_POINTER
1096854a0d95SVineet Gupta 		unsigned long top, bottom;
1097854a0d95SVineet Gupta 
1098854a0d95SVineet Gupta 		top = STACK_TOP_UNW(frame->task);
1099854a0d95SVineet Gupta 		bottom = STACK_BOTTOM_UNW(frame->task);
1100854a0d95SVineet Gupta #if FRAME_RETADDR_OFFSET < 0
1101854a0d95SVineet Gupta 		if (UNW_SP(frame) < top && UNW_FP(frame) <= UNW_SP(frame)
1102854a0d95SVineet Gupta 		    && bottom < UNW_FP(frame)
1103854a0d95SVineet Gupta #else
1104854a0d95SVineet Gupta 		if (UNW_SP(frame) > top && UNW_FP(frame) >= UNW_SP(frame)
1105854a0d95SVineet Gupta 		    && bottom > UNW_FP(frame)
1106854a0d95SVineet Gupta #endif
1107854a0d95SVineet Gupta 		    && !((UNW_SP(frame) | UNW_FP(frame))
1108854a0d95SVineet Gupta 			 & (sizeof(unsigned long) - 1))) {
1109854a0d95SVineet Gupta 			unsigned long link;
1110854a0d95SVineet Gupta 
1111854a0d95SVineet Gupta 			if (!__get_user(link, (unsigned long *)
1112854a0d95SVineet Gupta 					(UNW_FP(frame) + FRAME_LINK_OFFSET))
1113854a0d95SVineet Gupta #if FRAME_RETADDR_OFFSET < 0
1114854a0d95SVineet Gupta 			    && link > bottom && link < UNW_FP(frame)
1115854a0d95SVineet Gupta #else
1116854a0d95SVineet Gupta 			    && link > UNW_FP(frame) && link < bottom
1117854a0d95SVineet Gupta #endif
1118854a0d95SVineet Gupta 			    && !(link & (sizeof(link) - 1))
1119854a0d95SVineet Gupta 			    && !__get_user(UNW_PC(frame),
1120854a0d95SVineet Gupta 					   (unsigned long *)(UNW_FP(frame)
1121854a0d95SVineet Gupta 						+ FRAME_RETADDR_OFFSET)))
1122854a0d95SVineet Gupta 			{
1123854a0d95SVineet Gupta 				UNW_SP(frame) =
1124854a0d95SVineet Gupta 				    UNW_FP(frame) + FRAME_RETADDR_OFFSET
1125854a0d95SVineet Gupta #if FRAME_RETADDR_OFFSET < 0
1126854a0d95SVineet Gupta 				    -
1127854a0d95SVineet Gupta #else
1128854a0d95SVineet Gupta 				    +
1129854a0d95SVineet Gupta #endif
1130854a0d95SVineet Gupta 				    sizeof(UNW_PC(frame));
1131854a0d95SVineet Gupta 				UNW_FP(frame) = link;
1132854a0d95SVineet Gupta 				return 0;
1133854a0d95SVineet Gupta 			}
1134854a0d95SVineet Gupta 		}
1135854a0d95SVineet Gupta #endif
1136854a0d95SVineet Gupta 		return -ENXIO;
1137854a0d95SVineet Gupta 	}
1138854a0d95SVineet Gupta 	state.org = startLoc;
1139854a0d95SVineet Gupta 	memcpy(&state.cfa, &badCFA, sizeof(state.cfa));
1140854a0d95SVineet Gupta 
1141854a0d95SVineet Gupta 	unw_debug("\nProcess instructions\n");
1142854a0d95SVineet Gupta 
1143854a0d95SVineet Gupta 	/* process instructions
1144854a0d95SVineet Gupta 	 * For ARC, we optimize by having blink(retAddrReg) with
1145854a0d95SVineet Gupta 	 * the sameValue in the leaf function, so we should not check
1146854a0d95SVineet Gupta 	 * state.regs[retAddrReg].where == Nowhere
1147854a0d95SVineet Gupta 	 */
1148854a0d95SVineet Gupta 	if (!processCFI(ptr, end, pc, ptrType, &state)
1149854a0d95SVineet Gupta 	    || state.loc > endLoc
1150854a0d95SVineet Gupta /*	   || state.regs[retAddrReg].where == Nowhere */
1151854a0d95SVineet Gupta 	    || state.cfa.reg >= ARRAY_SIZE(reg_info)
1152854a0d95SVineet Gupta 	    || reg_info[state.cfa.reg].width != sizeof(unsigned long)
1153854a0d95SVineet Gupta 	    || state.cfa.offs % sizeof(unsigned long))
1154854a0d95SVineet Gupta 		return -EIO;
1155854a0d95SVineet Gupta 
1156854a0d95SVineet Gupta #ifdef UNWIND_DEBUG
1157854a0d95SVineet Gupta 	unw_debug("\n");
1158854a0d95SVineet Gupta 
1159854a0d95SVineet Gupta 	unw_debug("\nRegister State Based on the rules parsed from FDE:\n");
1160854a0d95SVineet Gupta 	for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
1161854a0d95SVineet Gupta 
1162854a0d95SVineet Gupta 		if (REG_INVALID(i))
1163854a0d95SVineet Gupta 			continue;
1164854a0d95SVineet Gupta 
1165854a0d95SVineet Gupta 		switch (state.regs[i].where) {
1166854a0d95SVineet Gupta 		case Nowhere:
1167854a0d95SVineet Gupta 			break;
1168854a0d95SVineet Gupta 		case Memory:
1169854a0d95SVineet Gupta 			unw_debug(" r%d: c(%lu),", i, state.regs[i].value);
1170854a0d95SVineet Gupta 			break;
1171854a0d95SVineet Gupta 		case Register:
1172854a0d95SVineet Gupta 			unw_debug(" r%d: r(%lu),", i, state.regs[i].value);
1173854a0d95SVineet Gupta 			break;
1174854a0d95SVineet Gupta 		case Value:
1175854a0d95SVineet Gupta 			unw_debug(" r%d: v(%lu),", i, state.regs[i].value);
1176854a0d95SVineet Gupta 			break;
1177854a0d95SVineet Gupta 		}
1178854a0d95SVineet Gupta 	}
1179854a0d95SVineet Gupta 
1180854a0d95SVineet Gupta 	unw_debug("\n");
1181854a0d95SVineet Gupta #endif
1182854a0d95SVineet Gupta 
1183854a0d95SVineet Gupta 	/* update frame */
1184854a0d95SVineet Gupta #ifndef CONFIG_AS_CFI_SIGNAL_FRAME
1185854a0d95SVineet Gupta 	if (frame->call_frame
1186854a0d95SVineet Gupta 	    && !UNW_DEFAULT_RA(state.regs[retAddrReg], state.dataAlign))
1187854a0d95SVineet Gupta 		frame->call_frame = 0;
1188854a0d95SVineet Gupta #endif
1189854a0d95SVineet Gupta 	cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs;
1190854a0d95SVineet Gupta 	startLoc = min_t(unsigned long, UNW_SP(frame), cfa);
1191854a0d95SVineet Gupta 	endLoc = max_t(unsigned long, UNW_SP(frame), cfa);
1192854a0d95SVineet Gupta 	if (STACK_LIMIT(startLoc) != STACK_LIMIT(endLoc)) {
1193854a0d95SVineet Gupta 		startLoc = min(STACK_LIMIT(cfa), cfa);
1194854a0d95SVineet Gupta 		endLoc = max(STACK_LIMIT(cfa), cfa);
1195854a0d95SVineet Gupta 	}
1196854a0d95SVineet Gupta 
1197854a0d95SVineet Gupta 	unw_debug("\nCFA reg: 0x%lx, offset: 0x%lx =>  0x%lx\n",
1198854a0d95SVineet Gupta 		  state.cfa.reg, state.cfa.offs, cfa);
1199854a0d95SVineet Gupta 
1200854a0d95SVineet Gupta 	for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
1201854a0d95SVineet Gupta 		if (REG_INVALID(i)) {
1202854a0d95SVineet Gupta 			if (state.regs[i].where == Nowhere)
1203854a0d95SVineet Gupta 				continue;
1204854a0d95SVineet Gupta 			return -EIO;
1205854a0d95SVineet Gupta 		}
1206854a0d95SVineet Gupta 		switch (state.regs[i].where) {
1207854a0d95SVineet Gupta 		default:
1208854a0d95SVineet Gupta 			break;
1209854a0d95SVineet Gupta 		case Register:
1210854a0d95SVineet Gupta 			if (state.regs[i].value >= ARRAY_SIZE(reg_info)
1211854a0d95SVineet Gupta 			    || REG_INVALID(state.regs[i].value)
1212854a0d95SVineet Gupta 			    || reg_info[i].width >
1213854a0d95SVineet Gupta 			    reg_info[state.regs[i].value].width)
1214854a0d95SVineet Gupta 				return -EIO;
1215854a0d95SVineet Gupta 			switch (reg_info[state.regs[i].value].width) {
1216854a0d95SVineet Gupta 			case sizeof(u8):
1217854a0d95SVineet Gupta 				state.regs[i].value =
1218854a0d95SVineet Gupta 				FRAME_REG(state.regs[i].value, const u8);
1219854a0d95SVineet Gupta 				break;
1220854a0d95SVineet Gupta 			case sizeof(u16):
1221854a0d95SVineet Gupta 				state.regs[i].value =
1222854a0d95SVineet Gupta 				FRAME_REG(state.regs[i].value, const u16);
1223854a0d95SVineet Gupta 				break;
1224854a0d95SVineet Gupta 			case sizeof(u32):
1225854a0d95SVineet Gupta 				state.regs[i].value =
1226854a0d95SVineet Gupta 				FRAME_REG(state.regs[i].value, const u32);
1227854a0d95SVineet Gupta 				break;
1228854a0d95SVineet Gupta #ifdef CONFIG_64BIT
1229854a0d95SVineet Gupta 			case sizeof(u64):
1230854a0d95SVineet Gupta 				state.regs[i].value =
1231854a0d95SVineet Gupta 				FRAME_REG(state.regs[i].value, const u64);
1232854a0d95SVineet Gupta 				break;
1233854a0d95SVineet Gupta #endif
1234854a0d95SVineet Gupta 			default:
1235854a0d95SVineet Gupta 				return -EIO;
1236854a0d95SVineet Gupta 			}
1237854a0d95SVineet Gupta 			break;
1238854a0d95SVineet Gupta 		}
1239854a0d95SVineet Gupta 	}
1240854a0d95SVineet Gupta 
1241854a0d95SVineet Gupta 	unw_debug("\nRegister state after evaluation with realtime Stack:\n");
1242854a0d95SVineet Gupta 	fptr = (unsigned long *)(&frame->regs);
1243854a0d95SVineet Gupta 	for (i = 0; i < ARRAY_SIZE(state.regs); ++i, fptr++) {
1244854a0d95SVineet Gupta 
1245854a0d95SVineet Gupta 		if (REG_INVALID(i))
1246854a0d95SVineet Gupta 			continue;
1247854a0d95SVineet Gupta 		switch (state.regs[i].where) {
1248854a0d95SVineet Gupta 		case Nowhere:
1249854a0d95SVineet Gupta 			if (reg_info[i].width != sizeof(UNW_SP(frame))
1250854a0d95SVineet Gupta 			    || &FRAME_REG(i, __typeof__(UNW_SP(frame)))
1251854a0d95SVineet Gupta 			    != &UNW_SP(frame))
1252854a0d95SVineet Gupta 				continue;
1253854a0d95SVineet Gupta 			UNW_SP(frame) = cfa;
1254854a0d95SVineet Gupta 			break;
1255854a0d95SVineet Gupta 		case Register:
1256854a0d95SVineet Gupta 			switch (reg_info[i].width) {
1257854a0d95SVineet Gupta 			case sizeof(u8):
1258854a0d95SVineet Gupta 				FRAME_REG(i, u8) = state.regs[i].value;
1259854a0d95SVineet Gupta 				break;
1260854a0d95SVineet Gupta 			case sizeof(u16):
1261854a0d95SVineet Gupta 				FRAME_REG(i, u16) = state.regs[i].value;
1262854a0d95SVineet Gupta 				break;
1263854a0d95SVineet Gupta 			case sizeof(u32):
1264854a0d95SVineet Gupta 				FRAME_REG(i, u32) = state.regs[i].value;
1265854a0d95SVineet Gupta 				break;
1266854a0d95SVineet Gupta #ifdef CONFIG_64BIT
1267854a0d95SVineet Gupta 			case sizeof(u64):
1268854a0d95SVineet Gupta 				FRAME_REG(i, u64) = state.regs[i].value;
1269854a0d95SVineet Gupta 				break;
1270854a0d95SVineet Gupta #endif
1271854a0d95SVineet Gupta 			default:
1272854a0d95SVineet Gupta 				return -EIO;
1273854a0d95SVineet Gupta 			}
1274854a0d95SVineet Gupta 			break;
1275854a0d95SVineet Gupta 		case Value:
1276854a0d95SVineet Gupta 			if (reg_info[i].width != sizeof(unsigned long))
1277854a0d95SVineet Gupta 				return -EIO;
1278854a0d95SVineet Gupta 			FRAME_REG(i, unsigned long) = cfa + state.regs[i].value
1279854a0d95SVineet Gupta 			    * state.dataAlign;
1280854a0d95SVineet Gupta 			break;
1281854a0d95SVineet Gupta 		case Memory:
1282854a0d95SVineet Gupta 			addr = cfa + state.regs[i].value * state.dataAlign;
1283854a0d95SVineet Gupta 
1284854a0d95SVineet Gupta 			if ((state.regs[i].value * state.dataAlign)
1285854a0d95SVineet Gupta 			    % sizeof(unsigned long)
1286854a0d95SVineet Gupta 			    || addr < startLoc
1287854a0d95SVineet Gupta 			    || addr + sizeof(unsigned long) < addr
1288854a0d95SVineet Gupta 			    || addr + sizeof(unsigned long) > endLoc)
1289854a0d95SVineet Gupta 					return -EIO;
1290854a0d95SVineet Gupta 
1291854a0d95SVineet Gupta 			switch (reg_info[i].width) {
1292854a0d95SVineet Gupta 			case sizeof(u8):
1293854a0d95SVineet Gupta 				__get_user(FRAME_REG(i, u8),
1294854a0d95SVineet Gupta 					   (u8 __user *)addr);
1295854a0d95SVineet Gupta 				break;
1296854a0d95SVineet Gupta 			case sizeof(u16):
1297854a0d95SVineet Gupta 				__get_user(FRAME_REG(i, u16),
1298854a0d95SVineet Gupta 					   (u16 __user *)addr);
1299854a0d95SVineet Gupta 				break;
1300854a0d95SVineet Gupta 			case sizeof(u32):
1301854a0d95SVineet Gupta 				__get_user(FRAME_REG(i, u32),
1302854a0d95SVineet Gupta 					   (u32 __user *)addr);
1303854a0d95SVineet Gupta 				break;
1304854a0d95SVineet Gupta #ifdef CONFIG_64BIT
1305854a0d95SVineet Gupta 			case sizeof(u64):
1306854a0d95SVineet Gupta 				__get_user(FRAME_REG(i, u64),
1307854a0d95SVineet Gupta 					   (u64 __user *)addr);
1308854a0d95SVineet Gupta 				break;
1309854a0d95SVineet Gupta #endif
1310854a0d95SVineet Gupta 			default:
1311854a0d95SVineet Gupta 				return -EIO;
1312854a0d95SVineet Gupta 			}
1313854a0d95SVineet Gupta 
1314854a0d95SVineet Gupta 			break;
1315854a0d95SVineet Gupta 		}
1316854a0d95SVineet Gupta 		unw_debug("r%d: 0x%lx ", i, *fptr);
1317854a0d95SVineet Gupta 	}
1318854a0d95SVineet Gupta 
1319854a0d95SVineet Gupta 	return 0;
1320854a0d95SVineet Gupta #undef FRAME_REG
1321854a0d95SVineet Gupta }
1322854a0d95SVineet Gupta EXPORT_SYMBOL(arc_unwind);
1323