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:
parent
f9c08462ba
commit
bfd964a91f
18 changed files with 816 additions and 1903 deletions
340
docs/design/datacontracts/EcmaMetadata.md
Normal file
340
docs/design/datacontracts/EcmaMetadata.md
Normal 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);
|
||||
}
|
||||
```
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
29
src/native/managed/cdacreader/src/Contracts/EcmaMetadata.cs
Normal file
29
src/native/managed/cdacreader/src/Contracts/EcmaMetadata.cs
Normal 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
|
||||
}
|
318
src/native/managed/cdacreader/src/Contracts/EcmaMetadata_1.cs
Normal file
318
src/native/managed/cdacreader/src/Contracts/EcmaMetadata_1.cs
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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(", ");
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue