1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
4 * Copyright (C) 2002-2006 Novell, Inc.
5 * Jan Beulich <jbeulich@novell.com>
6 *
7 * A simple API for unwinding kernel stacks. This is used for
8 * debugging and error reporting purposes. The kernel doesn't need
9 * full-blown stack unwinding with all the bells and whistles, so there
10 * is not much point in implementing the full Dwarf2 unwind API.
11 */
12
13 #include <linux/sched.h>
14 #include <linux/module.h>
15 #include <linux/memblock.h>
16 #include <linux/sort.h>
17 #include <linux/slab.h>
18 #include <linux/stop_machine.h>
19 #include <linux/uaccess.h>
20 #include <linux/ptrace.h>
21 #include <asm/sections.h>
22 #include <linux/unaligned.h>
23 #include <asm/unwind.h>
24
25 extern char __start_unwind[], __end_unwind[];
26 /* extern const u8 __start_unwind_hdr[], __end_unwind_hdr[];*/
27
28 /* #define UNWIND_DEBUG */
29
30 #ifdef UNWIND_DEBUG
31 int dbg_unw;
32 #define unw_debug(fmt, ...) \
33 do { \
34 if (dbg_unw) \
35 pr_info(fmt, ##__VA_ARGS__); \
36 } while (0);
37 #else
38 #define unw_debug(fmt, ...)
39 #endif
40
41 #define MAX_STACK_DEPTH 8
42
43 #define EXTRA_INFO(f) { \
44 BUILD_BUG_ON_ZERO(offsetof(struct unwind_frame_info, f) \
45 % sizeof_field(struct unwind_frame_info, f)) \
46 + offsetof(struct unwind_frame_info, f) \
47 / sizeof_field(struct unwind_frame_info, f), \
48 sizeof_field(struct unwind_frame_info, f) \
49 }
50 #define PTREGS_INFO(f) EXTRA_INFO(regs.f)
51
52 static const struct {
53 unsigned offs:BITS_PER_LONG / 2;
54 unsigned width:BITS_PER_LONG / 2;
55 } reg_info[] = {
56 UNW_REGISTER_INFO};
57
58 #undef PTREGS_INFO
59 #undef EXTRA_INFO
60
61 #ifndef REG_INVALID
62 #define REG_INVALID(r) (reg_info[r].width == 0)
63 #endif
64
65 #define DW_CFA_nop 0x00
66 #define DW_CFA_set_loc 0x01
67 #define DW_CFA_advance_loc1 0x02
68 #define DW_CFA_advance_loc2 0x03
69 #define DW_CFA_advance_loc4 0x04
70 #define DW_CFA_offset_extended 0x05
71 #define DW_CFA_restore_extended 0x06
72 #define DW_CFA_undefined 0x07
73 #define DW_CFA_same_value 0x08
74 #define DW_CFA_register 0x09
75 #define DW_CFA_remember_state 0x0a
76 #define DW_CFA_restore_state 0x0b
77 #define DW_CFA_def_cfa 0x0c
78 #define DW_CFA_def_cfa_register 0x0d
79 #define DW_CFA_def_cfa_offset 0x0e
80 #define DW_CFA_def_cfa_expression 0x0f
81 #define DW_CFA_expression 0x10
82 #define DW_CFA_offset_extended_sf 0x11
83 #define DW_CFA_def_cfa_sf 0x12
84 #define DW_CFA_def_cfa_offset_sf 0x13
85 #define DW_CFA_val_offset 0x14
86 #define DW_CFA_val_offset_sf 0x15
87 #define DW_CFA_val_expression 0x16
88 #define DW_CFA_lo_user 0x1c
89 #define DW_CFA_GNU_window_save 0x2d
90 #define DW_CFA_GNU_args_size 0x2e
91 #define DW_CFA_GNU_negative_offset_extended 0x2f
92 #define DW_CFA_hi_user 0x3f
93
94 #define DW_EH_PE_FORM 0x07
95 #define DW_EH_PE_native 0x00
96 #define DW_EH_PE_leb128 0x01
97 #define DW_EH_PE_data2 0x02
98 #define DW_EH_PE_data4 0x03
99 #define DW_EH_PE_data8 0x04
100 #define DW_EH_PE_signed 0x08
101 #define DW_EH_PE_ADJUST 0x70
102 #define DW_EH_PE_abs 0x00
103 #define DW_EH_PE_pcrel 0x10
104 #define DW_EH_PE_textrel 0x20
105 #define DW_EH_PE_datarel 0x30
106 #define DW_EH_PE_funcrel 0x40
107 #define DW_EH_PE_aligned 0x50
108 #define DW_EH_PE_indirect 0x80
109 #define DW_EH_PE_omit 0xff
110
111 #define CIE_ID 0
112
113 typedef unsigned long uleb128_t;
114 typedef signed long sleb128_t;
115
116 static struct unwind_table {
117 struct {
118 unsigned long pc;
119 unsigned long range;
120 } core, init;
121 const void *address;
122 unsigned long size;
123 const unsigned char *header;
124 unsigned long hdrsz;
125 struct unwind_table *link;
126 const char *name;
127 } root_table;
128
129 struct unwind_item {
130 enum item_location {
131 Nowhere,
132 Memory,
133 Register,
134 Value
135 } where;
136 uleb128_t value;
137 };
138
139 struct unwind_state {
140 uleb128_t loc, org;
141 const u8 *cieStart, *cieEnd;
142 uleb128_t codeAlign;
143 sleb128_t dataAlign;
144 struct cfa {
145 uleb128_t reg, offs;
146 } cfa;
147 struct unwind_item regs[ARRAY_SIZE(reg_info)];
148 unsigned stackDepth:8;
149 unsigned version:8;
150 const u8 *label;
151 const u8 *stack[MAX_STACK_DEPTH];
152 };
153
154 static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 };
155
find_table(unsigned long pc)156 static struct unwind_table *find_table(unsigned long pc)
157 {
158 struct unwind_table *table;
159
160 for (table = &root_table; table; table = table->link)
161 if ((pc >= table->core.pc
162 && pc < table->core.pc + table->core.range)
163 || (pc >= table->init.pc
164 && pc < table->init.pc + table->init.range))
165 break;
166
167 return table;
168 }
169
170 static unsigned long read_pointer(const u8 **pLoc,
171 const void *end, signed ptrType);
172 static void init_unwind_hdr(struct unwind_table *table,
173 void *(*alloc) (unsigned long));
174
175 /*
176 * wrappers for header alloc (vs. calling one vs. other at call site)
177 * to elide section mismatches warnings
178 */
unw_hdr_alloc_early(unsigned long sz)179 static void *__init unw_hdr_alloc_early(unsigned long sz)
180 {
181 return memblock_alloc_from(sz, sizeof(unsigned int), MAX_DMA_ADDRESS);
182 }
183
init_unwind_table(struct unwind_table * table,const char * name,const void * core_start,unsigned long core_size,const void * init_start,unsigned long init_size,const void * table_start,unsigned long table_size,const u8 * header_start,unsigned long header_size)184 static void init_unwind_table(struct unwind_table *table, const char *name,
185 const void *core_start, unsigned long core_size,
186 const void *init_start, unsigned long init_size,
187 const void *table_start, unsigned long table_size,
188 const u8 *header_start, unsigned long header_size)
189 {
190 table->core.pc = (unsigned long)core_start;
191 table->core.range = core_size;
192 table->init.pc = (unsigned long)init_start;
193 table->init.range = init_size;
194 table->address = table_start;
195 table->size = table_size;
196 /* To avoid the pointer addition with NULL pointer.*/
197 if (header_start != NULL) {
198 const u8 *ptr = header_start + 4;
199 const u8 *end = header_start + header_size;
200 /* See if the linker provided table looks valid. */
201 if (header_size <= 4
202 || header_start[0] != 1
203 || (void *)read_pointer(&ptr, end, header_start[1])
204 != table_start
205 || header_start[2] == DW_EH_PE_omit
206 || read_pointer(&ptr, end, header_start[2]) <= 0
207 || header_start[3] == DW_EH_PE_omit)
208 header_start = NULL;
209 }
210 table->hdrsz = header_size;
211 smp_wmb();
212 table->header = header_start;
213 table->link = NULL;
214 table->name = name;
215 }
216
arc_unwind_init(void)217 void __init arc_unwind_init(void)
218 {
219 init_unwind_table(&root_table, "kernel", _text, _end - _text, NULL, 0,
220 __start_unwind, __end_unwind - __start_unwind,
221 NULL, 0);
222 /*__start_unwind_hdr, __end_unwind_hdr - __start_unwind_hdr);*/
223
224 init_unwind_hdr(&root_table, unw_hdr_alloc_early);
225 }
226
227 static const u32 bad_cie, not_fde;
228 static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *);
229 static const u32 *__cie_for_fde(const u32 *fde);
230 static signed fde_pointer_type(const u32 *cie);
231
232 struct eh_frame_hdr_table_entry {
233 unsigned long start, fde;
234 };
235
cmp_eh_frame_hdr_table_entries(const void * p1,const void * p2)236 static int cmp_eh_frame_hdr_table_entries(const void *p1, const void *p2)
237 {
238 const struct eh_frame_hdr_table_entry *e1 = p1;
239 const struct eh_frame_hdr_table_entry *e2 = p2;
240
241 return (e1->start > e2->start) - (e1->start < e2->start);
242 }
243
init_unwind_hdr(struct unwind_table * table,void * (* alloc)(unsigned long))244 static void init_unwind_hdr(struct unwind_table *table,
245 void *(*alloc) (unsigned long))
246 {
247 const u8 *ptr;
248 unsigned long tableSize = table->size, hdrSize;
249 unsigned int n;
250 const u32 *fde;
251 struct {
252 u8 version;
253 u8 eh_frame_ptr_enc;
254 u8 fde_count_enc;
255 u8 table_enc;
256 unsigned long eh_frame_ptr;
257 unsigned int fde_count;
258 struct eh_frame_hdr_table_entry table[];
259 } __attribute__ ((__packed__)) *header;
260
261 if (table->header)
262 return;
263
264 if (table->hdrsz)
265 pr_warn(".eh_frame_hdr for '%s' present but unusable\n",
266 table->name);
267
268 if (tableSize & (sizeof(*fde) - 1))
269 return;
270
271 for (fde = table->address, n = 0;
272 tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde;
273 tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
274 const u32 *cie = cie_for_fde(fde, table);
275 signed ptrType;
276
277 if (cie == ¬_fde)
278 continue;
279 if (cie == NULL || cie == &bad_cie)
280 goto ret_err;
281 ptrType = fde_pointer_type(cie);
282 if (ptrType < 0)
283 goto ret_err;
284
285 ptr = (const u8 *)(fde + 2);
286 if (!read_pointer(&ptr, (const u8 *)(fde + 1) + *fde,
287 ptrType)) {
288 /* FIXME_Rajesh We have 4 instances of null addresses
289 * instead of the initial loc addr
290 * return;
291 */
292 WARN(1, "unwinder: FDE->initial_location NULL %p\n",
293 (const u8 *)(fde + 1) + *fde);
294 }
295 ++n;
296 }
297
298 if (tableSize || !n)
299 goto ret_err;
300
301 hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int)
302 + 2 * n * sizeof(unsigned long);
303
304 header = alloc(hdrSize);
305 if (!header)
306 goto ret_err;
307
308 header->version = 1;
309 header->eh_frame_ptr_enc = DW_EH_PE_abs | DW_EH_PE_native;
310 header->fde_count_enc = DW_EH_PE_abs | DW_EH_PE_data4;
311 header->table_enc = DW_EH_PE_abs | DW_EH_PE_native;
312 put_unaligned((unsigned long)table->address, &header->eh_frame_ptr);
313 BUILD_BUG_ON(offsetof(typeof(*header), fde_count)
314 % __alignof(typeof(header->fde_count)));
315 header->fde_count = n;
316
317 BUILD_BUG_ON(offsetof(typeof(*header), table)
318 % __alignof(typeof(*header->table)));
319 for (fde = table->address, tableSize = table->size, n = 0;
320 tableSize;
321 tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
322 const u32 *cie = __cie_for_fde(fde);
323
324 if (fde[1] == CIE_ID)
325 continue; /* this is a CIE */
326 ptr = (const u8 *)(fde + 2);
327 header->table[n].start = read_pointer(&ptr,
328 (const u8 *)(fde + 1) +
329 *fde,
330 fde_pointer_type(cie));
331 header->table[n].fde = (unsigned long)fde;
332 ++n;
333 }
334 WARN_ON(n != header->fde_count);
335
336 sort(header->table,
337 n,
338 sizeof(*header->table),
339 cmp_eh_frame_hdr_table_entries, NULL);
340
341 table->hdrsz = hdrSize;
342 smp_wmb();
343 table->header = (const void *)header;
344 return;
345
346 ret_err:
347 panic("Attention !!! Dwarf FDE parsing errors\n");
348 }
349
350 #ifdef CONFIG_MODULES
unw_hdr_alloc(unsigned long sz)351 static void *unw_hdr_alloc(unsigned long sz)
352 {
353 return kmalloc(sz, GFP_KERNEL);
354 }
355
356 static struct unwind_table *last_table;
357
358 /* Must be called with module_mutex held. */
unwind_add_table(struct module * module,const void * table_start,unsigned long table_size)359 void *unwind_add_table(struct module *module, const void *table_start,
360 unsigned long table_size)
361 {
362 struct unwind_table *table;
363 struct module_memory *core_text;
364 struct module_memory *init_text;
365
366 if (table_size <= 0)
367 return NULL;
368
369 table = kmalloc(sizeof(*table), GFP_KERNEL);
370 if (!table)
371 return NULL;
372
373 core_text = &module->mem[MOD_TEXT];
374 init_text = &module->mem[MOD_INIT_TEXT];
375
376 init_unwind_table(table, module->name, core_text->base, core_text->size,
377 init_text->base, init_text->size, table_start, table_size, NULL, 0);
378
379 init_unwind_hdr(table, unw_hdr_alloc);
380
381 #ifdef UNWIND_DEBUG
382 unw_debug("Table added for [%s] %lx %lx\n",
383 module->name, table->core.pc, table->core.range);
384 #endif
385 if (last_table)
386 last_table->link = table;
387 else
388 root_table.link = table;
389 last_table = table;
390
391 return table;
392 }
393
394 struct unlink_table_info {
395 struct unwind_table *table;
396 int init_only;
397 };
398
unlink_table(void * arg)399 static int unlink_table(void *arg)
400 {
401 struct unlink_table_info *info = arg;
402 struct unwind_table *table = info->table, *prev;
403
404 for (prev = &root_table; prev->link && prev->link != table;
405 prev = prev->link)
406 ;
407
408 if (prev->link) {
409 if (info->init_only) {
410 table->init.pc = 0;
411 table->init.range = 0;
412 info->table = NULL;
413 } else {
414 prev->link = table->link;
415 if (!prev->link)
416 last_table = prev;
417 }
418 } else
419 info->table = NULL;
420
421 return 0;
422 }
423
424 /* Must be called with module_mutex held. */
unwind_remove_table(void * handle,int init_only)425 void unwind_remove_table(void *handle, int init_only)
426 {
427 struct unwind_table *table = handle;
428 struct unlink_table_info info;
429
430 if (!table || table == &root_table)
431 return;
432
433 if (init_only && table == last_table) {
434 table->init.pc = 0;
435 table->init.range = 0;
436 return;
437 }
438
439 info.table = table;
440 info.init_only = init_only;
441
442 unlink_table(&info); /* XXX: SMP */
443 kfree(table->header);
444 kfree(table);
445 }
446
447 #endif /* CONFIG_MODULES */
448
get_uleb128(const u8 ** pcur,const u8 * end)449 static uleb128_t get_uleb128(const u8 **pcur, const u8 *end)
450 {
451 const u8 *cur = *pcur;
452 uleb128_t value;
453 unsigned int shift;
454
455 for (shift = 0, value = 0; cur < end; shift += 7) {
456 if (shift + 7 > 8 * sizeof(value)
457 && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
458 cur = end + 1;
459 break;
460 }
461 value |= (uleb128_t) (*cur & 0x7f) << shift;
462 if (!(*cur++ & 0x80))
463 break;
464 }
465 *pcur = cur;
466
467 return value;
468 }
469
get_sleb128(const u8 ** pcur,const u8 * end)470 static sleb128_t get_sleb128(const u8 **pcur, const u8 *end)
471 {
472 const u8 *cur = *pcur;
473 sleb128_t value;
474 unsigned int shift;
475
476 for (shift = 0, value = 0; cur < end; shift += 7) {
477 if (shift + 7 > 8 * sizeof(value)
478 && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
479 cur = end + 1;
480 break;
481 }
482 value |= (sleb128_t) (*cur & 0x7f) << shift;
483 if (!(*cur & 0x80)) {
484 value |= -(*cur++ & 0x40) << shift;
485 break;
486 }
487 }
488 *pcur = cur;
489
490 return value;
491 }
492
__cie_for_fde(const u32 * fde)493 static const u32 *__cie_for_fde(const u32 *fde)
494 {
495 const u32 *cie;
496
497 cie = fde + 1 - fde[1] / sizeof(*fde);
498
499 return cie;
500 }
501
cie_for_fde(const u32 * fde,const struct unwind_table * table)502 static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *table)
503 {
504 const u32 *cie;
505
506 if (!*fde || (*fde & (sizeof(*fde) - 1)))
507 return &bad_cie;
508
509 if (fde[1] == CIE_ID)
510 return ¬_fde; /* this is a CIE */
511
512 if ((fde[1] & (sizeof(*fde) - 1)))
513 /* || fde[1] > (unsigned long)(fde + 1) - (unsigned long)table->address) */
514 return NULL; /* this is not a valid FDE */
515
516 cie = __cie_for_fde(fde);
517
518 if (*cie <= sizeof(*cie) + 4 || *cie >= fde[1] - sizeof(*fde)
519 || (*cie & (sizeof(*cie) - 1))
520 || (cie[1] != CIE_ID))
521 return NULL; /* this is not a (valid) CIE */
522 return cie;
523 }
524
read_pointer(const u8 ** pLoc,const void * end,signed ptrType)525 static unsigned long read_pointer(const u8 **pLoc, const void *end,
526 signed ptrType)
527 {
528 unsigned long value = 0;
529 union {
530 const u8 *p8;
531 const u16 *p16u;
532 const s16 *p16s;
533 const u32 *p32u;
534 const s32 *p32s;
535 const unsigned long *pul;
536 } ptr;
537
538 if (ptrType < 0 || ptrType == DW_EH_PE_omit)
539 return 0;
540 ptr.p8 = *pLoc;
541 switch (ptrType & DW_EH_PE_FORM) {
542 case DW_EH_PE_data2:
543 if (end < (const void *)(ptr.p16u + 1))
544 return 0;
545 if (ptrType & DW_EH_PE_signed)
546 value = get_unaligned((u16 *) ptr.p16s++);
547 else
548 value = get_unaligned((u16 *) ptr.p16u++);
549 break;
550 case DW_EH_PE_data4:
551 #ifdef CONFIG_64BIT
552 if (end < (const void *)(ptr.p32u + 1))
553 return 0;
554 if (ptrType & DW_EH_PE_signed)
555 value = get_unaligned(ptr.p32s++);
556 else
557 value = get_unaligned(ptr.p32u++);
558 break;
559 case DW_EH_PE_data8:
560 BUILD_BUG_ON(sizeof(u64) != sizeof(value));
561 #else
562 BUILD_BUG_ON(sizeof(u32) != sizeof(value));
563 #endif
564 fallthrough;
565 case DW_EH_PE_native:
566 if (end < (const void *)(ptr.pul + 1))
567 return 0;
568 value = get_unaligned((unsigned long *)ptr.pul++);
569 break;
570 case DW_EH_PE_leb128:
571 BUILD_BUG_ON(sizeof(uleb128_t) > sizeof(value));
572 value = ptrType & DW_EH_PE_signed ? get_sleb128(&ptr.p8, end)
573 : get_uleb128(&ptr.p8, end);
574 if ((const void *)ptr.p8 > end)
575 return 0;
576 break;
577 default:
578 return 0;
579 }
580 switch (ptrType & DW_EH_PE_ADJUST) {
581 case DW_EH_PE_abs:
582 break;
583 case DW_EH_PE_pcrel:
584 value += (unsigned long)*pLoc;
585 break;
586 default:
587 return 0;
588 }
589 if ((ptrType & DW_EH_PE_indirect)
590 && __get_user(value, (unsigned long __user *)value))
591 return 0;
592 *pLoc = ptr.p8;
593
594 return value;
595 }
596
fde_pointer_type(const u32 * cie)597 static signed fde_pointer_type(const u32 *cie)
598 {
599 const u8 *ptr = (const u8 *)(cie + 2);
600 unsigned int version = *ptr;
601
602 if (*++ptr) {
603 const char *aug;
604 const u8 *end = (const u8 *)(cie + 1) + *cie;
605 uleb128_t len;
606
607 /* check if augmentation size is first (and thus present) */
608 if (*ptr != 'z')
609 return -1;
610
611 /* check if augmentation string is nul-terminated */
612 aug = (const void *)ptr;
613 ptr = memchr(aug, 0, end - ptr);
614 if (ptr == NULL)
615 return -1;
616
617 ++ptr; /* skip terminator */
618 get_uleb128(&ptr, end); /* skip code alignment */
619 get_sleb128(&ptr, end); /* skip data alignment */
620 /* skip return address column */
621 version <= 1 ? (void) ++ptr : (void)get_uleb128(&ptr, end);
622 len = get_uleb128(&ptr, end); /* augmentation length */
623
624 if (ptr + len < ptr || ptr + len > end)
625 return -1;
626
627 end = ptr + len;
628 while (*++aug) {
629 if (ptr >= end)
630 return -1;
631 switch (*aug) {
632 case 'L':
633 ++ptr;
634 break;
635 case 'P':{
636 signed ptrType = *ptr++;
637
638 if (!read_pointer(&ptr, end, ptrType)
639 || ptr > end)
640 return -1;
641 }
642 break;
643 case 'R':
644 return *ptr;
645 default:
646 return -1;
647 }
648 }
649 }
650 return DW_EH_PE_native | DW_EH_PE_abs;
651 }
652
advance_loc(unsigned long delta,struct unwind_state * state)653 static int advance_loc(unsigned long delta, struct unwind_state *state)
654 {
655 state->loc += delta * state->codeAlign;
656
657 /* FIXME_Rajesh: Probably we are defining for the initial range as well;
658 return delta > 0;
659 */
660 unw_debug("delta %3lu => loc 0x%lx: ", delta, state->loc);
661 return 1;
662 }
663
set_rule(uleb128_t reg,enum item_location where,uleb128_t value,struct unwind_state * state)664 static void set_rule(uleb128_t reg, enum item_location where, uleb128_t value,
665 struct unwind_state *state)
666 {
667 if (reg < ARRAY_SIZE(state->regs)) {
668 state->regs[reg].where = where;
669 state->regs[reg].value = value;
670
671 #ifdef UNWIND_DEBUG
672 unw_debug("r%lu: ", reg);
673 switch (where) {
674 case Nowhere:
675 unw_debug("s ");
676 break;
677 case Memory:
678 unw_debug("c(%lu) ", value);
679 break;
680 case Register:
681 unw_debug("r(%lu) ", value);
682 break;
683 case Value:
684 unw_debug("v(%lu) ", value);
685 break;
686 default:
687 break;
688 }
689 #endif
690 }
691 }
692
processCFI(const u8 * start,const u8 * end,unsigned long targetLoc,signed ptrType,struct unwind_state * state)693 static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
694 signed ptrType, struct unwind_state *state)
695 {
696 union {
697 const u8 *p8;
698 const u16 *p16;
699 const u32 *p32;
700 } ptr;
701 int result = 1;
702 u8 opcode;
703
704 if (start != state->cieStart) {
705 state->loc = state->org;
706 result =
707 processCFI(state->cieStart, state->cieEnd, 0, ptrType,
708 state);
709 if (targetLoc == 0 && state->label == NULL)
710 return result;
711 }
712 for (ptr.p8 = start; result && ptr.p8 < end;) {
713 switch (*ptr.p8 >> 6) {
714 uleb128_t value;
715
716 case 0:
717 opcode = *ptr.p8++;
718
719 switch (opcode) {
720 case DW_CFA_nop:
721 unw_debug("cfa nop ");
722 break;
723 case DW_CFA_set_loc:
724 state->loc = read_pointer(&ptr.p8, end,
725 ptrType);
726 if (state->loc == 0)
727 result = 0;
728 unw_debug("cfa_set_loc: 0x%lx ", state->loc);
729 break;
730 case DW_CFA_advance_loc1:
731 unw_debug("\ncfa advance loc1:");
732 result = ptr.p8 < end
733 && advance_loc(*ptr.p8++, state);
734 break;
735 case DW_CFA_advance_loc2:
736 value = *ptr.p8++;
737 value += *ptr.p8++ << 8;
738 unw_debug("\ncfa advance loc2:");
739 result = ptr.p8 <= end + 2
740 /* && advance_loc(*ptr.p16++, state); */
741 && advance_loc(value, state);
742 break;
743 case DW_CFA_advance_loc4:
744 unw_debug("\ncfa advance loc4:");
745 result = ptr.p8 <= end + 4
746 && advance_loc(*ptr.p32++, state);
747 break;
748 case DW_CFA_offset_extended:
749 value = get_uleb128(&ptr.p8, end);
750 unw_debug("cfa_offset_extended: ");
751 set_rule(value, Memory,
752 get_uleb128(&ptr.p8, end), state);
753 break;
754 case DW_CFA_val_offset:
755 value = get_uleb128(&ptr.p8, end);
756 set_rule(value, Value,
757 get_uleb128(&ptr.p8, end), state);
758 break;
759 case DW_CFA_offset_extended_sf:
760 value = get_uleb128(&ptr.p8, end);
761 set_rule(value, Memory,
762 get_sleb128(&ptr.p8, end), state);
763 break;
764 case DW_CFA_val_offset_sf:
765 value = get_uleb128(&ptr.p8, end);
766 set_rule(value, Value,
767 get_sleb128(&ptr.p8, end), state);
768 break;
769 case DW_CFA_restore_extended:
770 unw_debug("cfa_restore_extended: ");
771 case DW_CFA_undefined:
772 unw_debug("cfa_undefined: ");
773 case DW_CFA_same_value:
774 unw_debug("cfa_same_value: ");
775 set_rule(get_uleb128(&ptr.p8, end), Nowhere, 0,
776 state);
777 break;
778 case DW_CFA_register:
779 unw_debug("cfa_register: ");
780 value = get_uleb128(&ptr.p8, end);
781 set_rule(value,
782 Register,
783 get_uleb128(&ptr.p8, end), state);
784 break;
785 case DW_CFA_remember_state:
786 unw_debug("cfa_remember_state: ");
787 if (ptr.p8 == state->label) {
788 state->label = NULL;
789 return 1;
790 }
791 if (state->stackDepth >= MAX_STACK_DEPTH)
792 return 0;
793 state->stack[state->stackDepth++] = ptr.p8;
794 break;
795 case DW_CFA_restore_state:
796 unw_debug("cfa_restore_state: ");
797 if (state->stackDepth) {
798 const uleb128_t loc = state->loc;
799 const u8 *label = state->label;
800
801 state->label =
802 state->stack[state->stackDepth - 1];
803 memcpy(&state->cfa, &badCFA,
804 sizeof(state->cfa));
805 memset(state->regs, 0,
806 sizeof(state->regs));
807 state->stackDepth = 0;
808 result =
809 processCFI(start, end, 0, ptrType,
810 state);
811 state->loc = loc;
812 state->label = label;
813 } else
814 return 0;
815 break;
816 case DW_CFA_def_cfa:
817 state->cfa.reg = get_uleb128(&ptr.p8, end);
818 unw_debug("cfa_def_cfa: r%lu ", state->cfa.reg);
819 fallthrough;
820 case DW_CFA_def_cfa_offset:
821 state->cfa.offs = get_uleb128(&ptr.p8, end);
822 unw_debug("cfa_def_cfa_offset: 0x%lx ",
823 state->cfa.offs);
824 break;
825 case DW_CFA_def_cfa_sf:
826 state->cfa.reg = get_uleb128(&ptr.p8, end);
827 fallthrough;
828 case DW_CFA_def_cfa_offset_sf:
829 state->cfa.offs = get_sleb128(&ptr.p8, end)
830 * state->dataAlign;
831 break;
832 case DW_CFA_def_cfa_register:
833 unw_debug("cfa_def_cfa_register: ");
834 state->cfa.reg = get_uleb128(&ptr.p8, end);
835 break;
836 /*todo case DW_CFA_def_cfa_expression: */
837 /*todo case DW_CFA_expression: */
838 /*todo case DW_CFA_val_expression: */
839 case DW_CFA_GNU_args_size:
840 get_uleb128(&ptr.p8, end);
841 break;
842 case DW_CFA_GNU_negative_offset_extended:
843 value = get_uleb128(&ptr.p8, end);
844 set_rule(value,
845 Memory,
846 (uleb128_t) 0 - get_uleb128(&ptr.p8,
847 end),
848 state);
849 break;
850 case DW_CFA_GNU_window_save:
851 default:
852 unw_debug("UNKNOWN OPCODE 0x%x\n", opcode);
853 result = 0;
854 break;
855 }
856 break;
857 case 1:
858 unw_debug("\ncfa_adv_loc: ");
859 result = advance_loc(*ptr.p8++ & 0x3f, state);
860 break;
861 case 2:
862 unw_debug("cfa_offset: ");
863 value = *ptr.p8++ & 0x3f;
864 set_rule(value, Memory, get_uleb128(&ptr.p8, end),
865 state);
866 break;
867 case 3:
868 unw_debug("cfa_restore: ");
869 set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state);
870 break;
871 }
872
873 if (ptr.p8 > end)
874 result = 0;
875 if (result && targetLoc != 0 && targetLoc < state->loc)
876 return 1;
877 }
878
879 return result && ptr.p8 == end && (targetLoc == 0 || (
880 /*todo While in theory this should apply, gcc in practice omits
881 everything past the function prolog, and hence the location
882 never reaches the end of the function.
883 targetLoc < state->loc && */ state->label == NULL));
884 }
885
886 /* Unwind to previous to frame. Returns 0 if successful, negative
887 * number in case of an error. */
arc_unwind(struct unwind_frame_info * frame)888 int arc_unwind(struct unwind_frame_info *frame)
889 {
890 #define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
891 const u32 *fde = NULL, *cie = NULL;
892 const u8 *ptr = NULL, *end = NULL;
893 unsigned long pc = UNW_PC(frame) - frame->call_frame;
894 unsigned long startLoc = 0, endLoc = 0, cfa;
895 unsigned int i;
896 signed ptrType = -1;
897 uleb128_t retAddrReg = 0;
898 const struct unwind_table *table;
899 struct unwind_state state;
900 unsigned long *fptr;
901 unsigned long addr;
902
903 unw_debug("\n\nUNWIND FRAME:\n");
904 unw_debug("PC: 0x%lx BLINK: 0x%lx, SP: 0x%lx, FP: 0x%x\n",
905 UNW_PC(frame), UNW_BLINK(frame), UNW_SP(frame),
906 UNW_FP(frame));
907
908 if (UNW_PC(frame) == 0)
909 return -EINVAL;
910
911 #ifdef UNWIND_DEBUG
912 {
913 unsigned long *sptr = (unsigned long *)UNW_SP(frame);
914 unw_debug("\nStack Dump:\n");
915 for (i = 0; i < 20; i++, sptr++)
916 unw_debug("0x%p: 0x%lx\n", sptr, *sptr);
917 unw_debug("\n");
918 }
919 #endif
920
921 table = find_table(pc);
922 if (table != NULL
923 && !(table->size & (sizeof(*fde) - 1))) {
924 const u8 *hdr = table->header;
925 unsigned long tableSize;
926
927 smp_rmb();
928 if (hdr && hdr[0] == 1) {
929 switch (hdr[3] & DW_EH_PE_FORM) {
930 case DW_EH_PE_native:
931 tableSize = sizeof(unsigned long);
932 break;
933 case DW_EH_PE_data2:
934 tableSize = 2;
935 break;
936 case DW_EH_PE_data4:
937 tableSize = 4;
938 break;
939 case DW_EH_PE_data8:
940 tableSize = 8;
941 break;
942 default:
943 tableSize = 0;
944 break;
945 }
946 ptr = hdr + 4;
947 end = hdr + table->hdrsz;
948 if (tableSize && read_pointer(&ptr, end, hdr[1])
949 == (unsigned long)table->address
950 && (i = read_pointer(&ptr, end, hdr[2])) > 0
951 && i == (end - ptr) / (2 * tableSize)
952 && !((end - ptr) % (2 * tableSize))) {
953 do {
954 const u8 *cur =
955 ptr + (i / 2) * (2 * tableSize);
956
957 startLoc = read_pointer(&cur,
958 cur + tableSize,
959 hdr[3]);
960 if (pc < startLoc)
961 i /= 2;
962 else {
963 ptr = cur - tableSize;
964 i = (i + 1) / 2;
965 }
966 } while (startLoc && i > 1);
967 if (i == 1
968 && (startLoc = read_pointer(&ptr,
969 ptr + tableSize,
970 hdr[3])) != 0
971 && pc >= startLoc)
972 fde = (void *)read_pointer(&ptr,
973 ptr +
974 tableSize,
975 hdr[3]);
976 }
977 }
978
979 if (fde != NULL) {
980 cie = cie_for_fde(fde, table);
981 ptr = (const u8 *)(fde + 2);
982 if (cie != NULL
983 && cie != &bad_cie
984 && cie != ¬_fde
985 && (ptrType = fde_pointer_type(cie)) >= 0
986 && read_pointer(&ptr,
987 (const u8 *)(fde + 1) + *fde,
988 ptrType) == startLoc) {
989 if (!(ptrType & DW_EH_PE_indirect))
990 ptrType &=
991 DW_EH_PE_FORM | DW_EH_PE_signed;
992 endLoc =
993 startLoc + read_pointer(&ptr,
994 (const u8 *)(fde +
995 1) +
996 *fde, ptrType);
997 if (pc >= endLoc) {
998 fde = NULL;
999 cie = NULL;
1000 }
1001 } else {
1002 fde = NULL;
1003 cie = NULL;
1004 }
1005 }
1006 }
1007 if (cie != NULL) {
1008 memset(&state, 0, sizeof(state));
1009 state.cieEnd = ptr; /* keep here temporarily */
1010 ptr = (const u8 *)(cie + 2);
1011 end = (const u8 *)(cie + 1) + *cie;
1012 frame->call_frame = 1;
1013 if (*++ptr) {
1014 /* check if augmentation size is first (thus present) */
1015 if (*ptr == 'z') {
1016 while (++ptr < end && *ptr) {
1017 switch (*ptr) {
1018 /* chk for ignorable or already handled
1019 * nul-terminated augmentation string */
1020 case 'L':
1021 case 'P':
1022 case 'R':
1023 continue;
1024 case 'S':
1025 frame->call_frame = 0;
1026 continue;
1027 default:
1028 break;
1029 }
1030 break;
1031 }
1032 }
1033 if (ptr >= end || *ptr)
1034 cie = NULL;
1035 }
1036 ++ptr;
1037 }
1038 if (cie != NULL) {
1039 /* get code alignment factor */
1040 state.codeAlign = get_uleb128(&ptr, end);
1041 /* get data alignment factor */
1042 state.dataAlign = get_sleb128(&ptr, end);
1043 if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end)
1044 cie = NULL;
1045 else {
1046 retAddrReg =
1047 state.version <= 1 ? *ptr++ : get_uleb128(&ptr,
1048 end);
1049 unw_debug("CIE Frame Info:\n");
1050 unw_debug("return Address register 0x%lx\n",
1051 retAddrReg);
1052 unw_debug("data Align: %ld\n", state.dataAlign);
1053 unw_debug("code Align: %lu\n", state.codeAlign);
1054 /* skip augmentation */
1055 if (((const char *)(cie + 2))[1] == 'z') {
1056 uleb128_t augSize = get_uleb128(&ptr, end);
1057
1058 ptr += augSize;
1059 }
1060 if (ptr > end || retAddrReg >= ARRAY_SIZE(reg_info)
1061 || REG_INVALID(retAddrReg)
1062 || reg_info[retAddrReg].width !=
1063 sizeof(unsigned long))
1064 cie = NULL;
1065 }
1066 }
1067 if (cie != NULL) {
1068 state.cieStart = ptr;
1069 ptr = state.cieEnd;
1070 state.cieEnd = end;
1071 end = (const u8 *)(fde + 1) + *fde;
1072 /* skip augmentation */
1073 if (((const char *)(cie + 2))[1] == 'z') {
1074 uleb128_t augSize = get_uleb128(&ptr, end);
1075
1076 if ((ptr += augSize) > end)
1077 fde = NULL;
1078 }
1079 }
1080 if (cie == NULL || fde == NULL) {
1081 #ifdef CONFIG_FRAME_POINTER
1082 unsigned long top, bottom;
1083
1084 top = STACK_TOP_UNW(frame->task);
1085 bottom = STACK_BOTTOM_UNW(frame->task);
1086 #if FRAME_RETADDR_OFFSET < 0
1087 if (UNW_SP(frame) < top && UNW_FP(frame) <= UNW_SP(frame)
1088 && bottom < UNW_FP(frame)
1089 #else
1090 if (UNW_SP(frame) > top && UNW_FP(frame) >= UNW_SP(frame)
1091 && bottom > UNW_FP(frame)
1092 #endif
1093 && !((UNW_SP(frame) | UNW_FP(frame))
1094 & (sizeof(unsigned long) - 1))) {
1095 unsigned long link;
1096
1097 if (!__get_user(link, (unsigned long *)
1098 (UNW_FP(frame) + FRAME_LINK_OFFSET))
1099 #if FRAME_RETADDR_OFFSET < 0
1100 && link > bottom && link < UNW_FP(frame)
1101 #else
1102 && link > UNW_FP(frame) && link < bottom
1103 #endif
1104 && !(link & (sizeof(link) - 1))
1105 && !__get_user(UNW_PC(frame),
1106 (unsigned long *)(UNW_FP(frame)
1107 + FRAME_RETADDR_OFFSET)))
1108 {
1109 UNW_SP(frame) =
1110 UNW_FP(frame) + FRAME_RETADDR_OFFSET
1111 #if FRAME_RETADDR_OFFSET < 0
1112 -
1113 #else
1114 +
1115 #endif
1116 sizeof(UNW_PC(frame));
1117 UNW_FP(frame) = link;
1118 return 0;
1119 }
1120 }
1121 #endif
1122 return -ENXIO;
1123 }
1124 state.org = startLoc;
1125 memcpy(&state.cfa, &badCFA, sizeof(state.cfa));
1126
1127 unw_debug("\nProcess instructions\n");
1128
1129 /* process instructions
1130 * For ARC, we optimize by having blink(retAddrReg) with
1131 * the sameValue in the leaf function, so we should not check
1132 * state.regs[retAddrReg].where == Nowhere
1133 */
1134 if (!processCFI(ptr, end, pc, ptrType, &state)
1135 || state.loc > endLoc
1136 /* || state.regs[retAddrReg].where == Nowhere */
1137 || state.cfa.reg >= ARRAY_SIZE(reg_info)
1138 || reg_info[state.cfa.reg].width != sizeof(unsigned long)
1139 || state.cfa.offs % sizeof(unsigned long))
1140 return -EIO;
1141
1142 #ifdef UNWIND_DEBUG
1143 unw_debug("\n");
1144
1145 unw_debug("\nRegister State Based on the rules parsed from FDE:\n");
1146 for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
1147
1148 if (REG_INVALID(i))
1149 continue;
1150
1151 switch (state.regs[i].where) {
1152 case Nowhere:
1153 break;
1154 case Memory:
1155 unw_debug(" r%d: c(%lu),", i, state.regs[i].value);
1156 break;
1157 case Register:
1158 unw_debug(" r%d: r(%lu),", i, state.regs[i].value);
1159 break;
1160 case Value:
1161 unw_debug(" r%d: v(%lu),", i, state.regs[i].value);
1162 break;
1163 }
1164 }
1165
1166 unw_debug("\n");
1167 #endif
1168
1169 /* update frame */
1170 if (frame->call_frame
1171 && !UNW_DEFAULT_RA(state.regs[retAddrReg], state.dataAlign))
1172 frame->call_frame = 0;
1173 cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs;
1174 startLoc = min_t(unsigned long, UNW_SP(frame), cfa);
1175 endLoc = max_t(unsigned long, UNW_SP(frame), cfa);
1176 if (STACK_LIMIT(startLoc) != STACK_LIMIT(endLoc)) {
1177 startLoc = min(STACK_LIMIT(cfa), cfa);
1178 endLoc = max(STACK_LIMIT(cfa), cfa);
1179 }
1180
1181 unw_debug("\nCFA reg: 0x%lx, offset: 0x%lx => 0x%lx\n",
1182 state.cfa.reg, state.cfa.offs, cfa);
1183
1184 for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
1185 if (REG_INVALID(i)) {
1186 if (state.regs[i].where == Nowhere)
1187 continue;
1188 return -EIO;
1189 }
1190 switch (state.regs[i].where) {
1191 default:
1192 break;
1193 case Register:
1194 if (state.regs[i].value >= ARRAY_SIZE(reg_info)
1195 || REG_INVALID(state.regs[i].value)
1196 || reg_info[i].width >
1197 reg_info[state.regs[i].value].width)
1198 return -EIO;
1199 switch (reg_info[state.regs[i].value].width) {
1200 case sizeof(u8):
1201 state.regs[i].value =
1202 FRAME_REG(state.regs[i].value, const u8);
1203 break;
1204 case sizeof(u16):
1205 state.regs[i].value =
1206 FRAME_REG(state.regs[i].value, const u16);
1207 break;
1208 case sizeof(u32):
1209 state.regs[i].value =
1210 FRAME_REG(state.regs[i].value, const u32);
1211 break;
1212 #ifdef CONFIG_64BIT
1213 case sizeof(u64):
1214 state.regs[i].value =
1215 FRAME_REG(state.regs[i].value, const u64);
1216 break;
1217 #endif
1218 default:
1219 return -EIO;
1220 }
1221 break;
1222 }
1223 }
1224
1225 unw_debug("\nRegister state after evaluation with realtime Stack:\n");
1226 fptr = (unsigned long *)(&frame->regs);
1227 for (i = 0; i < ARRAY_SIZE(state.regs); ++i, fptr++) {
1228
1229 if (REG_INVALID(i))
1230 continue;
1231 switch (state.regs[i].where) {
1232 case Nowhere:
1233 if (reg_info[i].width != sizeof(UNW_SP(frame))
1234 || &FRAME_REG(i, __typeof__(UNW_SP(frame)))
1235 != &UNW_SP(frame))
1236 continue;
1237 UNW_SP(frame) = cfa;
1238 break;
1239 case Register:
1240 switch (reg_info[i].width) {
1241 case sizeof(u8):
1242 FRAME_REG(i, u8) = state.regs[i].value;
1243 break;
1244 case sizeof(u16):
1245 FRAME_REG(i, u16) = state.regs[i].value;
1246 break;
1247 case sizeof(u32):
1248 FRAME_REG(i, u32) = state.regs[i].value;
1249 break;
1250 #ifdef CONFIG_64BIT
1251 case sizeof(u64):
1252 FRAME_REG(i, u64) = state.regs[i].value;
1253 break;
1254 #endif
1255 default:
1256 return -EIO;
1257 }
1258 break;
1259 case Value:
1260 if (reg_info[i].width != sizeof(unsigned long))
1261 return -EIO;
1262 FRAME_REG(i, unsigned long) = cfa + state.regs[i].value
1263 * state.dataAlign;
1264 break;
1265 case Memory:
1266 addr = cfa + state.regs[i].value * state.dataAlign;
1267
1268 if ((state.regs[i].value * state.dataAlign)
1269 % sizeof(unsigned long)
1270 || addr < startLoc
1271 || addr + sizeof(unsigned long) < addr
1272 || addr + sizeof(unsigned long) > endLoc)
1273 return -EIO;
1274
1275 switch (reg_info[i].width) {
1276 case sizeof(u8):
1277 __get_user(FRAME_REG(i, u8),
1278 (u8 __user *)addr);
1279 break;
1280 case sizeof(u16):
1281 __get_user(FRAME_REG(i, u16),
1282 (u16 __user *)addr);
1283 break;
1284 case sizeof(u32):
1285 __get_user(FRAME_REG(i, u32),
1286 (u32 __user *)addr);
1287 break;
1288 #ifdef CONFIG_64BIT
1289 case sizeof(u64):
1290 __get_user(FRAME_REG(i, u64),
1291 (u64 __user *)addr);
1292 break;
1293 #endif
1294 default:
1295 return -EIO;
1296 }
1297
1298 break;
1299 }
1300 unw_debug("r%d: 0x%lx ", i, *fptr);
1301 }
1302
1303 return 0;
1304 #undef FRAME_REG
1305 }
1306 EXPORT_SYMBOL(arc_unwind);
1307