Skip to content

Commit

Permalink
[cdac] Implement ISOSDacInterface::GetPEFileName in cDAC (#106358)
Browse files Browse the repository at this point in the history
- Include Module path in data descriptor
- Implement `GetPath` in `Loader` contract
- Make cDAC implement ISOSDacInterface::GetPEFileName
  • Loading branch information
elinor-fung authored Aug 14, 2024
1 parent 605ff6f commit 527ab8f
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 7 deletions.
9 changes: 9 additions & 0 deletions docs/design/datacontracts/Loader.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ internal enum AvailableMetadataType
ModuleHandle GetModuleHandle(TargetPointer);
TargetPointer GetAssembly(ModuleHandle handle);
ModuleFlags GetFlags(ModuleHandle handle);
string GetPath(ModuleHandle handle);
TargetPointer GetLoaderAllocator(ModuleHandle handle);
TargetPointer GetThunkHeap(ModuleHandle handle);
TargetPointer GetILBase(ModuleHandle handle);
Expand All @@ -122,6 +123,7 @@ Data descriptors used:
| `Module` | `Flags` | Assembly of the Module |
| `Module` | `LoaderAllocator` | LoaderAllocator of the Module |
| `Module` | `ThunkHeap` | Pointer to the thunk heap |
| `Module` | `Path` | Path of the Module (UTF-16, null-terminated) |
| `Module` | `DynamicMetadata` | Pointer to saved metadata for reflection emit modules |
| `Module` | `FieldDefToDescMap` | Mapping table |
| `Module` | `ManifestModuleReferencesMap` | Mapping table |
Expand Down Expand Up @@ -149,6 +151,13 @@ ModuleFlags GetFlags(ModuleHandle handle)
return target.Read<uint>(handle.Address + /* Module::Flags offset */);
}

string GetPath(ModuleHandle handle)
{
TargetPointer pathStart = target.ReadPointer(handle.Address + /* Module::Path offset */);
char[] path = // Read<char> from target starting at pathStart until null terminator
return new string(path);
}

