|
// 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.Collections.Generic;
using System.Linq;
using Microsoft.Diagnostics.DataContractReader.Data;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Diagnostics.CodeAnalysis;
namespace Microsoft.Diagnostics.DataContractReader.Contracts;
internal readonly struct Loader_1 : ILoader
{
private const string DefaultDomainFriendlyName = "DefaultDomain";
private const uint ASSEMBLY_NOTIFYFLAGS_PROFILER_NOTIFIED = 0x1; // Assembly Notify Flag for profiler notification
private const ushort MaxWebcilSections = 16; // Must stay in sync with native WEBCIL_MAX_SECTIONS.
private enum ModuleFlags_1 : uint
{
Tenured = 0x1, // Set once we know for sure the Module will not be freed until the appdomain itself exits
JitOptimizationDisabled = 0x2, // Cached flag: JIT optimizations are disabled
EditAndContinue = 0x8, // Edit and Continue is enabled for this module
ReflectionEmit = 0x40, // Reflection.Emit was used to create this module
EncCapable = 0x200, // Cached flag: module is Edit and Continue capable
}
private const uint DebuggerInfoMask = 0x0000FC00;
private const int DebuggerInfoShift = 10;
private const uint DEBUGGER_ALLOW_JIT_OPTS_PRIV = 0x00000800;
private enum PEImageFlags : uint
{
FLAG_MAPPED = 0x01, // the file is mapped/hydrated (vs. the raw disk layout)
};
// Must stay in sync with native PEImageLayout::ImageFormat values.
private enum ImageFormat : uint
{
PE = 0,
Webcil = 1,
}
private readonly Target _target;
internal Loader_1(Target target)
{
_target = target;
}
ModuleHandle ILoader.GetModuleHandleFromModulePtr(TargetPointer modulePointer)
{
if (modulePointer == TargetPointer.Null)
throw new ArgumentNullException(nameof(modulePointer));
return new ModuleHandle(modulePointer);
}
ModuleHandle ILoader.GetModuleHandleFromAssemblyPtr(TargetPointer assemblyPointer)
{
if (assemblyPointer == TargetPointer.Null)
throw new ArgumentNullException(nameof(assemblyPointer));
Data.Assembly assembly = _target.ProcessedData.GetOrAdd<Data.Assembly>(assemblyPointer);
if (assembly.Module == TargetPointer.Null)
throw new InvalidOperationException("Assembly does not have a module associated with it.");
return new ModuleHandle(assembly.Module);
}
IEnumerable<ModuleHandle> ILoader.GetModuleHandles(TargetPointer appDomain, AssemblyIterationFlags iterationFlags)
{
if (appDomain == TargetPointer.Null)
throw new ArgumentNullException(nameof(appDomain));
Data.AppDomain domain = _target.ProcessedData.GetOrAdd<Data.AppDomain>(appDomain);
ArrayListBase arrayList = _target.ProcessedData.GetOrAdd<ArrayListBase>(domain.AssemblyList);
foreach (TargetPointer pAssembly in arrayList.Elements)
{
Data.Assembly assembly = _target.ProcessedData.GetOrAdd<Data.Assembly>(pAssembly);
// following logic is based on AppDomain::AssemblyIterator::Next_Unlocked in appdomain.cpp
if (assembly.IsError)
{
// assembly is in an error state, return if we are supposed to include it
// otherwise we skip it and continue to the next assembly
if (iterationFlags.HasFlag(AssemblyIterationFlags.IncludeFailedToLoad))
{
yield return new ModuleHandle(assembly.Module);
}
continue;
}
if ((assembly.NotifyFlags & ASSEMBLY_NOTIFYFLAGS_PROFILER_NOTIFIED) != 0 && !iterationFlags.HasFlag(AssemblyIterationFlags.IncludeAvailableToProfilers))
{
// The assembly has reached the state at which we would notify profilers,
// and we're supposed to include such assemblies in the enumeration. So
// don't reject it (i.e., noop here, and don't bother with the rest of
// the load status checks). Check for this first, since
// IncludeAvailableToProfilers contains some loaded AND loading
// assemblies.
}
else if (assembly.IsLoaded)
{
if (!iterationFlags.HasFlag(AssemblyIterationFlags.IncludeLoaded))
continue; // skip loaded assemblies
}
else
{
if (!iterationFlags.HasFlag(AssemblyIterationFlags.IncludeLoading))
continue; // skip loading assemblies
}
// Next, reject assemblies whose execution status is
// not to be included in the enumeration
if (!iterationFlags.HasFlag(AssemblyIterationFlags.IncludeExecution))
continue; // skip assemblies with execution status
if (assembly.IsCollectible != 0)
{
if (iterationFlags.HasFlag(AssemblyIterationFlags.ExcludeCollectible))
continue; // skip collectible assemblies
Module module = _target.ProcessedData.GetOrAdd<Data.Module>(assembly.Module);
if (!GetFlags(module).HasFlag(ModuleFlags.Tenured))
continue; // skip un-tenured modules
LoaderAllocator loaderAllocator = _target.ProcessedData.GetOrAdd<Data.LoaderAllocator>(module.LoaderAllocator);
if (!loaderAllocator.IsAlive && !iterationFlags.HasFlag(AssemblyIterationFlags.IncludeCollected))
continue; // skip collected assemblies
}
yield return new ModuleHandle(assembly.Module);
}
}
TargetPointer ILoader.GetRootAssembly()
{
TargetPointer appDomainPointer = _target.ReadGlobalPointer(Constants.Globals.AppDomain);
Data.AppDomain appDomain = _target.ProcessedData.GetOrAdd<Data.AppDomain>(_target.ReadPointer(appDomainPointer));
return appDomain.RootAssembly;
}
string ILoader.GetAppDomainFriendlyName()
{
TargetPointer appDomainPointer = _target.ReadGlobalPointer(Constants.Globals.AppDomain);
Data.AppDomain appDomain = _target.ProcessedData.GetOrAdd<Data.AppDomain>(_target.ReadPointer(appDomainPointer));
return appDomain.FriendlyName != TargetPointer.Null
? _target.ReadUtf16String(appDomain.FriendlyName)
: DefaultDomainFriendlyName;
}
TargetPointer ILoader.GetModule(ModuleHandle handle)
{
return handle.Address;
}
TargetPointer ILoader.GetAssembly(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
return module.Assembly;
}
TargetPointer ILoader.GetPEAssembly(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
return module.PEAssembly;
}
private bool TryGetPEImage(ModuleHandle handle, [NotNullWhen(true)] out Data.PEImage? peImage)
{
peImage = default;
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
if (module.PEAssembly == TargetPointer.Null)
return false;
Data.PEAssembly peAssembly = _target.ProcessedData.GetOrAdd<Data.PEAssembly>(module.PEAssembly);
if (peAssembly.PEImage == TargetPointer.Null)
return false;
peImage = _target.ProcessedData.GetOrAdd<Data.PEImage>(peAssembly.PEImage);
return true;
}
bool ILoader.TryGetLoadedImageContents(ModuleHandle handle, out TargetPointer baseAddress, out uint size, out uint imageFlags)
{
baseAddress = TargetPointer.Null;
size = 0;
imageFlags = 0;
if (!TryGetPEImage(handle, out Data.PEImage? peImage))
return false; // no PE image
if (peImage.LoadedImageLayout == TargetPointer.Null)
return false; // no loaded image layout
Data.PEImageLayout peImageLayout = _target.ProcessedData.GetOrAdd<Data.PEImageLayout>(peImage.LoadedImageLayout);
baseAddress = peImageLayout.Base;
size = peImageLayout.Size;
imageFlags = peImageLayout.Flags;
return true;
}
private static bool IsMapped(Data.PEImageLayout peImageLayout)
{
if (peImageLayout.Format == (uint)ImageFormat.Webcil)
return false;
return (peImageLayout.Flags & (uint)PEImageFlags.FLAG_MAPPED) != 0;
}
bool ILoader.IsModuleMapped(ModuleHandle handle)
{
if (!TryGetPEImage(handle, out Data.PEImage? peImage))
return false; // no PE image
if (peImage.LoadedImageLayout == TargetPointer.Null)
return false;
Data.PEImageLayout peImageLayout = _target.ProcessedData.GetOrAdd<Data.PEImageLayout>(peImage.LoadedImageLayout);
return IsMapped(peImageLayout);
}
private TargetPointer FindNTHeaders(Data.PEImageLayout imageLayout)
{
Data.ImageDosHeader dosHeader = _target.ProcessedData.GetOrAdd<Data.ImageDosHeader>(imageLayout.Base);
return imageLayout.Base + (uint)dosHeader.Lfanew;
}
private TargetPointer RvaToSection(int rva, Data.PEImageLayout imageLayout)
{
TargetPointer ntHeadersPtr = FindNTHeaders(imageLayout);
Data.ImageNTHeaders ntHeaders = _target.ProcessedData.GetOrAdd<Data.ImageNTHeaders>(ntHeadersPtr);
int offset = Data.ImageNTHeaders.OptionalHeaderOffset;
TargetPointer section = ntHeadersPtr + (uint)offset + ntHeaders.FileHeader.SizeOfOptionalHeader;
TargetPointer sectionEnd = section + Data.ImageSectionHeader.Size * ntHeaders.FileHeader.NumberOfSections;
while (section < sectionEnd)
{
Data.ImageSectionHeader sectionHeader = _target.ProcessedData.GetOrAdd<Data.ImageSectionHeader>(section);
if (rva >= sectionHeader.VirtualAddress && rva < sectionHeader.VirtualAddress + sectionHeader.SizeOfRawData)
{
return section;
}
section += Data.ImageSectionHeader.Size;
}
return TargetPointer.Null;
}
private uint RvaToOffset(int rva, Data.PEImageLayout imageLayout)
{
if (imageLayout.Format == (uint)ImageFormat.Webcil)
return WebcilRvaToOffset(rva, imageLayout);
TargetPointer section = RvaToSection(rva, imageLayout);
if (section == TargetPointer.Null)
throw new InvalidOperationException("Failed to read from image.");
Data.ImageSectionHeader sectionHeader = _target.ProcessedData.GetOrAdd<Data.ImageSectionHeader>(section);
uint offset = (uint)(rva - sectionHeader.VirtualAddress) + sectionHeader.PointerToRawData;
return offset;
}
private uint WebcilRvaToOffset(int rva, Data.PEImageLayout imageLayout)
{
if (rva < 0)
throw new InvalidOperationException("Negative RVA in Webcil image.");
TargetPointer headerBase = imageLayout.Base;
Data.WebcilHeader webcilHeader = _target.ProcessedData.GetOrAdd<Data.WebcilHeader>(headerBase);
ushort numSections = webcilHeader.CoffSections;
if (numSections == 0 || numSections > MaxWebcilSections)
throw new InvalidOperationException("Invalid Webcil section count.");
if (webcilHeader.VersionMajor != 0 && webcilHeader.VersionMajor != 1)
throw new InvalidOperationException("Unsupported Webcil version.");
TargetPointer sectionTableBase = headerBase + webcilHeader.Size; // See docs/design/mono/webcil.md
for (int i = 0; i < numSections; i++)
{
TargetPointer sectionPtr = sectionTableBase + (uint)(i * (int)16); // See docs/design/mono/webcil.md
Data.WebcilSectionHeader section = _target.ProcessedData.GetOrAdd<Data.WebcilSectionHeader>(sectionPtr);
uint rvaUnsigned = (uint)rva;
if (rvaUnsigned >= section.VirtualAddress)
{
uint offset = rvaUnsigned - section.VirtualAddress;
if (offset < section.VirtualSize && offset < section.SizeOfRawData)
{
return offset + section.PointerToRawData;
}
}
}
throw new InvalidOperationException("Failed to resolve RVA in Webcil image.");
}
private TargetPointer GetRvaData(TargetPointer peAssemblyPtr, int rva, bool isNullOk)
{
if (rva == 0 && !isNullOk)
return TargetPointer.Null;
Data.PEAssembly assembly = _target.ProcessedData.GetOrAdd<Data.PEAssembly>(peAssemblyPtr);
if (assembly.PEImage == TargetPointer.Null)
throw new InvalidOperationException("PEAssembly does not have a PEImage associated with it.");
Data.PEImage peImage = _target.ProcessedData.GetOrAdd<Data.PEImage>(assembly.PEImage);
if (peImage.LoadedImageLayout == TargetPointer.Null)
throw new InvalidOperationException("PEImage does not have a LoadedImageLayout associated with it.");
Data.PEImageLayout peImageLayout = _target.ProcessedData.GetOrAdd<Data.PEImageLayout>(peImage.LoadedImageLayout);
uint offset;
if (IsMapped(peImageLayout))
offset = (uint)rva;
else
offset = RvaToOffset(rva, peImageLayout);
return peImageLayout.Base + offset;
}
TargetPointer ILoader.GetILAddr(TargetPointer peAssemblyPtr, int rva) => GetRvaData(peAssemblyPtr, rva, false);
TargetPointer ILoader.GetFieldAddressFromRva(TargetPointer peAssemblyPtr, int rva) => GetRvaData(peAssemblyPtr, rva, true);
bool ILoader.TryGetSymbolStream(ModuleHandle handle, out TargetPointer buffer, out uint size)
{
buffer = TargetPointer.Null;
size = 0;
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
if (module.GrowableSymbolStream == TargetPointer.Null)
return false;
Data.CGrowableSymbolStream growableSymbolStream = _target.ProcessedData.GetOrAdd<CGrowableSymbolStream>(module.GrowableSymbolStream);
buffer = growableSymbolStream.Buffer;
size = growableSymbolStream.Size;
return true;
}
IEnumerable<TargetPointer> ILoader.GetAvailableTypeParams(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
if (module.AvailableTypeParams == TargetPointer.Null)
return [];
EETypeHashTable typeHashTable = _target.ProcessedData.GetOrAdd<EETypeHashTable>(module.AvailableTypeParams);
return typeHashTable.Entries.Select(entry => entry.TypeHandle);
}
IEnumerable<TargetPointer> ILoader.GetInstantiatedMethods(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
if (module.InstMethodHashTable == TargetPointer.Null)
return [];
InstMethodHashTable methodHashTable = _target.ProcessedData.GetOrAdd<InstMethodHashTable>(module.InstMethodHashTable);
return methodHashTable.Entries.Select(entry => entry.MethodDesc);
}
bool ILoader.IsProbeExtensionResultValid(ModuleHandle handle)
{
if (!TryGetPEImage(handle, out Data.PEImage? peImage))
return false; // no PE image
// 0 is the invalid type. See assemblyprobeextension.h for details
return peImage.ProbeExtensionResult.Type != 0;
}
private static ModuleFlags GetFlags(Data.Module module)
{
// currently these flags are the same, but could diverge in the future
ModuleFlags_1 runtimeFlags = (ModuleFlags_1)module.Flags;
ModuleFlags flags = default;
if (runtimeFlags.HasFlag(ModuleFlags_1.Tenured))
flags |= ModuleFlags.Tenured;
if (runtimeFlags.HasFlag(ModuleFlags_1.JitOptimizationDisabled))
flags |= ModuleFlags.JitOptimizationDisabled;
if (runtimeFlags.HasFlag(ModuleFlags_1.EditAndContinue))
flags |= ModuleFlags.EditAndContinue;
if (runtimeFlags.HasFlag(ModuleFlags_1.ReflectionEmit))
flags |= ModuleFlags.ReflectionEmit;
if (runtimeFlags.HasFlag(ModuleFlags_1.EncCapable))
flags |= ModuleFlags.EncCapable;
return flags;
}
ModuleFlags ILoader.GetFlags(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
return GetFlags(module);
}
DebuggerAssemblyControlFlags ILoader.GetDebuggerInfoBits(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
return (DebuggerAssemblyControlFlags)((module.Flags & DebuggerInfoMask) >> DebuggerInfoShift);
}
void ILoader.SetDebuggerInfoBits(ModuleHandle handle, DebuggerAssemblyControlFlags newBits)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
uint currentFlags = module.Flags;
uint debuggerInfoBitsMask = DebuggerInfoMask >> DebuggerInfoShift;
uint updatedFlags = (currentFlags & ~DebuggerInfoMask) | (((uint)newBits & debuggerInfoBitsMask) << DebuggerInfoShift);
bool jitOptDisabled = (updatedFlags & DEBUGGER_ALLOW_JIT_OPTS_PRIV) == 0 || (updatedFlags & (uint)ModuleFlags.ProfDisableOptimizations) != 0;
if (jitOptDisabled)
updatedFlags |= (uint)ModuleFlags.JitOptimizationDisabled;
else
updatedFlags &= ~(uint)ModuleFlags.JitOptimizationDisabled;
if ((updatedFlags & (uint)ModuleFlags.EncCapable) != 0)
{
TargetPointer configPtr = _target.ReadGlobalPointer(Constants.Globals.EEConfig);
Data.EEConfig config = _target.ProcessedData.GetOrAdd<Data.EEConfig>(configPtr);
ClrModifiableAssemblies modifiableAssemblies = (ClrModifiableAssemblies)config.ModifiableAssemblies;
if (modifiableAssemblies != ClrModifiableAssemblies.None)
{
bool encRequested = (newBits & DebuggerAssemblyControlFlags.DACF_ENC_ENABLED) != 0;
bool jitOptsDisabledForEnc = (updatedFlags & (uint)ModuleFlags.JitOptimizationDisabled) != 0;
bool setEnC = encRequested || (modifiableAssemblies == ClrModifiableAssemblies.Debug && jitOptsDisabledForEnc);
if (setEnC)
updatedFlags |= (uint)ModuleFlags.EditAndContinue;
}
}
module.WriteFlags(_target, updatedFlags);
}
bool ILoader.IsReadyToRun(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
return module.ReadyToRunInfo != TargetPointer.Null;
}
string ILoader.GetSimpleName(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
return module.SimpleName != TargetPointer.Null
? _target.ReadUtf8String(module.SimpleName, strict: true)
: string.Empty;
}
string ILoader.GetPath(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
return module.Path != TargetPointer.Null
? _target.ReadUtf16String(module.Path)
: string.Empty;
}
string ILoader.GetFileName(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
return module.FileName != TargetPointer.Null
? _target.ReadUtf16String(module.FileName)
: string.Empty;
}
TargetPointer ILoader.GetLoaderAllocator(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
return module.LoaderAllocator;
}
TargetPointer ILoader.GetILBase(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
return module.Base;
}
TargetPointer ILoader.GetAssemblyLoadContext(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
Data.PEAssembly peAssembly = _target.ProcessedData.GetOrAdd<Data.PEAssembly>(module.PEAssembly);
Data.AssemblyBinder binder = _target.ProcessedData.GetOrAdd<Data.AssemblyBinder>(peAssembly.AssemblyBinder);
return binder.AssemblyLoadContext.Object;
}
ModuleLookupTables ILoader.GetLookupTables(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
return new ModuleLookupTables(
module.FieldDefToDescMap,
module.ManifestModuleReferencesMap,
module.MemberRefToDescMap,
module.MethodDefToDescMap,
module.TypeDefToMethodTableMap,
module.TypeRefToMethodTableMap,
module.MethodDefToILCodeVersioningStateMap);
}
private static (bool Done, uint NextIndex) IterateLookupMap(uint index) => (false, index + 1);
private static (bool Done, uint NextIndex) SearchLookupMap(uint index) => (true, index);
private delegate (bool Done, uint NextIndex) Delegate(uint index);
private IEnumerable<(TargetPointer, uint)> IterateModuleLookupMap(TargetPointer table, uint index, Delegate iterator)
{
bool doneIterating;
do
{
Data.ModuleLookupMap lookupMap = _target.ProcessedData.GetOrAdd<Data.ModuleLookupMap>(table);
if (index < lookupMap.Count)
{
TargetPointer entryAddress = lookupMap.TableData + (ulong)(index * _target.PointerSize);
TargetPointer rawValue = _target.ReadPointer(entryAddress);
yield return (rawValue, index);
(doneIterating, index) = iterator(index);
if (doneIterating)
yield break;
}
else
{
table = lookupMap.Next;
index -= lookupMap.Count;
}
} while (table != TargetPointer.Null);
}
TargetPointer ILoader.GetModuleLookupMapElement(TargetPointer table, uint token, out TargetNUInt flags)
{
uint rid = EcmaMetadataUtils.GetRowId(token);
if (table == TargetPointer.Null || rid == 0)
{
flags = new TargetNUInt(0);
return TargetPointer.Null;
}
Data.ModuleLookupMap lookupMap = _target.ProcessedData.GetOrAdd<Data.ModuleLookupMap>(table);
ulong supportedFlagsMask = lookupMap.SupportedFlagsMask.Value;
(TargetPointer rval, uint _) = IterateModuleLookupMap(table, rid, SearchLookupMap).FirstOrDefault();
flags = new TargetNUInt(rval & supportedFlagsMask);
return rval & ~supportedFlagsMask;
}
IEnumerable<(TargetPointer, uint)> ILoader.EnumerateModuleLookupMap(TargetPointer table)
{
if (table == TargetPointer.Null)
yield break;
Data.ModuleLookupMap lookupMap = _target.ProcessedData.GetOrAdd<Data.ModuleLookupMap>(table);
ulong supportedFlagsMask = lookupMap.SupportedFlagsMask.Value;
TargetNUInt flags = new TargetNUInt(0);
uint index = 1; // zero is invalid
foreach ((TargetPointer targetPointer, uint idx) in IterateModuleLookupMap(table, index, IterateLookupMap))
{
TargetPointer rval = targetPointer & ~supportedFlagsMask;
if (rval != TargetPointer.Null)
yield return (rval, idx);
}
}
bool ILoader.IsCollectible(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
Data.Assembly la = _target.ProcessedData.GetOrAdd<Data.Assembly>(module.Assembly);
return la.IsCollectible != 0;
}
bool ILoader.IsDynamic(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
Data.Assembly assembly = _target.ProcessedData.GetOrAdd<Data.Assembly>(module.Assembly);
return assembly.IsDynamic;
}
bool ILoader.IsAssemblyLoaded(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
Data.Assembly assembly = _target.ProcessedData.GetOrAdd<Data.Assembly>(module.Assembly);
return assembly.IsLoaded;
}
TargetPointer ILoader.GetGlobalLoaderAllocator()
{
TargetPointer systemDomainPointer = _target.ReadGlobalPointer(Constants.Globals.SystemDomain);
Data.SystemDomain systemDomain = _target.ProcessedData.GetOrAdd<Data.SystemDomain>(_target.ReadPointer(systemDomainPointer));
return systemDomain.GlobalLoaderAllocator;
}
TargetPointer ILoader.GetSystemAssembly()
{
TargetPointer systemDomainPointer = _target.ReadGlobalPointer(Constants.Globals.SystemDomain);
Data.SystemDomain systemDomain = _target.ProcessedData.GetOrAdd<Data.SystemDomain>(_target.ReadPointer(systemDomainPointer));
return systemDomain.SystemAssembly;
}
TargetPointer ILoader.GetHighFrequencyHeap(TargetPointer loaderAllocatorPointer)
{
Data.LoaderAllocator loaderAllocator = _target.ProcessedData.GetOrAdd<Data.LoaderAllocator>(loaderAllocatorPointer);
return loaderAllocator.HighFrequencyHeap;
}
TargetPointer ILoader.GetLowFrequencyHeap(TargetPointer loaderAllocatorPointer)
{
Data.LoaderAllocator loaderAllocator = _target.ProcessedData.GetOrAdd<Data.LoaderAllocator>(loaderAllocatorPointer);
return loaderAllocator.LowFrequencyHeap;
}
TargetPointer ILoader.GetStubHeap(TargetPointer loaderAllocatorPointer)
{
Data.LoaderAllocator loaderAllocator = _target.ProcessedData.GetOrAdd<Data.LoaderAllocator>(loaderAllocatorPointer);
return loaderAllocator.StubHeap;
}
TargetPointer ILoader.GetObjectHandle(TargetPointer loaderAllocatorPointer)
{
Data.LoaderAllocator loaderAllocator = _target.ProcessedData.GetOrAdd<Data.LoaderAllocator>(loaderAllocatorPointer);
return loaderAllocator.ObjectHandle.Handle;
}
private int GetRVAFromMetadata(ModuleHandle handle, int token)
{
IEcmaMetadata ecmaMetadataContract = _target.Contracts.EcmaMetadata;
MetadataReader? mdReader = ecmaMetadataContract.GetMetadata(handle);
if (mdReader == null)
throw new NotImplementedException();
MethodDefinition methodDef = mdReader.GetMethodDefinition(MetadataTokens.MethodDefinitionHandle(token));
return methodDef.RelativeVirtualAddress;
}
TargetPointer ILoader.GetILHeader(ModuleHandle handle, uint token)
{
// we need module
ILoader loader = this;
TargetPointer headerPtr = loader.GetDynamicIL(handle, token);
if (headerPtr == TargetPointer.Null)
{
TargetPointer peAssembly = loader.GetPEAssembly(handle);
int rva = GetRVAFromMetadata(handle, (int)token);
headerPtr = loader.GetILAddr(peAssembly, rva);
}
return headerPtr;
}
private sealed class DynamicILBlobTraits : ITraits<uint, DynamicILBlobEntry>
{
public uint GetKey(DynamicILBlobEntry entry) => entry.EntryMethodToken;
public bool Equals(uint left, uint right) => left == right;
public uint Hash(uint key) => key;
public bool IsNull(DynamicILBlobEntry entry) => entry.EntryMethodToken == 0;
public DynamicILBlobEntry Null() => new DynamicILBlobEntry(0, TargetPointer.Null);
public bool IsDeleted(DynamicILBlobEntry entry) => false;
}
private sealed class DynamicILBlobTable : IData<DynamicILBlobTable>
{
static DynamicILBlobTable IData<DynamicILBlobTable>.Create(Target target, TargetPointer address)
=> new DynamicILBlobTable(target, address);
public DynamicILBlobTable(Target target, TargetPointer address)
{
ISHash sHashContract = target.Contracts.SHash;
Target.TypeInfo type = target.GetTypeInfo(DataType.DynamicILBlobTable);
HashTable = sHashContract.CreateSHash(target, address, type, new DynamicILBlobTraits());
}
public ISHash<uint, DynamicILBlobEntry> HashTable { get; init; }
}
TargetPointer ILoader.GetDynamicIL(ModuleHandle handle, uint token)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
if (module.DynamicILBlobTable == TargetPointer.Null)
{
return TargetPointer.Null;
}
DynamicILBlobTable dynamicILBlobTable = _target.ProcessedData.GetOrAdd<DynamicILBlobTable>(module.DynamicILBlobTable);
ISHash shashContract = _target.Contracts.SHash;
return shashContract.LookupSHash(dynamicILBlobTable.HashTable, token).EntryIL;
}
TargetPointer ILoader.GetFirstLoaderHeapBlock(TargetPointer loaderHeap)
{
return _target.ProcessedData.GetOrAdd<Data.LoaderHeap>(loaderHeap).FirstBlock;
}
LoaderHeapBlockData ILoader.GetLoaderHeapBlockData(TargetPointer block)
{
Data.LoaderHeapBlock blockData = _target.ProcessedData.GetOrAdd<Data.LoaderHeapBlock>(block);
return new LoaderHeapBlockData
{
Address = blockData.VirtualAddress,
Size = blockData.VirtualSize,
NextBlock = blockData.Next,
};
}
IReadOnlyDictionary<LoaderAllocatorHeapType, TargetPointer> ILoader.GetLoaderAllocatorHeaps(TargetPointer loaderAllocatorPointer)
{
Data.LoaderAllocator loaderAllocator = _target.ProcessedData.GetOrAdd<Data.LoaderAllocator>(loaderAllocatorPointer);
Target.TypeInfo laType = _target.GetTypeInfo(DataType.LoaderAllocator);
Dictionary<LoaderAllocatorHeapType, TargetPointer> heaps = new()
{
[LoaderAllocatorHeapType.LowFrequencyHeap] = loaderAllocator.LowFrequencyHeap,
[LoaderAllocatorHeapType.HighFrequencyHeap] = loaderAllocator.HighFrequencyHeap,
[LoaderAllocatorHeapType.StaticsHeap] = loaderAllocator.StaticsHeap,
[LoaderAllocatorHeapType.StubHeap] = loaderAllocator.StubHeap,
[LoaderAllocatorHeapType.ExecutableHeap] = loaderAllocator.ExecutableHeap,
};
if (laType.Fields.ContainsKey(nameof(Data.LoaderAllocator.FixupPrecodeHeap)))
heaps[LoaderAllocatorHeapType.FixupPrecodeHeap] = loaderAllocator.FixupPrecodeHeap!.Value;
if (laType.Fields.ContainsKey(nameof(Data.LoaderAllocator.NewStubPrecodeHeap)))
heaps[LoaderAllocatorHeapType.NewStubPrecodeHeap] = loaderAllocator.NewStubPrecodeHeap!.Value;
if (laType.Fields.ContainsKey(nameof(Data.LoaderAllocator.DynamicHelpersStubHeap)))
heaps[LoaderAllocatorHeapType.DynamicHelpersStubHeap] = loaderAllocator.DynamicHelpersStubHeap!.Value;
if (loaderAllocator.VirtualCallStubManager != TargetPointer.Null)
{
Data.VirtualCallStubManager vcsMgr = _target.ProcessedData.GetOrAdd<Data.VirtualCallStubManager>(loaderAllocator.VirtualCallStubManager);
Target.TypeInfo vcsType = _target.GetTypeInfo(DataType.VirtualCallStubManager);
heaps[LoaderAllocatorHeapType.IndcellHeap] = vcsMgr.IndcellHeap;
if (vcsType.Fields.ContainsKey(nameof(Data.VirtualCallStubManager.CacheEntryHeap)))
heaps[LoaderAllocatorHeapType.CacheEntryHeap] = vcsMgr.CacheEntryHeap!.Value;
}
return heaps;
}
}
|