aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2016-11-15 08:55:59 -0500
committerRussell King <rmk+kernel@armlinux.org.uk>2016-11-15 10:25:39 -0500
commit24c66dfd569c4744fc43aea638155ad2dc1499d8 (patch)
treeaafbb0d392b4384411c0027773890cbd7ec77cb8 /arch/arm
parent6127d124ee4eb9c39983813cc9803f3654ab7e16 (diff)
ARM: fix backtrace
Recent kernels have changed their behaviour to be more inconsistent when handling printk continuations. With todays kernels, the output looks sane on the console, but dmesg splits individual printk()s which do not have the KERN_CONT prefix into separate lines. Since the assembly code is not trivial to add the KERN_CONT, and we ideally want to avoid using KERN_CONT (as multiple printk()s can race between different threads), convert the assembly dumping the register values to C code, and have the C code build the output a line at a time before dumping to the console. This avoids the KERN_CONT issue, and also avoids situations where the output is intermixed with other console activity. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/kernel/traps.c20
-rw-r--r--arch/arm/lib/backtrace.S37
2 files changed, 23 insertions, 34 deletions
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index bc698383e822..9688ec0c6ef4 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -74,6 +74,26 @@ void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long
74 dump_mem("", "Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs)); 74 dump_mem("", "Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs));
75} 75}
76 76
77void dump_backtrace_stm(u32 *stack, u32 instruction)
78{
79 char str[80], *p;
80 unsigned int x;
81 int reg;
82
83 for (reg = 10, x = 0, p = str; reg >= 0; reg--) {
84 if (instruction & BIT(reg)) {
85 p += sprintf(p, " r%d:%08x", reg, *stack--);
86 if (++x == 6) {
87 x = 0;
88 p = str;
89 printk("%s\n", str);
90 }
91 }
92 }
93 if (p != str)
94 printk("%s\n", str);
95}
96
77#ifndef CONFIG_ARM_UNWIND 97#ifndef CONFIG_ARM_UNWIND
78/* 98/*
79 * Stack pointers should always be within the kernels view of 99 * Stack pointers should always be within the kernels view of
diff --git a/arch/arm/lib/backtrace.S b/arch/arm/lib/backtrace.S
index fab5a50503ae..7d7952e5a3b1 100644
--- a/arch/arm/lib/backtrace.S
+++ b/arch/arm/lib/backtrace.S
@@ -10,6 +10,7 @@
10 * 27/03/03 Ian Molton Clean up CONFIG_CPU 10 * 27/03/03 Ian Molton Clean up CONFIG_CPU
11 * 11 *
12 */ 12 */
13#include <linux/kern_levels.h>
13#include <linux/linkage.h> 14#include <linux/linkage.h>
14#include <asm/assembler.h> 15#include <asm/assembler.h>
15 .text 16 .text
@@ -83,13 +84,13 @@ for_each_frame: tst frame, mask @ Check for address exceptions
83 teq r3, r1, lsr #11 84 teq r3, r1, lsr #11
84 ldreq r0, [frame, #-8] @ get sp 85 ldreq r0, [frame, #-8] @ get sp
85 subeq r0, r0, #4 @ point at the last arg 86 subeq r0, r0, #4 @ point at the last arg
86 bleq .Ldumpstm @ dump saved registers 87 bleq dump_backtrace_stm @ dump saved registers
87 88
881004: ldr r1, [sv_pc, #0] @ if stmfd sp!, {..., fp, ip, lr, pc} 891004: ldr r1, [sv_pc, #0] @ if stmfd sp!, {..., fp, ip, lr, pc}
89 ldr r3, .Ldsi @ instruction exists, 90 ldr r3, .Ldsi @ instruction exists,
90 teq r3, r1, lsr #11 91 teq r3, r1, lsr #11
91 subeq r0, frame, #16 92 subeq r0, frame, #16
92 bleq .Ldumpstm @ dump saved registers 93 bleq dump_backtrace_stm @ dump saved registers
93 94
94 teq sv_fp, #0 @ zero saved fp means 95 teq sv_fp, #0 @ zero saved fp means
95 beq no_frame @ no further frames 96 beq no_frame @ no further frames
@@ -112,38 +113,6 @@ ENDPROC(c_backtrace)
112 .long 1004b, 1006b 113 .long 1004b, 1006b
113 .popsection 114 .popsection
114 115
115#define instr r4
116#define reg r5
117#define stack r6
118
119.Ldumpstm: stmfd sp!, {instr, reg, stack, r7, lr}
120 mov stack, r0
121 mov instr, r1
122 mov reg, #10
123 mov r7, #0
1241: mov r3, #1
125 ARM( tst instr, r3, lsl reg )
126 THUMB( lsl r3, reg )
127 THUMB( tst instr, r3 )
128 beq 2f
129 add r7, r7, #1
130 teq r7, #6
131 moveq r7, #0
132 adr r3, .Lcr
133 addne r3, r3, #1 @ skip newline
134 ldr r2, [stack], #-4
135 mov r1, reg
136 adr r0, .Lfp
137 bl printk
1382: subs reg, reg, #1
139 bpl 1b
140 teq r7, #0
141 adrne r0, .Lcr
142 blne printk
143 ldmfd sp!, {instr, reg, stack, r7, pc}
144
145.Lfp: .asciz " r%d:%08x%s"
146.Lcr: .asciz "\n"
147.Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n" 116.Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n"
148 .align 117 .align
149.Ldsi: .word 0xe92dd800 >> 11 @ stmfd sp!, {... fp, ip, lr, pc} 118.Ldsi: .word 0xe92dd800 >> 11 @ stmfd sp!, {... fp, ip, lr, pc}