Skip to content

Commit 64b6a79

Browse files
author
Max Charlamb
committed
simplify PEDecoder using PEReader
1 parent 1c4606e commit 64b6a79

File tree

3 files changed

+83
-251
lines changed

3 files changed

+83
-251
lines changed
Lines changed: 77 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,87 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System;
45
using System.IO;
5-
using Microsoft.Diagnostics.DataContractReader.Decoder.PETypes;
6-
using Microsoft.Diagnostics.DataContractReader.Legacy;
6+
using System.Reflection.PortableExecutable;
7+
using System.Text;
78

89
namespace Microsoft.Diagnostics.DataContractReader.Decoder;
9-
internal sealed class PEDecoder
10+
11+
internal sealed class PEDecoder : IDisposable
1012
{
11-
private readonly ICLRDataTarget _dataTarget;
12-
private readonly ulong _baseAddress;
13-
private uint _peSigOffset;
14-
private ushort _optHeaderMagic;
13+
private struct IMAGE_EXPORT_DIRECTORY
14+
{
15+
public uint Characteristics;
16+
public uint TimeDateStamp;
17+
public ushort MajorVersion;
18+
public ushort MinorVersion;
19+
public uint Name;
20+
public uint Base;
21+
public uint NumberOfFunctions;
22+
public uint NumberOfNames;
23+
public uint AddressOfFunctions;
24+
public uint AddressOfNames;
25+
public uint AddressOfNameOrdinals;
26+
27+
public IMAGE_EXPORT_DIRECTORY(BinaryReader reader)
28+
{
29+
Characteristics = reader.ReadUInt32();
30+
TimeDateStamp = reader.ReadUInt32();
31+
MajorVersion = reader.ReadUInt16();
32+
MinorVersion = reader.ReadUInt16();
33+
Name = reader.ReadUInt32();
34+
Base = reader.ReadUInt32();
35+
NumberOfFunctions = reader.ReadUInt32();
36+
NumberOfNames = reader.ReadUInt32();
37+
AddressOfFunctions = reader.ReadUInt32();
38+
AddressOfNames = reader.ReadUInt32();
39+
AddressOfNameOrdinals = reader.ReadUInt32();
40+
}
41+
}
42+
43+
private readonly Stream _stream;
1544
private IMAGE_EXPORT_DIRECTORY _exportDir;
45+
private bool _disposed;
1646

1747
public bool IsValid { get; init; }
1848

19-
public PEDecoder(ICLRDataTarget dataTarget, ulong baseAddress)
49+
/// <summary>
50+
/// Create PEDecoder with stream beginning at the base address of the module.
51+
/// </summary>
52+
public PEDecoder(Stream stream)
2053
{
21-
_dataTarget = dataTarget;
22-
_baseAddress = baseAddress;
54+
_stream = stream;
2355

2456
IsValid = Initialize();
2557
}
2658

2759
private bool Initialize()
2860
{
29-
using BinaryReader reader = new(new DataTargetStream(_dataTarget, _baseAddress));
61+
using PEReader peReader = new(_stream, PEStreamOptions.LeaveOpen);
3062

31-
ushort dosMagic = reader.ReadUInt16();
32-
if (dosMagic != 0x5A4D) // "MZ"
33-
return false;
34-
35-
// PE Header offset is at 0x3C in DOS header
36-
reader.BaseStream.Seek(0x3C, SeekOrigin.Begin);
37-
_peSigOffset = reader.ReadUInt32();
38-
39-
// Read PE signature
40-
reader.BaseStream.Seek(_peSigOffset, SeekOrigin.Begin);
41-
uint peSig = reader.ReadUInt32();
42-
if (peSig != 0x00004550) // "PE00"
43-
return false;
44-
45-
// Seek to beginning of opt header and read magic
46-
reader.BaseStream.Seek(_peSigOffset + 0x18, SeekOrigin.Begin);
47-
_optHeaderMagic = reader.ReadUInt16();
48-
49-
// Seek back to beginning of opt header and parse
50-
reader.BaseStream.Seek(_peSigOffset + 0x18, SeekOrigin.Begin);
51-
uint rva;
52-
switch (_optHeaderMagic)
63+
PEHeader? peHeader = peReader.PEHeaders.PEHeader;
64+
if (peHeader is null)
5365
{
54-
case 0x10B: // PE32
55-
IMAGE_OPTIONAL_HEADER32 optHeader32 = new(reader);
56-
rva = optHeader32.DataDirectory[0].VirtualAddress;
57-
break;
58-
case 0x20B: // PE32+
59-
IMAGE_OPTIONAL_HEADER64 optHeader64 = new(reader);
60-
rva = optHeader64.DataDirectory[0].VirtualAddress;
61-
break;
62-
// unknown type, invalid
63-
default:
64-
return false;
66+
// If PEHeader is null, then the file is not a valid PE file.
67+
return false;
6568
}
69+
DirectoryEntry exportsDirectory = peHeader.ExportTableDirectory;
6670

67-
// Seek to export directory and parse
68-
reader.BaseStream.Seek(rva, SeekOrigin.Begin);
71+
_stream.Seek(exportsDirectory.RelativeVirtualAddress, SeekOrigin.Begin);
72+
using BinaryReader reader = new(_stream, Encoding.UTF8, leaveOpen: true);
6973
_exportDir = new IMAGE_EXPORT_DIRECTORY(reader);
7074

7175
return true;
7276
}
7377

74-
public TargetPointer GetSymbolAddress(string symbol)
78+
public bool TryGetRelativeSymbolAddress(string symbol, out ulong address)
7579
{
80+
address = 0;
7681
if (!IsValid)
77-
return TargetPointer.Null;
82+
return false;
7883

79-
using BinaryReader reader = new(new DataTargetStream(_dataTarget, _baseAddress));
84+
using BinaryReader reader = new(_stream, Encoding.UTF8, leaveOpen: true);
8085

8186
for (int nameIndex = 0; nameIndex < _exportDir.NumberOfNames; nameIndex++)
8287
{
@@ -99,10 +104,31 @@ public TargetPointer GetSymbolAddress(string symbol)
99104
reader.BaseStream.Seek(_exportDir.AddressOfFunctions + sizeof(uint) * ordinalForNamedExport, SeekOrigin.Begin);
100105
uint symbolRVA = reader.ReadUInt32();
101106

102-
return new TargetPointer(_baseAddress + symbolRVA);
107+
address = symbolRVA;
108+
return true;
109+
}
110+
}
111+
112+
return false;
113+
}
114+
115+
private void Dispose(bool disposing)
116+
{
117+
if (!_disposed)
118+
{
119+
if (disposing)
120+
{
121+
_stream.Dispose();
103122
}
123+
124+
_disposed = true;
104125
}
126+
}
105127

