Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
b5140fe
Implement partial ExecutionManager GetFuncletStartAddress
May 6, 2025
89e9505
allow nativeAOT compilation on x86
May 16, 2025
02f14ef
implement GCInfo and RelativeAddress lookup
May 19, 2025
99a7f56
wip
May 21, 2025
6829dda
wip working PushedArgDepth
May 22, 2025
f71b823
finish the bones of x86 unwinder
May 22, 2025
3fe4a8a
continued testing and bug fixes
May 27, 2025
6b58012
fix issues with ICFs
May 28, 2025
fba0091
add docs for ExecutionManager changes
May 28, 2025
7f6b388
add doc for IsFunclet
May 28, 2025
2917ef9
fix some build issues
May 28, 2025
34a7169
move gcinfo decoding into folder
May 28, 2025
1b19fb2
move x86 context next to other contexts
May 28, 2025
3092546
add some doc comments
May 28, 2025
3b02419
remove debug print helpers
May 28, 2025
05e5909
use constant
May 29, 2025
5e813b6
add x86 stackwalk docs
May 29, 2025
1505bbb
lazily read ArgTable
Jun 2, 2025
e648dda
add datadescriptors for CalleeSavedRegisters on x86
Jun 2, 2025
2335f6d
remove unused GCInfo decoders
Jun 2, 2025
7f06960
fix stackwalk logic for x86
Jun 2, 2025
570659d
fix UnwindEspFrame
Jun 2, 2025
7e75287
R2R find GCInfo correctly
Jun 2, 2025
d7a99f0
Handle parsing ArgTab correctly when ArgTabOffset is not present
Jun 2, 2025
d6ecb88
loosen GetUsefulGlobals assertion
Jun 2, 2025
e1feb95
remove prints
Jun 2, 2025
aeb8dc4
refactor ReadyToRunJitManager to de-duplicate RuntimeFunction lookup …
Jun 2, 2025
61fbed5
comments/cleanup InfoHdr.cs
Jun 3, 2025
af6a9b1
add rts docs
Jun 3, 2025
82eb5aa
remove r2r GCDecoder change
Jun 3, 2025
ebf14c3
clean up GCInfo.cs
Jun 3, 2025
350b993
move x86 specific stackwalking helpers into namespace
Jun 3, 2025
233615e
import nit
Jun 3, 2025
dce3e02
fix
Jun 3, 2025
dff89fd
overriding increment/decrement is not required
Jun 3, 2025
2170a9f
fix some TODOs in the X86 Unwinder
Jun 3, 2025
9710bde
use xor for InfoHdr REV_PINVOKE_OFFSET
Jun 3, 2025
43eed4f
convert to use ClrDataAddress
Jun 4, 2025
7909b7d
add readytorunheader datadescriptors
Jun 5, 2025
408c566
clean up R2RJitManager
Jun 5, 2025
55e26f9
improve GCInfoVersion handling
max-charlamb Jun 5, 2025
675673b
always check for JitHalt
max-charlamb Jun 5, 2025
0bcaaf0
remove magic numbers in RTS contract
max-charlamb Jun 5, 2025
26d4b7d
remove todos
max-charlamb Jun 5, 2025
581ea4a
Merge remote-tracking branch 'origin/main' into cdac-funclets-x86-wip-2
max-charlamb Jun 5, 2025
7e4d18f
remove unused datadescriptor
max-charlamb Jun 5, 2025
905b3dc
fix managed tests
max-charlamb Jun 6, 2025
116f178
Merge remote-tracking branch 'origin/main' into cdac-funclets-x86-wip-2
max-charlamb Jun 9, 2025
38c5048
Merge branch 'cdac-funclets-x86-wip-2' of github.com:max-charlamb/run…
max-charlamb Jun 9, 2025
4b2df0f
update to match #116388
max-charlamb Jun 9, 2025
c8bba50
clean up docs
max-charlamb Jun 9, 2025
9160287
use span for const data
max-charlamb Jun 13, 2025
0a5b3d5
fix unwinder issue
max-charlamb Jun 13, 2025
ef1281e
add check for GCInfo version
max-charlamb Jun 13, 2025
423ff27
comments
max-charlamb Jun 16, 2025
fe4ead1
remove FeatureEHFunclets check in modified code
max-charlamb Jun 16, 2025
4c96d48
add comment explaining loosened GetUsefulGlobals assertions
max-charlamb Jun 16, 2025
cf8dd64
word
max-charlamb Jun 16, 2025
49d1631
Merge branch 'main' into cdac-funclets-x86-wip-2
max-charlamb Jun 16, 2025
7b18c84
Merge branch 'main' into cdac-funclets-x86-wip-2
max-charlamb Jun 17, 2025
8b7f03f
fix merge conflict
max-charlamb Jun 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 31 additions & 4 deletions docs/design/datacontracts/ExecutionManager.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,19 @@ struct CodeBlockHandle
TargetPointer GetMethodDesc(CodeBlockHandle codeInfoHandle);
// Get the instruction pointer address of the start of the code block
TargetCodePointer GetStartAddress(CodeBlockHandle codeInfoHandle);
// Get the instruction pointer address of the start of the funclet containing the code block
TargetCodePointer GetFuncletStartAddress(CodeBlockHandle codeInfoHandle);
// Gets the unwind info of the code block at the specified code pointer
TargetPointer GetUnwindInfo(CodeBlockHandle codeInfoHandle, TargetCodePointer ip);
// Gets the base address the UnwindInfo of codeInfoHandle is relative to.
TargetPointer GetUnwindInfo(CodeBlockHandle codeInfoHandle);
// Gets the base address the UnwindInfo of codeInfoHandle is relative to
TargetPointer GetUnwindInfoBaseAddress(CodeBlockHandle codeInfoHandle);
// Gets the GCInfo associated with the code block and its version
void GetGCInfo(CodeBlockHandle codeInfoHandle, out TargetPointer gcInfo, out uint gcVersion);
// Gets the offset of the codeInfoHandle inside of the code block
TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle);

