Skip to content

Commit 2313209

Browse files
authored
[cDAC] X86 support TailCallFrame (#116792)
* support tailcall frame
1 parent 4672402 commit 2313209

File tree

9 files changed

+71
-2
lines changed

9 files changed

+71
-2
lines changed

docs/design/datacontracts/StackWalk.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ This contract depends on the following descriptors:
5858
| `HijackArgs` (amd64 Windows) | `Rsp` | Saved stack pointer |
5959
| `HijackArgs` (arm64) | For each register `r` saved in HijackArgs, `r` | Register names associated with stored register values |
6060
| `CalleeSavedRegisters` | For each callee saved register `r`, `r` | Register names associated with stored register values |
61+
| `TailCallFrame` (x86 Windows) | `CalleeSavedRegisters` | CalleeSavedRegisters data structure |
62+
| `TailCallFrame` (x86 Windows) | `ReturnAddress` | Frame's stored instruction pointer |
6163

6264
Global variables used:
6365
| Global Name | Type | Purpose |
@@ -291,7 +293,7 @@ HijackFrames carry a IP (ReturnAddress) and a pointer to `HijackArgs`. All platf
291293

292294
#### TailCallFrame
293295

294-
TailCallFrames are only used on Windows x86 which is not yet supported in the cDAC and therefore not implemented.
296+
TailCallFrames only appear on x86 Windows. They hold a `CalleeSavedRegisters` struct as well as a `ReturnAddress`. While the stack pointer is not directly contained in the TailCallFrame structure, it will be on the stack immediately following the Frame (found at the address of the Frame + size of the Frame). To process these Frames, update all of the registers in `CalleeSavedRegisters`, the instruction pointer from the stored return address, and the stack pointer from the address saved on the stack.
295297

296298
### APIs
297299

src/coreclr/debug/runtimeinfo/datadescriptor.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,14 @@ CDAC_TYPE_FIELD(FaultingExceptionFrame, /*T_CONTEXT*/, TargetContext, cdac_data<
788788
#endif // FEATURE_EH_FUNCLETS
789789
CDAC_TYPE_END(FaultingExceptionFrame)
790790

791+
#if defined(TARGET_X86) && !defined(UNIX_X86_ABI)
792+
CDAC_TYPE_BEGIN(TailCallFrame)
793+
CDAC_TYPE_SIZE(sizeof(TailCallFrame))
794+
CDAC_TYPE_FIELD(TailCallFrame, /*CalleeSavedRegisters*/, CalleeSavedRegisters, cdac_data<TailCallFrame>::CalleeSavedRegisters)
795+
CDAC_TYPE_FIELD(TailCallFrame, /*pointer*/, ReturnAddress, cdac_data<TailCallFrame>::ReturnAddress)
796+
CDAC_TYPE_END(TailCallFrame)
797+
#endif // TARGET_X86 && !UNIX_X86_ABI
798+
791799
// CalleeSavedRegisters struct is different on each platform
792800
CDAC_TYPE_BEGIN(CalleeSavedRegisters)
793801
CDAC_TYPE_SIZE(sizeof(CalleeSavedRegisters))

src/coreclr/vm/frames.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2343,7 +2343,17 @@ class TailCallFrame : public Frame
23432343
}
23442344

23452345
void UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats = false);
2346+
2347+
friend struct cdac_data<TailCallFrame>;
2348+
};
2349+
2350+
template<>
2351+
struct cdac_data<TailCallFrame>
2352+
{
2353+
static constexpr size_t CalleeSavedRegisters = offsetof(TailCallFrame, m_regs);
2354+
static constexpr size_t ReturnAddress = offsetof(TailCallFrame, m_ReturnAddress);
23462355
};
2356+
23472357
#endif // TARGET_X86 && !UNIX_X86_ABI
23482358

23492359
//------------------------------------------------------------------------

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,5 @@ public enum DataType
114114
ResumableFrame,
115115
FaultingExceptionFrame,
116116
HijackFrame,
117+
TailCallFrame,
117118
}

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/FrameHandling/BaseFrameHandler.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ public virtual void HandleResumableFrame(ResumableFrame frame)
7272
_context.ReadFromAddress(_target, frame.TargetContextPtr);
7373
}
7474

