11da177e4SLinus Torvalds/* 21da177e4SLinus Torvalds * linux/arch/arm/lib/backtrace.S 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1995, 1996 Russell King 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 71da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2 as 81da177e4SLinus Torvalds * published by the Free Software Foundation. 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * 27/03/03 Ian Molton Clean up CONFIG_CPU 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds */ 1324c66dfdSRussell King#include <linux/kern_levels.h> 141da177e4SLinus Torvalds#include <linux/linkage.h> 151da177e4SLinus Torvalds#include <asm/assembler.h> 161da177e4SLinus Torvalds .text 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds@ fp is 0 or stack frame 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds#define frame r4 217ab3f8d5SRussell King#define sv_fp r5 227ab3f8d5SRussell King#define sv_pc r6 231da177e4SLinus Torvalds#define mask r7 241da177e4SLinus Torvalds#define offset r8 251da177e4SLinus Torvalds 261da177e4SLinus TorvaldsENTRY(c_backtrace) 271da177e4SLinus Torvalds 283ee357f0SMalcolm Parsons#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK) 296ebbf2ceSRussell King ret lr 3093ed3970SCatalin MarinasENDPROC(c_backtrace) 311da177e4SLinus Torvalds#else 321da177e4SLinus Torvalds stmfd sp!, {r4 - r8, lr} @ Save an extra register so we have a location... 337ab3f8d5SRussell King movs frame, r0 @ if frame pointer is zero 347ab3f8d5SRussell King beq no_frame @ we have no stack frames 351da177e4SLinus Torvalds 367ab3f8d5SRussell King tst r1, #0x10 @ 26 or 32-bit mode? 378b592783SCatalin Marinas ARM( moveq mask, #0xfc000003 ) 388b592783SCatalin Marinas THUMB( moveq mask, #0xfc000000 ) 398b592783SCatalin Marinas THUMB( orreq mask, #0x03 ) 407ab3f8d5SRussell King movne mask, #0 @ mask for 32-bit 417ab3f8d5SRussell King 427ab3f8d5SRussell King1: stmfd sp!, {pc} @ calculate offset of PC stored 437ab3f8d5SRussell King ldr r0, [sp], #4 @ by stmfd for this CPU 447ab3f8d5SRussell King adr r1, 1b 451da177e4SLinus Torvalds sub offset, r0, r1 461da177e4SLinus Torvalds 477ab3f8d5SRussell King/* 487ab3f8d5SRussell King * Stack frame layout: 497ab3f8d5SRussell King * optionally saved caller registers (r4 - r10) 507ab3f8d5SRussell King * saved fp 517ab3f8d5SRussell King * saved sp 527ab3f8d5SRussell King * saved lr 537ab3f8d5SRussell King * frame => saved pc 547ab3f8d5SRussell King * optionally saved arguments (r0 - r3) 557ab3f8d5SRussell King * saved sp => <next word> 567ab3f8d5SRussell King * 577ab3f8d5SRussell King * Functions start with the following code sequence: 587ab3f8d5SRussell King * mov ip, sp 597ab3f8d5SRussell King * stmfd sp!, {r0 - r3} (optional) 607ab3f8d5SRussell King * corrected pc => stmfd sp!, {..., fp, ip, lr, pc} 617ab3f8d5SRussell King */ 627ab3f8d5SRussell Kingfor_each_frame: tst frame, mask @ Check for address exceptions 637ab3f8d5SRussell King bne no_frame 641da177e4SLinus Torvalds 657ab3f8d5SRussell King1001: ldr sv_pc, [frame, #0] @ get saved pc 667ab3f8d5SRussell King1002: ldr sv_fp, [frame, #-12] @ get saved fp 677ab3f8d5SRussell King 687ab3f8d5SRussell King sub sv_pc, sv_pc, offset @ Correct PC for prefetching 697ab3f8d5SRussell King bic sv_pc, sv_pc, mask @ mask PC/LR for the mode 707ab3f8d5SRussell King 717ab3f8d5SRussell King1003: ldr r2, [sv_pc, #-4] @ if stmfd sp!, {args} exists, 727ab3f8d5SRussell King ldr r3, .Ldsi+4 @ adjust saved 'pc' back one 737ab3f8d5SRussell King teq r3, r2, lsr #10 @ instruction 747ab3f8d5SRussell King subne r0, sv_pc, #4 @ allow for mov 757ab3f8d5SRussell King subeq r0, sv_pc, #8 @ allow for mov + stmia 767ab3f8d5SRussell King 777ab3f8d5SRussell King ldr r1, [frame, #-4] @ get saved lr 787ab3f8d5SRussell King mov r2, frame 797ab3f8d5SRussell King bic r1, r1, mask @ mask PC/LR for the mode 801da177e4SLinus Torvalds bl dump_backtrace_entry 811da177e4SLinus Torvalds 827ab3f8d5SRussell King ldr r1, [sv_pc, #-4] @ if stmfd sp!, {args} exists, 837ab3f8d5SRussell King ldr r3, .Ldsi+4 84ef41b5c9SRussell King teq r3, r1, lsr #11 857ab3f8d5SRussell King ldreq r0, [frame, #-8] @ get sp 867ab3f8d5SRussell King subeq r0, r0, #4 @ point at the last arg 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 9324c66dfdSRussell King bleq dump_backtrace_stm @ dump saved registers 941da177e4SLinus Torvalds 957ab3f8d5SRussell King teq sv_fp, #0 @ zero saved fp means 967ab3f8d5SRussell King beq no_frame @ no further frames 971da177e4SLinus Torvalds 987ab3f8d5SRussell King cmp sv_fp, frame @ next frame must be 997ab3f8d5SRussell King mov frame, sv_fp @ above the current frame 1007ab3f8d5SRussell King bhi for_each_frame 1011da177e4SLinus Torvalds 1027ab3f8d5SRussell King1006: adr r0, .Lbad 1031da177e4SLinus Torvalds mov r1, frame 1041da177e4SLinus Torvalds bl printk 1057ab3f8d5SRussell Kingno_frame: ldmfd sp!, {r4 - r8, pc} 10693ed3970SCatalin MarinasENDPROC(c_backtrace) 1071da177e4SLinus Torvalds 1084260415fSRussell King .pushsection __ex_table,"a" 1091da177e4SLinus Torvalds .align 3 1107ab3f8d5SRussell King .long 1001b, 1006b 1117ab3f8d5SRussell King .long 1002b, 1006b 1127ab3f8d5SRussell King .long 1003b, 1006b 1137ab3f8d5SRussell King .long 1004b, 1006b 1144260415fSRussell King .popsection 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds.Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n" 1171da177e4SLinus Torvalds .align 118ef41b5c9SRussell King.Ldsi: .word 0xe92dd800 >> 11 @ stmfd sp!, {... fp, ip, lr, pc} 119ef41b5c9SRussell King .word 0xe92d0000 >> 11 @ stmfd sp!, {} 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds#endif 122