linux/arch/arm/lib/backtrace.S
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-only */
   2/*
   3 *  linux/arch/arm/lib/backtrace.S
   4 *
   5 *  Copyright (C) 1995, 1996 Russell King
   6 *
   7 * 27/03/03 Ian Molton Clean up CONFIG_CPU
   8 */
   9#include <linux/kern_levels.h>
  10#include <linux/linkage.h>
  11#include <asm/assembler.h>
  12                .text
  13
  14@ fp is 0 or stack frame
  15
  16#define frame   r4
  17#define sv_fp   r5
  18#define sv_pc   r6
  19#define mask    r7
  20#define offset  r8
  21#define loglvl  r9
  22
  23ENTRY(c_backtrace)
  24
  25#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
  26                ret     lr
  27ENDPROC(c_backtrace)
  28#else
  29                stmfd   sp!, {r4 - r9, lr}      @ Save an extra register so we have a location...
  30                movs    frame, r0               @ if frame pointer is zero
  31                beq     no_frame                @ we have no stack frames
  32                mov     loglvl, r2
  33
  34                tst     r1, #0x10               @ 26 or 32-bit mode?
  35 ARM(           moveq   mask, #0xfc000003       )
  36 THUMB(         moveq   mask, #0xfc000000       )
  37 THUMB(         orreq   mask, #0x03             )
  38                movne   mask, #0                @ mask for 32-bit
  39
  401:              stmfd   sp!, {pc}               @ calculate offset of PC stored
  41                ldr     r0, [sp], #4            @ by stmfd for this CPU
  42                adr     r1, 1b
  43                sub     offset, r0, r1
  44
  45/*
  46 * Stack frame layout:
  47 *             optionally saved caller registers (r4 - r10)
  48 *             saved fp
  49 *             saved sp
  50 *             saved lr
  51 *    frame => saved pc
  52 *             optionally saved arguments (r0 - r3)
  53 * saved sp => <next word>
  54 *
  55 * Functions start with the following code sequence:
  56 *                  mov   ip, sp
  57 *                  stmfd sp!, {r0 - r3} (optional)
  58 * corrected pc =>  stmfd sp!, {..., fp, ip, lr, pc}
  59 */
  60for_each_frame: tst     frame, mask             @ Check for address exceptions
  61                bne     no_frame
  62
  631001:           ldr     sv_pc, [frame, #0]      @ get saved pc
  641002:           ldr     sv_fp, [frame, #-12]    @ get saved fp
  65
  66                sub     sv_pc, sv_pc, offset    @ Correct PC for prefetching
  67                bic     sv_pc, sv_pc, mask      @ mask PC/LR for the mode
  68
  691003:           ldr     r2, [sv_pc, #-4]        @ if stmfd sp!, {args} exists,
  70                ldr     r3, .Ldsi+4             @ adjust saved 'pc' back one
  71                teq     r3, r2, lsr #11         @ instruction
  72                subne   r0, sv_pc, #4           @ allow for mov
  73                subeq   r0, sv_pc, #8           @ allow for mov + stmia
  74
  75                ldr     r1, [frame, #-4]        @ get saved lr
  76                mov     r2, frame
  77                bic     r1, r1, mask            @ mask PC/LR for the mode
  78                mov     r3, loglvl
  79                bl      dump_backtrace_entry
  80
  81                ldr     r1, [sv_pc, #-4]        @ if stmfd sp!, {args} exists,
  82                ldr     r3, .Ldsi+4
  83                teq     r3, r1, lsr #11
  84                ldreq   r0, [frame, #-8]        @ get sp
  85                subeq   r0, r0, #4              @ point at the last arg
  86                mov     r2, loglvl
  87                bleq    dump_backtrace_stm      @ dump saved registers
  88
  891004:           ldr     r1, [sv_pc, #0]         @ if stmfd sp!, {..., fp, ip, lr, pc}
  90                ldr     r3, .Ldsi               @ instruction exists,
  91                teq     r3, r1, lsr #11
  92                subeq   r0, frame, #16
  93                mov     r2, loglvl
  94                bleq    dump_backtrace_stm      @ dump saved registers
  95
  96                teq     sv_fp, #0               @ zero saved fp means
  97                beq     no_frame                @ no further frames
  98
  99                cmp     sv_fp, frame            @ next frame must be
 100                mov     frame, sv_fp            @ above the current frame
 101                bhi     for_each_frame
 102
 1031006:           adr     r0, .Lbad
 104                mov     r1, loglvl
 105                mov     r2, frame
 106                bl      _printk
 107no_frame:       ldmfd   sp!, {r4 - r9, pc}
 108ENDPROC(c_backtrace)
 109                
 110                .pushsection __ex_table,"a"
 111                .align  3
 112                .long   1001b, 1006b
 113                .long   1002b, 1006b
 114                .long   1003b, 1006b
 115                .long   1004b, 1006b
 116                .popsection
 117
 118.Lbad:          .asciz  "%sBacktrace aborted due to bad frame pointer <%p>\n"
 119                .align
 120.Ldsi:          .word   0xe92dd800 >> 11        @ stmfd sp!, {... fp, ip, lr, pc}
 121                .word   0xe92d0000 >> 11        @ stmfd sp!, {}
 122
 123#endif
 124