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