Skip to content

Commit a794374

Browse files
author
Max Charlamb
committed
AMD64/ARM64 stackwalking backend
1 parent da73082 commit a794374

File tree

17 files changed

+498
-278
lines changed

17 files changed

+498
-278
lines changed

src/coreclr/debug/runtimeinfo/datadescriptor.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,14 @@ CDAC_TYPE_FIELD(InlinedCallFrame, /*pointer*/, CallerReturnAddress, offsetof(Inl
587587
CDAC_TYPE_FIELD(InlinedCallFrame, /*pointer*/, CalleeSavedFP, offsetof(InlinedCallFrame, m_pCalleeSavedFP))
588588
CDAC_TYPE_END(InlinedCallFrame)
589589

590+
#ifdef FEATURE_EH_FUNCLETS
591+
CDAC_TYPE_BEGIN(SoftwareExceptionFrame)
592+
CDAC_TYPE_SIZE(sizeof(SoftwareExceptionFrame))
593+
CDAC_TYPE_FIELD(SoftwareExceptionFrame, /*T_CONTEXT*/, TargetContext, cdac_data<SoftwareExceptionFrame>::TargetContext)
594+
CDAC_TYPE_FIELD(SoftwareExceptionFrame, /*pointer*/, ReturnAddress, cdac_data<SoftwareExceptionFrame>::ReturnAddress)
595+
CDAC_TYPE_END(SoftwareExceptionFrame)
596+
#endif // FEATURE_EH_FUNCLETS
597+
590598
#define DEFINE_FRAME_TYPE(frameType) \
591599
CDAC_TYPE_BEGIN(frameType) \
592600
CDAC_TYPE_SIZE(sizeof(frameType)) \

src/coreclr/unwinder/amd64/unwinder.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,8 +352,6 @@ BOOL amd64Unwind(void* pContext, ReadCallback readCallback, GetAllocatedBuffer g
352352
{
353353
HRESULT hr = E_FAIL;
354354

355-
return (long)((CONTEXT*)pContext)->Rip;
356-
357355
OOPStackUnwinderAMD64 unwinder { readCallback, getAllocatedBuffer, getStackWalkInfo };
358356
hr = unwinder.Unwind((CONTEXT*) pContext);
359357

src/coreclr/unwinder/arm64/unwinder.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,25 @@ typedef struct _ARM64_VFP_STATE
174174
// Macros for accessing memory. These can be overridden if other code
175175
// (in particular the debugger) needs to use them.
176176

177-
#if !defined(DEBUGGER_UNWIND)
177+
#if !defined(DEBUGGER_UNWIND) && !defined(FEATURE_CDAC_UNWINDER)
178178

179179
#define MEMORY_READ_BYTE(params, addr) (*dac_cast<PTR_BYTE>(addr))
180180
#define MEMORY_READ_WORD(params, addr) (*dac_cast<PTR_WORD>(addr))
181181
#define MEMORY_READ_DWORD(params, addr) (*dac_cast<PTR_DWORD>(addr))
182182
#define MEMORY_READ_QWORD(params, addr) (*dac_cast<PTR_UINT64>(addr))
183183

184+
#elif defined(FEATURE_CDAC_UNWINDER)
185+
template<typename T>
186+
T cdacRead(uint64_t addr)
187+
{
188+
T t;
189+
g_pUnwinder->readCallback(addr, &t, sizeof(t));
190+
return t;
191+
}
192+
#define MEMORY_READ_BYTE(params, addr) (cdacRead<BYTE>(addr))
193+
#define MEMORY_READ_WORD(params, addr) (cdacRead<WORD>(addr))
194+
#define MEMORY_READ_DWORD(params, addr) (cdacRead<DWORD>(addr))
195+
#define MEMORY_READ_QWORD(params, addr) (cdacRead<UINT64>(addr))
184196
#endif
185197

186198
//
@@ -2788,15 +2800,17 @@ BOOL DacUnwindStackFrame(T_CONTEXT *pContext, T_KNONVOLATILE_CONTEXT_POINTERS* p
27882800
#endif // DACCESS_COMPILE
27892801

27902802
#ifdef FEATURE_CDAC_UNWINDER
2803+
OOPStackUnwinderArm64* g_pUnwinder;
27912804
BOOL arm64Unwind(void* pContext, ReadCallback readCallback, GetAllocatedBuffer getAllocatedBuffer, GetStackWalkInfo getStackWalkInfo)
27922805
{
27932806
HRESULT hr = E_FAIL;
27942807

2795-
return (long)((T_CONTEXT*)pContext)->Pc;
2796-
27972808
OOPStackUnwinderArm64 unwinder { readCallback, getAllocatedBuffer, getStackWalkInfo };
2809+
g_pUnwinder = &unwinder;
27982810
hr = unwinder.Unwind((T_CONTEXT*) pContext);
27992811

2812+
g_pUnwinder = nullptr;
2813+
28002814
return (hr == S_OK);
28012815
}
28022816
#endif

src/coreclr/unwinder/baseunwinder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ class OOPStackUnwinder
5252
getStackWalkInfo(getStackWalkInfo)
5353
{ }
5454

55+
56+
public:
57+
// These functions are marked public because they are called using
58+
// a global instance of OOPStackUnwinder in the ARM64 implementation.
5559
ReadCallback readCallback;
5660
GetAllocatedBuffer getAllocatedBuffer;
5761
GetStackWalkInfo getStackWalkInfo;

src/coreclr/vm/frames.h

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,10 +1213,18 @@ class SoftwareExceptionFrame : public Frame
12131213

12141214
virtual void UpdateRegDisplay(const PREGDISPLAY, bool updateFloats = false);
12151215

1216+
friend struct ::cdac_data<SoftwareExceptionFrame>;
1217+
12161218
// Keep as last entry in class
12171219
DEFINE_VTABLE_GETTER_AND_DTOR(SoftwareExceptionFrame)
12181220
};
12191221

1222+
template<>
1223+
struct cdac_data<SoftwareExceptionFrame>
1224+
{
1225+
static constexpr size_t TargetContext = offsetof(SoftwareExceptionFrame, m_Context);
1226+
static constexpr size_t ReturnAddress = offsetof(SoftwareExceptionFrame, m_ReturnAddress);
1227+
};
12201228
#endif // FEATURE_EH_FUNCLETS
12211229

12221230
//-----------------------------------------------------------------------
@@ -1452,10 +1460,10 @@ class HelperMethodFrame : public Frame
14521460

14531461
LazyMachState m_MachState; // pRetAddr points to the return address and the stack arguments
14541462

1463+
friend struct ::cdac_data<HelperMethodFrame>;
1464+
14551465
// Keep as last entry in class
14561466
DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame)
1457-
1458-
friend struct ::cdac_data<HelperMethodFrame>;
14591467
};
14601468

14611469
template<>
@@ -1547,10 +1555,10 @@ class HelperMethodFrame_1OBJ : public HelperMethodFrame
15471555
private:
15481556
PTR_OBJECTREF gcPtrs[1];
15491557

1558+
friend struct ::cdac_data<HelperMethodFrame_1OBJ>;
1559+
15501560
// Keep as last entry in class
15511561
DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_1OBJ)
1552-
1553-
friend struct ::cdac_data<HelperMethodFrame_1OBJ>;
15541562
};
15551563

