mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-18 00:24:58 +08:00
5489ab50c2
Currently, the log-level of show_stack() depends on a platform realization. It creates situations where the headers are printed with lower log level or higher than the stacktrace (depending on a platform or user). Furthermore, it forces the logic decision from user to an architecture side. In result, some users as sysrq/kdb/etc are doing tricks with temporary rising console_loglevel while printing their messages. And in result it not only may print unwanted messages from other CPUs, but also omit printing at all in the unlucky case where the printk() was deferred. Introducing log-level parameter and KERN_UNSUPPRESSED [1] seems an easier approach than introducing more printk buffers. Also, it will consolidate printings with headers. Add log level argument to c_backtrace() as a preparation for introducing show_stack_loglvl(). [1]: https://lore.kernel.org/lkml/20190528002412.1625-1-dima@arista.com/T/#u Signed-off-by: Dmitry Safonov <dima@arista.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Cc: Russell King <linux@armlinux.org.uk> Cc: Will Deacon <will@kernel.org> Link: http://lkml.kernel.org/r/20200418201944.482088-5-dima@arista.com Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
124 lines
3.1 KiB
ArmAsm
124 lines
3.1 KiB
ArmAsm
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* linux/arch/arm/lib/backtrace.S
|
|
*
|
|
* Copyright (C) 1995, 1996 Russell King
|
|
*
|
|
* 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
|
|
#define loglvl r9
|
|
|
|
ENTRY(c_backtrace)
|
|
|
|
#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
|
|
ret lr
|
|
ENDPROC(c_backtrace)
|
|
#else
|
|
stmfd sp!, {r4 - r9, 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
|
|
mov loglvl, r2
|
|
|
|
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 #11 @ 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
|
|
mov r3, loglvl
|
|
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
|
|
mov r2, loglvl
|
|
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
|
|
mov r2, loglvl
|
|
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, loglvl
|
|
mov r2, frame
|
|
bl printk
|
|
no_frame: ldmfd sp!, {r4 - r9, 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 "%sBacktrace 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
|