TargetPointer GetLoaderAllocator(ModuleHandle handle)
{
return target.ReadPointer(handle.Address + /* Module::LoaderAllocator offset */);
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/debug/daccess/dacimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1243,6 +1243,7 @@ class ClrDataAccess
HRESULT GetObjectDataImpl(CLRDATA_ADDRESS addr, struct DacpObjectData *objectData);
HRESULT GetObjectExceptionDataImpl(CLRDATA_ADDRESS objAddr, struct DacpExceptionObjectData *data);
HRESULT GetObjectStringDataImpl(CLRDATA_ADDRESS obj, unsigned int count, _Inout_updates_z_(count) WCHAR *stringData, unsigned int *pNeeded);
HRESULT GetPEFileNameImpl(CLRDATA_ADDRESS moduleAddr, unsigned int count, _Inout_updates_z_(count) WCHAR *fileName, unsigned int *pNeeded);
HRESULT GetUsefulGlobalsImpl(struct DacpUsefulGlobalsData *globalsData);
HRESULT GetMethodDescDataImpl(CLRDATA_ADDRESS methodDesc, CLRDATA_ADDRESS ip, struct DacpMethodDescData *data, ULONG cRevertedRejitVersions, DacpReJitData * rgRevertedRejitData, ULONG * pcNeededRevertedRejitData);
HRESULT GetMethodDescNameImpl(CLRDATA_ADDRESS methodDesc, unsigned int count, _Inout_updates_z_(count) WCHAR *name, unsigned int *pNeeded);
Expand Down
42 changes: 38 additions & 4 deletions src/coreclr/debug/daccess/request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2542,18 +2542,53 @@ ClrDataAccess::GetPEFileName(CLRDATA_ADDRESS moduleAddr, unsigned int count, _In
return E_INVALIDARG;

SOSDacEnter();

if (m_cdacSos != NULL)
{
hr = m_cdacSos->GetPEFileName(moduleAddr, count, fileName, pNeeded);
if (FAILED(hr))
{
hr = GetPEFileNameImpl(moduleAddr, count, fileName, pNeeded);
}
#ifdef _DEBUG
else
{
NewArrayHolder<WCHAR> fileNameLocal(new WCHAR[count]);
unsigned int neededLocal = 0;
HRESULT hrLocal = GetPEFileNameImpl(moduleAddr, count, fileNameLocal, &neededLocal);

DacAssertsEnabledHolder assertsEnabled;
_ASSERTE(hr == hrLocal);
_ASSERTE(pNeeded == NULL || *pNeeded == neededLocal);
_ASSERTE(fileName == NULL || u16_strncmp(fileName, fileNameLocal, count) == 0);
}
#endif
}
else
{
hr = GetPEFileNameImpl(moduleAddr, count, fileName, pNeeded);;
}


SOSDacLeave();
return hr;
}

HRESULT
ClrDataAccess::GetPEFileNameImpl(CLRDATA_ADDRESS moduleAddr, unsigned int count, _Inout_updates_z_(count) WCHAR *fileName, unsigned int *pNeeded)
{
PTR_Module pModule = PTR_Module(TO_TADDR(moduleAddr));
PEAssembly* pPEAssembly = pModule->GetPEAssembly();

// Turn from bytes to wide characters
if (!pPEAssembly->GetPath().IsEmpty())
{
if (!pPEAssembly->GetPath().DacGetUnicode(count, fileName, pNeeded))
hr = E_FAIL;
return E_FAIL;
}
else if (!pPEAssembly->IsReflectionEmit())
{
hr = E_NOTIMPL;
return E_NOTIMPL;
}
else
{
Expand All @@ -2564,8 +2599,7 @@ ClrDataAccess::GetPEFileName(CLRDATA_ADDRESS moduleAddr, unsigned int count, _In
*pNeeded = 1;
}

SOSDacLeave();
return hr;
return S_OK;
}

HRESULT
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/debug/runtimeinfo/datadescriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ CDAC_TYPE_FIELD(Module, /*pointer*/, Flags, cdac_data<Module>::Flags)
CDAC_TYPE_FIELD(Module, /*pointer*/, LoaderAllocator, cdac_data<Module>::LoaderAllocator)
CDAC_TYPE_FIELD(Module, /*pointer*/, ThunkHeap, cdac_data<Module>::ThunkHeap)
CDAC_TYPE_FIELD(Module, /*pointer*/, DynamicMetadata, cdac_data<Module>::DynamicMetadata)
CDAC_TYPE_FIELD(Module, /*pointer*/, Path, cdac_data<Module>::Path)

CDAC_TYPE_FIELD(Module, /*pointer*/, FieldDefToDescMap, cdac_data<Module>::FieldDefToDescMap)
CDAC_TYPE_FIELD(Module, /*pointer*/, ManifestModuleReferencesMap, cdac_data<Module>::ManifestModuleReferencesMap)
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/ceeload.h
Original file line number Diff line number Diff line change
Expand Up @@ -1639,6 +1639,7 @@ struct cdac_data<Module>
static constexpr size_t LoaderAllocator = offsetof(Module, m_loaderAllocator);
static constexpr size_t ThunkHeap = offsetof(Module, m_pThunkHeap);
static constexpr size_t DynamicMetadata = offsetof(Module, m_pDynamicMetadata);
static constexpr size_t Path = offsetof(Module, m_path);

// Lookup map pointers
static constexpr size_t FieldDefToDescMap = offsetof(Module, m_FieldDefToDescMap);
Expand Down
4 changes: 2 additions & 2 deletions src/native/managed/cdacreader/src/Contracts/Loader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ static IContract IContract.Create(Target target, int version)

public virtual TargetPointer GetAssembly(ModuleHandle handle) => throw new NotImplementedException();
public virtual ModuleFlags GetFlags(ModuleHandle handle) => throw new NotImplementedException();
public virtual string GetPath(ModuleHandle handle) => throw new NotImplementedException();

public virtual TargetPointer GetLoaderAllocator(ModuleHandle handle) => throw new NotImplementedException();
public virtual TargetPointer GetThunkHeap(ModuleHandle handle) => throw new NotImplementedException();

Expand All @@ -131,8 +133,6 @@ static IContract IContract.Create(Target target, int version)
public virtual TargetEcmaMetadata GetReadWriteMetadata(ModuleHandle handle) => throw new NotImplementedException();

public virtual ModuleLookupTables GetLookupTables(ModuleHandle handle) => throw new NotImplementedException();

public virtual string GetPath(ModuleHandle handle) => throw new NotImplementedException();
}

internal readonly struct Loader : ILoader
Expand Down
26 changes: 26 additions & 0 deletions src/native/managed/cdacreader/src/Contracts/Loader_1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

Expand Down Expand Up @@ -35,6 +36,31 @@ ModuleFlags ILoader.GetFlags(ModuleHandle handle)
return (ModuleFlags)module.Flags;
}

