root/arch/arc/kernel/unwind.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. find_table
  2. unw_hdr_alloc_early
  3. init_unwind_table
  4. arc_unwind_init
  5. cmp_eh_frame_hdr_table_entries
  6. swap_eh_frame_hdr_table_entries
  7. init_unwind_hdr
  8. unw_hdr_alloc
  9. unwind_add_table
  10. unlink_table
  11. unwind_remove_table
  12. get_uleb128
  13. get_sleb128
  14. __cie_for_fde
  15. cie_for_fde
  16. read_pointer
  17. fde_pointer_type
  18. advance_loc
  19. set_rule
  20. processCFI
  21. arc_unwind

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
   4  * Copyright (C) 2002-2006 Novell, Inc.
   5  *      Jan Beulich <jbeulich@novell.com>
   6  *
   7  * A simple API for unwinding kernel stacks.  This is used for
   8  * debugging and error reporting purposes.  The kernel doesn't need
   9  * full-blown stack unwinding with all the bells and whistles, so there
  10  * is not much point in implementing the full Dwarf2 unwind API.
  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 /* extern const u8 __start_unwind_hdr[], __end_unwind_hdr[];*/
  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(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  * wrappers for header alloc (vs. calling one vs. other at call site)
 177  * to elide section mismatches warnings
 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         /* See if the linker provided table looks valid. */
 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           /*__start_unwind_hdr, __end_unwind_hdr - __start_unwind_hdr);*/
 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 == &not_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                         /* FIXME_Rajesh We have 4 instances of null addresses
 302                          * instead of the initial loc addr
 303                          * return;
 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;       /* this is a CIE */
 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 /* Must be called with module_mutex held. */
 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 /* Must be called with module_mutex held. */
 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); /* XXX: SMP */
 454         kfree(table->header);
 455         kfree(table);
 456 }
 457 
 458 #endif /* CONFIG_MODULES */
 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 &not_fde;        /* this is a CIE */
 522 
 523         if ((fde[1] & (sizeof(*fde) - 1)))
 524 /* || fde[1] > (unsigned long)(fde + 1) - (unsigned long)table->address) */
 525                 return NULL;    /* this is not a valid FDE */
 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;    /* this is not a (valid) CIE */
 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                 /* Fall through */
 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                 /* check if augmentation size is first (and thus present) */
 619                 if (*ptr != 'z')
 620                         return -1;
 621 
 622                 /* check if augmentation string is nul-terminated */
 623                 aug = (const void *)ptr;
 624                 ptr = memchr(aug, 0, end - ptr);
 625                 if (ptr == NULL)
 626                         return -1;
 627 
 628                 ++ptr;          /* skip terminator */
 629                 get_uleb128(&ptr, end); /* skip code alignment */
 630                 get_sleb128(&ptr, end); /* skip data alignment */
 631                 /* skip return address column */
 632                 version <= 1 ? (void) ++ptr : (void)get_uleb128(&ptr, end);
 633                 len = get_uleb128(&ptr, end);   /* augmentation length */
 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         /* FIXME_Rajesh: Probably we are defining for the initial range as well;
 669            return delta > 0;
 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                                     /* && advance_loc(*ptr.p16++, state); */
 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                                 /* fall through */
 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                                 /* fall through */
 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                                 /*todo case DW_CFA_def_cfa_expression: */
 848                                 /*todo case DW_CFA_expression: */
 849                                 /*todo case DW_CFA_val_expression: */
 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                 /*todo While in theory this should apply, gcc in practice omits
 892                   everything past the function prolog, and hence the location
 893                   never reaches the end of the function.
 894                 targetLoc < state->loc && */  state->label == NULL));
 895 }
 896 
 897 /* Unwind to previous to frame.  Returns 0 if successful, negative
 898  * number in case of an error. */
 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 != &not_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;     /* keep here temporarily */
1021                 ptr = (const u8 *)(cie + 2);
1022                 end = (const u8 *)(cie + 1) + *cie;
1023                 frame->call_frame = 1;
1024                 if (*++ptr) {
1025                         /* check if augmentation size is first (thus present) */
1026                         if (*ptr == 'z') {
1027                                 while (++ptr < end && *ptr) {
1028                                         switch (*ptr) {
1029                                         /* chk for ignorable or already handled
1030                                          * nul-terminated augmentation string */
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                 /* get code alignment factor */
1051                 state.codeAlign = get_uleb128(&ptr, end);
1052                 /* get data alignment factor */
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                         /* skip augmentation */
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                 /* skip augmentation */
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         /* process instructions
1141          * For ARC, we optimize by having blink(retAddrReg) with
1142          * the sameValue in the leaf function, so we should not check
1143          * state.regs[retAddrReg].where == Nowhere
1144          */
1145         if (!processCFI(ptr, end, pc, ptrType, &state)
1146             || state.loc > endLoc
1147 /*         || state.regs[retAddrReg].where == Nowhere */
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         /* update frame */
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);

/* [<][>][^][v][top][bottom][index][help] */