^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0-only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * linux/arch/arm/lib/backtrace.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 1995, 1996 Russell King
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * 27/03/03 Ian Molton Clean up CONFIG_CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/kern_levels.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/linkage.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <asm/assembler.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) .text
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) @ fp is 0 or stack frame
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define frame r4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define sv_fp r5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define sv_pc r6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define mask r7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define offset r8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define loglvl r9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) ENTRY(c_backtrace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) ret lr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) ENDPROC(c_backtrace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) stmfd sp!, {r4 - r9, lr} @ Save an extra register so we have a location...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) movs frame, r0 @ if frame pointer is zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) beq no_frame @ we have no stack frames
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) mov loglvl, r2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) tst r1, #0x10 @ 26 or 32-bit mode?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) ARM( moveq mask, #0xfc000003 )
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) THUMB( moveq mask, #0xfc000000 )
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) THUMB( orreq mask, #0x03 )
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) movne mask, #0 @ mask for 32-bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) 1: stmfd sp!, {pc} @ calculate offset of PC stored
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) ldr r0, [sp], #4 @ by stmfd for this CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) adr r1, 1b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) sub offset, r0, r1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * Stack frame layout:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * optionally saved caller registers (r4 - r10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * saved fp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * saved sp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * saved lr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * frame => saved pc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * optionally saved arguments (r0 - r3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * saved sp => <next word>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * Functions start with the following code sequence:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * mov ip, sp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * stmfd sp!, {r0 - r3} (optional)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * corrected pc => stmfd sp!, {..., fp, ip, lr, pc}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) for_each_frame: tst frame, mask @ Check for address exceptions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) bne no_frame
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) 1001: ldr sv_pc, [frame, #0] @ get saved pc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) 1002: ldr sv_fp, [frame, #-12] @ get saved fp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) sub sv_pc, sv_pc, offset @ Correct PC for prefetching
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) bic sv_pc, sv_pc, mask @ mask PC/LR for the mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) 1003: ldr r2, [sv_pc, #-4] @ if stmfd sp!, {args} exists,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) ldr r3, .Ldsi+4 @ adjust saved 'pc' back one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) teq r3, r2, lsr #11 @ instruction
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) subne r0, sv_pc, #4 @ allow for mov
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) subeq r0, sv_pc, #8 @ allow for mov + stmia
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) ldr r1, [frame, #-4] @ get saved lr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) mov r2, frame
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) bic r1, r1, mask @ mask PC/LR for the mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) mov r3, loglvl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) bl dump_backtrace_entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) ldr r1, [sv_pc, #-4] @ if stmfd sp!, {args} exists,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) ldr r3, .Ldsi+4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) teq r3, r1, lsr #11
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) ldreq r0, [frame, #-8] @ get sp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) subeq r0, r0, #4 @ point at the last arg
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) mov r2, loglvl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) bleq dump_backtrace_stm @ dump saved registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) 1004: ldr r1, [sv_pc, #0] @ if stmfd sp!, {..., fp, ip, lr, pc}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) ldr r3, .Ldsi @ instruction exists,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) teq r3, r1, lsr #11
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) subeq r0, frame, #16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) mov r2, loglvl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) bleq dump_backtrace_stm @ dump saved registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) teq sv_fp, #0 @ zero saved fp means
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) beq no_frame @ no further frames
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) cmp sv_fp, frame @ next frame must be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) mov frame, sv_fp @ above the current frame
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) bhi for_each_frame
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 1006: adr r0, .Lbad
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) mov r1, loglvl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) mov r2, frame
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) bl printk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) no_frame: ldmfd sp!, {r4 - r9, pc}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) ENDPROC(c_backtrace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) .pushsection __ex_table,"a"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) .align 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) .long 1001b, 1006b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) .long 1002b, 1006b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) .long 1003b, 1006b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) .long 1004b, 1006b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) .popsection
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) .Lbad: .asciz "%sBacktrace aborted due to bad frame pointer <%p>\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) .align
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) .Ldsi: .word 0xe92dd800 >> 11 @ stmfd sp!, {... fp, ip, lr, pc}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) .word 0xe92d0000 >> 11 @ stmfd sp!, {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #endif