mirror of https://github.com/dotnet/runtime
Merge 9ac4101265
into 123627ba0f
This commit is contained in:
commit
5d205b8f5d
|
@ -43,6 +43,16 @@ namespace
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
int WriteToTargetCallback(uint64_t addr, const uint8_t* buff, uint32_t count, void* context)
|
||||
{
|
||||
ICorDebugMutableDataTarget* target = static_cast<ICorDebugMutableDataTarget*>(context);
|
||||
HRESULT hr = target->WriteVirtual((CORDB_ADDRESS)addr, buff, count);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
int ReadThreadContext(uint32_t threadId, uint32_t contextFlags, uint32_t contextBufferSize, uint8_t* contextBuffer, void* context)
|
||||
{
|
||||
ICorDebugDataTarget* target = reinterpret_cast<ICorDebugDataTarget*>(context);
|
||||
|
@ -54,7 +64,7 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
CDAC CDAC::Create(uint64_t descriptorAddr, ICorDebugDataTarget* target, IUnknown* legacyImpl)
|
||||
CDAC CDAC::Create(uint64_t descriptorAddr, ICorDebugMutableDataTarget* target, IUnknown* legacyImpl)
|
||||
{
|
||||
HMODULE cdacLib;
|
||||
if (!TryLoadCDACLibrary(&cdacLib))
|
||||
|
@ -64,7 +74,7 @@ CDAC CDAC::Create(uint64_t descriptorAddr, ICorDebugDataTarget* target, IUnknown
|
|||
_ASSERTE(init != nullptr);
|
||||
|
||||
intptr_t handle;
|
||||
if (init(descriptorAddr, &ReadFromTargetCallback, &ReadThreadContext, target, &handle) != 0)
|
||||
if (init(descriptorAddr, &ReadFromTargetCallback, &WriteToTargetCallback, &ReadThreadContext, target, &handle) != 0)
|
||||
{
|
||||
::FreeLibrary(cdacLib);
|
||||
return {};
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
class CDAC final
|
||||
{
|
||||
public: // static
|
||||
static CDAC Create(uint64_t descriptorAddr, ICorDebugDataTarget *pDataTarget, IUnknown* legacyImpl);
|
||||
static CDAC Create(uint64_t descriptorAddr, ICorDebugMutableDataTarget *pDataTarget, IUnknown* legacyImpl);
|
||||
|
||||
public:
|
||||
CDAC() = default;
|
||||
|
|
|
@ -7033,7 +7033,7 @@ CLRDataCreateInstance(REFIID iid,
|
|||
HRESULT qiRes = pClrDataAccess->QueryInterface(IID_IUnknown, (void**)&thisImpl);
|
||||
_ASSERTE(SUCCEEDED(qiRes));
|
||||
CDAC& cdac = pClrDataAccess->m_cdac;
|
||||
cdac = CDAC::Create(contractDescriptorAddr, pClrDataAccess->m_pTarget, thisImpl);
|
||||
cdac = CDAC::Create(contractDescriptorAddr, pClrDataAccess->m_pMutableTarget, thisImpl);
|
||||
if (cdac.IsValid())
|
||||
{
|
||||
// Get SOS interfaces from the cDAC if available.
|
||||
|
|
|
@ -72,6 +72,13 @@ public abstract class Target
|
|||
/// <param name="buffer">Destination to copy the bytes, the number of bytes to read is the span length</param>
|
||||
public abstract void ReadBuffer(ulong address, Span<byte> buffer);
|
||||
|
||||
/// <summary>
|
||||
/// Write some bytes to the target
|
||||
/// </summary>
|
||||
/// <param name="address">The address where to start writing</param>
|
||||
/// <param name="buffer">Source of the bytes to write, the number of bytes to write is the span length</param>
|
||||
public abstract void WriteBuffer(ulong address, Span<byte> buffer);
|
||||
|
||||
/// <summary>
|
||||
/// Read a null-terminated UTF-8 string from the target
|
||||
/// </summary>
|
||||
|
@ -133,6 +140,15 @@ public abstract class Target
|
|||
/// <returns>Value read from the target</returns>
|
||||
public abstract T Read<T>(ulong address) where T : unmanaged, IBinaryInteger<T>, IMinMaxValue<T>;
|
||||
|
||||
/// <summary>
|
||||
/// Write a value to the target in target endianness
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of value to write</typeparam>
|
||||
/// <param name="address">Address to start writing to</param>
|
||||
/// <param name="value">Value to write</param>
|
||||
/// <returns>True if the write was successful, false otherwise</returns>
|
||||
public abstract bool Write<T>(ulong address, T value) where T : unmanaged, IBinaryInteger<T>, IMinMaxValue<T>;
|
||||
|
||||
/// <summary>
|
||||
/// Read a target pointer from a span of bytes
|
||||
/// </summary>
|
||||
|
|
|
@ -32,8 +32,7 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
}
|
||||
|
||||
private readonly Configuration _config;
|
||||
private readonly Reader _reader;
|
||||
|
||||
private readonly DataTargetDelegates _dataTargetDelegates;
|
||||
private readonly Dictionary<string, int> _contracts = [];
|
||||
private readonly IReadOnlyDictionary<string, GlobalValue> _globals = new Dictionary<string, GlobalValue>();
|
||||
private readonly Dictionary<DataType, Target.TypeInfo> _knownTypes = [];
|
||||
|
@ -43,6 +42,7 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
public override DataCache ProcessedData { get; }
|
||||
|
||||
public delegate int ReadFromTargetDelegate(ulong address, Span<byte> bufferToFill);
|
||||
public delegate int WriteToTargetDelegate(ulong address, Span<byte> bufferToWrite);
|
||||
public delegate int GetTargetThreadContextDelegate(uint threadId, uint contextFlags, Span<byte> bufferToFill);
|
||||
|
||||
/// <summary>
|
||||
|
@ -56,18 +56,19 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
public static bool TryCreate(
|
||||
ulong contractDescriptor,
|
||||
ReadFromTargetDelegate readFromTarget,
|
||||
WriteToTargetDelegate writeToTarget,
|
||||
GetTargetThreadContextDelegate getThreadContext,
|
||||
[NotNullWhen(true)] out ContractDescriptorTarget? target)
|
||||
{
|
||||
Reader reader = new Reader(readFromTarget, getThreadContext);
|
||||
DataTargetDelegates dataTargetDelegates = new DataTargetDelegates(readFromTarget, writeToTarget, getThreadContext);
|
||||
if (TryReadContractDescriptor(
|
||||
contractDescriptor,
|
||||
reader,
|
||||
dataTargetDelegates,
|
||||
out Configuration config,
|
||||
out ContractDescriptorParser.ContractDescriptor? descriptor,
|
||||
out TargetPointer[] pointerData))
|
||||
{
|
||||
target = new ContractDescriptorTarget(config, descriptor!, pointerData, reader);
|
||||
target = new ContractDescriptorTarget(config, descriptor!, pointerData, dataTargetDelegates);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -89,6 +90,7 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
ContractDescriptorParser.ContractDescriptor contractDescriptor,
|
||||
TargetPointer[] globalPointerValues,
|
||||
ReadFromTargetDelegate readFromTarget,
|
||||
WriteToTargetDelegate writeToTarget,
|
||||
GetTargetThreadContextDelegate getThreadContext,
|
||||
bool isLittleEndian,
|
||||
int pointerSize)
|
||||
|
@ -97,15 +99,15 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
new Configuration { IsLittleEndian = isLittleEndian, PointerSize = pointerSize },
|
||||
contractDescriptor,
|
||||
globalPointerValues,
|
||||
new Reader(readFromTarget, getThreadContext));
|
||||
new DataTargetDelegates(readFromTarget, writeToTarget, getThreadContext));
|
||||
}
|
||||
|
||||
private ContractDescriptorTarget(Configuration config, ContractDescriptorParser.ContractDescriptor descriptor, TargetPointer[] pointerData, Reader reader)
|
||||
private ContractDescriptorTarget(Configuration config, ContractDescriptorParser.ContractDescriptor descriptor, TargetPointer[] pointerData, DataTargetDelegates dataTargetDelegates)
|
||||
{
|
||||
Contracts = new CachingContractRegistry(this, this.TryGetContractVersion);
|
||||
ProcessedData = new DataCache(this);
|
||||
_config = config;
|
||||
_reader = reader;
|
||||
_dataTargetDelegates = dataTargetDelegates;
|
||||
|
||||
_contracts = descriptor.Contracts ?? [];
|
||||
|
||||
|
@ -187,7 +189,7 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
// See docs/design/datacontracts/contract-descriptor.md
|
||||
private static bool TryReadContractDescriptor(
|
||||
ulong address,
|
||||
Reader reader,
|
||||
DataTargetDelegates dataTargetDelegates,
|
||||
out Configuration config,
|
||||
out ContractDescriptorParser.ContractDescriptor? descriptor,
|
||||
out TargetPointer[] pointerData)
|
||||
|
@ -198,7 +200,7 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
|
||||
// Magic - uint64_t
|
||||
Span<byte> buffer = stackalloc byte[sizeof(ulong)];
|
||||
if (reader.ReadFromTarget(address, buffer) < 0)
|
||||
if (dataTargetDelegates.ReadFromTarget(address, buffer) < 0)
|
||||
return false;
|
||||
|
||||
address += sizeof(ulong);
|
||||
|
@ -209,7 +211,7 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
return false;
|
||||
|
||||
// Flags - uint32_t
|
||||
if (!TryRead(address, isLittleEndian, reader, out uint flags))
|
||||
if (!TryRead(address, isLittleEndian, dataTargetDelegates, out uint flags))
|
||||
return false;
|
||||
|
||||
address += sizeof(uint);
|
||||
|
@ -220,19 +222,19 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
config = new Configuration { IsLittleEndian = isLittleEndian, PointerSize = pointerSize };
|
||||
|
||||
// Descriptor size - uint32_t
|
||||
if (!TryRead(address, config.IsLittleEndian, reader, out uint descriptorSize))
|
||||
if (!TryRead(address, config.IsLittleEndian, dataTargetDelegates, out uint descriptorSize))
|
||||
return false;
|
||||
|
||||
address += sizeof(uint);
|
||||
|
||||
// Descriptor - char*
|
||||
if (!TryReadPointer(address, config, reader, out TargetPointer descriptorAddr))
|
||||
if (!TryReadPointer(address, config, dataTargetDelegates, out TargetPointer descriptorAddr))
|
||||
return false;
|
||||
|
||||
address += (uint)pointerSize;
|
||||
|
||||
// Pointer data count - uint32_t
|
||||
if (!TryRead(address, config.IsLittleEndian, reader, out uint pointerDataCount))
|
||||
if (!TryRead(address, config.IsLittleEndian, dataTargetDelegates, out uint pointerDataCount))
|
||||
return false;
|
||||
|
||||
address += sizeof(uint);
|
||||
|
@ -241,14 +243,14 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
address += sizeof(uint);
|
||||
|
||||
// Pointer data - uintptr_t*
|
||||
if (!TryReadPointer(address, config, reader, out TargetPointer pointerDataAddr))
|
||||
if (!TryReadPointer(address, config, dataTargetDelegates, out TargetPointer pointerDataAddr))
|
||||
return false;
|
||||
|
||||
// Read descriptor
|
||||
Span<byte> descriptorBuffer = descriptorSize <= StackAllocByteThreshold
|
||||
? stackalloc byte[(int)descriptorSize]
|
||||
: new byte[(int)descriptorSize];
|
||||
if (reader.ReadFromTarget(descriptorAddr.Value, descriptorBuffer) < 0)
|
||||
if (dataTargetDelegates.ReadFromTarget(descriptorAddr.Value, descriptorBuffer) < 0)
|
||||
return false;
|
||||
|
||||
descriptor = ContractDescriptorParser.ParseCompact(descriptorBuffer);
|
||||
|
@ -259,7 +261,7 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
pointerData = new TargetPointer[pointerDataCount];
|
||||
for (int i = 0; i < pointerDataCount; i++)
|
||||
{
|
||||
if (!TryReadPointer(pointerDataAddr.Value + (uint)(i * pointerSize), config, reader, out pointerData[i]))
|
||||
if (!TryReadPointer(pointerDataAddr.Value + (uint)(i * pointerSize), config, dataTargetDelegates, out pointerData[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -280,7 +282,7 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
public override bool TryGetThreadContext(ulong threadId, uint contextFlags, Span<byte> buffer)
|
||||
{
|
||||
// Underlying API only supports 32-bit thread IDs, mask off top 32 bits
|
||||
int hr = _reader.GetThreadContext((uint)(threadId & uint.MaxValue), contextFlags, buffer);
|
||||
int hr = _dataTargetDelegates.GetThreadContext((uint)(threadId & uint.MaxValue), contextFlags, buffer);
|
||||
return hr == 0;
|
||||
}
|
||||
|
||||
|
@ -292,17 +294,17 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
/// <returns>Value read from the target</returns>
|
||||
public override T Read<T>(ulong address)
|
||||
{
|
||||
if (!TryRead(address, _config.IsLittleEndian, _reader, out T value))
|
||||
if (!TryRead(address, _config.IsLittleEndian, _dataTargetDelegates, out T value))
|
||||
throw new InvalidOperationException($"Failed to read {typeof(T)} at 0x{address:x8}.");
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private static bool TryRead<T>(ulong address, bool isLittleEndian, Reader reader, out T value) where T : unmanaged, IBinaryInteger<T>, IMinMaxValue<T>
|
||||
private static bool TryRead<T>(ulong address, bool isLittleEndian, DataTargetDelegates dataTargetDelegates, out T value) where T : unmanaged, IBinaryInteger<T>, IMinMaxValue<T>
|
||||
{
|
||||
value = default;
|
||||
Span<byte> buffer = stackalloc byte[sizeof(T)];
|
||||
if (reader.ReadFromTarget(address, buffer) < 0)
|
||||
if (dataTargetDelegates.ReadFromTarget(address, buffer) < 0)
|
||||
return false;
|
||||
|
||||
return isLittleEndian
|
||||
|
@ -310,6 +312,32 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
: T.TryReadBigEndian(buffer, !IsSigned<T>(), out value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a value to the target in target endianness
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of value to write</typeparam>
|
||||
/// <param name="address">Address to start writing to</param>
|
||||
/// <returns>True if the value is successfully written. Throws an InvalidOperationException otherwise.</returns>
|
||||
public override bool Write<T>(ulong address, T value)
|
||||
{
|
||||
if (!TryWrite(address, _config.IsLittleEndian, _dataTargetDelegates, value))
|
||||
throw new InvalidOperationException($"Failed to write {typeof(T)} at 0x{address:x8}.");
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryWrite<T>(ulong address, bool isLittleEndian, DataTargetDelegates dataTargetDelegates, T value) where T : unmanaged, IBinaryInteger<T>, IMinMaxValue<T>
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(T)];
|
||||
int bytesWritten = default;
|
||||
bool success = isLittleEndian
|
||||
? value.TryWriteLittleEndian(buffer, out bytesWritten)
|
||||
: value.TryWriteBigEndian(buffer, out bytesWritten);
|
||||
if (!success || bytesWritten != buffer.Length || dataTargetDelegates.WriteToTarget(address, buffer) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static T Read<T>(ReadOnlySpan<byte> bytes, bool isLittleEndian) where T : unmanaged, IBinaryInteger<T>, IMinMaxValue<T>
|
||||
{
|
||||
if (sizeof(T) != bytes.Length)
|
||||
|
@ -335,7 +363,18 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
|
||||
private bool TryReadBuffer(ulong address, Span<byte> buffer)
|
||||
{
|
||||
return _reader.ReadFromTarget(address, buffer) >= 0;
|
||||
return _dataTargetDelegates.ReadFromTarget(address, buffer) >= 0;
|
||||
}
|
||||
|
||||
public override void WriteBuffer(ulong address, Span<byte> buffer)
|
||||
{
|
||||
if (!TryWriteBuffer(address, buffer))
|
||||
throw new InvalidOperationException($"Failed to write {buffer.Length} bytes at 0x{address:x8}.");
|
||||
}
|
||||
|
||||
private bool TryWriteBuffer(ulong address, Span<byte> buffer)
|
||||
{
|
||||
return _dataTargetDelegates.WriteToTarget(address, buffer) >= 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
@ -351,7 +390,7 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
/// <returns>Pointer read from the target</returns>}
|
||||
public override TargetPointer ReadPointer(ulong address)
|
||||
{
|
||||
if (!TryReadPointer(address, _config, _reader, out TargetPointer pointer))
|
||||
if (!TryReadPointer(address, _config, _dataTargetDelegates, out TargetPointer pointer))
|
||||
throw new InvalidOperationException($"Failed to read pointer at 0x{address:x8}.");
|
||||
|
||||
return pointer;
|
||||
|
@ -456,33 +495,33 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
/// <returns>Value read from the target</returns>
|
||||
public override TargetNUInt ReadNUInt(ulong address)
|
||||
{
|
||||
if (!TryReadNUInt(address, _config, _reader, out ulong value))
|
||||
if (!TryReadNUInt(address, _config, _dataTargetDelegates, out ulong value))
|
||||
throw new InvalidOperationException($"Failed to read nuint at 0x{address:x8}.");
|
||||
|
||||
return new TargetNUInt(value);
|
||||
}
|
||||
|
||||
private static bool TryReadPointer(ulong address, Configuration config, Reader reader, out TargetPointer pointer)
|
||||
private static bool TryReadPointer(ulong address, Configuration config, DataTargetDelegates dataTargetDelegates, out TargetPointer pointer)
|
||||
{
|
||||
pointer = TargetPointer.Null;
|
||||
if (!TryReadNUInt(address, config, reader, out ulong value))
|
||||
if (!TryReadNUInt(address, config, dataTargetDelegates, out ulong value))
|
||||
return false;
|
||||
|
||||
pointer = new TargetPointer(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryReadNUInt(ulong address, Configuration config, Reader reader, out ulong value)
|
||||
private static bool TryReadNUInt(ulong address, Configuration config, DataTargetDelegates dataTargetDelegates, out ulong value)
|
||||
{
|
||||
value = 0;
|
||||
if (config.PointerSize == sizeof(uint)
|
||||
&& TryRead(address, config.IsLittleEndian, reader, out uint value32))
|
||||
&& TryRead(address, config.IsLittleEndian, dataTargetDelegates, out uint value32))
|
||||
{
|
||||
value = value32;
|
||||
return true;
|
||||
}
|
||||
else if (config.PointerSize == sizeof(ulong)
|
||||
&& TryRead(address, config.IsLittleEndian, reader, out ulong value64))
|
||||
&& TryRead(address, config.IsLittleEndian, dataTargetDelegates, out ulong value64))
|
||||
{
|
||||
value = value64;
|
||||
return true;
|
||||
|
@ -657,8 +696,9 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
}
|
||||
}
|
||||
|
||||
private readonly struct Reader(
|
||||
private readonly struct DataTargetDelegates(
|
||||
ReadFromTargetDelegate readFromTarget,
|
||||
WriteToTargetDelegate writeToTarget,
|
||||
GetTargetThreadContextDelegate getThreadContext)
|
||||
{
|
||||
public int ReadFromTarget(ulong address, Span<byte> buffer)
|
||||
|
@ -673,5 +713,9 @@ public sealed unsafe class ContractDescriptorTarget : Target
|
|||
{
|
||||
return getThreadContext(threadId, contextFlags, buffer);
|
||||
}
|
||||
public int WriteToTarget(ulong address, Span<byte> buffer)
|
||||
{
|
||||
return writeToTarget(address, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ extern "C"
|
|||
int cdac_reader_init(
|
||||
uint64_t descriptor,
|
||||
int(*read_from_target)(uint64_t, uint8_t*, uint32_t, void*),
|
||||
int(*write_to_target)(uint64_t, const uint8_t*, uint32_t, void*),
|
||||
int(*read_thread_context)(uint32_t, uint32_t, uint32_t, uint8_t*, void*),
|
||||
void* read_context,
|
||||
/*out*/ intptr_t* handle);
|
||||
|
|
|
@ -16,8 +16,9 @@ internal static class Entrypoints
|
|||
private static unsafe int Init(
|
||||
ulong descriptor,
|
||||
delegate* unmanaged<ulong, byte*, uint, void*, int> readFromTarget,
|
||||
delegate* unmanaged<ulong, byte*, uint, void*, int> writeToTarget,
|
||||
delegate* unmanaged<uint, uint, uint, byte*, void*, int> readThreadContext,
|
||||
void* readContext,
|
||||
void* delegateContext,
|
||||
IntPtr* handle)
|
||||
{
|
||||
// TODO: [cdac] Better error code/details
|
||||
|
@ -27,14 +28,21 @@ internal static class Entrypoints
|
|||
{
|
||||
fixed (byte* bufferPtr = buffer)
|
||||
{
|
||||
return readFromTarget(address, bufferPtr, (uint)buffer.Length, readContext);
|
||||
return readFromTarget(address, bufferPtr, (uint)buffer.Length, delegateContext);
|
||||
}
|
||||
},
|
||||
(address, buffer) =>
|
||||
{
|
||||
fixed (byte* bufferPtr = buffer)
|
||||
{
|
||||
return writeToTarget(address, bufferPtr, (uint)buffer.Length, delegateContext);
|
||||
}
|
||||
},
|
||||
(threadId, contextFlags, buffer) =>
|
||||
{
|
||||
fixed (byte* bufferPtr = buffer)
|
||||
{
|
||||
return readThreadContext(threadId, contextFlags, (uint)buffer.Length, bufferPtr, readContext);
|
||||
return readThreadContext(threadId, contextFlags, (uint)buffer.Length, bufferPtr, delegateContext);
|
||||
}
|
||||
},
|
||||
out ContractDescriptorTarget? target))
|
||||
|
@ -124,6 +132,14 @@ internal static class Entrypoints
|
|||
return dataTarget.ReadVirtual(address, bufferPtr, (uint)buffer.Length, &bytesRead);
|
||||
}
|
||||
},
|
||||
(address, buffer) =>
|
||||
{
|
||||
fixed (byte* bufferPtr = buffer)
|
||||
{
|
||||
uint bytesWritten;
|
||||
return dataTarget.WriteVirtual(address, bufferPtr, (uint)buffer.Length, &bytesWritten);
|
||||
}
|
||||
},
|
||||
(threadId, contextFlags, bufferToFill) =>
|
||||
{
|
||||
fixed (byte* bufferPtr = bufferToFill)
|
||||
|
|
|
@ -11,6 +11,15 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy;
|
|||
// See src/coreclr/inc/sospriv.idl
|
||||
|
||||
#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value
|
||||
|
||||
internal enum CLRDataOtherNotifyFlag
|
||||
{
|
||||
CLRDATA_NOTIFY_ON_MODULE_LOAD = 0x1,
|
||||
CLRDATA_NOTIFY_ON_MODULE_UNLOAD = 0x2,
|
||||
CLRDATA_NOTIFY_ON_EXCEPTION = 0x4,
|
||||
CLRDATA_NOTIFY_ON_EXCEPTION_CATCH_ENTER = 0x8
|
||||
}
|
||||
|
||||
internal struct DacpThreadStoreData
|
||||
{
|
||||
public int threadCount;
|
||||
|
|
|
@ -233,7 +233,55 @@ internal sealed unsafe partial class SOSDacImpl : IXCLRDataProcess, IXCLRDataPro
|
|||
return hr;
|
||||
}
|
||||
int IXCLRDataProcess.SetOtherNotificationFlags(uint flags)
|
||||
=> _legacyProcess is not null ? _legacyProcess.SetOtherNotificationFlags(flags) : HResults.E_NOTIMPL;
|
||||
{
|
||||
int hr = HResults.S_OK;
|
||||
try
|
||||
{
|
||||
if ((flags & ~((uint)CLRDataOtherNotifyFlag.CLRDATA_NOTIFY_ON_MODULE_LOAD |
|
||||
(uint)CLRDataOtherNotifyFlag.CLRDATA_NOTIFY_ON_MODULE_UNLOAD |
|
||||
(uint)CLRDataOtherNotifyFlag.CLRDATA_NOTIFY_ON_EXCEPTION |
|
||||
(uint)CLRDataOtherNotifyFlag.CLRDATA_NOTIFY_ON_EXCEPTION_CATCH_ENTER)) != 0)
|
||||
{
|
||||
hr = HResults.E_INVALIDARG;
|
||||
}
|
||||
else
|
||||
{
|
||||
TargetPointer dacNotificationFlags = _target.ReadGlobalPointer(Constants.Globals.DacNotificationFlags);
|
||||
_target.Write<uint>(dacNotificationFlags, flags);
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
hr = ex.HResult;
|
||||
}
|
||||
#if DEBUG
|
||||
if (_legacyProcess is not null)
|
||||
{
|
||||
int hrLocal = default;
|
||||
uint flagsLocal = default;
|
||||
// have to read the flags like this and not with GetOtherNotificationFlags
|
||||
// because the legacy DAC cache will not be updated when we set the flags in cDAC
|
||||
// so we need to verify without using the legacy DAC
|
||||
hrLocal = HResults.S_OK;
|
||||
try
|
||||
{
|
||||
flagsLocal = _target.Read<uint>(_target.ReadGlobalPointer(Constants.Globals.DacNotificationFlags));
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
hrLocal = ex.HResult;
|
||||
}
|
||||
Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}");
|
||||
if (hr == HResults.S_OK)
|
||||
{
|
||||
Debug.Assert(flags == flagsLocal);
|
||||
}
|
||||
// update the DAC cache
|
||||
_legacyProcess.SetOtherNotificationFlags(flags);
|
||||
}
|
||||
#endif
|
||||
return hr;
|
||||
}
|
||||
|
||||
int IXCLRDataProcess.StartEnumMethodDefinitionsByAddress(ClrDataAddress address, ulong* handle)
|
||||
=> _legacyProcess is not null ? _legacyProcess.StartEnumMethodDefinitionsByAddress(address, handle) : HResults.E_NOTIMPL;
|
||||
|
|
|
@ -145,7 +145,7 @@ public class CodeVersionsTests
|
|||
|
||||
TestPlaceholderTarget target = new TestPlaceholderTarget(
|
||||
arch,
|
||||
builder.Builder.GetReadContext().ReadFromTarget,
|
||||
builder.Builder.GetMemoryContext().ReadFromTarget,
|
||||
builder.Types);
|
||||
|
||||
IContractFactory<ICodeVersions> cvfactory = new CodeVersionsFactory();
|
||||
|
|
|
@ -178,7 +178,7 @@ internal class ContractDescriptorBuilder : MockMemorySpace.Builder
|
|||
if (_created)
|
||||
throw new InvalidOperationException("Context already created");
|
||||
ulong contractDescriptorAddress = CreateDescriptorFragments();
|
||||
MockMemorySpace.ReadContext context = GetReadContext();
|
||||
return ContractDescriptorTarget.TryCreate(contractDescriptorAddress, context.ReadFromTarget, null, out target);
|
||||
MockMemorySpace.MemoryContext memoryContext = GetMemoryContext();
|
||||
return ContractDescriptorTarget.TryCreate(contractDescriptorAddress, memoryContext.ReadFromTarget, memoryContext.WriteToTarget, null, out target);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -183,6 +183,25 @@ public unsafe class TargetTests
|
|||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[ClassData(typeof(MockTarget.StdArch))]
|
||||
public void WriteValue(MockTarget.Architecture arch)
|
||||
{
|
||||
TargetTestHelpers targetTestHelpers = new(arch);
|
||||
ContractDescriptorBuilder builder = new(targetTestHelpers);
|
||||
uint expected = 0xdeadbeef;
|
||||
ulong addr = 0x1000;
|
||||
|
||||
MockMemorySpace.HeapFragment fragment = new() { Address = addr, Data = new byte[4] };
|
||||
builder.AddHeapFragment(fragment);
|
||||
|
||||
bool success = builder.TryCreateTarget(out ContractDescriptorTarget? target);
|
||||
Assert.True(success);
|
||||
bool writeSuccess = target.Write<uint>(addr, expected);
|
||||
Assert.True(writeSuccess);
|
||||
Assert.Equal(expected, target.Read<uint>(addr));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[ClassData(typeof(MockTarget.StdArch))]
|
||||
public void ReadUtf16String(MockTarget.Architecture arch)
|
||||
|
|
|
@ -42,7 +42,7 @@ public class DacStreamsTests
|
|||
builder = configure(builder);
|
||||
}
|
||||
|
||||
var target = new TestPlaceholderTarget(arch, builder.GetReadContext().ReadFromTarget, DacStreamsTypes, DacStreamsGlobals);
|
||||
var target = new TestPlaceholderTarget(arch, builder.GetMemoryContext().ReadFromTarget, DacStreamsTypes, DacStreamsGlobals);
|
||||
target.SetContracts(Mock.Of<ContractRegistry>(
|
||||
c => c.DacStreams == ((IContractFactory<IDacStreams>)new DacStreamsFactory()).CreateContract(target, 1)));
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ public class ExecutionManagerTests
|
|||
private static Target CreateTarget(MockDescriptors.ExecutionManager emBuilder)
|
||||
{
|
||||
var arch = emBuilder.Builder.TargetTestHelpers.Arch;
|
||||
TestPlaceholderTarget.ReadFromTargetDelegate reader = emBuilder.Builder.GetReadContext().ReadFromTarget;
|
||||
TestPlaceholderTarget.ReadFromTargetDelegate reader = emBuilder.Builder.GetMemoryContext().ReadFromTarget;
|
||||
var target = new TestPlaceholderTarget(arch, reader, emBuilder.Types, emBuilder.Globals);
|
||||
IContractFactory<IExecutionManager> emfactory = new ExecutionManagerFactory();
|
||||
ContractRegistry reg = Mock.Of<ContractRegistry>(
|
||||
|
|
|
@ -25,7 +25,7 @@ public class HashMapTests
|
|||
TargetPointer mapAddress = hashMap.CreateMap(entries);
|
||||
TargetPointer ptrMapAddress = hashMap.CreatePtrMap(entries);
|
||||
|
||||
Target target = new TestPlaceholderTarget(builder.TargetTestHelpers.Arch, builder.GetReadContext().ReadFromTarget, hashMap.Types, hashMap.Globals);
|
||||
Target target = new TestPlaceholderTarget(builder.TargetTestHelpers.Arch, builder.GetMemoryContext().ReadFromTarget, hashMap.Types, hashMap.Globals);
|
||||
|
||||
var lookup = HashMapLookup.Create(target);
|
||||
var ptrLookup = PtrHashMapLookup.Create(target);
|
||||
|
@ -61,7 +61,7 @@ public class HashMapTests
|
|||
TargetPointer mapAddress = hashMap.CreateMap(entries);
|
||||
TargetPointer ptrMapAddress = hashMap.CreatePtrMap(entries);
|
||||
|
||||
Target target = new TestPlaceholderTarget(builder.TargetTestHelpers.Arch, builder.GetReadContext().ReadFromTarget, hashMap.Types, hashMap.Globals);
|
||||
Target target = new TestPlaceholderTarget(builder.TargetTestHelpers.Arch, builder.GetMemoryContext().ReadFromTarget, hashMap.Types, hashMap.Globals);
|
||||
|
||||
var lookup = HashMapLookup.Create(target);
|
||||
var ptrLookup = PtrHashMapLookup.Create(target);
|
||||
|
@ -86,7 +86,7 @@ public class HashMapTests
|
|||
TargetPointer mapAddress = hashMap.CreateMap(entries);
|
||||
TargetPointer ptrMapAddress = hashMap.CreatePtrMap(entries);
|
||||
|
||||
Target target = new TestPlaceholderTarget(builder.TargetTestHelpers.Arch, builder.GetReadContext().ReadFromTarget, hashMap.Types, hashMap.Globals);
|
||||
Target target = new TestPlaceholderTarget(builder.TargetTestHelpers.Arch, builder.GetMemoryContext().ReadFromTarget, hashMap.Types, hashMap.Globals);
|
||||
|
||||
{
|
||||
var lookup = HashMapLookup.Create(target);
|
||||
|
|
|
@ -11,11 +11,11 @@ public class NibbleMapTestsBase
|
|||
{
|
||||
internal static Target CreateTarget(NibbleMapTestBuilderBase nibbleMapTestBuilder)
|
||||
{
|
||||
MockMemorySpace.ReadContext readContext = new()
|
||||
MockMemorySpace.MemoryContext memoryContext = new()
|
||||
{
|
||||
HeapFragments = new[] { nibbleMapTestBuilder.NibbleMapFragment }
|
||||
};
|
||||
return new TestPlaceholderTarget(nibbleMapTestBuilder.Arch, readContext.ReadFromTarget);
|
||||
return new TestPlaceholderTarget(nibbleMapTestBuilder.Arch, memoryContext.ReadFromTarget);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ public class RangeSectionMapTests
|
|||
public void TestLookupFail(MockTarget.Architecture arch)
|
||||
{
|
||||
var builder = MockDescriptors.ExecutionManager.CreateRangeSection(arch);
|
||||
var target = new TestPlaceholderTarget(arch, builder.GetReadContext().ReadFromTarget);
|
||||
var target = new TestPlaceholderTarget(arch, builder.GetMemoryContext().ReadFromTarget);
|
||||
|
||||
var rsla = RangeSectionMap.Create(target);
|
||||
|
||||
|
@ -33,7 +33,7 @@ public class RangeSectionMapTests
|
|||
var length = 0x1000u;
|
||||
var value = 0x0a0a_0a0au;
|
||||
builder.InsertAddressRange(inputPC, length, value);
|
||||
var target = new TestPlaceholderTarget(arch, builder.GetReadContext().ReadFromTarget);
|
||||
var target = new TestPlaceholderTarget(arch, builder.GetMemoryContext().ReadFromTarget);
|
||||
|
||||
var rsla = RangeSectionMap.Create(target);
|
||||
|
||||
|
@ -48,7 +48,7 @@ public class RangeSectionMapTests
|
|||
public void TestGetIndexForLevel(MockTarget.Architecture arch)
|
||||
{
|
||||
// Exhaustively test GetIndexForLevel for all possible values of the byte for each level
|
||||
var target = new TestPlaceholderTarget(arch, new MockMemorySpace.ReadContext().ReadFromTarget);
|
||||
var target = new TestPlaceholderTarget(arch, new MockMemorySpace.MemoryContext().ReadFromTarget);
|
||||
var rsla = RangeSectionMap.Create(target);
|
||||
int numLevels = arch.Is64Bit ? 5 : 2;
|
||||
// the bits 0..effectiveRange - 1 are not handled the map and are irrelevant
|
||||
|
|
|
@ -34,7 +34,7 @@ public class RuntimeFunctionTests
|
|||
uint[] entries = [0x100, 0x1f0, 0x1000, 0x2000, 0xa000];
|
||||
TargetPointer addr = runtimeFunctions.AddRuntimeFunctions(entries);
|
||||
|
||||
Target target = new TestPlaceholderTarget(builder.TargetTestHelpers.Arch, builder.GetReadContext().ReadFromTarget, runtimeFunctions.Types);
|
||||
Target target = new TestPlaceholderTarget(builder.TargetTestHelpers.Arch, builder.GetMemoryContext().ReadFromTarget, runtimeFunctions.Types);
|
||||
RuntimeFunctionLookup lookup = RuntimeFunctionLookup.Create(target);
|
||||
|
||||
for (uint i = 0; i < entries.Length; i++)
|
||||
|
@ -59,7 +59,7 @@ public class RuntimeFunctionTests
|
|||
uint[] entries = [0x100, 0x1f0, 0x1000, 0x2000, 0xa000];
|
||||
TargetPointer addr = runtimeFunctions.AddRuntimeFunctions(entries);
|
||||
|
||||
TestPlaceholderTarget target = new TestPlaceholderTarget(builder.TargetTestHelpers.Arch, builder.GetReadContext().ReadFromTarget, runtimeFunctions.Types);
|
||||
TestPlaceholderTarget target = new TestPlaceholderTarget(builder.TargetTestHelpers.Arch, builder.GetMemoryContext().ReadFromTarget, runtimeFunctions.Types);
|
||||
ContractRegistry reg = Mock.Of<ContractRegistry>(
|
||||
c => c.PlatformMetadata == new Mock<Contracts.IPlatformMetadata>().Object);
|
||||
target.SetContracts(reg);
|
||||
|
@ -84,7 +84,7 @@ public class RuntimeFunctionTests
|
|||
uint[] entries = [0x100, 0x1f0];
|
||||
TargetPointer addr = runtimeFunctions.AddRuntimeFunctions(entries);
|
||||
|
||||
TestPlaceholderTarget target = new TestPlaceholderTarget(builder.TargetTestHelpers.Arch, builder.GetReadContext().ReadFromTarget, runtimeFunctions.Types);
|
||||
TestPlaceholderTarget target = new TestPlaceholderTarget(builder.TargetTestHelpers.Arch, builder.GetMemoryContext().ReadFromTarget, runtimeFunctions.Types);
|
||||
ContractRegistry reg = Mock.Of<ContractRegistry>(
|
||||
c => c.PlatformMetadata == new Mock<Contracts.IPlatformMetadata>().Object);
|
||||
target.SetContracts(reg);
|
||||
|
|
|
@ -28,7 +28,7 @@ public unsafe class LoaderTests
|
|||
TargetPointer moduleAddr = loader.AddModule(path: expected);
|
||||
TargetPointer moduleAddrEmptyPath = loader.AddModule();
|
||||
|
||||
var target = new TestPlaceholderTarget(arch, builder.GetReadContext().ReadFromTarget, loader.Types);
|
||||
var target = new TestPlaceholderTarget(arch, builder.GetMemoryContext().ReadFromTarget, loader.Types);
|
||||
target.SetContracts(Mock.Of<ContractRegistry>(
|
||||
c => c.Loader == ((IContractFactory<ILoader>)new LoaderFactory()).CreateContract(target, 1)));
|
||||
|
||||
|
@ -62,7 +62,7 @@ public unsafe class LoaderTests
|
|||
TargetPointer moduleAddr = loader.AddModule(fileName: expected);
|
||||
TargetPointer moduleAddrEmptyName = loader.AddModule();
|
||||
|
||||
var target = new TestPlaceholderTarget(arch, builder.GetReadContext().ReadFromTarget, loader.Types);
|
||||
var target = new TestPlaceholderTarget(arch, builder.GetMemoryContext().ReadFromTarget, loader.Types);
|
||||
target.SetContracts(Mock.Of<ContractRegistry>(
|
||||
c => c.Loader == ((IContractFactory<ILoader>)new LoaderFactory()).CreateContract(target, 1)));
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ public class MethodDescTests
|
|||
private static Target CreateTarget(MockDescriptors.MethodDescriptors methodDescBuilder, Mock<IExecutionManager> mockExecutionManager = null)
|
||||
{
|
||||
MockMemorySpace.Builder builder = methodDescBuilder.Builder;
|
||||
var target = new TestPlaceholderTarget(builder.TargetTestHelpers.Arch, builder.GetReadContext().ReadFromTarget, methodDescBuilder.Types, methodDescBuilder.Globals);
|
||||
var target = new TestPlaceholderTarget(builder.TargetTestHelpers.Arch, builder.GetMemoryContext().ReadFromTarget, methodDescBuilder.Types, methodDescBuilder.Globals);
|
||||
|
||||
mockExecutionManager ??= new Mock<IExecutionManager>();
|
||||
target.SetContracts(Mock.Of<ContractRegistry>(
|
||||
|
|
|
@ -21,7 +21,7 @@ public class MethodTableTests
|
|||
|
||||
configure?.Invoke(rtsBuilder);
|
||||
|
||||
var target = new TestPlaceholderTarget(arch, builder.GetReadContext().ReadFromTarget, rtsBuilder.Types, rtsBuilder.Globals);
|
||||
var target = new TestPlaceholderTarget(arch, builder.GetMemoryContext().ReadFromTarget, rtsBuilder.Types, rtsBuilder.Globals);
|
||||
target.SetContracts(Mock.Of<ContractRegistry>(
|
||||
c => c.RuntimeTypeSystem == ((IContractFactory<IRuntimeTypeSystem>)new RuntimeTypeSystemFactory()).CreateContract(target, 1)));
|
||||
|
||||
|
|
|
@ -166,9 +166,9 @@ internal partial class MockDescriptors
|
|||
} while (cur.Value < end);
|
||||
}
|
||||
|
||||
public MockMemorySpace.ReadContext GetReadContext()
|
||||
public MockMemorySpace.MemoryContext GetMemoryContext()
|
||||
{
|
||||
return _builder.GetReadContext();
|
||||
return _builder.GetMemoryContext();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ internal unsafe static partial class MockMemorySpace
|
|||
{
|
||||
foreach (var fragment in _heapFragments)
|
||||
{
|
||||
if (address >= fragment.Address && address+(ulong)length <= fragment.Address + (ulong)fragment.Data.Length)
|
||||
if (address >= fragment.Address && address + (ulong)length <= fragment.Address + (ulong)fragment.Data.Length)
|
||||
return fragment.Data.AsSpan((int)(address - fragment.Address), length);
|
||||
}
|
||||
throw new InvalidOperationException($"No fragment includes addresses from 0x{address:x} with length {length}");
|
||||
|
@ -83,9 +83,9 @@ internal unsafe static partial class MockMemorySpace
|
|||
return this;
|
||||
}
|
||||
|
||||
internal ReadContext GetReadContext()
|
||||
internal MemoryContext GetMemoryContext()
|
||||
{
|
||||
ReadContext context = new ReadContext
|
||||
MemoryContext context = new MemoryContext
|
||||
{
|
||||
HeapFragments = _heapFragments,
|
||||
};
|
||||
|
@ -124,9 +124,9 @@ internal unsafe static partial class MockMemorySpace
|
|||
}
|
||||
|
||||
// Used by ReadFromTarget to return the appropriate bytes
|
||||
internal class ReadContext
|
||||
internal class MemoryContext
|
||||
{
|
||||
public IReadOnlyList<HeapFragment> HeapFragments { get; init; }
|
||||
public IList<HeapFragment> HeapFragments { get; init; }
|
||||
|
||||
internal int ReadFromTarget(ulong address, Span<byte> buffer)
|
||||
{
|
||||
|
@ -173,5 +173,54 @@ internal unsafe static partial class MockMemorySpace
|
|||
throw new InvalidOperationException($"Not enough data in fragment at {lastHeapFragment.Address:X} ('{lastHeapFragment.Name}') to read {buffer.Length} bytes at {address:X} (only {availableLength} bytes available)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
internal int WriteToTarget(ulong address, Span<byte> buffer)
|
||||
{
|
||||
if (buffer.Length == 0)
|
||||
return 0;
|
||||
|
||||
if (address == 0)
|
||||
return -1;
|
||||
|
||||
bool partialWriteOccurred = false;
|
||||
HeapFragment lastHeapFragment = default;
|
||||
int availableLength = 0;
|
||||
while (true)
|
||||
{
|
||||
bool tryAgain = false;
|
||||
for (int i = 0; i < HeapFragments.Count; i++)
|
||||
{
|
||||
var fragment = HeapFragments[i];
|
||||
if (address >= fragment.Address && address < fragment.Address + (ulong)fragment.Data.Length)
|
||||
{
|
||||
int offset = (int)(address - fragment.Address);
|
||||
availableLength = fragment.Data.Length - offset;
|
||||
if (availableLength >= buffer.Length)
|
||||
{
|
||||
buffer.CopyTo(fragment.Data.AsSpan(offset, buffer.Length));
|
||||
HeapFragments[i] = fragment; // Update the fragment in the list
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastHeapFragment = fragment;
|
||||
partialWriteOccurred = true;
|
||||
tryAgain = true;
|
||||
buffer.Slice(0, availableLength).CopyTo(fragment.Data.AsSpan(offset, availableLength));
|
||||
HeapFragments[i] = fragment; // Update the fragment in the list
|
||||
buffer = buffer.Slice(availableLength);
|
||||
address = fragment.Address + (ulong)fragment.Data.Length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!tryAgain)
|
||||
break;
|
||||
}
|
||||
|
||||
if (partialWriteOccurred)
|
||||
throw new InvalidOperationException($"Not enough space in fragment at {lastHeapFragment.Address:X} ('{lastHeapFragment.Name}') to write {buffer.Length} bytes at {address:X} (only {availableLength} bytes available)");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ public unsafe class ObjectTests
|
|||
|
||||
configure?.Invoke(objectBuilder);
|
||||
|
||||
var target = new TestPlaceholderTarget(arch, builder.GetReadContext().ReadFromTarget, objectBuilder.Types, objectBuilder.Globals);
|
||||
var target = new TestPlaceholderTarget(arch, builder.GetMemoryContext().ReadFromTarget, objectBuilder.Types, objectBuilder.Globals);
|
||||
target.SetContracts(Mock.Of<ContractRegistry>(
|
||||
c => c.Object == ((IContractFactory<IObject>)new ObjectFactory()).CreateContract(target, 1)
|
||||
&& c.RuntimeTypeSystem == ((IContractFactory<IRuntimeTypeSystem>)new RuntimeTypeSystemFactory()).CreateContract(target, 1)));
|
||||
|
|
|
@ -348,7 +348,7 @@ public class PrecodeStubsTests
|
|||
private static Target CreateTarget(PrecodeBuilder precodeBuilder)
|
||||
{
|
||||
var arch = precodeBuilder.Builder.TargetTestHelpers.Arch;
|
||||
TestPlaceholderTarget.ReadFromTargetDelegate reader = precodeBuilder.Builder.GetReadContext().ReadFromTarget;
|
||||
TestPlaceholderTarget.ReadFromTargetDelegate reader = precodeBuilder.Builder.GetMemoryContext().ReadFromTarget;
|
||||
// hack for this test put the precode machine descriptor at the same address as the PlatformMetadata
|
||||
(string Name, ulong Value)[] globals = [(Constants.Globals.PlatformMetadata, precodeBuilder.MachineDescriptorAddress)];
|
||||
var target = new TestPlaceholderTarget(arch, reader, precodeBuilder.Types, globals);
|
||||
|
|
|
@ -20,7 +20,7 @@ public class ReJITTests
|
|||
MockReJIT builder,
|
||||
Mock<ICodeVersions> mockCodeVersions = null)
|
||||
{
|
||||
TestPlaceholderTarget target = new TestPlaceholderTarget(arch, builder.Builder.GetReadContext().ReadFromTarget, builder.Types, builder.Globals);
|
||||
TestPlaceholderTarget target = new TestPlaceholderTarget(arch, builder.Builder.GetMemoryContext().ReadFromTarget, builder.Types, builder.Globals);
|
||||
|
||||
mockCodeVersions ??= new Mock<ICodeVersions>();
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ public class RuntimeInfoTests
|
|||
(string Name, string Value)[] globalStrings)
|
||||
{
|
||||
MockMemorySpace.Builder builder = new MockMemorySpace.Builder(new TargetTestHelpers(arch));
|
||||
TestPlaceholderTarget target = new TestPlaceholderTarget(arch, builder.GetReadContext().ReadFromTarget, [], [], globalStrings);
|
||||
TestPlaceholderTarget target = new TestPlaceholderTarget(arch, builder.GetMemoryContext().ReadFromTarget, [], [], globalStrings);
|
||||
|
||||
IContractFactory<IRuntimeInfo> runtimeInfoFactory = new RuntimeInfoFactory();
|
||||
|
||||
|
|
|
@ -83,6 +83,7 @@ internal class TestPlaceholderTarget : Target
|
|||
if (_dataReader(address, buffer) < 0)
|
||||
throw new InvalidOperationException($"Failed to read {buffer.Length} bytes at 0x{address:x8}.");
|
||||
}
|
||||
public override void WriteBuffer(ulong address, Span<byte> buffer) => throw new NotImplementedException();
|
||||
|
||||
public override string ReadUtf8String(ulong address) => throw new NotImplementedException();
|
||||
public override string ReadUtf16String(ulong address)
|
||||
|
@ -160,6 +161,7 @@ internal class TestPlaceholderTarget : Target
|
|||
}
|
||||
|
||||
public override T Read<T>(ulong address) => DefaultRead<T>(address);
|
||||
public override bool Write<T>(ulong address, T value) => throw new NotImplementedException();
|
||||
|
||||
#region subclass reader helpers
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ public unsafe class ThreadTests
|
|||
private static Target CreateTarget(MockDescriptors.Thread thread)
|
||||
{
|
||||
MockTarget.Architecture arch = thread.Builder.TargetTestHelpers.Arch;
|
||||
var target = new TestPlaceholderTarget(arch, thread.Builder.GetReadContext().ReadFromTarget, thread.Types, thread.Globals);
|
||||
var target = new TestPlaceholderTarget(arch, thread.Builder.GetMemoryContext().ReadFromTarget, thread.Types, thread.Globals);
|
||||
target.SetContracts(Mock.Of<ContractRegistry>(
|
||||
c => c.Thread == ((IContractFactory<IThread>)new ThreadFactory()).CreateContract(target, 1)));
|
||||
return target;
|
||||
|
|
|
@ -194,7 +194,7 @@ public class TypeDescTests
|
|||
|
||||
private static Target CreateTarget(MockDescriptors.RuntimeTypeSystem rtsBuilder)
|
||||
{
|
||||
var target = new TestPlaceholderTarget(rtsBuilder.Builder.TargetTestHelpers.Arch, rtsBuilder.Builder.GetReadContext().ReadFromTarget, rtsBuilder.Types, rtsBuilder.Globals);
|
||||
var target = new TestPlaceholderTarget(rtsBuilder.Builder.TargetTestHelpers.Arch, rtsBuilder.Builder.GetMemoryContext().ReadFromTarget, rtsBuilder.Types, rtsBuilder.Globals);
|
||||
target.SetContracts(Mock.Of<ContractRegistry>(
|
||||
c => c.RuntimeTypeSystem == ((IContractFactory<IRuntimeTypeSystem>)new RuntimeTypeSystemFactory()).CreateContract(target, 1)));
|
||||
return target;
|
||||
|
|
|
@ -493,6 +493,7 @@ public static class Program
|
|||
GetDescriptor(contractVersion),
|
||||
[TargetPointer.Null, new TargetPointer(header->memoryBase + (nuint)((byte*)&header->moduleTable - (byte*)header))],
|
||||
(address, buffer) => ReadFromMemoryMappedLog(address, buffer, header),
|
||||
(address, buffer) => throw new NotImplementedException("StressLogAnalyzer does not provide WriteToTarget implementation"),
|
||||
(threadId, contextFlags, bufferToFill) => throw new NotImplementedException("StressLogAnalyzer does not provide GetTargetThreadContext implementation"),
|
||||
true,
|
||||
nuint.Size);
|
||||
|
|
Loading…
Reference in New Issue