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