mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-03 15:47:36 +00:00
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:
parent
41195d236e
commit
854a0d9505
9 changed files with 1612 additions and 1 deletions
|
@ -25,6 +25,7 @@ config ARC
|
||||||
select HAVE_ARCH_TRACEHOOK
|
select HAVE_ARCH_TRACEHOOK
|
||||||
select HAVE_GENERIC_HARDIRQS
|
select HAVE_GENERIC_HARDIRQS
|
||||||
select HAVE_MEMBLOCK
|
select HAVE_MEMBLOCK
|
||||||
|
select HAVE_MOD_ARCH_SPECIFIC if ARC_DW2_UNWIND
|
||||||
select HAVE_OPROFILE
|
select HAVE_OPROFILE
|
||||||
select IRQ_DOMAIN
|
select IRQ_DOMAIN
|
||||||
select MODULES_USE_ELF_RELA
|
select MODULES_USE_ELF_RELA
|
||||||
|
@ -344,6 +345,20 @@ menuconfig ARC_DBG
|
||||||
bool "ARC debugging"
|
bool "ARC debugging"
|
||||||
default y
|
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
|
config ARC_DBG_TLB_PARANOIA
|
||||||
bool "Paranoia Checks in Low Level TLB Handlers"
|
bool "Paranoia Checks in Low Level TLB Handlers"
|
||||||
depends on ARC_DBG && !SMP
|
depends on ARC_DBG && !SMP
|
||||||
|
|
|
@ -14,6 +14,13 @@
|
||||||
|
|
||||||
#include <asm-generic/module.h>
|
#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_PROC_FAMILY "ARC700"
|
||||||
|
|
||||||
#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY
|
#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY
|
||||||
|
|
163
arch/arc/include/asm/unwind.h
Normal file
163
arch/arc/include/asm/unwind.h
Normal 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 */
|
|
@ -14,10 +14,16 @@ obj-y += devtree.o
|
||||||
|
|
||||||
obj-$(CONFIG_MODULES) += arcksyms.o module.o
|
obj-$(CONFIG_MODULES) += arcksyms.o module.o
|
||||||
obj-$(CONFIG_SMP) += smp.o
|
obj-$(CONFIG_SMP) += smp.o
|
||||||
|
obj-$(CONFIG_ARC_DW2_UNWIND) += unwind.o
|
||||||
|
|
||||||
obj-$(CONFIG_ARC_FPU_SAVE_RESTORE) += fpu.o
|
obj-$(CONFIG_ARC_FPU_SAVE_RESTORE) += fpu.o
|
||||||
CFLAGS_fpu.o += -mdpfp
|
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
|
obj-y += ctx_sw_asm.o
|
||||||
|
endif
|
||||||
|
|
||||||
extra-y := vmlinux.lds head.o
|
extra-y := vmlinux.lds head.o
|
||||||
|
|
|
@ -815,3 +815,12 @@ ARC_ENTRY sys_clone_wrapper
|
||||||
|
|
||||||
b ret_from_system_call
|
b ret_from_system_call
|
||||||
ARC_EXIT sys_clone_wrapper
|
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
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
|
#include <asm/unwind.h>
|
||||||
|
|
||||||
static inline void arc_write_me(unsigned short *addr, unsigned long value)
|
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);
|
*(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,
|
int apply_relocate_add(Elf32_Shdr *sechdrs,
|
||||||
const char *strtab,
|
const char *strtab,
|
||||||
unsigned int symindex, /* sec index for sym tbl */
|
unsigned int symindex, /* sec index for sym tbl */
|
||||||
|
@ -85,3 +122,24 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
|
||||||
return -ENOEXEC;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
#include <asm/arcregs.h>
|
#include <asm/arcregs.h>
|
||||||
#include <asm/prom.h>
|
#include <asm/prom.h>
|
||||||
|
#include <asm/unwind.h>
|
||||||
|
|
||||||
#define FIX_PTR(x) __asm__ __volatile__(";" : "+r"(x))
|
#define FIX_PTR(x) __asm__ __volatile__(";" : "+r"(x))
|
||||||
|
|
||||||
|
@ -105,6 +106,8 @@ void __init setup_arch(char **cmdline_p)
|
||||||
conswitchp = &dummy_con;
|
conswitchp = &dummy_con;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
arc_unwind_init();
|
||||||
|
arc_unwind_setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
1329
arch/arc/kernel/unwind.c
Normal file
1329
arch/arc/kernel/unwind.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -100,17 +100,38 @@ SECTIONS
|
||||||
|
|
||||||
BSS_SECTION(0, 0, 0)
|
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
|
NOTES
|
||||||
|
|
||||||
. = ALIGN(PAGE_SIZE);
|
. = ALIGN(PAGE_SIZE);
|
||||||
_end = . ;
|
_end = . ;
|
||||||
|
|
||||||
STABS_DEBUG
|
STABS_DEBUG
|
||||||
DWARF_DEBUG
|
|
||||||
DISCARDS
|
DISCARDS
|
||||||
|
|
||||||
.arcextmap 0 : {
|
.arcextmap 0 : {
|
||||||
*(.gnu.linkonce.arcextmap.*)
|
*(.gnu.linkonce.arcextmap.*)
|
||||||
*(.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) }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue