/// -*- mode: asm; asm-comment-char: ?/ -*- /// /// Register dump and debugging for 32-bit ARM /// /// (c) 2019 Straylight/Edgeware /// ///----- Licensing notice --------------------------------------------------- /// /// This file is part of Catacomb. /// /// Catacomb is free software: you can redistribute it and/or modify it /// under the terms of the GNU Library General Public License as published /// by the Free Software Foundation; either version 2 of the License, or /// (at your option) any later version. /// /// Catacomb is distributed in the hope that it will be useful, but /// WITHOUT ANY WARRANTY; without even the implied warranty of /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU /// Library General Public License for more details. /// /// You should have received a copy of the GNU Library General Public /// License along with Catacomb. If not, write to the Free Software /// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, /// USA. ///-------------------------------------------------------------------------- /// Preliminaries. #include "config.h" #include "asm-common.h" #include "regdump.h" .arch armv7-a .fpu neon .text ///-------------------------------------------------------------------------- /// Main code. FUNC(regdump_gpsave) endprologue // On entry, r13 should point to `REGDUMP_GPSIZE' bytes of // word-aligned storage to be the general-purpose save area, with r12 // and r14 already saved. On exit, the initial registers are saved // in this space, and modified: r4 points to the general-purpose save // area, r6 holds the focus address (possibly already saved), r0 // contains the number of bytes required in the extended save area, // and other general-purpose registers are clobbered or used to // communicate with `regdump_xtsave' below. Doing anything other // than lowering the stack pointer and calling `regdump_xtsave' is // not recommended. // Save the easy registers. stmia r13, {r0-r11} mov r4, r13 // Determine the previous stack pointer and save it. add r0, r4, #REGDUMP_GPSIZE str r0, [r4, #13*4] // Clear the magic Thumb-state bit from the return address. bic r1, r14, #1 str r1, [r13, #15*4] // Load the focus address and save it as r6. ldr r6, [r4, #4*REGIX_ADDR] // Determine the extended save area size. ldgot mov r0, #8 + 8 leaext r12, regdump__flags ldr r12, [r12] tst r12, #REGF_VFP addne r0, r0, #REGDUMP_FPSIZE_D16 tstne r12, #REGF_D32 addne r0, r0, #REGDUMP_FPSIZE_D32 - REGDUMP_FPSIZE_D16 // Done. bx r14 ENDFUNC FUNC(regdump_gprstr) endprologue // On entry, r4 points to a general-purpose save area, established by // `regdump_gpsave'. On exit, the general-purpose registers (other // than r13 and r14) are restored to their original values. // Restore the processor flags. ldr r0, [r4, #4*REGIX_CPSR] msr cpsr_fs, r0 // Load the easy registers. ldmia r4, {r0-r12} // Done. bx r14 ENDFUNC FUNC(regdump_xtsave) endprologue // On entry, r13 points to an extended save area, of size determined // by `regdump_gpsave' above. On exit, the save area is filled in // and a handy map placed at its base, and r5 is left pointing to the // reigster map. // Set up the map/extended save area pointer. add r5, r13, #7 bic r5, r5, #7 // Start by filling in the easy part of the map. str r4, [r5, #regmap_gp] // Fetch the flags explaining what to do. ldgot leaext r12, regdump__flags ldr r12, [r12] // Figure out whether there are VFP/NEON registers. tst r12, #REGF_VFP moveq r3, #0 addne r3, r5, #regmap_size str r3, [r5, #regmap_fp] beq 9f // Get the FP status register. vmrs r0, fpscr str r0, [r3], #8 // At least the first 16. vstmia r3!, {d0-d15} // Maybe the other 16 too. tst r12, #REGF_D32 vstmiane r3!, {d16-d31} // Done. 9: bx r14 ENDFUNC FUNC(regdump_xtrstr) endprologue // On entry, r5 points to a register-save map. On exit, the extended // registers are restored from the save area, r4 (pointing to the // general-purpose save area) is preserved, and the other general // registers are clobbered. // Fetch the flags explaining what to do. ldgot leaext r12, regdump__flags ldr r12, [r12] // Figure out if there are VFP/NEON registers. tst r12, #REGF_VFP beq 9f ldr r3, [r5, #regmap_fp] // Load the FP status register. ldr r0, [r3], #8 vmsr fpscr, r0 // Load the first 16 registers. vldmia r3!, {d0-d15} // And maybe the other 16. tst r12, #REGF_D32 vldmiane r3!, {d16-d31} // Done. 9: bx r14 ENDFUNC ///----- That's all, folks --------------------------------------------------