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