Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARC: DWARF2 .debug_frame based stack unwinder

-Originally written by Rajeshwar Ranga
-Derived off of generic unwinder in 2.6.19 and adapted to ARC

Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Cc: Rajeshwar Ranga <rajeshwar.ranga@gmail.com>

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