75+
public virtual void HandleTailCallFrame(TailCallFrame tailCallFrame)
76+
{
77+
throw new InvalidOperationException("TailCallFrame handling is not implemented on the target platform.");
78+
}
79+
7580
protected void UpdateFromRegisterDict(IReadOnlyDictionary<string, TargetNUInt> registers)
7681
{
7782
foreach ((string name, TargetNUInt value) in registers)

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/FrameHandling/FrameIterator.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,12 @@ internal enum FrameType
3434

3535
HijackFrame,
3636

37+
TailCallFrame,
38+
3739
/* Other Frame Types not handled by the iterator */
3840
UnmanagedToManagedFrame,
3941
ComMethodFrame,
4042
ComPrestubMethodFrame,
41-
TailCallFrame,
4243
ProtectValueClassFrame,
4344
DebuggerClassInitMarkFrame,
4445
DebuggerExitFrame,
@@ -124,6 +125,10 @@ public void UpdateContextFromFrame(IPlatformAgnosticContext context)
124125
Data.HijackFrame hijackFrame = target.ProcessedData.GetOrAdd<Data.HijackFrame>(CurrentFrame.Address);
125126
GetFrameHandler(context).HandleHijackFrame(hijackFrame);
126127
return;
128+
case FrameType.TailCallFrame:
129+
Data.TailCallFrame tailCallFrame = target.ProcessedData.GetOrAdd<Data.TailCallFrame>(CurrentFrame.Address);
130+
GetFrameHandler(context).HandleTailCallFrame(tailCallFrame);
131+
return;
127132
default:
128133
// Unknown Frame type. This could either be a Frame that we don't know how to handle,
129134
// or a Frame that does not update the context.

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/FrameHandling/IPlatformFrameHandler.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ internal interface IPlatformFrameHandler
1818
void HandleResumableFrame(Data.ResumableFrame frame);
1919
void HandleFaultingExceptionFrame(Data.FaultingExceptionFrame frame);
2020
void HandleHijackFrame(Data.HijackFrame frame);
21+
void HandleTailCallFrame(Data.TailCallFrame frame);
2122
}

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/FrameHandling/X86FrameHandler.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,21 @@ public void HandleHijackFrame(HijackFrame frame)
3131
throw new NotImplementedException();
3232
}
3333

34+
public override void HandleTailCallFrame(TailCallFrame frame)
35+
{
36+
_context.Context.Eip = (uint)frame.ReturnAddress;
37+
38+
// The stack pointer is set to the address immediately after the TailCallFrame structure.
39+
if (_target.GetTypeInfo(DataType.TailCallFrame).Size is not uint tailCallFrameSize)
40+
{
41+
throw new InvalidOperationException("TailCallFrame missing size information");
42+
}
43+
_context.Context.Esp = (uint)(frame.Address + tailCallFrameSize);
44+
45+
CalleeSavedRegisters calleeSavedRegisters = _target.ProcessedData.GetOrAdd<Data.CalleeSavedRegisters>(frame.CalleeSavedRegisters);
46+
UpdateFromRegisterDict(calleeSavedRegisters.Registers);
47+
}
48+
3449
public override void HandleFuncEvalFrame(FuncEvalFrame funcEvalFrame)
3550
{
3651
Data.DebuggerEval debuggerEval = _target.ProcessedData.GetOrAdd<Data.DebuggerEval>(funcEvalFrame.DebuggerEvalPtr);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.Diagnostics.DataContractReader.Data;
5+
6+
internal class TailCallFrame : IData<TailCallFrame>
7+
{
8+
static TailCallFrame IData<TailCallFrame>.Create(Target target, TargetPointer address)
9+
=> new TailCallFrame(target, address);
10+
11+
public TailCallFrame(Target target, TargetPointer address)
12+
{
13+
Target.TypeInfo type = target.GetTypeInfo(DataType.TailCallFrame);
14+
Address = address;
15+
CalleeSavedRegisters = address + (ulong)type.Fields[nameof(CalleeSavedRegisters)].Offset;
16+
ReturnAddress = target.ReadPointer(address + (ulong)type.Fields[nameof(ReturnAddress)].Offset);
17+
}
18+
19+
public TargetPointer Address { get; }
20+
public TargetPointer CalleeSavedRegisters { get; }
21+
public TargetPointer ReturnAddress { get; }
22+
}

0 commit comments

Comments
 (0)