├── README.md
├── src
├── StackParser
│ ├── msdia140.dll
│ ├── Microsoft.Deployment.Compression.dll
│ ├── Microsoft.Deployment.Compression.Cab.dll
│ ├── App.config
│ ├── CabUnpacker.cs
│ ├── StackParser.csproj
│ ├── SymStore.cs
│ ├── Program.cs
│ ├── DiaHelper.cs
│ └── PEReader.cs
├── performance
│ └── perfcollect
│ │ └── README.md
├── dir.props
├── .nuget
│ └── packages.Windows_NT.config
├── reliability
│ └── README.md
├── BuildValues.props
├── NuGet.Config
├── dir.targets
└── dirs.proj
├── CONTRIBUTING.md
├── CODE-OF-CONDUCT.md
├── SECURITY.md
├── LICENSE
├── .gitattributes
├── .gitignore
├── dir.traversal.targets
├── dir.targets
└── dir.props
/README.md:
--------------------------------------------------------------------------------
1 | # corefx-tools
2 | Place to include various misc tools for .NET and .NET Core.
3 |
--------------------------------------------------------------------------------
/src/StackParser/msdia140.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dotnet/corefx-tools/HEAD/src/StackParser/msdia140.dll
--------------------------------------------------------------------------------
/src/performance/perfcollect/README.md:
--------------------------------------------------------------------------------
1 | Perfcollect has moved to https://github.com/microsoft/perfview/tree/master/src/perfcollect.
2 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Information on contributing is in the [Contributing Guide](https://github.com/dotnet/corefx/wiki/Contributing).
4 |
--------------------------------------------------------------------------------
/src/StackParser/Microsoft.Deployment.Compression.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dotnet/corefx-tools/HEAD/src/StackParser/Microsoft.Deployment.Compression.dll
--------------------------------------------------------------------------------
/src/StackParser/Microsoft.Deployment.Compression.Cab.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dotnet/corefx-tools/HEAD/src/StackParser/Microsoft.Deployment.Compression.Cab.dll
--------------------------------------------------------------------------------
/src/dir.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/StackParser/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/.nuget/packages.Windows_NT.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/reliability/README.md:
--------------------------------------------------------------------------------
1 | #This code has moved
2 |
3 | The code for .NET reliability and stress tooling has moved to its own git hub repo. To view the code download or contribute please visit the [dotnet-reliability](https://github.com/Microsoft/dotnet-reliability) repo.
--------------------------------------------------------------------------------
/CODE-OF-CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Code of Conduct
2 |
3 | This project has adopted the code of conduct defined by the Contributor Covenant
4 | to clarify expected behavior in our community.
5 |
6 | For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).
7 |
--------------------------------------------------------------------------------
/src/BuildValues.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 | 00001
12 |
13 |
--------------------------------------------------------------------------------
/src/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Supported Versions
4 |
5 | The .NET Core and ASP.NET Core support policy, including supported versions can be found at the [.NET Core Support Policy Page](https://dotnet.microsoft.com/platform/support/policy/dotnet-core).
6 |
7 | ## Reporting a Vulnerability
8 |
9 | Security issues and bugs should be reported privately to the Microsoft Security Response Center (MSRC), either by emailing secure@microsoft.com or via the portal at https://msrc.microsoft.com.
10 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your
11 | original message. Further information, including the MSRC PGP key, can be found in the [MSRC Report an Issue FAQ](https://www.microsoft.com/en-us/msrc/faqs-report-an-issue).
12 |
13 | Reports via MSRC may qualify for the .NET Core Bug Bounty. Details of the .NET Core Bug Bounty including terms and conditions are at [https://aka.ms/corebounty](https://aka.ms/corebounty).
14 |
15 | Please do not open issues for anything you think might have a security implication.
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Microsoft Corporation
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/dir.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 |
5 |
6 |
7 |
8 |
10 |
12 |
13 |
15 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/dirs.proj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | $(TraversalBuildDependsOn);
21 | BuildPackages;
22 |
23 |
24 |
25 |
26 | true
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/src/StackParser/CabUnpacker.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Deployment.Compression;
2 | using Microsoft.Deployment.Compression.Cab;
3 | using System;
4 | using System.Diagnostics;
5 | using System.IO;
6 |
7 | namespace StackParser
8 | {
9 | public static class CabUnpacker
10 | {
11 | public static Stream Unpack(Stream compressedStream)
12 | {
13 | CabEngine cabEngine = new CabEngine();
14 | InMemoryUnpackContext unpackContext = new InMemoryUnpackContext(compressedStream);
15 | cabEngine.Unpack(unpackContext, suffix => true);
16 | Stream s = unpackContext.UncompressedStream;
17 | s.Seek(0, SeekOrigin.Begin);
18 | return s;
19 | }
20 |
21 | class InMemoryUnpackContext : IUnpackStreamContext
22 | {
23 | public InMemoryUnpackContext(Stream compressedStream)
24 | {
25 | // The stream isn't always seekable and we need to be able to seek to decompress the
26 | // file. We solve this by copying all the data into a memory buffer that is seekable.
27 | // This copy is unfortunate for large files and could be improved if performance
28 | // analysis indicated a problem.
29 | if (!compressedStream.CanSeek)
30 | {
31 | _compressedStream = new MemoryStream();
32 | compressedStream.CopyTo(_compressedStream);
33 | }
34 | else
35 | {
36 | _compressedStream = compressedStream;
37 | }
38 | }
39 | Stream _compressedStream;
40 | MemoryStream _uncompressedStream = new MemoryStream();
41 |
42 | public void CloseArchiveReadStream(int archiveNumber, string archiveName, Stream stream)
43 | {
44 | Debug.Assert(stream == _compressedStream);
45 | }
46 |
47 | public void CloseFileWriteStream(string path, Stream stream, FileAttributes attributes, DateTime lastWriteTime)
48 | {
49 | Debug.Assert(stream == _uncompressedStream);
50 | }
51 |
52 | public Stream OpenArchiveReadStream(int archiveNumber, string archiveName, CompressionEngine compressionEngine)
53 | {
54 | _compressedStream.Seek(0, SeekOrigin.Begin);
55 | return _compressedStream;
56 | }
57 |
58 | public Stream OpenFileWriteStream(string path, long fileSize, DateTime lastWriteTime)
59 | {
60 | return _uncompressedStream;
61 | }
62 |
63 | public MemoryStream UncompressedStream { get { return _uncompressedStream; } }
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/StackParser/StackParser.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Debug
9 | AnyCPU
10 | {33E61B41-5C47-40B5-B90F-F588AA8E459E}
11 | Exe
12 | Properties
13 | StackParser
14 | StackParser
15 | v4.5
16 | 512
17 |
18 |
19 | AnyCPU
20 | true
21 | full
22 | false
23 | bin\Debug\
24 | DEBUG;TRACE
25 | prompt
26 | 4
27 |
28 |
29 | AnyCPU
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 |
39 |
40 | .\Microsoft.Deployment.Compression.dll
41 |
42 |
43 | .\Microsoft.Deployment.Compression.Cab.dll
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | PreserveNewest
66 |
67 |
68 |
69 |
76 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | syntax: glob
2 |
3 | ### VisualStudio ###
4 | #nuget lock files
5 | project.lock.json
6 |
7 | # User-specific files
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 | .vs
13 |
14 | # Build results
15 | [Dd]ebug/
16 | [Dd]ebugPublic/
17 | [Rr]elease/
18 | [Rr]eleases/
19 | x64/
20 | x86/
21 | build/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | msbuild.log
26 |
27 | # Roslyn stuff
28 | *.sln.ide
29 | *.ide/
30 |
31 | # MSTest test Results
32 | [Tt]est[Rr]esult*/
33 | [Bb]uild[Ll]og.*
34 |
35 | #NUNIT
36 | *.VisualState.xml
37 | TestResult.xml
38 |
39 | # Build Results of an ATL Project
40 | [Dd]ebugPS/
41 | [Rr]eleasePS/
42 | dlldata.c
43 |
44 | *_i.c
45 | *_p.c
46 | *_i.h
47 | *.ilk
48 | *.meta
49 | *.obj
50 | *.pch
51 | *.pdb
52 | *.pgc
53 | *.pgd
54 | *.rsp
55 | *.sbr
56 | *.tlb
57 | *.tli
58 | *.tlh
59 | *.tmp
60 | *.tmp_proj
61 | *.log
62 | *.vspscc
63 | *.vssscc
64 | .builds
65 | *.pidb
66 | *.svclog
67 | *.scc
68 |
69 | # Chutzpah Test files
70 | _Chutzpah*
71 |
72 | # Visual C++ cache files
73 | ipch/
74 | *.aps
75 | *.ncb
76 | *.opensdf
77 | *.sdf
78 | *.cachefile
79 |
80 | # Visual Studio profiler
81 | *.psess
82 | *.vsp
83 | *.vspx
84 |
85 | # TFS 2012 Local Workspace
86 | $tf/
87 |
88 | # Guidance Automation Toolkit
89 | *.gpState
90 |
91 | # ReSharper is a .NET coding add-in
92 | _ReSharper*/
93 | *.[Rr]e[Ss]harper
94 | *.DotSettings.user
95 |
96 | # JustCode is a .NET coding addin-in
97 | .JustCode
98 |
99 | # TeamCity is a build add-in
100 | _TeamCity*
101 |
102 | # DotCover is a Code Coverage Tool
103 | *.dotCover
104 |
105 | # NCrunch
106 | _NCrunch_*
107 | .*crunch*.local.xml
108 |
109 | # MightyMoose
110 | *.mm.*
111 | AutoTest.Net/
112 |
113 | # Web workbench (sass)
114 | .sass-cache/
115 |
116 | # Installshield output folder
117 | [Ee]xpress/
118 |
119 | # DocProject is a documentation generator add-in
120 | DocProject/buildhelp/
121 | DocProject/Help/*.HxT
122 | DocProject/Help/*.HxC
123 | DocProject/Help/*.hhc
124 | DocProject/Help/*.hhk
125 | DocProject/Help/*.hhp
126 | DocProject/Help/Html2
127 | DocProject/Help/html
128 |
129 | # Click-Once directory
130 | publish/
131 |
132 | # Publish Web Output
133 | *.[Pp]ublish.xml
134 | *.azurePubxml
135 | *.pubxml
136 | *.publishproj
137 |
138 | # NuGet Packages
139 | *.nupkg
140 | **/packages/*
141 |
142 | # Windows Azure Build Output
143 | csx/
144 | *.build.csdef
145 |
146 | # Windows Store app package directory
147 | AppPackages/
148 |
149 | # Others
150 | sql/
151 | *.Cache
152 | ClientBin/
153 | [Ss]tyle[Cc]op.*
154 | ~$*
155 | *.dbmdl
156 | *.dbproj.schemaview
157 | *.pfx
158 | *.publishsettings
159 | node_modules/
160 | *.metaproj
161 | *.metaproj.tmp
162 |
163 | # RIA/Silverlight projects
164 | Generated_Code/
165 |
166 | # Backup & report files from converting an old project file
167 | # to a newer Visual Studio version. Backup files are not needed,
168 | # because we have git ;-)
169 | _UpgradeReport_Files/
170 | Backup*/
171 | UpgradeLog*.XML
172 | UpgradeLog*.htm
173 |
174 | # SQL Server files
175 | *.mdf
176 | *.ldf
177 |
178 | # Business Intelligence projects
179 | *.rdl.data
180 | *.bim.layout
181 | *.bim_*.settings
182 |
183 | # Microsoft Fakes
184 | FakesAssemblies/
185 |
186 | ### MonoDevelop ###
187 |
188 | *.pidb
189 | *.userprefs
190 |
191 | ### Windows ###
192 |
193 | # Windows image file caches
194 | Thumbs.db
195 | ehthumbs.db
196 |
197 | # Folder config file
198 | Desktop.ini
199 |
200 | # Recycle Bin used on file shares
201 | $RECYCLE.BIN/
202 |
203 | # Windows Installer files
204 | *.cab
205 | *.msi
206 | *.msm
207 | *.msp
208 |
209 | # Windows shortcuts
210 | *.lnk
211 |
212 | ### Linux ###
213 |
214 | *~
215 |
216 | # KDE directory preferences
217 | .directory
218 |
219 | ### OSX ###
220 |
221 | .DS_Store
222 | .AppleDouble
223 | .LSOverride
224 |
225 | # Icon must end with two \r
226 | Icon
227 |
228 | # Thumbnails
229 | ._*
230 |
231 | # Files that might appear on external disk
232 | .Spotlight-V100
233 | .Trashes
234 |
235 | # Directories potentially created on remote AFP share
236 | .AppleDB
237 | .AppleDesktop
238 | Network Trash Folder
239 | Temporary Items
240 | .apdisk
241 |
242 | # vim temporary files
243 | [._]*.s[a-w][a-z]
244 | [._]s[a-w][a-z]
245 | *.un~
246 | Session.vim
247 | .netrwhist
248 | *~
249 |
--------------------------------------------------------------------------------
/dir.traversal.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | $(MSBuildProjectDefaultTargets)
7 |
8 |
9 |
11 |
16 |
17 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | Clean
31 |
32 |
33 |
35 |
40 |
41 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | RestorePackages
57 |
58 |
59 |
61 |
66 |
67 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | BuildAllProjects;
81 | $(TraversalBuildDependsOn);
82 |
83 |
84 |
85 | CleanAllProjects;
86 | $(TraversalCleanDependsOn);
87 |
88 |
89 |
90 | RestoreAllProjectPackages;
91 | $(TraversalRestorePackagesDependsOn)
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/dir.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | maxTries)
37 | {
38 | throw;
39 | }
40 | else
41 | {
42 | Log.LogMessage(MessageImportance.High, "Download failed, retrying: {0}", e.Message);
43 | }
44 | }
45 | }
46 |
47 | try
48 | {
49 | if (!File.Exists(FileName))
50 | File.Move(tempFile, FileName);
51 | }
52 | finally
53 | {
54 | if (File.Exists(tempFile))
55 | File.Delete(tempFile);
56 | }
57 | ]]>
58 |
59 |
60 |
61 |
62 |
65 |
66 | $(ToolsDir)BuildTools.semaphore
67 |
68 |
69 |
73 |
74 |
75 |
78 |
79 |
80 |
81 |
82 |
83 |
86 |
87 |
89 |
90 |
91 | <_RestoreBuildToolsCommand>$(NugetRestoreCommand) "$(SourceDir).nuget/packages.$(OsEnvironment).config"
92 |
93 |
94 |
95 |
96 |
97 |
98 |
100 |
102 |
104 |
105 |
109 |
113 |
114 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/dir.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 | $(OS)
9 |
10 |
11 |
12 |
13 | 1.0.25-prerelease-00094
14 | 1.0.0-beta7
15 | dnx-coreclr-win-x86.$(DnxVersion)
16 | dnx-mono.$(DnxVersion)
17 | 1.0.0-rc3-20150510-01
18 | Microsoft.Net.ToolsetCompilers
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | True
27 |
28 |
29 |
30 |
31 |
32 | $(MSBuildThisFileDirectory)
33 | $(ProjectDir)src/
34 |
35 |
36 | $(ProjectDir)bin/
37 | $(BinDir)obj/
38 | $(BinDir)tests/
39 | $(BinDir)packages/
40 |
41 |
42 | $(ProjectDir)packages/
43 | $(PackagesDir)Microsoft.DotNet.BuildTools.$(BuildToolsVersion)/lib/
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | $(PackagesDir)NuGet.exe
55 | @(NuGetSourceList -> '-source %(Identity)', ' ')
56 | $(NuGetPackageSource)
57 |
58 | "$(NuGetToolPath)"
59 | $(NugetRestoreCommand) install
60 |
61 | $(NugetRestoreCommand) -OutputDirectory "$(PackagesDir.TrimEnd('/\'.ToCharArray()))"
62 | $(NugetRestoreCommand) $(NuGetConfigCommandLine)
63 | $(NugetRestoreCommand) -Verbosity detailed
64 | mono $(NuGetRestoreCommand)
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | $(PackagesDir)/$(DnxPackageName)/
86 | $(DnxPackageDir)\bin\dnu.cmd
87 | $(DnxPackageDir)/bin/dnu
88 |
89 | @(DnuSourceList -> '--source %(Identity)', ' ')
90 | @(DnuRestoreDir -> '%(Identity)', ' ')
91 |
92 | "$(DnuToolPath)"
93 | $(DnuRestoreCommand) restore
94 | $(DnuRestoreCommand) --parallel
95 | $(DnuRestoreCommand) --packages "$(PackagesDir.TrimEnd('/\'.ToCharArray()))" $(DnuRestoreSource)
96 | $(DnuRestoreCommand) --lock
97 |
98 |
99 |
100 |
101 | false
102 |
103 |
104 |
107 |
108 | $(PackagesDir)/$(RoslynPackageName).$(RoslynVersion)/
109 | $(RoslynPackageDir)build/Microsoft.Net.ToolsetCompilers.props
110 |
111 |
112 |
116 | false
117 | none
118 |
122 | false
123 |
124 |
125 |
126 |
130 | false
131 |
136 | true
137 |
138 |
139 |
149 |
150 |
151 |
152 | AnyCPU
153 |
154 | Debug
155 | Debug
156 | Release
157 | $(Configuration)
158 |
159 | Windows_NT
160 | Linux
161 | OSX
162 | FreeBSD
163 | Windows_NT
164 |
165 |
166 |
167 |
168 | true
169 | false
170 | full
171 | $(DefineConstants),DEBUG,TRACE
172 |
173 |
174 | true
175 | true
176 | pdbonly
177 | $(DefineConstants),TRACE
178 |
179 |
180 |
181 |
182 | true
183 | true
184 | false
185 | false
186 |
187 |
188 |
189 |
190 | 4
191 | true
192 |
193 |
194 |
195 |
196 | $(SourceDir)Common
197 |
198 |
199 |
200 |
201 | $(OSGroup).$(Platform).$(ConfigurationGroup)
202 |
203 | $(BinDir)
204 | $(BaseOutputPath)$(OSPlatformConfig)\$(MSBuildProjectName)\
205 |
206 | $(ObjDir)
207 | $(BaseIntermediateOutputPath)$(OSPlatformConfig)\
208 | $(IntermediateOutputRootPath)$(MSBuildProjectName)\
209 |
210 | $(TestWorkingDir)$(OSPlatformConfig)\$(MSBuildProjectName)\
211 |
212 | $(BinDir)$(OSPlatformConfig)
213 |
214 |
215 |
216 |
217 | true
218 | true
219 | true
220 | true
221 |
222 | true
223 |
224 |
225 |
226 |
229 | <_WindowsKitBinPath>$(MSBuildProgramFiles32)\Windows Kits\8.1\bin\x86
230 | <_WindowsPhoneKitBinPath>$(MSBuildProgramFiles32)\Windows Phone Kits\8.1\bin
231 | $(_WindowsKitBinPath)\makepri.exe
232 | $(_WindowsKitBinPath)\makeappx.exe
233 | $(_WindowsKitBinPath)\signtool.exe
234 | $(_WindowsPhoneKitBinPath)\x86\MrmEnvironmentExtDl.dll
235 | $(_WindowsPhoneKitBinPath)\x64\MrmEnvironmentExtDl.dll
236 |
237 |
238 |
240 |
241 |
242 |
243 |
245 |
246 |
247 |
--------------------------------------------------------------------------------
/src/StackParser/SymStore.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Net;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace StackParser
10 | {
11 | ///
12 | /// An extension that adds symbol server support to MDbg. Loading this extension will
13 | /// cause all paths in the symbol search path to get interpretted as symbol stores
14 | /// in addition to flat directories. Also paths that start with srv* will now be interpretted
15 | ///
16 | ///
17 | #if NotNow
18 | [MDbgExtensionEntryPointClass]
19 | public abstract class SrcSrvExtension : CommandBase
20 | {
21 | public static void LoadExtension()
22 | {
23 | m_symbolServerSearchTechnique = new SymbolServerSearchTechnique();
24 | Debugger.FileLocator.SearchTechniques.Add(m_symbolServerSearchTechnique);
25 | WriteOutput("SymbolSrv loaded");
26 | }
27 |
28 | public static void UnloadExtension()
29 | {
30 | Debugger.FileLocator.SearchTechniques.Remove(m_symbolServerSearchTechnique);
31 | WriteOutput("SymbolSrv unloaded");
32 | }
33 |
34 | private static SymbolServerSearchTechnique m_symbolServerSearchTechnique;
35 | }
36 |
37 | public class SymbolServerSearchTechnique : ISearchTechnique
38 | {
39 | public void Search(string searchPathEntry, FileSearchInfo searchInfo, FileSearchResult result)
40 | {
41 | if (searchPathEntry == FileLocator.FirstSearchEntry || searchPathEntry == FileLocator.LastSearchEntry)
42 | return;
43 | if (searchInfo.SearchKind == FileSearchInfo.FileSearchKind.Source)
44 | return;
45 |
46 | // don't search for ngen images on the symbol server, we won't find them
47 | if (searchInfo.Path.EndsWith(".ni.dll", StringComparison.OrdinalIgnoreCase))
48 | return;
49 |
50 | string fileName = Path.GetFileName(searchInfo.Path);
51 | string indexString = ComputeIndexString(searchInfo);
52 |
53 | SymStore store;
54 | if(searchPathEntry.StartsWith("srv*"))
55 | store = SymStore.FromPath(searchPathEntry);
56 | else
57 | store = SymStore.FromPath(@"srv**" + searchPathEntry);
58 | string filePath;
59 | if (store.TryGetFile(fileName, indexString, out filePath))
60 | result.CreateEntry(filePath);
61 | }
62 |
63 |
64 | private static string ComputeIndexString(FileSearchInfo searchInfo)
65 | {
66 | string indexString = null;
67 | if (searchInfo is SymbolFileSearchInfo)
68 | {
69 | SymbolFileSearchInfo symSearchInfo = (searchInfo as SymbolFileSearchInfo);
70 | indexString = symSearchInfo.Signature.ToString().Replace("-", "").ToUpper() +
71 | symSearchInfo.Age.ToString();
72 | }
73 | else if (searchInfo is BinaryFileSearchInfo)
74 | {
75 | BinaryFileSearchInfo binarySearchInfo = (searchInfo as BinaryFileSearchInfo);
76 | indexString = binarySearchInfo.Timestamp.ToString("x").Replace("-", "").ToUpper() +
77 | binarySearchInfo.Size.ToString("x");
78 | }
79 | return indexString;
80 | }
81 | }
82 | #endif
83 | public class SymStoreResult
84 | {
85 | public SymStoreResult()
86 | {
87 | MessageLog = new List();
88 | }
89 | public string CachedPath { get; set; }
90 | public string OriginalPath { get; set; }
91 | public List MessageLog { get; set; }
92 | }
93 |
94 | public abstract class SymStore
95 | {
96 | public static SymStore FromPath(string path)
97 | {
98 | List stores = new List();
99 | if (path != null)
100 | stores.AddRange(path.Split('*'));
101 |
102 | // if there is a leading srv*, remove it
103 | // even without the srv* we assume everything is a symstore
104 | if (stores.Count > 0 && stores[0] == "srv")
105 | stores.RemoveAt(0);
106 |
107 | return FromPathHelper(stores, stores.Count - 1, null);
108 | }
109 |
110 | private static SymStore FromPathHelper(List stores, int currentIndex, SymStore backingStore)
111 | {
112 | if (currentIndex == -1)
113 | return backingStore;
114 | string currentStorePath = RedirectStorePath(stores[currentIndex]);
115 | if (currentStorePath.StartsWith("http://") || currentStorePath.StartsWith("https://"))
116 | return FromPathHelper(stores, currentIndex - 1, new HttpSymStore(currentStorePath, backingStore));
117 | else
118 | return FromPathHelper(stores, currentIndex - 1, new UNCSymStore(currentStorePath, backingStore));
119 | }
120 |
121 | private static string RedirectStorePath(string storePath)
122 | {
123 | if (storePath == "") // default downstream store
124 | {
125 | return Path.Combine(Environment.CurrentDirectory, "sym");
126 | }
127 | else
128 | {
129 | try
130 | {
131 | if (!storePath.StartsWith("http:") && !storePath.StartsWith("https:"))
132 | {
133 | string pingMePath = Path.Combine(storePath, "pingme.txt");
134 | if (File.Exists(pingMePath))
135 | {
136 | string pingMeContents = File.ReadAllText(pingMePath);
137 | if (pingMeContents.StartsWith("STORE:"))
138 | return pingMeContents.Substring(6).TrimEnd('\n', '\r');
139 | }
140 | }
141 | }
142 | catch (IOException)
143 | {
144 | return storePath;
145 | }
146 | }
147 |
148 | return storePath;
149 | }
150 |
151 | protected SymStore(string path, SymStore backingStore)
152 | {
153 | if (!path.EndsWith("/"))
154 | path += "/";
155 | StoreRootAddress = new Uri(path);
156 | BackingStore = backingStore;
157 | }
158 |
159 | public bool TryGetFile(string fileName, string indexString, SymStoreResult result)
160 | {
161 | Stream unused;
162 | bool ret = TryGetFile(fileName, indexString, result, out unused);
163 | if (unused != null)
164 | unused.Dispose();
165 | return ret;
166 | }
167 |
168 | public bool TryGetFile(string fileName, string indexString, SymStoreResult result, out Stream fileData)
169 | {
170 | // try and get the file from this store
171 | if (TryGetFileLocal(fileName, indexString, result, out fileData))
172 | {
173 | return true;
174 | }
175 |
176 | // if there is backing store try getting it from there and cache it in this store
177 | if (BackingStore != null)
178 | {
179 | Stream backingFileData;
180 | if (BackingStore.TryGetFile(fileName, indexString, result, out backingFileData))
181 | {
182 | WriteFile(fileName, indexString, backingFileData);
183 | if (backingFileData != null)
184 | backingFileData.Dispose();
185 | if (TryGetFileLocal(fileName, indexString, result, out fileData))
186 | return true;
187 | }
188 | }
189 |
190 | // if nothing has worked yet, fail
191 | return false;
192 | }
193 |
194 | private bool TryGetFileLocal(string fileName, string indexString, SymStoreResult result, out Stream fileData)
195 | {
196 | fileData = null;
197 | string errorMessage = null;
198 | Uri request = new Uri(StoreRootAddress, fileName + "/" + indexString + "/" + fileName);
199 |
200 | //We could do better and actually calculate the backing path
201 | if (result.OriginalPath == null)
202 | result.OriginalPath = request.ToString();
203 |
204 | if (TryGetDataForUri(request, out fileData, out errorMessage))
205 | {
206 | result.CachedPath = request.AbsolutePath;
207 | result.MessageLog.Add("Retrieved " + request);
208 | return true;
209 | }
210 | else
211 | {
212 | result.MessageLog.Add(request.ToString() + " [" + errorMessage + "]");
213 | }
214 |
215 | string fileNameUnderBar = fileName.Substring(0, fileName.Length - 1) + "_";
216 | Uri requestUnderBar = new Uri(StoreRootAddress, fileName + "/" + indexString + "/" + fileNameUnderBar);
217 | Stream compressedFileData = null;
218 | if (TryGetDataForUri(requestUnderBar, out compressedFileData, out errorMessage))
219 | {
220 | fileData = CabUnpacker.Unpack(compressedFileData);
221 | result.CachedPath = requestUnderBar.AbsolutePath;
222 | result.MessageLog.Add("Retrieved " + requestUnderBar);
223 | return true;
224 | }
225 | else
226 | {
227 | result.MessageLog.Add(requestUnderBar.ToString() + " [" + errorMessage + "]");
228 | }
229 |
230 | Uri requestPtr = new Uri(StoreRootAddress, fileName + "/" + indexString + "/file.ptr");
231 | Stream ptrFileData;
232 | PtrFile ptr;
233 | if (!TryGetDataForUri(requestPtr, out ptrFileData, out errorMessage))
234 | {
235 | result.MessageLog.Add(requestPtr.ToString() + " [" + errorMessage + "]");
236 | return false;
237 | }
238 | else if (!PtrFile.TryParse(new StreamReader(ptrFileData).ReadToEnd(), out ptr))
239 | {
240 | result.MessageLog.Add(requestPtr.ToString() + " [Unable to parse]");
241 | return false;
242 | }
243 | else
244 | {
245 | result.MessageLog.Add(requestPtr.ToString() + " [Redirecting search]");
246 | result.MessageLog.Add(" Path: " + ptr.Path);
247 | if (!string.IsNullOrWhiteSpace(ptr.Message))
248 | {
249 | result.MessageLog.Add(" Msg: " + ptr.Message);
250 | }
251 | }
252 | try
253 | {
254 | fileData = File.OpenRead(ptr.Path);
255 | result.CachedPath = ptr.Path;
256 | }
257 | catch (IOException e)
258 | {
259 | result.MessageLog.Add(ptr.Path + " [" + e.ToString() + "]");
260 | return false;
261 | }
262 |
263 | return true;
264 | }
265 |
266 | protected string WriteFile(string fileName, string indexString, Stream fileData)
267 | {
268 | Uri request = new Uri(Path.Combine(StoreRootAddress.AbsolutePath, fileName + "\\" + indexString + "\\" + fileName));
269 | WriteFile(request, fileData);
270 | return request.AbsolutePath;
271 | }
272 |
273 | protected abstract bool TryGetDataForUri(Uri file, out Stream fileData, out string errorMessage);
274 | protected abstract void WriteFile(Uri file, Stream fileData);
275 |
276 | public SymStore BackingStore { get; private set; }
277 | public Uri StoreRootAddress { get; private set; }
278 |
279 | protected class PtrFile
280 | {
281 | public static bool TryParse(string fileContents, out PtrFile file)
282 | {
283 | file = new PtrFile();
284 | if (fileContents.StartsWith("MSG: "))
285 | {
286 | file.Message = fileContents.Substring(5);
287 | }
288 | else if (fileContents.StartsWith("PATH:"))
289 | {
290 | file.Path = fileContents.Substring(5);
291 | }
292 | else
293 | {
294 | file = null;
295 | return false;
296 | }
297 | return true;
298 | }
299 |
300 | public string Message { get; private set; }
301 | public string Path { get; private set; }
302 | }
303 | }
304 |
305 | internal class HttpSymStore : SymStore
306 | {
307 | internal HttpSymStore(string path, SymStore backingStore) : base(path, backingStore) { }
308 |
309 | protected override bool TryGetDataForUri(Uri file, out Stream fileData, out string errorMessage)
310 | {
311 | fileData = null;
312 | errorMessage = null;
313 | HttpWebRequest wr = (HttpWebRequest)HttpWebRequest.Create(file);
314 | wr.UserAgent = "Microsoft-Symbol-Server/6.3.9600.17095";
315 | try
316 | {
317 | IAsyncResult result = wr.BeginGetResponse(null, null);
318 | if (!result.AsyncWaitHandle.WaitOne(30000))
319 | {
320 | wr.Abort();
321 | errorMessage = "Timed out waiting for http response";
322 | }
323 | HttpWebResponse response = (HttpWebResponse)wr.EndGetResponse(result);
324 | HttpStatusCode statusCode = response.StatusCode;
325 | // for missing files the symbol server still returns code OK, but the content is an html error message
326 | if (statusCode != HttpStatusCode.OK)
327 | {
328 | errorMessage = "Http request answered with status code " + statusCode;
329 | }
330 | else if (response.ContentType.Equals("text/html") && response.ResponseUri != null)
331 | {
332 | errorMessage = "Http request redirected to " + response.ResponseUri;
333 | }
334 | else
335 | {
336 | fileData = response.GetResponseStream();
337 | return true;
338 | }
339 | }
340 | catch (WebException e)
341 | {
342 | errorMessage = e.Message;
343 | }
344 |
345 | return false;
346 | }
347 |
348 | protected override void WriteFile(Uri file, Stream fileData)
349 | {
350 | throw new NotSupportedException();
351 | }
352 | }
353 |
354 | internal class UNCSymStore : SymStore
355 | {
356 | internal UNCSymStore(string storeRootAddress, SymStore backingStore) : base(storeRootAddress, backingStore) { }
357 |
358 | protected override bool TryGetDataForUri(Uri file, out Stream fileData, out string errorMessage)
359 | {
360 | fileData = null;
361 | errorMessage = null;
362 | try
363 | {
364 | if (File.Exists(file.AbsolutePath))
365 | {
366 | fileData = File.OpenRead(file.AbsolutePath);
367 | return true;
368 | }
369 | else
370 | {
371 | errorMessage = "File not found at " + file.AbsolutePath;
372 | }
373 | }
374 | catch (IOException e)
375 | {
376 | errorMessage = e.ToString();
377 | }
378 | return false;
379 | }
380 |
381 | protected override void WriteFile(Uri file, Stream fileData)
382 | {
383 | // copy the stream in 64KB chunks if we can
384 | byte[] block = new byte[1024 * 64];
385 | string dir = Path.GetDirectoryName(file.AbsolutePath);
386 | if (!Directory.Exists(dir))
387 | Directory.CreateDirectory(dir);
388 | using (FileStream outFile = File.Open(file.AbsolutePath, FileMode.Create, FileAccess.Write))
389 | {
390 | int bytesRead = 0;
391 | do
392 | {
393 | bytesRead = fileData.Read(block, 0, block.Length);
394 | outFile.Write(block, 0, bytesRead);
395 | } while (bytesRead != 0);
396 | }
397 | }
398 | }
399 | }
400 |
--------------------------------------------------------------------------------
/src/StackParser/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Runtime.InteropServices;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace StackParser
10 | {
11 | public static class KnownFolder
12 | {
13 | public static readonly Guid Downloads = new Guid("374DE290-123F-4565-9164-39C4925E467B");
14 | }
15 |
16 | class Program
17 | {
18 |
19 | [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
20 | static extern int SHGetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)] Guid rfid, uint dwFlags, IntPtr hToken, out string pszPath);
21 |
22 | static string s_localSymbolRoot = null;
23 | static string s_inputFile;
24 | static string s_outputFile;
25 | static string s_symbolServerPath;
26 | static bool s_keepModules = false;
27 | static Dictionary s_pdbMap = new Dictionary(StringComparer.OrdinalIgnoreCase);
28 | static Dictionary s_moduleToPeFileMap = new Dictionary(StringComparer.OrdinalIgnoreCase);
29 | static List s_pdbFileList = new List();
30 | static char[] s_OptionValSeparator = { ':', '=' };
31 | static SymStore s_symStore = null;
32 |
33 | // symbol server constants
34 | const string internalSymbolServer = "http://symweb";
35 | const string publicSymbolServer = "http://msdl.microsoft.com/download/symbols";
36 |
37 | static void PrintUsage()
38 | {
39 | Console.WriteLine("StackParser [/pdbs {pdbFiles}] [/modules {PE files}]");
40 | Console.WriteLine(" [/keep] [/in inputFile] [/out outputfile] [/symsrv definition]");
41 | Console.WriteLine();
42 | Console.WriteLine(" All arguments are optional, but at least one pdb file or one PE file need to be defined.");
43 | Console.WriteLine();
44 | Console.WriteLine(" /pdbs {pdbFiles} A non empty list of pdb files to be used.");
45 | Console.WriteLine(" Use wildcards to load more files from a single directory.");
46 | Console.WriteLine(" /modules {PE files} A non empty list of loaded modules used.");
47 | Console.WriteLine(" Symbols are fetched from the symbol store.");
48 | Console.WriteLine(" /keep Keep the pdb files.");
49 | Console.WriteLine(" (default: all downloaded symbol files are deleted).");
50 | Console.WriteLine(" /in Input to operate on (default: stdin).");
51 | Console.WriteLine(" /out Append output to file (default: stdout).");
52 | Console.WriteLine(" /symsrv \"Standard\"definition for symbol server cache.");
53 | Console.WriteLine(" (Implies /keep).");
54 |
55 | Console.WriteLine();
56 | Console.WriteLine(" Examples:");
57 | Console.WriteLine(" StackParser /pdbs app.pdb SharedLibrary.pdb < log.txt");
58 | Console.WriteLine(" Uses existing PDB files to convert log.txt and writes result to console.");
59 | Console.WriteLine();
60 | Console.WriteLine(" StackParser /pdbs app.pdb /modules Lib.dll /in log.txt /out symlog.txt");
61 | Console.WriteLine(" Uses existing PDB (app.pdb) and looks up pdb file for Lib.dll;");
62 | Console.WriteLine(" reads input from log.txt and writes result to symlog.txt.");
63 | Console.WriteLine();
64 | Console.WriteLine(@" StackParser /modules foo.dll /in log.txt /symserver srv*c:\symbols*http://msdl.microsoft.com/download/symbols");
65 | Console.WriteLine(@" Converts log.txt by getting symbols from public symbol server");
66 | Console.WriteLine(@" (with local cache at c:\symbols).");
67 | Console.WriteLine();
68 | }
69 |
70 | static int GetOptionValue(string[] args, string curArg, int argPos, out string value)
71 | {
72 | int j = curArg.IndexOfAny(s_OptionValSeparator);
73 | if (j != -1 && j < curArg.Length-1)
74 | {
75 | value = curArg.Substring(j + 1);
76 | return argPos;
77 | }
78 | if (argPos + 1 < args.Length)
79 | {
80 | value = args[++argPos];
81 | return argPos;
82 | }
83 |
84 | value = null;
85 | return argPos;
86 | }
87 | static int CommandLineParser(string[] args)
88 | {
89 |
90 | bool inPdbs = false;
91 | bool inModules = false;
92 |
93 | for (int i = 0; i < args.Length; ++i)
94 | {
95 | string curArg = args[i];
96 | if (curArg.StartsWith("/") || curArg.StartsWith("-"))
97 | {
98 | //consume option character
99 | curArg = curArg.Substring(1).ToLower();
100 | if (curArg.StartsWith("pdbs"))
101 | {
102 | inPdbs = true;
103 | inModules = false;
104 | }
105 | else if (curArg.StartsWith("modules"))
106 | {
107 | inPdbs = false;
108 | inModules = true;
109 | }
110 | else if (curArg == "keep")
111 | {
112 | s_keepModules = true;
113 | }
114 | else if (curArg == "in")
115 | {
116 | i = GetOptionValue(args, curArg, i, out s_inputFile);
117 | }
118 | else if (curArg == "out")
119 | {
120 | i = GetOptionValue(args, curArg, i, out s_outputFile);
121 | }
122 | else if (curArg == "symsrv")
123 | {
124 | i = GetOptionValue(args, curArg, i, out s_symbolServerPath);
125 | }
126 | else
127 | {
128 | Console.Error.WriteLine("Unexpected Option: {0}", curArg);
129 | return -1;
130 | }
131 | continue;
132 | }
133 |
134 | if (inPdbs)
135 | {
136 | s_pdbFileList.Add(curArg);
137 | }
138 | else if (inModules)
139 | {
140 | string moduleName = Path.GetFileNameWithoutExtension(curArg);
141 |
142 | s_moduleToPeFileMap[moduleName] = curArg;
143 | }
144 | else
145 | {
146 | Console.Error.WriteLine("unexpected input");
147 | return -1;
148 | }
149 | }
150 |
151 | // no point in running without any debug info
152 | if (s_pdbFileList.Count == 0 && s_moduleToPeFileMap.Count == 0)
153 | return -1;
154 | return 1;
155 | }
156 | static void Main(string[] args)
157 | {
158 | if (args.Length == 0)
159 | {
160 | PrintUsage();
161 | return;
162 | }
163 |
164 |
165 | if (CommandLineParser(args) == -1)
166 | {
167 | PrintUsage();
168 | return;
169 | }
170 |
171 | foreach (string pdbName in s_pdbFileList)
172 | {
173 | try
174 | {
175 | string moduleName = Path.GetFileNameWithoutExtension(pdbName);
176 | if (moduleName.Contains("*") || moduleName.Contains("?"))
177 | {
178 | string pdbPath = Path.GetDirectoryName(pdbName);
179 | if (string.IsNullOrEmpty(pdbPath))
180 | {
181 | pdbPath = Directory.GetCurrentDirectory();
182 | }
183 | string pdbSearchPattern = Path.GetFileName(pdbName);
184 | foreach (string fileName in Directory.GetFiles(pdbPath, pdbSearchPattern))
185 | {
186 | moduleName = Path.GetFileNameWithoutExtension(fileName);
187 | var pdbSession = DiaHelper.LoadPDB(fileName);
188 | if (pdbSession != null)
189 | s_pdbMap[moduleName] = pdbSession;
190 | }
191 | }
192 | else
193 | {
194 | string fullName = Path.GetFullPath(pdbName);
195 | if (!File.Exists(fullName))
196 | {
197 | continue;
198 | }
199 | var pdbSession = DiaHelper.LoadPDB(fullName);
200 | if (pdbSession != null)
201 | s_pdbMap[moduleName] = pdbSession;
202 | }
203 | }
204 | catch (Exception e)
205 | {
206 | Console.Error.WriteLine(e.Message);
207 | return;
208 | }
209 | }
210 |
211 | List tmpFileList = new List();
212 |
213 | System.IO.StreamReader sr = null;
214 | System.IO.StreamWriter sw = null;
215 | System.IO.TextReader tr;
216 | System.IO.TextWriter tw = null;
217 | if (!String.IsNullOrEmpty(s_inputFile) && File.Exists(s_inputFile))
218 | {
219 | tr = sr = new System.IO.StreamReader(s_inputFile);
220 | }
221 | else
222 | {
223 | tr = Console.In;
224 | }
225 |
226 | if (!String.IsNullOrEmpty(s_outputFile))
227 | {
228 | // create file (appened if it exists)
229 | tw = sw = new StreamWriter(s_outputFile, true);
230 |
231 | }
232 | if (tw == null)
233 | {
234 | tw = Console.Out;
235 | }
236 |
237 | string line;
238 |
239 | // If we are using a pre-defined
240 | if (!String.IsNullOrEmpty(s_symbolServerPath))
241 | {
242 | s_keepModules = true;
243 | }
244 |
245 | // Create a (unique) local temp directory
246 | // string tempDir = Environment.GetEnvironmentVariable("TEMP");
247 |
248 | if (s_moduleToPeFileMap.Count > 0)
249 | {
250 | if (String.IsNullOrEmpty(s_symbolServerPath))
251 | {
252 | string tempDir;
253 | SHGetKnownFolderPath(KnownFolder.Downloads, 0, IntPtr.Zero, out tempDir);
254 | if (tempDir == null)
255 | {
256 | Console.Error.WriteLine("Cannot get path for download directory");
257 | tempDir = @"C:\SymbStore";
258 | }
259 |
260 | if (!String.IsNullOrEmpty(tempDir))
261 | {
262 | int i = 0;
263 | bool created = false;
264 | do
265 | {
266 | s_localSymbolRoot = Path.Combine(tempDir, String.Concat("PDBTemp", i.ToString()));
267 | i++;
268 | if (!s_keepModules && Directory.Exists(s_localSymbolRoot))
269 | continue;
270 |
271 | try
272 | {
273 | Directory.CreateDirectory(s_localSymbolRoot);
274 | created = true;
275 | }
276 | catch (Exception)
277 | {
278 | }
279 | } while (!created);
280 | }
281 | // construct our own path
282 | s_symbolServerPath = "srv*" + s_localSymbolRoot + "*" + internalSymbolServer;
283 | }
284 | }
285 |
286 | while((line = tr.ReadLine()) != null)
287 | {
288 | const string separator = "!+0x";
289 | string[] frags = line.Split(new string[] { separator }, StringSplitOptions.RemoveEmptyEntries);
290 | if (frags.Length == 2)
291 | {
292 | string moduleStr = frags[0];
293 | int idx = moduleStr.LastIndexOf(' ');
294 | if (idx < 0) idx = -1;
295 | string moduleName = moduleStr.Substring(idx + 1);
296 | string prefix = moduleStr.Substring(0, idx + 1);
297 |
298 | string rvaStr = frags[1];
299 | idx = rvaStr.IndexOf(' ');
300 | if (idx < 0) idx = rvaStr.Length;
301 | string rva = rvaStr.Substring(0, idx);
302 | string suffix = rvaStr.Substring(idx);
303 |
304 | uint rvaNum;
305 | IDiaSession pdbSession = null;
306 | string methodName;
307 | if (!s_pdbMap.TryGetValue(moduleName, out pdbSession))
308 | {
309 | string peFileName;
310 | if (s_moduleToPeFileMap.TryGetValue(moduleName, out peFileName))
311 | {
312 | // Try to get the pdb file from the symbol store
313 | string pdbFileName = GetPdbFileForModule(peFileName);
314 |
315 | if (!String.IsNullOrEmpty(pdbFileName))
316 | {
317 |
318 | if (!tmpFileList.Contains(pdbFileName))
319 | tmpFileList.Add(pdbFileName);
320 | // Load pdb
321 | pdbSession = DiaHelper.LoadPDB(pdbFileName);
322 |
323 | // cache session
324 | if (pdbSession != null)
325 | s_pdbMap[moduleName] = pdbSession;
326 | }
327 |
328 | }
329 | }
330 |
331 | if (pdbSession == null ||
332 | (rvaNum = HexToUint(rva)) == 0 ||
333 | ((methodName = DiaHelper.GetMethodName(pdbSession, rvaNum)) == null))
334 | {
335 | tw.WriteLine("{0}{1}{2}", moduleStr, separator, rvaStr);
336 | continue;
337 | }
338 |
339 | tw.WriteLine("{0}{1}!{2}{3}", prefix, moduleName, methodName, suffix);
340 | }
341 | else
342 | {
343 | tw.WriteLine(line);
344 | }
345 | }
346 |
347 | // clean up
348 |
349 | if (!String.IsNullOrEmpty(s_localSymbolRoot) && tmpFileList.Count > 0)
350 | {
351 | if (s_keepModules)
352 | {
353 | Console.WriteLine("Downloaded symbol file{0}:", tmpFileList.Count != 1 ? "s" : "");
354 | foreach (string tmpFile in tmpFileList)
355 | {
356 | Console.WriteLine(tmpFile);
357 | }
358 |
359 | }
360 | else
361 | {
362 | foreach (KeyValuePair mapPair in s_pdbMap)
363 | {
364 | DiaHelper.ReleaseSession(mapPair.Value);
365 | }
366 |
367 | // reset pdbMap (drop references to IDiaSession)
368 | s_pdbMap = new Dictionary();
369 | // reset symbol store (relinquish potential references to just downloaded pdb files)
370 | s_symStore = null;
371 |
372 | // let the GC finalize (release) COM objects
373 | GC.Collect();
374 | GC.Collect();
375 |
376 | foreach (string tmpFile in tmpFileList)
377 | {
378 | try
379 | {
380 | File.Delete(tmpFile);
381 | }
382 | catch (Exception e)
383 | {
384 | Console.Error.WriteLine("Failed to delete {0}", tmpFile);
385 | Console.Error.WriteLine(e.Message);
386 | }
387 | }
388 | try
389 | {
390 | Directory.Delete(s_localSymbolRoot, true);
391 | }
392 | catch (Exception e)
393 | {
394 | Console.Error.WriteLine("Failed to delete directory {0}", s_localSymbolRoot);
395 | Console.Error.WriteLine(e.Message);
396 | }
397 | }
398 | }
399 |
400 | if (sr != null)
401 | {
402 | sr.Close();
403 | }
404 |
405 | if (sw != null)
406 | {
407 | sw.Close();
408 | }
409 | }
410 |
411 | static CodeViewDebugData CvDataFromPE(string fileName)
412 | {
413 | PEReader per = null;
414 | try
415 | {
416 | // Inspect PE to get the PDB information
417 | per = new PEReader(new System.IO.FileStream(fileName, FileMode.Open));
418 | }
419 | catch (Exception)
420 | {
421 | }
422 |
423 | return (per != null) ? per.CodeViewDebugData : null;
424 | }
425 |
426 | static Dictionary s_pdbFileForModule = new Dictionary();
427 | static string GetPdbFileForModule(string fileName)
428 | {
429 | string retVal;
430 |
431 | // look in the "cache" of already successfully opened
432 | if (s_pdbFileForModule.TryGetValue(fileName, out retVal))
433 | {
434 | return retVal;
435 | }
436 |
437 | retVal = null;
438 | CodeViewDebugData cvdd = CvDataFromPE(fileName);
439 |
440 | if (cvdd != null)
441 | {
442 | if (s_symStore == null)
443 | s_symStore = SymStore.FromPath(s_symbolServerPath);
444 |
445 | if (s_symStore != null)
446 | {
447 | Stream pdbStream;
448 | string indexString = cvdd.Signature.ToString().Replace("-", "").ToUpper() + cvdd.Age.ToString();
449 | string localFileName = Path.GetFileName(cvdd.PdbPath);
450 | SymStoreResult symResult = new SymStoreResult();
451 | if (s_symStore.TryGetFile(localFileName, indexString, symResult, out pdbStream))
452 | {
453 | retVal = symResult.CachedPath;
454 | }
455 | }
456 |
457 | }
458 |
459 | s_pdbFileForModule.Add(fileName, retVal);
460 | return retVal;
461 | }
462 |
463 | static uint HexToUint(string hexStr)
464 | {
465 | try
466 | {
467 | return Convert.ToUInt32(hexStr, 16);
468 | }
469 | catch(FormatException)
470 | {
471 | return 0;
472 | }
473 | }
474 |
475 | }
476 | }
477 |
--------------------------------------------------------------------------------
/src/StackParser/DiaHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Reflection;
6 | using System.Runtime.InteropServices;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Runtime.InteropServices.CustomMarshalers;
10 |
11 | namespace StackParser
12 | {
13 | class DiaHelper
14 | {
15 | static Dictionary sessionMap = new Dictionary();
16 | public static IDiaSession LoadPDB(string pdbFileName)
17 | {
18 | string msg;
19 | IDiaDataSource source;
20 | string curDir = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
21 | string msdDIADllPath = System.IO.Path.Combine(curDir, "msdia140.dll");
22 | if (!MSDebugInterfaceAccessFactory.TryCreate(msdDIADllPath, out source, out msg, new Guid("e6756135-1e65-4d17-8576-610761398c3c")))
23 | {
24 | throw new InvalidOperationException("Could not load dia from path " + msdDIADllPath);
25 | }
26 |
27 | IDiaSession session;
28 | source.loadDataFromPdb(pdbFileName);
29 | source.openSession(out session);
30 | sessionMap.Add(session, source);
31 | return session;
32 | }
33 |
34 | public static void ReleaseSession(IDiaSession session)
35 | {
36 | IDiaDataSource source;
37 | if (sessionMap.TryGetValue(session, out source))
38 | {
39 | sessionMap.Remove(session);
40 | Marshal.FinalReleaseComObject(session);
41 | Marshal.FinalReleaseComObject(source);
42 | }
43 | }
44 |
45 | public static string GetMethodName(IDiaSession pdbSession, uint rva)
46 | {
47 | IDiaSymbol funcSym;
48 | pdbSession.findSymbolByRVA(rva, SymTagEnum.SymTagFunction, out funcSym);
49 | if (funcSym == null)
50 | pdbSession.findSymbolByRVA(rva, SymTagEnum.SymTagPublicSymbol, out funcSym);
51 |
52 | if (funcSym == null)
53 | return null;
54 |
55 | StringBuilder methodNameStr = new StringBuilder();
56 |
57 | // Append the method-name
58 | methodNameStr.Append(funcSym.GetUndecoratedNameEx(UndName.DebuggerInternal));
59 |
60 | // Append the offset of current instruction inside method
61 | methodNameStr.Append("+0x");
62 | methodNameStr.Append(Convert.ToString(rva - funcSym.GetRelativeVirtualAddress(), 16));
63 |
64 | // Append the source line
65 | IDiaEnumLineNumbers lines = null;
66 | IDiaSourceFile sourceFile = null;
67 | pdbSession.findLinesByRVA(rva, 1, out lines);
68 | int i;
69 | if (lines != null && lines.count == 1)
70 | {
71 | IDiaLineNumber line = lines.Item(0);
72 | if (line != null)
73 | {
74 | sourceFile = line.SourceFile;
75 | methodNameStr.Append(" (");
76 | methodNameStr.Append(sourceFile.FileName);
77 | methodNameStr.Append(", line ");
78 | methodNameStr.Append(line.LineNumber);
79 | methodNameStr.Append(")");
80 |
81 | i = Marshal.ReleaseComObject(line);
82 | if (i != 0)
83 | Console.WriteLine("RefCount(funcSym) == {0}", i);
84 | }
85 | }
86 | i = Marshal.ReleaseComObject(funcSym);
87 | if (i != 0)
88 | Console.WriteLine("RefCount(funcSym) == {0}", i);
89 | if (lines != null)
90 | {
91 | if (sourceFile != null)
92 | {
93 | i = Marshal.ReleaseComObject(sourceFile);
94 | if (i != 0)
95 | Console.WriteLine("RefCount(sourceFile) == {0}", i);
96 |
97 | }
98 | // line?
99 | i = Marshal.ReleaseComObject(lines);
100 | if (i != 0)
101 | Console.WriteLine("RefCount(lines) == {0}", i);
102 | }
103 |
104 | //return funcSym.GetName();
105 | return methodNameStr.ToString();
106 | }
107 | }
108 |
109 | public static class MSDebugInterfaceAccessFactory
110 | {
111 | ///
112 | /// Creates a stackwalker out of msdia specified by MSDiaDllPath.
113 | ///
114 | ///
115 | ///
116 | /// This will be used to create the stackwalker in DllGetClassObject
117 | /// The DIA type parameter. Currently the interfaces supported are IDiaDataSource, IDiaStackWalker
118 | /// True if sucessful, false if not
119 | public static bool TryCreate(string msdDIADllPath, out T source, out string errorMessage, Guid diaSourceClsid)
120 | where T : class
121 | {
122 | if (!string.IsNullOrWhiteSpace(msdDIADllPath) && !System.IO.File.Exists(msdDIADllPath))
123 | {
124 | source = default(T);
125 | errorMessage = "Path to msdia not found - " + msdDIADllPath;
126 | return false;
127 | }
128 | return ComDllObjectFactory.LoadAndCreate(msdDIADllPath, out source, out errorMessage, diaSourceClsid);
129 | }
130 | }
131 |
132 | public static class ComDllObjectFactory
133 | {
134 |
135 | ///
136 | /// The signature of the DllGetClassObject, COM entriy point in DLLs, that allows to create objects from that DLL
137 | ///
138 | ///
139 | [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.StdCall)]
140 | public delegate int DllGetClassObjectFunction([In] ref Guid clsid, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out object iFace);
141 |
142 | [ComImport]
143 | [Guid("00000001-0000-0000-C000-000000000046")]
144 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
145 | private interface IClassFactory
146 | {
147 | [return: MarshalAs(UnmanagedType.Interface)]
148 | object CreateInstance(
149 | [MarshalAs(UnmanagedType.IUnknown)] object punkOuter,
150 | [In, MarshalAs(UnmanagedType.LPStruct)] Guid iid);
151 |
152 | void LockServer(bool fLock);
153 | }
154 |
155 | [DllImportAttribute("kernel32.dll")]
156 | public static extern IntPtr LoadLibraryEx(String fileName, int hFile, uint dwFlags);
157 | public static IntPtr LoadLibrary(string fileName)
158 | {
159 | return LoadLibraryEx(fileName, 0, 0);
160 | }
161 | [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true)]
162 | public static extern IntPtr GetProcAddress(
163 | IntPtr hModule,
164 | string procName);
165 |
166 | ///
167 | /// Creates an object from a given COM dll by a class id and a given interface
168 | ///
169 | public static bool LoadAndCreate(string dllPath, out T source, out string errorMessage, Guid classId)
170 | where T : class
171 | {
172 | if (string.IsNullOrWhiteSpace(dllPath) && !System.IO.File.Exists(dllPath))
173 | {
174 | source = null;
175 | errorMessage = "Path to a dll not found - " + dllPath;
176 | return false;
177 | }
178 |
179 | IntPtr dllHandle = LoadLibrary(dllPath);
180 | if (dllHandle == IntPtr.Zero)
181 | {
182 | source = null;
183 | errorMessage = "Could not load library " + dllPath;
184 | return false;
185 | }
186 |
187 | try
188 | {
189 | IntPtr fp = GetProcAddress(dllHandle, "DllGetClassObject");
190 | DllGetClassObjectFunction getClassObj = (DllGetClassObjectFunction)Marshal.GetDelegateForFunctionPointer(fp, typeof(DllGetClassObjectFunction));
191 | object c;
192 | Guid diaSourceClassGuid = classId;
193 |
194 | Guid classFactoryGuid = typeof(IClassFactory).GUID;
195 | int hr = getClassObj(ref diaSourceClassGuid, ref classFactoryGuid, out c);
196 |
197 | if (hr != 0)
198 | {
199 | throw new COMException("Could not get object for CLSID " + classId, hr);
200 | }
201 |
202 | IClassFactory factory = c as IClassFactory;
203 | T diaSource = (T)factory.CreateInstance(null, typeof(T).GUID);
204 | // the cast to T increased the reference count
205 | //int cnt = Marshal.ReleaseComObject(diaSource);
206 | //if (cnt != 1)
207 | // Console.WriteLine("diaSource.RefCount not 1, but {0}", cnt);
208 | source = diaSource;
209 | errorMessage = "";
210 | return true;
211 | }
212 | catch (Exception e)
213 | {
214 | errorMessage = string.Format("Could not get {0} from the library {1}. Details: {2}", typeof(T).Name, dllPath, e);
215 | source = null;
216 | return false;
217 | }
218 | }
219 | }
220 |
221 | [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("79F1BB5F-B66E-48E5-B6A9-1545C323CA3D")]
222 | public interface IDiaDataSource
223 | {
224 | //[DispId(1)]
225 | //void loadDataFromPdb([In, MarshalAs(UnmanagedType.LPWStr)] string pdbPath);
226 |
227 | //[DispId(5)]
228 | //void openSession([MarshalAs(UnmanagedType.Interface)] out IDiaSession ppSession);
229 |
230 | string lastError { [return: MarshalAs(UnmanagedType.BStr)] get; }
231 | void loadDataFromPdb([In, MarshalAs(UnmanagedType.LPWStr)] string pdbPath);
232 | void loadAndValidateDataFromPdb([In, MarshalAs(UnmanagedType.LPWStr)] string pdbPath, [In] ref Guid pcsig70, [In] uint sig, [In] uint age);
233 | void loadDataForExe([In, MarshalAs(UnmanagedType.LPWStr)] string executable, [In, MarshalAs(UnmanagedType.LPWStr)] string searchPath, [In, MarshalAs(UnmanagedType.IUnknown)] object pCallback);
234 | void loadDataFromIStream([In, MarshalAs(UnmanagedType.Interface)] System.Runtime.InteropServices.ComTypes.IStream pIStream);
235 | void openSession([MarshalAs(UnmanagedType.Interface)] out IDiaSession ppSession);
236 | void loadDataFromCodeViewInfo([In, MarshalAs(UnmanagedType.LPWStr)] string executable, [In, MarshalAs(UnmanagedType.LPWStr)] string searchPath, [In] uint cbCvInfo,
237 | [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] pbCvInfo,
238 | [In, MarshalAs(UnmanagedType.IUnknown)] object pCallback);
239 | void loadDataFromMiscInfo([In, MarshalAs(UnmanagedType.LPWStr)] string executable, [In, MarshalAs(UnmanagedType.LPWStr)] string searchPath,
240 | [In] uint timeStampExe, [In] uint timeStampDbg, [In] uint sizeOfExe, [In] uint cbMiscInfo, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)] byte[] pbMiscInfo,
241 | [In, MarshalAs(UnmanagedType.IUnknown)] object pCallback);
242 | }
243 |
244 |
245 |
246 | [ComImport, Guid("2F609EE1-D1C8-4E24-8288-3326BADCD211"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
247 | public interface IDiaSession
248 | {
249 | ulong loadAddress { get; [param: In] set; }
250 | IDiaSymbol globalScope { [return: MarshalAs(UnmanagedType.Interface)] get; }
251 | void getEnumTables();
252 |
253 | void getSymbolsByAddr();
254 |
255 | void findChildren();
256 |
257 | void findChildrenEx();
258 |
259 | void findChildrenExByAddr();
260 |
261 | void findChildrenExByVA();
262 |
263 | void findChildrenExByRVA();
264 |
265 | void findSymbolByAddr();
266 |
267 | void findSymbolByRVA([In] uint rva, [In] SymTagEnum symTag, [MarshalAs(UnmanagedType.Interface)] out IDiaSymbol ppSymbol);
268 |
269 | void findSymbolByVA([In] long va, [In] SymTagEnum symTag, [MarshalAs(UnmanagedType.Interface)] out IDiaSymbol ppSymbol);
270 |
271 | void findSymbolByToken([In] uint token, [In] SymTagEnum symTag, [MarshalAs(UnmanagedType.Interface)] out IDiaSymbol ppSymbol);
272 |
273 | void symsAreEquiv([In, MarshalAs(UnmanagedType.Interface)] IDiaSymbol symbolA, [In, MarshalAs(UnmanagedType.Interface)] IDiaSymbol symbolB);
274 |
275 | IDiaSymbol symbolById([In] uint id);
276 |
277 | void findSymbolByRVAEx([In] uint rva, [In] SymTagEnum symTag, [MarshalAs(UnmanagedType.Interface)] out IDiaSymbol ppSymbol, out int displacement);
278 |
279 | void findSymbolByVAEx([In] long va, [In] SymTagEnum symTag, [MarshalAs(UnmanagedType.Interface)] out IDiaSymbol ppSymbol, out int displacement);
280 |
281 | void findFile();
282 |
283 | void findFileById([In] uint uniqueId, [MarshalAs(UnmanagedType.Interface)] out IDiaSourceFile ppResult);
284 |
285 | void findLines([In, MarshalAs(UnmanagedType.Interface)] IDiaSymbol compiland, [In, MarshalAs(UnmanagedType.Interface)] IDiaSourceFile file, [MarshalAs(UnmanagedType.Interface)] out IDiaEnumLineNumbers ppResult);
286 |
287 | void findLinesByAddr([In] uint seg, [In] uint offset, [In] uint length, [MarshalAs(UnmanagedType.Interface)] out IDiaEnumLineNumbers ppResult);
288 |
289 | void findLinesByRVA([In] uint rva, [In] uint length, [MarshalAs(UnmanagedType.Interface)] out IDiaEnumLineNumbers ppResult);
290 | }
291 |
292 | [Flags]
293 | public enum UndName : uint
294 | {
295 | DebuggerInternal = 0x80000000 // only used by debuggers when dealing with symbols from ProjectN PDB
296 | }
297 |
298 | public enum SymTagEnum
299 | {
300 | SymTagNull,
301 | SymTagExe,
302 | SymTagCompiland,
303 | SymTagCompilandDetails,
304 | SymTagCompilandEnv,
305 | SymTagFunction,
306 | SymTagBlock,
307 | SymTagData,
308 | SymTagAnnotation,
309 | SymTagLabel,
310 | SymTagPublicSymbol,
311 | SymTagUDT,
312 | SymTagEnum,
313 | SymTagFunctionType,
314 | SymTagPointerType,
315 | SymTagArrayType,
316 | SymTagBaseType,
317 | SymTagTypedef,
318 | SymTagBaseClass,
319 | SymTagFriend,
320 | SymTagFunctionArgType,
321 | SymTagFuncDebugStart,
322 | SymTagFuncDebugEnd,
323 | SymTagUsingNamespace,
324 | SymTagVTableShape,
325 | SymTagVTable,
326 | SymTagCustom,
327 | SymTagThunk,
328 | SymTagCustomType,
329 | SymTagManagedType,
330 | SymTagDimension,
331 | SymTagCallSite,
332 | SymTagInlineSite,
333 | SymTagBaseInterface,
334 | SymTagVectorType,
335 | SymTagMatrixType,
336 | SymTagHLSLType,
337 | SymTagMax
338 | }
339 |
340 | [ComImport, Guid("CB787B2F-BD6C-4635-BA52-933126BD2DCD"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
341 | public interface IDiaSymbol
342 | {
343 | [DispId(0)]
344 | uint GetSymIndexId();
345 |
346 | [DispId(1)]
347 | SymTagEnum GetSymTag();
348 |
349 | [DispId(2)]
350 | [return: MarshalAs(UnmanagedType.BStr)]
351 | string GetName();
352 |
353 | [DispId(3)]
354 | IDiaSymbol GetLexicalParent();
355 |
356 | [DispId(4)]
357 | IDiaSymbol GetClassParent();
358 |
359 | [DispId(5)]
360 | IDiaSymbol GetType();
361 |
362 | [DispId(6)]
363 | int GetDataKind();
364 |
365 | [DispId(7)]
366 | int GetLocationType();
367 |
368 | [DispId(8)]
369 | uint GetAddressSection();
370 |
371 | [DispId(9)]
372 | uint GetAddressOffset();
373 |
374 | [DispId(10)]
375 | uint GetRelativeVirtualAddress();
376 |
377 | [DispId(11)]
378 | long GetVirtualAddress();
379 |
380 | [DispId(12)]
381 | int GetRegisterId();
382 |
383 | [DispId(13)]
384 | int GetOffset();
385 |
386 | [DispId(14)]
387 | ulong GetLength();
388 |
389 | [DispId(15)]
390 | [PreserveSig]
391 | int GetSlot(out int slotIndex);
392 |
393 | [DispId(16)]
394 | [return: MarshalAs(UnmanagedType.Bool)]
395 | bool GetVolatileType();
396 |
397 | [DispId(17)]
398 | [return: MarshalAs(UnmanagedType.Bool)]
399 | bool GetConstType();
400 |
401 | [DispId(18)]
402 | [return: MarshalAs(UnmanagedType.Bool)]
403 | bool GetUnalignedType();
404 |
405 | [DispId(19)]
406 | uint GetAccess();
407 |
408 | [DispId(20)]
409 | [return: MarshalAs(UnmanagedType.BStr)]
410 | string GetLibraryName();
411 |
412 | [DispId(21)]
413 | uint GetPlatform();
414 |
415 | [DispId(22)]
416 | uint GetLanguage();
417 |
418 | [DispId(23)]
419 | [return: MarshalAs(UnmanagedType.Bool)]
420 | bool GetEditAndContinueEnabled();
421 |
422 | [DispId(24)]
423 | uint GetFrontEndMajor();
424 |
425 | [DispId(25)]
426 | uint GetFrontEndMinor();
427 |
428 | [DispId(26)]
429 | uint GetFrontEndBuild();
430 |
431 | [DispId(27)]
432 | uint GetBackEndMajor();
433 |
434 | [DispId(28)]
435 | uint GetBackEndMinor();
436 |
437 | [DispId(29)]
438 | uint GetBackEndBuild();
439 |
440 | [DispId(30)]
441 | [return: MarshalAs(UnmanagedType.BStr)]
442 | string GetSourceFileName();
443 |
444 | [DispId(31)]
445 | [return: MarshalAs(UnmanagedType.BStr)]
446 | string GetUnused();
447 |
448 | [DispId(32)]
449 | uint GetThunkOrdinal();
450 |
451 | [DispId(33)]
452 | int GetThisAdjust();
453 |
454 | [DispId(34)]
455 | uint GetVirtualBaseOffset();
456 |
457 | [DispId(35)]
458 | [return: MarshalAs(UnmanagedType.Bool)]
459 | bool GetVirtual();
460 |
461 | [DispId(36)]
462 | [return: MarshalAs(UnmanagedType.Bool)]
463 | bool GetIntro();
464 |
465 | [DispId(37)]
466 | [return: MarshalAs(UnmanagedType.Bool)]
467 | bool GetPure();
468 |
469 | [DispId(38)]
470 | uint GetCallingConvention();
471 |
472 | [DispId(39)]
473 | [return: MarshalAs(UnmanagedType.Struct)]
474 | object GetValue();
475 |
476 | [DispId(40)]
477 | int GetBaseType();
478 |
479 | [DispId(41)]
480 | uint GetToken();
481 |
482 | [DispId(42)]
483 | uint GetTimeStamp();
484 |
485 | [DispId(43)]
486 | Guid GetGuid();
487 |
488 | [DispId(44)]
489 | [return: MarshalAs(UnmanagedType.BStr)]
490 | string GetSymbolsFileName();
491 |
492 | [DispId(46)]
493 | [return: MarshalAs(UnmanagedType.Bool)]
494 | bool GetReference();
495 |
496 | [DispId(47)]
497 | int GetCount();
498 |
499 | [DispId(49)]
500 | int GetBitPosition();
501 |
502 | [DispId(50)]
503 | IDiaSymbol GetArrayIndexType();
504 |
505 | [DispId(51)]
506 | [return: MarshalAs(UnmanagedType.Bool)]
507 | bool GetPacked();
508 |
509 | [DispId(52)]
510 | [return: MarshalAs(UnmanagedType.Bool)]
511 | bool GetConstructor();
512 |
513 | [DispId(53)]
514 | [return: MarshalAs(UnmanagedType.Bool)]
515 | bool GetOverloadedOperator();
516 |
517 | [DispId(54)]
518 | [return: MarshalAs(UnmanagedType.Bool)]
519 | bool GetNested();
520 |
521 | [DispId(55)]
522 | [return: MarshalAs(UnmanagedType.Bool)]
523 | bool GetHasNestedTypes();
524 |
525 | [DispId(56)]
526 | [return: MarshalAs(UnmanagedType.Bool)]
527 | bool GetHasAssignmentOperator();
528 |
529 | [DispId(57)]
530 | [return: MarshalAs(UnmanagedType.Bool)]
531 | bool GetHasCastOperator();
532 |
533 | [DispId(58)]
534 | [return: MarshalAs(UnmanagedType.Bool)]
535 | bool GetScoped();
536 |
537 | [DispId(59)]
538 | [return: MarshalAs(UnmanagedType.Bool)]
539 | bool GetVirtualBaseClass();
540 |
541 | [DispId(60)]
542 | [return: MarshalAs(UnmanagedType.Bool)]
543 | bool GetIndirectVirtualBaseClass();
544 |
545 | [DispId(61)]
546 | int GetVirtualBasePointerOffset();
547 |
548 | [DispId(62)]
549 | IDiaSymbol GetVirtualTableShape();
550 |
551 | [DispId(64)]
552 | uint GetLexicalParentId();
553 |
554 | [DispId(65)]
555 | uint GetClassParentId();
556 |
557 | [DispId(66)]
558 | uint GetTypeId();
559 |
560 | [DispId(67)]
561 | uint GetArrayIndexTypeId();
562 |
563 | [DispId(68)]
564 | uint GetVirtualTableShapeId();
565 |
566 | [DispId(69)]
567 | [return: MarshalAs(UnmanagedType.Bool)]
568 | bool GetCode();
569 |
570 | [DispId(70)]
571 | [return: MarshalAs(UnmanagedType.Bool)]
572 | bool GetFunction();
573 |
574 | [DispId(71)]
575 | [return: MarshalAs(UnmanagedType.Bool)]
576 | bool GetManaged();
577 |
578 | [DispId(72)]
579 | [return: MarshalAs(UnmanagedType.Bool)]
580 | bool GetMsil();
581 |
582 | [DispId(73)]
583 | uint GetVirtualBaseDispIndex();
584 |
585 | [DispId(74)]
586 | [return: MarshalAs(UnmanagedType.BStr)]
587 | string GetUndecoratedName();
588 |
589 | [DispId(75)]
590 | uint GetAge();
591 |
592 | [DispId(76)]
593 | uint GetSignature();
594 |
595 | [DispId(77)]
596 | [return: MarshalAs(UnmanagedType.Bool)]
597 | bool GetCompilerGenerated();
598 |
599 | [DispId(78)]
600 | [return: MarshalAs(UnmanagedType.Bool)]
601 | bool GetAddressTaken();
602 |
603 | [DispId(79)]
604 | uint GetRank();
605 |
606 | [DispId(80)]
607 | IDiaSymbol GetLowerBound();
608 |
609 | [DispId(81)]
610 | IDiaSymbol GetUpperBound();
611 |
612 | [DispId(82)]
613 | uint GetLowerBoundId();
614 |
615 | [DispId(83)]
616 | uint GetUpperBoundId();
617 |
618 | [PreserveSig]
619 | int GetDataBytes(int cbData, out int pcbData, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] byte[] data);
620 |
621 | void FindChildren(SymTagEnum symTag, [In, MarshalAs(UnmanagedType.BStr)] string name, uint compareFlags);
622 |
623 | void FindChildrenEx(SymTagEnum symTag, [In, MarshalAs(UnmanagedType.BStr)] string name, uint compareFlags);
624 |
625 | void FindChildrenExByAddr(SymTagEnum symTag, [In, MarshalAs(UnmanagedType.BStr)] string name, uint compareFlags, uint isect, uint offset);
626 |
627 | void FindChildrenExByVA(SymTagEnum symTag, [In, MarshalAs(UnmanagedType.BStr)] string name, uint compareFlags, ulong va);
628 |
629 | void FindChildrenExByRVA(SymTagEnum symTag, [In, MarshalAs(UnmanagedType.BStr)] string name, uint compareFlags, uint rva);
630 |
631 | [DispId(84)]
632 | uint GetTargetSection();
633 |
634 | [DispId(85)]
635 | uint GetTargetOffset();
636 |
637 | [DispId(86)]
638 | uint GetTargetRelativeVirtualAddress();
639 |
640 | [DispId(87)]
641 | ulong GetTargetVirtualAddress();
642 |
643 | [DispId(88)]
644 | uint GetMachineType();
645 |
646 | [DispId(89)]
647 | uint GetOemId();
648 |
649 | [DispId(90)]
650 | uint GetOemSymbolId();
651 |
652 | void GetTypes(int cTypes, out int pcTypes, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IDiaSymbol[] pTypes);
653 |
654 | void GetTypeIds(int cTypeIds, out int pcTypeIds, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] int[] pdwTypeIds);
655 |
656 | [DispId(91)]
657 | IDiaSymbol GetObjectPointerType();
658 |
659 | [DispId(92)]
660 | int GetUdtKind();
661 |
662 | [return: MarshalAs(UnmanagedType.BStr)]
663 | string GetUndecoratedNameEx(UndName undecorateOptions);
664 | }
665 |
666 | [ComImport, Guid("FE30E878-54AC-44F1-81BA-39DE940F6052"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), DefaultMember("Item")]
667 | public interface IDiaEnumLineNumbers
668 | {
669 | [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "", MarshalTypeRef = typeof(EnumeratorToEnumVariantMarshaler), MarshalCookie = "")]
670 | IEnumerator GetEnumerator();
671 | int count { get; }
672 | [return: MarshalAs(UnmanagedType.Interface)]
673 | IDiaLineNumber Item([In] int index);
674 | void Next([In] uint celt, [MarshalAs(UnmanagedType.Interface)] out IDiaLineNumber rgelt, out uint pceltFetched);
675 | void Skip([In] uint celt);
676 | void Reset();
677 | void Clone([MarshalAs(UnmanagedType.Interface)] out IDiaEnumLineNumbers ppenum);
678 | }
679 |
680 | [ComImport, Guid("B388EB14-BE4D-421D-A8A1-6CF7AB057086"), InterfaceType((short)1)]
681 | public interface IDiaLineNumber
682 | {
683 | IDiaSymbol Compiland { get; }
684 | IDiaSourceFile SourceFile { get; }
685 | int LineNumber { get; }
686 | int LineNumberEnd { get; }
687 | int ColumnNumber { get; }
688 | int ColumnNumberEnd { get; }
689 | int AddressSection { get; }
690 | int AddressOffset { get; }
691 | int RelativeVirtualAddress { get; }
692 | long VirtualAddress { get; }
693 | int Length { get; }
694 | int SourceFileId { get; }
695 | int Statement { get; }
696 | int CompilandId { get; }
697 | }
698 |
699 | [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("A2EF5353-F5A8-4EB3-90D2-CB526ACB3CDD")]
700 | public interface IDiaSourceFile
701 | {
702 | int UniqueId { get; }
703 | string FileName { [return: MarshalAs(UnmanagedType.BStr)] get; }
704 | int ChecksumType { get; }
705 | IDiaEnumSymbols Compilands { get; }
706 | void GetChecksum(int cbData, out int pcbData, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] byte[] pbData);
707 | }
708 |
709 | [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("CAB72C48-443B-48F5-9B0B-42F0820AB29A"), DefaultMember("Item")]
710 | public interface IDiaEnumSymbols
711 | {
712 | [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "", MarshalTypeRef = typeof(EnumeratorToEnumVariantMarshaler), MarshalCookie = "")]
713 | IEnumerator GetEnumerator();
714 | int count { get; }
715 | [return: MarshalAs(UnmanagedType.Interface)]
716 | IDiaSymbol Item([In] int index);
717 | void Next([In] uint celt, [MarshalAs(UnmanagedType.Interface)] out IDiaSymbol rgelt, out uint pceltFetched);
718 | void Skip([In] uint celt);
719 | void Reset();
720 | void Clone([MarshalAs(UnmanagedType.Interface)] out IDiaEnumSymbols ppenum);
721 | }
722 | }
723 |
--------------------------------------------------------------------------------
/src/StackParser/PEReader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.IO;
6 | using System.Diagnostics;
7 |
8 | namespace StackParser
9 | {
10 | ///
11 | /// An interface for reading bytes from a module image
12 | ///
13 | public interface IModuleReader
14 | {
15 | int ReadAtOffset(byte[] fileBytes, int offset);
16 | PEStreamFormat Format { get; }
17 | int Size { get; }
18 | }
19 | ///
20 | /// Describes the layout of PE information within a stream
21 | ///
22 | public enum PEStreamFormat
23 | {
24 | // The format of a PE file as it exists on disk, as speced by CLI.
25 | // In this format RVAs must be mapped to stream contents using section header mapping information.
26 | DiskFormat,
27 | // The canonical format of PE data as it is layed out in memory by the
28 | // OS loader. In this format RVAs can be used as direct offsets into the stream.
29 | MemoryLayoutFormat
30 | }
31 | public class StreamModuleReader : IModuleReader
32 | {
33 | Stream m_peStream;
34 |
35 | public StreamModuleReader(Stream peStream)
36 | {
37 | m_peStream = peStream;
38 | }
39 |
40 | public int ReadAtOffset(byte[] fileBytes, int offset)
41 | {
42 | m_peStream.Seek(offset, SeekOrigin.Begin);
43 | int bytesReadTotal = 0;
44 | int bytesRead = 0;
45 | do
46 | {
47 | bytesRead = m_peStream.Read(fileBytes, bytesReadTotal, fileBytes.Length - bytesReadTotal);
48 | bytesReadTotal += bytesRead;
49 | } while (bytesReadTotal != fileBytes.Length && bytesRead != 0);
50 | return bytesReadTotal;
51 | }
52 |
53 | public PEStreamFormat Format { get { return PEStreamFormat.DiskFormat; } }
54 |
55 | public int Size { get { return (int)m_peStream.Length; } }
56 | }
57 |
58 | public enum GetRuntimeFunctionEntryResult
59 | {
60 | Found,
61 | DoesNotExist,
62 | MissingMemory
63 | }
64 |
65 | public class RuntimeFunctionEntry : IComparable
66 | {
67 | ///
68 | /// The RVA where code for this function starts
69 | ///
70 | public int BeginAddress;
71 | ///
72 | /// The RVA where code for this function ends
73 | ///
74 | public int EndAddress;
75 | public int UnwindData;
76 |
77 | public virtual int Size { get { throw new NotImplementedException(); } }
78 |
79 | public virtual int CompareTo(RuntimeFunctionEntry other)
80 | {
81 | return BeginAddress.CompareTo(other.BeginAddress);
82 | }
83 |
84 | public virtual void WriteTo(BinaryWriter writer)
85 | {
86 | throw new NotImplementedException();
87 | }
88 |
89 | public static int GetSize(ImageFileMachine arch)
90 | {
91 | if (arch == ImageFileMachine.ARM)
92 | {
93 | return ARMImageRuntimeFunctionEntry.GetSize();
94 | }
95 | else
96 | {
97 | return AMD64ImageRuntimeFunctionEntry.GetSize();
98 | }
99 | }
100 |
101 | public static RuntimeFunctionEntry ReadFrom(BinaryReader r, ImageFileMachine arch)
102 | {
103 | if (arch == ImageFileMachine.ARM)
104 | {
105 | return ARMImageRuntimeFunctionEntry.ReadFrom(r);
106 | }
107 | else
108 | {
109 | return AMD64ImageRuntimeFunctionEntry.ReadFrom(r);
110 | }
111 | }
112 | }
113 |
114 | public class ARMImageRuntimeFunctionEntry : RuntimeFunctionEntry
115 | {
116 | public static ARMImageRuntimeFunctionEntry ReadFrom(BinaryReader r)
117 | {
118 | ARMImageRuntimeFunctionEntry entry = new ARMImageRuntimeFunctionEntry();
119 | entry.BeginAddress = r.ReadInt32();
120 | entry.UnwindData = r.ReadInt32();
121 | return entry;
122 | }
123 | public static int GetSize() { return 8; }
124 |
125 | public override int Size { get { return 8; } }
126 | public override void WriteTo(BinaryWriter writer)
127 | {
128 | writer.Write(BeginAddress);
129 | writer.Write(UnwindData);
130 | }
131 | }
132 |
133 | public class AMD64ImageRuntimeFunctionEntry : RuntimeFunctionEntry
134 | {
135 | public static AMD64ImageRuntimeFunctionEntry ReadFrom(BinaryReader r)
136 | {
137 | AMD64ImageRuntimeFunctionEntry entry = new AMD64ImageRuntimeFunctionEntry();
138 | entry.BeginAddress = r.ReadInt32();
139 | entry.EndAddress = r.ReadInt32();
140 | entry.UnwindData = r.ReadInt32();
141 | return entry;
142 | }
143 | public static int GetSize() { return 12; }
144 |
145 | public override int Size { get { return 12; } }
146 | public override void WriteTo(BinaryWriter writer)
147 | {
148 | writer.Write(BeginAddress);
149 | writer.Write(EndAddress);
150 | writer.Write(UnwindData);
151 | }
152 | }
153 |
154 | public class PEReaderException : Exception
155 | {
156 | public PEReaderException(string message) : base(message) { }
157 | }
158 |
159 |
160 | ///
161 | /// A very basic PE reader that can extract a few useful pieces of information
162 | ///
163 | public class PEReader
164 | {
165 |
166 |
167 | // PE file
168 | IModuleReader m_peReader;
169 |
170 | // cached information from the PE file
171 | int peHeaderOffset = 0;
172 | int optionalHeaderDirectoryEntriesOffset = 0;
173 |
174 | // PE file contents starting from the PEHeaderOffset
175 | // 4 byte signature
176 | COFFFileHeader? coffHeader;
177 | // optional header standard fields
178 | // optional header additional fields
179 | OptionalHeaderDirectoryEntries? optionalHeaderDirectoryEntries;
180 | SectionHeader[] sectionHeaders;
181 | COR20Header? cor20header;
182 | CodeViewDebugData codeViewDebugData;
183 | RuntimeFunctionEntry[] m_pData;
184 |
185 | public PEReader(IModuleReader peReader)
186 | {
187 | m_peReader = peReader;
188 | }
189 |
190 | public PEReader(Stream peFileStream)
191 | {
192 | m_peReader = new StreamModuleReader(peFileStream);
193 | }
194 |
195 | public int TimeStamp
196 | {
197 | get
198 | {
199 | return ReadDwordAtFileOffset(PEHeaderOffset + 8);
200 | }
201 | }
202 |
203 | public int SizeOfImage
204 | {
205 | get
206 | {
207 | return ReadDwordAtFileOffset(PEHeaderOffset + 80);
208 | }
209 | }
210 |
211 | int PEHeaderOffset
212 | {
213 | get
214 | {
215 | if (peHeaderOffset == 0)
216 | {
217 | peHeaderOffset = ReadDwordAtFileOffset(0x3c);
218 | }
219 | return peHeaderOffset;
220 | }
221 | }
222 |
223 | int OptionalHeaderDirectoryEntriesOffset
224 | {
225 | get
226 | {
227 | if (optionalHeaderDirectoryEntriesOffset == 0)
228 | {
229 | int peOptionalHeaderOffset = PEHeaderOffset + 4 + PEFileConstants.SizeofCOFFFileHeader;
230 | PEMagic magic = (PEMagic) ReadWordAtFileOffset(peOptionalHeaderOffset);
231 | if (magic == PEMagic.PEMagic32)
232 | {
233 | optionalHeaderDirectoryEntriesOffset = peOptionalHeaderOffset + PEFileConstants.SizeofOptionalHeaderStandardFields32 +
234 | PEFileConstants.SizeofOptionalHeaderNTAdditionalFields32;
235 | }
236 | else
237 | {
238 | optionalHeaderDirectoryEntriesOffset = peOptionalHeaderOffset + PEFileConstants.SizeofOptionalHeaderStandardFields64 +
239 | PEFileConstants.SizeofOptionalHeaderNTAdditionalFields64;
240 | }
241 | }
242 | return optionalHeaderDirectoryEntriesOffset;
243 | }
244 | }
245 |
246 | int SectionHeadersOffset
247 | {
248 | get
249 | {
250 | return OptionalHeaderDirectoryEntriesOffset + PEFileConstants.SizeofOptionalHeaderDirectoriesEntries;
251 | }
252 | }
253 |
254 | public COFFFileHeader COFFFileHeader
255 | {
256 | get
257 | {
258 | if (!coffHeader.HasValue)
259 | {
260 | coffHeader = ReadCOFFFileHeader();
261 | }
262 | return coffHeader.Value;
263 | }
264 | }
265 |
266 | public OptionalHeaderDirectoryEntries OptionalHeaderDirectoryEntries
267 | {
268 | get
269 | {
270 | if (!optionalHeaderDirectoryEntries.HasValue)
271 | {
272 | optionalHeaderDirectoryEntries = ReadOptionalHeaderDirectoryEntries();
273 | }
274 | return optionalHeaderDirectoryEntries.Value;
275 | }
276 | }
277 |
278 | public SectionHeader[] SectionHeaders
279 | {
280 | get
281 | {
282 | if (sectionHeaders == null)
283 | {
284 | sectionHeaders = ReadSectionHeaders();
285 | }
286 | return sectionHeaders;
287 | }
288 | }
289 |
290 | public COR20Header Cor20Header
291 | {
292 | get
293 | {
294 | if (cor20header == null)
295 | {
296 | cor20header = ReadCOR20Header();
297 | }
298 | return cor20header.Value;
299 | }
300 | }
301 |
302 | COFFFileHeader ReadCOFFFileHeader()
303 | {
304 | byte[] bytes = new byte[PEFileConstants.SizeofCOFFFileHeader];
305 | ReadBytesAtFileOffset(bytes, PEHeaderOffset + 4);
306 | BinaryReader reader = new BinaryReader(new MemoryStream(bytes));
307 |
308 | COFFFileHeader header = new COFFFileHeader();
309 | header.Machine = reader.ReadUInt16();
310 | header.NumberOfSections = reader.ReadInt16();
311 | header.TimeDateStamp = reader.ReadInt32();
312 | header.PointerToSymbolTable = reader.ReadInt32();
313 | header.NumberOfSymbols = reader.ReadInt32();
314 | header.SizeOfOptionalHeader = reader.ReadInt16();
315 | header.Characteristics = reader.ReadUInt16();
316 | return header;
317 | }
318 |
319 | OptionalHeaderStandardFields ReadOptionalHeaderStandardFields32()
320 | {
321 | byte[] bytes = new byte[PEFileConstants.SizeofOptionalHeaderStandardFields32];
322 | ReadBytesAtFileOffset(bytes, PEHeaderOffset + 4 + PEFileConstants.SizeofCOFFFileHeader);
323 | BinaryReader reader = new BinaryReader(new MemoryStream(bytes));
324 |
325 | OptionalHeaderStandardFields header = new OptionalHeaderStandardFields();
326 | header.PEMagic = (PEMagic)reader.ReadUInt16();
327 | header.MajorLinkerVersion = reader.ReadByte();
328 | header.MinorLinkerVersion = reader.ReadByte();
329 | header.SizeOfCode = reader.ReadInt32();
330 | header.SizeOfInitializedData = reader.ReadInt32();
331 | header.SizeOfUninitializedData = reader.ReadInt32();
332 | header.RVAOfEntryPoint = reader.ReadInt32();
333 | header.BaseOfCode = reader.ReadInt32();
334 | header.BaseOfData = reader.ReadInt32();
335 | return header;
336 | }
337 |
338 | OptionalHeaderStandardFields ReadOptionalHeaderStandardFields64()
339 | {
340 | byte[] bytes = new byte[PEFileConstants.SizeofOptionalHeaderStandardFields64];
341 | ReadBytesAtFileOffset(bytes, PEHeaderOffset + 4 + PEFileConstants.SizeofCOFFFileHeader);
342 | BinaryReader reader = new BinaryReader(new MemoryStream(bytes));
343 |
344 | OptionalHeaderStandardFields header = new OptionalHeaderStandardFields();
345 | header.PEMagic = (PEMagic)reader.ReadUInt16();
346 | header.MajorLinkerVersion = reader.ReadByte();
347 | header.MinorLinkerVersion = reader.ReadByte();
348 | header.SizeOfCode = reader.ReadInt32();
349 | header.SizeOfInitializedData = reader.ReadInt32();
350 | header.SizeOfUninitializedData = reader.ReadInt32();
351 | header.RVAOfEntryPoint = reader.ReadInt32();
352 | header.BaseOfCode = reader.ReadInt32();
353 | return header;
354 | }
355 |
356 | OptionalHeaderDirectoryEntries ReadOptionalHeaderDirectoryEntries()
357 | {
358 | byte[] bytes = new byte[PEFileConstants.SizeofOptionalHeaderDirectoriesEntries];
359 | ReadBytesAtFileOffset(bytes, OptionalHeaderDirectoryEntriesOffset);
360 | BinaryReader reader = new BinaryReader(new MemoryStream(bytes));
361 |
362 | OptionalHeaderDirectoryEntries header = new OptionalHeaderDirectoryEntries();
363 | header.ExportTableDirectory.RelativeVirtualAddress = reader.ReadInt32();
364 | header.ExportTableDirectory.Size = reader.ReadUInt32();
365 | header.ImportTableDirectory.RelativeVirtualAddress = reader.ReadInt32();
366 | header.ImportTableDirectory.Size = reader.ReadUInt32();
367 | header.ResourceTableDirectory.RelativeVirtualAddress = reader.ReadInt32();
368 | header.ResourceTableDirectory.Size = reader.ReadUInt32();
369 | header.ExceptionTableDirectory.RelativeVirtualAddress = reader.ReadInt32();
370 | header.ExceptionTableDirectory.Size = reader.ReadUInt32();
371 | header.CertificateTableDirectory.RelativeVirtualAddress = reader.ReadInt32();
372 | header.CertificateTableDirectory.Size = reader.ReadUInt32();
373 | header.BaseRelocationTableDirectory.RelativeVirtualAddress = reader.ReadInt32();
374 | header.BaseRelocationTableDirectory.Size = reader.ReadUInt32();
375 | header.DebugTableDirectory.RelativeVirtualAddress = reader.ReadInt32();
376 | header.DebugTableDirectory.Size = reader.ReadUInt32();
377 | header.CopyrightTableDirectory.RelativeVirtualAddress = reader.ReadInt32();
378 | header.CopyrightTableDirectory.Size = reader.ReadUInt32();
379 | header.GlobalPointerTableDirectory.RelativeVirtualAddress = reader.ReadInt32();
380 | header.GlobalPointerTableDirectory.Size = reader.ReadUInt32();
381 | header.ThreadLocalStorageTableDirectory.RelativeVirtualAddress = reader.ReadInt32();
382 | header.ThreadLocalStorageTableDirectory.Size = reader.ReadUInt32();
383 | header.LoadConfigTableDirectory.RelativeVirtualAddress = reader.ReadInt32();
384 | header.LoadConfigTableDirectory.Size = reader.ReadUInt32();
385 | header.BoundImportTableDirectory.RelativeVirtualAddress = reader.ReadInt32();
386 | header.BoundImportTableDirectory.Size = reader.ReadUInt32();
387 | header.ImportAddressTableDirectory.RelativeVirtualAddress = reader.ReadInt32();
388 | header.ImportAddressTableDirectory.Size = reader.ReadUInt32();
389 | header.DelayImportTableDirectory.RelativeVirtualAddress = reader.ReadInt32();
390 | header.DelayImportTableDirectory.Size = reader.ReadUInt32();
391 | header.COR20HeaderTableDirectory.RelativeVirtualAddress = reader.ReadInt32();
392 | header.COR20HeaderTableDirectory.Size = reader.ReadUInt32();
393 | header.ReservedDirectory.RelativeVirtualAddress = reader.ReadInt32();
394 | header.ReservedDirectory.Size = reader.ReadUInt32();
395 | return header;
396 | }
397 |
398 | List ReadDebugDirectories()
399 | {
400 | // there might not be a debug directory, in which case return an empty list
401 | if (OptionalHeaderDirectoryEntries.DebugTableDirectory.RelativeVirtualAddress == 0)
402 | return new List();
403 |
404 | BinaryReader reader;
405 | if (!TryDirectoryToReader(OptionalHeaderDirectoryEntries.DebugTableDirectory, out reader))
406 | {
407 | throw new PEReaderException("Unable to load DebugDirectory from PE");
408 | }
409 | int countDirectories = (int) (OptionalHeaderDirectoryEntries.DebugTableDirectory.Size / PEFileConstants.SizeofDebugDirectory);
410 | List debugDirectories = new List();
411 | for (int i = 0; i < countDirectories; i++)
412 | {
413 | DebugDirectory debugDir = new DebugDirectory();
414 | debugDir.Characteristics = reader.ReadUInt32();
415 | debugDir.TimeDateStamp = reader.ReadUInt32();
416 | debugDir.MajorVersion = reader.ReadUInt16();
417 | debugDir.MinorVersion = reader.ReadUInt16();
418 | debugDir.Type = (ImageDebugType)reader.ReadUInt32();
419 | debugDir.SizeOfData = reader.ReadUInt32();
420 | debugDir.AddressOfRawData = reader.ReadUInt32();
421 | debugDir.PointerToRawData = reader.ReadUInt32();
422 | debugDirectories.Add(debugDir);
423 | }
424 |
425 | return debugDirectories;
426 | }
427 |
428 | CodeViewDebugData ReadCodeViewDebugData(DebugDirectory debugDir)
429 | {
430 | Debug.Assert(debugDir.Type == ImageDebugType.CodeView);
431 | //Console.WriteLine("ReadCodeViewDebugData: Debug directory with AddressOfRawData 0x" + debugDir.AddressOfRawData.ToString("x"));
432 |
433 | // sanity check read size
434 | if (debugDir.SizeOfData > 1000)
435 | {
436 | Console.WriteLine("ReadCodeViewDebugData: SizeOfData > 1000 - assuming bad data");
437 | return null;
438 | }
439 |
440 | BinaryReader reader;
441 | if (!TryReadAtRVA((int)debugDir.AddressOfRawData, (int)debugDir.SizeOfData, out reader))
442 | {
443 | Console.WriteLine("ReadCodeViewDebugData: Unable to read rva=0x" + debugDir.AddressOfRawData.ToString("x") + " size=" +debugDir.SizeOfData);
444 | return null;
445 | }
446 | int signature = reader.ReadInt32();
447 | if (signature != PEFileConstants.CodeViewSignature)
448 | {
449 | Console.WriteLine("ReadCodeViewDebugData: Invalid codeview signature Expected: " + PEFileConstants.CodeViewSignature + " Actual: " + signature);
450 | return null;
451 | }
452 | CodeViewDebugData codeView = new CodeViewDebugData();
453 | codeView.Signature = new Guid(reader.ReadBytes(16));
454 | codeView.Age = (int)reader.ReadUInt32();
455 | codeView.PdbPath = reader.ReadNullTerminatedString(Encoding.UTF8);
456 | //Console.WriteLine("ReadCodeViewDebugData: PdbPath=" + codeView.PdbPath + " Age=" + codeView.Age + " Signature="+codeView.Signature);
457 | return codeView;
458 | }
459 |
460 | public CodeViewDebugData CodeViewDebugData
461 | {
462 | get
463 | {
464 | if (codeViewDebugData == null)
465 | {
466 | List debugDirs = ReadDebugDirectories();
467 | // Console.WriteLine("CodeViewDebugData: Found " + debugDirs.Count + " debug dirs");
468 | foreach (DebugDirectory dir in debugDirs)
469 | {
470 | if (dir.Type == ImageDebugType.CodeView)
471 | {
472 | // Console.WriteLine("CodeViewDebugData: Debug directory for 0x" + dir.AddressOfRawData.ToString("x") + " is code view");
473 | codeViewDebugData = ReadCodeViewDebugData(dir);
474 | }
475 | else
476 | {
477 | // Console.WriteLine("CodeViewDebugData: Debug directory for 0x" + dir.AddressOfRawData.ToString("x") + " is not code view");
478 | }
479 | }
480 | }
481 | return codeViewDebugData;
482 | }
483 | }
484 |
485 | RuntimeFunctionEntry[] PData
486 | {
487 | get
488 | {
489 | if (m_pData == null)
490 | {
491 | int rfeSize = RuntimeFunctionEntry.GetSize((ImageFileMachine)this.COFFFileHeader.Machine);
492 | int countEntries = (int)OptionalHeaderDirectoryEntries.ExceptionTableDirectory.Size / rfeSize;
493 | List entries = new List();
494 | int rva = OptionalHeaderDirectoryEntries.ExceptionTableDirectory.RelativeVirtualAddress;
495 | for (int i = 0; i < countEntries; i++, rva += rfeSize)
496 | {
497 | // in to read from dumps which may have gaps in the collected memory we read
498 | // each RuntimeFunctionEntry individually. Even if some are missing we will
499 | // get the rest
500 | BinaryReader pdataReader;
501 | if (TryReadAtRVA(rva, rfeSize, out pdataReader))
502 | {
503 | entries.Add(RuntimeFunctionEntry.ReadFrom(pdataReader, (ImageFileMachine)this.COFFFileHeader.Machine));
504 | }
505 | }
506 | m_pData = entries.ToArray();
507 | }
508 | return m_pData;
509 | }
510 | }
511 |
512 | public GetRuntimeFunctionEntryResult GetRuntimeFunctionEntry(int functionRVA, out RuntimeFunctionEntry entry)
513 | {
514 | RuntimeFunctionEntry[] entries = PData;
515 | entry = null;
516 | if (entries == null)
517 | return GetRuntimeFunctionEntryResult.MissingMemory;
518 |
519 | RuntimeFunctionEntry targetEntry = new RuntimeFunctionEntry();
520 | targetEntry.BeginAddress = functionRVA;
521 | int index = Array.BinarySearch(entries, targetEntry);
522 |
523 | if (index >= 0) // found an entry whose start address matches exactly
524 | entry = entries[index];
525 | else if (~index > 0)
526 | {
527 | // ~index is the index of the first entry larger than targetEntry
528 | // ~index could be >= entries.Length, in which case there was no entry larger
529 | // than targetEntry
530 | int possibleEnclosingIndex = Math.Min(~index, entries.Length) - 1;
531 | if (entries[possibleEnclosingIndex].BeginAddress <= functionRVA)
532 | entry = entries[possibleEnclosingIndex];
533 | }
534 |
535 | if (entry == null)
536 | return GetRuntimeFunctionEntryResult.DoesNotExist;
537 |
538 | if ((ImageFileMachine)this.COFFFileHeader.Machine == ImageFileMachine.AMD64 &&
539 | (entry.UnwindData & 0x1) == 0x1) // chained data
540 | {
541 | int parentEntryRva = entry.UnwindData & ~0x1;
542 | int basePDataRva = OptionalHeaderDirectoryEntries.ExceptionTableDirectory.RelativeVirtualAddress;
543 | int parentIndex = (parentEntryRva - basePDataRva) /
544 | RuntimeFunctionEntry.GetSize((ImageFileMachine)this.COFFFileHeader.Machine);
545 |
546 | if (parentIndex < 0 || parentIndex >= entries.Length)
547 | return GetRuntimeFunctionEntryResult.DoesNotExist; // bad pdata?
548 |
549 | entry = entries[parentIndex];
550 | }
551 | return GetRuntimeFunctionEntryResult.Found;
552 | }
553 |
554 | COR20Header ReadCOR20Header()
555 | {
556 | BinaryReader reader;
557 | if(!TryDirectoryToReader(OptionalHeaderDirectoryEntries.COR20HeaderTableDirectory, out reader))
558 | {
559 | throw new PEReaderException("Unable to load Cor20HeaderTableDirectory from PE");
560 | }
561 |
562 | COR20Header header = new COR20Header();
563 | header.CountBytes = reader.ReadInt32();
564 | header.MajorRuntimeVersion = reader.ReadUInt16();
565 | header.MinorRuntimeVersion = reader.ReadUInt16();
566 | header.MetaDataDirectory.RelativeVirtualAddress = reader.ReadInt32();
567 | header.MetaDataDirectory.Size = reader.ReadUInt32();
568 | header.COR20Flags = (COR20Flags)reader.ReadUInt32();
569 | header.EntryPointTokenOrRVA = reader.ReadUInt32();
570 | header.ResourcesDirectory.RelativeVirtualAddress = reader.ReadInt32();
571 | header.ResourcesDirectory.Size = reader.ReadUInt32();
572 | header.StrongNameSignatureDirectory.RelativeVirtualAddress = reader.ReadInt32();
573 | header.StrongNameSignatureDirectory.Size = reader.ReadUInt32();
574 | header.CodeManagerTableDirectory.RelativeVirtualAddress = reader.ReadInt32();
575 | header.CodeManagerTableDirectory.Size = reader.ReadUInt32();
576 | header.VtableFixupsDirectory.RelativeVirtualAddress = reader.ReadInt32();
577 | header.ExportAddressTableJumpsDirectory.Size = reader.ReadUInt32();
578 | header.ExportAddressTableJumpsDirectory.RelativeVirtualAddress = reader.ReadInt32();
579 | header.ExportAddressTableJumpsDirectory.Size = reader.ReadUInt32();
580 | header.ManagedNativeHeaderDirectory.RelativeVirtualAddress = reader.ReadInt32();
581 | header.ManagedNativeHeaderDirectory.Size = reader.ReadUInt32();
582 | return header;
583 | }
584 |
585 | public PEExport[] ReadExports()
586 | {
587 | BinaryReader reader;
588 | if (!TryDirectoryToReader(OptionalHeaderDirectoryEntries.ExportTableDirectory, out reader))
589 | {
590 | throw new PEReaderException("Unable to load ExportDirectory from PE");
591 | }
592 | ExportDirectory ed = new ExportDirectory();
593 | ed.ExportFlags = reader.ReadUInt32();
594 | ed.DateTimeStamp = reader.ReadUInt32();
595 | ed.MajorVersion = reader.ReadUInt16();
596 | ed.MinorVersion = reader.ReadUInt16();
597 | ed.NameRva = reader.ReadUInt32();
598 | ed.OrdinalBase = reader.ReadUInt32();
599 | ed.AddressTablesEntries = reader.ReadUInt32();
600 | ed.NumberNamePointers = reader.ReadUInt32();
601 | ed.ExportAddressTableRva = reader.ReadUInt32();
602 | ed.NamePointerRva = reader.ReadUInt32();
603 | ed.OrdinalTableRva = reader.ReadUInt32();
604 |
605 | // read the export name pointer table
606 | reader = null;
607 | if (!TryReadAtRVA((int)ed.NamePointerRva, (int)ed.NumberNamePointers * 4, out reader))
608 | {
609 | throw new PEReaderException("Unable to read Export NamePointer table from PE");
610 | }
611 | int[] nameRvas = new int[ed.NumberNamePointers];
612 | for (int i = 0; i < ed.NumberNamePointers; i++)
613 | {
614 | nameRvas[i] = reader.ReadInt32();
615 | }
616 |
617 | // read the exports name table
618 | PEExport[] exports = new PEExport[ed.NumberNamePointers];
619 | for (int i = 0; i < ed.NumberNamePointers; i++)
620 | {
621 | // making some simplifying assumptions that all names are < 100 chars and
622 | // that a 100 char read won't go off then end of a mapped section. I'm not
623 | // sure if either is really true.
624 | reader = null;
625 | if (!TryReadAtRVA(nameRvas[i], 100, out reader))
626 | {
627 | throw new PEReaderException("Unable to read Export name from PE");
628 | }
629 | exports[i].Name = reader.ReadNullTerminatedString(Encoding.ASCII);
630 | }
631 |
632 | // read the export ordinal table
633 | reader = null;
634 | if (!TryReadAtRVA((int)ed.OrdinalTableRva, (int)ed.NumberNamePointers * 2, out reader))
635 | {
636 | throw new PEReaderException("Unable to read Export OridnalTable from PE");
637 | }
638 | for (int i = 0; i < ed.NumberNamePointers; i++)
639 | {
640 | //This doesn't match up with what the PE spec describes, but it does seem to produce
641 | //the right data empirically
642 | //The spec claims that value encoded in the PE is the ordinal, and that you need to
643 | //subtract the ordinal base in order to get an index into the address table
644 | //In practice it seems that the value encoded in the PE is the index into the address
645 | //table and you need to add ordinal base in order to get the ordinal
646 | exports[i].Ordinal = (int)(reader.ReadUInt16() + ed.OrdinalBase);
647 | }
648 |
649 | // read the export address table
650 | reader = null;
651 | if (!TryReadAtRVA((int)ed.ExportAddressTableRva, (int)ed.AddressTablesEntries * 4, out reader))
652 | {
653 | throw new PEReaderException("Unable to read Export OridnalTable from PE");
654 | }
655 | int[] exportAddresses = new int[ed.AddressTablesEntries];
656 | for (int i = 0; i < ed.AddressTablesEntries; i++)
657 | {
658 | exportAddresses[i] = reader.ReadInt32();
659 | }
660 |
661 | //populate export addresses
662 | for (int i = 0; i < exports.Length; i++)
663 | {
664 | int ord = (int)(exports[i].Ordinal - ed.OrdinalBase);
665 | if (ord >= 0 && ord < exportAddresses.Length)
666 | exports[i].Rva = exportAddresses[ord];
667 | }
668 | return exports;
669 | }
670 |
671 | SectionHeader[] ReadSectionHeaders()
672 | {
673 | int numberOfSections = COFFFileHeader.NumberOfSections;
674 | byte[] bytes = new byte[PEFileConstants.SizeofSectionHeader * numberOfSections];
675 | ReadBytesAtFileOffset(bytes, SectionHeadersOffset);
676 | BinaryReader reader = new BinaryReader(new MemoryStream(bytes));
677 |
678 | SectionHeader[] sectionHeaderArray = new SectionHeader[numberOfSections];
679 | for (int i = 0; i < numberOfSections; ++i)
680 | {
681 | sectionHeaderArray[i].Name = Encoding.UTF8.GetString(reader.ReadBytes(PEFileConstants.SizeofSectionName));
682 | sectionHeaderArray[i].VirtualSize = reader.ReadInt32();
683 | sectionHeaderArray[i].VirtualAddress = reader.ReadInt32();
684 | sectionHeaderArray[i].SizeOfRawData = reader.ReadInt32();
685 | sectionHeaderArray[i].OffsetToRawData = reader.ReadInt32();
686 | sectionHeaderArray[i].RVAToRelocations = reader.ReadInt32();
687 | sectionHeaderArray[i].PointerToLineNumbers = reader.ReadInt32();
688 | sectionHeaderArray[i].NumberOfRelocations = reader.ReadUInt16();
689 | sectionHeaderArray[i].NumberOfLineNumbers = reader.ReadUInt16();
690 | sectionHeaderArray[i].SectionCharacteristics = reader.ReadUInt32();
691 | }
692 | return sectionHeaderArray;
693 | }
694 |
695 | bool TryDirectoryToReader(DirectoryEntry directory, out BinaryReader reader)
696 | {
697 | return TryReadAtRVA(directory.RelativeVirtualAddress, (int)directory.Size, out reader);
698 | }
699 |
700 | public bool TryReadAtRVA(int rva, int size, out byte[] data)
701 | {
702 | data = null;
703 | // disk format requires RVA->file offset mapping
704 | if (m_peReader.Format == PEStreamFormat.DiskFormat)
705 | {
706 | foreach (SectionHeader sectionHeaderIter in SectionHeaders)
707 | {
708 | if (sectionHeaderIter.VirtualAddress <= rva && rva < sectionHeaderIter.VirtualAddress + sectionHeaderIter.VirtualSize)
709 | {
710 | int relativeOffset = rva - sectionHeaderIter.VirtualAddress;
711 | data = new byte[size];
712 | return TryReadBytesAtFileOffset(data, sectionHeaderIter.OffsetToRawData + relativeOffset);
713 | }
714 | }
715 |
716 | // although its not part of the section table, the OS does map the initial file headers into the address space and it is
717 | // reasonable to refer to them with RVAs. I'm not certain exactly what the OS maps in, but lets assume it includes everything
718 | // up through the section tables at least.
719 | int endSectionTablesOffset = SectionHeadersOffset + PEFileConstants.SizeofSectionHeader * COFFFileHeader.NumberOfSections;
720 | if (rva + size <= endSectionTablesOffset)
721 | {
722 | data = new byte[size];
723 | return TryReadBytesAtFileOffset(data, rva);
724 | }
725 |
726 | return false;
727 | }
728 | // in memory format can use RVA offsets directly
729 | else
730 | {
731 | data = new byte[size];
732 | return TryReadBytesAtFileOffset(data, rva);
733 | }
734 | }
735 |
736 | public bool TryReadAtRVA(int rva, int size, out BinaryReader reader)
737 | {
738 | byte[] data;
739 | if (TryReadAtRVA(rva, size, out data))
740 | {
741 | reader = new BinaryReader(new MemoryStream(data));
742 | return true;
743 | }
744 | else
745 | {
746 | reader = null;
747 | return false;
748 | }
749 | }
750 |
751 | public bool IsManagedBinary
752 | {
753 | get
754 | {
755 | DirectoryEntry de = OptionalHeaderDirectoryEntries.COR20HeaderTableDirectory;
756 | return de.RelativeVirtualAddress != 0;
757 | }
758 | }
759 |
760 | int ReadDwordAtFileOffset(int fileOffset)
761 | {
762 | byte[] dword = new byte[4];
763 | ReadBytesAtFileOffset(dword, fileOffset);
764 | return BitConverter.ToInt32(dword, 0);
765 | }
766 |
767 | ushort ReadWordAtFileOffset(int fileOffset)
768 | {
769 | byte[] word = new byte[2];
770 | ReadBytesAtFileOffset(word, fileOffset);
771 | return BitConverter.ToUInt16(word, 0);
772 | }
773 |
774 | bool TryReadBytesAtFileOffset(byte[] bytes, int fileOffset)
775 | {
776 | return (bytes.Length == m_peReader.ReadAtOffset(bytes, fileOffset));
777 | }
778 |
779 | void ReadBytesAtFileOffset(byte[] bytes, int fileOffset)
780 | {
781 | if (bytes.Length != m_peReader.ReadAtOffset(bytes, fileOffset))
782 | {
783 | throw new PEReaderException("Unable to read at 0x" + fileOffset.ToString("x") + ", 0x" + bytes.Length.ToString("x") + " bytes");
784 | }
785 | }
786 | }
787 | internal static class BinaryReaderExtensions
788 | {
789 | // BinaryReader reads length prefixed strings but not null-terminated ones
790 | public static string ReadNullTerminatedString(this BinaryReader reader, Encoding encoding)
791 | {
792 | // make sure we are scanning something where a single 0 byte means end of string
793 | // although UTF8 does have code points that encode with more than one byte, byte 0 is never used except
794 | // to encode code point 0.
795 | if (encoding != Encoding.UTF8 && encoding != Encoding.ASCII)
796 | throw new NotSupportedException("PEReader.ReadNullTerminatedString: Only UTF8 or ascii are supported for now");
797 | List stringBytes = new List();
798 | byte nextByte = reader.ReadByte();
799 | while (nextByte != 0)
800 | {
801 | stringBytes.Add(nextByte);
802 | nextByte = reader.ReadByte();
803 | }
804 |
805 | return encoding.GetString(stringBytes.ToArray(), 0, stringBytes.Count);
806 | }
807 | }
808 | internal static class PEFileConstants
809 | {
810 | internal const ushort DosSignature = 0x5A4D; // MZ
811 | internal const int PESignatureOffsetLocation = 0x3C;
812 | internal const uint PESignature = 0x00004550; // PE00
813 | internal const int BasicPEHeaderSize = PEFileConstants.PESignatureOffsetLocation;
814 | internal const int SizeofCOFFFileHeader = 20;
815 | internal const int SizeofOptionalHeaderStandardFields32 = 28;
816 | internal const int SizeofOptionalHeaderStandardFields64 = 24;
817 | internal const int SizeofOptionalHeaderNTAdditionalFields32 = 68;
818 | internal const int SizeofOptionalHeaderNTAdditionalFields64 = 88;
819 | internal const int NumberofOptionalHeaderDirectoryEntries = 16;
820 | internal const int SizeofOptionalHeaderDirectoriesEntries = 128;
821 | internal const int SizeofSectionHeader = 40;
822 | internal const int SizeofSectionName = 8;
823 | internal const int SizeofResourceDirectory = 16;
824 | internal const int SizeofResourceDirectoryEntry = 8;
825 | internal const int SizeofDebugDirectory = 28;
826 | internal const int CodeViewSignature = 0x53445352; // "RSDS" in little endian format
827 | }
828 |
829 | public struct COFFFileHeader
830 | {
831 | public ushort Machine;
832 | public short NumberOfSections;
833 | public int TimeDateStamp;
834 | public int PointerToSymbolTable;
835 | public int NumberOfSymbols;
836 | public short SizeOfOptionalHeader;
837 | public ushort Characteristics;
838 | }
839 |
840 | public struct OptionalHeaderStandardFields
841 | {
842 | public PEMagic PEMagic;
843 | public byte MajorLinkerVersion;
844 | public byte MinorLinkerVersion;
845 | public int SizeOfCode;
846 | public int SizeOfInitializedData;
847 | public int SizeOfUninitializedData;
848 | public int RVAOfEntryPoint;
849 | public int BaseOfCode;
850 | public int BaseOfData;
851 | }
852 |
853 | public struct DirectoryEntry
854 | {
855 | public int RelativeVirtualAddress;
856 | public uint Size;
857 | }
858 |
859 | public struct OptionalHeaderDirectoryEntries
860 | {
861 | public DirectoryEntry ExportTableDirectory;
862 | public DirectoryEntry ImportTableDirectory;
863 | public DirectoryEntry ResourceTableDirectory;
864 | public DirectoryEntry ExceptionTableDirectory;
865 | public DirectoryEntry CertificateTableDirectory;
866 | public DirectoryEntry BaseRelocationTableDirectory;
867 | public DirectoryEntry DebugTableDirectory;
868 | public DirectoryEntry CopyrightTableDirectory;
869 | public DirectoryEntry GlobalPointerTableDirectory;
870 | public DirectoryEntry ThreadLocalStorageTableDirectory;
871 | public DirectoryEntry LoadConfigTableDirectory;
872 | public DirectoryEntry BoundImportTableDirectory;
873 | public DirectoryEntry ImportAddressTableDirectory;
874 | public DirectoryEntry DelayImportTableDirectory;
875 | public DirectoryEntry COR20HeaderTableDirectory;
876 | public DirectoryEntry ReservedDirectory;
877 | }
878 |
879 | public struct SectionHeader
880 | {
881 | public string Name;
882 | public int VirtualSize;
883 | public int VirtualAddress;
884 | public int SizeOfRawData;
885 | public int OffsetToRawData;
886 | public int RVAToRelocations;
887 | public int PointerToLineNumbers;
888 | public ushort NumberOfRelocations;
889 | public ushort NumberOfLineNumbers;
890 | public uint SectionCharacteristics;
891 | }
892 |
893 | internal enum ImageDebugType : uint
894 | {
895 | Unknown = 0,
896 | Coff = 1,
897 | CodeView = 2,
898 | Fpo = 3,
899 | Misc = 4,
900 | Exception = 5,
901 | Fixup = 6,
902 | Borland = 9
903 | }
904 |
905 | internal struct DebugDirectory
906 | {
907 | public uint Characteristics;
908 | public uint TimeDateStamp;
909 | public ushort MajorVersion;
910 | public ushort MinorVersion;
911 | public ImageDebugType Type;
912 | public uint SizeOfData;
913 | public uint AddressOfRawData;
914 | public uint PointerToRawData;
915 | }
916 |
917 | public class CodeViewDebugData
918 | {
919 | public Guid Signature;
920 | public int Age;
921 | public string PdbPath;
922 | }
923 |
924 | public enum COR20Flags : uint
925 | {
926 | ILOnly = 0x00000001,
927 | Bit32Required = 0x00000002,
928 | ILLibrary = 0x00000004,
929 | StrongNameSigned = 0x00000008,
930 | NativeEntryPoint = 0x00000010,
931 | TrackDebugData = 0x00010000,
932 | }
933 |
934 | public enum PEMagic : ushort
935 | {
936 | PEMagic32 = 0x010B,
937 | PEMagic64 = 0x020B,
938 | }
939 |
940 |
941 |
942 | public struct COR20Header
943 | {
944 | public int CountBytes;
945 | public ushort MajorRuntimeVersion;
946 | public ushort MinorRuntimeVersion;
947 | public DirectoryEntry MetaDataDirectory;
948 | public COR20Flags COR20Flags;
949 | public uint EntryPointTokenOrRVA;
950 | public DirectoryEntry ResourcesDirectory;
951 | public DirectoryEntry StrongNameSignatureDirectory;
952 | public DirectoryEntry CodeManagerTableDirectory;
953 | public DirectoryEntry VtableFixupsDirectory;
954 | public DirectoryEntry ExportAddressTableJumpsDirectory;
955 | public DirectoryEntry ManagedNativeHeaderDirectory;
956 | }
957 |
958 | public class ImageImportDescriptor
959 | {
960 | public const uint Size = 4 * 5;
961 | public uint Characteristics { get; private set; }
962 | public uint OriginalFirstThunk { get; private set; }
963 | public uint TimeDateStamp { get; private set; }
964 | public uint ForwarderChain { get; private set; }
965 | public uint Name { get; private set; }
966 | public uint FirstThunk { get; private set; }
967 | public ImageImportDescriptor(BinaryReader br)
968 | {
969 | this.Characteristics = br.ReadUInt32();
970 | if (this.Characteristics != 0)
971 | {
972 | this.OriginalFirstThunk = this.Characteristics;
973 | this.TimeDateStamp = br.ReadUInt32();
974 | this.ForwarderChain = br.ReadUInt32();
975 | this.Name = br.ReadUInt32();
976 | this.FirstThunk = br.ReadUInt32();
977 | }
978 | else
979 | {
980 | this.OriginalFirstThunk = 0;
981 | this.TimeDateStamp = 0;
982 | this.ForwarderChain = 0;
983 | this.Name = 0;
984 | this.FirstThunk = 0;
985 | }
986 | }
987 | }
988 |
989 | struct ExportDirectory
990 | {
991 | public uint ExportFlags;
992 | public uint DateTimeStamp;
993 | public ushort MajorVersion;
994 | public ushort MinorVersion;
995 | public uint NameRva;
996 | public uint OrdinalBase;
997 | public uint AddressTablesEntries;
998 | public uint NumberNamePointers;
999 | public uint ExportAddressTableRva;
1000 | public uint NamePointerRva;
1001 | public uint OrdinalTableRva;
1002 | }
1003 |
1004 | public struct PEExport
1005 | {
1006 | public string Name;
1007 | public int Ordinal;
1008 | public int Rva;
1009 | }
1010 |
1011 | [Flags]
1012 | public enum ImageFileMachine : int
1013 | {
1014 | X86 = 0x014c,
1015 | AMD64 = 0x8664,
1016 | IA64 = 0x0200,
1017 | ARM = 0x01c4, // IMAGE_FILE_MACHINE_ARMNT
1018 | }
1019 |
1020 | public enum Platform
1021 | {
1022 | None = 0,
1023 | X86 = 1,
1024 | AMD64 = 2,
1025 | IA64 = 3,
1026 | ARM = 4,
1027 | }
1028 |
1029 | ///
1030 | /// Describes the ProcessorArchitecture in a SYSTEM_INFO field.
1031 | /// This can also be reported by a dump file.
1032 | ///
1033 | public enum ProcessorArchitecture : ushort
1034 | {
1035 | PROCESSOR_ARCHITECTURE_INTEL = 0,
1036 | PROCESSOR_ARCHITECTURE_MIPS = 1,
1037 | PROCESSOR_ARCHITECTURE_ALPHA = 2,
1038 | PROCESSOR_ARCHITECTURE_PPC = 3,
1039 | PROCESSOR_ARCHITECTURE_SHX = 4,
1040 | PROCESSOR_ARCHITECTURE_ARM = 5,
1041 | PROCESSOR_ARCHITECTURE_IA64 = 6,
1042 | PROCESSOR_ARCHITECTURE_ALPHA64 = 7,
1043 | PROCESSOR_ARCHITECTURE_MSIL = 8,
1044 | PROCESSOR_ARCHITECTURE_AMD64 = 9,
1045 | PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 = 10,
1046 | }
1047 |
1048 |
1049 | }
1050 |
--------------------------------------------------------------------------------