Skip to content

Commit d8c4bed

Browse files
committed
fix: Add compatibility with larger assemblies with varying heap index widths.
Fixes: #3
1 parent c531788 commit d8c4bed

File tree

13 files changed

+136
-56
lines changed

13 files changed

+136
-56
lines changed

CsharpFunctionDumper/CLRProcessing/MetaDataHeader.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public MetaDataHeader(AssemblyBuffer buffer, CLRHeader clrHeader, SectionsHeader
4949

5050
this.Streams[(uint)MetaDataStreamType.DEFS_AND_REFS] = new DefsAndRefsStream(buffer, clrHeader,this);
5151
this.Streams[(uint)MetaDataStreamType.STRINGS] = new StringStream(buffer, clrHeader);
52+
// These are boiler plate.
5253
this.Streams[(uint)MetaDataStreamType.US] = new StringStream(buffer, clrHeader);
5354
this.Streams[(uint)MetaDataStreamType.GUID] = new StringStream(buffer, clrHeader);
5455
this.Streams[(uint)MetaDataStreamType.BLOB] = new BlobStream(buffer, clrHeader);

CsharpFunctionDumper/CLRProcessing/MetaDataStreams/BlobStream.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,22 @@ namespace CsharpFunctionDumper.CLRProcessing.MetaDataStreams
1313
/// </summary>
1414
public class BlobStream : StreamHeader
1515
{
16-
public BlobStream(AssemblyBuffer buffer, CLRHeader clrHeader) : base(buffer, clrHeader)
16+
public BlobStream(AssemblyBuffer buffer, CLRHeader clrHeader) :
17+
base(buffer, clrHeader)
1718
{
1819
}
1920

2021
public uint GetSignatureAtOffset(uint offset)
2122
{
22-
return _cachedBuffer[offset];
23+
return CachedBuffer[offset];
2324
}
2425

2526
public MethodDefSignature GetMethodDefValue(uint signatureOffset)
2627
{
27-
_cachedAssemblyBuffer.SetIndexPointer(signatureOffset);
28+
CachedAssemblyBuffer.SetIndexPointer(signatureOffset);
2829

2930
MethodDefSignature signature = new MethodDefSignature();
30-
signature.PopulateFields(_cachedAssemblyBuffer);
31+
signature.PopulateFields(CachedAssemblyBuffer);
3132

3233
return signature;
3334
}

CsharpFunctionDumper/CLRProcessing/MetaDataStreams/DefsAndRefsStream.cs

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ public class DefsAndRefsStream : StreamHeader
3232

3333
public Dictionary<MetaDataTableType, List<TableRow>> TableRows { get; private set; }
3434

35-
public DefsAndRefsStream(AssemblyBuffer buffer, CLRHeader clrHeader, MetaDataHeader metaDataHeader) : base(
36-
buffer, clrHeader)
35+
public DefsAndRefsStream(AssemblyBuffer buffer, CLRHeader clrHeader, MetaDataHeader metaDataHeader) :
36+
base(buffer, clrHeader)
3737
{
3838
this._metaDataHeader = metaDataHeader;
3939
this.TableLengths = new uint[64];
@@ -47,14 +47,43 @@ public static DefsAndRefsStream GetInstance()
4747
return Instance;
4848
}
4949

50+
public uint ReadBlobOffset(AssemblyBuffer buffer)
51+
{
52+
if ((this.HeapOffsetSizes & (byte)HeapOffsetSize.BlobTableIndexOversize) != 0)
53+
{
54+
return buffer.ReadDWord();
55+
}
56+
57+
return buffer.ReadWord();
58+
}
59+
60+
public uint ReadStringOffset(AssemblyBuffer buffer)
61+
{
62+
if ((this.HeapOffsetSizes & (byte)HeapOffsetSize.StringTableIndexOversize) != 0)
63+
{
64+
return buffer.ReadDWord();
65+
}
66+
67+
return buffer.ReadWord();
68+
}
69+
70+
public uint ReadGuidOffset(AssemblyBuffer buffer)
71+
{
72+
if ((this.HeapOffsetSizes & (byte)HeapOffsetSize.GuidTableIndexOversize) != 0)
73+
{
74+
return buffer.ReadDWord();
75+
}
76+
77+
return buffer.ReadWord();
78+
}
79+
5080
public override void ProcessTables(AssemblyBuffer buffer)
5181
{
5282
buffer.SetIndexPointer(this.AbsoluteAddress);
5383
uint val = buffer.ReadDWord(); // Reserved.
5484
byte major = buffer.ReadByte(); // Major and minor version
5585
byte minor = buffer.ReadByte(); // Major and minor version
56-
this.HeapOffsetSizes =
57-
buffer.ReadByte(); // Bit flags for the heap index width. Ref: https://www.codeproject.com/Articles/12585/The-NET-File-Format
86+
this.HeapOffsetSizes = buffer.ReadByte(); // Bit flags for the heap index width. Ref: https://www.codeproject.com/Articles/12585/The-NET-File-Format
5887

5988
buffer.ReadByte(); // Padding byte.
6089

@@ -82,7 +111,8 @@ public override void ProcessTables(AssemblyBuffer buffer)
82111

83112
private MetaDataTableType GetMetaTableTypeFromType(Type type)
84113
{
85-
return (MetaDataTableType) type.GetField("OwnerTable", BindingFlags.Static | BindingFlags.Public)
114+
return (MetaDataTableType) type
115+
.GetField("OwnerTable", BindingFlags.Static | BindingFlags.Public)
86116
.GetValue(null);
87117
}
88118

@@ -114,6 +144,7 @@ private void PopulateTableRows(AssemblyBuffer buffer)
114144
MetaDataTableType tableType = (MetaDataTableType) idx;
115145
// These weren't valid in the present DWORD.
116146
if (this.TableLengths[idx] == 0) continue;
147+
117148
if (!this.TableRowTypes.ContainsKey(tableType))
118149
{
119150
Console.WriteLine($"WARNING: NO TYPE HANDLER FOR: {tableType.ToString()}");
@@ -141,19 +172,29 @@ private void PopulateTableRows(AssemblyBuffer buffer)
141172
}
142173
}
143174

144-
public List<MethodTableRow> GetMethodTableRowsFromOffset(int offset)
175+
private uint ResolveEndOfMethodList(int idxInTableRows)
145176
{
146-
List<MethodTableRow> methodTableRows = new List<MethodTableRow>();
147-
List<TableRow> tableRows = this.TableRows[MetaDataTableType.MethodDef];
148-
int currentOffset = offset;
149-
methodTableRows.Add((MethodTableRow) tableRows[currentOffset]);
150-
currentOffset++;
177+
var typeDefRows = this.TableRows[MetaDataTableType.TypeDef];
178+
var methodDefRows = this.TableRows[MetaDataTableType.MethodDef];
179+
TypeDefTableRow row = (TypeDefTableRow)typeDefRows[idxInTableRows];
180+
//Console.WriteLine($"{idxInTableRows + 1 >= typeDefRows.Count}: {(uint)methodDefRows.Count - 1} {((TypeDefTableRow) typeDefRows[idxInTableRows + 1])?.MethodList}");
181+
return idxInTableRows + 1 >= typeDefRows.Count
182+
? (uint)methodDefRows.Count - 1
183+
: ((TypeDefTableRow) typeDefRows[idxInTableRows + 1]).MethodList;
184+
}
151185

152-
while (true)
153-
{
154-
if (currentOffset >= tableRows.Count) break;
155-
MethodTableRow methodTableRow = (MethodTableRow) tableRows[currentOffset];
156-
if (methodTableRow.Name == ".ctor") break;
186+
public List<MethodTableRow> GetMethodTableRowsFromTypeDef(TypeDefTableRow typeDef)
187+
{
188+
int posInTableRows = this.TableRows[MetaDataTableType.TypeDef].FindIndex((x)=> x == typeDef);
189+
190+
List<MethodTableRow> methodTableRows = new List<MethodTableRow>();
191+
List<TableRow> methodRows = this.TableRows[MetaDataTableType.MethodDef];
192+
193+
int currentOffset = typeDef.MethodList - 1;
194+
int endOfList = (int)ResolveEndOfMethodList(posInTableRows) - 1;
195+
int deltaMethodList = endOfList - currentOffset;
196+
for(int i =0; i < deltaMethodList ; i++){
197+
MethodTableRow methodTableRow = (MethodTableRow) methodRows[currentOffset];
157198
methodTableRows.Add(methodTableRow);
158199
currentOffset++;
159200
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace CsharpFunctionDumper.CLRProcessing.MetaDataStreams
2+
{
3+
/// <summary>
4+
/// This is the size displayed in the Stream headers,
5+
/// It's representative of "HeapOffsetSize".
6+
/// </summary>
7+
public enum HeapIndexSize
8+
{
9+
WORD,
10+
DWORD
11+
}
12+
}

CsharpFunctionDumper/CLRProcessing/MetaDataStreams/StreamHeader.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ public abstract class StreamHeader
1212

1313
public uint AbsoluteAddress { get; private set; }
1414

15-
protected byte[] _cachedBuffer { get; private set; }
16-
17-
protected AssemblyBuffer _cachedAssemblyBuffer { get; private set; }
15+
protected byte[] CachedBuffer { get; private set; }
1816

17+
protected AssemblyBuffer CachedAssemblyBuffer { get; private set; }
18+
1919

2020
public StreamHeader(AssemblyBuffer buffer, CLRHeader clrHeader)
2121
{
@@ -30,9 +30,9 @@ public StreamHeader(AssemblyBuffer buffer, CLRHeader clrHeader)
3030
public void CacheBuffer(AssemblyBuffer buffer)
3131
{
3232
buffer.SetIndexPointer(this.AbsoluteAddress);
33-
this._cachedBuffer = new byte[this.Size];
34-
this._cachedBuffer = buffer.ReadBytes(this.Size);
35-
this._cachedAssemblyBuffer = new AssemblyBuffer("", this._cachedBuffer);
33+
this.CachedBuffer = new byte[this.Size];
34+
this.CachedBuffer = buffer.ReadBytes(this.Size);
35+
this.CachedAssemblyBuffer = new AssemblyBuffer("", this.CachedBuffer);
3636
}
3737

3838

CsharpFunctionDumper/CLRProcessing/MetaDataStreams/StringStream.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ namespace CsharpFunctionDumper.CLRProcessing.MetaDataStreams
55
public class StringStream : StreamHeader
66
{
77

8-
public StringStream(AssemblyBuffer buffer, CLRHeader clrHeader) : base(buffer,clrHeader)
8+
public StringStream(AssemblyBuffer buffer, CLRHeader clrHeader) :
9+
base(buffer, clrHeader)
910
{
1011
}
1112

@@ -17,7 +18,7 @@ public string ReadUntilNull(uint startOffset)
1718
byte val;
1819
while(true)
1920
{
20-
val = this._cachedBuffer[startOffset];
21+
val = this.CachedBuffer[startOffset];
2122

2223
if (val == 0x0)
2324
{

CsharpFunctionDumper/CLRProcessing/MetaDataStreams/TableRows/FieldTableRow.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ public class FieldTableRow : TableRow
66
{
77
public static MetaDataTableType OwnerTable = MetaDataTableType.Field;
88

9-
public ushort NameAddress { get; private set; }
9+
public uint NameAddress { get; private set; }
1010

1111
public string Name { get; private set; }
1212

1313
public ushort Flags { get; private set; }
1414

15-
public ushort Signature { get; private set; }
15+
public uint Signature { get; private set; }
1616

1717

1818
public FieldTableRow(AssemblyBuffer buffer) : base(buffer)
@@ -22,8 +22,8 @@ public FieldTableRow(AssemblyBuffer buffer) : base(buffer)
2222
public override void Read(AssemblyBuffer buffer)
2323
{
2424
this.Flags = buffer.ReadWord();
25-
this.NameAddress = buffer.ReadWord();
26-
this.Signature = buffer.ReadWord();
25+
this.NameAddress = this.ReadStringTableOffset(buffer);
26+
this.Signature = this.ReadBlobTableOffset(buffer);
2727

2828
this.Name = this.ReadStringAtOffset(this.NameAddress);
2929
}

CsharpFunctionDumper/CLRProcessing/MetaDataStreams/TableRows/MethodTableRow.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ public class MethodTableRow : TableRow
1212
public uint RVA { get; private set; }
1313
public ushort ImplementationFlags { get; private set; }
1414
public ushort DefinitionFlags { get; private set; }
15-
public ushort NameAddress { get; private set; }
16-
public ushort Signature { get; private set; }
15+
public uint NameAddress { get; private set; }
16+
public uint Signature { get; private set; }
1717
public ushort ParamsListIndex { get; private set; }
1818
public string Name { get; private set; }
1919

@@ -28,8 +28,8 @@ public override void Read(AssemblyBuffer buffer)
2828
this.RVA = buffer.ReadDWord();
2929
this.ImplementationFlags = buffer.ReadWord();
3030
this.DefinitionFlags = buffer.ReadWord();
31-
this.NameAddress = buffer.ReadWord();
32-
this.Signature = buffer.ReadWord();
31+
this.NameAddress = this.ReadStringTableOffset(buffer);
32+
this.Signature = this.ReadBlobTableOffset(buffer);
3333
this.ParamsListIndex = buffer.ReadWord();
3434

3535
this.Name = this.ReadStringAtOffset(this.NameAddress);
@@ -61,13 +61,15 @@ public override string Display()
6161
{
6262
StringBuilder funcDef = new StringBuilder();
6363
funcDef.Append($"func {this.Name}(");
64+
6465
DefsAndRefsStream defsAndRefsStream = DefsAndRefsStream.GetInstance();
6566
List<ParamTableRow> paramTableRows = defsAndRefsStream.GetParameterTableRowsFromOffset(this.ParamsListIndex);
67+
6668
MethodDefSignature method = this.GetBlobStream().GetMethodDefValue(this.Signature);
69+
6770
for (var i = 0; i < paramTableRows.Count; i++)
6871
{
6972
ParamTableRow paramTableRow = paramTableRows[i];
70-
7173

7274
if (i < method.ParameterTypes.Count)
7375
{

CsharpFunctionDumper/CLRProcessing/MetaDataStreams/TableRows/ModuleTableRow.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ namespace CsharpFunctionDumper.CLRProcessing.MetaDataStreams.TableRows
55
public class ModuleTableRow : TableRow
66
{
77
public ushort Generation { get; private set; }
8-
public ushort NameAddress { get; private set; }
9-
public ushort MvId { get; private set; }
10-
public ushort EncId { get; private set; }
11-
public ushort EncBaseId { get; private set; }
8+
public uint NameAddress { get; private set; }
9+
public uint MvId { get; private set; }
10+
public uint EncId { get; private set; }
11+
public uint EncBaseId { get; private set; }
1212

1313
public string Name { get; private set; }
1414

@@ -21,10 +21,10 @@ public ModuleTableRow(AssemblyBuffer buffer) : base(buffer)
2121
public override void Read(AssemblyBuffer buffer)
2222
{
2323
this.Generation = buffer.ReadWord();
24-
this.NameAddress = buffer.ReadWord();
25-
this.MvId = buffer.ReadWord();
26-
this.EncId = buffer.ReadWord();
27-
this.EncBaseId = buffer.ReadWord();
24+
this.NameAddress = this.ReadStringTableOffset(buffer);
25+
this.MvId = this.ReadGuidOffset(buffer);
26+
this.EncId = this.ReadGuidOffset(buffer);
27+
this.EncBaseId = this.ReadGuidOffset(buffer);
2828
this.Name = this.ReadStringAtOffset(this.NameAddress);
2929
}
3030

CsharpFunctionDumper/CLRProcessing/MetaDataStreams/TableRows/ParamTableRow.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public class ParamTableRow : TableRow
1010

1111
public ushort Flags { get; private set; }
1212
public ushort Sequence { get; private set; }
13-
public ushort NameAddresss { get; private set; }
13+
public uint NameAddresss { get; private set; }
1414
public string Name { get; private set; }
1515

1616

@@ -22,7 +22,7 @@ public override void Read(AssemblyBuffer buffer)
2222
{
2323
this.Flags = buffer.ReadWord();
2424
this.Sequence = buffer.ReadWord();
25-
this.NameAddresss = buffer.ReadWord();
25+
this.NameAddresss = this.ReadStringTableOffset(buffer);
2626
this.Name = this.ReadStringAtOffset(this.NameAddresss);
2727
}
2828

0 commit comments

Comments
 (0)