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 ;
45using 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
89namespace 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}
0 commit comments