Skip to content

Commit 30acb0b

Browse files
committed
Merge remote-tracking branch 'upstream/main' into interlockedgeneric
2 parents 9be3f2c + 27776e2 commit 30acb0b

File tree

74 files changed

+4431
-375
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+4431
-375
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Contract DacStreams
2+
3+
This contract is for getting information from the streams embedded into a dump file as it crashes
4+
5+
## APIs of contract
6+
7+
``` csharp
8+
// Return string corresponding to type system data structure if it exists, or null otherwise
9+
string StringFromEEAddress(TargetPointer address);
10+
```
11+
12+
## Version 1
13+
14+
Global variables used
15+
| Global Name | Type | Purpose |
16+
| --- | --- | --- |
17+
| MiniMetaDataBuffAddress | TargetPointer | Identify where the mini metadata stream exists |
18+
| MiniMetaDataBuffMaxSize | uint | Identify where the size of the mini metadata stream |
19+
20+
Magic numbers
21+
| Name | Value |
22+
| --- | --- |
23+
| MiniMetadataSignature | 0x6d727473 |
24+
| EENameStreamSignature | 0x614e4545 |
25+
26+
The format of the MiniMetadataStream begins with a Streams header, which has 3 fields
27+
28+
| Field | Type | Offset | Meaning |
29+
| --- | --- | --- | --- |
30+
| MiniMetadataSignature| uint | 0 | Magic value used to identify that there are streams |
31+
| TotalSize | uint | 4 | Total size of the entire set of MiniMetadata streams including this header |
32+
| Count of Streams | uint | 8 | Number of streams in the MiniMetadata |
33+
34+
The concept is that each stream simply follows the previous stream in the buffer.
35+
There is no padding, so the data is not expected to be aligned within the buffer.
36+
NOTE: At the moment there is only 1 supported stream type, so Count of Streams can only be 1.
37+
38+
The `EENameStream` is structured as a header, plus a series of null-terminated utf8 strings, and pointers.
39+
40+
The EENameStream header
41+
| Field | Type | Offset | Meaning |
42+
| --- | --- | --- | --- |
43+
| EENameStreamSignature | uint | 0 | Magic value used to identify that the bytes immediately following are an `EENameStream` |
44+
| CountOfNames | uint | 4 | Number of names encoded |
45+
46+
EENameStream entry
47+
| Field | Type | Offset | Meaning |
48+
| --- | --- | --- | --- |
49+
| Pointer | pointer | 0 | Pointer to type system structure |
50+
| String | null-terminated UTF-8 sting | 4 or 8 based on target pointer size | Pointer to type system structure |
51+
52+
Following the EENameStream header, there are CountOfNames entries. Each entry begins with a target pointer sized block which identifies a particular type system data structure, followed by a utf8 encoded null-terminated string.
53+
54+
``` csharp
55+
string StringFromEEAddress(TargetPointer address)
56+
{
57+
TargetPointer miniMetaDataBuffAddress = _target.Read<uint>(_target.ReadGlobalPointer(Constants.Globals.MiniMetaDataBuffAddress));
58+
uint miniMetaDataBuffMaxSize = _target.Read<uint>(_target.ReadGlobalPointer(Constants.Globals.MiniMetaDataBuffMaxSize));
59+
60+
// Parse MiniMetadataStream according the the format described above to produce a dictionary from pointer to string from the EENameStream.
61+
// Then lookup in the dictionary, to produce a result if it was present in the table.
62+
// In general, since this api is intended for fallback scenarios, implementations of this api should attempt
63+
// to return null instead of producing errors.
64+
// Since in normal execution of the runtime no stream is constructed, it is normal when examining full dumps and live process state without a stream encoded.
65+
}
66+
```

