Skip to content

Commit 385083c

Browse files
authored
[cDAC] ARM Stackwalking (#116645)
* Add ARMContext, ARMFrameHandler, and ARMUnwinder * ARM SoftwareExceptionFrames support * ARM InlinedCallFrame support * ARM TransitionFrame support * ARM FaultingExceptionFrame support * ARM HijackFrame support
1 parent 3224c6c commit 385083c

File tree

19 files changed

+1660
-46
lines changed

19 files changed

+1660
-46
lines changed

docs/design/datacontracts/StackWalk.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,13 @@ This contract depends on the following descriptors:
4242
| `InlinedCallFrame` | `CallSiteSP` | SP saved in Frame |
4343
| `InlinedCallFrame` | `CallerReturnAddress` | Return address saved in Frame |
4444
| `InlinedCallFrame` | `CalleeSavedFP` | FP saved in Frame |
45+
| `InlinedCallFrame` (arm) | `SPAfterProlog` | Value of the SP after prolog. Used on ARM to maintain additional JIT invariant |
4546
| `SoftwareExceptionFrame` | `TargetContext` | Context object saved in Frame |
4647
| `SoftwareExceptionFrame` | `ReturnAddress` | Return address saved in Frame |
4748
| `FramedMethodFrame` | `TransitionBlockPtr` | Pointer to Frame's TransitionBlock |
4849
| `TransitionBlock` | `ReturnAddress` | Return address associated with the TransitionBlock |
4950
| `TransitionBlock` | `CalleeSavedRegisters` | Platform specific CalleeSavedRegisters struct associated with the TransitionBlock |
51+
| `TransitionBlock` (arm) | `ArgumentRegisters` | ARM specific `ArgumentRegisters` struct |
5052
| `FuncEvalFrame` | `DebuggerEvalPtr` | Pointer to the Frame's DebuggerEval object |
5153
| `DebuggerEval` | `TargetContext` | Context saved inside DebuggerEval |
5254
| `DebuggerEval` | `EvalDuringException` | Flag used in processing FuncEvalFrame |
@@ -56,7 +58,8 @@ This contract depends on the following descriptors:
5658
| `HijackFrame` | `HijackArgsPtr` | Pointer to the Frame's stored HijackArgs |
5759
| `HijackArgs` (amd64) | `CalleeSavedRegisters` | CalleeSavedRegisters data structure |
5860
| `HijackArgs` (amd64 Windows) | `Rsp` | Saved stack pointer |
59-
| `HijackArgs` (arm64/x86) | For each register `r` saved in HijackArgs, `r` | Register names associated with stored register values |
61+
| `HijackArgs` (arm/arm64/x86) | For each register `r` saved in HijackArgs, `r` | Register names associated with stored register values |
62+
| `ArgumentRegisters` (arm) | For each register `r` saved in ArgumentRegisters, `r` | Register names associated with stored register values |
6063
| `CalleeSavedRegisters` | For each callee saved register `r`, `r` | Register names associated with stored register values |
6164
| `TailCallFrame` (x86 Windows) | `CalleeSavedRegisters` | CalleeSavedRegisters data structure |
6265
| `TailCallFrame` (x86 Windows) | `ReturnAddress` | Frame's stored instruction pointer |
@@ -244,6 +247,8 @@ Most of the handlers are implemented in `BaseFrameHandler`. Platform specific co
244247

245248
InlinedCallFrames store and update only the IP, SP, and FP of a given context. If the stored IP (CallerReturnAddress) is 0 then the InlinedCallFrame does not have an active call and should not update the context.
246249

250+
* On ARM, the InlinedCallFrame stores the value of the SP after the prolog (`SPAfterProlog`) to allow unwinding for functions with stackalloc. When a function uses stackalloc, the CallSiteSP can already have been adjusted. This value should be placed in R9.
251+
247252
#### SoftwareExceptionFrame
248253

249254
SoftwareExceptionFrames store a copy of the context struct. The IP, SP, and all ABI specified (platform specific) callee-saved registers are copied from the stored context to the working context.
@@ -254,6 +259,8 @@ TransitionFrames hold a pointer to a `TransitionBlock`. The TransitionBlock hold
254259

255260
When updating the context from a TransitionFrame, the IP, SP, and all ABI specified callee-saved registers are copied over.
256261

262+
* On ARM, the additional register values stored in `ArgumentRegisters` are copied over. The `TransitionBlock` holds a pointer to the `ArgumentRegister` struct containing these values.
263+
257264
The following Frame types also use this mechanism:
258265
* FramedMethodFrame
259266
* CLRToCOMMethodFrame
@@ -289,7 +296,9 @@ HijackFrames carry a IP (ReturnAddress) and a pointer to `HijackArgs`. All platf
289296
* x64 - On x64, HijackArgs contains a CalleeSavedRegister struct. The saved registers values contained in the struct are copied over to the working context.
290297
* Windows - On Windows, HijackArgs also contains the SP value directly which is copied over to the working context.
291298
* Non-Windows - On OS's other than Windows, HijackArgs does not contain an SP value. Instead since the HijackArgs struct lives on the stack, the SP is `&hijackArgs + sizeof(HijackArgs)`. This value is also copied over.
292-
* arm64 - Unlike on x64, on arm64 HijackArgs contains a list of register values instead of the CalleeSavedRegister struct. These values are copied over to the working context. The SP is fetched using the same technique as on x64 non-Windows where `SP = &hijackArgs + sizeof(HijackArgs)` and is copied over to the working context.
299+
* x86 - On x86, HijackArgs contains a list of register values instead of the CalleeSavedRegister struct. These values are copied over to the working context. The SP copied over to the working context and found using `SP = &hijackArgs + sizeof(HijackArgs)`.
300+
* arm64 - Unlike on x64, on arm64 HijackArgs contains a list of register values instead of the CalleeSavedRegister struct. These values are copied over to the working context. The SP is fetched using the same technique as on x64 non-Windows where `SP = &hijackArgs + sizeof(HijackArgs) + (hijackArgsSize % 16)` and is copied over to the working context. Note: `HijackArgs` may be padded to maintain 16 byte stack alignment.
301+
* arm - Similar to arm64, HijackArgs contains a list of register values. These values are copied over to the working context. The SP is fetched using the same technique as arm64 where `SP = &hijackArgs + sizeof(HijackArgs) + (hijackArgsSize % 8)` and is copied over to the working context. Note: `HijackArgs` may be padded to maintain 8 byte stack alignment.
293302

294303
#### TailCallFrame
295304

src/coreclr/debug/runtimeinfo/datadescriptor.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,9 @@ CDAC_TYPE_SIZE(sizeof(InlinedCallFrame))
706706
CDAC_TYPE_FIELD(InlinedCallFrame, /*pointer*/, CallSiteSP, offsetof(InlinedCallFrame, m_pCallSiteSP))
707707
CDAC_TYPE_FIELD(InlinedCallFrame, /*pointer*/, CallerReturnAddress, offsetof(InlinedCallFrame, m_pCallerReturnAddress))
708708
CDAC_TYPE_FIELD(InlinedCallFrame, /*pointer*/, CalleeSavedFP, offsetof(InlinedCallFrame, m_pCalleeSavedFP))
709+
#ifdef TARGET_ARM
710+
CDAC_TYPE_FIELD(InlinedCallFrame, /*pointer*/, SPAfterProlog, offsetof(InlinedCallFrame, m_pSPAfterProlog))
711+
#endif // TARGET_ARM
709712
CDAC_TYPE_END(InlinedCallFrame)
710713

711714
CDAC_TYPE_BEGIN(SoftwareExceptionFrame)
@@ -723,6 +726,9 @@ CDAC_TYPE_BEGIN(TransitionBlock)
723726
CDAC_TYPE_SIZE(sizeof(TransitionBlock))
724727
CDAC_TYPE_FIELD(TransitionBlock, /*pointer*/, ReturnAddress, offsetof(TransitionBlock, m_ReturnAddress))
725728
CDAC_TYPE_FIELD(TransitionBlock, /*CalleeSavedRegisters*/, CalleeSavedRegisters, offsetof(TransitionBlock, m_calleeSavedRegisters))
729+
#ifdef TARGET_ARM
730+
CDAC_TYPE_FIELD(TransitionBlock, /*ArgumentRegisters*/, ArgumentRegisters, offsetof(TransitionBlock, m_argumentRegisters))
731+
#endif // TARGET_ARM
726732
CDAC_TYPE_END(TransitionBlock)
727733

728734
#ifdef DEBUGGING_SUPPORTED
@@ -788,6 +794,19 @@ CDAC_TYPE_FIELD(HijackArgs, /*pointer*/, Eax, offsetof(HijackArgs, Eax))
788794
CDAC_TYPE_FIELD(HijackArgs, /*pointer*/, Ebp, offsetof(HijackArgs, Ebp))
789795
CDAC_TYPE_FIELD(HijackArgs, /*pointer*/, Eip, offsetof(HijackArgs, Eip))
790796

797+
#elif defined(TARGET_ARM)
798+
799+
CDAC_TYPE_FIELD(HijackArgs, /*pointer*/, R0, offsetof(HijackArgs, R0))
800+
CDAC_TYPE_FIELD(HijackArgs, /*pointer*/, R2, offsetof(HijackArgs, R2))
801+
CDAC_TYPE_FIELD(HijackArgs, /*pointer*/, R4, offsetof(HijackArgs, R4))
802+
CDAC_TYPE_FIELD(HijackArgs, /*pointer*/, R5, offsetof(HijackArgs, R5))
803+
CDAC_TYPE_FIELD(HijackArgs, /*pointer*/, R6, offsetof(HijackArgs, R6))
804+
CDAC_TYPE_FIELD(HijackArgs, /*pointer*/, R7, offsetof(HijackArgs, R7))
805+
CDAC_TYPE_FIELD(HijackArgs, /*pointer*/, R8, offsetof(HijackArgs, R8))
806+
CDAC_TYPE_FIELD(HijackArgs, /*pointer*/, R9, offsetof(HijackArgs, R9))
807+
CDAC_TYPE_FIELD(HijackArgs, /*pointer*/, R10, offsetof(HijackArgs, R10))
808+
CDAC_TYPE_FIELD(HijackArgs, /*pointer*/, R11, offsetof(HijackArgs, R11))
809+
791810
#endif // Platform switch
792811
CDAC_TYPE_END(HijackArgs)
793812
#endif // FEATURE_HIJACK
@@ -807,6 +826,19 @@ CDAC_TYPE_FIELD(TailCallFrame, /*pointer*/, ReturnAddress, cdac_data<TailCallFra
807826
CDAC_TYPE_END(TailCallFrame)
808827
#endif // TARGET_X86 && !UNIX_X86_ABI
809828

829+
// ArgumentRegisters struct is different on each platform
830+
CDAC_TYPE_BEGIN(ArgumentRegisters)
831+
CDAC_TYPE_SIZE(sizeof(ArgumentRegisters))
832+
#if defined(TARGET_ARM)
833+
834+
CDAC_TYPE_FIELD(ArgumentRegisters, /*nuint*/, R0, offsetof(ArgumentRegisters, r[0]))
835+
CDAC_TYPE_FIELD(ArgumentRegisters, /*nuint*/, R1, offsetof(ArgumentRegisters, r[1]))
836+
CDAC_TYPE_FIELD(ArgumentRegisters, /*nuint*/, R2, offsetof(ArgumentRegisters, r[2]))
837+
CDAC_TYPE_FIELD(ArgumentRegisters, /*nuint*/, R3, offsetof(ArgumentRegisters, r[3]))
838+
839+
#endif // TARGET_ARM
840+
CDAC_TYPE_END(ArgumentRegisters)
841+
810842
// CalleeSavedRegisters struct is different on each platform
811843
CDAC_TYPE_BEGIN(CalleeSavedRegisters)
812844
CDAC_TYPE_SIZE(sizeof(CalleeSavedRegisters))
@@ -817,6 +849,18 @@ CDAC_TYPE_SIZE(sizeof(CalleeSavedRegisters))
817849
ENUM_CALLEE_SAVED_REGISTERS()
818850
#undef CALLEE_SAVED_REGISTER
819851

852+
#elif defined(TARGET_ARM)
853+
854+
CDAC_TYPE_FIELD(CalleeSavedRegisters, /*nuint*/, R4, offsetof(CalleeSavedRegisters, r4))
855+
CDAC_TYPE_FIELD(CalleeSavedRegisters, /*nuint*/, R5, offsetof(CalleeSavedRegisters, r5))
856+
CDAC_TYPE_FIELD(CalleeSavedRegisters, /*nuint*/, R6, offsetof(CalleeSavedRegisters, r6))
857+
CDAC_TYPE_FIELD(CalleeSavedRegisters, /*nuint*/, R7, offsetof(CalleeSavedRegisters, r7))
858+
CDAC_TYPE_FIELD(CalleeSavedRegisters, /*nuint*/, R8, offsetof(CalleeSavedRegisters, r8))
859+
CDAC_TYPE_FIELD(CalleeSavedRegisters, /*nuint*/, R9, offsetof(CalleeSavedRegisters, r9))
860+
CDAC_TYPE_FIELD(CalleeSavedRegisters, /*nuint*/, R10, offsetof(CalleeSavedRegisters, r10))
861+
CDAC_TYPE_FIELD(CalleeSavedRegisters, /*nuint*/, R11, offsetof(CalleeSavedRegisters, r11))
862+
CDAC_TYPE_FIELD(CalleeSavedRegisters, /*nuint*/, Lr, offsetof(CalleeSavedRegisters, r14))
863+
820864
#elif defined(TARGET_ARM64)
821865

822866
CDAC_TYPE_FIELD(CalleeSavedRegisters, /*nuint*/, X19, offsetof(CalleeSavedRegisters, x19))

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ public enum DataType
103103

104104
TransitionBlock,
105105
DebuggerEval,
106+
ArgumentRegisters,
106107
CalleeSavedRegisters,
107108
HijackArgs,
108109

0 commit comments

Comments
 (0)