mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-09 07:23:14 +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
@ -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
|
||||
|
@ -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
|
||||
|
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_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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
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)
|
||||
|
||||
#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) }
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user