root/arch/arm/lib/backtrace-clang.S

/* [<][>][^][v][top][bottom][index][help] */
   1 /* SPDX-License-Identifier: GPL-2.0-only */
   2 /*
   3  *  linux/arch/arm/lib/backtrace-clang.S
   4  *
   5  *  Copyright (C) 2019 Nathan Huckleberry
   6  *
   7  */
   8 #include <linux/kern_levels.h>
   9 #include <linux/linkage.h>
  10 #include <asm/assembler.h>
  11                 .text
  12 
  13 /* fp is 0 or stack frame */
  14 
  15 #define frame   r4
  16 #define sv_fp   r5
  17 #define sv_pc   r6
  18 #define mask    r7
  19 #define sv_lr   r8
  20 
  21 ENTRY(c_backtrace)
  22 
  23 #if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
  24                 ret     lr
  25 ENDPROC(c_backtrace)
  26 #else
  27 
  28 
  29 /*
  30  * Clang does not store pc or sp in function prologues so we don't know exactly
  31  * where the function starts.
  32  *
  33  * We can treat the current frame's lr as the saved pc and the preceding
  34  * frame's lr as the current frame's lr, but we can't trace the most recent
  35  * call.  Inserting a false stack frame allows us to reference the function
  36  * called last in the stacktrace.
  37  *
  38  * If the call instruction was a bl we can look at the callers branch
  39  * instruction to calculate the saved pc.  We can recover the pc in most cases,
  40  * but in cases such as calling function pointers we cannot. In this case,
  41  * default to using the lr. This will be some address in the function, but will
  42  * not be the function start.
  43  *
  44  * Unfortunately due to the stack frame layout we can't dump r0 - r3, but these
  45  * are less frequently saved.
  46  *
  47  * Stack frame layout:
  48  *              <larger addresses>
  49  *              saved lr
  50  *      frame=> saved fp
  51  *              optionally saved caller registers (r4 - r10)
  52  *              optionally saved arguments (r0 - r3)
  53  *              <top of stack frame>
  54  *              <smaller addresses>
  55  *
  56  * Functions start with the following code sequence:
  57  * corrected pc =>  stmfd sp!, {..., fp, lr}
  58  *              add fp, sp, #x
  59  *              stmfd sp!, {r0 - r3} (optional)
  60  *
  61  *
  62  *
  63  *
  64  *
  65  *
  66  * The diagram below shows an example stack setup for dump_stack.
  67  *
  68  * The frame for c_backtrace has pointers to the code of dump_stack. This is
  69  * why the frame of c_backtrace is used to for the pc calculation of
  70  * dump_stack. This is why we must move back a frame to print dump_stack.
  71  *
  72  * The stored locals for dump_stack are in dump_stack's frame. This means that
  73  * to fully print dump_stack's frame we need both the frame for dump_stack (for
  74  * locals) and the frame that was called by dump_stack (for pc).
  75  *
  76  * To print locals we must know where the function start is. If we read the
  77  * function prologue opcodes we can determine which variables are stored in the
  78  * stack frame.
  79  *
  80  * To find the function start of dump_stack we can look at the stored LR of
  81  * show_stack. It points at the instruction directly after the bl dump_stack.
  82  * We can then read the offset from the bl opcode to determine where the branch
  83  * takes us.  The address calculated must be the start of dump_stack.
  84  *
  85  * c_backtrace frame           dump_stack:
  86  * {[LR]    }  ============|   ...
  87  * {[FP]    }  =======|    |   bl c_backtrace
  88  *                    |    |=> ...
  89  * {[R4-R10]}         |
  90  * {[R0-R3] }         |        show_stack:
  91  * dump_stack frame   |        ...
  92  * {[LR]    } =============|   bl dump_stack
  93  * {[FP]    } <=======|    |=> ...
  94  * {[R4-R10]}
  95  * {[R0-R3] }
  96  */
  97 
  98                 stmfd   sp!, {r4 - r9, fp, lr}  @ Save an extra register
  99                                                 @ to ensure 8 byte alignment
 100                 movs    frame, r0               @ if frame pointer is zero
 101                 beq     no_frame                @ we have no stack frames
 102                 tst     r1, #0x10               @ 26 or 32-bit mode?
 103                 moveq   mask, #0xfc000003
 104                 movne   mask, #0                @ mask for 32-bit
 105 
 106 /*
 107  * Switches the current frame to be the frame for dump_stack.
 108  */
 109                 add     frame, sp, #24          @ switch to false frame
 110 for_each_frame: tst     frame, mask             @ Check for address exceptions
 111                 bne     no_frame
 112 
 113 /*
 114  * sv_fp is the stack frame with the locals for the current considered
 115  * function.
 116  *
 117  * sv_pc is the saved lr frame the frame above. This is a pointer to a code
 118  * address within the current considered function, but it is not the function
 119  * start. This value gets updated to be the function start later if it is
 120  * possible.
 121  */
 122 1001:           ldr     sv_pc, [frame, #4]      @ get saved 'pc'
 123 1002:           ldr     sv_fp, [frame, #0]      @ get saved fp
 124 
 125                 teq     sv_fp, mask             @ make sure next frame exists
 126                 beq     no_frame
 127 
 128 /*
 129  * sv_lr is the lr from the function that called the current function. This is
 130  * a pointer to a code address in the current function's caller.  sv_lr-4 is
 131  * the instruction used to call the current function.
 132  *
 133  * This sv_lr can be used to calculate the function start if the function was
 134  * called using a bl instruction. If the function start can be recovered sv_pc
 135  * is overwritten with the function start.
 136  *
 137  * If the current function was called using a function pointer we cannot
 138  * recover the function start and instead continue with sv_pc as an arbitrary
 139  * value within the current function. If this is the case we cannot print
 140  * registers for the current function, but the stacktrace is still printed
 141  * properly.
 142  */
 143 1003:           ldr     sv_lr, [sv_fp, #4]      @ get saved lr from next frame
 144 
 145                 ldr     r0, [sv_lr, #-4]        @ get call instruction
 146                 ldr     r3, .Lopcode+4
 147                 and     r2, r3, r0              @ is this a bl call
 148                 teq     r2, r3
 149                 bne     finished_setup          @ give up if it's not
 150                 and     r0, #0xffffff           @ get call offset 24-bit int
 151                 lsl     r0, r0, #8              @ sign extend offset
 152                 asr     r0, r0, #8
 153                 ldr     sv_pc, [sv_fp, #4]      @ get lr address
 154                 add     sv_pc, sv_pc, #-4       @ get call instruction address
 155                 add     sv_pc, sv_pc, #8        @ take care of prefetch
 156                 add     sv_pc, sv_pc, r0, lsl #2@ find function start
 157 
 158 finished_setup:
 159 
 160                 bic     sv_pc, sv_pc, mask      @ mask PC/LR for the mode
 161 
 162 /*
 163  * Print the function (sv_pc) and where it was called from (sv_lr).
 164  */
 165 1004:           mov     r0, sv_pc
 166 
 167                 mov     r1, sv_lr
 168                 mov     r2, frame
 169                 bic     r1, r1, mask            @ mask PC/LR for the mode
 170                 bl      dump_backtrace_entry
 171 
 172 /*
 173  * Test if the function start is a stmfd instruction to determine which
 174  * registers were stored in the function prologue.
 175  *
 176  * If we could not recover the sv_pc because we were called through a function
 177  * pointer the comparison will fail and no registers will print. Unwinding will
 178  * continue as if there had been no registers stored in this frame.
 179  */
 180 1005:           ldr     r1, [sv_pc, #0]         @ if stmfd sp!, {..., fp, lr}
 181                 ldr     r3, .Lopcode            @ instruction exists,
 182                 teq     r3, r1, lsr #11
 183                 ldr     r0, [frame]             @ locals are stored in
 184                                                 @ the preceding frame
 185                 subeq   r0, r0, #4
 186                 bleq    dump_backtrace_stm      @ dump saved registers
 187 
 188 /*
 189  * If we are out of frames or if the next frame is invalid.
 190  */
 191                 teq     sv_fp, #0               @ zero saved fp means
 192                 beq     no_frame                @ no further frames
 193 
 194                 cmp     sv_fp, frame            @ next frame must be
 195                 mov     frame, sv_fp            @ above the current frame
 196                 bhi     for_each_frame
 197 
 198 1006:           adr     r0, .Lbad
 199                 mov     r1, frame
 200                 bl      printk
 201 no_frame:       ldmfd   sp!, {r4 - r9, fp, pc}
 202 ENDPROC(c_backtrace)
 203                 .pushsection __ex_table,"a"
 204                 .align  3
 205                 .long   1001b, 1006b
 206                 .long   1002b, 1006b
 207                 .long   1003b, 1006b
 208                 .long   1004b, 1006b
 209                 .long   1005b, 1006b
 210                 .popsection
 211 
 212 .Lbad:          .asciz  "Backtrace aborted due to bad frame pointer <%p>\n"
 213                 .align
 214 .Lopcode:       .word   0xe92d4800 >> 11        @ stmfd sp!, {... fp, lr}
 215                 .word   0x0b000000              @ bl if these bits are set
 216 
 217 #endif

/* [<][>][^][v][top][bottom][index][help] */