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