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