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);