From 97f361e2498ada54b48a235619eaf5af8e46427e Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 17 Aug 2009 05:07:38 +0900 Subject: sh: unwinder: Move initialization to early_initcall() and tidy up locking. This moves the initialization over to an early_initcall(). This fixes up some lockdep interaction issues. At the same time, kill off some superfluous locking in the init path. Signed-off-by: Paul Mundt --- arch/sh/include/asm/dwarf.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'arch/sh/include/asm') diff --git a/arch/sh/include/asm/dwarf.h b/arch/sh/include/asm/dwarf.h index d3d3837c5e1..2fbe8720411 100644 --- a/arch/sh/include/asm/dwarf.h +++ b/arch/sh/include/asm/dwarf.h @@ -370,8 +370,6 @@ static inline unsigned int DW_CFA_operand(unsigned long insn) #define DW_EXT_HI 0xffffffff #define DW_EXT_DWARF64 DW_EXT_HI -extern void dwarf_unwinder_init(void); - extern struct dwarf_frame *dwarf_unwind_stack(unsigned long, struct dwarf_frame *); #endif /* __ASSEMBLY__ */ -- cgit v1.2.3 From fb3f3e7fc6d4afb32f9eba32124beaf40313de3c Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Sun, 16 Aug 2009 15:44:08 +0100 Subject: sh: unwinder: Fix memory leak and create our own kmem cache Plug a memory leak in dwarf_unwinder_dump() where we didn't free the memory that we had previously allocated for the DWARF frames and DWARF registers. Now is also a opportune time to implement our own mempool and kmem cache. It's a good idea to have a certain number of frame and register objects in reserve at all times, so that we are guaranteed to have our allocation satisfied even when memory is scarce. Since we have pools to allocate from we can implement the registers for each frame as a linked list as opposed to a sparsely populated array. Whilst it's true that the lookup time for a linked list is larger than for arrays, there's only usually a maximum of 8 registers per frame. So the overhead isn't that much of a concern. Signed-off-by: Matt Fleming --- arch/sh/include/asm/dwarf.h | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) (limited to 'arch/sh/include/asm') diff --git a/arch/sh/include/asm/dwarf.h b/arch/sh/include/asm/dwarf.h index 2fbe8720411..a22fbe98303 100644 --- a/arch/sh/include/asm/dwarf.h +++ b/arch/sh/include/asm/dwarf.h @@ -265,10 +265,7 @@ struct dwarf_frame { unsigned long pc; - struct dwarf_reg *regs; - unsigned int num_regs; /* how many regs are allocated? */ - - unsigned int depth; /* what level are we in the callstack? */ + struct list_head reg_list; unsigned long cfa; @@ -292,22 +289,15 @@ struct dwarf_frame { * @flags: Describes how to calculate the value of this register */ struct dwarf_reg { + struct list_head link; + + unsigned int number; + unsigned long addr; unsigned long flags; #define DWARF_REG_OFFSET (1 << 0) }; -/** - * dwarf_stack - a DWARF stack contains a collection of DWARF frames - * @depth: the number of frames in the stack - * @level: an array of DWARF frames, indexed by stack level - * - */ -struct dwarf_stack { - unsigned int depth; - struct dwarf_frame **level; -}; - /* * Call Frame instruction opcodes. */ @@ -372,7 +362,7 @@ static inline unsigned int DW_CFA_operand(unsigned long insn) extern struct dwarf_frame *dwarf_unwind_stack(unsigned long, struct dwarf_frame *); -#endif /* __ASSEMBLY__ */ +#endif /* !__ASSEMBLY__ */ #define CFI_STARTPROC .cfi_startproc #define CFI_ENDPROC .cfi_endproc -- cgit v1.2.3 From 97efbbd5886e27b61c19c77d41f6491f5d96fbd0 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Sun, 16 Aug 2009 15:56:35 +0100 Subject: sh: unwinder: Set the flags for DW_CFA_val_offset ops as DWARF_VAL_OFFSET The handling of DW_CFA_val_offset ops was incorrectly using the DWARF_REG_OFFSET flag but the register's value cannot be calculated using the DWARF_REG_OFFSET method. Create a new flag to indicate that a different method must be used to calculate the register's value even though there is no implementation for DWARF_VAL_OFFSET yet; it's mainly just a place holder. Signed-off-by: Matt Fleming --- arch/sh/include/asm/dwarf.h | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/sh/include/asm') diff --git a/arch/sh/include/asm/dwarf.h b/arch/sh/include/asm/dwarf.h index a22fbe98303..8b0bcc08738 100644 --- a/arch/sh/include/asm/dwarf.h +++ b/arch/sh/include/asm/dwarf.h @@ -296,6 +296,7 @@ struct dwarf_reg { unsigned long addr; unsigned long flags; #define DWARF_REG_OFFSET (1 << 0) +#define DWARF_VAL_OFFSET (1 << 1) }; /* -- cgit v1.2.3 From b344e24a8e8ceda83d1285d22e3e5baf4f5e42d3 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Sun, 16 Aug 2009 21:54:48 +0100 Subject: sh: unwinder: Introduce UNWINDER_BUG() and UNWINDER_BUG_ON() We can't assume that if we execute the unwinder code and the unwinder was already running that it has faulted. Clearly two kernel threads can invoke the unwinder at the same time and may be running simultaneously. The previous approach used BUG() and BUG_ON() in the unwinder code to detect whether the unwinder was incapable of unwinding the stack, and that the next available unwinder should be used instead. A better approach is to explicitly invoke a trap handler to switch unwinders when the current unwinder cannot continue. Signed-off-by: Matt Fleming --- arch/sh/include/asm/bug.h | 25 +++++++++++++++++++++++++ arch/sh/include/asm/system.h | 5 +++++ arch/sh/include/asm/unwinder.h | 6 ++++++ 3 files changed, 36 insertions(+) (limited to 'arch/sh/include/asm') diff --git a/arch/sh/include/asm/bug.h b/arch/sh/include/asm/bug.h index c0171804016..b7d9822fd6c 100644 --- a/arch/sh/include/asm/bug.h +++ b/arch/sh/include/asm/bug.h @@ -1,6 +1,7 @@ #ifndef __ASM_SH_BUG_H #define __ASM_SH_BUG_H +#define TRAPA_UNWINDER_BUG_OPCODE 0xc33b /* trapa #0x3b */ #define TRAPA_BUG_OPCODE 0xc33e /* trapa #0x3e */ #ifdef CONFIG_GENERIC_BUG @@ -72,6 +73,30 @@ do { \ unlikely(__ret_warn_on); \ }) +#define UNWINDER_BUG() \ +do { \ + __asm__ __volatile__ ( \ + "1:\t.short %O0\n" \ + _EMIT_BUG_ENTRY \ + : \ + : "n" (TRAPA_UNWINDER_BUG_OPCODE), \ + "i" (__FILE__), \ + "i" (__LINE__), "i" (0), \ + "i" (sizeof(struct bug_entry))); \ +} while (0) + +#define UNWINDER_BUG_ON(x) ({ \ + int __ret_unwinder_on = !!(x); \ + if (__builtin_constant_p(__ret_unwinder_on)) { \ + if (__ret_unwinder_on) \ + UNWINDER_BUG(); \ + } else { \ + if (unlikely(__ret_unwinder_on)) \ + UNWINDER_BUG(); \ + } \ + unlikely(__ret_unwinder_on); \ +}) + #endif /* CONFIG_GENERIC_BUG */ #include diff --git a/arch/sh/include/asm/system.h b/arch/sh/include/asm/system.h index ab79e1f4fbe..f9e2ceb94d9 100644 --- a/arch/sh/include/asm/system.h +++ b/arch/sh/include/asm/system.h @@ -181,6 +181,11 @@ BUILD_TRAP_HANDLER(breakpoint); BUILD_TRAP_HANDLER(singlestep); BUILD_TRAP_HANDLER(fpu_error); BUILD_TRAP_HANDLER(fpu_state_restore); +BUILD_TRAP_HANDLER(unwinder); + +#ifdef CONFIG_BUG +extern void handle_BUG(struct pt_regs *); +#endif #define arch_align_stack(x) (x) diff --git a/arch/sh/include/asm/unwinder.h b/arch/sh/include/asm/unwinder.h index 3dc551453e2..1e65c07b3e1 100644 --- a/arch/sh/include/asm/unwinder.h +++ b/arch/sh/include/asm/unwinder.h @@ -22,4 +22,10 @@ extern void stack_reader_dump(struct task_struct *, struct pt_regs *, unsigned long *, const struct stacktrace_ops *, void *); +/* + * Used by fault handling code to signal to the unwinder code that it + * should switch to a different unwinder. + */ +extern int unwinder_faulted; + #endif /* _LINUX_UNWINDER_H */ -- cgit v1.2.3 From 5580e9044df9c0e87861739d8c527006ead92e52 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Thu, 20 Aug 2009 19:53:49 +0100 Subject: sh: Handle the DWARF op, DW_CFA_undefined Allow a DWARF register to have an undefined value. When applied to the DWARF return address register this lets lets us label a function as having no direct caller, e.g. kernel_thread_helper(). Signed-off-by: Matt Fleming --- arch/sh/include/asm/dwarf.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/sh/include/asm') diff --git a/arch/sh/include/asm/dwarf.h b/arch/sh/include/asm/dwarf.h index 8b0bcc08738..c367ed3373c 100644 --- a/arch/sh/include/asm/dwarf.h +++ b/arch/sh/include/asm/dwarf.h @@ -297,6 +297,7 @@ struct dwarf_reg { unsigned long flags; #define DWARF_REG_OFFSET (1 << 0) #define DWARF_VAL_OFFSET (1 << 1) +#define DWARF_UNDEFINED (1 << 2) }; /* @@ -370,6 +371,7 @@ extern struct dwarf_frame *dwarf_unwind_stack(unsigned long, #define CFI_DEF_CFA .cfi_def_cfa #define CFI_REGISTER .cfi_register #define CFI_REL_OFFSET .cfi_rel_offset +#define CFI_UNDEFINED .cfi_undefined #else @@ -383,6 +385,7 @@ extern struct dwarf_frame *dwarf_unwind_stack(unsigned long, #define CFI_DEF_CFA CFI_IGNORE #define CFI_REGISTER CFI_IGNORE #define CFI_REL_OFFSET CFI_IGNORE +#define CFI_UNDEFINED CFI_IGNORE #ifndef __ASSEMBLY__ static inline void dwarf_unwinder_init(void) -- cgit v1.2.3 From e115f2c17cbceee93b34d787a7a4a867fc73e7b4 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 22 Aug 2009 05:28:25 +0900 Subject: sh: unwinder: Use a special bug flag for unwinder traps. This simplifies the unwinder trap handling, dropping the use of the special trapa vector and simply piggybacking on top of the BUG support. A new BUGFLAG_UNWINDER is added for flagging the unwinder fault, before continuing on with regular BUG dispatch. Signed-off-by: Paul Mundt --- arch/sh/include/asm/bug.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'arch/sh/include/asm') diff --git a/arch/sh/include/asm/bug.h b/arch/sh/include/asm/bug.h index b7d9822fd6c..23c5504a3a0 100644 --- a/arch/sh/include/asm/bug.h +++ b/arch/sh/include/asm/bug.h @@ -1,8 +1,8 @@ #ifndef __ASM_SH_BUG_H #define __ASM_SH_BUG_H -#define TRAPA_UNWINDER_BUG_OPCODE 0xc33b /* trapa #0x3b */ #define TRAPA_BUG_OPCODE 0xc33e /* trapa #0x3e */ +#define BUGFLAG_UNWINDER (1 << 1) #ifdef CONFIG_GENERIC_BUG #define HAVE_ARCH_BUG @@ -73,15 +73,16 @@ do { \ unlikely(__ret_warn_on); \ }) -#define UNWINDER_BUG() \ +#define UNWINDER_BUG() \ do { \ __asm__ __volatile__ ( \ "1:\t.short %O0\n" \ - _EMIT_BUG_ENTRY \ + _EMIT_BUG_ENTRY \ : \ - : "n" (TRAPA_UNWINDER_BUG_OPCODE), \ + : "n" (TRAPA_BUG_OPCODE), \ "i" (__FILE__), \ - "i" (__LINE__), "i" (0), \ + "i" (__LINE__), \ + "i" (BUGFLAG_UNWINDER), \ "i" (sizeof(struct bug_entry))); \ } while (0) -- cgit v1.2.3 From 74db2479c1fecefd0a190f282f28f00565309807 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 22 Aug 2009 05:31:45 +0900 Subject: sh64: dummy unwinder BUG wrappers. sh64 does not yet support GENERIC_BUG, but still wants unwinder support. Alias UNWINDER_BUG and UNWINDER_BUG_ON to their BUG counterparts until the conversion to GENERIC_BUG is completed. Signed-off-by: Paul Mundt --- arch/sh/include/asm/bug.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'arch/sh/include/asm') diff --git a/arch/sh/include/asm/bug.h b/arch/sh/include/asm/bug.h index 23c5504a3a0..d02c01b3e6b 100644 --- a/arch/sh/include/asm/bug.h +++ b/arch/sh/include/asm/bug.h @@ -98,6 +98,11 @@ do { \ unlikely(__ret_unwinder_on); \ }) +#else + +#define UNWINDER_BUG BUG +#define UNWINDER_BUG_ON BUG_ON + #endif /* CONFIG_GENERIC_BUG */ #include -- cgit v1.2.3