1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-08 03:27:04 +09:00

[cdac] Synthesize a valid ECMA-335 image for read/write metadata instead of providing a separate metadata reader (#106164)

* Synthesize a valid ECMA-335 image for read/write metadata instead of providing a separate metadata reader

* Remove copies

* Add a comment

* Create EcmaMetadata contract for handling all metadata retrieval and remove metadata handling completely from the Loader contract.

* Add EcmaMetadata contract to CoreCLR's list of implemented contracts

---------

Co-authored-by: Elinor Fung <elfung@microsoft.com>
This commit is contained in:
Jeremy Koritzinsky 2024-08-13 20:30:07 -07:00 committed by GitHub
parent f9c08462ba
commit bfd964a91f
Signed by: github
GPG key ID: B5690EEEBB952194
18 changed files with 816 additions and 1903 deletions

View file

@ -0,0 +1,340 @@
# Contract EcmaMetadata
This contract provides methods to get a view of the ECMA-335 metadata for a given module.
## APIs of contract
```csharp
TargetSpan GetReadOnlyMetadataAddress(ModuleHandle handle);
System.Reflection.Metadata.MetadataReader? GetMetadata(ModuleHandle handle);
```
Types from other contracts:
| Type | Contract |
|------|----------|
| ModuleHandle | [Loader](./Loader.md#apis-of-contract) |
## Version 1
Data descriptors used:
| Data Descriptor Name | Field | Meaning |
| --- | --- | --- |
| `Module` | `Base` | Pointer to start of PE file in memory |
| `Module` | `DynamicMetadata` | Pointer to saved metadata for reflection emit modules |
| `Module` | `FieldDefToDescMap` | Mapping table |
| `DynamicMetadata` | `Size` | Size of the dynamic metadata blob (as a 32bit uint) |
| `DynamicMetadata` | `Data` | Start of dynamic metadata data array |
```csharp
using System.IO;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
TargetSpan GetReadOnlyMetadataAddress(ModuleHandle handle)
{
TargetPointer baseAddress = Target.ReadPointer(handle.Address + /* Module::Base offset */);
if (baseAddress == TargetPointer.Null)
{
return default;
}
// Read CLR header per https://learn.microsoft.com/windows/win32/debug/pe-format
ulong clrHeaderRVA = ...
// Read Metadata per ECMA-335 II.25.3.3 CLI Header
ulong metadataDirectoryAddress = baseAddress + clrHeaderRva + /* offset to Metadata */
int rva = Target.Read<int>(metadataDirectoryAddress);
ulong size = Target.Read<int>(metadataDirectoryAddress + sizeof(int));
return new(baseAddress + rva, size);
}
MetadataReader? GetMetadata(ModuleHandle handle)
{
AvailableMetadataType type = GetAvailableMetadataType(handle);
switch (type)
{
case AvailableMetadataType.None:
return null;
case AvailableMetadataType.ReadOnly:
{
TargetSpan address = GetReadOnlyMetadataAddress(handle);
byte[] data = new byte[address.Size];
_target.ReadBuffer(address.Address, data);
return MetadataReaderProvider.FromMetadataImage(ImmutableCollectionsMarshal.AsImmutableArray(data)).GetMetadataReader();
}
case AvailableMetadataType.ReadWriteSavedCopy:
{
TargetSpan address = GetReadWriteSavedMetadataAddress(handle);
byte[] data = new byte[address.Size];
_target.ReadBuffer(address.Address, data);
return MetadataReaderProvider.FromMetadataImage(ImmutableCollectionsMarshal.AsImmutableArray(data)).GetMetadataReader();
}
case AvailableMetadataType.ReadWrite:
{
var targetEcmaMetadata = GetReadWriteMetadata(handle);
// From the multiple different target spans, we need to build a single
// contiguous ECMA-335 metadata blob.
BlobBuilder builder = new BlobBuilder();
builder.WriteUInt32(0x424A5342);
// major version
builder.WriteUInt16(1);
// minor version
builder.WriteUInt16(1);
// reserved
builder.WriteUInt32(0);
string version = targetEcmaMetadata.Schema.MetadataVersion;
builder.WriteInt32(AlignUp(version.Length, 4));
Write4ByteAlignedString(builder, version);
// reserved
builder.WriteUInt16(0);
// number of streams
ushort numStreams = 5; // #Strings, #US, #Blob, #GUID, #~ (metadata)
if (targetEcmaMetadata.Schema.VariableSizedColumnsAreAll4BytesLong)
{
// We direct MetadataReader to use 4-byte encoding for all variable-sized columns
// by providing the marker stream for a "minimal delta" image.
numStreams++;
}
builder.WriteUInt16(numStreams);
// Write Stream headers
if (targetEcmaMetadata.Schema.VariableSizedColumnsAreAll4BytesLong)
{
// Write the #JTD stream to indicate that all variable-sized columns are 4 bytes long.
WriteStreamHeader(builder, "#JTD", 0).WriteInt32(builder.Count);
}
BlobWriter stringsOffset = WriteStreamHeader(builder, "#Strings", (int)AlignUp(targetEcmaMetadata.StringHeap.Size, 4ul));
BlobWriter blobOffset = WriteStreamHeader(builder, "#Blob", (int)targetEcmaMetadata.BlobHeap.Size);
BlobWriter guidOffset = WriteStreamHeader(builder, "#GUID", (int)targetEcmaMetadata.GuidHeap.Size);
BlobWriter userStringOffset = WriteStreamHeader(builder, "#US", (int)targetEcmaMetadata.UserStringHeap.Size);
// We'll use the "uncompressed" tables stream name as the runtime may have created the *Ptr tables
// that are only present in the uncompressed tables stream.
BlobWriter tablesOffset = WriteStreamHeader(builder, "#-", 0);
// Write the heap-style Streams
stringsOffset.WriteInt32(builder.Count);
WriteTargetSpan(builder, targetEcmaMetadata.StringHeap);
for (ulong i = targetEcmaMetadata.StringHeap.Size; i < AlignUp(targetEcmaMetadata.StringHeap.Size, 4ul); i++)
{
builder.WriteByte(0);
}
blobOffset.WriteInt32(builder.Count);
WriteTargetSpan(builder, targetEcmaMetadata.BlobHeap);
guidOffset.WriteInt32(builder.Count);
WriteTargetSpan(builder, targetEcmaMetadata.GuidHeap);
userStringOffset.WriteInt32(builder.Count);
WriteTargetSpan(builder, targetEcmaMetadata.UserStringHeap);
// Write tables stream
tablesOffset.WriteInt32(builder.Count);
// Write tables stream header
builder.WriteInt32(0); // reserved
builder.WriteByte(2); // major version
builder.WriteByte(0); // minor version
uint heapSizes =
(targetEcmaMetadata.Schema.LargeStringHeap ? 1u << 0 : 0) |
(targetEcmaMetadata.Schema.LargeBlobHeap ? 1u << 1 : 0) |
(targetEcmaMetadata.Schema.LargeGuidHeap ? 1u << 2 : 0);
builder.WriteByte((byte)heapSizes);
builder.WriteByte(1); // reserved
ulong validTables = 0;
for (int i = 0; i < targetEcmaMetadata.Schema.RowCount.Length; i++)
{
if (targetEcmaMetadata.Schema.RowCount[i] != 0)
{
validTables |= 1ul << i;
}
}
ulong sortedTables = 0;
for (int i = 0; i < targetEcmaMetadata.Schema.IsSorted.Length; i++)
{
if (targetEcmaMetadata.Schema.IsSorted[i])
{
sortedTables |= 1ul << i;
}
}
builder.WriteUInt64(validTables);
builder.WriteUInt64(sortedTables);
foreach (int rowCount in targetEcmaMetadata.Schema.RowCount)
{
if (rowCount > 0)
{
builder.WriteInt32(rowCount);
}
}
// Write the tables
foreach (TargetSpan span in targetEcmaMetadata.Tables)
{
WriteTargetSpan(builder, span);
}
MemoryStream metadataStream = new MemoryStream();
builder.WriteContentTo(metadataStream);
return MetadataReaderProvider.FromMetadataStream(metadataStream).GetMetadataReader();
void WriteTargetSpan(BlobBuilder builder, TargetSpan span)
{
Blob blob = builder.ReserveBytes(checked((int)span.Size));
_target.ReadBuffer(span.Address, blob.GetBytes().AsSpan());
}
static BlobWriter WriteStreamHeader(BlobBuilder builder, string name, int size)
{
BlobWriter offset = new(builder.ReserveBytes(4));
builder.WriteInt32(size);
Write4ByteAlignedString(builder, name);
return offset;
}
static void Write4ByteAlignedString(BlobBuilder builder, string value)
{
int bufferStart = builder.Count;
builder.WriteUTF8(value);
builder.WriteByte(0);
int stringEnd = builder.Count;
for (int i = stringEnd; i < bufferStart + AlignUp(value.Length, 4); i++)
{
builder.WriteByte(0);
}
}
}
}
}
```
### Helper Methods
``` csharp
using System;
using System.Numerics;
struct EcmaMetadataSchema
{
public EcmaMetadataSchema(string metadataVersion, bool largeStringHeap, bool largeBlobHeap, bool largeGuidHeap, int[] rowCount, bool[] isSorted, bool variableSizedColumnsAre4BytesLong)
{
MetadataVersion = metadataVersion;
LargeStringHeap = largeStringHeap;
LargeBlobHeap = largeBlobHeap;
LargeGuidHeap = largeGuidHeap;
_rowCount = rowCount;
_isSorted = isSorted;
VariableSizedColumnsAreAll4BytesLong = variableSizedColumnsAre4BytesLong;
}
public readonly string MetadataVersion;
public readonly bool LargeStringHeap;
public readonly bool LargeBlobHeap;
public readonly bool LargeGuidHeap;
// Table data, these structures hold MetadataTable.Count entries
private readonly int[] _rowCount;
public readonly ReadOnlySpan<int> RowCount => _rowCount;
private readonly bool[] _isSorted;
public readonly ReadOnlySpan<bool> IsSorted => _isSorted;
// In certain scenarios the size of the tables is forced to be the maximum size
// Otherwise the size of columns should be computed based on RowSize/the various heap flags
public readonly bool VariableSizedColumnsAreAll4BytesLong;
}
class TargetEcmaMetadata
{
public TargetEcmaMetadata(EcmaMetadataSchema schema,
TargetSpan[] tables,
TargetSpan stringHeap,
TargetSpan userStringHeap,
TargetSpan blobHeap,
TargetSpan guidHeap)
{
Schema = schema;
_tables = tables;
StringHeap = stringHeap;
UserStringHeap = userStringHeap;
BlobHeap = blobHeap;
GuidHeap = guidHeap;
}
public EcmaMetadataSchema Schema { get; init; }
private TargetSpan[] _tables;
public ReadOnlySpan<TargetSpan> Tables => _tables;
public TargetSpan StringHeap { get; init; }
public TargetSpan UserStringHeap { get; init; }
public TargetSpan BlobHeap { get; init; }
public TargetSpan GuidHeap { get; init; }
}
[Flags]
enum AvailableMetadataType
{
None = 0,
ReadOnly = 1,
ReadWriteSavedCopy = 2,
ReadWrite = 4
}
AvailableMetadataType GetAvailableMetadataType(ModuleHandle handle)
{
Data.Module module = new Data.Module(Target, handle.Address);
AvailableMetadataType flags = AvailableMetadataType.None;
TargetPointer dynamicMetadata = Target.ReadPointer(handle.Address + /* Module::DynamicMetadata offset */);
if (dynamicMetadata != TargetPointer.Null)
flags |= AvailableMetadataType.ReadWriteSavedCopy;
else
flags |= AvailableMetadataType.ReadOnly;
return flags;
}
TargetSpan GetReadWriteSavedMetadataAddress(ModuleHandle handle)
{
Data.Module module = new Data.Module(Target, handle.Address);
TargetPointer dynamicMetadata = Target.ReadPointer(handle.Address + /* Module::DynamicMetadata offset */);
ulong size = Target.Read<uint>(handle.Address + /* DynamicMetadata::Size offset */);
TargetPointer result = handle.Address + /* DynamicMetadata::Data offset */;
return new(result, size);
}
TargetEcmaMetadata GetReadWriteMetadata(ModuleHandle handle)
{
// [cdac] TODO.
}
T AlignUp<T>(T input, T alignment)
where T : IBinaryInteger<T>
{
return input + (alignment - T.One) & ~(alignment - T.One);
}
```

View file

@ -27,89 +27,16 @@ record struct ModuleLookupTables(
TargetPointer TypeDefToMethodTable,
TargetPointer TypeRefToMethodTable,
TargetPointer MethodDefToILCodeVersioningState);
internal struct EcmaMetadataSchema
{
public EcmaMetadataSchema(string metadataVersion, bool largeStringHeap, bool largeBlobHeap, bool largeGuidHeap, int[] rowCount, bool[] isSorted, bool variableSizedColumnsAre4BytesLong)
{
MetadataVersion = metadataVersion;
LargeStringHeap = largeStringHeap;
LargeBlobHeap = largeBlobHeap;
LargeGuidHeap = largeGuidHeap;
_rowCount = rowCount;
_isSorted = isSorted;
VariableSizedColumnsAreAll4BytesLong = variableSizedColumnsAre4BytesLong;
}
public readonly string MetadataVersion;
public readonly bool LargeStringHeap;
public readonly bool LargeBlobHeap;
public readonly bool LargeGuidHeap;
// Table data, these structures hold MetadataTable.Count entries
private readonly int[] _rowCount;
public readonly ReadOnlySpan<int> RowCount => _rowCount;
private readonly bool[] _isSorted;
public readonly ReadOnlySpan<bool> IsSorted => _isSorted;
// In certain scenarios the size of the tables is forced to be the maximum size
// Otherwise the size of columns should be computed based on RowSize/the various heap flags
public readonly bool VariableSizedColumnsAreAll4BytesLong;
}
internal class TargetEcmaMetadata
{
public TargetEcmaMetadata(EcmaMetadataSchema schema,
TargetSpan[] tables,
TargetSpan stringHeap,
TargetSpan userStringHeap,
TargetSpan blobHeap,
TargetSpan guidHeap)
{
Schema = schema;
_tables = tables;
StringHeap = stringHeap;
UserStringHeap = userStringHeap;
BlobHeap = blobHeap;
GuidHeap = guidHeap;
}
public EcmaMetadataSchema Schema { get; init; }
private TargetSpan[] _tables;
public ReadOnlySpan<TargetSpan> Tables => _tables;
public TargetSpan StringHeap { get; init; }
public TargetSpan UserStringHeap { get; init; }
public TargetSpan BlobHeap { get; init; }
public TargetSpan GuidHeap { get; init; }
}
[Flags]
internal enum AvailableMetadataType
{
None = 0,
ReadOnly = 1,
ReadWriteSavedCopy = 2,
ReadWrite = 4
}
```
``` csharp
ModuleHandle GetModuleHandle(TargetPointer);
ModuleHandle GetModuleHandle(TargetPointer module);
TargetPointer GetAssembly(ModuleHandle handle);
ModuleFlags GetFlags(ModuleHandle handle);
string GetPath(ModuleHandle handle);
TargetPointer GetLoaderAllocator(ModuleHandle handle);
TargetPointer GetThunkHeap(ModuleHandle handle);
TargetPointer GetILBase(ModuleHandle handle);
TargetPointer GetMetadataAddress(ModuleHandle handle, out ulong size);
AvailableMetadataType GetAvailableMetadataType(ModuleHandle handle);
TargetPointer GetReadWriteSavedMetadataAddress(ModuleHandle handle, out ulong size);
TargetEcmaMetadata GetReadWriteMetadata(ModuleHandle handle);
ModuleLookupTables GetLookupTables(ModuleHandle handle);
```
@ -124,15 +51,12 @@ Data descriptors used:
| `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 |
| `Module` | `MemberRefToDescMap` | Mapping table |
| `Module` | `MethodDefToDescMap` | Mapping table |
| `Module` | `TypeDefToMethodTableMap` | Mapping table |
| `Module` | `TypeRefToMethodTableMap` | Mapping table |
| `DynamicMetadata` | `Size` | Size of the dynamic metadata blob (as a 32bit uint) |
| `DynamicMetadata` | `Data` | Start of dynamic metadata data array |
| `ModuleLookupMap` | `TableData` | Start of the mapping table's data |
``` csharp
@ -173,51 +97,6 @@ TargetPointer GetILBase(ModuleHandle handle)
return target.ReadPointer(handle.Address + /* Module::Base offset */);
}
TargetPointer GetMetadataAddress(ModuleHandle handle, out ulong size)
{
TargetPointer baseAddress = GetILBase(handle);
if (baseAddress == TargetPointer.Null)
{
size = 0;
return TargetPointer.Null;
}
// Read CLR header per https://learn.microsoft.com/windows/win32/debug/pe-format
ulong clrHeaderRVA = ...
// Read Metadata per ECMA-335 II.25.3.3 CLI Header
ulong metadataDirectoryAddress = baseAddress + clrHeaderRva + /* offset to Metadata */
int rva = target.Read<int>(metadataDirectoryAddress);
size = target.Read<int>(metadataDirectoryAddress + sizeof(int));
return baseAddress + rva;
}
AvailableMetadataType ILoader.GetAvailableMetadataType(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
AvailableMetadataType flags = AvailableMetadataType.None;
TargetPointer dynamicMetadata = target.ReadPointer(handle.Address + /* Module::DynamicMetadata offset */);
if (dynamicMetadata != TargetPointer.Null)
flags |= AvailableMetadataType.ReadWriteSavedCopy;
else
flags |= AvailableMetadataType.ReadOnly;
return flags;
}
TargetPointer ILoader.GetReadWriteSavedMetadataAddress(ModuleHandle handle, out ulong size)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
TargetPointer dynamicMetadata = target.ReadPointer(handle.Address + /* Module::DynamicMetadata offset */);
size = target.Read<uint>(handle.Address + /* DynamicMetadata::Size offset */);
TargetPointer result = handle.Address + /* DynamicMetadata::Data offset */;
return result;
}
ModuleLookupTables GetLookupTables(ModuleHandle handle)
{
return new ModuleLookupTables(

View file

@ -37,6 +37,18 @@ namespace DataContracts
// Add a full set of operators to support pointer arithmetic
}
public readonly struct TargetSpan
{
public TargetSpan(TargetPointer address, ulong size)
{
Address = address;
Size = size;
}
public TargetPointer Address { get; }
public ulong Size { get; }
}
struct TargetNInt
{
public long Value;

View file

@ -10,6 +10,7 @@
// so to conditionally include contracts, put additional contracts in a separate file
{
"DacStreams": 1,
"EcmaMetadata" : 1,
"Exception": 1,
"Loader": 1,
"Object": 1,

View file

@ -0,0 +1,29 @@
// 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.Reflection.Metadata;
namespace Microsoft.Diagnostics.DataContractReader.Contracts;
internal interface IEcmaMetadata : IContract
{
static string IContract.Name { get; } = nameof(EcmaMetadata);
static IContract IContract.Create(Target target, int version)
{
return version switch
{
1 => new EcmaMetadata_1(target),
_ => default(EcmaMetadata),
};
}
public virtual TargetSpan GetReadOnlyMetadataAddress(ModuleHandle handle) => throw new NotImplementedException();
public virtual MetadataReader? GetMetadata(ModuleHandle module) => throw new NotImplementedException();
}
internal readonly struct EcmaMetadata : IEcmaMetadata
{
// Everything throws NotImplementedException
}

View file

@ -0,0 +1,318 @@
// 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.IO;
using System.Numerics;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
namespace Microsoft.Diagnostics.DataContractReader.Contracts;
internal class EcmaMetadata_1(Target target) : IEcmaMetadata
{
private Dictionary<ModuleHandle, MetadataReaderProvider?> _metadata = new();
public TargetSpan GetReadOnlyMetadataAddress(ModuleHandle handle)
{
Data.Module module = target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
TargetPointer baseAddress = module.GetLoadedMetadata(out ulong size);
return new TargetSpan(baseAddress, size);
}
public MetadataReader? GetMetadata(ModuleHandle handle)
{
if (_metadata.TryGetValue(handle, out MetadataReaderProvider? result))
{
return result?.GetMetadataReader();
}
else
{
MetadataReaderProvider? provider = GetMetadataProvider(handle);
_metadata.Add(handle, provider);
return provider?.GetMetadataReader();
}
}
private MetadataReaderProvider? GetMetadataProvider(ModuleHandle handle)
{
AvailableMetadataType type = GetAvailableMetadataType(handle);
switch (type)
{
case AvailableMetadataType.None:
return null;
case AvailableMetadataType.ReadOnly:
{
TargetSpan address = GetReadOnlyMetadataAddress(handle);
byte[] data = new byte[address.Size];
target.ReadBuffer(address.Address, data);
return MetadataReaderProvider.FromMetadataImage(ImmutableCollectionsMarshal.AsImmutableArray(data));
}
case AvailableMetadataType.ReadWriteSavedCopy:
{
TargetSpan address = GetReadWriteSavedMetadataAddress(handle);
byte[] data = new byte[address.Size];
target.ReadBuffer(address.Address, data);
return MetadataReaderProvider.FromMetadataImage(ImmutableCollectionsMarshal.AsImmutableArray(data));
}
case AvailableMetadataType.ReadWrite:
{
var targetEcmaMetadata = GetReadWriteMetadata(handle);
// From the multiple different target spans, we need to build a single
// contiguous ECMA-335 metadata blob.
BlobBuilder builder = new BlobBuilder();
builder.WriteUInt32(0x424A5342);
// major version
builder.WriteUInt16(1);
// minor version
builder.WriteUInt16(1);
// reserved
builder.WriteUInt32(0);
string version = targetEcmaMetadata.Schema.MetadataVersion;
builder.WriteInt32(AlignUp(version.Length, 4));
Write4ByteAlignedString(builder, version);
// reserved
builder.WriteUInt16(0);
// number of streams
ushort numStreams = 5; // #Strings, #US, #Blob, #GUID, #~ (metadata)
if (targetEcmaMetadata.Schema.VariableSizedColumnsAreAll4BytesLong)
{
// We direct MetadataReader to use 4-byte encoding for all variable-sized columns
// by providing the marker stream for a "minimal delta" image.
numStreams++;
}
builder.WriteUInt16(numStreams);
// Write Stream headers
if (targetEcmaMetadata.Schema.VariableSizedColumnsAreAll4BytesLong)
{
// Write the #JTD stream to indicate that all variable-sized columns are 4 bytes long.
WriteStreamHeader(builder, "#JTD", 0).WriteInt32(builder.Count);
}
BlobWriter stringsOffset = WriteStreamHeader(builder, "#Strings", (int)AlignUp(targetEcmaMetadata.StringHeap.Size, 4ul));
BlobWriter blobOffset = WriteStreamHeader(builder, "#Blob", (int)targetEcmaMetadata.BlobHeap.Size);
BlobWriter guidOffset = WriteStreamHeader(builder, "#GUID", (int)targetEcmaMetadata.GuidHeap.Size);
BlobWriter userStringOffset = WriteStreamHeader(builder, "#US", (int)targetEcmaMetadata.UserStringHeap.Size);
// We'll use the "uncompressed" tables stream name as the runtime may have created the *Ptr tables
// that are only present in the uncompressed tables stream.
BlobWriter tablesOffset = WriteStreamHeader(builder, "#-", 0);
// Write the heap-style Streams
stringsOffset.WriteInt32(builder.Count);
WriteTargetSpan(builder, targetEcmaMetadata.StringHeap);
for (ulong i = targetEcmaMetadata.StringHeap.Size; i < AlignUp(targetEcmaMetadata.StringHeap.Size, 4ul); i++)
{
builder.WriteByte(0);
}
blobOffset.WriteInt32(builder.Count);
WriteTargetSpan(builder, targetEcmaMetadata.BlobHeap);
guidOffset.WriteInt32(builder.Count);
WriteTargetSpan(builder, targetEcmaMetadata.GuidHeap);
userStringOffset.WriteInt32(builder.Count);
WriteTargetSpan(builder, targetEcmaMetadata.UserStringHeap);
// Write tables stream
tablesOffset.WriteInt32(builder.Count);
// Write tables stream header
builder.WriteInt32(0); // reserved
builder.WriteByte(2); // major version
builder.WriteByte(0); // minor version
uint heapSizes =
(targetEcmaMetadata.Schema.LargeStringHeap ? 1u << 0 : 0) |
(targetEcmaMetadata.Schema.LargeBlobHeap ? 1u << 1 : 0) |
(targetEcmaMetadata.Schema.LargeGuidHeap ? 1u << 2 : 0);
builder.WriteByte((byte)heapSizes);
builder.WriteByte(1); // reserved
ulong validTables = 0;
for (int i = 0; i < targetEcmaMetadata.Schema.RowCount.Length; i++)
{
if (targetEcmaMetadata.Schema.RowCount[i] != 0)
{
validTables |= 1ul << i;
}
}
ulong sortedTables = 0;
for (int i = 0; i < targetEcmaMetadata.Schema.IsSorted.Length; i++)
{
if (targetEcmaMetadata.Schema.IsSorted[i])
{
sortedTables |= 1ul << i;
}
}
builder.WriteUInt64(validTables);
builder.WriteUInt64(sortedTables);
foreach (int rowCount in targetEcmaMetadata.Schema.RowCount)
{
if (rowCount > 0)
{
builder.WriteInt32(rowCount);
}
}
// Write the tables
foreach (TargetSpan span in targetEcmaMetadata.Tables)
{
WriteTargetSpan(builder, span);
}
MemoryStream metadataStream = new MemoryStream();
builder.WriteContentTo(metadataStream);
return MetadataReaderProvider.FromMetadataStream(metadataStream);
void WriteTargetSpan(BlobBuilder builder, TargetSpan span)
{
Blob blob = builder.ReserveBytes(checked((int)span.Size));
target.ReadBuffer(span.Address, blob.GetBytes().AsSpan());
}
static BlobWriter WriteStreamHeader(BlobBuilder builder, string name, int size)
{
BlobWriter offset = new(builder.ReserveBytes(4));
builder.WriteInt32(size);
Write4ByteAlignedString(builder, name);
return offset;
}
static void Write4ByteAlignedString(BlobBuilder builder, string value)
{
int bufferStart = builder.Count;
builder.WriteUTF8(value);
builder.WriteByte(0);
int stringEnd = builder.Count;
for (int i = stringEnd; i < bufferStart + AlignUp(value.Length, 4); i++)
{
builder.WriteByte(0);
}
}
}
default:
throw new NotImplementedException();
}
}
private struct EcmaMetadataSchema
{
public EcmaMetadataSchema(string metadataVersion, bool largeStringHeap, bool largeBlobHeap, bool largeGuidHeap, int[] rowCount, bool[] isSorted, bool variableSizedColumnsAre4BytesLong)
{
MetadataVersion = metadataVersion;
LargeStringHeap = largeStringHeap;
LargeBlobHeap = largeBlobHeap;
LargeGuidHeap = largeGuidHeap;
_rowCount = rowCount;
_isSorted = isSorted;
VariableSizedColumnsAreAll4BytesLong = variableSizedColumnsAre4BytesLong;
}
public readonly string MetadataVersion;
public readonly bool LargeStringHeap;
public readonly bool LargeBlobHeap;
public readonly bool LargeGuidHeap;
// Table data, these structures hold MetadataTable.Count entries
private readonly int[] _rowCount;
public readonly ReadOnlySpan<int> RowCount => _rowCount;
private readonly bool[] _isSorted;
public readonly ReadOnlySpan<bool> IsSorted => _isSorted;
// In certain scenarios the size of the tables is forced to be the maximum size
// Otherwise the size of columns should be computed based on RowSize/the various heap flags
public readonly bool VariableSizedColumnsAreAll4BytesLong;
}
private class TargetEcmaMetadata
{
public TargetEcmaMetadata(EcmaMetadataSchema schema,
TargetSpan[] tables,
TargetSpan stringHeap,
TargetSpan userStringHeap,
TargetSpan blobHeap,
TargetSpan guidHeap)
{
Schema = schema;
_tables = tables;
StringHeap = stringHeap;
UserStringHeap = userStringHeap;
BlobHeap = blobHeap;
GuidHeap = guidHeap;
}
public EcmaMetadataSchema Schema { get; init; }
private TargetSpan[] _tables;
public ReadOnlySpan<TargetSpan> Tables => _tables;
public TargetSpan StringHeap { get; init; }
public TargetSpan UserStringHeap { get; init; }
public TargetSpan BlobHeap { get; init; }
public TargetSpan GuidHeap { get; init; }
}
[Flags]
private enum AvailableMetadataType
{
None = 0,
ReadOnly = 1,
ReadWriteSavedCopy = 2,
ReadWrite = 4
}
private AvailableMetadataType GetAvailableMetadataType(ModuleHandle handle)
{
Data.Module module = target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
AvailableMetadataType flags = AvailableMetadataType.None;
if (module.DynamicMetadata != TargetPointer.Null)
flags |= AvailableMetadataType.ReadWriteSavedCopy;
else
flags |= AvailableMetadataType.ReadOnly;
// TODO(cdac) implement direct reading of unsaved ReadWrite metadata
return flags;
}
private TargetSpan GetReadWriteSavedMetadataAddress(ModuleHandle handle)
{
Data.Module module = target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
Data.DynamicMetadata dynamicMetadata = target.ProcessedData.GetOrAdd<Data.DynamicMetadata>(module.DynamicMetadata);
return new TargetSpan(dynamicMetadata.Data, dynamicMetadata.Size);
}
private TargetEcmaMetadata GetReadWriteMetadata(ModuleHandle handle)
{
throw new NotImplementedException();
}
private static T AlignUp<T>(T input, T alignment)
where T : IBinaryInteger<T>
{
return input + (alignment - T.One) & ~(alignment - T.One);
}
}

View file

@ -32,75 +32,6 @@ internal record struct ModuleLookupTables(
TargetPointer TypeRefToMethodTable,
TargetPointer MethodDefToILCodeVersioningState);
internal struct EcmaMetadataSchema
{
public EcmaMetadataSchema(string metadataVersion, bool largeStringHeap, bool largeBlobHeap, bool largeGuidHeap, int[] rowCount, bool[] isSorted, bool variableSizedColumnsAre4BytesLong)
{
MetadataVersion = metadataVersion;
LargeStringHeap = largeStringHeap;
LargeBlobHeap = largeBlobHeap;
LargeGuidHeap = largeGuidHeap;
_rowCount = rowCount;
_isSorted = isSorted;
VariableSizedColumnsAreAll4BytesLong = variableSizedColumnsAre4BytesLong;
}
public readonly string MetadataVersion;
public readonly bool LargeStringHeap;
public readonly bool LargeBlobHeap;
public readonly bool LargeGuidHeap;
// Table data, these structures hold MetadataTable.Count entries
private readonly int[] _rowCount;
public readonly ReadOnlySpan<int> RowCount => _rowCount;
private readonly bool[] _isSorted;
public readonly ReadOnlySpan<bool> IsSorted => _isSorted;
// In certain scenarios the size of the tables is forced to be the maximum size
// Otherwise the size of columns should be computed based on RowSize/the various heap flags
public readonly bool VariableSizedColumnsAreAll4BytesLong;
}
internal class TargetEcmaMetadata
{
public TargetEcmaMetadata(EcmaMetadataSchema schema,
TargetSpan[] tables,
TargetSpan stringHeap,
TargetSpan userStringHeap,
TargetSpan blobHeap,
TargetSpan guidHeap)
{
Schema = schema;
_tables = tables;
StringHeap = stringHeap;
UserStringHeap = userStringHeap;
BlobHeap = blobHeap;
GuidHeap = guidHeap;
}
public EcmaMetadataSchema Schema { get; init; }
private TargetSpan[] _tables;
public ReadOnlySpan<TargetSpan> Tables => _tables;
public TargetSpan StringHeap { get; init; }
public TargetSpan UserStringHeap { get; init; }
public TargetSpan BlobHeap { get; init; }
public TargetSpan GuidHeap { get; init; }
}
[Flags]
internal enum AvailableMetadataType
{
None = 0,
ReadOnly = 1,
ReadWriteSavedCopy = 2,
ReadWrite = 4
}
internal interface ILoader : IContract
{
static string IContract.Name => nameof(Loader);
@ -121,17 +52,7 @@ internal interface ILoader : IContract
public virtual TargetPointer GetLoaderAllocator(ModuleHandle handle) => throw new NotImplementedException();
public virtual TargetPointer GetThunkHeap(ModuleHandle handle) => throw new NotImplementedException();
public virtual TargetPointer GetILBase(ModuleHandle handle) => throw new NotImplementedException();
public virtual TargetPointer GetMetadataAddress(ModuleHandle handle, out ulong size) => throw new NotImplementedException();
public virtual AvailableMetadataType GetAvailableMetadataType(ModuleHandle handle) => throw new NotImplementedException();
public virtual TargetPointer GetReadWriteSavedMetadataAddress(ModuleHandle handle, out ulong size) => throw new NotImplementedException();
public virtual TargetEcmaMetadata GetReadWriteMetadata(ModuleHandle handle) => throw new NotImplementedException();
public virtual ModuleLookupTables GetLookupTables(ModuleHandle handle) => throw new NotImplementedException();
}

View file

@ -79,39 +79,6 @@ internal readonly struct Loader_1 : ILoader
return module.Base;
}
TargetPointer ILoader.GetMetadataAddress(ModuleHandle handle, out ulong size)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
return module.GetLoadedMetadata(out size);
}
AvailableMetadataType ILoader.GetAvailableMetadataType(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
AvailableMetadataType flags = AvailableMetadataType.None;
if (module.DynamicMetadata != TargetPointer.Null)
flags |= AvailableMetadataType.ReadWriteSavedCopy;
else
flags |= AvailableMetadataType.ReadOnly;
// TODO(cdac) implement direct reading of unsaved ReadWrite metadata
return flags;
}
TargetPointer ILoader.GetReadWriteSavedMetadataAddress(ModuleHandle handle, out ulong size)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
Data.DynamicMetadata dynamicMetadata = _target.ProcessedData.GetOrAdd<Data.DynamicMetadata>(module.DynamicMetadata);
TargetPointer result = dynamicMetadata.Data;
size = dynamicMetadata.Size;
return result;
}
TargetEcmaMetadata ILoader.GetReadWriteMetadata(ModuleHandle handle) => throw new NotImplementedException();
ModuleLookupTables ILoader.GetLookupTables(ModuleHandle handle)
{
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);

View file

@ -20,6 +20,7 @@ internal sealed class Registry
public IException Exception => GetContract<IException>();
public ILoader Loader => GetContract<ILoader>();
public IEcmaMetadata EcmaMetadata => GetContract<IEcmaMetadata>();
public IObject Object => GetContract<IObject>();
public IThread Thread => GetContract<IThread>();
public IRuntimeTypeSystem RuntimeTypeSystem => GetContract<IRuntimeTypeSystem>();

View file

@ -1,106 +0,0 @@
// 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.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Diagnostics.DataContractReader.Contracts;
namespace Microsoft.Diagnostics.DataContractReader.Helpers;
internal partial class EcmaMetadataReader
{
private int ColumnSize(MetadataColumnIndex column)
{
return columnSize[(int)column];
}
private int ColumnOffset(MetadataColumnIndex column)
{
return columnOffset[(int)column];
}
private int RowCount(MetadataTable table)
{
return _ecmaMetadata.Schema.RowCount[(int)table];
}
private bool TryReadTableEntry(ReadOnlySpan<byte> bytes, MetadataColumnIndex column, out uint value)
{
int size = ColumnSize(column);
ReadOnlySpan<byte> singleColumn = bytes.Slice(ColumnOffset(column), size);
if (size == 2)
{
if (TryReadCore<ushort>(singleColumn, out ushort valueAsShort))
{
value = valueAsShort;
return true;
}
value = 0;
return false;
}
if (size != 4)
throw new ArgumentOutOfRangeException(nameof(column));
return TryReadCore(singleColumn, out value);
}
private uint GetColumnRaw(EcmaMetadataCursor c, MetadataColumnIndex col_idx)
{
if (c.Table != ColumnTable(col_idx))
throw new ArgumentOutOfRangeException(nameof(col_idx));
if (!TryReadTableEntry(c.Row, col_idx, out uint rawResult))
{
throw new ArgumentOutOfRangeException(nameof(col_idx));
}
return rawResult;
}
private int RidEncodingBits(MetadataTable table)
{
if (table == MetadataTable.Unused)
return 0;
int countInTable = RowCount(table);
// Tables start at 1
countInTable++;
return 32 - BitOperations.LeadingZeroCount((uint)countInTable);
}
private int RidEncodingBytes(MetadataTable table)
{
if (RidEncodingBits(table) > 16)
return 4;
else
return 2;
}
private int CodedIndexEncodingBytes(ReadOnlySpan<MetadataTable> tablesEncoded)
{
uint encodingMask = BitOperations.RoundUpToPowerOf2((uint)tablesEncoded.Length) - 1;
int bitsForTableEncoding = 32 - BitOperations.LeadingZeroCount(encodingMask);
if (tablesEncoded.Length == 1)
{
Debug.Assert(bitsForTableEncoding == 0); // This is just a rid to token conversion, no extra bits.
}
if (tablesEncoded.Length == 3 && tablesEncoded[0] == (MetadataTable)(-2))
{
// Ptr scenario
return RidEncodingBytes(tablesEncoded[2]);
}
foreach (MetadataTable table in tablesEncoded)
{
if ((RidEncodingBits(table) + bitsForTableEncoding) > 16)
return 4;
}
return 2;
}
}

View file

@ -1,594 +0,0 @@
// 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.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Diagnostics.DataContractReader.Contracts;
namespace Microsoft.Diagnostics.DataContractReader.Helpers;
internal partial class EcmaMetadataReader
{
private enum ColumnType
{
Unknown,
TwoByteConstant,
FourByteConstant,
Utf8String,
Blob,
Guid,
Token
}
[Flags]
private enum PtrTablesPresent
{
None = 0,
Method = 1,
Field = 2,
Param = 4,
Property = 8,
Event = 16
}
private static readonly MetadataTable[] columnTable = GetColumnTables();
private static readonly ColumnType[] columnTypes = GetColumnTypes();
private static readonly Func<uint, uint>[][] columnTokenDecoders = GetColumnTokenDecoders();
private static readonly MetadataTable[][] codedIndexDecoderRing = ColumnDecodeData.GetCodedIndexDecoderRing();
private static ColumnType[] GetColumnTypes()
{
ColumnType[] columnTypes = new ColumnType[(int)MetadataColumnIndex.Count];
columnTypes[(int)MetadataColumnIndex.Module_Generation] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.Module_Name] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.Module_Mvid] = ColumnType.Guid;
columnTypes[(int)MetadataColumnIndex.Module_EncId] = ColumnType.Guid;
columnTypes[(int)MetadataColumnIndex.Module_EncBaseId] = ColumnType.Guid;
columnTypes[(int)MetadataColumnIndex.TypeRef_ResolutionScope] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.TypeRef_TypeName] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.TypeRef_TypeNamespace] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.TypeDef_Flags] = ColumnType.FourByteConstant;
columnTypes[(int)MetadataColumnIndex.TypeDef_TypeName] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.TypeDef_TypeNamespace] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.TypeDef_Extends] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.TypeDef_FieldList] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.TypeDef_MethodList] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.FieldPtr_Field] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.Field_Flags] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.Field_Name] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.Field_Signature] = ColumnType.Blob;
columnTypes[(int)MetadataColumnIndex.MethodPtr_Method] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.MethodDef_Rva] = ColumnType.FourByteConstant;
columnTypes[(int)MetadataColumnIndex.MethodDef_ImplFlags] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.MethodDef_Flags] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.MethodDef_Name] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.MethodDef_Signature] = ColumnType.Blob;
columnTypes[(int)MetadataColumnIndex.MethodDef_ParamList] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.ParamPtr_Param] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.Param_Flags] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.Param_Sequence] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.Param_Name] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.InterfaceImpl_Class] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.InterfaceImpl_Interface] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.MemberRef_Class] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.MemberRef_Name] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.MemberRef_Signature] = ColumnType.Blob;
columnTypes[(int)MetadataColumnIndex.Constant_Type] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.Constant_Parent] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.Constant_Value] = ColumnType.Blob;
columnTypes[(int)MetadataColumnIndex.CustomAttribute_Parent] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.CustomAttribute_Type] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.CustomAttribute_Value] = ColumnType.Blob;
columnTypes[(int)MetadataColumnIndex.FieldMarshal_Parent] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.FieldMarshal_NativeType] = ColumnType.Blob;
columnTypes[(int)MetadataColumnIndex.DeclSecurity_Action] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.DeclSecurity_Parent] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.DeclSecurity_PermissionSet] = ColumnType.Blob;
columnTypes[(int)MetadataColumnIndex.ClassLayout_PackingSize] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.ClassLayout_ClassSize] = ColumnType.FourByteConstant;
columnTypes[(int)MetadataColumnIndex.ClassLayout_Parent] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.FieldLayout_Offset] = ColumnType.FourByteConstant;
columnTypes[(int)MetadataColumnIndex.FieldLayout_Field] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.StandAloneSig_Signature] = ColumnType.Blob;
columnTypes[(int)MetadataColumnIndex.EventMap_Parent] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.EventMap_EventList] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.EventPtr_Event] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.Event_EventFlags] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.Event_Name] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.Event_EventType] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.PropertyMap_Parent] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.PropertyMap_PropertyList] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.PropertyPtr_Property] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.Property_Flags] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.Property_Name] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.Property_Type] = ColumnType.Blob;
columnTypes[(int)MetadataColumnIndex.MethodSemantics_Semantics] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.MethodSemantics_Method] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.MethodSemantics_Association] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.MethodImpl_Class] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.MethodImpl_MethodBody] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.MethodImpl_MethodDeclaration] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.ModuleRef_Name] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.TypeSpec_Signature] = ColumnType.Blob;
columnTypes[(int)MetadataColumnIndex.ImplMap_MappingFlags] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.ImplMap_MemberForwarded] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.ImplMap_ImportName] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.ImplMap_ImportScope] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.FieldRva_Rva] = ColumnType.FourByteConstant;
columnTypes[(int)MetadataColumnIndex.FieldRva_Field] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.ENCLog_Token] = ColumnType.FourByteConstant;
columnTypes[(int)MetadataColumnIndex.ENCLog_Op] = ColumnType.FourByteConstant;
columnTypes[(int)MetadataColumnIndex.ENCMap_Token] = ColumnType.FourByteConstant;
columnTypes[(int)MetadataColumnIndex.Assembly_HashAlgId] = ColumnType.FourByteConstant;
columnTypes[(int)MetadataColumnIndex.Assembly_MajorVersion] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.Assembly_MinorVersion] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.Assembly_BuildNumber] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.Assembly_RevisionNumber] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.Assembly_Flags] = ColumnType.FourByteConstant;
columnTypes[(int)MetadataColumnIndex.Assembly_PublicKey] = ColumnType.Blob;
columnTypes[(int)MetadataColumnIndex.Assembly_Name] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.Assembly_Culture] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.AssemblyRef_MajorVersion] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.AssemblyRef_MinorVersion] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.AssemblyRef_BuildNumber] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.AssemblyRef_RevisionNumber] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.AssemblyRef_Flags] = ColumnType.FourByteConstant;
columnTypes[(int)MetadataColumnIndex.AssemblyRef_PublicKeyOrToken] = ColumnType.Blob;
columnTypes[(int)MetadataColumnIndex.AssemblyRef_Name] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.AssemblyRef_Culture] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.AssemblyRef_HashValue] = ColumnType.Blob;
columnTypes[(int)MetadataColumnIndex.File_Flags] = ColumnType.FourByteConstant;
columnTypes[(int)MetadataColumnIndex.File_Name] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.File_HashValue] = ColumnType.Blob;
columnTypes[(int)MetadataColumnIndex.ExportedType_Flags] = ColumnType.FourByteConstant;
columnTypes[(int)MetadataColumnIndex.ExportedType_TypeDefId] = ColumnType.FourByteConstant;
columnTypes[(int)MetadataColumnIndex.ExportedType_TypeName] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.ExportedType_TypeNamespace] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.ExportedType_Implementation] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.ManifestResource_Offset] = ColumnType.FourByteConstant;
columnTypes[(int)MetadataColumnIndex.ManifestResource_Flags] = ColumnType.FourByteConstant;
columnTypes[(int)MetadataColumnIndex.ManifestResource_Name] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.ManifestResource_Implementation] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.NestedClass_NestedClass] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.NestedClass_EnclosingClass] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.GenericParam_Number] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.GenericParam_Flags] = ColumnType.TwoByteConstant;
columnTypes[(int)MetadataColumnIndex.GenericParam_Owner] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.GenericParam_Name] = ColumnType.Utf8String;
columnTypes[(int)MetadataColumnIndex.MethodSpec_Method] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.MethodSpec_Instantiation] = ColumnType.Blob;
columnTypes[(int)MetadataColumnIndex.GenericParamConstraint_Owner] = ColumnType.Token;
columnTypes[(int)MetadataColumnIndex.GenericParamConstraint_Constraint] = ColumnType.Token;
return columnTypes;
}
private static MetadataTable[] GetColumnTables()
{
MetadataTable[] metadataTables = new MetadataTable[(int)MetadataColumnIndex.Count];
metadataTables[(int)MetadataColumnIndex.Module_Generation] = MetadataTable.Module;
metadataTables[(int)MetadataColumnIndex.Module_Name] = MetadataTable.Module;
metadataTables[(int)MetadataColumnIndex.Module_Mvid] = MetadataTable.Module;
metadataTables[(int)MetadataColumnIndex.Module_EncId] = MetadataTable.Module;
metadataTables[(int)MetadataColumnIndex.Module_EncBaseId] = MetadataTable.Module;
metadataTables[(int)MetadataColumnIndex.TypeRef_ResolutionScope] = MetadataTable.TypeRef;
metadataTables[(int)MetadataColumnIndex.TypeRef_TypeName] = MetadataTable.TypeRef;
metadataTables[(int)MetadataColumnIndex.TypeRef_TypeNamespace] = MetadataTable.TypeRef;
metadataTables[(int)MetadataColumnIndex.TypeDef_Flags] = MetadataTable.TypeDef;
metadataTables[(int)MetadataColumnIndex.TypeDef_TypeName] = MetadataTable.TypeDef;
metadataTables[(int)MetadataColumnIndex.TypeDef_TypeNamespace] = MetadataTable.TypeDef;
metadataTables[(int)MetadataColumnIndex.TypeDef_Extends] = MetadataTable.TypeDef;
metadataTables[(int)MetadataColumnIndex.TypeDef_FieldList] = MetadataTable.TypeDef;
metadataTables[(int)MetadataColumnIndex.TypeDef_MethodList] = MetadataTable.TypeDef;
metadataTables[(int)MetadataColumnIndex.FieldPtr_Field] = MetadataTable.FieldPtr;
metadataTables[(int)MetadataColumnIndex.Field_Flags] = MetadataTable.Field;
metadataTables[(int)MetadataColumnIndex.Field_Name] = MetadataTable.Field;
metadataTables[(int)MetadataColumnIndex.Field_Signature] = MetadataTable.Field;
metadataTables[(int)MetadataColumnIndex.MethodPtr_Method] = MetadataTable.MethodPtr;
metadataTables[(int)MetadataColumnIndex.MethodDef_Rva] = MetadataTable.MethodDef;
metadataTables[(int)MetadataColumnIndex.MethodDef_ImplFlags] = MetadataTable.MethodDef;
metadataTables[(int)MetadataColumnIndex.MethodDef_Flags] = MetadataTable.MethodDef;
metadataTables[(int)MetadataColumnIndex.MethodDef_Name] = MetadataTable.MethodDef;
metadataTables[(int)MetadataColumnIndex.MethodDef_Signature] = MetadataTable.MethodDef;
metadataTables[(int)MetadataColumnIndex.MethodDef_ParamList] = MetadataTable.MethodDef;
metadataTables[(int)MetadataColumnIndex.ParamPtr_Param] = MetadataTable.ParamPtr;
metadataTables[(int)MetadataColumnIndex.Param_Flags] = MetadataTable.Param;
metadataTables[(int)MetadataColumnIndex.Param_Sequence] = MetadataTable.Param;
metadataTables[(int)MetadataColumnIndex.Param_Name] = MetadataTable.Param;
metadataTables[(int)MetadataColumnIndex.InterfaceImpl_Class] = MetadataTable.InterfaceImpl;
metadataTables[(int)MetadataColumnIndex.InterfaceImpl_Interface] = MetadataTable.InterfaceImpl;
metadataTables[(int)MetadataColumnIndex.MemberRef_Class] = MetadataTable.MemberRef;
metadataTables[(int)MetadataColumnIndex.MemberRef_Name] = MetadataTable.MemberRef;
metadataTables[(int)MetadataColumnIndex.MemberRef_Signature] = MetadataTable.MemberRef;
metadataTables[(int)MetadataColumnIndex.Constant_Type] = MetadataTable.Constant;
metadataTables[(int)MetadataColumnIndex.Constant_Parent] = MetadataTable.Constant;
metadataTables[(int)MetadataColumnIndex.Constant_Value] = MetadataTable.Constant;
metadataTables[(int)MetadataColumnIndex.CustomAttribute_Parent] = MetadataTable.CustomAttribute;
metadataTables[(int)MetadataColumnIndex.CustomAttribute_Type] = MetadataTable.CustomAttribute;
metadataTables[(int)MetadataColumnIndex.CustomAttribute_Value] = MetadataTable.CustomAttribute;
metadataTables[(int)MetadataColumnIndex.FieldMarshal_Parent] = MetadataTable.FieldMarshal;
metadataTables[(int)MetadataColumnIndex.FieldMarshal_NativeType] = MetadataTable.FieldMarshal;
metadataTables[(int)MetadataColumnIndex.DeclSecurity_Action] = MetadataTable.DeclSecurity;
metadataTables[(int)MetadataColumnIndex.DeclSecurity_Parent] = MetadataTable.DeclSecurity;
metadataTables[(int)MetadataColumnIndex.DeclSecurity_PermissionSet] = MetadataTable.DeclSecurity;
metadataTables[(int)MetadataColumnIndex.ClassLayout_PackingSize] = MetadataTable.ClassLayout;
metadataTables[(int)MetadataColumnIndex.ClassLayout_ClassSize] = MetadataTable.ClassLayout;
metadataTables[(int)MetadataColumnIndex.ClassLayout_Parent] = MetadataTable.ClassLayout;
metadataTables[(int)MetadataColumnIndex.FieldLayout_Offset] = MetadataTable.FieldLayout;
metadataTables[(int)MetadataColumnIndex.FieldLayout_Field] = MetadataTable.FieldLayout;
metadataTables[(int)MetadataColumnIndex.StandAloneSig_Signature] = MetadataTable.StandAloneSig;
metadataTables[(int)MetadataColumnIndex.EventMap_Parent] = MetadataTable.EventMap;
metadataTables[(int)MetadataColumnIndex.EventMap_EventList] = MetadataTable.EventMap;
metadataTables[(int)MetadataColumnIndex.EventPtr_Event] = MetadataTable.EventPtr;
metadataTables[(int)MetadataColumnIndex.Event_EventFlags] = MetadataTable.Event;
metadataTables[(int)MetadataColumnIndex.Event_Name] = MetadataTable.Event;
metadataTables[(int)MetadataColumnIndex.Event_EventType] = MetadataTable.Event;
metadataTables[(int)MetadataColumnIndex.PropertyMap_Parent] = MetadataTable.PropertyMap;
metadataTables[(int)MetadataColumnIndex.PropertyMap_PropertyList] = MetadataTable.PropertyMap;
metadataTables[(int)MetadataColumnIndex.PropertyPtr_Property] = MetadataTable.PropertyPtr;
metadataTables[(int)MetadataColumnIndex.Property_Flags] = MetadataTable.Property;
metadataTables[(int)MetadataColumnIndex.Property_Name] = MetadataTable.Property;
metadataTables[(int)MetadataColumnIndex.Property_Type] = MetadataTable.Property;
metadataTables[(int)MetadataColumnIndex.MethodSemantics_Semantics] = MetadataTable.MethodSemantics;
metadataTables[(int)MetadataColumnIndex.MethodSemantics_Method] = MetadataTable.MethodSemantics;
metadataTables[(int)MetadataColumnIndex.MethodSemantics_Association] = MetadataTable.MethodSemantics;
metadataTables[(int)MetadataColumnIndex.MethodImpl_Class] = MetadataTable.MethodImpl;
metadataTables[(int)MetadataColumnIndex.MethodImpl_MethodBody] = MetadataTable.MethodImpl;
metadataTables[(int)MetadataColumnIndex.MethodImpl_MethodDeclaration] = MetadataTable.MethodImpl;
metadataTables[(int)MetadataColumnIndex.ModuleRef_Name] = MetadataTable.ModuleRef;
metadataTables[(int)MetadataColumnIndex.TypeSpec_Signature] = MetadataTable.TypeSpec;
metadataTables[(int)MetadataColumnIndex.ImplMap_MappingFlags] = MetadataTable.ImplMap;
metadataTables[(int)MetadataColumnIndex.ImplMap_MemberForwarded] = MetadataTable.ImplMap;
metadataTables[(int)MetadataColumnIndex.ImplMap_ImportName] = MetadataTable.ImplMap;
metadataTables[(int)MetadataColumnIndex.ImplMap_ImportScope] = MetadataTable.ImplMap;
metadataTables[(int)MetadataColumnIndex.FieldRva_Rva] = MetadataTable.FieldRva;
metadataTables[(int)MetadataColumnIndex.FieldRva_Field] = MetadataTable.FieldRva;
metadataTables[(int)MetadataColumnIndex.ENCLog_Token] = MetadataTable.ENCLog;
metadataTables[(int)MetadataColumnIndex.ENCLog_Op] = MetadataTable.ENCLog;
metadataTables[(int)MetadataColumnIndex.ENCMap_Token] = MetadataTable.ENCMap;
metadataTables[(int)MetadataColumnIndex.Assembly_HashAlgId] = MetadataTable.Assembly;
metadataTables[(int)MetadataColumnIndex.Assembly_MajorVersion] = MetadataTable.Assembly;
metadataTables[(int)MetadataColumnIndex.Assembly_MinorVersion] = MetadataTable.Assembly;
metadataTables[(int)MetadataColumnIndex.Assembly_BuildNumber] = MetadataTable.Assembly;
metadataTables[(int)MetadataColumnIndex.Assembly_RevisionNumber] = MetadataTable.Assembly;
metadataTables[(int)MetadataColumnIndex.Assembly_Flags] = MetadataTable.Assembly;
metadataTables[(int)MetadataColumnIndex.Assembly_PublicKey] = MetadataTable.Assembly;
metadataTables[(int)MetadataColumnIndex.Assembly_Name] = MetadataTable.Assembly;
metadataTables[(int)MetadataColumnIndex.Assembly_Culture] = MetadataTable.Assembly;
metadataTables[(int)MetadataColumnIndex.AssemblyRef_MajorVersion] = MetadataTable.AssemblyRef;
metadataTables[(int)MetadataColumnIndex.AssemblyRef_MinorVersion] = MetadataTable.AssemblyRef;
metadataTables[(int)MetadataColumnIndex.AssemblyRef_BuildNumber] = MetadataTable.AssemblyRef;
metadataTables[(int)MetadataColumnIndex.AssemblyRef_RevisionNumber] = MetadataTable.AssemblyRef;
metadataTables[(int)MetadataColumnIndex.AssemblyRef_Flags] = MetadataTable.AssemblyRef;
metadataTables[(int)MetadataColumnIndex.AssemblyRef_PublicKeyOrToken] = MetadataTable.AssemblyRef;
metadataTables[(int)MetadataColumnIndex.AssemblyRef_Name] = MetadataTable.AssemblyRef;
metadataTables[(int)MetadataColumnIndex.AssemblyRef_Culture] = MetadataTable.AssemblyRef;
metadataTables[(int)MetadataColumnIndex.AssemblyRef_HashValue] = MetadataTable.AssemblyRef;
metadataTables[(int)MetadataColumnIndex.File_Flags] = MetadataTable.File;
metadataTables[(int)MetadataColumnIndex.File_Name] = MetadataTable.File;
metadataTables[(int)MetadataColumnIndex.File_HashValue] = MetadataTable.File;
metadataTables[(int)MetadataColumnIndex.ExportedType_Flags] = MetadataTable.ExportedType;
metadataTables[(int)MetadataColumnIndex.ExportedType_TypeDefId] = MetadataTable.ExportedType;
metadataTables[(int)MetadataColumnIndex.ExportedType_TypeName] = MetadataTable.ExportedType;
metadataTables[(int)MetadataColumnIndex.ExportedType_TypeNamespace] = MetadataTable.ExportedType;
metadataTables[(int)MetadataColumnIndex.ExportedType_Implementation] = MetadataTable.ExportedType;
metadataTables[(int)MetadataColumnIndex.ManifestResource_Offset] = MetadataTable.ManifestResource;
metadataTables[(int)MetadataColumnIndex.ManifestResource_Flags] = MetadataTable.ManifestResource;
metadataTables[(int)MetadataColumnIndex.ManifestResource_Name] = MetadataTable.ManifestResource;
metadataTables[(int)MetadataColumnIndex.ManifestResource_Implementation] = MetadataTable.ManifestResource;
metadataTables[(int)MetadataColumnIndex.NestedClass_NestedClass] = MetadataTable.NestedClass;
metadataTables[(int)MetadataColumnIndex.NestedClass_EnclosingClass] = MetadataTable.NestedClass;
metadataTables[(int)MetadataColumnIndex.GenericParam_Number] = MetadataTable.GenericParam;
metadataTables[(int)MetadataColumnIndex.GenericParam_Flags] = MetadataTable.GenericParam;
metadataTables[(int)MetadataColumnIndex.GenericParam_Owner] = MetadataTable.GenericParam;
metadataTables[(int)MetadataColumnIndex.GenericParam_Name] = MetadataTable.GenericParam;
metadataTables[(int)MetadataColumnIndex.MethodSpec_Method] = MetadataTable.MethodSpec;
metadataTables[(int)MetadataColumnIndex.MethodSpec_Instantiation] = MetadataTable.MethodSpec;
metadataTables[(int)MetadataColumnIndex.GenericParamConstraint_Owner] = MetadataTable.GenericParamConstraint;
metadataTables[(int)MetadataColumnIndex.GenericParamConstraint_Constraint] = MetadataTable.GenericParamConstraint;
return metadataTables;
}
private static Func<uint, uint>[][] GetColumnTokenDecoders()
{
Func<uint, uint>[][] decoders = new Func<uint, uint>[32][];
for (int i = 0; i < 32; i++)
{
List<MetadataTable> ptrTablesPresent = new();
PtrTablesPresent tablesPresent = (PtrTablesPresent)i;
if (tablesPresent.HasFlag(PtrTablesPresent.Field))
{
ptrTablesPresent.Add(MetadataTable.FieldPtr);
}
if (tablesPresent.HasFlag(PtrTablesPresent.Param))
{
ptrTablesPresent.Add(MetadataTable.ParamPtr);
}
if (tablesPresent.HasFlag(PtrTablesPresent.Param))
{
ptrTablesPresent.Add(MetadataTable.ParamPtr);
}
if (tablesPresent.HasFlag(PtrTablesPresent.Property))
{
ptrTablesPresent.Add(MetadataTable.PropertyPtr);
}
if (tablesPresent.HasFlag(PtrTablesPresent.Event))
{
ptrTablesPresent.Add(MetadataTable.EventPtr);
}
decoders[i] = GetColumnTokenDecode(ptrTablesPresent);
}
return decoders;
}
private static class ColumnDecodeData
{
private static readonly MetadataTable[] TypeDefOrRef = { MetadataTable.TypeDef, MetadataTable.TypeRef, MetadataTable.TypeSpec };
private static readonly MetadataTable[] HasConstant = { MetadataTable.Field, MetadataTable.Param, MetadataTable.Property };
private static readonly MetadataTable[] HasCustomAttribute =
{
MetadataTable.MethodDef,
MetadataTable.Field,
MetadataTable.TypeRef,
MetadataTable.TypeDef,
MetadataTable.Param,
MetadataTable.InterfaceImpl,
MetadataTable.MemberRef,
MetadataTable.Module,
MetadataTable.DeclSecurity,
MetadataTable.Property,
MetadataTable.Event,
MetadataTable.StandAloneSig,
MetadataTable.ModuleRef,
MetadataTable.TypeSpec,
MetadataTable.Assembly,
MetadataTable.AssemblyRef,
MetadataTable.File,
MetadataTable.ExportedType,
MetadataTable.ManifestResource,
MetadataTable.GenericParam,
MetadataTable.GenericParamConstraint,
MetadataTable.MethodSpec };
private static readonly MetadataTable[] HasFieldMarshal = { MetadataTable.Field, MetadataTable.Param };
private static readonly MetadataTable[] HasDeclSecurity = { MetadataTable.TypeDef, MetadataTable.MethodDef, MetadataTable.Assembly };
private static readonly MetadataTable[] MemberRefParent = { MetadataTable.TypeDef, MetadataTable.TypeRef, MetadataTable.ModuleRef, MetadataTable.MethodDef, MetadataTable.TypeSpec };
private static readonly MetadataTable[] HasSemantics = { MetadataTable.Event, MetadataTable.Property };
private static readonly MetadataTable[] MethodDefOrRef = { MetadataTable.MethodDef, MetadataTable.MemberRef };
private static readonly MetadataTable[] MemberForwarded = { MetadataTable.Field, MetadataTable.MethodDef };
private static readonly MetadataTable[] Implementation = { MetadataTable.File, MetadataTable.AssemblyRef, MetadataTable.ExportedType };
private static readonly MetadataTable[] CustomAttributeType = { MetadataTable.Unused, MetadataTable.Unused, MetadataTable.MethodDef, MetadataTable.MemberRef, MetadataTable.Unused };
private static readonly MetadataTable[] ResolutionScope = { MetadataTable.Module, MetadataTable.ModuleRef, MetadataTable.AssemblyRef, MetadataTable.TypeRef };
private static readonly MetadataTable[] TypeOrMethodDef = { MetadataTable.TypeDef, MetadataTable.MethodDef };
private static readonly MetadataTable[] FieldOrFieldPtr = { (MetadataTable)(-2), MetadataTable.Field, MetadataTable.FieldPtr };
private static readonly MetadataTable[] MethodDefOrMethodPtr = { (MetadataTable)(-2), MetadataTable.MethodDef, MetadataTable.MethodPtr };
private static readonly MetadataTable[] ParamOrParamPtr = { (MetadataTable)(-2), MetadataTable.Param, MetadataTable.ParamPtr };
private static readonly MetadataTable[] EventOrEventPtr = { (MetadataTable)(-2), MetadataTable.Event, MetadataTable.EventPtr };
private static readonly MetadataTable[] PropertyOrPropertyPtr = { (MetadataTable)(-2), MetadataTable.Property, MetadataTable.PropertyPtr };
public static MetadataTable[][] GetCodedIndexDecoderRing()
{
MetadataTable[][] decoderRing = new MetadataTable[(int)MetadataColumnIndex.Count][];
decoderRing[(int)MetadataColumnIndex.TypeRef_ResolutionScope] = ResolutionScope;
decoderRing[(int)MetadataColumnIndex.TypeDef_Extends] = TypeDefOrRef;
decoderRing[(int)MetadataColumnIndex.TypeDef_FieldList] = FieldOrFieldPtr;
decoderRing[(int)MetadataColumnIndex.TypeDef_MethodList] = MethodDefOrMethodPtr;
decoderRing[(int)MetadataColumnIndex.FieldPtr_Field] = new[] { MetadataTable.Field };
decoderRing[(int)MetadataColumnIndex.MethodPtr_Method] = new[] { MetadataTable.MethodDef };
decoderRing[(int)MetadataColumnIndex.MethodDef_ParamList] = ParamOrParamPtr;
decoderRing[(int)MetadataColumnIndex.ParamPtr_Param] = new[] { MetadataTable.Param };
decoderRing[(int)MetadataColumnIndex.InterfaceImpl_Class] = new[] { MetadataTable.TypeDef };
decoderRing[(int)MetadataColumnIndex.InterfaceImpl_Interface] = TypeDefOrRef;
decoderRing[(int)MetadataColumnIndex.MemberRef_Class] = MemberRefParent;
decoderRing[(int)MetadataColumnIndex.Constant_Parent] = HasConstant;
decoderRing[(int)MetadataColumnIndex.CustomAttribute_Parent] = HasCustomAttribute;
decoderRing[(int)MetadataColumnIndex.CustomAttribute_Type] = CustomAttributeType;
decoderRing[(int)MetadataColumnIndex.FieldMarshal_Parent] = HasFieldMarshal;
decoderRing[(int)MetadataColumnIndex.DeclSecurity_Parent] = HasDeclSecurity;
decoderRing[(int)MetadataColumnIndex.ClassLayout_Parent] = new[] { MetadataTable.TypeDef };
decoderRing[(int)MetadataColumnIndex.FieldLayout_Field] = new[] { MetadataTable.Field };
decoderRing[(int)MetadataColumnIndex.EventMap_Parent] = new[] { MetadataTable.TypeDef };
decoderRing[(int)MetadataColumnIndex.EventMap_EventList] = EventOrEventPtr;
decoderRing[(int)MetadataColumnIndex.EventPtr_Event] = new[] { MetadataTable.Event };
decoderRing[(int)MetadataColumnIndex.Event_EventType] = TypeDefOrRef;
decoderRing[(int)MetadataColumnIndex.PropertyMap_Parent] = new[] { MetadataTable.TypeDef };
decoderRing[(int)MetadataColumnIndex.PropertyMap_PropertyList] = PropertyOrPropertyPtr;
decoderRing[(int)MetadataColumnIndex.PropertyPtr_Property] = new[] { MetadataTable.Property };
decoderRing[(int)MetadataColumnIndex.MethodSemantics_Method] = new[] { MetadataTable.MethodDef };
decoderRing[(int)MetadataColumnIndex.MethodSemantics_Association] = HasSemantics;
decoderRing[(int)MetadataColumnIndex.MethodImpl_Class] = new[] { MetadataTable.TypeDef };
decoderRing[(int)MetadataColumnIndex.MethodImpl_MethodBody] = MethodDefOrRef;
decoderRing[(int)MetadataColumnIndex.MethodImpl_MethodDeclaration] = MethodDefOrRef;
decoderRing[(int)MetadataColumnIndex.ImplMap_MemberForwarded] = MemberForwarded;
decoderRing[(int)MetadataColumnIndex.ImplMap_ImportScope] = new[] { MetadataTable.ModuleRef };
decoderRing[(int)MetadataColumnIndex.FieldRva_Field] = new[] { MetadataTable.ModuleRef };
decoderRing[(int)MetadataColumnIndex.ExportedType_Implementation] = Implementation;
decoderRing[(int)MetadataColumnIndex.ManifestResource_Implementation] = Implementation;
decoderRing[(int)MetadataColumnIndex.NestedClass_NestedClass] = new[] { MetadataTable.TypeDef };
decoderRing[(int)MetadataColumnIndex.NestedClass_EnclosingClass] = new[] { MetadataTable.TypeDef };
decoderRing[(int)MetadataColumnIndex.GenericParam_Owner] = TypeOrMethodDef;
decoderRing[(int)MetadataColumnIndex.MethodSpec_Method] = MethodDefOrRef;
decoderRing[(int)MetadataColumnIndex.GenericParamConstraint_Owner] = new[] { MetadataTable.GenericParam };
decoderRing[(int)MetadataColumnIndex.GenericParamConstraint_Constraint] = TypeDefOrRef;
return decoderRing;
}
}
private static uint DecodeCodedIndex(uint input, ReadOnlySpan<MetadataTable> tablesEncoded)
{
uint encodingMask = BitOperations.RoundUpToPowerOf2((uint)tablesEncoded.Length) - 1;
int bitsForTableEncoding = 32 - BitOperations.LeadingZeroCount(BitOperations.RoundUpToPowerOf2((uint)tablesEncoded.Length) - 1);
MetadataTable table = tablesEncoded[(int)(input & encodingMask)];
uint rid = input >> bitsForTableEncoding;
return CreateToken(table, rid);
}
private static Func<uint, uint>[] GetColumnTokenDecode(List<MetadataTable> ptrTablesPresent)
{
Func<uint, uint>[] columnTokenDecode = new Func<uint, uint>[(int)MetadataColumnIndex.Count];
MetadataTable[][] decoderRing = ColumnDecodeData.GetCodedIndexDecoderRing();
for (int i = 0; i < decoderRing.Length; i++)
{
if (decoderRing[i] != null)
{
columnTokenDecode[i] = ComputeDecoder(decoderRing[i]);
}
}
return columnTokenDecode;
Func<uint, uint> ComputeDecoder(MetadataTable[] decoderData)
{
Func<uint, uint> result;
if (decoderData.Length == 1)
{
MetadataTable metadataTable = decoderData[0];
result = delegate (uint input) { return CreateToken(metadataTable, input); };
}
else
{
if ((decoderData.Length == 1) && decoderData[0] == (MetadataTable)(-2))
{
MetadataTable metadataTable = decoderData[0];
if (!ptrTablesPresent.Contains(decoderData[2]))
{
metadataTable = decoderData[1];
}
else
{
metadataTable = decoderData[2];
}
result = delegate (uint input) { return CreateToken(metadataTable, input); };
}
else
{
result = delegate (uint input) { return DecodeCodedIndex(input, decoderData); };
}
}
return result;
}
}
}

View file

@ -1,59 +0,0 @@
// 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.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Diagnostics.DataContractReader.Contracts;
namespace Microsoft.Diagnostics.DataContractReader.Helpers;
internal partial class EcmaMetadataReader
{
public static MetadataTable TokenToTable(uint token)
{
byte tableIndex = (byte)(token >> 24);
if (tableIndex > (uint)MetadataTable.GenericParamConstraint)
{
return MetadataTable.Unused;
}
else
{
return (MetadataTable)tableIndex;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsSigned<T>() where T : struct, INumberBase<T>, IMinMaxValue<T>
{
return T.IsNegative(T.MinValue);
}
private static bool TryReadCore<T>(ReadOnlySpan<byte> bytes, out T value) where T : struct, IBinaryInteger<T>, IMinMaxValue<T>
{
return T.TryReadLittleEndian(bytes.Slice(0, Unsafe.SizeOf<T>()), IsSigned<T>(), out value);
}
private static T ReadLittleEndian<T>(ReadOnlySpan<byte> bytes) where T : struct, IBinaryInteger<T>, IMinMaxValue<T>
{
if (!TryReadCore<T>(bytes, out T value))
throw new ArgumentOutOfRangeException(nameof(value));
return value;
}
public static uint RidFromToken(uint token)
{
return token & 0xFFFFFF;
}
public static uint CreateToken(MetadataTable table, uint rid)
{
ArgumentOutOfRangeException.ThrowIfGreaterThan<uint>(rid, 0xFFFFFF, nameof(rid));
ArgumentOutOfRangeException.ThrowIfGreaterThan<int>((int)table, (int)MetadataTable.GenericParamConstraint, nameof(table));
return ((uint)table << 24) | rid;
}
}

View file

@ -1,434 +0,0 @@
// 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.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Reflection;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Diagnostics.DataContractReader.Contracts;
namespace Microsoft.Diagnostics.DataContractReader.Helpers;
internal struct EcmaMetadataCursor
{
internal ReadOnlyMemory<byte> TableData;
internal MetadataTable Table;
internal uint Rid;
internal int RowSize;
public ReadOnlySpan<byte> Row
{
get
{
return TableData.Span.Slice((int)(RowSize * (Rid - 1)), (int)RowSize);
}
}
}
internal partial class EcmaMetadataReader
{
private EcmaMetadata _ecmaMetadata;
private int[] rowSize;
private int[] columnSize;
private int[] columnOffset;
private Func<uint, uint>[] columnTokenDecode;
public EcmaMetadataReader(ReadOnlyMemory<byte> imageMemory)
{
columnSize = new int[(int)MetadataColumnIndex.Count];
columnOffset = new int[(int)MetadataColumnIndex.Count];
rowSize = new int[(int)MetadataTable.Count];
columnTokenDecode = Array.Empty<Func<uint, uint>>();
ReadOnlySpan<byte> image = imageMemory.Span;
int magic = ReadLittleEndian<int>(image);
if (magic != 0x424A5342)
throw new ArgumentOutOfRangeException(nameof(imageMemory));
int versionSize = ReadLittleEndian<int>(image.Slice(12, 4));
versionSize = AlignUp(versionSize, 4);
ReadOnlySpan<byte> versionName = image.Slice(16, versionSize);
int nullTerminatorIndex = versionName.IndexOf((byte)0);
if ((nullTerminatorIndex == -1) || (nullTerminatorIndex == 0))
{
// VersionName isn't null terminated
throw new ArgumentException(nameof(imageMemory));
}
string metadataVersion = Encoding.UTF8.GetString(versionName.Slice(0, nullTerminatorIndex));
int currentOffset = 16 + versionSize;
currentOffset += 2; // Flags ... unused in this implementation
ushort streams = ReadLittleEndian<ushort>(image.Slice(currentOffset));
currentOffset += 2;
ReadOnlyMemory<byte> StringHeap = null;
ReadOnlyMemory<byte> UserStringHeap = null;
ReadOnlyMemory<byte> BlobHeap = null;
ReadOnlyMemory<byte> GuidHeap = null;
ReadOnlyMemory<byte> TablesHeap = null;
for (ushort iStream = 0; iStream < streams; iStream++)
{
var stream = ReadStream(ref image);
if (stream.Name == "#Strings")
{
StringHeap = stream.Data;
}
else if (stream.Name == "#US")
{
UserStringHeap = stream.Data;
}
else if (stream.Name == "#Blob")
{
BlobHeap = stream.Data;
}
else if (stream.Name == "#GUID")
{
GuidHeap = stream.Data;
}
else if (stream.Name == "#~")
{
TablesHeap = stream.Data;
}
else if (stream.Name == "#-")
{
TablesHeap = stream.Data;
}
}
if (TablesHeap.Length == 0)
{
throw new ArgumentException(nameof(imageMemory));
}
ReadOnlySpan<byte> tables = TablesHeap.Span;
byte heapSizes = ReadLittleEndian<byte>(tables.Slice(6, 1));
ulong validTables = ReadLittleEndian<ulong>(tables.Slice(8, 8));
ulong sortedTables = ReadLittleEndian<ulong>(tables.Slice(16, 8));
int[] tableRowCounts = new int[(int)MetadataTable.Count];
bool[] isSorted = new bool[(int)MetadataTable.Count];
int currentTablesOffset = 24;
for (int i = 0; i < (int)MetadataTable.Count; i++)
{
if ((validTables & ((ulong)1 << i)) != 0)
{
tableRowCounts[i] = ReadLittleEndian<int>(tables.Slice(currentTablesOffset));
currentTablesOffset += 4;
}
if ((sortedTables & ((ulong)1 << i)) != 0)
{
isSorted[i] = true;
}
}
// There is an undocumented flag "extra_data" which adds a 4 byte pad here.
if ((heapSizes & 0x40) != 0)
{
currentTablesOffset += 4;
}
EcmaMetadataSchema schema = new EcmaMetadataSchema(metadataVersion,
largeStringHeap: (heapSizes & 1) != 0,
largeGuidHeap: (heapSizes & 2) != 0,
largeBlobHeap: (heapSizes & 4) != 0,
rowCount: tableRowCounts,
isSorted: isSorted,
variableSizedColumnsAre4BytesLong: false
);
ReadOnlyMemory<byte>[] tableData = new ReadOnlyMemory<byte>[(int)MetadataTable.Count];
_ecmaMetadata = new EcmaMetadata(schema, tableData, StringHeap, UserStringHeap, BlobHeap, GuidHeap);
Init();
// Init will compute row sizes, which is necessary for actually computing the tableData
for (int i = 0; i < (int)MetadataTable.Count; i++)
{
checked
{
if ((validTables & ((ulong)1 << i)) != 0)
{
int tableSize = checked(rowSize![i] * _ecmaMetadata.Schema.RowCount[i]);
tableData[i] = TablesHeap.Slice(currentTablesOffset, tableSize);
currentTablesOffset += tableSize;
}
}
}
(string Name, ReadOnlyMemory<byte> Data) ReadStream(ref ReadOnlySpan<byte> image)
{
int offset = ReadLittleEndian<int>(image.Slice(currentOffset));
currentOffset += 4;
int size = ReadLittleEndian<int>(image.Slice(currentOffset));
currentOffset += 4;
int nameStartOffset = currentOffset;
int nameLen = 0;
while (image[currentOffset++] != 0)
{
nameLen++;
if (nameLen > 31) throw new ArgumentException(nameof(imageMemory));
}
if (nameLen == 0) throw new ArgumentException(nameof(imageMemory));
currentOffset = AlignUp(currentOffset, 4);
return (Encoding.ASCII.GetString(image.Slice(nameStartOffset, nameLen)), imageMemory.Slice(offset, size));
}
}
private static int AlignUp(int input, int alignment)
{
return input + (alignment - 1) & ~(alignment - 1);
}
public EcmaMetadataReader(EcmaMetadata ecmaMetadata)
{
columnTokenDecode = Array.Empty<Func<uint, uint>>();
columnSize = new int[(int)MetadataColumnIndex.Count];
columnOffset = new int[(int)MetadataColumnIndex.Count];
rowSize = new int[(int)MetadataTable.Count];
_ecmaMetadata = ecmaMetadata;
Init();
}
private void Init()
{
PtrTablesPresent ptrTable = PtrTablesPresent.None;
if (RowCount(MetadataTable.MethodPtr) != 0)
ptrTable |= PtrTablesPresent.Method;
if (RowCount(MetadataTable.FieldPtr) != 0)
ptrTable |= PtrTablesPresent.Field;
if (RowCount(MetadataTable.ParamPtr) != 0)
ptrTable |= PtrTablesPresent.Param;
if (RowCount(MetadataTable.EventPtr) != 0)
ptrTable |= PtrTablesPresent.Event;
if (RowCount(MetadataTable.PropertyPtr) != 0)
ptrTable |= PtrTablesPresent.Property;
columnTokenDecode = columnTokenDecoders[(int)ptrTable];
ComputeColumnSizesAndOffsets();
void ComputeColumnSizesAndOffsets()
{
MetadataTable currentTable = MetadataTable.Unused;
MetadataColumnIndex? prevColumn = null;
for (int i = 0; i < (int)MetadataColumnIndex.Count; i++)
{
MetadataColumnIndex column = (MetadataColumnIndex)i;
MetadataTable newColumnTable = ColumnTable(column);
if (currentTable != newColumnTable)
{
if (prevColumn.HasValue)
rowSize[(int)currentTable] = ComputeColumnEnd(prevColumn.Value);
currentTable = newColumnTable;
columnOffset[i] = 0;
}
else
{
columnOffset[i] = ComputeColumnEnd(prevColumn!.Value);
}
prevColumn = column;
columnSize[i] = columnTypes[i] switch
{
ColumnType.TwoByteConstant => 2,
ColumnType.FourByteConstant => 4,
ColumnType.Utf8String => _ecmaMetadata.Schema.LargeStringHeap ? 4 : 2,
ColumnType.Blob => _ecmaMetadata.Schema.LargeBlobHeap ? 4 : 2,
ColumnType.Guid => _ecmaMetadata.Schema.LargeGuidHeap ? 4 : 2,
ColumnType.Token => _ecmaMetadata.Schema.VariableSizedColumnsAreAll4BytesLong ? 4 : CodedIndexEncodingBytes(codedIndexDecoderRing[i]),
_ => throw new System.Exception()
};
}
rowSize[(int)ColumnTable(prevColumn!.Value)] = ComputeColumnEnd(prevColumn!.Value);
}
int ComputeColumnEnd(MetadataColumnIndex column)
{
return ColumnOffset(column) + ColumnSize(column);
}
}
public EcmaMetadata UnderlyingMetadata => _ecmaMetadata;
public uint GetColumnAsConstant(EcmaMetadataCursor c, MetadataColumnIndex col_idx)
{
if (columnTypes[(int)col_idx] != ColumnType.TwoByteConstant && columnTypes[(int)col_idx] != ColumnType.FourByteConstant)
throw new ArgumentOutOfRangeException(nameof(col_idx));
return GetColumnRaw(c, col_idx);
}
public System.ReadOnlySpan<byte> GetColumnAsBlob(EcmaMetadataCursor c, MetadataColumnIndex col_idx)
{
if (columnTypes[(int)col_idx] != ColumnType.Blob)
throw new NotImplementedException();
uint rawResult = GetColumnRaw(c, col_idx);
if (rawResult == 0)
return default;
checked
{
ReadOnlySpan<byte> blobHeap = _ecmaMetadata.BlobHeap.Span;
int curOffset = (int)rawResult;
byte headerByte1 = blobHeap[curOffset];
int size;
if ((headerByte1 & 0x80) == 0)
{
size = headerByte1;
}
else if ((headerByte1 & 0xC) == 0x80)
{
byte headerByte2 = blobHeap[++curOffset];
size = headerByte1 & 0x3F << 8 + headerByte2;
}
else
{
byte headerByte2 = blobHeap[++curOffset];
byte headerByte3 = blobHeap[++curOffset];
byte headerByte4 = blobHeap[++curOffset];
size = (headerByte1 & 0x3F << 24) +
(headerByte2 << 16) +
(headerByte3 << 8) +
headerByte4;
}
curOffset++;
return blobHeap.Slice(curOffset, size);
}
}
public uint GetColumnAsToken(EcmaMetadataCursor c, MetadataColumnIndex col_idx)
{
Func<uint, uint> decoder = columnTokenDecode[(int)col_idx];
if (decoder == null)
{
throw new ArgumentOutOfRangeException(nameof(col_idx));
}
uint rawResult = GetColumnRaw(c, col_idx);
uint result = decoder(rawResult);
return result;
}
public System.ReadOnlySpan<byte> GetColumnAsUtf8(EcmaMetadataCursor c, MetadataColumnIndex col_idx)
{
if (columnTypes[(int)col_idx] != ColumnType.Utf8String)
throw new ArgumentOutOfRangeException(nameof(col_idx));
int initialOffset = (int)GetColumnRaw(c, col_idx);
if (initialOffset == 0)
return default(ReadOnlySpan<byte>);
checked
{
ReadOnlySpan<byte> stringHeap = _ecmaMetadata.StringHeap.Span;
int curOffset = initialOffset;
while (stringHeap[curOffset] != '\0')
{
curOffset++;
}
return stringHeap.Slice(initialOffset, curOffset - initialOffset);
}
}
public bool TryGetCursor(uint token, out EcmaMetadataCursor cursor)
{
cursor = default;
MetadataTable table = TokenToTable(token);
if (table == MetadataTable.Unused)
return false;
if (RowCount(table) < RidFromToken(token))
return false;
cursor.Rid = RidFromToken(token);
cursor.TableData = _ecmaMetadata.Tables[(int)table];
cursor.RowSize = rowSize[(int)table];
cursor.Table = table;
return true;
}
public bool TryGetCursorToFirstEntryInTable(MetadataTable table, out EcmaMetadataCursor cursor)
{
cursor = default;
if (RowCount(table) > 0)
{
cursor.Rid = 1;
cursor.TableData = _ecmaMetadata.Tables[(int)table];
cursor.RowSize = rowSize[(int)table];
cursor.Table = table;
return true;
}
return false;
}
public bool TryFindRowFromCursor(EcmaMetadataCursor tableCursor, MetadataColumnIndex col_idx, uint searchToken, out EcmaMetadataCursor foundRow)
{
foundRow = tableCursor;
/* if (_ecmaMetadata.Schema.IsSorted[(int)tableCursor.Table])
{
// TODO(cdac) implement sorted searching in metadata
}
else*/
{
while (foundRow.Rid <= RowCount(tableCursor.Table))
{
if (GetColumnAsToken(foundRow, col_idx) == searchToken)
{
return true;
}
foundRow.Rid += 1;
}
}
return false;
}
public EcmaMetadataCursor GetCursor(uint token)
{
if (!TryGetCursor(token, out EcmaMetadataCursor cursor))
{
throw new ArgumentOutOfRangeException(nameof(token));
}
return cursor;
}
public static uint GetToken(EcmaMetadataCursor c)
{
return CreateToken(c.Table, c.Rid);
}
private static MetadataTable ColumnTable(MetadataColumnIndex column)
{
return columnTable[(int)column];
}
public virtual string GetColumnAsUtf8String(EcmaMetadataCursor c, MetadataColumnIndex col_idx)
{
ReadOnlySpan<byte> utf8Data = GetColumnAsUtf8(c, col_idx);
string str = string.Empty;
if (utf8Data.Length > 0)
{
str = System.Text.Encoding.UTF8.GetString(utf8Data);
}
return str;
}
}

View file

@ -1,334 +0,0 @@
// 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 Microsoft.Diagnostics.DataContractReader.Contracts;
namespace Microsoft.Diagnostics.DataContractReader.Helpers;
internal enum MetadataTable
{
Unused = -1,
Module = 0x0,
TypeRef = 0x01,
TypeDef = 0x02,
FieldPtr = 0x03,
Field = 0x04,
MethodPtr = 0x05,
MethodDef = 0x06,
ParamPtr = 0x07,
Param = 0x08,
InterfaceImpl = 0x09,
MemberRef = 0x0a,
Constant = 0x0b,
CustomAttribute = 0x0c,
FieldMarshal = 0x0d,
DeclSecurity = 0x0e,
ClassLayout = 0x0f,
FieldLayout = 0x10,
StandAloneSig = 0x11,
EventMap = 0x12,
EventPtr = 0x13,
Event = 0x14,
PropertyMap = 0x15,
PropertyPtr = 0x16,
Property = 0x17,
MethodSemantics = 0x18,
MethodImpl = 0x19,
ModuleRef = 0x1a,
TypeSpec = 0x1b,
ImplMap = 0x1c,
FieldRva = 0x1d,
ENCLog = 0x1e,
ENCMap = 0x1f,
Assembly = 0x20,
AssemblyProcessor = 0x21,
AssemblyOS = 0x22,
AssemblyRef = 0x23,
AssemblyRefProcessor = 0x24,
AssemblyRefOS = 0x25,
File = 0x26,
ExportedType = 0x27,
ManifestResource = 0x28,
NestedClass = 0x29,
GenericParam = 0x2a,
MethodSpec = 0x2b,
GenericParamConstraint = 0x2c,
Count = 0x2d
}
internal class EcmaMetadata
{
public EcmaMetadata(EcmaMetadataSchema schema,
ReadOnlyMemory<byte>[] tables,
ReadOnlyMemory<byte> stringHeap,
ReadOnlyMemory<byte> userStringHeap,
ReadOnlyMemory<byte> blobHeap,
ReadOnlyMemory<byte> guidHeap)
{
Schema = schema;
_tables = tables;
StringHeap = stringHeap;
UserStringHeap = userStringHeap;
BlobHeap = blobHeap;
GuidHeap = guidHeap;
}
public EcmaMetadataSchema Schema { get; init; }
private ReadOnlyMemory<byte>[] _tables;
public ReadOnlySpan<ReadOnlyMemory<byte>> Tables => _tables;
public ReadOnlyMemory<byte> StringHeap { get; init; }
public ReadOnlyMemory<byte> UserStringHeap { get; init; }
public ReadOnlyMemory<byte> BlobHeap { get; init; }
public ReadOnlyMemory<byte> GuidHeap { get; init; }
private Microsoft.Diagnostics.DataContractReader.Helpers.EcmaMetadataReader? _ecmaMetadataReader;
public Microsoft.Diagnostics.DataContractReader.Helpers.EcmaMetadataReader EcmaMetadataReader
{
get
{
_ecmaMetadataReader ??= new Helpers.EcmaMetadataReader(this);
return _ecmaMetadataReader;
}
}
}
internal enum MetadataColumnIndex
{
Module_Generation,
Module_Name,
Module_Mvid,
Module_EncId,
Module_EncBaseId,
TypeRef_ResolutionScope,
TypeRef_TypeName,
TypeRef_TypeNamespace,
TypeDef_Flags,
TypeDef_TypeName,
TypeDef_TypeNamespace,
TypeDef_Extends,
TypeDef_FieldList,
TypeDef_MethodList,
FieldPtr_Field,
Field_Flags,
Field_Name,
Field_Signature,
MethodPtr_Method,
MethodDef_Rva,
MethodDef_ImplFlags,
MethodDef_Flags,
MethodDef_Name,
MethodDef_Signature,
MethodDef_ParamList,
ParamPtr_Param,
Param_Flags,
Param_Sequence,
Param_Name,
InterfaceImpl_Class,
InterfaceImpl_Interface,
MemberRef_Class,
MemberRef_Name,
MemberRef_Signature,
Constant_Type,
Constant_Parent,
Constant_Value,
CustomAttribute_Parent,
CustomAttribute_Type,
CustomAttribute_Value,
FieldMarshal_Parent,
FieldMarshal_NativeType,
DeclSecurity_Action,
DeclSecurity_Parent,
DeclSecurity_PermissionSet,
ClassLayout_PackingSize,
ClassLayout_ClassSize,
ClassLayout_Parent,
FieldLayout_Offset,
FieldLayout_Field,
StandAloneSig_Signature,
EventMap_Parent,
EventMap_EventList,
EventPtr_Event,
Event_EventFlags,
Event_Name,
Event_EventType,
PropertyMap_Parent,
PropertyMap_PropertyList,
PropertyPtr_Property,
Property_Flags,
Property_Name,
Property_Type,
MethodSemantics_Semantics,
MethodSemantics_Method,
MethodSemantics_Association,
MethodImpl_Class,
MethodImpl_MethodBody,
MethodImpl_MethodDeclaration,
ModuleRef_Name,
TypeSpec_Signature,
ImplMap_MappingFlags,
ImplMap_MemberForwarded,
ImplMap_ImportName,
ImplMap_ImportScope,
FieldRva_Rva,
FieldRva_Field,
ENCLog_Token,
ENCLog_Op,
ENCMap_Token,
Assembly_HashAlgId,
Assembly_MajorVersion,
Assembly_MinorVersion,
Assembly_BuildNumber,
Assembly_RevisionNumber,
Assembly_Flags,
Assembly_PublicKey,
Assembly_Name,
Assembly_Culture,
AssemblyRef_MajorVersion,
AssemblyRef_MinorVersion,
AssemblyRef_BuildNumber,
AssemblyRef_RevisionNumber,
AssemblyRef_Flags,
AssemblyRef_PublicKeyOrToken,
AssemblyRef_Name,
AssemblyRef_Culture,
AssemblyRef_HashValue,
File_Flags,
File_Name,
File_HashValue,
ExportedType_Flags,
ExportedType_TypeDefId,
ExportedType_TypeName,
ExportedType_TypeNamespace,
ExportedType_Implementation,
ManifestResource_Offset,
ManifestResource_Flags,
ManifestResource_Name,
ManifestResource_Implementation,
NestedClass_NestedClass,
NestedClass_EnclosingClass,
GenericParam_Number,
GenericParam_Flags,
GenericParam_Owner,
GenericParam_Name,
MethodSpec_Method,
MethodSpec_Instantiation,
GenericParamConstraint_Owner,
GenericParamConstraint_Constraint,
Count
}
internal class Metadata
{
private readonly Target _target;
private readonly Dictionary<ulong, EcmaMetadata> _metadata = [];
public Metadata(Target target)
{
_target = target;
}
public virtual EcmaMetadata GetMetadata(Contracts.ModuleHandle module)
{
if (_metadata.TryGetValue(module.Address, out EcmaMetadata? result))
return result;
AvailableMetadataType metadataType = _target.Contracts.Loader.GetAvailableMetadataType(module);
if (metadataType == AvailableMetadataType.ReadOnly)
{
if (this.MetadataProvider != null)
result = this.MetadataProvider(module);
if (result == null)
{
TargetPointer address = _target.Contracts.Loader.GetMetadataAddress(module, out ulong size);
byte[] data = new byte[size];
_target.ReadBuffer(address, data);
result = (new Helpers.EcmaMetadataReader(new ReadOnlyMemory<byte>(data))).UnderlyingMetadata;
}
}
else if (metadataType == AvailableMetadataType.ReadWriteSavedCopy)
{
TargetPointer address = _target.Contracts.Loader.GetReadWriteSavedMetadataAddress(module, out ulong size);
byte[] data = new byte[size];
_target.ReadBuffer(address, data);
result = (new Helpers.EcmaMetadataReader(new ReadOnlyMemory<byte>(data))).UnderlyingMetadata;
}
else
{
var targetEcmaMetadata = _target.Contracts.Loader.GetReadWriteMetadata(module);
result = new EcmaMetadata(targetEcmaMetadata.Schema,
GetReadOnlyMemoryFromTargetSpans(targetEcmaMetadata.Tables),
GetReadOnlyMemoryFromTargetSpan(targetEcmaMetadata.StringHeap),
GetReadOnlyMemoryFromTargetSpan(targetEcmaMetadata.UserStringHeap),
GetReadOnlyMemoryFromTargetSpan(targetEcmaMetadata.BlobHeap),
GetReadOnlyMemoryFromTargetSpan(targetEcmaMetadata.GuidHeap));
ReadOnlyMemory<byte> GetReadOnlyMemoryFromTargetSpan(TargetSpan span)
{
if (span.Size == 0)
return default;
byte[] data = new byte[span.Size];
_target.ReadBuffer(span.Address, data);
return new ReadOnlyMemory<byte>(data);
}
ReadOnlyMemory<byte>[] GetReadOnlyMemoryFromTargetSpans(ReadOnlySpan<TargetSpan> spans)
{
ReadOnlyMemory<byte>[] memories = new ReadOnlyMemory<byte>[spans.Length];
for (int i = 0; i < spans.Length; i++)
{
memories[i] = GetReadOnlyMemoryFromTargetSpan(spans[i]);
}
return memories;
}
}
_metadata.Add(module.Address, result);
return result;
}
public Func<Contracts.ModuleHandle, EcmaMetadata>? MetadataProvider;
}

View file

@ -341,8 +341,9 @@ internal sealed partial class SOSDacImpl : ISOSDacInterface, ISOSDacInterface2,
data->dwTransientFlags = (uint)flags;
data->ilBase = contract.GetILBase(handle);
data->metadataStart = contract.GetMetadataAddress(handle, out ulong metadataSize);
data->metadataSize = metadataSize;
TargetSpan readOnlyMetadata = _target.Contracts.EcmaMetadata.GetReadOnlyMetadataAddress(handle);
data->metadataStart = readOnlyMetadata.Address;
data->metadataSize = readOnlyMetadata.Size;
data->LoaderAllocator = contract.GetLoaderAllocator(handle);
data->ThunkHeap = contract.GetThunkHeap(handle);

View file

@ -3,24 +3,23 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.Diagnostics.DataContractReader.Contracts;
using Microsoft.Diagnostics.DataContractReader.Helpers;
namespace Microsoft.Diagnostics.DataContractReader.Legacy
{
internal static class SigFormat
{
private const uint IMAGE_CEE_CS_CALLCONV_MASK = 0xF;
private const uint IMAGE_CEE_CS_CALLCONV_VARARG = 0x5;
private const uint IMAGE_CEE_CS_CALLCONV_GENERIC = 0x10;
public static void AppendSigFormat(Target target,
public static unsafe void AppendSigFormat(Target target,
StringBuilder stringBuilder,
ReadOnlySpan<byte> signature,
EcmaMetadataReader? metadata,
MetadataReader? metadata,
string? memberName,
string? className,
string? namespaceName,
@ -28,14 +27,32 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy
ReadOnlySpan<TypeHandle> methodInstantiation,
bool CStringParmsOnly)
{
byte callConv = checked((byte)GetData(ref signature));
if ((callConv & IMAGE_CEE_CS_CALLCONV_GENERIC) != 0)
fixed (byte* pSignature = signature)
{
GetData(ref signature); // Ignore generic parameter count
BlobReader blobReader = new BlobReader(pSignature, signature.Length);
AppendSigFormat(target, stringBuilder, blobReader, metadata, memberName, className, namespaceName, typeInstantiation, methodInstantiation, CStringParmsOnly);
}
int cArgs = (int)GetData(ref signature);
bool isVarArg = (callConv & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_VARARG;
}
public static void AppendSigFormat(Target target,
StringBuilder stringBuilder,
BlobReader signature,
MetadataReader? metadata,
string? memberName,
string? className,
string? namespaceName,
ReadOnlySpan<TypeHandle> typeInstantiation,
ReadOnlySpan<TypeHandle> methodInstantiation,
bool CStringParmsOnly)
{
SignatureHeader header = signature.ReadSignatureHeader();
if (header.IsGeneric)
{
signature.ReadCompressedInteger(); // Ignore generic parameter count
}
int cArgs = (int)signature.ReadCompressedInteger();
bool isVarArg = header.CallingConvention == SignatureCallingConvention.VarArgs;
if (!CStringParmsOnly)
{
@ -80,65 +97,19 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy
stringBuilder.Append(')');
}
private static Contracts.CorElementType GetElemType(ref ReadOnlySpan<byte> signature)
{
CorElementType result = (Contracts.CorElementType)signature[0];
signature = signature.Slice(1);
return result;
}
private static uint GetData(ref ReadOnlySpan<byte> signature)
{
byte headerByte = signature[0];
if ((headerByte & 0x80) == 0)
{
signature = signature.Slice(1);
return headerByte;
}
else if ((headerByte & 0x40) == 0)
{
int result = ((headerByte & 0x3f) << 8) | signature[1];
signature = signature.Slice(2);
return (uint)result;
}
else if ((headerByte & 0x20) == 0)
{
int result = ((headerByte & 0x1f) << 24) | (signature[1] << 16) | (signature[2] << 8) | signature[3];
signature = signature.Slice(4);
return (uint)result;
}
throw new InvalidOperationException("Invalid signature format");
}
private static uint GetToken(ref ReadOnlySpan<byte> signature)
{
uint data = GetData(ref signature);
MetadataTable table;
switch (data & 3)
{
case 0: table = MetadataTable.TypeDef; break;
case 1: table = MetadataTable.TypeRef; break;
case 2: table = MetadataTable.TypeSpec; break;
default: throw new InvalidOperationException("Invalid signature format");
}
return EcmaMetadataReader.CreateToken(table, data >> 2);
}
private static void AddTypeString(Target target,
private static unsafe void AddTypeString(Target target,
StringBuilder stringBuilder,
ref ReadOnlySpan<byte> signature,
ref BlobReader signature,
ReadOnlySpan<TypeHandle> typeInstantiation,
ReadOnlySpan<TypeHandle> methodInstantiation,
EcmaMetadataReader? metadata)
MetadataReader? metadata)
{
string _namespace;
string name;
EcmaMetadataCursor cursor;
while (true)
{
switch (GetElemType(ref signature))
switch ((CorElementType)signature.ReadByte())
{
case CorElementType.Void: stringBuilder.Append("Void"); return;
case CorElementType.Boolean: stringBuilder.Append("Boolean"); return;
@ -163,17 +134,18 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy
case CorElementType.Class:
if (metadata == null)
throw new InvalidOperationException("Invalid signature without metadata reader");
uint token = GetToken(ref signature);
cursor = metadata.GetCursor(token);
switch (EcmaMetadataReader.TokenToTable(token))
EntityHandle handle = signature.ReadTypeHandle();
switch (handle.Kind)
{
case MetadataTable.TypeDef:
_namespace = metadata.GetColumnAsUtf8String(cursor, MetadataColumnIndex.TypeDef_TypeNamespace);
name = metadata.GetColumnAsUtf8String(cursor, MetadataColumnIndex.TypeDef_TypeNamespace);
case HandleKind.TypeDefinition:
TypeDefinition typeDef = metadata.GetTypeDefinition((TypeDefinitionHandle)handle);
_namespace = metadata.GetString(typeDef.Namespace);
name = metadata.GetString(typeDef.Name);
break;
case MetadataTable.TypeRef:
_namespace = metadata.GetColumnAsUtf8String(cursor, MetadataColumnIndex.TypeRef_TypeNamespace);
name = metadata.GetColumnAsUtf8String(cursor, MetadataColumnIndex.TypeRef_TypeNamespace);
case HandleKind.TypeReference:
TypeReference typeRef = metadata.GetTypeReference((TypeReferenceHandle)handle);
_namespace = metadata.GetString(typeRef.Namespace);
name = metadata.GetString(typeRef.Name);
break;
default:
return;
@ -188,9 +160,8 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy
return;
case CorElementType.Internal:
TargetPointer typeHandlePointer = target.ReadPointerFromSpan(signature);
TargetPointer typeHandlePointer = target.ReadPointerFromSpan(signature.ReadBytes(target.PointerSize));
IRuntimeTypeSystem runtimeTypeSystem = target.Contracts.RuntimeTypeSystem;
signature.Slice(target.PointerSize);
TypeHandle th = runtimeTypeSystem.GetTypeHandle(typeHandlePointer);
switch (runtimeTypeSystem.GetSignatureCorElementType(th))
{
@ -214,10 +185,11 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy
uint typeDefToken = runtimeTypeSystem.GetTypeDefToken(th);
TargetPointer modulePointer = target.Contracts.RuntimeTypeSystem.GetModule(th);
Contracts.ModuleHandle module = target.Contracts.Loader.GetModuleHandle(modulePointer);
EcmaMetadataReader internalTypeMetadata = target.Metadata.GetMetadata(module).EcmaMetadataReader;
cursor = internalTypeMetadata.GetCursor(typeDefToken);
_namespace = internalTypeMetadata.GetColumnAsUtf8String(cursor, MetadataColumnIndex.TypeDef_TypeNamespace);
name = internalTypeMetadata.GetColumnAsUtf8String(cursor, MetadataColumnIndex.TypeDef_TypeNamespace);
MetadataReader internalTypeMetadata = target.Contracts.EcmaMetadata.GetMetadata(module)!;
TypeDefinition internalTypeDef = internalTypeMetadata.GetTypeDefinition((TypeDefinitionHandle)MetadataTokens.Handle((int)typeDefToken));
_namespace = internalTypeMetadata.GetString(internalTypeDef.Namespace);
name = internalTypeMetadata.GetString(internalTypeDef.Name);
if (!string.IsNullOrEmpty(_namespace))
{
@ -242,10 +214,10 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy
return;
case CorElementType.MVar:
uint mvarIndex = GetData(ref signature);
if (methodInstantiation.Length > (int)mvarIndex)
int mvarIndex = signature.ReadCompressedInteger();
if (methodInstantiation.Length > mvarIndex)
{
AddType(target, stringBuilder, methodInstantiation[(int)mvarIndex]);
AddType(target, stringBuilder, methodInstantiation[mvarIndex]);
}
else
{
@ -254,10 +226,10 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy
return;
case CorElementType.Var:
uint varIndex = GetData(ref signature);
if (methodInstantiation.Length > (int)varIndex)
int varIndex = signature.ReadCompressedInteger();
if (methodInstantiation.Length > varIndex)
{
AddType(target, stringBuilder, methodInstantiation[(int)varIndex]);
AddType(target, stringBuilder, methodInstantiation[varIndex]);
}
else
{
@ -267,9 +239,9 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy
case CorElementType.GenericInst:
AddTypeString(target, stringBuilder, ref signature, typeInstantiation, methodInstantiation, metadata);
uint genericArgCount = GetData(ref signature);
int genericArgCount = signature.ReadCompressedInteger();
stringBuilder.Append('<');
for (uint i = 0; i < genericArgCount; i++)
for (int i = 0; i < genericArgCount; i++)
{
if (i != 0)
stringBuilder.Append(',');
@ -286,27 +258,27 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy
case CorElementType.Array:
AddTypeString(target, stringBuilder, ref signature, typeInstantiation, methodInstantiation, metadata);
stringBuilder.Append('[');
uint rank = GetData(ref signature);
int rank = signature.ReadCompressedInteger();
for (uint i = 1; i < rank; i++)
{
stringBuilder.Append(',');
}
stringBuilder.Append(']');
uint numSizes = GetData(ref signature);
for (uint i = 0; i < numSizes; i++)
int numSizes = signature.ReadCompressedInteger();
for (int i = 0; i < numSizes; i++)
{
GetData(ref signature);
_ = signature.ReadCompressedInteger();
}
uint numLoBounds = GetData(ref signature);
for (uint i = 0; i < numLoBounds; i++)
int numLoBounds = signature.ReadCompressedInteger();
for (int i = 0; i < numLoBounds; i++)
{
GetData(ref signature);
_ = signature.ReadCompressedSignedInteger();
}
return;
case CorElementType.FnPtr:
uint callConv = GetData(ref signature);
uint cArgs = GetData(ref signature);
SignatureHeader fnPtrHeader = signature.ReadSignatureHeader();
int cArgs = signature.ReadCompressedInteger();
AddTypeString(target, stringBuilder, ref signature, typeInstantiation, methodInstantiation, metadata);
stringBuilder.Append(" (");
for (uint i = 0; i < cArgs; i++)
@ -315,7 +287,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy
if (i != cArgs - 1)
stringBuilder.Append(", ");
}
if ((callConv & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_VARARG)
if (fnPtrHeader.CallingConvention == SignatureCallingConvention.VarArgs)
{
if (cArgs > 0)
stringBuilder.Append(", ");
@ -326,7 +298,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy
case CorElementType.CModOpt:
case CorElementType.CModReqd:
GetToken(ref signature);
_ = signature.ReadTypeHandle();
break;
default:
@ -374,10 +346,10 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy
uint typeDefToken = runtimeTypeSystem.GetTypeDefToken(typeHandle);
TargetPointer modulePointer = target.Contracts.RuntimeTypeSystem.GetModule(typeHandle);
Contracts.ModuleHandle module = target.Contracts.Loader.GetModuleHandle(modulePointer);
EcmaMetadataReader metadata = target.Metadata.GetMetadata(module).EcmaMetadataReader;
EcmaMetadataCursor cursor = metadata.GetCursor(typeDefToken);
string _namespace = metadata.GetColumnAsUtf8String(cursor, MetadataColumnIndex.TypeDef_TypeNamespace);
string name = metadata.GetColumnAsUtf8String(cursor, MetadataColumnIndex.TypeDef_TypeNamespace);
MetadataReader metadata = target.Contracts.EcmaMetadata.GetMetadata(module)!;
TypeDefinition typeDef = metadata.GetTypeDefinition((TypeDefinitionHandle)MetadataTokens.Handle((int)typeDefToken));
string _namespace = metadata.GetString(typeDef.Namespace);
string name = metadata.GetString(typeDef.Name);
if (!string.IsNullOrEmpty(_namespace))
{
@ -419,9 +391,9 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy
case CorElementType.Var:
runtimeTypeSystem.IsGenericVariable(typeHandle, out TargetPointer genericVariableModulePointer, out uint typeVarToken);
Contracts.ModuleHandle genericVariableModule = target.Contracts.Loader.GetModuleHandle(genericVariableModulePointer);
EcmaMetadataReader genericVariableMetadata = target.Metadata.GetMetadata(genericVariableModule).EcmaMetadataReader;
EcmaMetadataCursor genericVariableCursor = genericVariableMetadata.GetCursor(typeVarToken);
stringBuilder.Append(genericVariableMetadata.GetColumnAsUtf8String(genericVariableCursor, MetadataColumnIndex.GenericParam_Name));
MetadataReader generatedVariableMetadata = target.Contracts.EcmaMetadata.GetMetadata(genericVariableModule)!;
GenericParameter genericVariable = generatedVariableMetadata.GetGenericParameter((GenericParameterHandle)MetadataTokens.Handle((int)typeVarToken));
stringBuilder.Append(generatedVariableMetadata.GetString(genericVariable.Name));
return;
case CorElementType.SzArray:
@ -443,6 +415,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy
case CorElementType.FnPtr:
runtimeTypeSystem.IsFunctionPointer(typeHandle, out ReadOnlySpan<TypeHandle> retAndArgTypes, out byte callConv);
SignatureHeader header = new SignatureHeader(callConv);
AddType(target, stringBuilder, retAndArgTypes[0]);
stringBuilder.Append(" (");
for (int i = 1; i < retAndArgTypes.Length; i++)
@ -451,7 +424,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy
if (i != retAndArgTypes.Length - 1)
stringBuilder.Append(", ");
}
if ((callConv & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_VARARG)
if (header.CallingConvention == SignatureCallingConvention.VarArgs)
{
if (retAndArgTypes.Length > 1)
stringBuilder.Append(", ");

View file

@ -3,9 +3,10 @@
using System;
using System.Collections.Generic;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Text;
using Microsoft.Diagnostics.DataContractReader.Contracts;
using Microsoft.Diagnostics.DataContractReader.Helpers;
namespace Microsoft.Diagnostics.DataContractReader.Legacy;
@ -119,9 +120,9 @@ internal struct TypeNameBuilder
else
{
module = loader.GetModuleHandle(runtimeTypeSystem.GetModule(th));
EcmaMetadataReader reader = target.Metadata.GetMetadata(module).EcmaMetadataReader;
var cursor = reader.GetCursor(runtimeTypeSystem.GetMethodToken(method));
stringBuilder.Append(reader.GetColumnAsUtf8String(cursor, MetadataColumnIndex.MethodDef_Name));
MetadataReader reader = target.Contracts.EcmaMetadata.GetMetadata(module)!;
MethodDefinition methodDef = reader.GetMethodDefinition(MetadataTokens.MethodDefinitionHandle((int)runtimeTypeSystem.GetMethodToken(method)));
stringBuilder.Append(reader.GetString(methodDef.Name));
}
ReadOnlySpan<TypeHandle> genericMethodInstantiation = runtimeTypeSystem.GetGenericMethodInstantiation(method);
@ -133,12 +134,15 @@ internal struct TypeNameBuilder
if (format.HasFlag(TypeNameFormat.FormatSignature))
{
ReadOnlySpan<byte> signature;
EcmaMetadataReader? reader = default;
MetadataReader? reader = default;
if (!runtimeTypeSystem.IsStoredSigMethodDesc(method, out signature))
{
reader = target.Metadata.GetMetadata(module).EcmaMetadataReader;
var cursor = reader.GetCursor(runtimeTypeSystem.GetMethodToken(method));
signature = reader.GetColumnAsBlob(cursor, MetadataColumnIndex.MethodDef_Signature);
reader = target.Contracts.EcmaMetadata.GetMetadata(module);
if (reader is not null)
{
MethodDefinition methodDef = reader.GetMethodDefinition(MetadataTokens.MethodDefinitionHandle((int)runtimeTypeSystem.GetMethodToken(method)));
signature = reader.GetBlobBytes(methodDef.Signature);
}
}
ReadOnlySpan<TypeHandle> typeInstantiationSigFormat = default;
@ -217,12 +221,12 @@ internal struct TypeNameBuilder
else if (typeSystemContract.IsGenericVariable(typeHandle, out TargetPointer modulePointer, out uint genericParamToken))
{
Contracts.ModuleHandle module = tnb.Target.Contracts.Loader.GetModuleHandle(modulePointer);
EcmaMetadataReader reader = tnb.Target.Metadata.GetMetadata(module).EcmaMetadataReader;
EcmaMetadataCursor cursor = reader.GetCursor(genericParamToken);
MetadataReader reader = tnb.Target.Contracts.EcmaMetadata.GetMetadata(module)!;
var handle = (GenericParameterHandle)MetadataTokens.Handle((int)genericParamToken);
GenericParameter genericParam = reader.GetGenericParameter(handle);
if (format.HasFlag(TypeNameFormat.FormatGenericParam))
{
uint owner = reader.GetColumnAsToken(cursor, MetadataColumnIndex.GenericParam_Owner);
if (EcmaMetadataReader.TokenToTable(owner) == MetadataTable.TypeDef)
if (genericParam.Parent.Kind == HandleKind.TypeDefinition)
{
tnb.TypeString.Append('!');
}
@ -231,7 +235,7 @@ internal struct TypeNameBuilder
tnb.TypeString.Append("!!");
}
}
tnb.AddName(reader.GetColumnAsUtf8String(cursor, MetadataColumnIndex.GenericParam_Name));
tnb.AddName(reader.GetString(genericParam.Name));
format &= ~TypeNameFormat.FormatAssembly;
}
else if (typeSystemContract.IsFunctionPointer(typeHandle, out ReadOnlySpan<TypeHandle> retAndArgTypes, out byte callConv))
@ -271,14 +275,14 @@ internal struct TypeNameBuilder
// ...otherwise it's just a plain type def or an instantiated type
uint typeDefToken = typeSystemContract.GetTypeDefToken(typeHandle);
Contracts.ModuleHandle moduleHandle = tnb.Target.Contracts.Loader.GetModuleHandle(typeSystemContract.GetModule(typeHandle));
if (EcmaMetadataReader.RidFromToken(typeDefToken) == 0)
if (MetadataTokens.EntityHandle((int)typeDefToken).IsNil)
{
tnb.AddName("(dynamicClass)");
}
else
{
EcmaMetadataReader reader = tnb.Target.Metadata.GetMetadata(moduleHandle).EcmaMetadataReader;
AppendNestedTypeDef(ref tnb, reader, typeDefToken, format);
MetadataReader reader = tnb.Target.Contracts.EcmaMetadata.GetMetadata(moduleHandle)!;
AppendNestedTypeDef(ref tnb, reader, (TypeDefinitionHandle)MetadataTokens.EntityHandle((int)typeDefToken), format);
}
// Append instantiation
@ -303,9 +307,9 @@ internal struct TypeNameBuilder
Contracts.ModuleHandle module = tnb.Target.Contracts.Loader.GetModuleHandle(modulePtr);
// NOTE: The DAC variant of assembly name generation is different than the runtime version. The DAC variant is simpler, and only uses SimpleName
EcmaMetadataReader mr = tnb.Target.Metadata.GetMetadata(module).EcmaMetadataReader;
EcmaMetadataCursor cursor = mr.GetCursor(0x20000001);
string assemblySimpleName = mr.GetColumnAsUtf8String(cursor, MetadataColumnIndex.Assembly_Name);
MetadataReader mr = tnb.Target.Contracts.EcmaMetadata.GetMetadata(module)!;
string assemblySimpleName = mr.GetString(mr.GetAssemblyDefinition().Name);
tnb.AddAssemblySpec(assemblySimpleName);
}
@ -470,38 +474,34 @@ internal struct TypeNameBuilder
}
}
private static void AppendNestedTypeDef(ref TypeNameBuilder tnb, EcmaMetadataReader reader, uint typeDefToken, TypeNameFormat format)
private static void AppendNestedTypeDef(ref TypeNameBuilder tnb, MetadataReader reader, TypeDefinitionHandle typeDefToken, TypeNameFormat format)
{
EcmaMetadataCursor cursor = reader.GetCursor(typeDefToken);
System.Reflection.TypeAttributes typeDefAttributes = (System.Reflection.TypeAttributes)reader.GetColumnAsConstant(cursor, MetadataColumnIndex.TypeDef_Flags);
TypeDefinition typeDef = reader.GetTypeDefinition(typeDefToken);
System.Reflection.TypeAttributes typeDefAttributes = typeDef.Attributes;
if ((int)(typeDefAttributes & System.Reflection.TypeAttributes.VisibilityMask) >= (int)System.Reflection.TypeAttributes.NestedPublic)
{
uint currentTypeDefToken = typeDefToken;
List<uint> nestedTokens = new();
EcmaMetadataCursor nestedTypesCursor = reader.GetCursor(EcmaMetadataReader.CreateToken(MetadataTable.NestedClass, 1));
while (reader.TryFindRowFromCursor(nestedTypesCursor, MetadataColumnIndex.NestedClass_NestedClass, currentTypeDefToken, out EcmaMetadataCursor foundNestedClassRecord))
List<TypeDefinitionHandle> nestedTokens = [];
for (TypeDefinitionHandle enclosingType = typeDef.GetDeclaringType(); !enclosingType.IsNil; enclosingType = reader.GetTypeDefinition(enclosingType).GetDeclaringType())
{
currentTypeDefToken = reader.GetColumnAsToken(foundNestedClassRecord, MetadataColumnIndex.NestedClass_EnclosingClass);
nestedTokens.Add(currentTypeDefToken);
nestedTokens.Add(enclosingType);
}
for (int i = nestedTokens.Count - 1; i >= 0; i--)
{
AppendTypeDef(ref tnb, reader, nestedTokens[i], format);
AppendTypeDef(ref tnb, reader, reader.GetTypeDefinition(nestedTokens[i]), format);
}
}
AppendTypeDef(ref tnb, reader, typeDefToken, format);
AppendTypeDef(ref tnb, reader, typeDef, format);
}
private static void AppendTypeDef(ref TypeNameBuilder tnb, EcmaMetadataReader reader, uint typeDefToken, TypeNameFormat format)
private static void AppendTypeDef(ref TypeNameBuilder tnb, MetadataReader reader, TypeDefinition typeDef, TypeNameFormat format)
{
EcmaMetadataCursor cursor = reader.GetCursor(typeDefToken);
string? typeNamespace = null;
if (format.HasFlag(TypeNameFormat.FormatNamespace))
{
typeNamespace = reader.GetColumnAsUtf8String(cursor, MetadataColumnIndex.TypeDef_TypeNamespace);
typeNamespace = reader.GetString(typeDef.Namespace);
}
tnb.AddName(reader.GetColumnAsUtf8String(cursor, MetadataColumnIndex.TypeDef_TypeName), typeNamespace);
tnb.AddName(reader.GetString(typeDef.Name), typeNamespace);
}
private static void AppendParamTypeQualifier(ref TypeNameBuilder tnb, CorElementType kind, uint rank)

View file

@ -95,7 +95,6 @@ public sealed unsafe class Target
internal Contracts.Registry Contracts { get; }
internal DataCache ProcessedData { get; }
internal Helpers.Metadata Metadata { get; }
public delegate int ReadFromTargetDelegate(ulong address, Span<byte> bufferToFill);
@ -116,7 +115,6 @@ public sealed unsafe class Target
{
Contracts = new Contracts.Registry(this);
ProcessedData = new DataCache(this);
Metadata = new Helpers.Metadata(this);
_config = config;
_reader = reader;