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