Commit bff595c1 authored by Catalin Marinas's avatar Catalin Marinas Committed by Russell King

[ARM] 5383/2: unwind: Add core support for ARM stack unwinding

This patch adds the main functionality for parsing the stack unwinding
information generated by the ARM EABI toolchains. The unwinding
information consists of an index with a pair of words per function and a
table with unwinding instructions. For more information, see "Exception
Handling ABI for the ARM Architecture" at:

http://infocenter.arm.com/help/topic/com.arm.doc.subset.swdev.abi/index.htmlSigned-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 2d7c11bf
...@@ -11,6 +11,11 @@ OUTPUT_ARCH(arm) ...@@ -11,6 +11,11 @@ OUTPUT_ARCH(arm)
ENTRY(_start) ENTRY(_start)
SECTIONS SECTIONS
{ {
/DISCARD/ : {
*(.ARM.exidx*)
*(.ARM.extab*)
}
. = TEXT_START; . = TEXT_START;
_text = .; _text = .;
......
/*
* arch/arm/include/asm/unwind.h
*
* Copyright (C) 2008 ARM Limited
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __ASM_UNWIND_H
#define __ASM_UNWIND_H
#ifndef __ASSEMBLY__
/* Unwind reason code according the the ARM EABI documents */
enum unwind_reason_code {
URC_OK = 0, /* operation completed successfully */
URC_CONTINUE_UNWIND = 8,
URC_FAILURE = 9 /* unspecified failure of some kind */
};
struct unwind_idx {
unsigned long addr;
unsigned long insn;
};
struct unwind_table {
struct list_head list;
struct unwind_idx *start;
struct unwind_idx *stop;
unsigned long begin_addr;
unsigned long end_addr;
};
extern struct unwind_table *unwind_table_add(unsigned long start,
unsigned long size,
unsigned long text_addr,
unsigned long text_size);
extern void unwind_table_del(struct unwind_table *tab);
extern void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk);
#ifdef CONFIG_ARM_UNWIND
extern int __init unwind_init(void);
#else
static inline int __init unwind_init(void)
{
return 0;
}
#endif
#endif /* !__ASSEMBLY__ */
#ifdef CONFIG_ARM_UNWIND
#define UNWIND(code...) code
#else
#define UNWIND(code...)
#endif
#endif /* __ASM_UNWIND_H */
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <asm/mach/time.h> #include <asm/mach/time.h>
#include <asm/traps.h> #include <asm/traps.h>
#include <asm/unwind.h>
#include "compat.h" #include "compat.h"
#include "atags.h" #include "atags.h"
...@@ -684,6 +685,8 @@ void __init setup_arch(char **cmdline_p) ...@@ -684,6 +685,8 @@ void __init setup_arch(char **cmdline_p)
struct machine_desc *mdesc; struct machine_desc *mdesc;
char *from = default_command_line; char *from = default_command_line;
unwind_init();
setup_processor(); setup_processor();
mdesc = setup_machine(machine_arch_type); mdesc = setup_machine(machine_arch_type);
machine_name = mdesc->name; machine_name = mdesc->name;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <asm/system.h> #include <asm/system.h>
#include <asm/unistd.h> #include <asm/unistd.h>
#include <asm/traps.h> #include <asm/traps.h>
#include <asm/unwind.h>
#include "ptrace.h" #include "ptrace.h"
#include "signal.h" #include "signal.h"
...@@ -61,6 +62,7 @@ void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long ...@@ -61,6 +62,7 @@ void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long
dump_mem("Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs)); dump_mem("Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs));
} }
#ifndef CONFIG_ARM_UNWIND
/* /*
* Stack pointers should always be within the kernels view of * Stack pointers should always be within the kernels view of
* physical memory. If it is not there, then we can't dump * physical memory. If it is not there, then we can't dump
...@@ -74,6 +76,7 @@ static int verify_stack(unsigned long sp) ...@@ -74,6 +76,7 @@ static int verify_stack(unsigned long sp)
return 0; return 0;
} }
#endif
/* /*
* Dump out the contents of some memory nicely... * Dump out the contents of some memory nicely...
...@@ -150,6 +153,12 @@ static void dump_instr(struct pt_regs *regs) ...@@ -150,6 +153,12 @@ static void dump_instr(struct pt_regs *regs)
set_fs(fs); set_fs(fs);
} }
#ifdef CONFIG_ARM_UNWIND
static inline void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
{
unwind_backtrace(regs, tsk);
}
#else
static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
{ {
unsigned int fp, mode; unsigned int fp, mode;
...@@ -184,6 +193,7 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) ...@@ -184,6 +193,7 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
if (ok) if (ok)
c_backtrace(fp, mode); c_backtrace(fp, mode);
} }
#endif
void dump_stack(void) void dump_stack(void)
{ {
......
This diff is collapsed.
...@@ -80,6 +80,8 @@ SECTIONS ...@@ -80,6 +80,8 @@ SECTIONS
EXIT_TEXT EXIT_TEXT
EXIT_DATA EXIT_DATA
*(.exitcall.exit) *(.exitcall.exit)
*(.ARM.exidx.exit.text)
*(.ARM.extab.exit.text)
#ifndef CONFIG_MMU #ifndef CONFIG_MMU
*(.fixup) *(.fixup)
*(__ex_table) *(__ex_table)
...@@ -110,6 +112,23 @@ SECTIONS ...@@ -110,6 +112,23 @@ SECTIONS
_etext = .; /* End of text and rodata section */ _etext = .; /* End of text and rodata section */
#ifdef CONFIG_ARM_UNWIND
/*
* Stack unwinding tables
*/
. = ALIGN(8);
.ARM.unwind_idx : {
__start_unwind_idx = .;
*(.ARM.exidx*)
__stop_unwind_idx = .;
}
.ARM.unwind_tab : {
__start_unwind_tab = .;
*(.ARM.extab*)
__stop_unwind_tab = .;
}
#endif
#ifdef CONFIG_XIP_KERNEL #ifdef CONFIG_XIP_KERNEL
__data_loc = ALIGN(4); /* location in binary */ __data_loc = ALIGN(4); /* location in binary */
. = PAGE_OFFSET + TEXT_OFFSET; . = PAGE_OFFSET + TEXT_OFFSET;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment