Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
0004  * Copyright (C) 2002-2006 Novell, Inc.
0005  *  Jan Beulich <jbeulich@novell.com>
0006  *
0007  * A simple API for unwinding kernel stacks.  This is used for
0008  * debugging and error reporting purposes.  The kernel doesn't need
0009  * full-blown stack unwinding with all the bells and whistles, so there
0010  * is not much point in implementing the full Dwarf2 unwind API.
0011  */
0012 
0013 #include <linux/sched.h>
0014 #include <linux/module.h>
0015 #include <linux/memblock.h>
0016 #include <linux/sort.h>
0017 #include <linux/slab.h>
0018 #include <linux/stop_machine.h>
0019 #include <linux/uaccess.h>
0020 #include <linux/ptrace.h>
0021 #include <asm/sections.h>
0022 #include <asm/unaligned.h>
0023 #include <asm/unwind.h>
0024 
0025 extern char __start_unwind[], __end_unwind[];
0026 /* extern const u8 __start_unwind_hdr[], __end_unwind_hdr[];*/
0027 
0028 /* #define UNWIND_DEBUG */
0029 
0030 #ifdef UNWIND_DEBUG
0031 int dbg_unw;
0032 #define unw_debug(fmt, ...)         \
0033 do {                        \
0034     if (dbg_unw)                \
0035         pr_info(fmt, ##__VA_ARGS__);    \
0036 } while (0);
0037 #else
0038 #define unw_debug(fmt, ...)
0039 #endif
0040 
0041 #define MAX_STACK_DEPTH 8
0042 
0043 #define EXTRA_INFO(f) { \
0044         BUILD_BUG_ON_ZERO(offsetof(struct unwind_frame_info, f) \
0045                 % sizeof_field(struct unwind_frame_info, f)) \
0046                 + offsetof(struct unwind_frame_info, f) \
0047                 / sizeof_field(struct unwind_frame_info, f), \
0048                 sizeof_field(struct unwind_frame_info, f) \
0049     }
0050 #define PTREGS_INFO(f) EXTRA_INFO(regs.f)
0051 
0052 static const struct {
0053     unsigned offs:BITS_PER_LONG / 2;
0054     unsigned width:BITS_PER_LONG / 2;
0055 } reg_info[] = {
0056 UNW_REGISTER_INFO};
0057 
0058 #undef PTREGS_INFO
0059 #undef EXTRA_INFO
0060 
0061 #ifndef REG_INVALID
0062 #define REG_INVALID(r) (reg_info[r].width == 0)
0063 #endif
0064 
0065 #define DW_CFA_nop                          0x00
0066 #define DW_CFA_set_loc                      0x01
0067 #define DW_CFA_advance_loc1                 0x02
0068 #define DW_CFA_advance_loc2                 0x03
0069 #define DW_CFA_advance_loc4                 0x04
0070 #define DW_CFA_offset_extended              0x05
0071 #define DW_CFA_restore_extended             0x06
0072 #define DW_CFA_undefined                    0x07
0073 #define DW_CFA_same_value                   0x08
0074 #define DW_CFA_register                     0x09
0075 #define DW_CFA_remember_state               0x0a
0076 #define DW_CFA_restore_state                0x0b
0077 #define DW_CFA_def_cfa                      0x0c
0078 #define DW_CFA_def_cfa_register             0x0d
0079 #define DW_CFA_def_cfa_offset               0x0e
0080 #define DW_CFA_def_cfa_expression           0x0f
0081 #define DW_CFA_expression                   0x10
0082 #define DW_CFA_offset_extended_sf           0x11
0083 #define DW_CFA_def_cfa_sf                   0x12
0084 #define DW_CFA_def_cfa_offset_sf            0x13
0085 #define DW_CFA_val_offset                   0x14
0086 #define DW_CFA_val_offset_sf                0x15
0087 #define DW_CFA_val_expression               0x16
0088 #define DW_CFA_lo_user                      0x1c
0089 #define DW_CFA_GNU_window_save              0x2d
0090 #define DW_CFA_GNU_args_size                0x2e
0091 #define DW_CFA_GNU_negative_offset_extended 0x2f
0092 #define DW_CFA_hi_user                      0x3f
0093 
0094 #define DW_EH_PE_FORM     0x07
0095 #define DW_EH_PE_native   0x00
0096 #define DW_EH_PE_leb128   0x01
0097 #define DW_EH_PE_data2    0x02
0098 #define DW_EH_PE_data4    0x03
0099 #define DW_EH_PE_data8    0x04
0100 #define DW_EH_PE_signed   0x08
0101 #define DW_EH_PE_ADJUST   0x70
0102 #define DW_EH_PE_abs      0x00
0103 #define DW_EH_PE_pcrel    0x10
0104 #define DW_EH_PE_textrel  0x20
0105 #define DW_EH_PE_datarel  0x30
0106 #define DW_EH_PE_funcrel  0x40
0107 #define DW_EH_PE_aligned  0x50
0108 #define DW_EH_PE_indirect 0x80
0109 #define DW_EH_PE_omit     0xff
0110 
0111 #define CIE_ID  0
0112 
0113 typedef unsigned long uleb128_t;
0114 typedef signed long sleb128_t;
0115 
0116 static struct unwind_table {
0117     struct {
0118         unsigned long pc;
0119         unsigned long range;
0120     } core, init;
0121     const void *address;
0122     unsigned long size;
0123     const unsigned char *header;
0124     unsigned long hdrsz;
0125     struct unwind_table *link;
0126     const char *name;
0127 } root_table;
0128 
0129 struct unwind_item {
0130     enum item_location {
0131         Nowhere,
0132         Memory,
0133         Register,
0134         Value
0135     } where;
0136     uleb128_t value;
0137 };
0138 
0139 struct unwind_state {
0140     uleb128_t loc, org;
0141     const u8 *cieStart, *cieEnd;
0142     uleb128_t codeAlign;
0143     sleb128_t dataAlign;
0144     struct cfa {
0145         uleb128_t reg, offs;
0146     } cfa;
0147     struct unwind_item regs[ARRAY_SIZE(reg_info)];
0148     unsigned stackDepth:8;
0149     unsigned version:8;
0150     const u8 *label;
0151     const u8 *stack[MAX_STACK_DEPTH];
0152 };
0153 
0154 static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 };
0155 
0156 static struct unwind_table *find_table(unsigned long pc)
0157 {
0158     struct unwind_table *table;
0159 
0160     for (table = &root_table; table; table = table->link)
0161         if ((pc >= table->core.pc
0162              && pc < table->core.pc + table->core.range)
0163             || (pc >= table->init.pc
0164             && pc < table->init.pc + table->init.range))
0165             break;
0166 
0167     return table;
0168 }
0169 
0170 static unsigned long read_pointer(const u8 **pLoc,
0171                   const void *end, signed ptrType);
0172 static void init_unwind_hdr(struct unwind_table *table,
0173                 void *(*alloc) (unsigned long));
0174 
0175 /*
0176  * wrappers for header alloc (vs. calling one vs. other at call site)
0177  * to elide section mismatches warnings
0178  */
0179 static void *__init unw_hdr_alloc_early(unsigned long sz)
0180 {
0181     return memblock_alloc_from(sz, sizeof(unsigned int), MAX_DMA_ADDRESS);
0182 }
0183 
0184 static void init_unwind_table(struct unwind_table *table, const char *name,
0185                   const void *core_start, unsigned long core_size,
0186                   const void *init_start, unsigned long init_size,
0187                   const void *table_start, unsigned long table_size,
0188                   const u8 *header_start, unsigned long header_size)
0189 {
0190     table->core.pc = (unsigned long)core_start;
0191     table->core.range = core_size;
0192     table->init.pc = (unsigned long)init_start;
0193     table->init.range = init_size;
0194     table->address = table_start;
0195     table->size = table_size;
0196     /* To avoid the pointer addition with NULL pointer.*/
0197     if (header_start != NULL) {
0198         const u8 *ptr = header_start + 4;
0199         const u8 *end = header_start + header_size;
0200         /* See if the linker provided table looks valid. */
0201         if (header_size <= 4
0202         || header_start[0] != 1
0203         || (void *)read_pointer(&ptr, end, header_start[1])
0204                 != table_start
0205         || header_start[2] == DW_EH_PE_omit
0206         || read_pointer(&ptr, end, header_start[2]) <= 0
0207         || header_start[3] == DW_EH_PE_omit)
0208             header_start = NULL;
0209     }
0210     table->hdrsz = header_size;
0211     smp_wmb();
0212     table->header = header_start;
0213     table->link = NULL;
0214     table->name = name;
0215 }
0216 
0217 void __init arc_unwind_init(void)
0218 {
0219     init_unwind_table(&root_table, "kernel", _text, _end - _text, NULL, 0,
0220               __start_unwind, __end_unwind - __start_unwind,
0221               NULL, 0);
0222       /*__start_unwind_hdr, __end_unwind_hdr - __start_unwind_hdr);*/
0223 
0224     init_unwind_hdr(&root_table, unw_hdr_alloc_early);
0225 }
0226 
0227 static const u32 bad_cie, not_fde;
0228 static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *);
0229 static const u32 *__cie_for_fde(const u32 *fde);
0230 static signed fde_pointer_type(const u32 *cie);
0231 
0232 struct eh_frame_hdr_table_entry {
0233     unsigned long start, fde;
0234 };
0235 
0236 static int cmp_eh_frame_hdr_table_entries(const void *p1, const void *p2)
0237 {
0238     const struct eh_frame_hdr_table_entry *e1 = p1;
0239     const struct eh_frame_hdr_table_entry *e2 = p2;
0240 
0241     return (e1->start > e2->start) - (e1->start < e2->start);
0242 }
0243 
0244 static void swap_eh_frame_hdr_table_entries(void *p1, void *p2, int size)
0245 {
0246     struct eh_frame_hdr_table_entry *e1 = p1;
0247     struct eh_frame_hdr_table_entry *e2 = p2;
0248 
0249     swap(e1->start, e2->start);
0250     swap(e1->fde, e2->fde);
0251 }
0252 
0253 static void init_unwind_hdr(struct unwind_table *table,
0254                 void *(*alloc) (unsigned long))
0255 {
0256     const u8 *ptr;
0257     unsigned long tableSize = table->size, hdrSize;
0258     unsigned int n;
0259     const u32 *fde;
0260     struct {
0261         u8 version;
0262         u8 eh_frame_ptr_enc;
0263         u8 fde_count_enc;
0264         u8 table_enc;
0265         unsigned long eh_frame_ptr;
0266         unsigned int fde_count;
0267         struct eh_frame_hdr_table_entry table[];
0268     } __attribute__ ((__packed__)) *header;
0269 
0270     if (table->header)
0271         return;
0272 
0273     if (table->hdrsz)
0274         pr_warn(".eh_frame_hdr for '%s' present but unusable\n",
0275             table->name);
0276 
0277     if (tableSize & (sizeof(*fde) - 1))
0278         return;
0279 
0280     for (fde = table->address, n = 0;
0281          tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde;
0282          tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
0283         const u32 *cie = cie_for_fde(fde, table);
0284         signed ptrType;
0285 
0286         if (cie == &not_fde)
0287             continue;
0288         if (cie == NULL || cie == &bad_cie)
0289             goto ret_err;
0290         ptrType = fde_pointer_type(cie);
0291         if (ptrType < 0)
0292             goto ret_err;
0293 
0294         ptr = (const u8 *)(fde + 2);
0295         if (!read_pointer(&ptr, (const u8 *)(fde + 1) + *fde,
0296                                 ptrType)) {
0297             /* FIXME_Rajesh We have 4 instances of null addresses
0298              * instead of the initial loc addr
0299              * return;
0300              */
0301             WARN(1, "unwinder: FDE->initial_location NULL %p\n",
0302                 (const u8 *)(fde + 1) + *fde);
0303         }
0304         ++n;
0305     }
0306 
0307     if (tableSize || !n)
0308         goto ret_err;
0309 
0310     hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int)
0311         + 2 * n * sizeof(unsigned long);
0312 
0313     header = alloc(hdrSize);
0314     if (!header)
0315         goto ret_err;
0316 
0317     header->version = 1;
0318     header->eh_frame_ptr_enc = DW_EH_PE_abs | DW_EH_PE_native;
0319     header->fde_count_enc = DW_EH_PE_abs | DW_EH_PE_data4;
0320     header->table_enc = DW_EH_PE_abs | DW_EH_PE_native;
0321     put_unaligned((unsigned long)table->address, &header->eh_frame_ptr);
0322     BUILD_BUG_ON(offsetof(typeof(*header), fde_count)
0323              % __alignof(typeof(header->fde_count)));
0324     header->fde_count = n;
0325 
0326     BUILD_BUG_ON(offsetof(typeof(*header), table)
0327              % __alignof(typeof(*header->table)));
0328     for (fde = table->address, tableSize = table->size, n = 0;
0329          tableSize;
0330          tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
0331         const u32 *cie = __cie_for_fde(fde);
0332 
0333         if (fde[1] == CIE_ID)
0334             continue;   /* this is a CIE */
0335         ptr = (const u8 *)(fde + 2);
0336         header->table[n].start = read_pointer(&ptr,
0337                               (const u8 *)(fde + 1) +
0338                               *fde,
0339                               fde_pointer_type(cie));
0340         header->table[n].fde = (unsigned long)fde;
0341         ++n;
0342     }
0343     WARN_ON(n != header->fde_count);
0344 
0345     sort(header->table,
0346          n,
0347          sizeof(*header->table),
0348          cmp_eh_frame_hdr_table_entries, swap_eh_frame_hdr_table_entries);
0349 
0350     table->hdrsz = hdrSize;
0351     smp_wmb();
0352     table->header = (const void *)header;
0353     return;
0354 
0355 ret_err:
0356     panic("Attention !!! Dwarf FDE parsing errors\n");
0357 }
0358 
0359 #ifdef CONFIG_MODULES
0360 static void *unw_hdr_alloc(unsigned long sz)
0361 {
0362     return kmalloc(sz, GFP_KERNEL);
0363 }
0364 
0365 static struct unwind_table *last_table;
0366 
0367 /* Must be called with module_mutex held. */
0368 void *unwind_add_table(struct module *module, const void *table_start,
0369                unsigned long table_size)
0370 {
0371     struct unwind_table *table;
0372 
0373     if (table_size <= 0)
0374         return NULL;
0375 
0376     table = kmalloc(sizeof(*table), GFP_KERNEL);
0377     if (!table)
0378         return NULL;
0379 
0380     init_unwind_table(table, module->name,
0381               module->core_layout.base, module->core_layout.size,
0382               module->init_layout.base, module->init_layout.size,
0383               table_start, table_size,
0384               NULL, 0);
0385 
0386     init_unwind_hdr(table, unw_hdr_alloc);
0387 
0388 #ifdef UNWIND_DEBUG
0389     unw_debug("Table added for [%s] %lx %lx\n",
0390         module->name, table->core.pc, table->core.range);
0391 #endif
0392     if (last_table)
0393         last_table->link = table;
0394     else
0395         root_table.link = table;
0396     last_table = table;
0397 
0398     return table;
0399 }
0400 
0401 struct unlink_table_info {
0402     struct unwind_table *table;
0403     int init_only;
0404 };
0405 
0406 static int unlink_table(void *arg)
0407 {
0408     struct unlink_table_info *info = arg;
0409     struct unwind_table *table = info->table, *prev;
0410 
0411     for (prev = &root_table; prev->link && prev->link != table;
0412          prev = prev->link)
0413         ;
0414 
0415     if (prev->link) {
0416         if (info->init_only) {
0417             table->init.pc = 0;
0418             table->init.range = 0;
0419             info->table = NULL;
0420         } else {
0421             prev->link = table->link;
0422             if (!prev->link)
0423                 last_table = prev;
0424         }
0425     } else
0426         info->table = NULL;
0427 
0428     return 0;
0429 }
0430 
0431 /* Must be called with module_mutex held. */
0432 void unwind_remove_table(void *handle, int init_only)
0433 {
0434     struct unwind_table *table = handle;
0435     struct unlink_table_info info;
0436 
0437     if (!table || table == &root_table)
0438         return;
0439 
0440     if (init_only && table == last_table) {
0441         table->init.pc = 0;
0442         table->init.range = 0;
0443         return;
0444     }
0445 
0446     info.table = table;
0447     info.init_only = init_only;
0448 
0449     unlink_table(&info); /* XXX: SMP */
0450     kfree(table->header);
0451     kfree(table);
0452 }
0453 
0454 #endif /* CONFIG_MODULES */
0455 
0456 static uleb128_t get_uleb128(const u8 **pcur, const u8 *end)
0457 {
0458     const u8 *cur = *pcur;
0459     uleb128_t value;
0460     unsigned int shift;
0461 
0462     for (shift = 0, value = 0; cur < end; shift += 7) {
0463         if (shift + 7 > 8 * sizeof(value)
0464             && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
0465             cur = end + 1;
0466             break;
0467         }
0468         value |= (uleb128_t) (*cur & 0x7f) << shift;
0469         if (!(*cur++ & 0x80))
0470             break;
0471     }
0472     *pcur = cur;
0473 
0474     return value;
0475 }
0476 
0477 static sleb128_t get_sleb128(const u8 **pcur, const u8 *end)
0478 {
0479     const u8 *cur = *pcur;
0480     sleb128_t value;
0481     unsigned int shift;
0482 
0483     for (shift = 0, value = 0; cur < end; shift += 7) {
0484         if (shift + 7 > 8 * sizeof(value)
0485             && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
0486             cur = end + 1;
0487             break;
0488         }
0489         value |= (sleb128_t) (*cur & 0x7f) << shift;
0490         if (!(*cur & 0x80)) {
0491             value |= -(*cur++ & 0x40) << shift;
0492             break;
0493         }
0494     }
0495     *pcur = cur;
0496 
0497     return value;
0498 }
0499 
0500 static const u32 *__cie_for_fde(const u32 *fde)
0501 {
0502     const u32 *cie;
0503 
0504     cie = fde + 1 - fde[1] / sizeof(*fde);
0505 
0506     return cie;
0507 }
0508 
0509 static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *table)
0510 {
0511     const u32 *cie;
0512 
0513     if (!*fde || (*fde & (sizeof(*fde) - 1)))
0514         return &bad_cie;
0515 
0516     if (fde[1] == CIE_ID)
0517         return &not_fde;    /* this is a CIE */
0518 
0519     if ((fde[1] & (sizeof(*fde) - 1)))
0520 /* || fde[1] > (unsigned long)(fde + 1) - (unsigned long)table->address) */
0521         return NULL;    /* this is not a valid FDE */
0522 
0523     cie = __cie_for_fde(fde);
0524 
0525     if (*cie <= sizeof(*cie) + 4 || *cie >= fde[1] - sizeof(*fde)
0526         || (*cie & (sizeof(*cie) - 1))
0527         || (cie[1] != CIE_ID))
0528         return NULL;    /* this is not a (valid) CIE */
0529     return cie;
0530 }
0531 
0532 static unsigned long read_pointer(const u8 **pLoc, const void *end,
0533                   signed ptrType)
0534 {
0535     unsigned long value = 0;
0536     union {
0537         const u8 *p8;
0538         const u16 *p16u;
0539         const s16 *p16s;
0540         const u32 *p32u;
0541         const s32 *p32s;
0542         const unsigned long *pul;
0543     } ptr;
0544 
0545     if (ptrType < 0 || ptrType == DW_EH_PE_omit)
0546         return 0;
0547     ptr.p8 = *pLoc;
0548     switch (ptrType & DW_EH_PE_FORM) {
0549     case DW_EH_PE_data2:
0550         if (end < (const void *)(ptr.p16u + 1))
0551             return 0;
0552         if (ptrType & DW_EH_PE_signed)
0553             value = get_unaligned((u16 *) ptr.p16s++);
0554         else
0555             value = get_unaligned((u16 *) ptr.p16u++);
0556         break;
0557     case DW_EH_PE_data4:
0558 #ifdef CONFIG_64BIT
0559         if (end < (const void *)(ptr.p32u + 1))
0560             return 0;
0561         if (ptrType & DW_EH_PE_signed)
0562             value = get_unaligned(ptr.p32s++);
0563         else
0564             value = get_unaligned(ptr.p32u++);
0565         break;
0566     case DW_EH_PE_data8:
0567         BUILD_BUG_ON(sizeof(u64) != sizeof(value));
0568 #else
0569         BUILD_BUG_ON(sizeof(u32) != sizeof(value));
0570 #endif
0571         fallthrough;
0572     case DW_EH_PE_native:
0573         if (end < (const void *)(ptr.pul + 1))
0574             return 0;
0575         value = get_unaligned((unsigned long *)ptr.pul++);
0576         break;
0577     case DW_EH_PE_leb128:
0578         BUILD_BUG_ON(sizeof(uleb128_t) > sizeof(value));
0579         value = ptrType & DW_EH_PE_signed ? get_sleb128(&ptr.p8, end)
0580             : get_uleb128(&ptr.p8, end);
0581         if ((const void *)ptr.p8 > end)
0582             return 0;
0583         break;
0584     default:
0585         return 0;
0586     }
0587     switch (ptrType & DW_EH_PE_ADJUST) {
0588     case DW_EH_PE_abs:
0589         break;
0590     case DW_EH_PE_pcrel:
0591         value += (unsigned long)*pLoc;
0592         break;
0593     default:
0594         return 0;
0595     }
0596     if ((ptrType & DW_EH_PE_indirect)
0597         && __get_user(value, (unsigned long __user *)value))
0598         return 0;
0599     *pLoc = ptr.p8;
0600 
0601     return value;
0602 }
0603 
0604 static signed fde_pointer_type(const u32 *cie)
0605 {
0606     const u8 *ptr = (const u8 *)(cie + 2);
0607     unsigned int version = *ptr;
0608 
0609     if (*++ptr) {
0610         const char *aug;
0611         const u8 *end = (const u8 *)(cie + 1) + *cie;
0612         uleb128_t len;
0613 
0614         /* check if augmentation size is first (and thus present) */
0615         if (*ptr != 'z')
0616             return -1;
0617 
0618         /* check if augmentation string is nul-terminated */
0619         aug = (const void *)ptr;
0620         ptr = memchr(aug, 0, end - ptr);
0621         if (ptr == NULL)
0622             return -1;
0623 
0624         ++ptr;      /* skip terminator */
0625         get_uleb128(&ptr, end); /* skip code alignment */
0626         get_sleb128(&ptr, end); /* skip data alignment */
0627         /* skip return address column */
0628         version <= 1 ? (void) ++ptr : (void)get_uleb128(&ptr, end);
0629         len = get_uleb128(&ptr, end);   /* augmentation length */
0630 
0631         if (ptr + len < ptr || ptr + len > end)
0632             return -1;
0633 
0634         end = ptr + len;
0635         while (*++aug) {
0636             if (ptr >= end)
0637                 return -1;
0638             switch (*aug) {
0639             case 'L':
0640                 ++ptr;
0641                 break;
0642             case 'P':{
0643                     signed ptrType = *ptr++;
0644 
0645                     if (!read_pointer(&ptr, end, ptrType)
0646                         || ptr > end)
0647                         return -1;
0648                 }
0649                 break;
0650             case 'R':
0651                 return *ptr;
0652             default:
0653                 return -1;
0654             }
0655         }
0656     }
0657     return DW_EH_PE_native | DW_EH_PE_abs;
0658 }
0659 
0660 static int advance_loc(unsigned long delta, struct unwind_state *state)
0661 {
0662     state->loc += delta * state->codeAlign;
0663 
0664     /* FIXME_Rajesh: Probably we are defining for the initial range as well;
0665        return delta > 0;
0666      */
0667     unw_debug("delta %3lu => loc 0x%lx: ", delta, state->loc);
0668     return 1;
0669 }
0670 
0671 static void set_rule(uleb128_t reg, enum item_location where, uleb128_t value,
0672              struct unwind_state *state)
0673 {
0674     if (reg < ARRAY_SIZE(state->regs)) {
0675         state->regs[reg].where = where;
0676         state->regs[reg].value = value;
0677 
0678 #ifdef UNWIND_DEBUG
0679         unw_debug("r%lu: ", reg);
0680         switch (where) {
0681         case Nowhere:
0682             unw_debug("s ");
0683             break;
0684         case Memory:
0685             unw_debug("c(%lu) ", value);
0686             break;
0687         case Register:
0688             unw_debug("r(%lu) ", value);
0689             break;
0690         case Value:
0691             unw_debug("v(%lu) ", value);
0692             break;
0693         default:
0694             break;
0695         }
0696 #endif
0697     }
0698 }
0699 
0700 static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
0701               signed ptrType, struct unwind_state *state)
0702 {
0703     union {
0704         const u8 *p8;
0705         const u16 *p16;
0706         const u32 *p32;
0707     } ptr;
0708     int result = 1;
0709     u8 opcode;
0710 
0711     if (start != state->cieStart) {
0712         state->loc = state->org;
0713         result =
0714             processCFI(state->cieStart, state->cieEnd, 0, ptrType,
0715                    state);
0716         if (targetLoc == 0 && state->label == NULL)
0717             return result;
0718     }
0719     for (ptr.p8 = start; result && ptr.p8 < end;) {
0720         switch (*ptr.p8 >> 6) {
0721             uleb128_t value;
0722 
0723         case 0:
0724             opcode = *ptr.p8++;
0725 
0726             switch (opcode) {
0727             case DW_CFA_nop:
0728                 unw_debug("cfa nop ");
0729                 break;
0730             case DW_CFA_set_loc:
0731                 state->loc = read_pointer(&ptr.p8, end,
0732                               ptrType);
0733                 if (state->loc == 0)
0734                     result = 0;
0735                 unw_debug("cfa_set_loc: 0x%lx ", state->loc);
0736                 break;
0737             case DW_CFA_advance_loc1:
0738                 unw_debug("\ncfa advance loc1:");
0739                 result = ptr.p8 < end
0740                     && advance_loc(*ptr.p8++, state);
0741                 break;
0742             case DW_CFA_advance_loc2:
0743                 value = *ptr.p8++;
0744                 value += *ptr.p8++ << 8;
0745                 unw_debug("\ncfa advance loc2:");
0746                 result = ptr.p8 <= end + 2
0747                     /* && advance_loc(*ptr.p16++, state); */
0748                     && advance_loc(value, state);
0749                 break;
0750             case DW_CFA_advance_loc4:
0751                 unw_debug("\ncfa advance loc4:");
0752                 result = ptr.p8 <= end + 4
0753                     && advance_loc(*ptr.p32++, state);
0754                 break;
0755             case DW_CFA_offset_extended:
0756                 value = get_uleb128(&ptr.p8, end);
0757                 unw_debug("cfa_offset_extended: ");
0758                 set_rule(value, Memory,
0759                      get_uleb128(&ptr.p8, end), state);
0760                 break;
0761             case DW_CFA_val_offset:
0762                 value = get_uleb128(&ptr.p8, end);
0763                 set_rule(value, Value,
0764                      get_uleb128(&ptr.p8, end), state);
0765                 break;
0766             case DW_CFA_offset_extended_sf:
0767                 value = get_uleb128(&ptr.p8, end);
0768                 set_rule(value, Memory,
0769                      get_sleb128(&ptr.p8, end), state);
0770                 break;
0771             case DW_CFA_val_offset_sf:
0772                 value = get_uleb128(&ptr.p8, end);
0773                 set_rule(value, Value,
0774                      get_sleb128(&ptr.p8, end), state);
0775                 break;
0776             case DW_CFA_restore_extended:
0777                 unw_debug("cfa_restore_extended: ");
0778             case DW_CFA_undefined:
0779                 unw_debug("cfa_undefined: ");
0780             case DW_CFA_same_value:
0781                 unw_debug("cfa_same_value: ");
0782                 set_rule(get_uleb128(&ptr.p8, end), Nowhere, 0,
0783                      state);
0784                 break;
0785             case DW_CFA_register:
0786                 unw_debug("cfa_register: ");
0787                 value = get_uleb128(&ptr.p8, end);
0788                 set_rule(value,
0789                      Register,
0790                      get_uleb128(&ptr.p8, end), state);
0791                 break;
0792             case DW_CFA_remember_state:
0793                 unw_debug("cfa_remember_state: ");
0794                 if (ptr.p8 == state->label) {
0795                     state->label = NULL;
0796                     return 1;
0797                 }
0798                 if (state->stackDepth >= MAX_STACK_DEPTH)
0799                     return 0;
0800                 state->stack[state->stackDepth++] = ptr.p8;
0801                 break;
0802             case DW_CFA_restore_state:
0803                 unw_debug("cfa_restore_state: ");
0804                 if (state->stackDepth) {
0805                     const uleb128_t loc = state->loc;
0806                     const u8 *label = state->label;
0807 
0808                     state->label =
0809                         state->stack[state->stackDepth - 1];
0810                     memcpy(&state->cfa, &badCFA,
0811                            sizeof(state->cfa));
0812                     memset(state->regs, 0,
0813                            sizeof(state->regs));
0814                     state->stackDepth = 0;
0815                     result =
0816                         processCFI(start, end, 0, ptrType,
0817                                state);
0818                     state->loc = loc;
0819                     state->label = label;
0820                 } else
0821                     return 0;
0822                 break;
0823             case DW_CFA_def_cfa:
0824                 state->cfa.reg = get_uleb128(&ptr.p8, end);
0825                 unw_debug("cfa_def_cfa: r%lu ", state->cfa.reg);
0826                 fallthrough;
0827             case DW_CFA_def_cfa_offset:
0828                 state->cfa.offs = get_uleb128(&ptr.p8, end);
0829                 unw_debug("cfa_def_cfa_offset: 0x%lx ",
0830                       state->cfa.offs);
0831                 break;
0832             case DW_CFA_def_cfa_sf:
0833                 state->cfa.reg = get_uleb128(&ptr.p8, end);
0834                 fallthrough;
0835             case DW_CFA_def_cfa_offset_sf:
0836                 state->cfa.offs = get_sleb128(&ptr.p8, end)
0837                     * state->dataAlign;
0838                 break;
0839             case DW_CFA_def_cfa_register:
0840                 unw_debug("cfa_def_cfa_register: ");
0841                 state->cfa.reg = get_uleb128(&ptr.p8, end);
0842                 break;
0843                 /*todo case DW_CFA_def_cfa_expression: */
0844                 /*todo case DW_CFA_expression: */
0845                 /*todo case DW_CFA_val_expression: */
0846             case DW_CFA_GNU_args_size:
0847                 get_uleb128(&ptr.p8, end);
0848                 break;
0849             case DW_CFA_GNU_negative_offset_extended:
0850                 value = get_uleb128(&ptr.p8, end);
0851                 set_rule(value,
0852                      Memory,
0853                      (uleb128_t) 0 - get_uleb128(&ptr.p8,
0854                                      end),
0855                      state);
0856                 break;
0857             case DW_CFA_GNU_window_save:
0858             default:
0859                 unw_debug("UNKNOWN OPCODE 0x%x\n", opcode);
0860                 result = 0;
0861                 break;
0862             }
0863             break;
0864         case 1:
0865             unw_debug("\ncfa_adv_loc: ");
0866             result = advance_loc(*ptr.p8++ & 0x3f, state);
0867             break;
0868         case 2:
0869             unw_debug("cfa_offset: ");
0870             value = *ptr.p8++ & 0x3f;
0871             set_rule(value, Memory, get_uleb128(&ptr.p8, end),
0872                  state);
0873             break;
0874         case 3:
0875             unw_debug("cfa_restore: ");
0876             set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state);
0877             break;
0878         }
0879 
0880         if (ptr.p8 > end)
0881             result = 0;
0882         if (result && targetLoc != 0 && targetLoc < state->loc)
0883             return 1;
0884     }
0885 
0886     return result && ptr.p8 == end && (targetLoc == 0 || (
0887         /*todo While in theory this should apply, gcc in practice omits
0888           everything past the function prolog, and hence the location
0889           never reaches the end of the function.
0890         targetLoc < state->loc && */  state->label == NULL));
0891 }
0892 
0893 /* Unwind to previous to frame.  Returns 0 if successful, negative
0894  * number in case of an error. */
0895 int arc_unwind(struct unwind_frame_info *frame)
0896 {
0897 #define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
0898     const u32 *fde = NULL, *cie = NULL;
0899     const u8 *ptr = NULL, *end = NULL;
0900     unsigned long pc = UNW_PC(frame) - frame->call_frame;
0901     unsigned long startLoc = 0, endLoc = 0, cfa;
0902     unsigned int i;
0903     signed ptrType = -1;
0904     uleb128_t retAddrReg = 0;
0905     const struct unwind_table *table;
0906     struct unwind_state state;
0907     unsigned long *fptr;
0908     unsigned long addr;
0909 
0910     unw_debug("\n\nUNWIND FRAME:\n");
0911     unw_debug("PC: 0x%lx BLINK: 0x%lx, SP: 0x%lx, FP: 0x%x\n",
0912           UNW_PC(frame), UNW_BLINK(frame), UNW_SP(frame),
0913           UNW_FP(frame));
0914 
0915     if (UNW_PC(frame) == 0)
0916         return -EINVAL;
0917 
0918 #ifdef UNWIND_DEBUG
0919     {
0920         unsigned long *sptr = (unsigned long *)UNW_SP(frame);
0921         unw_debug("\nStack Dump:\n");
0922         for (i = 0; i < 20; i++, sptr++)
0923             unw_debug("0x%p:  0x%lx\n", sptr, *sptr);
0924         unw_debug("\n");
0925     }
0926 #endif
0927 
0928     table = find_table(pc);
0929     if (table != NULL
0930         && !(table->size & (sizeof(*fde) - 1))) {
0931         const u8 *hdr = table->header;
0932         unsigned long tableSize;
0933 
0934         smp_rmb();
0935         if (hdr && hdr[0] == 1) {
0936             switch (hdr[3] & DW_EH_PE_FORM) {
0937             case DW_EH_PE_native:
0938                 tableSize = sizeof(unsigned long);
0939                 break;
0940             case DW_EH_PE_data2:
0941                 tableSize = 2;
0942                 break;
0943             case DW_EH_PE_data4:
0944                 tableSize = 4;
0945                 break;
0946             case DW_EH_PE_data8:
0947                 tableSize = 8;
0948                 break;
0949             default:
0950                 tableSize = 0;
0951                 break;
0952             }
0953             ptr = hdr + 4;
0954             end = hdr + table->hdrsz;
0955             if (tableSize && read_pointer(&ptr, end, hdr[1])
0956                 == (unsigned long)table->address
0957                 && (i = read_pointer(&ptr, end, hdr[2])) > 0
0958                 && i == (end - ptr) / (2 * tableSize)
0959                 && !((end - ptr) % (2 * tableSize))) {
0960                 do {
0961                     const u8 *cur =
0962                         ptr + (i / 2) * (2 * tableSize);
0963 
0964                     startLoc = read_pointer(&cur,
0965                                 cur + tableSize,
0966                                 hdr[3]);
0967                     if (pc < startLoc)
0968                         i /= 2;
0969                     else {
0970                         ptr = cur - tableSize;
0971                         i = (i + 1) / 2;
0972                     }
0973                 } while (startLoc && i > 1);
0974                 if (i == 1
0975                     && (startLoc = read_pointer(&ptr,
0976                                 ptr + tableSize,
0977                                 hdr[3])) != 0
0978                     && pc >= startLoc)
0979                     fde = (void *)read_pointer(&ptr,
0980                                    ptr +
0981                                    tableSize,
0982                                    hdr[3]);
0983             }
0984         }
0985 
0986         if (fde != NULL) {
0987             cie = cie_for_fde(fde, table);
0988             ptr = (const u8 *)(fde + 2);
0989             if (cie != NULL
0990                 && cie != &bad_cie
0991                 && cie != &not_fde
0992                 && (ptrType = fde_pointer_type(cie)) >= 0
0993                 && read_pointer(&ptr,
0994                         (const u8 *)(fde + 1) + *fde,
0995                         ptrType) == startLoc) {
0996                 if (!(ptrType & DW_EH_PE_indirect))
0997                     ptrType &=
0998                         DW_EH_PE_FORM | DW_EH_PE_signed;
0999                 endLoc =
1000                     startLoc + read_pointer(&ptr,
1001                                 (const u8 *)(fde +
1002                                      1) +
1003                                 *fde, ptrType);
1004                 if (pc >= endLoc) {
1005                     fde = NULL;
1006                     cie = NULL;
1007                 }
1008             } else {
1009                 fde = NULL;
1010                 cie = NULL;
1011             }
1012         }
1013     }
1014     if (cie != NULL) {
1015         memset(&state, 0, sizeof(state));
1016         state.cieEnd = ptr; /* keep here temporarily */
1017         ptr = (const u8 *)(cie + 2);
1018         end = (const u8 *)(cie + 1) + *cie;
1019         frame->call_frame = 1;
1020         if (*++ptr) {
1021             /* check if augmentation size is first (thus present) */
1022             if (*ptr == 'z') {
1023                 while (++ptr < end && *ptr) {
1024                     switch (*ptr) {
1025                     /* chk for ignorable or already handled
1026                      * nul-terminated augmentation string */
1027                     case 'L':
1028                     case 'P':
1029                     case 'R':
1030                         continue;
1031                     case 'S':
1032                         frame->call_frame = 0;
1033                         continue;
1034                     default:
1035                         break;
1036                     }
1037                     break;
1038                 }
1039             }
1040             if (ptr >= end || *ptr)
1041                 cie = NULL;
1042         }
1043         ++ptr;
1044     }
1045     if (cie != NULL) {
1046         /* get code alignment factor */
1047         state.codeAlign = get_uleb128(&ptr, end);
1048         /* get data alignment factor */
1049         state.dataAlign = get_sleb128(&ptr, end);
1050         if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end)
1051             cie = NULL;
1052         else {
1053             retAddrReg =
1054                 state.version <= 1 ? *ptr++ : get_uleb128(&ptr,
1055                                       end);
1056             unw_debug("CIE Frame Info:\n");
1057             unw_debug("return Address register 0x%lx\n",
1058                   retAddrReg);
1059             unw_debug("data Align: %ld\n", state.dataAlign);
1060             unw_debug("code Align: %lu\n", state.codeAlign);
1061             /* skip augmentation */
1062             if (((const char *)(cie + 2))[1] == 'z') {
1063                 uleb128_t augSize = get_uleb128(&ptr, end);
1064 
1065                 ptr += augSize;
1066             }
1067             if (ptr > end || retAddrReg >= ARRAY_SIZE(reg_info)
1068                 || REG_INVALID(retAddrReg)
1069                 || reg_info[retAddrReg].width !=
1070                 sizeof(unsigned long))
1071                 cie = NULL;
1072         }
1073     }
1074     if (cie != NULL) {
1075         state.cieStart = ptr;
1076         ptr = state.cieEnd;
1077         state.cieEnd = end;
1078         end = (const u8 *)(fde + 1) + *fde;
1079         /* skip augmentation */
1080         if (((const char *)(cie + 2))[1] == 'z') {
1081             uleb128_t augSize = get_uleb128(&ptr, end);
1082 
1083             if ((ptr += augSize) > end)
1084                 fde = NULL;
1085         }
1086     }
1087     if (cie == NULL || fde == NULL) {
1088 #ifdef CONFIG_FRAME_POINTER
1089         unsigned long top, bottom;
1090 
1091         top = STACK_TOP_UNW(frame->task);
1092         bottom = STACK_BOTTOM_UNW(frame->task);
1093 #if FRAME_RETADDR_OFFSET < 0
1094         if (UNW_SP(frame) < top && UNW_FP(frame) <= UNW_SP(frame)
1095             && bottom < UNW_FP(frame)
1096 #else
1097         if (UNW_SP(frame) > top && UNW_FP(frame) >= UNW_SP(frame)
1098             && bottom > UNW_FP(frame)
1099 #endif
1100             && !((UNW_SP(frame) | UNW_FP(frame))
1101              & (sizeof(unsigned long) - 1))) {
1102             unsigned long link;
1103 
1104             if (!__get_user(link, (unsigned long *)
1105                     (UNW_FP(frame) + FRAME_LINK_OFFSET))
1106 #if FRAME_RETADDR_OFFSET < 0
1107                 && link > bottom && link < UNW_FP(frame)
1108 #else
1109                 && link > UNW_FP(frame) && link < bottom
1110 #endif
1111                 && !(link & (sizeof(link) - 1))
1112                 && !__get_user(UNW_PC(frame),
1113                        (unsigned long *)(UNW_FP(frame)
1114                         + FRAME_RETADDR_OFFSET)))
1115             {
1116                 UNW_SP(frame) =
1117                     UNW_FP(frame) + FRAME_RETADDR_OFFSET
1118 #if FRAME_RETADDR_OFFSET < 0
1119                     -
1120 #else
1121                     +
1122 #endif
1123                     sizeof(UNW_PC(frame));
1124                 UNW_FP(frame) = link;
1125                 return 0;
1126             }
1127         }
1128 #endif
1129         return -ENXIO;
1130     }
1131     state.org = startLoc;
1132     memcpy(&state.cfa, &badCFA, sizeof(state.cfa));
1133 
1134     unw_debug("\nProcess instructions\n");
1135 
1136     /* process instructions
1137      * For ARC, we optimize by having blink(retAddrReg) with
1138      * the sameValue in the leaf function, so we should not check
1139      * state.regs[retAddrReg].where == Nowhere
1140      */
1141     if (!processCFI(ptr, end, pc, ptrType, &state)
1142         || state.loc > endLoc
1143 /*     || state.regs[retAddrReg].where == Nowhere */
1144         || state.cfa.reg >= ARRAY_SIZE(reg_info)
1145         || reg_info[state.cfa.reg].width != sizeof(unsigned long)
1146         || state.cfa.offs % sizeof(unsigned long))
1147         return -EIO;
1148 
1149 #ifdef UNWIND_DEBUG
1150     unw_debug("\n");
1151 
1152     unw_debug("\nRegister State Based on the rules parsed from FDE:\n");
1153     for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
1154 
1155         if (REG_INVALID(i))
1156             continue;
1157 
1158         switch (state.regs[i].where) {
1159         case Nowhere:
1160             break;
1161         case Memory:
1162             unw_debug(" r%d: c(%lu),", i, state.regs[i].value);
1163             break;
1164         case Register:
1165             unw_debug(" r%d: r(%lu),", i, state.regs[i].value);
1166             break;
1167         case Value:
1168             unw_debug(" r%d: v(%lu),", i, state.regs[i].value);
1169             break;
1170         }
1171     }
1172 
1173     unw_debug("\n");
1174 #endif
1175 
1176     /* update frame */
1177     if (frame->call_frame
1178         && !UNW_DEFAULT_RA(state.regs[retAddrReg], state.dataAlign))
1179         frame->call_frame = 0;
1180     cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs;
1181     startLoc = min_t(unsigned long, UNW_SP(frame), cfa);
1182     endLoc = max_t(unsigned long, UNW_SP(frame), cfa);
1183     if (STACK_LIMIT(startLoc) != STACK_LIMIT(endLoc)) {
1184         startLoc = min(STACK_LIMIT(cfa), cfa);
1185         endLoc = max(STACK_LIMIT(cfa), cfa);
1186     }
1187 
1188     unw_debug("\nCFA reg: 0x%lx, offset: 0x%lx =>  0x%lx\n",
1189           state.cfa.reg, state.cfa.offs, cfa);
1190 
1191     for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
1192         if (REG_INVALID(i)) {
1193             if (state.regs[i].where == Nowhere)
1194                 continue;
1195             return -EIO;
1196         }
1197         switch (state.regs[i].where) {
1198         default:
1199             break;
1200         case Register:
1201             if (state.regs[i].value >= ARRAY_SIZE(reg_info)
1202                 || REG_INVALID(state.regs[i].value)
1203                 || reg_info[i].width >
1204                 reg_info[state.regs[i].value].width)
1205                 return -EIO;
1206             switch (reg_info[state.regs[i].value].width) {
1207             case sizeof(u8):
1208                 state.regs[i].value =
1209                 FRAME_REG(state.regs[i].value, const u8);
1210                 break;
1211             case sizeof(u16):
1212                 state.regs[i].value =
1213                 FRAME_REG(state.regs[i].value, const u16);
1214                 break;
1215             case sizeof(u32):
1216                 state.regs[i].value =
1217                 FRAME_REG(state.regs[i].value, const u32);
1218                 break;
1219 #ifdef CONFIG_64BIT
1220             case sizeof(u64):
1221                 state.regs[i].value =
1222                 FRAME_REG(state.regs[i].value, const u64);
1223                 break;
1224 #endif
1225             default:
1226                 return -EIO;
1227             }
1228             break;
1229         }
1230     }
1231 
1232     unw_debug("\nRegister state after evaluation with realtime Stack:\n");
1233     fptr = (unsigned long *)(&frame->regs);
1234     for (i = 0; i < ARRAY_SIZE(state.regs); ++i, fptr++) {
1235 
1236         if (REG_INVALID(i))
1237             continue;
1238         switch (state.regs[i].where) {
1239         case Nowhere:
1240             if (reg_info[i].width != sizeof(UNW_SP(frame))
1241                 || &FRAME_REG(i, __typeof__(UNW_SP(frame)))
1242                 != &UNW_SP(frame))
1243                 continue;
1244             UNW_SP(frame) = cfa;
1245             break;
1246         case Register:
1247             switch (reg_info[i].width) {
1248             case sizeof(u8):
1249                 FRAME_REG(i, u8) = state.regs[i].value;
1250                 break;
1251             case sizeof(u16):
1252                 FRAME_REG(i, u16) = state.regs[i].value;
1253                 break;
1254             case sizeof(u32):
1255                 FRAME_REG(i, u32) = state.regs[i].value;
1256                 break;
1257 #ifdef CONFIG_64BIT
1258             case sizeof(u64):
1259                 FRAME_REG(i, u64) = state.regs[i].value;
1260                 break;
1261 #endif
1262             default:
1263                 return -EIO;
1264             }
1265             break;
1266         case Value:
1267             if (reg_info[i].width != sizeof(unsigned long))
1268                 return -EIO;
1269             FRAME_REG(i, unsigned long) = cfa + state.regs[i].value
1270                 * state.dataAlign;
1271             break;
1272         case Memory:
1273             addr = cfa + state.regs[i].value * state.dataAlign;
1274 
1275             if ((state.regs[i].value * state.dataAlign)
1276                 % sizeof(unsigned long)
1277                 || addr < startLoc
1278                 || addr + sizeof(unsigned long) < addr
1279                 || addr + sizeof(unsigned long) > endLoc)
1280                     return -EIO;
1281 
1282             switch (reg_info[i].width) {
1283             case sizeof(u8):
1284                 __get_user(FRAME_REG(i, u8),
1285                        (u8 __user *)addr);
1286                 break;
1287             case sizeof(u16):
1288                 __get_user(FRAME_REG(i, u16),
1289                        (u16 __user *)addr);
1290                 break;
1291             case sizeof(u32):
1292                 __get_user(FRAME_REG(i, u32),
1293                        (u32 __user *)addr);
1294                 break;
1295 #ifdef CONFIG_64BIT
1296             case sizeof(u64):
1297                 __get_user(FRAME_REG(i, u64),
1298                        (u64 __user *)addr);
1299                 break;
1300 #endif
1301             default:
1302                 return -EIO;
1303             }
1304 
1305             break;
1306         }
1307         unw_debug("r%d: 0x%lx ", i, *fptr);
1308     }
1309 
1310     return 0;
1311 #undef FRAME_REG
1312 }
1313 EXPORT_SYMBOL(arc_unwind);