162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/arch/arm/lib/backtrace.S 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1995, 1996 Russell King 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * 27/03/03 Ian Molton Clean up CONFIG_CPU 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include <linux/kern_levels.h> 1062306a36Sopenharmony_ci#include <linux/linkage.h> 1162306a36Sopenharmony_ci#include <asm/assembler.h> 1262306a36Sopenharmony_ci .text 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci@ fp is 0 or stack frame 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define frame r4 1762306a36Sopenharmony_ci#define sv_fp r5 1862306a36Sopenharmony_ci#define sv_pc r6 1962306a36Sopenharmony_ci#define mask r7 2062306a36Sopenharmony_ci#define offset r8 2162306a36Sopenharmony_ci#define loglvl r9 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ciENTRY(c_backtrace) 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK) 2662306a36Sopenharmony_ci ret lr 2762306a36Sopenharmony_ciENDPROC(c_backtrace) 2862306a36Sopenharmony_ci#else 2962306a36Sopenharmony_ci stmfd sp!, {r4 - r9, lr} @ Save an extra register so we have a location... 3062306a36Sopenharmony_ci movs frame, r0 @ if frame pointer is zero 3162306a36Sopenharmony_ci beq no_frame @ we have no stack frames 3262306a36Sopenharmony_ci mov loglvl, r2 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci tst r1, #0x10 @ 26 or 32-bit mode? 3562306a36Sopenharmony_ci ARM( moveq mask, #0xfc000003 ) 3662306a36Sopenharmony_ci THUMB( moveq mask, #0xfc000000 ) 3762306a36Sopenharmony_ci THUMB( orreq mask, #0x03 ) 3862306a36Sopenharmony_ci movne mask, #0 @ mask for 32-bit 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci1: stmfd sp!, {pc} @ calculate offset of PC stored 4162306a36Sopenharmony_ci ldr r0, [sp], #4 @ by stmfd for this CPU 4262306a36Sopenharmony_ci adr r1, 1b 4362306a36Sopenharmony_ci sub offset, r0, r1 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* 4662306a36Sopenharmony_ci * Stack frame layout: 4762306a36Sopenharmony_ci * optionally saved caller registers (r4 - r10) 4862306a36Sopenharmony_ci * saved fp 4962306a36Sopenharmony_ci * saved sp 5062306a36Sopenharmony_ci * saved lr 5162306a36Sopenharmony_ci * frame => saved pc 5262306a36Sopenharmony_ci * optionally saved arguments (r0 - r3) 5362306a36Sopenharmony_ci * saved sp => <next word> 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci * Functions start with the following code sequence: 5662306a36Sopenharmony_ci * mov ip, sp 5762306a36Sopenharmony_ci * stmfd sp!, {r0 - r3} (optional) 5862306a36Sopenharmony_ci * corrected pc => stmfd sp!, {..., fp, ip, lr, pc} 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_cifor_each_frame: tst frame, mask @ Check for address exceptions 6162306a36Sopenharmony_ci bne no_frame 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci1001: ldr sv_pc, [frame, #0] @ get saved pc 6462306a36Sopenharmony_ci1002: ldr sv_fp, [frame, #-12] @ get saved fp 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci sub sv_pc, sv_pc, offset @ Correct PC for prefetching 6762306a36Sopenharmony_ci bic sv_pc, sv_pc, mask @ mask PC/LR for the mode 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci1003: ldr r2, [sv_pc, #-4] @ if stmfd sp!, {args} exists, 7062306a36Sopenharmony_ci ldr r3, .Ldsi+4 @ adjust saved 'pc' back one 7162306a36Sopenharmony_ci teq r3, r2, lsr #11 @ instruction 7262306a36Sopenharmony_ci subne r0, sv_pc, #4 @ allow for mov 7362306a36Sopenharmony_ci subeq r0, sv_pc, #8 @ allow for mov + stmia 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci ldr r1, [frame, #-4] @ get saved lr 7662306a36Sopenharmony_ci mov r2, frame 7762306a36Sopenharmony_ci bic r1, r1, mask @ mask PC/LR for the mode 7862306a36Sopenharmony_ci mov r3, loglvl 7962306a36Sopenharmony_ci bl dump_backtrace_entry 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci ldr r1, [sv_pc, #-4] @ if stmfd sp!, {args} exists, 8262306a36Sopenharmony_ci ldr r3, .Ldsi+4 8362306a36Sopenharmony_ci teq r3, r1, lsr #11 8462306a36Sopenharmony_ci ldreq r0, [frame, #-8] @ get sp 8562306a36Sopenharmony_ci subeq r0, r0, #4 @ point at the last arg 8662306a36Sopenharmony_ci mov r2, loglvl 8762306a36Sopenharmony_ci bleq dump_backtrace_stm @ dump saved registers 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci1004: ldr r1, [sv_pc, #0] @ if stmfd sp!, {..., fp, ip, lr, pc} 9062306a36Sopenharmony_ci ldr r3, .Ldsi @ instruction exists, 9162306a36Sopenharmony_ci teq r3, r1, lsr #11 9262306a36Sopenharmony_ci subeq r0, frame, #16 9362306a36Sopenharmony_ci mov r2, loglvl 9462306a36Sopenharmony_ci bleq dump_backtrace_stm @ dump saved registers 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci teq sv_fp, #0 @ zero saved fp means 9762306a36Sopenharmony_ci beq no_frame @ no further frames 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci cmp sv_fp, frame @ next frame must be 10062306a36Sopenharmony_ci mov frame, sv_fp @ above the current frame 10162306a36Sopenharmony_ci#ifdef CONFIG_IRQSTACKS 10262306a36Sopenharmony_ci @ 10362306a36Sopenharmony_ci @ Kernel stacks may be discontiguous in memory. If the next 10462306a36Sopenharmony_ci @ frame is below the previous frame, accept it as long as it 10562306a36Sopenharmony_ci @ lives in kernel memory. 10662306a36Sopenharmony_ci @ 10762306a36Sopenharmony_ci cmpls sv_fp, #PAGE_OFFSET 10862306a36Sopenharmony_ci#endif 10962306a36Sopenharmony_ci bhi for_each_frame 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci1006: adr r0, .Lbad 11262306a36Sopenharmony_ci mov r1, loglvl 11362306a36Sopenharmony_ci mov r2, frame 11462306a36Sopenharmony_ci bl _printk 11562306a36Sopenharmony_cino_frame: ldmfd sp!, {r4 - r9, pc} 11662306a36Sopenharmony_ciENDPROC(c_backtrace) 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci .pushsection __ex_table,"a" 11962306a36Sopenharmony_ci .align 3 12062306a36Sopenharmony_ci .long 1001b, 1006b 12162306a36Sopenharmony_ci .long 1002b, 1006b 12262306a36Sopenharmony_ci .long 1003b, 1006b 12362306a36Sopenharmony_ci .long 1004b, 1006b 12462306a36Sopenharmony_ci .popsection 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci.Lbad: .asciz "%sBacktrace aborted due to bad frame pointer <%p>\n" 12762306a36Sopenharmony_ci .align 12862306a36Sopenharmony_ci.Ldsi: .word 0xe92dd800 >> 11 @ stmfd sp!, {... fp, ip, lr, pc} 12962306a36Sopenharmony_ci .word 0xe92d0000 >> 11 @ stmfd sp!, {} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci#endif 132