string ILoader.GetPath(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);

// TODO: [cdac] Add/use APIs on Target for reading strings in target endianness
TargetPointer addr = module.Path;
while (true)
{
// Read characters until we find the null terminator
char nameChar = _target.Read<char>(addr);
if (nameChar == 0)
break;

addr += sizeof(char);
}

int length = (int)(addr.Value - module.Path.Value);
if (length == 0)
return string.Empty;

Span<byte> span = stackalloc byte[length];
_target.ReadBuffer(module.Path, span);
return new string(MemoryMarshal.Cast<byte, char>(span));
}

TargetPointer ILoader.GetLoaderAllocator(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
Expand Down
2 changes: 2 additions & 0 deletions src/native/managed/cdacreader/src/Data/Module.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public Module(Target target, TargetPointer address)
LoaderAllocator = target.ReadPointer(address + (ulong)type.Fields[nameof(LoaderAllocator)].Offset);
ThunkHeap = target.ReadPointer(address + (ulong)type.Fields[nameof(ThunkHeap)].Offset);
DynamicMetadata = target.ReadPointer(address + (ulong)type.Fields[nameof(DynamicMetadata)].Offset);
Path = target.ReadPointer(address + (ulong)type.Fields[nameof(Path)].Offset);

FieldDefToDescMap = target.ReadPointer(address + (ulong)type.Fields[nameof(FieldDefToDescMap)].Offset);
ManifestModuleReferencesMap = target.ReadPointer(address + (ulong)type.Fields[nameof(ManifestModuleReferencesMap)].Offset);
Expand All @@ -39,6 +40,7 @@ public Module(Target target, TargetPointer address)
public TargetPointer LoaderAllocator { get; init; }
public TargetPointer ThunkHeap { get; init; }
public TargetPointer DynamicMetadata { get; init; }
public TargetPointer Path { get; init; }

public TargetPointer FieldDefToDescMap { get; init; }
public TargetPointer ManifestModuleReferencesMap { get; init; }
Expand Down
30 changes: 29 additions & 1 deletion src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,35 @@ public unsafe int GetObjectStringData(ulong obj, uint count, char* stringData, u
public unsafe int GetOOMData(ulong oomAddr, void* data) => HResults.E_NOTIMPL;
public unsafe int GetOOMStaticData(void* data) => HResults.E_NOTIMPL;
public unsafe int GetPEFileBase(ulong addr, ulong* peBase) => HResults.E_NOTIMPL;
public unsafe int GetPEFileName(ulong addr, uint count, char* fileName, uint* pNeeded) => HResults.E_NOTIMPL;

public unsafe int GetPEFileName(ulong addr, uint count, char* fileName, uint* pNeeded)
{
try
{
Contracts.ILoader contract = _target.Contracts.Loader;
Contracts.ModuleHandle handle = contract.GetModuleHandle(addr);
string path = contract.GetPath(handle);

// Return not implemented for empty paths for non-reflection emit assemblies (for example, loaded from memory)
if (string.IsNullOrEmpty(path))
{
Contracts.ModuleFlags flags = contract.GetFlags(handle);
if (!flags.HasFlag(Contracts.ModuleFlags.ReflectionEmit))
{
return HResults.E_NOTIMPL;
}
}

CopyStringToTargetBuffer(fileName, count, pNeeded, path);
}
catch (System.Exception ex)
{
return ex.HResult;
}

return HResults.S_OK;
}

public unsafe int GetPrivateBinPaths(ulong appDomain, int count, char* paths, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetRCWData(ulong addr, void* data) => HResults.E_NOTIMPL;
public unsafe int GetRCWInterfaces(ulong rcw, uint count, void* interfaces, uint* pNeeded) => HResults.E_NOTIMPL;
Expand Down

0 comments on commit 527ab8f

Please sign in to comment.