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