aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel
diff options
context:
space:
mode:
authorMatt Fleming <matt@console-pimps.org>2009-08-16 16:54:48 -0400
committerMatt Fleming <matt@console-pimps.org>2009-08-21 08:02:44 -0400
commitb344e24a8e8ceda83d1285d22e3e5baf4f5e42d3 (patch)
tree4b9500264a797736b48b59c3f0977277ace53386 /arch/sh/kernel
parent97efbbd5886e27b61c19c77d41f6491f5d96fbd0 (diff)
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 <matt@console-pimps.org>
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r--arch/sh/kernel/debugtraps.S6
-rw-r--r--arch/sh/kernel/dwarf.c38
-rw-r--r--arch/sh/kernel/traps.c7
-rw-r--r--arch/sh/kernel/traps_32.c1
-rw-r--r--arch/sh/kernel/unwinder.c33
5 files changed, 59 insertions, 26 deletions
diff --git a/arch/sh/kernel/debugtraps.S b/arch/sh/kernel/debugtraps.S
index 591741383ee6..cb00e4a82d4d 100644
--- a/arch/sh/kernel/debugtraps.S
+++ b/arch/sh/kernel/debugtraps.S
@@ -21,6 +21,10 @@
21#define sh_bios_handler debug_trap_handler 21#define sh_bios_handler debug_trap_handler
22#endif 22#endif
23 23
24#if !defined(CONFIG_DWARF_UNWINDER)
25#define unwinder_trap_handler debug_trap_handler
26#endif
27
24 .data 28 .data
25 29
26ENTRY(debug_trap_table) 30ENTRY(debug_trap_table)
@@ -35,7 +39,7 @@ ENTRY(debug_trap_table)
35 .long debug_trap_handler /* 0x38 */ 39 .long debug_trap_handler /* 0x38 */
36 .long debug_trap_handler /* 0x39 */ 40 .long debug_trap_handler /* 0x39 */
37 .long debug_trap_handler /* 0x3a */ 41 .long debug_trap_handler /* 0x3a */
38 .long debug_trap_handler /* 0x3b */ 42 .long unwinder_trap_handler /* 0x3b */
39 .long breakpoint_trap_handler /* 0x3c */ 43 .long breakpoint_trap_handler /* 0x3c */
40 .long singlestep_trap_handler /* 0x3d */ 44 .long singlestep_trap_handler /* 0x3d */
41 .long bug_trap_handler /* 0x3e */ 45 .long bug_trap_handler /* 0x3e */
diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c
index d271d04adccd..606ece37eb42 100644
--- a/arch/sh/kernel/dwarf.c
+++ b/arch/sh/kernel/dwarf.c
@@ -69,7 +69,7 @@ static struct dwarf_reg *dwarf_frame_alloc_reg(struct dwarf_frame *frame,
69 * Let's just bomb hard here, we have no way to 69 * Let's just bomb hard here, we have no way to
70 * gracefully recover. 70 * gracefully recover.
71 */ 71 */
72 BUG(); 72 UNWINDER_BUG();
73 } 73 }
74 74
75 reg->number = reg_num; 75 reg->number = reg_num;
@@ -232,7 +232,7 @@ static int dwarf_read_encoded_value(char *addr, unsigned long *val,
232 break; 232 break;
233 default: 233 default:
234 pr_debug("encoding=0x%x\n", (encoding & 0x70)); 234 pr_debug("encoding=0x%x\n", (encoding & 0x70));
235 BUG(); 235 UNWINDER_BUG();
236 } 236 }
237 237
238 if ((encoding & 0x07) == 0x00) 238 if ((encoding & 0x07) == 0x00)
@@ -247,7 +247,7 @@ static int dwarf_read_encoded_value(char *addr, unsigned long *val,
247 break; 247 break;
248 default: 248 default:
249 pr_debug("encoding=0x%x\n", encoding); 249 pr_debug("encoding=0x%x\n", encoding);
250 BUG(); 250 UNWINDER_BUG();
251 } 251 }
252 252
253 return count; 253 return count;
@@ -519,6 +519,7 @@ static int dwarf_cfa_execute_insns(unsigned char *insn_start,
519 break; 519 break;
520 default: 520 default:
521 pr_debug("unhandled DWARF instruction 0x%x\n", insn); 521 pr_debug("unhandled DWARF instruction 0x%x\n", insn);
522 UNWINDER_BUG();
522 break; 523 break;
523 } 524 }
524 } 525 }
@@ -535,8 +536,8 @@ static int dwarf_cfa_execute_insns(unsigned char *insn_start,
535 * on the callstack. Each of the lower (older) stack frames are 536 * on the callstack. Each of the lower (older) stack frames are
536 * linked via the "prev" member. 537 * linked via the "prev" member.
537 */ 538 */
538struct dwarf_frame *dwarf_unwind_stack(unsigned long pc, 539struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
539 struct dwarf_frame *prev) 540 struct dwarf_frame *prev)
540{ 541{
541 struct dwarf_frame *frame; 542 struct dwarf_frame *frame;
542 struct dwarf_cie *cie; 543 struct dwarf_cie *cie;
@@ -558,7 +559,7 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc,
558 frame = mempool_alloc(dwarf_frame_pool, GFP_ATOMIC); 559 frame = mempool_alloc(dwarf_frame_pool, GFP_ATOMIC);
559 if (!frame) { 560 if (!frame) {
560 printk(KERN_ERR "Unable to allocate a dwarf frame\n"); 561 printk(KERN_ERR "Unable to allocate a dwarf frame\n");
561 BUG(); 562 UNWINDER_BUG();
562 } 563 }
563 564
564 INIT_LIST_HEAD(&frame->reg_list); 565 INIT_LIST_HEAD(&frame->reg_list);
@@ -605,7 +606,8 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc,
605 case DWARF_FRAME_CFA_REG_OFFSET: 606 case DWARF_FRAME_CFA_REG_OFFSET:
606 if (prev) { 607 if (prev) {
607 reg = dwarf_frame_reg(prev, frame->cfa_register); 608 reg = dwarf_frame_reg(prev, frame->cfa_register);
608 BUG_ON(!reg); 609 UNWINDER_BUG_ON(!reg);
610 UNWINDER_BUG_ON(reg->flags != DWARF_REG_OFFSET);
609 611
610 addr = prev->cfa + reg->addr; 612 addr = prev->cfa + reg->addr;
611 frame->cfa = __raw_readl(addr); 613 frame->cfa = __raw_readl(addr);
@@ -624,12 +626,13 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc,
624 frame->cfa += frame->cfa_offset; 626 frame->cfa += frame->cfa_offset;
625 break; 627 break;
626 default: 628 default:
627 BUG(); 629 UNWINDER_BUG();
628 } 630 }
629 631
630 /* If we haven't seen the return address reg, we're screwed. */ 632 /* If we haven't seen the return address reg, we're screwed. */
631 reg = dwarf_frame_reg(frame, DWARF_ARCH_RA_REG); 633 reg = dwarf_frame_reg(frame, DWARF_ARCH_RA_REG);
632 BUG_ON(!reg); 634 UNWINDER_BUG_ON(!reg);
635 UNWINDER_BUG_ON(reg->flags != DWARF_REG_OFFSET);
633 636
634 addr = frame->cfa + reg->addr; 637 addr = frame->cfa + reg->addr;
635 frame->return_addr = __raw_readl(addr); 638 frame->return_addr = __raw_readl(addr);
@@ -664,7 +667,7 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
664 cie->cie_pointer = (unsigned long)entry; 667 cie->cie_pointer = (unsigned long)entry;
665 668
666 cie->version = *(char *)p++; 669 cie->version = *(char *)p++;
667 BUG_ON(cie->version != 1); 670 UNWINDER_BUG_ON(cie->version != 1);
668 671
669 cie->augmentation = p; 672 cie->augmentation = p;
670 p += strlen(cie->augmentation) + 1; 673 p += strlen(cie->augmentation) + 1;
@@ -694,7 +697,7 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
694 count = dwarf_read_uleb128(p, &length); 697 count = dwarf_read_uleb128(p, &length);
695 p += count; 698 p += count;
696 699
697 BUG_ON((unsigned char *)p > end); 700 UNWINDER_BUG_ON((unsigned char *)p > end);
698 701
699 cie->initial_instructions = p + length; 702 cie->initial_instructions = p + length;
700 cie->augmentation++; 703 cie->augmentation++;
@@ -722,16 +725,16 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
722 * routine in the CIE 725 * routine in the CIE
723 * augmentation. 726 * augmentation.
724 */ 727 */
725 BUG(); 728 UNWINDER_BUG();
726 } else if (*cie->augmentation == 'S') { 729 } else if (*cie->augmentation == 'S') {
727 BUG(); 730 UNWINDER_BUG();
728 } else { 731 } else {
729 /* 732 /*
730 * Unknown augmentation. Assume 733 * Unknown augmentation. Assume
731 * 'z' augmentation. 734 * 'z' augmentation.
732 */ 735 */
733 p = cie->initial_instructions; 736 p = cie->initial_instructions;
734 BUG_ON(!p); 737 UNWINDER_BUG_ON(!p);
735 break; 738 break;
736 } 739 }
737 } 740 }
@@ -805,9 +808,11 @@ static int dwarf_parse_fde(void *entry, u32 entry_type,
805 return 0; 808 return 0;
806} 809}
807 810
808static void dwarf_unwinder_dump(struct task_struct *task, struct pt_regs *regs, 811static void dwarf_unwinder_dump(struct task_struct *task,
812 struct pt_regs *regs,
809 unsigned long *sp, 813 unsigned long *sp,
810 const struct stacktrace_ops *ops, void *data) 814 const struct stacktrace_ops *ops,
815 void *data)
811{ 816{
812 struct dwarf_frame *frame, *_frame; 817 struct dwarf_frame *frame, *_frame;
813 unsigned long return_addr; 818 unsigned long return_addr;
@@ -831,7 +836,6 @@ static void dwarf_unwinder_dump(struct task_struct *task, struct pt_regs *regs,
831 return_addr = frame->return_addr; 836 return_addr = frame->return_addr;
832 ops->address(data, return_addr, 1); 837 ops->address(data, return_addr, 1);
833 } 838 }
834
835} 839}
836 840
837static struct unwinder dwarf_unwinder = { 841static struct unwinder dwarf_unwinder = {
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index b3e0067db358..881b9a32b7de 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -8,7 +8,7 @@
8#include <asm/system.h> 8#include <asm/system.h>
9 9
10#ifdef CONFIG_BUG 10#ifdef CONFIG_BUG
11static void handle_BUG(struct pt_regs *regs) 11void handle_BUG(struct pt_regs *regs)
12{ 12{
13 enum bug_trap_type tt; 13 enum bug_trap_type tt;
14 tt = report_bug(regs->pc, regs); 14 tt = report_bug(regs->pc, regs);
@@ -29,7 +29,10 @@ int is_valid_bugaddr(unsigned long addr)
29 if (probe_kernel_address((insn_size_t *)addr, opcode)) 29 if (probe_kernel_address((insn_size_t *)addr, opcode))
30 return 0; 30 return 0;
31 31
32 return opcode == TRAPA_BUG_OPCODE; 32 if (opcode == TRAPA_BUG_OPCODE || opcode == TRAPA_UNWINDER_BUG_OPCODE)
33 return 1;
34
35 return 0;
33} 36}
34#endif 37#endif
35 38
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index 563426487c6b..05a04b6df844 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -136,6 +136,7 @@ static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
136 regs->pc = fixup->fixup; 136 regs->pc = fixup->fixup;
137 return; 137 return;
138 } 138 }
139
139 die(str, regs, err); 140 die(str, regs, err);
140 } 141 }
141} 142}
diff --git a/arch/sh/kernel/unwinder.c b/arch/sh/kernel/unwinder.c
index 2b30fa28b440..b9c122abe251 100644
--- a/arch/sh/kernel/unwinder.c
+++ b/arch/sh/kernel/unwinder.c
@@ -53,8 +53,6 @@ static struct list_head unwinder_list = {
53 53
54static DEFINE_SPINLOCK(unwinder_lock); 54static DEFINE_SPINLOCK(unwinder_lock);
55 55
56static atomic_t unwinder_running = ATOMIC_INIT(0);
57
58/** 56/**
59 * select_unwinder - Select the best registered stack unwinder. 57 * select_unwinder - Select the best registered stack unwinder.
60 * 58 *
@@ -122,6 +120,8 @@ int unwinder_register(struct unwinder *u)
122 return ret; 120 return ret;
123} 121}
124 122
123int unwinder_faulted = 0;
124
125/* 125/*
126 * Unwind the call stack and pass information to the stacktrace_ops 126 * Unwind the call stack and pass information to the stacktrace_ops
127 * functions. Also handle the case where we need to switch to a new 127 * functions. Also handle the case where we need to switch to a new
@@ -144,19 +144,40 @@ void unwind_stack(struct task_struct *task, struct pt_regs *regs,
144 * Hopefully this will give us a semi-reliable stacktrace so we 144 * Hopefully this will give us a semi-reliable stacktrace so we
145 * can diagnose why curr_unwinder->dump() faulted. 145 * can diagnose why curr_unwinder->dump() faulted.
146 */ 146 */
147 if (atomic_inc_return(&unwinder_running) != 1) { 147 if (unwinder_faulted) {
148 spin_lock_irqsave(&unwinder_lock, flags); 148 spin_lock_irqsave(&unwinder_lock, flags);
149 149
150 if (!list_is_singular(&unwinder_list)) { 150 /* Make sure no one beat us to changing the unwinder */
151 if (unwinder_faulted && !list_is_singular(&unwinder_list)) {
151 list_del(&curr_unwinder->list); 152 list_del(&curr_unwinder->list);
152 curr_unwinder = select_unwinder(); 153 curr_unwinder = select_unwinder();
154
155 unwinder_faulted = 0;
153 } 156 }
154 157
155 spin_unlock_irqrestore(&unwinder_lock, flags); 158 spin_unlock_irqrestore(&unwinder_lock, flags);
156 atomic_dec(&unwinder_running);
157 } 159 }
158 160
159 curr_unwinder->dump(task, regs, sp, ops, data); 161 curr_unwinder->dump(task, regs, sp, ops, data);
162}
163
164/*
165 * Trap handler for UWINDER_BUG() statements. We must switch to the
166 * unwinder with the next highest rating.
167 */
168BUILD_TRAP_HANDLER(unwinder)
169{
170 insn_size_t insn;
171 TRAP_HANDLER_DECL;
172
173 /* Rewind */
174 regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
175 insn = *(insn_size_t *)instruction_pointer(regs);
176
177 /* Switch unwinders when unwind_stack() is called */
178 unwinder_faulted = 1;
160 179
161 atomic_dec(&unwinder_running); 180#ifdef CONFIG_BUG
181 handle_BUG(regs);
182#endif
162} 183}