15561564
template<>
@@ -1618,10 +1626,10 @@ class HelperMethodFrame_2OBJ : public HelperMethodFrame
16181626
private:
16191627
PTR_OBJECTREF gcPtrs[2];
16201628

1629+
friend struct ::cdac_data<HelperMethodFrame_2OBJ>;
1630+
16211631
// Keep as last entry in class
16221632
DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_2OBJ)
1623-
1624-
friend struct ::cdac_data<HelperMethodFrame_2OBJ>;
16251633
};
16261634

16271635
template<>
@@ -1694,10 +1702,10 @@ class HelperMethodFrame_3OBJ : public HelperMethodFrame
16941702
private:
16951703
PTR_OBJECTREF gcPtrs[3];
16961704

1705+
friend struct ::cdac_data<HelperMethodFrame_3OBJ>;
1706+
16971707
// Keep as last entry in class
16981708
DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_3OBJ)
1699-
1700-
friend struct ::cdac_data<HelperMethodFrame_3OBJ>;
17011709
};
17021710

17031711
template<>
@@ -1770,10 +1778,10 @@ class HelperMethodFrame_PROTECTOBJ : public HelperMethodFrame
17701778
PTR_OBJECTREF m_pObjRefs;
17711779
UINT m_numObjRefs;
17721780

1781+
friend struct ::cdac_data<HelperMethodFrame_PROTECTOBJ>;
1782+
17731783
// Keep as last entry in class
17741784
DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_PROTECTOBJ)
1775-
1776-
friend struct ::cdac_data<HelperMethodFrame_PROTECTOBJ>;
17771785
};
17781786

