1d2912cb1SThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-only */ 21da177e4SLinus Torvalds/* 31da177e4SLinus Torvalds * linux/arch/arm/lib/backtrace.S 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 1995, 1996 Russell King 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * 27/03/03 Ian Molton Clean up CONFIG_CPU 81da177e4SLinus Torvalds */ 924c66dfdSRussell King#include <linux/kern_levels.h> 101da177e4SLinus Torvalds#include <linux/linkage.h> 111da177e4SLinus Torvalds#include <asm/assembler.h> 121da177e4SLinus Torvalds .text 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds@ fp is 0 or stack frame 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds#define frame r4 177ab3f8d5SRussell King#define sv_fp r5 187ab3f8d5SRussell King#define sv_pc r6 191da177e4SLinus Torvalds#define mask r7 201da177e4SLinus Torvalds#define offset r8 215489ab50SDmitry Safonov#define loglvl r9 221da177e4SLinus Torvalds 231da177e4SLinus TorvaldsENTRY(c_backtrace) 241da177e4SLinus Torvalds 253ee357f0SMalcolm Parsons#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK) 266ebbf2ceSRussell King ret lr 2793ed3970SCatalin MarinasENDPROC(c_backtrace) 281da177e4SLinus Torvalds#else 295489ab50SDmitry Safonov stmfd sp!, {r4 - r9, lr} @ Save an extra register so we have a location... 307ab3f8d5SRussell King movs frame, r0 @ if frame pointer is zero 317ab3f8d5SRussell King beq no_frame @ we have no stack frames 325489ab50SDmitry Safonov mov loglvl, r2 331da177e4SLinus Torvalds 347ab3f8d5SRussell King tst r1, #0x10 @ 26 or 32-bit mode? 358b592783SCatalin Marinas ARM( moveq mask, #0xfc000003 ) 368b592783SCatalin Marinas THUMB( moveq mask, #0xfc000000 ) 378b592783SCatalin Marinas THUMB( orreq mask, #0x03 ) 387ab3f8d5SRussell King movne mask, #0 @ mask for 32-bit 397ab3f8d5SRussell King 407ab3f8d5SRussell King1: stmfd sp!, {pc} @ calculate offset of PC stored 417ab3f8d5SRussell King ldr r0, [sp], #4 @ by stmfd for this CPU 427ab3f8d5SRussell King adr r1, 1b 431da177e4SLinus Torvalds sub offset, r0, r1 441da177e4SLinus Torvalds 457ab3f8d5SRussell King/* 467ab3f8d5SRussell King * Stack frame layout: 477ab3f8d5SRussell King * optionally saved caller registers (r4 - r10) 487ab3f8d5SRussell King * saved fp 497ab3f8d5SRussell King * saved sp 507ab3f8d5SRussell King * saved lr 517ab3f8d5SRussell King * frame => saved pc 527ab3f8d5SRussell King * optionally saved arguments (r0 - r3) 537ab3f8d5SRussell King * saved sp => <next word> 547ab3f8d5SRussell King * 557ab3f8d5SRussell King * Functions start with the following code sequence: 567ab3f8d5SRussell King * mov ip, sp 577ab3f8d5SRussell King * stmfd sp!, {r0 - r3} (optional) 587ab3f8d5SRussell King * corrected pc => stmfd sp!, {..., fp, ip, lr, pc} 597ab3f8d5SRussell King */ 607ab3f8d5SRussell Kingfor_each_frame: tst frame, mask @ Check for address exceptions 617ab3f8d5SRussell King bne no_frame 621da177e4SLinus Torvalds 637ab3f8d5SRussell King1001: ldr sv_pc, [frame, #0] @ get saved pc 647ab3f8d5SRussell King1002: ldr sv_fp, [frame, #-12] @ get saved fp 657ab3f8d5SRussell King 667ab3f8d5SRussell King sub sv_pc, sv_pc, offset @ Correct PC for prefetching 677ab3f8d5SRussell King bic sv_pc, sv_pc, mask @ mask PC/LR for the mode 687ab3f8d5SRussell King 697ab3f8d5SRussell King1003: ldr r2, [sv_pc, #-4] @ if stmfd sp!, {args} exists, 707ab3f8d5SRussell King ldr r3, .Ldsi+4 @ adjust saved 'pc' back one 7169389837SLvqiang Huang teq r3, r2, lsr #11 @ instruction 727ab3f8d5SRussell King subne r0, sv_pc, #4 @ allow for mov 737ab3f8d5SRussell King subeq r0, sv_pc, #8 @ allow for mov + stmia 747ab3f8d5SRussell King 757ab3f8d5SRussell King ldr r1, [frame, #-4] @ get saved lr 767ab3f8d5SRussell King mov r2, frame 777ab3f8d5SRussell King bic r1, r1, mask @ mask PC/LR for the mode 785489ab50SDmitry Safonov mov r3, loglvl 791da177e4SLinus Torvalds bl dump_backtrace_entry 801da177e4SLinus Torvalds 817ab3f8d5SRussell King ldr r1, [sv_pc, #-4] @ if stmfd sp!, {args} exists, 827ab3f8d5SRussell King ldr r3, .Ldsi+4 83ef41b5c9SRussell King teq r3, r1, lsr #11 847ab3f8d5SRussell King ldreq r0, [frame, #-8] @ get sp 857ab3f8d5SRussell King subeq r0, r0, #4 @ point at the last arg 865489ab50SDmitry Safonov mov r2, loglvl 8724c66dfdSRussell King bleq dump_backtrace_stm @ dump saved registers 881da177e4SLinus Torvalds 897ab3f8d5SRussell King1004: ldr r1, [sv_pc, #0] @ if stmfd sp!, {..., fp, ip, lr, pc} 907ab3f8d5SRussell King ldr r3, .Ldsi @ instruction exists, 91ef41b5c9SRussell King teq r3, r1, lsr #11 927ab3f8d5SRussell King subeq r0, frame, #16 935489ab50SDmitry Safonov mov r2, loglvl 9424c66dfdSRussell King bleq dump_backtrace_stm @ dump saved registers 951da177e4SLinus Torvalds 967ab3f8d5SRussell King teq sv_fp, #0 @ zero saved fp means 977ab3f8d5SRussell King beq no_frame @ no further frames 981da177e4SLinus Torvalds 997ab3f8d5SRussell King cmp sv_fp, frame @ next frame must be 1007ab3f8d5SRussell King mov frame, sv_fp @ above the current frame 101*d4664b6cSArd Biesheuvel#ifdef CONFIG_IRQSTACKS 102*d4664b6cSArd Biesheuvel @ 103*d4664b6cSArd Biesheuvel @ Kernel stacks may be discontiguous in memory. If the next 104*d4664b6cSArd Biesheuvel @ frame is below the previous frame, accept it as long as it 105*d4664b6cSArd Biesheuvel @ lives in kernel memory. 106*d4664b6cSArd Biesheuvel @ 107*d4664b6cSArd Biesheuvel cmpls sv_fp, #PAGE_OFFSET 108*d4664b6cSArd Biesheuvel#endif 1097ab3f8d5SRussell King bhi for_each_frame 1101da177e4SLinus Torvalds 1117ab3f8d5SRussell King1006: adr r0, .Lbad 1125489ab50SDmitry Safonov mov r1, loglvl 1135489ab50SDmitry Safonov mov r2, frame 11433701557SChris Down bl _printk 1155489ab50SDmitry Safonovno_frame: ldmfd sp!, {r4 - r9, pc} 11693ed3970SCatalin MarinasENDPROC(c_backtrace) 1171da177e4SLinus Torvalds 1184260415fSRussell King .pushsection __ex_table,"a" 1191da177e4SLinus Torvalds .align 3 1207ab3f8d5SRussell King .long 1001b, 1006b 1217ab3f8d5SRussell King .long 1002b, 1006b 1227ab3f8d5SRussell King .long 1003b, 1006b 1237ab3f8d5SRussell King .long 1004b, 1006b 1244260415fSRussell King .popsection 1251da177e4SLinus Torvalds 1265489ab50SDmitry Safonov.Lbad: .asciz "%sBacktrace aborted due to bad frame pointer <%p>\n" 1271da177e4SLinus Torvalds .align 128ef41b5c9SRussell King.Ldsi: .word 0xe92dd800 >> 11 @ stmfd sp!, {... fp, ip, lr, pc} 129ef41b5c9SRussell King .word 0xe92d0000 >> 11 @ stmfd sp!, {} 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds#endif 132