// Extension Methods (implemented in terms of other APIs)
bool IsFunclet(CodeBlockHandle codeInfoHandle);
```

## Version 1
Expand Down Expand Up @@ -59,6 +68,7 @@ Data descriptors used:
| `RealCodeHeader` | `MethodDesc` | Pointer to the corresponding `MethodDesc` |
| `RealCodeHeader` | `NumUnwindInfos` | Number of Unwind Infos |
| `RealCodeHeader` | `UnwindInfos` | Start address of Unwind Infos |
| `RealCodeHeader` | `GCInfo` | Pointer to the GCInfo encoding |
| `Module` | `ReadyToRunInfo` | Pointer to the `ReadyToRunInfo` for the module |
| `ReadyToRunInfo` | `CompositeInfo` | Pointer to composite R2R info - or itself for non-composite |
| `ReadyToRunInfo` | `NumRuntimeFunctions` | Number of `RuntimeFunctions` |
Expand Down Expand Up @@ -220,7 +230,7 @@ class CodeBlock
}
```

The `GetMethodDesc` and `GetStartAddress` APIs extract fields of the `CodeBlock`:
The `GetMethodDesc`, `GetStartAddress`, and `GetRelativeOffset` APIs extract fields of the `CodeBlock`:

```csharp
TargetPointer IExecutionManager.GetMethodDesc(CodeBlockHandle codeInfoHandle)
Expand All @@ -234,9 +244,15 @@ The `GetMethodDesc` and `GetStartAddress` APIs extract fields of the `CodeBlock`
/* find CodeBlock info for codeInfoHandle.Address*/
return info.StartAddress;
}

TargetNUInt IExecutionManager.GetRelativeOffset(CodeBlockHandle codeInfoHandle)
{
/* find CodeBlock info for codeInfoHandle.Address*/
return info.RelativeOffset;
}
```

