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>
This commit is contained in:
Vineet Gupta 2013-01-22 17:03:19 +05:30
parent 41195d236e
commit 854a0d9505
9 changed files with 1612 additions and 1 deletions

View File

@ -25,6 +25,7 @@ config ARC
select HAVE_ARCH_TRACEHOOK
select HAVE_GENERIC_HARDIRQS
select HAVE_MEMBLOCK
select HAVE_MOD_ARCH_SPECIFIC if ARC_DW2_UNWIND
select HAVE_OPROFILE
select IRQ_DOMAIN
select MODULES_USE_ELF_RELA
@ -344,6 +345,20 @@ menuconfig ARC_DBG
bool "ARC debugging"
default y
config ARC_DW2_UNWIND
bool "Enable DWARF specific kernel stack unwind"
depends on ARC_DBG
default y
select KALLSYMS
help
Compiles the kernel with DWARF unwind information and can be used
to get stack backtraces.
If you say Y here the resulting kernel image will be slightly larger
but not slower, and it will give very useful debugging information.
If you don't debug the kernel, you can say N, but we may not be able
to solve problems without frame unwind information
config ARC_DBG_TLB_PARANOIA
bool "Paranoia Checks in Low Level TLB Handlers"
depends on ARC_DBG && !SMP

View File

@ -14,6 +14,13 @@
#include <asm-generic/module.h>
#ifdef CONFIG_ARC_DW2_UNWIND
struct mod_arch_specific {
void *unw_info;
int unw_sec_idx;
};
#endif
#define MODULE_PROC_FAMILY "ARC700"
#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY

View File

@ -0,0 +1,163 @@
/*
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_ARC_UNWIND_H
#define _ASM_ARC_UNWIND_H
#ifdef CONFIG_ARC_DW2_UNWIND
#include <linux/sched.h>
struct arc700_regs {
unsigned long r0;
unsigned long r1;
unsigned long r2;
unsigned long r3;
unsigned long r4;
unsigned long r5;
unsigned long r6;
unsigned long r7;
unsigned long r8;
unsigned long r9;
unsigned long r10;
unsigned long r11;
unsigned long r12;
unsigned long r13;
unsigned long r14;
unsigned long r15;
unsigned long r16;
unsigned long r17;
unsigned long r18;
unsigned long r19;
unsigned long r20;
unsigned long r21;
unsigned long r22;
unsigned long r23;
unsigned long r24;
unsigned long r25;
unsigned long r26;
unsigned long r27; /* fp */
unsigned long r28; /* sp */
unsigned long r29;
unsigned long r30;
unsigned long r31; /* blink */
unsigned long r63; /* pc */
};
struct unwind_frame_info {
struct arc700_regs regs;
struct task_struct *task;
unsigned call_frame:1;
};
#define UNW_PC(frame) ((frame)->regs.r63)
#define UNW_SP(frame) ((frame)->regs.r28)
#define UNW_BLINK(frame) ((frame)->regs.r31)
/* Rajesh FIXME */
#ifdef CONFIG_FRAME_POINTER
#define UNW_FP(frame) ((frame)->regs.r27)
#define FRAME_RETADDR_OFFSET 4
#define FRAME_LINK_OFFSET 0
#define STACK_BOTTOM_UNW(tsk) STACK_LIMIT((tsk)->thread.ksp)
#define STACK_TOP_UNW(tsk) ((tsk)->thread.ksp)
#else
#define UNW_FP(frame) ((void)(frame), 0)
#endif
#define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1))
#define UNW_REGISTER_INFO \
PTREGS_INFO(r0), \
PTREGS_INFO(r1), \
PTREGS_INFO(r2), \
PTREGS_INFO(r3), \
PTREGS_INFO(r4), \
PTREGS_INFO(r5), \
PTREGS_INFO(r6), \
PTREGS_INFO(r7), \
PTREGS_INFO(r8), \
PTREGS_INFO(r9), \
PTREGS_INFO(r10), \
PTREGS_INFO(r11), \
PTREGS_INFO(r12), \
PTREGS_INFO(r13), \
PTREGS_INFO(r14), \
PTREGS_INFO(r15), \
PTREGS_INFO(r16), \
PTREGS_INFO(r17), \
PTREGS_INFO(r18), \
PTREGS_INFO(r19), \
PTREGS_INFO(r20), \
PTREGS_INFO(r21), \
PTREGS_INFO(r22), \
PTREGS_INFO(r23), \
PTREGS_INFO(r24), \
PTREGS_INFO(r25), \
PTREGS_INFO(r26), \
PTREGS_INFO(r27), \
PTREGS_INFO(r28), \
PTREGS_INFO(r29), \
PTREGS_INFO(r30), \
PTREGS_INFO(r31), \
PTREGS_INFO(r63)
#define UNW_DEFAULT_RA(raItem, dataAlign) \
((raItem).where == Memory && !((raItem).value * (dataAlign) + 4))
extern int arc_unwind(struct unwind_frame_info *frame);
extern void arc_unwind_init(void);
extern void arc_unwind_setup(void);
extern void *unwind_add_table(struct module *module, const void *table_start,
unsigned long table_size);
extern void unwind_remove_table(void *handle, int init_only);
static inline int
arch_unwind_init_running(struct unwind_frame_info *info,
int (*callback) (struct unwind_frame_info *info,
void *arg),
void *arg)
{
return 0;
}
static inline int arch_unw_user_mode(const struct unwind_frame_info *info)
{
return 0;
}
static inline void arch_unw_init_blocked(struct unwind_frame_info *info)
{
return;
}
static inline void arch_unw_init_frame_info(struct unwind_frame_info *info,
struct pt_regs *regs)
{
return;
}
#else
#define UNW_PC(frame) ((void)(frame), 0)
#define UNW_SP(frame) ((void)(frame), 0)
#define UNW_FP(frame) ((void)(frame), 0)
static inline void arc_unwind_init(void)
{
}
static inline void arc_unwind_setup(void)
{
}
#define unwind_add_table(a, b, c)
#define unwind_remove_table(a, b)
#endif /* CONFIG_ARC_DW2_UNWIND */
#endif /* _ASM_ARC_UNWIND_H */

