![Uwe Kleine-König](/assets/img/avatar_default.png)
The linker places the unwind tables in readonly sections. So when using an XIP kernel these are located in ROM and cannot be modified. For that reason the current approach to convert the relative offsets in the unwind index to absolute addresses early in the boot process doesn't work with XIP. The offsets in the unwind index section are signed 31 bit numbers and the structs are sorted by this offset. So it first has offsets between 0x40000000 and 0x7fffffff (i.e. the negative offsets) and then offsets between 0x00000000 and 0x3fffffff. When seperating these two blocks the numbers are sorted even when interpreting the offsets as unsigned longs. So determine the first non-negative entry once and track that using the new origin pointer. The actual bisection can then use a plain unsigned long comparison. The only thing that makes the new bisection more complicated is that the offsets are relative to their position in the index section, so the key to search needs to be adapted accordingly in each step. Moreover several consts are added to catch future writes and rename the member "addr" of struct unwind_idx to "addr_offset" to better match the new semantic. (This has the additional benefit of breaking eventual users at compile time to make them aware of the change.) In my tests the new algorithm was a tad faster than the original and has the additional upside of not needing the initial conversion and so saves some boot time and it's possible to unwind even earlier. Acked-by: Catalin Marinas <catalin.marinas@arm.com> Acked-by: Nicolas Pitre <nico@fluxnic.net> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
62 lines
1.7 KiB
C
62 lines
1.7 KiB
C
/*
|
|
* 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_offset;
|
|
unsigned long insn;
|
|
};
|
|
|
|
struct unwind_table {
|
|
struct list_head list;
|
|
const struct unwind_idx *start;
|
|
const struct unwind_idx *origin;
|
|
const 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);
|
|
|
|
#endif /* !__ASSEMBLY__ */
|
|
|
|
#ifdef CONFIG_ARM_UNWIND
|
|
#define UNWIND(code...) code
|
|
#else
|
|
#define UNWIND(code...)
|
|
#endif
|
|
|
|
#endif /* __ASM_UNWIND_H */
|