`GetUnwindInfo` gets the Windows style unwind data in the form of `RUNTIME_FUNCTION` which has a platform dependent implementation. The ExecutionManager delegates to the JitManager implementations as the unwind infos (`RUNTIME_FUNCTION`) are stored differently on jitted and R2R code.
`IExecutionManager.GetUnwindInfo` gets the Windows style unwind data in the form of `RUNTIME_FUNCTION` which has a platform dependent implementation. The ExecutionManager delegates to the JitManager implementations as the unwind infos (`RUNTIME_FUNCTION`) are stored differently on jitted and R2R code.

* For jitted code (`EEJitManager`) a list of sorted `RUNTIME_FUNCTION` are stored on the `RealCodeHeader` which is accessed in the same was as `GetMethodInfo` described above. The correct `RUNTIME_FUNCTION` is found by binary searching the list based on IP.

Expand All @@ -245,6 +261,17 @@ The `GetMethodDesc` and `GetStartAddress` APIs extract fields of the `CodeBlock`
Unwind info (`RUNTIME_FUNCTION`) use relative addressing. For managed code, these values are relative to the start of the code's containing range in the RangeSectionMap (described below). This could be the beginning of a `CodeHeap` for jitted code or the base address of the loaded image for ReadyToRun code.
`GetUnwindInfoBaseAddress` finds this base address for a given `CodeBlockHandle`.

`IExecutionManager.GetGCInfo` gets a pointer to the relevant GCInfo for a `CodeBlockHandle`. The ExecutionManager delegates to the JitManager implementations as the GCInfo is stored differently on jitted and R2R code.

* For jitted code (`EEJitManager`) a pointer to the `GCInfo` is stored on the `RealCodeHeader` which is accessed in the same was as `GetMethodInfo` described above. This can simply be returned as is.

* For R2R code (`ReadyToRunJitManager`), the `GCInfo` is stored directly after the `UnwindData`. This in turn is found by looking up the `UnwindInfo` (`RUNTIME_FUNCTION`) and reading the `UnwindData` offset. We find the `UnwindInfo` as described above in `IExecutionManager.GetUnwindInfo`. Once we have the relevant unwind data, we calculate the size of the unwind data and return a pointer to the following byte (first byte of the GCInfo).
// TODO(cdacX86): Add information on finding the size of the unwind info.

`IExecutionManager.GetFuncletStartAddress` finds the start of the code blocks funclet. This will be different than the methods start address `GetStartAddress` if the current code block is inside of a funclet. To find the funclet start address, we get the unwind info corresponding to the code block using `IExecutionManager.GetUnwindInfo`. We then parse the unwind info to find the begin address (relative to the unwind info base address) and return the unwind info base address + unwind info begin address.

`IsFunclet` is implemented in terms of `IExecutionManager.GetStartAddress` and `IExecutionManager.GetFuncletStartAddress`. If the values are the same, the code block handle is not a funclet. If they are different, it is a funclet.

### RangeSectionMap

The range section map logically partitions the entire 32-bit or 64-bit addressable space into chunks.
Expand Down
13 changes: 13 additions & 0 deletions docs/design/datacontracts/StackWalk.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,3 +331,16 @@ TargetPointer GetFrameAddress(IStackDataFrameHandle stackDataFrameHandle);
```csharp
string GetFrameName(TargetPointer frameIdentifier);
```

### x86 Specifics

The x86 platform has some major differences to other platforms. In general this stems from the platform being older and not having a defined unwinding codes. Instead, to unwind managed frames, we rely on GCInfo associated with JITted code. For the unwind, we do not defer to a 'Windows like' native unwinder, instead the custom unwinder implementation was ported to managed code.

