Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cDAC] DAC like entry point #112653

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 11 additions & 0 deletions src/coreclr/debug/daccess/cdac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,17 @@ CDAC CDAC::Create(uint64_t descriptorAddr, ICorDebugDataTarget* target, IUnknown
return CDAC{cdacLib, handle, target, legacyImpl};
}

void CDAC::CreateInstance(void* iid, ICLRDataTarget* pLegacyTarget, void** iface)
{
HMODULE cdacLib;
if (!TryLoadCDACLibrary(&cdacLib))
return;

decltype(&cdac_reader_create_instance) create_instance = reinterpret_cast<decltype(&cdac_reader_create_instance)>(::GetProcAddress(cdacLib, "cdac_reader_create_instance"));

create_instance(iid, pLegacyTarget, iface);
}

CDAC::CDAC(HMODULE module, intptr_t handle, ICorDebugDataTarget* target, IUnknown* legacyImpl)
: m_module{module}
, m_cdac_handle{handle}
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/debug/daccess/cdac.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ class CDAC final
public: // static
static CDAC Create(uint64_t descriptorAddr, ICorDebugDataTarget *pDataTarget, IUnknown* legacyImpl);

static void CreateInstance(void* iid, ICLRDataTarget* pLegacyTarget, void** iface);

public:
CDAC() = default;

Expand Down
46 changes: 14 additions & 32 deletions src/coreclr/debug/daccess/daccess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "dbgutil.h"
#include "cdac.h"
#include <clrconfignocache.h>
#include <cdac_reader.h>

#ifdef USE_DAC_TABLE_RVA
#include <dactablerva.h>
Expand Down Expand Up @@ -7009,6 +7010,19 @@ CLRDataCreateInstance(REFIID iid,
}

*iface = NULL;


CLRConfigNoCache enable = CLRConfigNoCache::Get("ENABLE_CDAC");
if (enable.IsSet())
{
DWORD val;
if (enable.TryAsInteger(10, val) && val == 1)
{
CDAC::CreateInstance((void*)&iid, pLegacyTarget, iface);
return S_OK;
}
}