17791787
template<>

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/Target.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,24 @@ namespace Microsoft.Diagnostics.DataContractReader;
1818
/// </remarks>
1919
internal abstract class Target
2020
{
21+
public enum CorDebugPlatform : int
22+
{
23+
CORDB_PLATFORM_WINDOWS_X86 = 0,
24+
CORDB_PLATFORM_WINDOWS_AMD64 = 1,
25+
CORDB_PLATFORM_WINDOWS_IA64 = 2,
26+
CORDB_PLATFORM_MAC_PPC = 3,
27+
CORDB_PLATFORM_MAC_X86 = 4,
28+
CORDB_PLATFORM_WINDOWS_ARM = 5,
29+
CORDB_PLATFORM_MAC_AMD64 = 6,
30+
CORDB_PLATFORM_WINDOWS_ARM64 = 7,
31+
CORDB_PLATFORM_POSIX_AMD64 = 8,
32+
CORDB_PLATFORM_POSIX_X86 = 9,
33+
CORDB_PLATFORM_POSIX_ARM = 10,
34+
CORDB_PLATFORM_POSIX_ARM64 = 11,
35+
CORDB_PLATFORM_POSIX_LOONGARCH64 = 12,
36+
CORDB_PLATFORM_POSIX_RISCV64 = 12
37+
}
38+
2139
/// <summary>
2240
/// Pointer size of the target
2341
/// </summary>
@@ -28,7 +46,7 @@ internal abstract class Target
2846
public abstract bool IsLittleEndian { get; }
2947

3048
public abstract int GetThreadContext(uint threadId, uint contextFlags, uint contextSize, Span<byte> bufferToFill);
31-
public abstract int GetPlatform(out int platform);
49+
public abstract int GetPlatform(out CorDebugPlatform platform);
3250

3351
/// <summary>
3452
/// Reads a well-known global pointer value from the target process

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerBase.EEJitManager.cs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,19 +71,26 @@ public override TargetPointer GetUnwindInfo(RangeSection rangeSection, TargetCod
7171
throw new InvalidOperationException("Unable to get NumUnwindInfos");
7272
}
7373

74-
ulong imageBase = rangeSection.Data.RangeBegin;
74+
if (numUnwindInfos == 0)
75+
{
76+
return TargetPointer.Null;
77+
}
7578

76-
for (ulong i = 0; i < numUnwindInfos; i++)
79+
ulong imageBase = rangeSection.Data.RangeBegin;
80+
TargetPointer prevUnwindInfoAddress = unwindInfos;
81+
TargetPointer currUnwindInfoAddress;
82+
for (ulong i = 1; i < numUnwindInfos; i++)
7783
{
78-
TargetPointer unwindInfoAddress = unwindInfos + (i * runtimeFunctionSize);
79-
Data.RuntimeFunction runtimeFunction = Target.ProcessedData.GetOrAdd<Data.RuntimeFunction>(unwindInfoAddress);
80-
if (runtimeFunction.BeginAddress + imageBase <= jittedCodeAddress.Value && runtimeFunction.EndAddress + imageBase >= jittedCodeAddress.Value)
84+
currUnwindInfoAddress = unwindInfos + (i * runtimeFunctionSize);
85+
Data.RuntimeFunction nextRuntimeFunction = Target.ProcessedData.GetOrAdd<Data.RuntimeFunction>(currUnwindInfoAddress);
86+
if (nextRuntimeFunction.BeginAddress + imageBase > jittedCodeAddress.Value)
8187
{
82-
return unwindInfoAddress;
88+
return prevUnwindInfoAddress;
8389
}
90+
prevUnwindInfoAddress = currUnwindInfoAddress;
8491
}
8592

86-
return TargetPointer.Null;
93+
return prevUnwindInfoAddress;
8794
}
8895

