From f9823f66fc7e718264247d24d13086cbd8d9d181 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 1 Jul 2025 16:37:32 +0100 Subject: [PATCH] [AADWARF32] Allocate a register number for CPSR The document says of CPSR, along with the VFP (and FPA) control registers, "It is considered unlikely that these will be needed for producing a stack back-trace in a debugger." However, CPSR _can_ be required for producing a correct stack backtrace. This occurs due to conditional return sequences, for example ``` function: PUSH {r4, r5, r6, lr} SUB sp, sp, #64 // ... do stuff ... CMP this, that // we will return early if they are equal ADDEQ sp, sp, #64 POPEQ {r4, r5, r6, pc} // ... now, if we didn't return, continue using our stack frame ``` In between ADDEQ and POPEQ, the state of the stack depends on the flags in CPSR. If the Z flag is set, then the ADDEQ has happened, and the POPEQ is about to; if Z is clear, neither one has happened. In this example the function has no frame pointer, so the CFA is defined as an offset from sp, and _what_ offset depends on whether we just added 64 to sp. This style of conditional return has always been possible, since it depends only on the earliest features of the Arm instruction set. The accepted idiom in my experience has always been to write stack frame information that is valid for one case but not the other. Introducing a DWARF register number for CPSR makes it possible to write stack frame information that is valid in both cases. For example, you could write an expression along these lines, which uses the 4 bits at the top of CPSR to decide which bit of the constant `bitmask` to test, and then each Arm condition code is representable as a different bitmask: ``` DW_OP_breg_13 // fetch sp DW_OP_constu #bitmask // bit mask for the particular condition DW_OP_bregx #CPSR // fetch CPSR DW_OP_const1u #28 DW_OP_shr // make (CPSR >> 28), just the NZCV bits DW_OP_shr // shift bit mask right by the NZCV value DW_OP_const1u #1 DW_OP_and // AND with 1 to isolate low bit DW_OP_bra #label-offset-else // if nonzero, branch over the next constant DW_OP_constu #offset2 // load one possible value to add to sp DW_OP_skip #label-offset-end // and skip over the other constant label-offset-else: DW_OP_constu #offset1 // load the other value to add to sp label-offset-end: DW_OP_minus // add either offset2 or offset1 to sp ``` Of course, debuggers will take time to catch up. But a more interesting use case for being able to precisely describe stack situations like this is automatic static checkers for handwritten assembly language with handwritten call frame directives, which verify the semantics of the instructions against the call frame updates next to them. A debugger might almost never stop at the difficult location above, but a static checker will traverse it every time, and needs a way to avoid getting confused. --- aadwarf32/aadwarf32.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/aadwarf32/aadwarf32.rst b/aadwarf32/aadwarf32.rst index 6f51d911..31e69d78 100644 --- a/aadwarf32/aadwarf32.rst +++ b/aadwarf32/aadwarf32.rst @@ -435,7 +435,9 @@ LEB128 integers. Numbers 0-127 encode in 1 byte, 128-16383 in 2 bytes. +----------------+------------------------+-------------------------------------+ | 133 | SPSR_SVC | SVC-mode SPSR | +----------------+------------------------+-------------------------------------+ - | 134–142 | None | Reserved for future allocation | + | 134 | CPSR | Current CPSR, including the flags | + +----------------+------------------------+-------------------------------------+ + | 135–142 | None | Reserved for future allocation | +----------------+------------------------+-------------------------------------+ | 143 | RA_AUTH_CODE | `Return Address Authentication | | | | Code`_ | @@ -520,8 +522,8 @@ LEB128 integers. Numbers 0-127 encode in 1 byte, 128-16383 in 2 bytes. more precisely specified scheme using 2-byte register numbers. The new numbering scheme should also be used for VFP-v2. -The CPSR, VFP and FPA control registers are not allocated a numbering above. -It is considered unlikely that these will be needed for producing a stack +The VFP and FPA control registers are not allocated a numbering above. It is +considered unlikely that these will be needed for producing a stack back-trace in a debugger. VFP-v3 and Neon register descriptions