From bfd964a91fdf7ea1c854d3de217f79c0feaa7b7d Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 13 Aug 2024 20:30:07 -0700 Subject: [PATCH] [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 --- docs/design/datacontracts/EcmaMetadata.md | 340 ++++++++++ docs/design/datacontracts/Loader.md | 123 +--- .../contract_csharp_api_design.cs | 12 + src/coreclr/debug/runtimeinfo/contracts.jsonc | 1 + .../cdacreader/src/Contracts/EcmaMetadata.cs | 29 + .../src/Contracts/EcmaMetadata_1.cs | 318 ++++++++++ .../cdacreader/src/Contracts/Loader.cs | 79 --- .../cdacreader/src/Contracts/Loader_1.cs | 33 - .../cdacreader/src/Contracts/Registry.cs | 1 + .../EcmaMetadataReader.InternalHelpers.cs | 106 ---- .../Helpers/EcmaMetadataReader.StaticData.cs | 594 ------------------ .../EcmaMetadataReader.StaticHelpers.cs | 59 -- .../src/Helpers/EcmaMetadataReader.cs | 434 ------------- .../cdacreader/src/Helpers/Metadata.cs | 334 ---------- .../cdacreader/src/Legacy/SOSDacImpl.cs | 5 +- .../cdacreader/src/Legacy/SigFormat.cs | 181 +++--- .../cdacreader/src/Legacy/TypeNameBuilder.cs | 68 +- src/native/managed/cdacreader/src/Target.cs | 2 - 18 files changed, 816 insertions(+), 1903 deletions(-) create mode 100644 docs/design/datacontracts/EcmaMetadata.md create mode 100644 src/native/managed/cdacreader/src/Contracts/EcmaMetadata.cs create mode 100644 src/native/managed/cdacreader/src/Contracts/EcmaMetadata_1.cs delete mode 100644 src/native/managed/cdacreader/src/Helpers/EcmaMetadataReader.InternalHelpers.cs delete mode 100644 src/native/managed/cdacreader/src/Helpers/EcmaMetadataReader.StaticData.cs delete mode 100644 src/native/managed/cdacreader/src/Helpers/EcmaMetadataReader.StaticHelpers.cs delete mode 100644 src/native/managed/cdacreader/src/Helpers/EcmaMetadataReader.cs delete mode 100644 src/native/managed/cdacreader/src/Helpers/Metadata.cs diff --git a/docs/design/datacontracts/EcmaMetadata.md b/docs/design/datacontracts/EcmaMetadata.md new file mode 100644 index 00000000000..a5b445f10dc --- /dev/null +++ b/docs/design/datacontracts/EcmaMetadata.md @@ -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(metadataDirectoryAddress); + ulong size = Target.Read(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 RowCount => _rowCount; + + private readonly bool[] _isSorted; + public readonly ReadOnlySpan 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 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(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 input, T alignment) + where T : IBinaryInteger +{ + return input + (alignment - T.One) & ~(alignment - T.One); +} +``` diff --git a/docs/design/datacontracts/Loader.md b/docs/design/datacontracts/Loader.md index 3e6cbe0d0dc..d0fe390b5ad 100644 --- a/docs/design/datacontracts/Loader.md +++ b/docs/design/datacontracts/Loader.md @@ -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 RowCount => _rowCount; - - private readonly bool[] _isSorted; - public readonly ReadOnlySpan 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 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(metadataDirectoryAddress); - size = target.Read(metadataDirectoryAddress + sizeof(int)); - return baseAddress + rva; -} - -AvailableMetadataType ILoader.GetAvailableMetadataType(ModuleHandle handle) -{ - Data.Module module = _target.ProcessedData.GetOrAdd(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(handle.Address); - TargetPointer dynamicMetadata = target.ReadPointer(handle.Address + /* Module::DynamicMetadata offset */); - - size = target.Read(handle.Address + /* DynamicMetadata::Size offset */); - TargetPointer result = handle.Address + /* DynamicMetadata::Data offset */; - return result; -} - ModuleLookupTables GetLookupTables(ModuleHandle handle) { return new ModuleLookupTables( diff --git a/docs/design/datacontracts/contract_csharp_api_design.cs b/docs/design/datacontracts/contract_csharp_api_design.cs index a770c1f4576..272645ec482 100644 --- a/docs/design/datacontracts/contract_csharp_api_design.cs +++ b/docs/design/datacontracts/contract_csharp_api_design.cs @@ -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; diff --git a/src/coreclr/debug/runtimeinfo/contracts.jsonc b/src/coreclr/debug/runtimeinfo/contracts.jsonc index 7ccabcb41dc..499a284cbcd 100644 --- a/src/coreclr/debug/runtimeinfo/contracts.jsonc +++ b/src/coreclr/debug/runtimeinfo/contracts.jsonc @@ -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, diff --git a/src/native/managed/cdacreader/src/Contracts/EcmaMetadata.cs b/src/native/managed/cdacreader/src/Contracts/EcmaMetadata.cs new file mode 100644 index 00000000000..c7d8e5412b8 --- /dev/null +++ b/src/native/managed/cdacreader/src/Contracts/EcmaMetadata.cs @@ -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 +} diff --git a/src/native/managed/cdacreader/src/Contracts/EcmaMetadata_1.cs b/src/native/managed/cdacreader/src/Contracts/EcmaMetadata_1.cs new file mode 100644 index 00000000000..2bfa70f29c6 --- /dev/null +++ b/src/native/managed/cdacreader/src/Contracts/EcmaMetadata_1.cs @@ -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 _metadata = new(); + + public TargetSpan GetReadOnlyMetadataAddress(ModuleHandle handle) + { + Data.Module module = target.ProcessedData.GetOrAdd(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 RowCount => _rowCount; + + private readonly bool[] _isSorted; + public readonly ReadOnlySpan 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 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(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(handle.Address); + Data.DynamicMetadata dynamicMetadata = target.ProcessedData.GetOrAdd(module.DynamicMetadata); + + return new TargetSpan(dynamicMetadata.Data, dynamicMetadata.Size); + } + + private TargetEcmaMetadata GetReadWriteMetadata(ModuleHandle handle) + { + throw new NotImplementedException(); + } + + private static T AlignUp(T input, T alignment) + where T : IBinaryInteger + { + return input + (alignment - T.One) & ~(alignment - T.One); + } +} diff --git a/src/native/managed/cdacreader/src/Contracts/Loader.cs b/src/native/managed/cdacreader/src/Contracts/Loader.cs index 39845918cfc..a71bdd4d129 100644 --- a/src/native/managed/cdacreader/src/Contracts/Loader.cs +++ b/src/native/managed/cdacreader/src/Contracts/Loader.cs @@ -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 RowCount => _rowCount; - - private readonly bool[] _isSorted; - public readonly ReadOnlySpan 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 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(); } diff --git a/src/native/managed/cdacreader/src/Contracts/Loader_1.cs b/src/native/managed/cdacreader/src/Contracts/Loader_1.cs index 3385748b4dc..215eaed4a39 100644 --- a/src/native/managed/cdacreader/src/Contracts/Loader_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/Loader_1.cs @@ -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(handle.Address); - return module.GetLoadedMetadata(out size); - } - - AvailableMetadataType ILoader.GetAvailableMetadataType(ModuleHandle handle) - { - Data.Module module = _target.ProcessedData.GetOrAdd(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(handle.Address); - Data.DynamicMetadata dynamicMetadata = _target.ProcessedData.GetOrAdd(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(handle.Address); diff --git a/src/native/managed/cdacreader/src/Contracts/Registry.cs b/src/native/managed/cdacreader/src/Contracts/Registry.cs index 0d6894e9fce..a5d3721f06f 100644 --- a/src/native/managed/cdacreader/src/Contracts/Registry.cs +++ b/src/native/managed/cdacreader/src/Contracts/Registry.cs @@ -20,6 +20,7 @@ internal sealed class Registry public IException Exception => GetContract(); public ILoader Loader => GetContract(); + public IEcmaMetadata EcmaMetadata => GetContract(); public IObject Object => GetContract(); public IThread Thread => GetContract(); public IRuntimeTypeSystem RuntimeTypeSystem => GetContract(); diff --git a/src/native/managed/cdacreader/src/Helpers/EcmaMetadataReader.InternalHelpers.cs b/src/native/managed/cdacreader/src/Helpers/EcmaMetadataReader.InternalHelpers.cs deleted file mode 100644 index 1fe072ce1e9..00000000000 --- a/src/native/managed/cdacreader/src/Helpers/EcmaMetadataReader.InternalHelpers.cs +++ /dev/null @@ -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 bytes, MetadataColumnIndex column, out uint value) - { - int size = ColumnSize(column); - ReadOnlySpan singleColumn = bytes.Slice(ColumnOffset(column), size); - if (size == 2) - { - if (TryReadCore(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 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; - } -} diff --git a/src/native/managed/cdacreader/src/Helpers/EcmaMetadataReader.StaticData.cs b/src/native/managed/cdacreader/src/Helpers/EcmaMetadataReader.StaticData.cs deleted file mode 100644 index 851a10d0f78..00000000000 --- a/src/native/managed/cdacreader/src/Helpers/EcmaMetadataReader.StaticData.cs +++ /dev/null @@ -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[][] 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[][] GetColumnTokenDecoders() - { - Func[][] decoders = new Func[32][]; - for (int i = 0; i < 32; i++) - { - List 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 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[] GetColumnTokenDecode(List ptrTablesPresent) - { - Func[] columnTokenDecode = new Func[(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 ComputeDecoder(MetadataTable[] decoderData) - { - Func 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; - } - } -} diff --git a/src/native/managed/cdacreader/src/Helpers/EcmaMetadataReader.StaticHelpers.cs b/src/native/managed/cdacreader/src/Helpers/EcmaMetadataReader.StaticHelpers.cs deleted file mode 100644 index 07c8ef21fea..00000000000 --- a/src/native/managed/cdacreader/src/Helpers/EcmaMetadataReader.StaticHelpers.cs +++ /dev/null @@ -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() where T : struct, INumberBase, IMinMaxValue - { - return T.IsNegative(T.MinValue); - } - private static bool TryReadCore(ReadOnlySpan bytes, out T value) where T : struct, IBinaryInteger, IMinMaxValue - { - return T.TryReadLittleEndian(bytes.Slice(0, Unsafe.SizeOf()), IsSigned(), out value); - } - - private static T ReadLittleEndian(ReadOnlySpan bytes) where T : struct, IBinaryInteger, IMinMaxValue - { - if (!TryReadCore(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(rid, 0xFFFFFF, nameof(rid)); - ArgumentOutOfRangeException.ThrowIfGreaterThan((int)table, (int)MetadataTable.GenericParamConstraint, nameof(table)); - return ((uint)table << 24) | rid; - } - -} diff --git a/src/native/managed/cdacreader/src/Helpers/EcmaMetadataReader.cs b/src/native/managed/cdacreader/src/Helpers/EcmaMetadataReader.cs deleted file mode 100644 index 47a2a5d92ce..00000000000 --- a/src/native/managed/cdacreader/src/Helpers/EcmaMetadataReader.cs +++ /dev/null @@ -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 TableData; - internal MetadataTable Table; - internal uint Rid; - internal int RowSize; - - public ReadOnlySpan 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[] columnTokenDecode; - - - public EcmaMetadataReader(ReadOnlyMemory imageMemory) - { - columnSize = new int[(int)MetadataColumnIndex.Count]; - columnOffset = new int[(int)MetadataColumnIndex.Count]; - rowSize = new int[(int)MetadataTable.Count]; - columnTokenDecode = Array.Empty>(); - - ReadOnlySpan image = imageMemory.Span; - int magic = ReadLittleEndian(image); - if (magic != 0x424A5342) - throw new ArgumentOutOfRangeException(nameof(imageMemory)); - - int versionSize = ReadLittleEndian(image.Slice(12, 4)); - versionSize = AlignUp(versionSize, 4); - - ReadOnlySpan 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(image.Slice(currentOffset)); - currentOffset += 2; - - ReadOnlyMemory StringHeap = null; - ReadOnlyMemory UserStringHeap = null; - ReadOnlyMemory BlobHeap = null; - ReadOnlyMemory GuidHeap = null; - ReadOnlyMemory 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 tables = TablesHeap.Span; - - byte heapSizes = ReadLittleEndian(tables.Slice(6, 1)); - ulong validTables = ReadLittleEndian(tables.Slice(8, 8)); - ulong sortedTables = ReadLittleEndian(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(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[] tableData = new ReadOnlyMemory[(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 Data) ReadStream(ref ReadOnlySpan image) - { - int offset = ReadLittleEndian(image.Slice(currentOffset)); - currentOffset += 4; - int size = ReadLittleEndian(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>(); - 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 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 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 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 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); - - checked - { - ReadOnlySpan 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 utf8Data = GetColumnAsUtf8(c, col_idx); - string str = string.Empty; - if (utf8Data.Length > 0) - { - str = System.Text.Encoding.UTF8.GetString(utf8Data); - } - return str; - } -} diff --git a/src/native/managed/cdacreader/src/Helpers/Metadata.cs b/src/native/managed/cdacreader/src/Helpers/Metadata.cs deleted file mode 100644 index 5e683d5c72b..00000000000 --- a/src/native/managed/cdacreader/src/Helpers/Metadata.cs +++ /dev/null @@ -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[] tables, - ReadOnlyMemory stringHeap, - ReadOnlyMemory userStringHeap, - ReadOnlyMemory blobHeap, - ReadOnlyMemory guidHeap) - { - Schema = schema; - _tables = tables; - StringHeap = stringHeap; - UserStringHeap = userStringHeap; - BlobHeap = blobHeap; - GuidHeap = guidHeap; - } - - public EcmaMetadataSchema Schema { get; init; } - - private ReadOnlyMemory[] _tables; - public ReadOnlySpan> Tables => _tables; - public ReadOnlyMemory StringHeap { get; init; } - public ReadOnlyMemory UserStringHeap { get; init; } - public ReadOnlyMemory BlobHeap { get; init; } - public ReadOnlyMemory 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 _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(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(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 GetReadOnlyMemoryFromTargetSpan(TargetSpan span) - { - if (span.Size == 0) - return default; - byte[] data = new byte[span.Size]; - _target.ReadBuffer(span.Address, data); - return new ReadOnlyMemory(data); - } - ReadOnlyMemory[] GetReadOnlyMemoryFromTargetSpans(ReadOnlySpan spans) - { - ReadOnlyMemory[] memories = new ReadOnlyMemory[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? MetadataProvider; -} diff --git a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs index e6d4c1da939..4a9510f0159 100644 --- a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs @@ -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); diff --git a/src/native/managed/cdacreader/src/Legacy/SigFormat.cs b/src/native/managed/cdacreader/src/Legacy/SigFormat.cs index 965bb7edf99..4ce7832a7bd 100644 --- a/src/native/managed/cdacreader/src/Legacy/SigFormat.cs +++ b/src/native/managed/cdacreader/src/Legacy/SigFormat.cs @@ -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 signature, - EcmaMetadataReader? metadata, + MetadataReader? metadata, string? memberName, string? className, string? namespaceName, @@ -28,14 +27,32 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy ReadOnlySpan 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 typeInstantiation, + ReadOnlySpan 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 signature) - { - CorElementType result = (Contracts.CorElementType)signature[0]; - signature = signature.Slice(1); - return result; - } - - private static uint GetData(ref ReadOnlySpan 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 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 signature, + ref BlobReader signature, ReadOnlySpan typeInstantiation, ReadOnlySpan 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 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(", "); diff --git a/src/native/managed/cdacreader/src/Legacy/TypeNameBuilder.cs b/src/native/managed/cdacreader/src/Legacy/TypeNameBuilder.cs index 3e7dac65364..ce182819885 100644 --- a/src/native/managed/cdacreader/src/Legacy/TypeNameBuilder.cs +++ b/src/native/managed/cdacreader/src/Legacy/TypeNameBuilder.cs @@ -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 genericMethodInstantiation = runtimeTypeSystem.GetGenericMethodInstantiation(method); @@ -133,12 +134,15 @@ internal struct TypeNameBuilder if (format.HasFlag(TypeNameFormat.FormatSignature)) { ReadOnlySpan 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 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 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 nestedTokens = new(); - EcmaMetadataCursor nestedTypesCursor = reader.GetCursor(EcmaMetadataReader.CreateToken(MetadataTable.NestedClass, 1)); - while (reader.TryFindRowFromCursor(nestedTypesCursor, MetadataColumnIndex.NestedClass_NestedClass, currentTypeDefToken, out EcmaMetadataCursor foundNestedClassRecord)) + List 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) diff --git a/src/native/managed/cdacreader/src/Target.cs b/src/native/managed/cdacreader/src/Target.cs index a091e2e4f96..03e0d7ad8a4 100644 --- a/src/native/managed/cdacreader/src/Target.cs +++ b/src/native/managed/cdacreader/src/Target.cs @@ -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 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;