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