xref: /linux/arch/arm/lib/backtrace-clang.S (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
16dc5fd93SNathan Huckleberry/* SPDX-License-Identifier: GPL-2.0-only */
26dc5fd93SNathan Huckleberry/*
36dc5fd93SNathan Huckleberry *  linux/arch/arm/lib/backtrace-clang.S
46dc5fd93SNathan Huckleberry *
56dc5fd93SNathan Huckleberry *  Copyright (C) 2019 Nathan Huckleberry
66dc5fd93SNathan Huckleberry *
76dc5fd93SNathan Huckleberry */
86dc5fd93SNathan Huckleberry#include <linux/kern_levels.h>
96dc5fd93SNathan Huckleberry#include <linux/linkage.h>
106dc5fd93SNathan Huckleberry#include <asm/assembler.h>
116dc5fd93SNathan Huckleberry		.text
126dc5fd93SNathan Huckleberry
136dc5fd93SNathan Huckleberry/* fp is 0 or stack frame */
146dc5fd93SNathan Huckleberry
156dc5fd93SNathan Huckleberry#define frame	r4
166dc5fd93SNathan Huckleberry#define sv_fp	r5
176dc5fd93SNathan Huckleberry#define sv_pc	r6
186dc5fd93SNathan Huckleberry#define mask	r7
196dc5fd93SNathan Huckleberry#define sv_lr	r8
205489ab50SDmitry Safonov#define loglvl	r9
216dc5fd93SNathan Huckleberry
226dc5fd93SNathan HuckleberryENTRY(c_backtrace)
236dc5fd93SNathan Huckleberry
246dc5fd93SNathan Huckleberry#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
256dc5fd93SNathan Huckleberry		ret	lr
266dc5fd93SNathan HuckleberryENDPROC(c_backtrace)
276dc5fd93SNathan Huckleberry#else
286dc5fd93SNathan Huckleberry
296dc5fd93SNathan Huckleberry
306dc5fd93SNathan Huckleberry/*
316dc5fd93SNathan Huckleberry * Clang does not store pc or sp in function prologues so we don't know exactly
326dc5fd93SNathan Huckleberry * where the function starts.
336dc5fd93SNathan Huckleberry *
346dc5fd93SNathan Huckleberry * We can treat the current frame's lr as the saved pc and the preceding
356dc5fd93SNathan Huckleberry * frame's lr as the current frame's lr, but we can't trace the most recent
366dc5fd93SNathan Huckleberry * call.  Inserting a false stack frame allows us to reference the function
376dc5fd93SNathan Huckleberry * called last in the stacktrace.
386dc5fd93SNathan Huckleberry *
396dc5fd93SNathan Huckleberry * If the call instruction was a bl we can look at the callers branch
406dc5fd93SNathan Huckleberry * instruction to calculate the saved pc.  We can recover the pc in most cases,
416dc5fd93SNathan Huckleberry * but in cases such as calling function pointers we cannot. In this case,
426dc5fd93SNathan Huckleberry * default to using the lr. This will be some address in the function, but will
436dc5fd93SNathan Huckleberry * not be the function start.
446dc5fd93SNathan Huckleberry *
456dc5fd93SNathan Huckleberry * Unfortunately due to the stack frame layout we can't dump r0 - r3, but these
466dc5fd93SNathan Huckleberry * are less frequently saved.
476dc5fd93SNathan Huckleberry *
486dc5fd93SNathan Huckleberry * Stack frame layout:
496dc5fd93SNathan Huckleberry * 		<larger addresses>
506dc5fd93SNathan Huckleberry * 		saved lr
516dc5fd93SNathan Huckleberry * 	frame=> saved fp
526dc5fd93SNathan Huckleberry * 		optionally saved caller registers (r4 - r10)
536dc5fd93SNathan Huckleberry * 		optionally saved arguments (r0 - r3)
546dc5fd93SNathan Huckleberry * 		<top of stack frame>
556dc5fd93SNathan Huckleberry * 		<smaller addresses>
566dc5fd93SNathan Huckleberry *
576dc5fd93SNathan Huckleberry * Functions start with the following code sequence:
586dc5fd93SNathan Huckleberry * corrected pc =>  stmfd sp!, {..., fp, lr}
596dc5fd93SNathan Huckleberry *		add fp, sp, #x
606dc5fd93SNathan Huckleberry *		stmfd sp!, {r0 - r3} (optional)
616dc5fd93SNathan Huckleberry *
626dc5fd93SNathan Huckleberry *
636dc5fd93SNathan Huckleberry *
646dc5fd93SNathan Huckleberry *
656dc5fd93SNathan Huckleberry *
666dc5fd93SNathan Huckleberry *
676dc5fd93SNathan Huckleberry * The diagram below shows an example stack setup for dump_stack.
686dc5fd93SNathan Huckleberry *
696dc5fd93SNathan Huckleberry * The frame for c_backtrace has pointers to the code of dump_stack. This is
706dc5fd93SNathan Huckleberry * why the frame of c_backtrace is used to for the pc calculation of
716dc5fd93SNathan Huckleberry * dump_stack. This is why we must move back a frame to print dump_stack.
726dc5fd93SNathan Huckleberry *
736dc5fd93SNathan Huckleberry * The stored locals for dump_stack are in dump_stack's frame. This means that
746dc5fd93SNathan Huckleberry * to fully print dump_stack's frame we need both the frame for dump_stack (for
756dc5fd93SNathan Huckleberry * locals) and the frame that was called by dump_stack (for pc).
766dc5fd93SNathan Huckleberry *
776dc5fd93SNathan Huckleberry * To print locals we must know where the function start is. If we read the
786dc5fd93SNathan Huckleberry * function prologue opcodes we can determine which variables are stored in the
796dc5fd93SNathan Huckleberry * stack frame.
806dc5fd93SNathan Huckleberry *
816dc5fd93SNathan Huckleberry * To find the function start of dump_stack we can look at the stored LR of
826dc5fd93SNathan Huckleberry * show_stack. It points at the instruction directly after the bl dump_stack.
836dc5fd93SNathan Huckleberry * We can then read the offset from the bl opcode to determine where the branch
846dc5fd93SNathan Huckleberry * takes us.  The address calculated must be the start of dump_stack.
856dc5fd93SNathan Huckleberry *
866dc5fd93SNathan Huckleberry * c_backtrace frame           dump_stack:
876dc5fd93SNathan Huckleberry * {[LR]    }  ============|   ...
886dc5fd93SNathan Huckleberry * {[FP]    }  =======|    |   bl c_backtrace
896dc5fd93SNathan Huckleberry *                    |    |=> ...
906dc5fd93SNathan Huckleberry * {[R4-R10]}         |
916dc5fd93SNathan Huckleberry * {[R0-R3] }         |        show_stack:
926dc5fd93SNathan Huckleberry * dump_stack frame   |        ...
936dc5fd93SNathan Huckleberry * {[LR]    } =============|   bl dump_stack
946dc5fd93SNathan Huckleberry * {[FP]    } <=======|    |=> ...
956dc5fd93SNathan Huckleberry * {[R4-R10]}
966dc5fd93SNathan Huckleberry * {[R0-R3] }
976dc5fd93SNathan Huckleberry */
986dc5fd93SNathan Huckleberry
996dc5fd93SNathan Huckleberry		stmfd	sp!, {r4 - r9, fp, lr}	@ Save an extra register
1006dc5fd93SNathan Huckleberry						@ to ensure 8 byte alignment
1016dc5fd93SNathan Huckleberry		movs	frame, r0		@ if frame pointer is zero
1026dc5fd93SNathan Huckleberry		beq	no_frame		@ we have no stack frames
1035489ab50SDmitry Safonov		mov	loglvl, r2
1046dc5fd93SNathan Huckleberry		tst	r1, #0x10		@ 26 or 32-bit mode?
1056dc5fd93SNathan Huckleberry		moveq	mask, #0xfc000003
1066dc5fd93SNathan Huckleberry		movne	mask, #0		@ mask for 32-bit
1076dc5fd93SNathan Huckleberry
1086dc5fd93SNathan Huckleberry/*
1096dc5fd93SNathan Huckleberry * Switches the current frame to be the frame for dump_stack.
1106dc5fd93SNathan Huckleberry */
1116dc5fd93SNathan Huckleberry		add	frame, sp, #24		@ switch to false frame
1126dc5fd93SNathan Huckleberryfor_each_frame:	tst	frame, mask		@ Check for address exceptions
1136dc5fd93SNathan Huckleberry		bne	no_frame
1146dc5fd93SNathan Huckleberry
1156dc5fd93SNathan Huckleberry/*
1166dc5fd93SNathan Huckleberry * sv_fp is the stack frame with the locals for the current considered
1176dc5fd93SNathan Huckleberry * function.
1186dc5fd93SNathan Huckleberry *
1196dc5fd93SNathan Huckleberry * sv_pc is the saved lr frame the frame above. This is a pointer to a code
1206dc5fd93SNathan Huckleberry * address within the current considered function, but it is not the function
1216dc5fd93SNathan Huckleberry * start. This value gets updated to be the function start later if it is
1226dc5fd93SNathan Huckleberry * possible.
1236dc5fd93SNathan Huckleberry */
1246dc5fd93SNathan Huckleberry1001:		ldr	sv_pc, [frame, #4]	@ get saved 'pc'
1256dc5fd93SNathan Huckleberry1002:		ldr	sv_fp, [frame, #0]	@ get saved fp
1266dc5fd93SNathan Huckleberry
1276dc5fd93SNathan Huckleberry		teq	sv_fp, mask		@ make sure next frame exists
1286dc5fd93SNathan Huckleberry		beq	no_frame
1296dc5fd93SNathan Huckleberry
1306dc5fd93SNathan Huckleberry/*
1316dc5fd93SNathan Huckleberry * sv_lr is the lr from the function that called the current function. This is
1326dc5fd93SNathan Huckleberry * a pointer to a code address in the current function's caller.  sv_lr-4 is
1336dc5fd93SNathan Huckleberry * the instruction used to call the current function.
1346dc5fd93SNathan Huckleberry *
1356dc5fd93SNathan Huckleberry * This sv_lr can be used to calculate the function start if the function was
1366dc5fd93SNathan Huckleberry * called using a bl instruction. If the function start can be recovered sv_pc
1376dc5fd93SNathan Huckleberry * is overwritten with the function start.
1386dc5fd93SNathan Huckleberry *
1396dc5fd93SNathan Huckleberry * If the current function was called using a function pointer we cannot
1406dc5fd93SNathan Huckleberry * recover the function start and instead continue with sv_pc as an arbitrary
1416dc5fd93SNathan Huckleberry * value within the current function. If this is the case we cannot print
1426dc5fd93SNathan Huckleberry * registers for the current function, but the stacktrace is still printed
1436dc5fd93SNathan Huckleberry * properly.
1446dc5fd93SNathan Huckleberry */
1456dc5fd93SNathan Huckleberry1003:		ldr	sv_lr, [sv_fp, #4]	@ get saved lr from next frame
1466dc5fd93SNathan Huckleberry
147eae9523fSArd Biesheuvel1004:		ldr	r0, [sv_lr, #-4]	@ get call instruction
1486dc5fd93SNathan Huckleberry		ldr	r3, .Lopcode+4
1496dc5fd93SNathan Huckleberry		and	r2, r3, r0		@ is this a bl call
1506dc5fd93SNathan Huckleberry		teq	r2, r3
1516dc5fd93SNathan Huckleberry		bne	finished_setup		@ give up if it's not
1526dc5fd93SNathan Huckleberry		and	r0, #0xffffff		@ get call offset 24-bit int
1536dc5fd93SNathan Huckleberry		lsl	r0, r0, #8		@ sign extend offset
1546dc5fd93SNathan Huckleberry		asr	r0, r0, #8
1556dc5fd93SNathan Huckleberry		ldr	sv_pc, [sv_fp, #4]	@ get lr address
1566dc5fd93SNathan Huckleberry		add	sv_pc, sv_pc, #-4	@ get call instruction address
1576dc5fd93SNathan Huckleberry		add	sv_pc, sv_pc, #8	@ take care of prefetch
1586dc5fd93SNathan Huckleberry		add	sv_pc, sv_pc, r0, lsl #2@ find function start
1596dc5fd93SNathan Huckleberry
1606dc5fd93SNathan Huckleberryfinished_setup:
1616dc5fd93SNathan Huckleberry
1626dc5fd93SNathan Huckleberry		bic	sv_pc, sv_pc, mask	@ mask PC/LR for the mode
1636dc5fd93SNathan Huckleberry
1646dc5fd93SNathan Huckleberry/*
1656dc5fd93SNathan Huckleberry * Print the function (sv_pc) and where it was called from (sv_lr).
1666dc5fd93SNathan Huckleberry */
167eae9523fSArd Biesheuvel		mov	r0, sv_pc
1686dc5fd93SNathan Huckleberry
1696dc5fd93SNathan Huckleberry		mov	r1, sv_lr
1706dc5fd93SNathan Huckleberry		mov	r2, frame
1716dc5fd93SNathan Huckleberry		bic	r1, r1, mask		@ mask PC/LR for the mode
1725489ab50SDmitry Safonov		mov	r3, loglvl
1736dc5fd93SNathan Huckleberry		bl	dump_backtrace_entry
1746dc5fd93SNathan Huckleberry
1756dc5fd93SNathan Huckleberry/*
1766dc5fd93SNathan Huckleberry * Test if the function start is a stmfd instruction to determine which
1776dc5fd93SNathan Huckleberry * registers were stored in the function prologue.
1786dc5fd93SNathan Huckleberry *
1796dc5fd93SNathan Huckleberry * If we could not recover the sv_pc because we were called through a function
1806dc5fd93SNathan Huckleberry * pointer the comparison will fail and no registers will print. Unwinding will
1816dc5fd93SNathan Huckleberry * continue as if there had been no registers stored in this frame.
1826dc5fd93SNathan Huckleberry */
1836dc5fd93SNathan Huckleberry1005:		ldr	r1, [sv_pc, #0]		@ if stmfd sp!, {..., fp, lr}
1846dc5fd93SNathan Huckleberry		ldr	r3, .Lopcode		@ instruction exists,
1856dc5fd93SNathan Huckleberry		teq	r3, r1, lsr #11
1866dc5fd93SNathan Huckleberry		ldr	r0, [frame]		@ locals are stored in
1876dc5fd93SNathan Huckleberry						@ the preceding frame
1886dc5fd93SNathan Huckleberry		subeq	r0, r0, #4
1895489ab50SDmitry Safonov		mov	r2, loglvl
1906dc5fd93SNathan Huckleberry		bleq	dump_backtrace_stm	@ dump saved registers
1916dc5fd93SNathan Huckleberry
1926dc5fd93SNathan Huckleberry/*
1936dc5fd93SNathan Huckleberry * If we are out of frames or if the next frame is invalid.
1946dc5fd93SNathan Huckleberry */
1956dc5fd93SNathan Huckleberry		teq	sv_fp, #0		@ zero saved fp means
1966dc5fd93SNathan Huckleberry		beq	no_frame		@ no further frames
1976dc5fd93SNathan Huckleberry
1986dc5fd93SNathan Huckleberry		cmp	sv_fp, frame		@ next frame must be
1996dc5fd93SNathan Huckleberry		mov	frame, sv_fp		@ above the current frame
200*d4664b6cSArd Biesheuvel#ifdef CONFIG_IRQSTACKS
201*d4664b6cSArd Biesheuvel		@
202*d4664b6cSArd Biesheuvel		@ Kernel stacks may be discontiguous in memory. If the next
203*d4664b6cSArd Biesheuvel		@ frame is below the previous frame, accept it as long as it
204*d4664b6cSArd Biesheuvel		@ lives in kernel memory.
205*d4664b6cSArd Biesheuvel		@
206*d4664b6cSArd Biesheuvel		cmpls	sv_fp, #PAGE_OFFSET
207*d4664b6cSArd Biesheuvel#endif
2086dc5fd93SNathan Huckleberry		bhi	for_each_frame
2096dc5fd93SNathan Huckleberry
2106dc5fd93SNathan Huckleberry1006:		adr	r0, .Lbad
2115489ab50SDmitry Safonov		mov	r1, loglvl
2125489ab50SDmitry Safonov		mov	r2, frame
21333701557SChris Down		bl	_printk
2146dc5fd93SNathan Huckleberryno_frame:	ldmfd	sp!, {r4 - r9, fp, pc}
2156dc5fd93SNathan HuckleberryENDPROC(c_backtrace)
2166dc5fd93SNathan Huckleberry		.pushsection __ex_table,"a"
2176dc5fd93SNathan Huckleberry		.align	3
2186dc5fd93SNathan Huckleberry		.long	1001b, 1006b
2196dc5fd93SNathan Huckleberry		.long	1002b, 1006b
2206dc5fd93SNathan Huckleberry		.long	1003b, 1006b
221eae9523fSArd Biesheuvel		.long	1004b, finished_setup
2226dc5fd93SNathan Huckleberry		.long   1005b, 1006b
2236dc5fd93SNathan Huckleberry		.popsection
2246dc5fd93SNathan Huckleberry
2255489ab50SDmitry Safonov.Lbad:		.asciz	"%sBacktrace aborted due to bad frame pointer <%p>\n"
2266dc5fd93SNathan Huckleberry		.align
2276dc5fd93SNathan Huckleberry.Lopcode:	.word	0xe92d4800 >> 11	@ stmfd sp!, {... fp, lr}
2286dc5fd93SNathan Huckleberry		.word	0x0b000000		@ bl if these bits are set
2296dc5fd93SNathan Huckleberry
2306dc5fd93SNathan Huckleberry#endif
231