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