Skip to content

Commit a5d7490

Browse files
authored
[cDAC] Fixes for 32bit platforms (#116720)
* allow cdac to build on ARM32/x86 * modify DAC to properly sign extend firstNestedException * fix cDAC CodePointerFromAddress to properly handle nullptr * add missed conversions to ClrDataAddress * improve error messages
1 parent ad4e636 commit a5d7490

File tree

6 files changed

+100
-50
lines changed

6 files changed

+100
-50
lines changed

src/coreclr/debug/daccess/request.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -888,11 +888,11 @@ HRESULT ClrDataAccess::GetThreadData(CLRDATA_ADDRESS threadAddr, struct DacpThre
888888
#ifdef FEATURE_EH_FUNCLETS
889889
if (thread->m_ExceptionState.m_pCurrentTracker)
890890
{
891-
threadData->firstNestedException = PTR_HOST_TO_TADDR(
891+
threadData->firstNestedException = HOST_CDADDR(
892892
thread->m_ExceptionState.m_pCurrentTracker->m_pPrevNestedInfo);
893893
}
894894
#else
895-
threadData->firstNestedException = PTR_HOST_TO_TADDR(
895+
threadData->firstNestedException = HOST_CDADDR(
896896
thread->m_ExceptionState.m_currentExInfo.m_pPrevNestedInfo);
897897
#endif // FEATURE_EH_FUNCLETS
898898

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/CodePointerUtils.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ internal static class CodePointerUtils
1313

1414
internal static TargetCodePointer CodePointerFromAddress(TargetPointer address, Target target)
1515
{
16+
if (address == TargetPointer.Null)
17+
{
18+
return TargetCodePointer.Null;
19+
}
20+
1621
IPlatformMetadata metadata = target.Contracts.PlatformMetadata;
1722
CodePointerFlags flags = metadata.GetCodePointerFlags();
1823
if (flags.HasFlag(CodePointerFlags.HasArm32ThumbBit))

src/native/managed/cdac/mscordaccore_universal/Legacy/ClrDataStackWalk.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ int IXCLRDataStackWalk.Request(uint reqCode, uint inBufferSize, byte* inBuffer,
128128
IStackWalk sw = _target.Contracts.StackWalk;
129129
IStackDataFrameHandle frameData = _dataFrames.Current;
130130
TargetPointer frameAddr = sw.GetFrameAddress(frameData);
131-
*(ulong*)outBuffer = frameAddr.Value;
131+
*(ulong*)outBuffer = frameAddr.ToClrDataAddress(_target);
132132
hr = HResults.S_OK;
133133
break;
134134
default:

src/native/managed/cdac/mscordaccore_universal/Legacy/ConversionExtensions.cs

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

44
using System;
5+
using System.Diagnostics;
6+
using Microsoft.Diagnostics.DataContractReader.Contracts;
57

68
namespace Microsoft.Diagnostics.DataContractReader.Legacy;
79

810
internal static class ConversionExtensions
911
{
12+
private const uint Arm32ThumbBit = 1;
13+
1014
/// <summary>
1115
/// Converts a TargetPointer to a ClrDataAddress using sign extension if required.
1216
/// </summary>
@@ -24,21 +28,62 @@ public static ClrDataAddress ToClrDataAddress(this TargetPointer address, Target
2428

2529
/// <summary>
2630
/// Converts a ClrDataAddress to a TargetPointer, ensuring the address is within the valid range for the target platform.
31+
/// When overrideCheck is true, this will not check the range and will allow any address. This is used on legacy endpoints which
32+
/// may pass in invalid ClrDataAddress values.
2733
/// </summary>
28-
public static TargetPointer ToTargetPointer(this ClrDataAddress address, Target target)
34+
public static TargetPointer ToTargetPointer(this ClrDataAddress address, Target target, bool overrideCheck = false)
2935
{
3036
if (target.PointerSize == sizeof(ulong))
3137
{
3238
return new TargetPointer(address);
3339
}
3440
else
41+
{
42+
long signedAddr = (long)address.Value;
43+
if (!overrideCheck && (signedAddr > int.MaxValue || signedAddr < int.MinValue))
44+
{
45+
throw new ArgumentException($"ClrDataAddress 0x{address.Value:x} out of range for the target platform.", nameof(address));
46+
}
47+
return new TargetPointer((uint)address);
48+
}
49+
}
50+
51+
/// <summary>
52+
/// Converts a ClrDataAddress to a TargetCodePointer, ensuring the address is within the valid range for the target platform.
53+
/// </summary>
54+
public static TargetCodePointer ToTargetCodePointer(this ClrDataAddress address, Target target)
55+
{
56+
if (target.PointerSize == sizeof(ulong))
57+
{
58+
return new TargetCodePointer(address);
59+
}
60+
else
3561
{
3662
long signedAddr = (long)address.Value;
3763
if (signedAddr > int.MaxValue || signedAddr < int.MinValue)
3864
{
39-
throw new ArgumentException(nameof(address), "ClrDataAddress out of range for the target platform.");
65+
throw new ArgumentException($"ClrDataAddress 0x{address.Value:x} out of range for the target platform.", nameof(address));
4066
}
41-
return new TargetPointer((ulong)address);
67+
return new TargetCodePointer((uint)address);
68+
}
69+
}
70+
71+
/// <summary>
72+
/// Converts a TargetCodePointer to an address TargetPointer, removing any platform-specific bits such as the ARM32 Thumb bit or ARM64 pointer authentication.
73+
/// </summary>
74+
internal static TargetPointer ToAddress(this TargetCodePointer code, Target target)
75+
{
76+
IPlatformMetadata metadata = target.Contracts.PlatformMetadata;
77+
CodePointerFlags flags = metadata.GetCodePointerFlags();
78+
if (flags.HasFlag(CodePointerFlags.HasArm32ThumbBit))
79+
{
80+
return new TargetPointer(code.Value & ~Arm32ThumbBit);
81+
}
82+
else if (flags.HasFlag(CodePointerFlags.HasArm64PtrAuth))
83+
{
84+
throw new NotImplementedException($"{nameof(ToAddress)}: ARM64 with pointer authentication");
4285
}
86+
Debug.Assert(flags == default);
87+
return new TargetPointer(code.Value);
4388
}
4489
}

src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ int ISOSDacInterface.GetMethodDescData(ClrDataAddress addr, ClrDataAddress ip, D
438438
NativeCodeVersionHandle? activeNativeCodeVersion = null;
439439
if (ip != 0)
440440
{
441-
requestedNativeCodeVersion = nativeCodeContract.GetNativeCodeVersionForIP(new TargetCodePointer(ip));
441+
requestedNativeCodeVersion = nativeCodeContract.GetNativeCodeVersionForIP(ip.ToTargetCodePointer(_target));
442442
}
443443
else
444444
{
@@ -457,7 +457,7 @@ int ISOSDacInterface.GetMethodDescData(ClrDataAddress addr, ClrDataAddress ip, D
457457
if (nativeCodeAddr != TargetCodePointer.Null)
458458
{
459459
data->bHasNativeCode = 1;
460-
data->NativeCodeAddr = nativeCodeAddr.AsTargetPointer.ToClrDataAddress(_target);
460+
data->NativeCodeAddr = nativeCodeAddr.ToAddress(_target).ToClrDataAddress(_target);
461461
}
462462
else
463463
{
@@ -615,41 +615,41 @@ int ISOSDacInterface.GetMethodDescData(ClrDataAddress addr, ClrDataAddress ip, D
615615
Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}");
616616
if (hr == HResults.S_OK)
617617
{
618-
Debug.Assert(data->bHasNativeCode == dataLocal.bHasNativeCode);
619-
Debug.Assert(data->bIsDynamic == dataLocal.bIsDynamic);
620-
Debug.Assert(data->wSlotNumber == dataLocal.wSlotNumber);
621-
Debug.Assert(data->NativeCodeAddr == dataLocal.NativeCodeAddr);
622-
Debug.Assert(data->AddressOfNativeCodeSlot == dataLocal.AddressOfNativeCodeSlot);
623-
Debug.Assert(data->MethodDescPtr == dataLocal.MethodDescPtr);
624-
Debug.Assert(data->MethodTablePtr == dataLocal.MethodTablePtr);
625-
Debug.Assert(data->ModulePtr == dataLocal.ModulePtr);
626-
Debug.Assert(data->MDToken == dataLocal.MDToken);
627-
Debug.Assert(data->GCInfo == dataLocal.GCInfo);
628-
Debug.Assert(data->GCStressCodeCopy == dataLocal.GCStressCodeCopy);
618+
Debug.Assert(data->bHasNativeCode == dataLocal.bHasNativeCode, $"cDAC: {data->bHasNativeCode}, DAC: {dataLocal.bHasNativeCode}");
619+
Debug.Assert(data->bIsDynamic == dataLocal.bIsDynamic, $"cDAC: {data->bIsDynamic}, DAC: {dataLocal.bIsDynamic}");
620+
Debug.Assert(data->wSlotNumber == dataLocal.wSlotNumber, $"cDAC: {data->wSlotNumber}, DAC: {dataLocal.wSlotNumber}");
621+
Debug.Assert(data->NativeCodeAddr == dataLocal.NativeCodeAddr, $"cDAC: {data->NativeCodeAddr:x}, DAC: {dataLocal.NativeCodeAddr:x}");
622+
Debug.Assert(data->AddressOfNativeCodeSlot == dataLocal.AddressOfNativeCodeSlot, $"cDAC: {data->AddressOfNativeCodeSlot:x}, DAC: {dataLocal.AddressOfNativeCodeSlot:x}");
623+
Debug.Assert(data->MethodDescPtr == dataLocal.MethodDescPtr, $"cDAC: {data->MethodDescPtr:x}, DAC: {dataLocal.MethodDescPtr:x}");
624+
Debug.Assert(data->MethodTablePtr == dataLocal.MethodTablePtr, $"cDAC: {data->MethodTablePtr:x}, DAC: {dataLocal.MethodTablePtr:x}");
625+
Debug.Assert(data->ModulePtr == dataLocal.ModulePtr, $"cDAC: {data->ModulePtr:x}, DAC: {dataLocal.ModulePtr:x}");
626+
Debug.Assert(data->MDToken == dataLocal.MDToken, $"cDAC: {data->MDToken:x}, DAC: {dataLocal.MDToken:x}");
627+
Debug.Assert(data->GCInfo == dataLocal.GCInfo, $"cDAC: {data->GCInfo:x}, DAC: {dataLocal.GCInfo:x}");
628+
Debug.Assert(data->GCStressCodeCopy == dataLocal.GCStressCodeCopy, $"cDAC: {data->GCStressCodeCopy:x}, DAC: {dataLocal.GCStressCodeCopy:x}");
629629
// managedDynamicMethodObject is not currently populated by the cDAC API and may differ from legacyImpl.
630630
Debug.Assert(data->managedDynamicMethodObject == 0);
631-
Debug.Assert(data->requestedIP == dataLocal.requestedIP);
632-
Debug.Assert(data->cJittedRejitVersions == dataLocal.cJittedRejitVersions);
631+
Debug.Assert(data->requestedIP == dataLocal.requestedIP, $"cDAC: {data->requestedIP:x}, DAC: {dataLocal.requestedIP:x}");
632+
Debug.Assert(data->cJittedRejitVersions == dataLocal.cJittedRejitVersions, $"cDAC: {data->cJittedRejitVersions}, DAC: {dataLocal.cJittedRejitVersions}");
633633

634634
// rejitDataCurrent
635-
Debug.Assert(data->rejitDataCurrent.rejitID == dataLocal.rejitDataCurrent.rejitID);
636-
Debug.Assert(data->rejitDataCurrent.NativeCodeAddr == dataLocal.rejitDataCurrent.NativeCodeAddr);
637-
Debug.Assert(data->rejitDataCurrent.flags == dataLocal.rejitDataCurrent.flags);
635+
Debug.Assert(data->rejitDataCurrent.rejitID == dataLocal.rejitDataCurrent.rejitID, $"cDAC: {data->rejitDataCurrent.rejitID}, DAC: {dataLocal.rejitDataCurrent.rejitID}");
636+
Debug.Assert(data->rejitDataCurrent.NativeCodeAddr == dataLocal.rejitDataCurrent.NativeCodeAddr, $"cDAC: {data->rejitDataCurrent.NativeCodeAddr:x}, DAC: {dataLocal.rejitDataCurrent.NativeCodeAddr:x}");
637+
Debug.Assert(data->rejitDataCurrent.flags == dataLocal.rejitDataCurrent.flags, $"cDAC: {data->rejitDataCurrent.flags}, DAC: {dataLocal.rejitDataCurrent.flags}");
638638

639639
// rejitDataRequested
640-
Debug.Assert(data->rejitDataRequested.rejitID == dataLocal.rejitDataRequested.rejitID);
641-
Debug.Assert(data->rejitDataRequested.NativeCodeAddr == dataLocal.rejitDataRequested.NativeCodeAddr);
642-
Debug.Assert(data->rejitDataRequested.flags == dataLocal.rejitDataRequested.flags);
640+
Debug.Assert(data->rejitDataRequested.rejitID == dataLocal.rejitDataRequested.rejitID, $"cDAC: {data->rejitDataRequested.rejitID}, DAC: {dataLocal.rejitDataRequested.rejitID}");
641+
Debug.Assert(data->rejitDataRequested.NativeCodeAddr == dataLocal.rejitDataRequested.NativeCodeAddr, $"cDAC: {data->rejitDataRequested.NativeCodeAddr:x}, DAC: {dataLocal.rejitDataRequested.NativeCodeAddr:x}");
642+
Debug.Assert(data->rejitDataRequested.flags == dataLocal.rejitDataRequested.flags, $"cDAC: {data->rejitDataRequested.flags}, DAC: {dataLocal.rejitDataRequested.flags}");
643643

644644
// rgRevertedRejitData
645645
if (rgRevertedRejitData != null && rgRevertedRejitDataLocal != null)
646646
{
647-
Debug.Assert(cNeededRevertedRejitDataLocal == *pcNeededRevertedRejitData);
647+
Debug.Assert(cNeededRevertedRejitDataLocal == *pcNeededRevertedRejitData, $"cDAC: {*pcNeededRevertedRejitData}, DAC: {cNeededRevertedRejitDataLocal}");
648648
for (ulong i = 0; i < cNeededRevertedRejitDataLocal; i++)
649649
{
650-
Debug.Assert(rgRevertedRejitData[i].rejitID == rgRevertedRejitDataLocal[i].rejitID);
651-
Debug.Assert(rgRevertedRejitData[i].NativeCodeAddr == rgRevertedRejitDataLocal[i].NativeCodeAddr);
652-
Debug.Assert(rgRevertedRejitData[i].flags == rgRevertedRejitDataLocal[i].flags);
650+
Debug.Assert(rgRevertedRejitData[i].rejitID == rgRevertedRejitDataLocal[i].rejitID, $"cDAC: {rgRevertedRejitData[i].rejitID}, DAC: {rgRevertedRejitDataLocal[i].rejitID}");
651+
Debug.Assert(rgRevertedRejitData[i].NativeCodeAddr == rgRevertedRejitDataLocal[i].NativeCodeAddr, $"cDAC: {rgRevertedRejitData[i].NativeCodeAddr:x}, DAC: {rgRevertedRejitDataLocal[i].NativeCodeAddr:x}");
652+
Debug.Assert(rgRevertedRejitData[i].flags == rgRevertedRejitDataLocal[i].flags, $"cDAC: {rgRevertedRejitData[i].flags}, DAC: {rgRevertedRejitDataLocal[i].flags}");
653653
}
654654
}
655655
}
@@ -803,7 +803,7 @@ int ISOSDacInterface.GetMethodDescPtrFromIP(ClrDataAddress ip, ClrDataAddress* p
803803
IExecutionManager executionManager = _target.Contracts.ExecutionManager;
804804
IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
805805

806-
CodeBlockHandle? handle = executionManager.GetCodeBlockHandle(new TargetCodePointer(ip));
806+
CodeBlockHandle? handle = executionManager.GetCodeBlockHandle(ip.ToTargetCodePointer(_target));
807807
if (handle is CodeBlockHandle codeHandle)
808808
{
809809
TargetPointer methodDescAddr = executionManager.GetMethodDesc(codeHandle);
@@ -814,7 +814,7 @@ int ISOSDacInterface.GetMethodDescPtrFromIP(ClrDataAddress ip, ClrDataAddress* p
814814
// if validation fails, should return E_INVALIDARG
815815
rts.GetMethodDescHandle(methodDescAddr);
816816

817-
*ppMD = methodDescAddr.Value;
817+
*ppMD = methodDescAddr.ToClrDataAddress(_target);
818818
hr = HResults.S_OK;
819819
}
820820
catch (System.Exception)
@@ -963,7 +963,7 @@ int ISOSDacInterface.GetMethodTableName(ClrDataAddress mt, uint count, char* mtN
963963
try
964964
{
965965
Contracts.IRuntimeTypeSystem typeSystemContract = _target.Contracts.RuntimeTypeSystem;
966-
Contracts.TypeHandle methodTableHandle = typeSystemContract.GetTypeHandle(mt.ToTargetPointer(_target));
966+
Contracts.TypeHandle methodTableHandle = typeSystemContract.GetTypeHandle(mt.ToTargetPointer(_target, overrideCheck: true));
967967
if (typeSystemContract.IsFreeObjectMethodTable(methodTableHandle))
968968
{
969969
OutputBufferHelpers.CopyStringToBuffer(mtName, count, pNeeded, "Free");
@@ -1511,21 +1511,21 @@ int ISOSDacInterface.GetThreadData(ClrDataAddress thread, DacpThreadData* data)
15111511
Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}");
15121512
if (hr == HResults.S_OK)
15131513
{
1514-
Debug.Assert(data->corThreadId == dataLocal.corThreadId);
1515-
Debug.Assert(data->osThreadId == dataLocal.osThreadId);
1516-
Debug.Assert(data->state == dataLocal.state);
1517-
Debug.Assert(data->preemptiveGCDisabled == dataLocal.preemptiveGCDisabled);
1518-
Debug.Assert(data->allocContextPtr == dataLocal.allocContextPtr);
1519-
Debug.Assert(data->allocContextLimit == dataLocal.allocContextLimit);
1520-
Debug.Assert(data->fiberData == dataLocal.fiberData);
1521-
Debug.Assert(data->context == dataLocal.context);
1522-
Debug.Assert(data->domain == dataLocal.domain);
1523-
Debug.Assert(data->lockCount == dataLocal.lockCount);
1524-
Debug.Assert(data->pFrame == dataLocal.pFrame);
1525-
Debug.Assert(data->firstNestedException == dataLocal.firstNestedException);
1526-
Debug.Assert(data->teb == dataLocal.teb);
1527-
Debug.Assert(data->lastThrownObjectHandle == dataLocal.lastThrownObjectHandle);
1528-
Debug.Assert(data->nextThread == dataLocal.nextThread);
1514+
Debug.Assert(data->corThreadId == dataLocal.corThreadId, $"cDAC: {data->corThreadId}, DAC: {dataLocal.corThreadId}");
1515+
Debug.Assert(data->osThreadId == dataLocal.osThreadId, $"cDAC: {data->osThreadId}, DAC: {dataLocal.osThreadId}");
1516+
Debug.Assert(data->state == dataLocal.state, $"cDAC: {data->state}, DAC: {dataLocal.state}");
1517+
Debug.Assert(data->preemptiveGCDisabled == dataLocal.preemptiveGCDisabled, $"cDAC: {data->preemptiveGCDisabled}, DAC: {dataLocal.preemptiveGCDisabled}");
1518+
Debug.Assert(data->allocContextPtr == dataLocal.allocContextPtr, $"cDAC: {data->allocContextPtr:x}, DAC: {dataLocal.allocContextPtr:x}");
1519+
Debug.Assert(data->allocContextLimit == dataLocal.allocContextLimit, $"cDAC: {data->allocContextLimit:x}, DAC: {dataLocal.allocContextLimit:x}");
1520+
Debug.Assert(data->fiberData == dataLocal.fiberData, $"cDAC: {data->fiberData:x}, DAC: {dataLocal.fiberData:x}");
1521+
Debug.Assert(data->context == dataLocal.context, $"cDAC: {data->context:x}, DAC: {dataLocal.context:x}");
1522+
Debug.Assert(data->domain == dataLocal.domain, $"cDAC: {data->domain:x}, DAC: {dataLocal.domain:x}");
1523+
Debug.Assert(data->lockCount == dataLocal.lockCount, $"cDAC: {data->lockCount}, DAC: {dataLocal.lockCount}");
1524+
Debug.Assert(data->pFrame == dataLocal.pFrame, $"cDAC: {data->pFrame:x}, DAC: {dataLocal.pFrame:x}");
1525+
Debug.Assert(data->firstNestedException == dataLocal.firstNestedException, $"cDAC: {data->firstNestedException:x}, DAC: {dataLocal.firstNestedException:x}");
1526+
Debug.Assert(data->teb == dataLocal.teb, $"cDAC: {data->teb:x}, DAC: {dataLocal.teb:x}");
1527+
Debug.Assert(data->lastThrownObjectHandle == dataLocal.lastThrownObjectHandle, $"cDAC: {data->lastThrownObjectHandle:x}, DAC: {dataLocal.lastThrownObjectHandle:x}");
1528+
Debug.Assert(data->nextThread == dataLocal.nextThread, $"cDAC: {data->nextThread:x}, DAC: {dataLocal.nextThread:x}");
15291529
}
15301530
}
15311531
#endif

src/native/managed/compile-native.proj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<SupportsNativeAotComponents Condition="'$(SupportsNativeAotComponents)' == '' and '$(HostOS)' != '$(TargetOS)'">false</SupportsNativeAotComponents>
2424
<!-- unsupported targets -->
2525
<SupportsNativeAotComponents Condition="'$(SupportsNativeAotComponents)' == '' and '$(DotNetBuildSourceOnly)' == 'true'">false</SupportsNativeAotComponents>
26-
<SupportsNativeAotComponents Condition="'$(SupportsNativeAotComponents)' == '' and ('$(TargetArchitecture)' == 'arm' or '$(TargetArchitecture)' == 'armel' or '$(TargetArchitecture)' == 'riscv64')">false</SupportsNativeAotComponents>
26+
<SupportsNativeAotComponents Condition="'$(SupportsNativeAotComponents)' == '' and ('$(TargetArchitecture)' == 'armel' or '$(TargetArchitecture)' == 'riscv64')">false</SupportsNativeAotComponents>
2727
<SupportsNativeAotComponents Condition="'$(SupportsNativeAotComponents)' == '' and ('$(TargetsWindows)' == 'true' or '$(TargetsOSX)' == 'true' or ('$(TargetsLinux)' == 'true' and '$(TargetsAndroid)' != 'true' and '$(TargetsLinuxMusl)' != 'true'))">true</SupportsNativeAotComponents>
2828
<SupportsNativeAotComponents Condition="'$(SupportsNativeAotComponents)' == ''">false</SupportsNativeAotComponents>
2929
</PropertyGroup>

0 commit comments

Comments
 (0)