forked from Minki/linux
24c66dfd56
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>
122 lines
3.2 KiB
ArmAsm
122 lines
3.2 KiB
ArmAsm
/*
|
|
* linux/arch/arm/lib/backtrace.S
|
|
*
|
|
* Copyright (C) 1995, 1996 Russell King
|
|
*
|
|
* 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.
|
|
*
|
|
* 27/03/03 Ian Molton Clean up CONFIG_CPU
|
|
*
|
|
*/
|
|
#include <linux/kern_levels.h>
|
|
#include <linux/linkage.h>
|
|
#include <asm/assembler.h>
|
|
.text
|
|
|
|
@ fp is 0 or stack frame
|
|
|
|
#define frame r4
|
|
#define sv_fp r5
|
|
#define sv_pc r6
|
|
#define mask r7
|
|
#define offset r8
|
|
|
|
ENTRY(c_backtrace)
|
|
|
|
#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
|
|
ret lr
|
|
ENDPROC(c_backtrace)
|
|
#else
|
|
stmfd sp!, {r4 - r8, lr} @ Save an extra register so we have a location...
|
|
movs frame, r0 @ if frame pointer is zero
|
|
beq no_frame @ we have no stack frames
|
|
|
|
tst r1, #0x10 @ 26 or 32-bit mode?
|
|
ARM( moveq mask, #0xfc000003 )
|
|
THUMB( moveq mask, #0xfc000000 )
|
|
THUMB( orreq mask, #0x03 )
|
|
movne mask, #0 @ mask for 32-bit
|
|
|
|
1: stmfd sp!, {pc} @ calculate offset of PC stored
|
|
ldr r0, [sp], #4 @ by stmfd for this CPU
|
|
adr r1, 1b
|
|
sub offset, r0, r1
|
|
|
|
/*
|
|
* Stack frame layout:
|
|
* optionally saved caller registers (r4 - r10)
|
|
* saved fp
|
|
* saved sp
|
|
* saved lr
|
|
* frame => saved pc
|
|
* optionally saved arguments (r0 - r3)
|
|
* saved sp => <next word>
|
|
*
|
|
* Functions start with the following code sequence:
|
|
* mov ip, sp
|
|
* stmfd sp!, {r0 - r3} (optional)
|
|
* corrected pc => stmfd sp!, {..., fp, ip, lr, pc}
|
|
*/
|
|
for_each_frame: tst frame, mask @ Check for address exceptions
|
|
bne no_frame
|
|
|
|
1001: ldr sv_pc, [frame, #0] @ get saved pc
|
|
1002: ldr sv_fp, [frame, #-12] @ get saved fp
|
|
|
|
sub sv_pc, sv_pc, offset @ Correct PC for prefetching
|
|
bic sv_pc, sv_pc, mask @ mask PC/LR for the mode
|
|
|
|
1003: ldr r2, [sv_pc, #-4] @ if stmfd sp!, {args} exists,
|
|
ldr r3, .Ldsi+4 @ adjust saved 'pc' back one
|
|
teq r3, r2, lsr #10 @ instruction
|
|
subne r0, sv_pc, #4 @ allow for mov
|
|
subeq r0, sv_pc, #8 @ allow for mov + stmia
|
|
|
|
ldr r1, [frame, #-4] @ get saved lr
|
|
mov r2, frame
|
|
bic r1, r1, mask @ mask PC/LR for the mode
|
|
bl dump_backtrace_entry
|
|
|
|
ldr r1, [sv_pc, #-4] @ if stmfd sp!, {args} exists,
|
|
ldr r3, .Ldsi+4
|
|
teq r3, r1, lsr #11
|
|
ldreq r0, [frame, #-8] @ get sp
|
|
subeq r0, r0, #4 @ point at the last arg
|
|
bleq dump_backtrace_stm @ dump saved registers
|
|
|
|
1004: ldr r1, [sv_pc, #0] @ if stmfd sp!, {..., fp, ip, lr, pc}
|
|
ldr r3, .Ldsi @ instruction exists,
|
|
teq r3, r1, lsr #11
|
|
subeq r0, frame, #16
|
|
bleq dump_backtrace_stm @ dump saved registers
|
|
|
|
teq sv_fp, #0 @ zero saved fp means
|
|
beq no_frame @ no further frames
|
|
|
|
cmp sv_fp, frame @ next frame must be
|
|
mov frame, sv_fp @ above the current frame
|
|
bhi for_each_frame
|
|
|
|
1006: adr r0, .Lbad
|
|
mov r1, frame
|
|
bl printk
|
|
no_frame: ldmfd sp!, {r4 - r8, pc}
|
|
ENDPROC(c_backtrace)
|
|
|
|
.pushsection __ex_table,"a"
|
|
.align 3
|
|
.long 1001b, 1006b
|
|
.long 1002b, 1006b
|
|
.long 1003b, 1006b
|
|
.long 1004b, 1006b
|
|
.popsection
|
|
|
|
.Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n"
|
|
.align
|
|
.Ldsi: .word 0xe92dd800 >> 11 @ stmfd sp!, {... fp, ip, lr, pc}
|
|
.word 0xe92d0000 >> 11 @ stmfd sp!, {}
|
|
|
|
#endif
|