ClrDataAccess * pClrDataAccess;
HRESULT hr = CLRDataAccessCreateInstance(pLegacyTarget, &pClrDataAccess);
if (hr != S_OK)
Expand All @@ -7021,38 +7035,6 @@ CLRDataCreateInstance(REFIID iid,

// TODO: [cdac] Remove when cDAC deploys with SOS - https://github.com/dotnet/runtime/issues/108720
NonVMComHolder<IUnknown> cdacInterface = nullptr;
#ifdef CAN_USE_CDAC
CLRConfigNoCache enable = CLRConfigNoCache::Get("ENABLE_CDAC");
if (enable.IsSet())
{
DWORD val;
if (enable.TryAsInteger(10, val) && val == 1)
{
// TODO: [cdac] TryGetSymbol is only implemented for Linux, OSX, and Windows.
uint64_t contractDescriptorAddr = 0;
if (TryGetSymbol(pClrDataAccess->m_pTarget, pClrDataAccess->m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr))
{
IUnknown* thisImpl;
HRESULT qiRes = pClrDataAccess->QueryInterface(IID_IUnknown, (void**)&thisImpl);
_ASSERTE(SUCCEEDED(qiRes));
CDAC& cdac = pClrDataAccess->m_cdac;
cdac = CDAC::Create(contractDescriptorAddr, pClrDataAccess->m_pTarget, thisImpl);
if (cdac.IsValid())
{
// Get SOS interfaces from the cDAC if available.
cdac.CreateSosInterface(&cdacInterface);
_ASSERTE(cdacInterface != nullptr);

// Lifetime is now managed by cDAC implementation of SOS interfaces
pClrDataAccess->Release();
}

// Release the AddRef from the QI.
pClrDataAccess->Release();
}
}
}
#endif
if (cdacInterface != nullptr)
{
hr = cdacInterface->QueryInterface(iid, iface);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public static bool TryCreate(
ReadFromTargetDelegate readFromTarget,
GetTargetThreadContextDelegate getThreadContext,
GetTargetPlatformDelegate getTargetPlatform,
out ContractDescriptorTarget? target)
[NotNullWhen(true)] out ContractDescriptorTarget? target)
{
Reader reader = new Reader(readFromTarget, getThreadContext, getTargetPlatform);
if (TryReadContractDescriptor(
Expand Down
2 changes: 2 additions & 0 deletions src/native/managed/cdacreader/inc/cdac_reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ int cdac_reader_free(intptr_t handle);
// obj: returned SOS interface that can be QI'd to ISOSDacInterface*
int cdac_reader_create_sos_interface(intptr_t handle, IUnknown* legacyImpl, IUnknown** obj);

int cdac_reader_create_instance(void* iid, IUnknown* pLegacyTarget, void** iface);

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

using System.IO;
using System.Text;
using System;
using System.Numerics;
using System.Runtime.CompilerServices;

namespace Microsoft.Diagnostics.DataContractReader.Decoder;

internal static class BinaryReaderExtensions
{
/// <summary>
/// Reads a C-style, zero-terminated string from memory.
/// </summary>
public static string ReadZString(this BinaryReader reader)
{
var sb = new StringBuilder();
byte nextByte = reader.ReadByte();
while (nextByte != 0)
{
sb.Append((char)nextByte);
nextByte = reader.ReadByte();
}
return sb.ToString();
}

public static unsafe T Read<T>(this BinaryReader reader)
where T : unmanaged, IBinaryInteger<T>, IMinMaxValue<T>
{
T value = default;
Span<byte> buffer = stackalloc byte[sizeof(T)];

if (reader.Read(buffer) != buffer.Length)
{
throw new IOException();
}
if (!T.TryReadLittleEndian(buffer, !IsSigned<T>(), out value))
{
throw new InvalidOperationException("Unable to convert to type.");
}
return value;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsSigned<T>() where T : struct, INumberBase<T>, IMinMaxValue<T>
{
return T.IsNegative(T.MinValue);
}
}
64 changes: 64 additions & 0 deletions src/native/managed/cdacreader/src/Decoder/DataTargetStream.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.IO;
using Microsoft.Diagnostics.DataContractReader.Legacy;

namespace Microsoft.Diagnostics.DataContractReader.Decoder;

internal class DataTargetStream(ICLRDataTarget dataTarget, ulong startPosition) : Stream
{
private readonly ulong _startPosition = startPosition;
private long _offset;
private readonly ICLRDataTarget _dataTarget = dataTarget;

private ulong GlobalPosition => _startPosition + (ulong)_offset;

public override bool CanRead => true;

public override bool CanSeek => true;

public override bool CanWrite => false;

public override long Length => 0x10000;

public override long Position { get => _offset; set => _offset = value; }

public override unsafe int Read(byte[] buffer, int offset, int count)
Copy link
Contributor

Choose a reason for hiding this comment

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

You should also override the Read overload that takes a span.

{
Span<byte> span = buffer;
return Read(span.Slice(start: offset, length: count));
}
public override unsafe int Read(Span<byte> buffer)
{
fixed (byte* bufferPtr = buffer)
{
uint bytesRead;
int hr = _dataTarget.ReadVirtual(GlobalPosition, bufferPtr, (uint)buffer.Length, &bytesRead);
_offset += bytesRead;
if (hr != 0)
throw new InvalidOperationException($"ReadVirtual failed with hr={hr}");
return (int)bytesRead;
}
}
public override long Seek(long offset, SeekOrigin origin)
{
switch (origin)
{
case SeekOrigin.Begin:
_offset = offset;
break;
case SeekOrigin.Current:
_offset += offset;
break;
case SeekOrigin.End:
throw new NotSupportedException();
}
return _offset;
}

public override void Flush() => throw new NotImplementedException();
public override void SetLength(long value) => throw new NotImplementedException();
public override void Write(byte[] buffer, int offset, int count) => throw new NotImplementedException();
}
Loading