8996
private TargetPointer FindMethodCode(RangeSection rangeSection, TargetCodePointer jittedCodeAddress)

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/AMD64Context.cs

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers;
1212
/// AMD64-specific thread context.
1313
/// </summary>
1414
[StructLayout(LayoutKind.Explicit, Pack = 1)]
15-
public struct AMD64Context : IContext
15+
internal struct AMD64Context : IContext
1616
{
1717
[Flags]
1818
public enum ContextFlagsValues : uint
@@ -32,8 +32,47 @@ public enum ContextFlagsValues : uint
3232
public static uint Size => 0x4d0;
3333
public static uint DefaultContextFlags => (uint)ContextFlagsValues.CONTEXT_FULL;
3434

35-
public readonly TargetPointer StackPointer => new(Rsp);
36-
public readonly TargetPointer InstructionPointer => new(Rip);
35+
public TargetPointer StackPointer
36+
{
37+
readonly get => new(Rsp);
38+
set => Rsp = value.Value;
39+
}
40+
public TargetPointer InstructionPointer
41+
{
42+
readonly get => new(Rip);
43+
set => Rip = value.Value;
44+
}
45+
public TargetPointer FramePointer
46+
{
47+
readonly get => new(Rbp);
48+
set => Rbp = value.Value;
49+
}
50+
51+
public void Unwind(Target target)
52+
{
53+
Unwinder.AMD64Unwind(ref this, target);
54+
}
55+
56+
public unsafe void ReadFromAddress(Target target, TargetPointer address)
57+
{
58+
Span<byte> buffer = new byte[Size];
59+
target.ReadBuffer(address, buffer);
60+
Span<AMD64Context> structSpan = MemoryMarshal.CreateSpan(ref this, sizeof(AMD64Context));
61+
Span<byte> byteSpan = MemoryMarshal.Cast<AMD64Context, byte>(structSpan);
62+
if (buffer.Length > sizeof(AMD64Context))
63+
{
64+
buffer.Slice(0, sizeof(AMD64Context)).CopyTo(byteSpan);
65+
}
66+
else
67+
{
68+
buffer.CopyTo(byteSpan);
69+
}
70+
}
71+
72+
public void Clear()
73+
{
74+
this = default;
75+
}
3776

3877
public override string ToString()
3978
{

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/ARM64Context.cs

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using System.Reflection;
56
using System.Runtime.InteropServices;
7+
using System.Text;
68

79
namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers;
810

911
/// <summary>
1012
/// ARM64-specific thread context.
1113
/// </summary>
1214
[StructLayout(LayoutKind.Explicit, Pack = 1)]
13-
public struct ARM64Context : IContext
15+
internal struct ARM64Context : IContext
1416
{
1517
[Flags]
1618
public enum ContextFlagsValues : uint
@@ -29,8 +31,71 @@ public enum ContextFlagsValues : uint
2931

3032
public static uint DefaultContextFlags => (uint)ContextFlagsValues.CONTEXT_FULL;
3133

32-
public readonly TargetPointer StackPointer => new(Sp);
33-
public readonly TargetPointer InstructionPointer => new(Pc);
34+
public TargetPointer StackPointer
35+
{
36+
readonly get => new(Sp);
37+
set => Sp = value.Value;
38+
}
39+
public TargetPointer InstructionPointer
40+
{
41+
readonly get => new(Pc);
42+
set => Pc = value.Value;
43+
}
44+
public TargetPointer FramePointer
45+
{
46+
readonly get => new(Fp);
47+
set => Fp = value.Value;
48+
}
49+
50+
public void Unwind(Target target)
51+
{
52+
Unwinder.ARM64Unwind(ref this, target);
53+
}
54+
55+
public void Clear()
56+
{
57+
this = default;
58+
}
59+
60+
public unsafe void ReadFromAddress(Target target, TargetPointer address)
61+
{
62+
Span<byte> buffer = new byte[Size];
63+
target.ReadBuffer(address, buffer);
64+
Span<ARM64Context> structSpan = MemoryMarshal.CreateSpan(ref this, sizeof(ARM64Context));
65+
Span<byte> byteSpan = MemoryMarshal.Cast<ARM64Context, byte>(structSpan);
66+
if (buffer.Length > sizeof(ARM64Context))
67+
{
68+
buffer.Slice(0, sizeof(ARM64Context)).CopyTo(byteSpan);
69+
}
70+
else
71+
{
72+
buffer.CopyTo(byteSpan);
73+
}
74+
}
75+
76+
public override string ToString()
77+
{
78+
StringBuilder sb = new();
79+
foreach (FieldInfo fieldInfo in typeof(AMD64Context).GetFields())
80+
{
81+
switch (fieldInfo.GetValue(this))
82+
{
83+
case ulong v:
84+
sb.AppendLine($"{fieldInfo.Name} = {v:x16}");
85+
break;
86+
case uint v:
87+
sb.AppendLine($"{fieldInfo.Name} = {v:x8}");
88+
break;
89+
case ushort v:
90+
sb.AppendLine($"{fieldInfo.Name} = {v:x4}");
91+
break;
92+
default:
93+
sb.AppendLine($"{fieldInfo.Name} = {fieldInfo.GetValue(this)}");
94+
continue;
95+
}
96+
}
97+
return sb.ToString();
98+
}
3499

35100
// Control flags
36101

0 commit comments

Comments
 (0)