#### GCInfo Parsing
The GCInfo structure is encoded using a variety of formats to optimize for speed of decoding and size on disk. For information on decoding and parsing refer to [GC Information Encoding for x86](../coreclr/jit/jit-gc-info-x86.md).

#### Unwinding Algorithm

The x86 architecture uses a custom unwinding algorithm defined in `gc_unwind_x86.inl`. The cDAC uses a copy of this algorithm ported to managed code in `X86Unwinder.cs`.

Currently there isn't great documentation on the algorithm, beyond inspecting the implementations.
1 change: 1 addition & 0 deletions src/coreclr/debug/runtimeinfo/datadescriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,7 @@ CDAC_TYPE_END(RangeSection)
CDAC_TYPE_BEGIN(RealCodeHeader)
CDAC_TYPE_INDETERMINATE(RealCodeHeader)
CDAC_TYPE_FIELD(RealCodeHeader, /*pointer*/, MethodDesc, offsetof(RealCodeHeader, phdrMDesc))
CDAC_TYPE_FIELD(RealCodeHeader, /*pointer*/, GCInfo, offsetof(RealCodeHeader, phdrJitGCInfo))
#ifdef FEATURE_EH_FUNCLETS
CDAC_TYPE_FIELD(RealCodeHeader, /*uint32*/, NumUnwindInfos, offsetof(RealCodeHeader, nUnwindInfos))
CDAC_TYPE_FIELD(RealCodeHeader, /* T_RUNTIME_FUNCTION */, UnwindInfos, offsetof(RealCodeHeader, unwindInfos))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ public class InfoHdrDecoder {
private const uint HAS_UNTRACKED = 0xFFFFFFFF;
private const uint HAS_GS_COOKIE_OFFSET = 0xFFFFFFFF;
private const uint HAS_SYNC_OFFSET = 0xFFFFFFFF;
private const uint HAS_REV_PINVOKE_FRAME_OFFSET = 0xFFFFFFFF;
private const uint HAS_REV_PINVOKE_FRAME_OFFSET = 0xFFFFFFFF; // is this wrong??
private const uint HAS_NOGCREGIONS = 0xFFFFFFFF;
private const uint YES = HAS_VARPTR;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.Diagnostics.DataContractReader.Contracts.Extensions;

public static class IExecutionManagerExtensions
{
public static bool IsFunclet(this IExecutionManager eman, CodeBlockHandle codeBlockHandle)
{
return eman.GetStartAddress(codeBlockHandle) != eman.GetFuncletStartAddress(codeBlockHandle);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ public interface IExecutionManager : IContract
CodeBlockHandle? GetCodeBlockHandle(TargetCodePointer ip) => throw new NotImplementedException();
TargetPointer GetMethodDesc(CodeBlockHandle codeInfoHandle) => throw new NotImplementedException();
TargetCodePointer GetStartAddress(CodeBlockHandle codeInfoHandle) => throw new NotImplementedException();
TargetPointer GetUnwindInfo(CodeBlockHandle codeInfoHandle, TargetCodePointer ip) => throw new NotImplementedException();
TargetCodePointer GetFuncletStartAddress(CodeBlockHandle codeInfoHandle) => throw new NotImplementedException();
TargetPointer GetUnwindInfo(CodeBlockHandle codeInfoHandle) => throw new NotImplementedException();
TargetPointer GetUnwindInfoBaseAddress(CodeBlockHandle codeInfoHandle) => throw new NotImplementedException();
void GetGCInfo(CodeBlockHandle codeInfoHandle, out TargetPointer gcInfo, out uint gcVersion) => throw new NotImplementedException();
TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle) => throw new NotImplementedException();
}

public readonly struct ExecutionManager : IExecutionManager
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ namespace Microsoft.Diagnostics.DataContractReader;
public static implicit operator ulong(TargetPointer p) => p.Value;
public static implicit operator TargetPointer(ulong v) => new TargetPointer(v);

public static TargetPointer operator ++(TargetPointer p) => new TargetPointer(p.Value + 1);
public static TargetPointer operator --(TargetPointer p) => new TargetPointer(p.Value - 1);
public static bool operator ==(TargetPointer left, TargetPointer right) => left.Value == right.Value;
public static bool operator !=(TargetPointer left, TargetPointer right) => left.Value != right.Value;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ internal partial class ExecutionManagerCore<T> : IExecutionManager
{
private sealed class EEJitManager : JitManager
{
private const uint GCINFO_VERSION = 4;

private readonly INibbleMap _nibbleMap;
private readonly RuntimeFunctionLookup _runtimeFunctions;
public EEJitManager(Target target, INibbleMap nibbleMap) : base(target)
Expand Down Expand Up @@ -85,6 +87,30 @@ public override TargetPointer GetUnwindInfo(RangeSection rangeSection, TargetCod
return _runtimeFunctions.GetRuntimeFunctionAddress(unwindInfos, index);
}

public override void GetGCInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, out TargetPointer gcInfo, out uint gcVersion)
{
gcInfo = TargetPointer.Null;
gcVersion = 0;

// EEJitManager::GetGCInfoToken
if (rangeSection.IsRangeList)
return;

if (rangeSection.Data == null)
throw new ArgumentException(nameof(rangeSection));

TargetPointer codeStart = FindMethodCode(rangeSection, jittedCodeAddress);
if (codeStart == TargetPointer.Null)
return;
Debug.Assert(codeStart.Value <= jittedCodeAddress.Value);

if (!GetRealCodeHeader(rangeSection, codeStart, out Data.RealCodeHeader? realCodeHeader))
return;

gcVersion = GCINFO_VERSION;
gcInfo = realCodeHeader.GCInfo;
}

private TargetPointer FindMethodCode(RangeSection rangeSection, TargetCodePointer jittedCodeAddress)
{
// EEJitManager::FindMethodCode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ internal partial class ExecutionManagerCore<T> : IExecutionManager
{
private sealed class ReadyToRunJitManager : JitManager
{
private const uint GCINFO_VERSION = 4;

private readonly uint _runtimeFunctionSize;
private readonly PtrHashMapLookup _hashMap;
private readonly HotColdLookup _hotCold;
Expand Down Expand Up @@ -122,6 +124,42 @@ public override TargetPointer GetUnwindInfo(RangeSection rangeSection, TargetCod
return _runtimeFunctions.GetRuntimeFunctionAddress(r2rInfo.RuntimeFunctions, index);
}

public override void GetGCInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, out TargetPointer gcInfo, out uint gcVersion)
{
gcInfo = TargetPointer.Null;
gcVersion = 0;

// ReadyToRunJitManager::GetGCInfoToken
if (rangeSection.Data == null)
throw new ArgumentException(nameof(rangeSection));

Debug.Assert(rangeSection.Data.R2RModule != TargetPointer.Null);

Data.Module r2rModule = Target.ProcessedData.GetOrAdd<Data.Module>(rangeSection.Data.R2RModule);
Debug.Assert(r2rModule.ReadyToRunInfo != TargetPointer.Null);
Data.ReadyToRunInfo r2rInfo = Target.ProcessedData.GetOrAdd<Data.ReadyToRunInfo>(r2rModule.ReadyToRunInfo);

// Check if address is in a thunk
if (IsStubCodeBlockThunk(rangeSection.Data, r2rInfo, jittedCodeAddress))
return;

// Find the relative address that we are looking for
TargetPointer addr = CodePointerUtils.AddressFromCodePointer(jittedCodeAddress, Target);
TargetPointer imageBase = rangeSection.Data.RangeBegin;
TargetPointer relativeAddr = addr - imageBase;

uint index;
if (!_runtimeFunctions.TryGetRuntimeFunctionIndexForAddress(r2rInfo.RuntimeFunctions, r2rInfo.NumRuntimeFunctions, relativeAddr, out index))
return;

Data.RuntimeFunction runtimeFunction = _runtimeFunctions.GetRuntimeFunction(r2rInfo.RuntimeFunctions, index);

TargetPointer unwindInfo = runtimeFunction.UnwindData + imageBase;
uint unwindDataSize = sizeof(uint); // TODO(cdac): This is platform specific and maybe needs its own contract. Current value is for x86
gcInfo = unwindInfo + unwindDataSize;
gcVersion = GCINFO_VERSION; // TODO(cdac): This depends on the major version of the runtime.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the best way to handle this versioning would be to split it out into its own contract. That way we can use the contract versioning mechanism to handle versioning the format.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current contract versioning mechanism wouldn't exactly fit, but could be adapted. Multiple GCInfo formats could potentially exist within a project (old R2R code). I don't know if this is a supported scenario.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if this is a supported scenario.

Generally speaking it is supported by the runtime. There's only enforcement of minimum R2R format version, and IIRC version 2 and 3 of GC info could co-exist in the same process for a while.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im pretty sure that versioning the GC Info format is a backwards-incompatible change for R2R (and forces a minimum major version bump). There's only one decoder in the runtime and SOS only has a copy of the most recent GCInfo layout.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GC info version 2 and 3 had the same format. IIRC they differed in some offset adjustment and I'm somewhat convinced that they did co-exist for a moment without a minimum R2R version bump. I think there are some GC info version changes that are backwards compatible even if it was rare. That said, I am happy to defer to the subject expert on this one - @VSadov - who probably remembers the exact details of the version changes he has made.

Copy link
Member

@VSadov VSadov Jun 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GC info 2 and 3 had exactly the same format/encoding, but had semantical differences.

v3 started including volatile registers at call sites. v2 was expressive enough to include that, just did not.

I.E. the same GC info parser/dumper would work with either v2 or v3, but if GC root reporting for call sites relies entirely on GCInfo, including reporting of volatile registers, then v2 cannot be used by the runtime.

}

private bool IsStubCodeBlockThunk(Data.RangeSection rangeSection, Data.ReadyToRunInfo r2rInfo, TargetCodePointer jittedCodeAddress)
{
if (r2rInfo.DelayLoadMethodCallThunks == TargetPointer.Null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ protected JitManager(Target target)

public abstract bool GetMethodInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out CodeBlock? info);
public abstract TargetPointer GetUnwindInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress);
public abstract void GetGCInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, out TargetPointer gcInfo, out uint gcVersion);
}

private sealed class RangeSection
Expand Down Expand Up @@ -180,18 +181,41 @@ TargetCodePointer IExecutionManager.GetStartAddress(CodeBlockHandle codeInfoHand
return info.StartAddress;
}

TargetPointer IExecutionManager.GetUnwindInfo(CodeBlockHandle codeInfoHandle, TargetCodePointer ip)
TargetCodePointer IExecutionManager.GetFuncletStartAddress(CodeBlockHandle codeInfoHandle)
{
if (!_codeInfos.TryGetValue(codeInfoHandle.Address, out CodeBlock? info))
throw new InvalidOperationException($"{nameof(CodeBlock)} not found for {codeInfoHandle.Address}");

RangeSection range = RangeSection.Find(_target, _topRangeSectionMap, _rangeSectionMapLookup, ip);
RangeSection range = RangeSection.Find(_target, _topRangeSectionMap, _rangeSectionMapLookup, codeInfoHandle.Address.Value);
if (range.Data == null)
throw new InvalidOperationException("Unable to get runtime function address");

JitManager jitManager = GetJitManager(range.Data);
TargetPointer runtimeFunctionPtr = jitManager.GetUnwindInfo(range, codeInfoHandle.Address.Value);

if (runtimeFunctionPtr == TargetPointer.Null)
throw new InvalidOperationException("Unable to get runtime function address");

Data.RuntimeFunction runtimeFunction = _target.ProcessedData.GetOrAdd<Data.RuntimeFunction>(runtimeFunctionPtr);

// TODO(cdac): EXCEPTION_DATA_SUPPORTS_FUNCTION_FRAGMENTS, implement iterating over fragments until finding
// non-fragment RuntimeFunction

return range.Data.RangeBegin + runtimeFunction.BeginAddress;
}

TargetPointer IExecutionManager.GetUnwindInfo(CodeBlockHandle codeInfoHandle)
{
if (!_codeInfos.TryGetValue(codeInfoHandle.Address, out CodeBlock? info))
throw new InvalidOperationException($"{nameof(CodeBlock)} not found for {codeInfoHandle.Address}");

RangeSection range = RangeSection.Find(_target, _topRangeSectionMap, _rangeSectionMapLookup, codeInfoHandle.Address.Value);
if (range.Data == null)
return TargetPointer.Null;

JitManager jitManager = GetJitManager(range.Data);

return jitManager.GetUnwindInfo(range, ip);
return jitManager.GetUnwindInfo(range, codeInfoHandle.Address.Value);
}

TargetPointer IExecutionManager.GetUnwindInfoBaseAddress(CodeBlockHandle codeInfoHandle)
Expand All @@ -205,4 +229,29 @@ TargetPointer IExecutionManager.GetUnwindInfoBaseAddress(CodeBlockHandle codeInf

return range.Data.RangeBegin;
}

void IExecutionManager.GetGCInfo(CodeBlockHandle codeInfoHandle, out TargetPointer gcInfo, out uint gcVersion)
{
gcInfo = TargetPointer.Null;
gcVersion = 0;

if (!_codeInfos.TryGetValue(codeInfoHandle.Address, out CodeBlock? info))
throw new InvalidOperationException($"{nameof(CodeBlock)} not found for {codeInfoHandle.Address}");

RangeSection range = RangeSection.Find(_target, _topRangeSectionMap, _rangeSectionMapLookup, codeInfoHandle.Address.Value);
if (range.Data == null)
return;

JitManager jitManager = GetJitManager(range.Data);
jitManager.GetGCInfo(range, codeInfoHandle.Address.Value, out gcInfo, out gcVersion);
}


TargetNUInt IExecutionManager.GetRelativeOffset(CodeBlockHandle codeInfoHandle)
{
if (!_codeInfos.TryGetValue(codeInfoHandle.Address, out CodeBlock? info))
throw new InvalidOperationException($"{nameof(CodeBlock)} not found for {codeInfoHandle.Address}");

return info.RelativeOffset;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ internal ExecutionManager_1(Target target, Data.RangeSectionMap topRangeSectionM
public CodeBlockHandle? GetCodeBlockHandle(TargetCodePointer ip) => _executionManagerCore.GetCodeBlockHandle(ip);
public TargetPointer GetMethodDesc(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetMethodDesc(codeInfoHandle);
public TargetCodePointer GetStartAddress(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetStartAddress(codeInfoHandle);
public TargetPointer GetUnwindInfo(CodeBlockHandle codeInfoHandle, TargetCodePointer ip) => _executionManagerCore.GetUnwindInfo(codeInfoHandle, ip);
public TargetCodePointer GetFuncletStartAddress(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetFuncletStartAddress(codeInfoHandle);
public TargetPointer GetUnwindInfo(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetUnwindInfo(codeInfoHandle);
public TargetPointer GetUnwindInfoBaseAddress(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetUnwindInfoBaseAddress(codeInfoHandle);
public void GetGCInfo(CodeBlockHandle codeInfoHandle, out TargetPointer gcInfo, out uint gcVersion) => _executionManagerCore.GetGCInfo(codeInfoHandle, out gcInfo, out gcVersion);
public TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetRelativeOffset(codeInfoHandle);
}
Loading
Loading