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