docs/design/datacontracts/Loader.md

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,75 @@ record struct ModuleLookupTables(
2626
TargetPointer MethodDefToDesc,
2727
TargetPointer TypeDefToMethodTable,
2828
TargetPointer TypeRefToMethodTable);
29+
30+
internal struct EcmaMetadataSchema
31+
{
32+
public EcmaMetadataSchema(string metadataVersion, bool largeStringHeap, bool largeBlobHeap, bool largeGuidHeap, int[] rowCount, bool[] isSorted, bool variableSizedColumnsAre4BytesLong)
33+
{
34+
MetadataVersion = metadataVersion;
35+
LargeStringHeap = largeStringHeap;
36+
LargeBlobHeap = largeBlobHeap;
37+
LargeGuidHeap = largeGuidHeap;
38+
39+
_rowCount = rowCount;
40+
_isSorted = isSorted;
41+
42+
VariableSizedColumnsAreAll4BytesLong = variableSizedColumnsAre4BytesLong;
43+
}
44+
45+
public readonly string MetadataVersion;
46+
47+
public readonly bool LargeStringHeap;
48+
public readonly bool LargeBlobHeap;
49+
public readonly bool LargeGuidHeap;
50+
51+
// Table data, these structures hold MetadataTable.Count entries
52+
private readonly int[] _rowCount;
53+
public readonly ReadOnlySpan<int> RowCount => _rowCount;
54+
55+
private readonly bool[] _isSorted;
56+
public readonly ReadOnlySpan<bool> IsSorted => _isSorted;
57+
58+
// In certain scenarios the size of the tables is forced to be the maximum size
59+
// Otherwise the size of columns should be computed based on RowSize/the various heap flags
60+
public readonly bool VariableSizedColumnsAreAll4BytesLong;
61+
}
62+
63+
internal class TargetEcmaMetadata
64+
{
65+
public TargetEcmaMetadata(EcmaMetadataSchema schema,
66+
TargetSpan[] tables,
67+
TargetSpan stringHeap,
68+
TargetSpan userStringHeap,
69+
TargetSpan blobHeap,
70+
TargetSpan guidHeap)
71+
{
72+
Schema = schema;
73+
_tables = tables;
74+
StringHeap = stringHeap;
75+
UserStringHeap = userStringHeap;
76+
BlobHeap = blobHeap;
77+
GuidHeap = guidHeap;
78+
}
79+
80+
public EcmaMetadataSchema Schema { get; init; }
81+
82+
private TargetSpan[] _tables;
83+
public ReadOnlySpan<TargetSpan> Tables => _tables;
84+
public TargetSpan StringHeap { get; init; }
85+
public TargetSpan UserStringHeap { get; init; }
86+
public TargetSpan BlobHeap { get; init; }
87+
public TargetSpan GuidHeap { get; init; }
88+
}
89+
90+
[Flags]
91+
internal enum AvailableMetadataType
92+
{
93+
None = 0,
94+
ReadOnly = 1,
95+
ReadWriteSavedCopy = 2,
96+
ReadWrite = 4
97+
}
2998
```
3099

31100
``` csharp
@@ -36,13 +105,31 @@ TargetPointer GetLoaderAllocator(ModuleHandle handle);
36105
TargetPointer GetThunkHeap(ModuleHandle handle);
37106
TargetPointer GetILBase(ModuleHandle handle);
38107
TargetPointer GetMetadataAddress(ModuleHandle handle, out ulong size);
108+
AvailableMetadataType GetAvailableMetadataType(ModuleHandle handle);
109+
TargetPointer GetReadWriteSavedMetadataAddress(ModuleHandle handle, out ulong size);
110+
TargetEcmaMetadata GetReadWriteMetadata(ModuleHandle handle);
39111
ModuleLookupTables GetLookupTables(ModuleHandle handle);
40112
```
41113

42114
## Version 1
43115

44116
Data descriptors used:
45-
- `Module`
117+
| Data Descriptor Name | Field | Meaning |
118+
| --- | --- | --- |
119+
| `Module` | `Assembly` | Assembly of the Module |
120+
| `Module` | `Base` | Pointer to start of PE file in memory |
121+
| `Module` | `Flags` | Assembly of the Module |
122+
| `Module` | `LoaderAllocator` | LoaderAllocator of the Module |
123+
| `Module` | `ThunkHeap` | Pointer to the thunk heap |
124+
| `Module` | `DynamicMetadata` | Pointer to saved metadata for reflection emit modules |
125+
| `Module` | `FieldDefToDescMap` | Mapping table |
126+
| `Module` | `ManifestModuleReferencesMap` | Mapping table |
127+
| `Module` | `MemberRefToDescMap` | Mapping table |
128+
| `Module` | `MethodDefToDescMap` | Mapping table |
129+
| `Module` | `TypeDefToMethodTableMap` | Mapping table |
130+
| `Module` | `TypeRefToMethodTableMap` | Mapping table |
131+
| `DynamicMetadata` | `Size` | Size of the dynamic metadata blob (as a 32bit uint) |
132+
| `DynamicMetadata` | `Data` | Start of dynamic metadata data array |
46133

47134
``` csharp
48135
ModuleHandle GetModuleHandle(TargetPointer modulePointer)
@@ -94,6 +181,32 @@ TargetPointer GetMetadataAddress(ModuleHandle handle, out ulong size)
94181
return baseAddress + rva;
95182
}
96183

184+
AvailableMetadataType ILoader.GetAvailableMetadataType(ModuleHandle handle)
185+
{
186+
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
187+
188+
AvailableMetadataType flags = AvailableMetadataType.None;
189+
190+
TargetPointer dynamicMetadata = target.ReadPointer(handle.Address + /* Module::DynamicMetadata offset */);
191+
192+
if (dynamicMetadata != TargetPointer.Null)
193+
flags |= AvailableMetadataType.ReadWriteSavedCopy;
194+
else
195+
flags |= AvailableMetadataType.ReadOnly;
196+
197+
return flags;
198+
}
199+
200+
TargetPointer ILoader.GetReadWriteSavedMetadataAddress(ModuleHandle handle, out ulong size)
201+
{
202+
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
203+
TargetPointer dynamicMetadata = target.ReadPointer(handle.Address + /* Module::DynamicMetadata offset */);
204+
205+
size = target.Read<uint>(handle.Address + /* DynamicMetadata::Size offset */);
206+
TargetPointer result = handle.Address + /* DynamicMetadata::Data offset */;
207+
return result;
208+
}
209+
97210
ModuleLookupTables GetLookupTables(ModuleHandle handle)
98211
{
99212
return new ModuleLookupTables(

0 commit comments

Comments
 (0)