├── 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 | --------------------------------------------------------------------------------