106-
return TargetPointer.Null;
128+
void IDisposable.Dispose()
129+
{
130+
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
131+
Dispose(disposing: true);
132+
GC.SuppressFinalize(this);
107133
}
108134
}

src/native/managed/cdacreader/src/Decoder/PETypes.cs

Lines changed: 0 additions & 197 deletions
This file was deleted.

src/native/managed/cdacreader/src/Entrypoints.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,12 @@ private static unsafe int CLRDataCreateInstance(Guid* pIID, IntPtr /*ICLRDataTar
8787
dataTarget.GetImageBase("coreclr.dll", &baseAddress);
8888
}
8989

90-
91-
PEDecoder peDecoder = new(dataTarget, baseAddress);
92-
ulong contractDescriptor = peDecoder.GetSymbolAddress("DotNetRuntimeContractDescriptor");
90+
DataTargetStream dataTargetStream = new(dataTarget, baseAddress);
91+
using PEDecoder peDecoder = new(dataTargetStream);
92+
if (!peDecoder.TryGetRelativeSymbolAddress("DotNetRuntimeContractDescriptor", out ulong contractDescriptor))
93+
{
94+
return -1;
95+
}
9396

9497
if (!ContractDescriptorTarget.TryCreate(contractDescriptor, (address, buffer) =>
9598
{

0 commit comments

Comments
 (0)