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