View File

@ -14,10 +14,16 @@ obj-y += devtree.o
obj-$(CONFIG_MODULES) += arcksyms.o module.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_ARC_DW2_UNWIND) += unwind.o
obj-$(CONFIG_ARC_FPU_SAVE_RESTORE) += fpu.o
CFLAGS_fpu.o += -mdpfp
ifdef CONFIG_ARC_DW2_UNWIND
CFLAGS_ctx_sw.o += -fno-omit-frame-pointer
obj-y += ctx_sw.o
else
obj-y += ctx_sw_asm.o
endif
extra-y := vmlinux.lds head.o

View File

@ -815,3 +815,12 @@ ARC_ENTRY sys_clone_wrapper
b ret_from_system_call
ARC_EXIT sys_clone_wrapper
#ifdef CONFIG_ARC_DW2_UNWIND
; Workaround for bug 94179 (STAR ):
; Despite -fasynchronous-unwind-tables, linker is not making dwarf2 unwinder
; section (.debug_frame) as loadable. So we force it here.
; This also fixes STAR 9000487933 where the prev-workaround (objcopy --setflag)
; would not work after a clean build due to kernel build system dependencies.
.section .debug_frame, "wa",@progbits
#endif

View File

@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <asm/unwind.h>
static inline void arc_write_me(unsigned short *addr, unsigned long value)
{
@ -21,6 +22,42 @@ static inline void arc_write_me(unsigned short *addr, unsigned long value)
*(addr + 1) = (value & 0xffff);
}
/* ARC specific section quirks - before relocation loop in generic loader
*
* For dwarf unwinding out of modules, this needs to
* 1. Ensure the .debug_frame is allocatable (ARC Linker bug: despite
* -fasynchronous-unwind-tables it doesn't).
* 2. Since we are iterating thru sec hdr tbl anyways, make a note of
* the exact section index, for later use.
*/
int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
char *secstr, struct module *mod)
{
#ifdef CONFIG_ARC_DW2_UNWIND
int i;
mod->arch.unw_sec_idx = 0;
mod->arch.unw_info = NULL;
for (i = 1; i < hdr->e_shnum; i++) {
if (strcmp(secstr+sechdrs[i].sh_name, ".debug_frame") == 0) {
sechdrs[i].sh_flags |= SHF_ALLOC;
mod->arch.unw_sec_idx = i;
break;
}
}
#endif
return 0;
}
void module_arch_cleanup(struct module *mod)
{
#ifdef CONFIG_ARC_DW2_UNWIND
if (mod->arch.unw_info)
unwind_remove_table(mod->arch.unw_info, 0);
#endif
}
int apply_relocate_add(Elf32_Shdr *sechdrs,
const char *strtab,
unsigned int symindex, /* sec index for sym tbl */
@ -85,3 +122,24 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
return -ENOEXEC;
}
/* Just before lift off: After sections have been relocated, we add the
* dwarf section to unwinder table pool
* This couldn't be done in module_frob_arch_sections() because
* relocations had not been applied by then
*/
int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
struct module *mod)
{
#ifdef CONFIG_ARC_DW2_UNWIND
void *unw;
int unwsec = mod->arch.unw_sec_idx;
if (unwsec) {
unw = unwind_add_table(mod, (void *)sechdrs[unwsec].sh_addr,
sechdrs[unwsec].sh_size);
mod->arch.unw_info = unw;
}
#endif
return 0;
}

View File

@ -23,6 +23,7 @@
#include <asm/irq.h>
#include <asm/arcregs.h>
#include <asm/prom.h>
#include <asm/unwind.h>
#define FIX_PTR(x) __asm__ __volatile__(";" : "+r"(x))
@ -105,6 +106,8 @@ void __init setup_arch(char **cmdline_p)
conswitchp = &dummy_con;
#endif
arc_unwind_init();
arc_unwind_setup();
}
/*

1329
arch/arc/kernel/unwind.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -100,17 +100,38 @@ SECTIONS
BSS_SECTION(0, 0, 0)
#ifdef CONFIG_ARC_DW2_UNWIND
. = ALIGN(PAGE_SIZE);
.debug_frame : {
__start_unwind = .;
*(.debug_frame)
__end_unwind = .;
}
#else
/DISCARD/ : { *(.debug_frame) }
#endif
NOTES
. = ALIGN(PAGE_SIZE);
_end = . ;
STABS_DEBUG
DWARF_DEBUG
DISCARDS
.arcextmap 0 : {
*(.gnu.linkonce.arcextmap.*)
*(.arcextmap.*)
}
/* open-coded because we need .debug_frame seperately for unwinding */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
}