From 425667e640a6881dfc6e994ca2d21bc714e10347 Mon Sep 17 00:00:00 2001 From: dev747368 <48332326+dev747368@users.noreply.github.com> Date: Tue, 21 Jul 2020 18:34:35 -0400 Subject: [PATCH 1/9] GP-42 Initial implementation of Pdb symbol store / symbol servers --- GPL/CabExtract/build.gradle | 4 + .../data/PDB_SYMBOL_SERVER_URLS.pdburl | 7 +- .../help/topics/ImporterPlugin/load_pdb.html | 156 --- .../ghidra/app/util/bin/BinaryReader.java | 47 +- .../app/util/bin/format/pdb/PdbFactory.java | 53 - .../app/util/bin/format/pdb/PdbInfo.java | 63 ++ .../util/bin/format/pdb/PdbInfoCodeView.java | 113 +++ .../util/bin/format/pdb/PdbInfoDotNet.java | 131 +++ .../bin/format/pdb/PdbInfoDotNetIface.java | 33 - .../app/util/bin/format/pdb/PdbInfoIface.java | 32 - .../bin/format/pe/DebugDataDirectory.java | 8 +- .../bin/format/pe/debug/DebugCodeView.java | 28 +- .../app/util/datatype/microsoft/GUID.java | 124 ++- .../util/opinion/AbstractPeDebugLoader.java | 54 +- Ghidra/Features/PDB/certification.manifest | 21 +- .../PdbExamplePrescript.java} | 33 +- .../PdbSymbolServerExamplePrescript.java | 53 + .../PDB/src/global/docs/README_PDB.html | 2 +- .../PDB/src/main/help/help/TOC_Source.xml | 4 +- .../main/help/help/topics/Pdb/LoadPDBNew.html | 226 +++++ .../PDB/src/main/help/help/topics/Pdb/PDB.htm | 130 ++- .../help/topics/Pdb/download_pdb_file.html | 184 ---- .../images/KnownSymbolServerURLsDialog.png | Bin 14100 -> 0 bytes .../images/LoadPdb_Advanced_NeedsConfig.png | Bin 0 -> 46293 bytes .../images/LoadPdb_Advanced_Screenshot.png | Bin 0 -> 81637 bytes .../Pdb/images/LoadPdb_Initial_Screenshot.png | Bin 0 -> 31547 bytes .../help/topics/Pdb/images/PdbOrXmlDialog.png | Bin 9684 -> 0 bytes .../Pdb/images/PeSpecifiedPathDialog.png | Bin 8995 -> 0 bytes .../help/help/topics/Pdb/images/Plus2.png | Bin 0 -> 752 bytes .../help/topics/Pdb/images/SuccessDialog.png | Bin 14850 -> 0 bytes .../SymbolServerConfig_AddButtonMenu.png | Bin 0 -> 10777 bytes .../images/SymbolServerConfig_Screenshot.png | Bin 0 -> 14525 bytes .../Pdb/images/SymbolServerURLDialog.png | Bin 11146 -> 0 bytes .../main/help/help/topics/Pdb/images/disk.png | Bin 0 -> 620 bytes .../main/help/help/topics/Pdb/images/down.png | Bin 0 -> 192 bytes .../help/help/topics/Pdb/images/error.png | Bin 0 -> 1150 bytes .../help/help/topics/Pdb/images/reload3.png | Bin 0 -> 979 bytes .../main/help/help/topics/Pdb/images/up.png | Bin 0 -> 193 bytes .../app/plugin/core/analysis/PdbAnalyzer.java | 150 +-- .../core/analysis/PdbAnalyzerCommon.java | 182 ++++ .../core/analysis/PdbUniversalAnalyzer.java | 173 +--- .../app/util/bin/format/pdb/PdbInfo.java | 90 -- .../util/bin/format/pdb/PdbInfoDotNet.java | 89 -- .../app/util/bin/format/pdb/PdbParser.java | 347 +------ .../format/pdb2/pdbreader/PdbIdentifiers.java | 35 +- .../main/java/pdb/AskPdbOptionsDialog.java | 128 --- .../src/main/java/pdb/AskPdbUrlDialog.java | 230 ----- .../PDB/src/main/java/pdb/LoadPdbTask.java | 40 +- .../PDB/src/main/java/pdb/PdbInitializer.java | 31 - .../PDB/src/main/java/pdb/PdbPlugin.java | 226 +++-- .../main/java/pdb/PdbSymbolServerPlugin.java | 856 ---------------- .../PDB/src/main/java/pdb/PdbUtils.java | 117 +++ .../PDB/src/main/java/pdb/URLChoice.java | 34 - .../symbolserver/AbstractSymbolServer.java | 135 +++ .../symbolserver/DisabledSymbolServer.java | 127 +++ .../java/pdb/symbolserver/FindOption.java | 61 ++ .../pdb/symbolserver/HttpSymbolServer.java | 150 +++ .../pdb/symbolserver/LocalSymbolStore.java | 389 ++++++++ .../pdb/symbolserver/SameDirSymbolStore.java | 164 +++ .../java/pdb/symbolserver/SymbolFileInfo.java | 274 +++++ .../pdb/symbolserver/SymbolFileLocation.java | 114 +++ .../java/pdb/symbolserver/SymbolServer.java | 110 ++ .../symbolserver/SymbolServerInputStream.java | 60 ++ .../SymbolServerInstanceCreatorContext.java | 64 ++ .../SymbolServerInstanceCreatorRegistry.java | 220 ++++ .../pdb/symbolserver/SymbolServerService.java | 288 ++++++ .../java/pdb/symbolserver/SymbolStore.java | 91 ++ .../pdb/symbolserver/ui/ConfigPdbDialog.java | 79 ++ .../pdb/symbolserver/ui/FilePromptDialog.java | 195 ++++ .../pdb/symbolserver/ui/LoadPdbDialog.java | 942 ++++++++++++++++++ .../pdb/symbolserver/ui/SymbolFilePanel.java | 182 ++++ .../pdb/symbolserver/ui/SymbolFileRow.java | 53 + .../symbolserver/ui/SymbolFileTableModel.java | 289 ++++++ .../symbolserver/ui/SymbolServerPanel.java | 594 +++++++++++ .../pdb/symbolserver/ui/SymbolServerRow.java | 76 ++ .../ui/SymbolServerTableModel.java | 309 ++++++ .../ui/WellKnownSymbolServerLocation.java | 112 +++ .../util/bin/format/pdb/PdbParserTest.java | 915 +---------------- .../pdb/symbolserver/DummySymbolServer.java | 85 ++ .../symbolserver/HttpSymbolServerTest.java | 40 + .../symbolserver/LocalSymbolServerTest.java | 225 +++++ ...mbolServerInstanceCreatorRegistryTest.java | 101 ++ .../symbolserver/SymbolServerServiceTest.java | 160 +++ .../java/docking/DialogComponentProvider.java | 9 +- .../widgets/textfield/IntegerTextField.java | 14 +- .../src/main/java/ghidra/net/HttpClients.java | 88 ++ .../ghidra/net/SSLContextInitializer.java | 4 + .../main/java/ghidra/net/http/HttpUtil.java | 31 +- .../util/filechooser/ExtensionFileFilter.java | 183 +--- .../ghidra/util/task/MonitoredRunnable.java | 15 +- .../java/ghidra/net/http/HttpUtilTest.java | 48 + .../java/help/screenshot/PdbScreenShots.java | 221 ++-- .../SymbolServerService2Test.java | 138 +++ 93 files changed, 7715 insertions(+), 3874 deletions(-) delete mode 100644 Ghidra/Features/Base/src/main/help/help/topics/ImporterPlugin/load_pdb.html delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbFactory.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfo.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfoCodeView.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfoDotNet.java delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfoDotNetIface.java delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfoIface.java rename Ghidra/Features/PDB/{src/main/java/ghidra/app/util/bin/format/pdb/GhidraPdbFactory.java => developer_scripts/PdbExamplePrescript.java} (50%) create mode 100644 Ghidra/Features/PDB/developer_scripts/PdbSymbolServerExamplePrescript.java create mode 100644 Ghidra/Features/PDB/src/main/help/help/topics/Pdb/LoadPDBNew.html delete mode 100644 Ghidra/Features/PDB/src/main/help/help/topics/Pdb/download_pdb_file.html delete mode 100644 Ghidra/Features/PDB/src/main/help/help/topics/Pdb/images/KnownSymbolServerURLsDialog.png create mode 100644 Ghidra/Features/PDB/src/main/help/help/topics/Pdb/images/LoadPdb_Advanced_NeedsConfig.png create mode 100644 Ghidra/Features/PDB/src/main/help/help/topics/Pdb/images/LoadPdb_Advanced_Screenshot.png create mode 100644 Ghidra/Features/PDB/src/main/help/help/topics/Pdb/images/LoadPdb_Initial_Screenshot.png delete mode 100644 Ghidra/Features/PDB/src/main/help/help/topics/Pdb/images/PdbOrXmlDialog.png delete mode 100644 Ghidra/Features/PDB/src/main/help/help/topics/Pdb/images/PeSpecifiedPathDialog.png create mode 100644 Ghidra/Features/PDB/src/main/help/help/topics/Pdb/images/Plus2.png delete mode 100644 Ghidra/Features/PDB/src/main/help/help/topics/Pdb/images/SuccessDialog.png create mode 100644 Ghidra/Features/PDB/src/main/help/help/topics/Pdb/images/SymbolServerConfig_AddButtonMenu.png create mode 100644 Ghidra/Features/PDB/src/main/help/help/topics/Pdb/images/SymbolServerConfig_Screenshot.png delete mode 100644 Ghidra/Features/PDB/src/main/help/help/topics/Pdb/images/SymbolServerURLDialog.png create mode 100644 Ghidra/Features/PDB/src/main/help/help/topics/Pdb/images/disk.png create mode 100644 Ghidra/Features/PDB/src/main/help/help/topics/Pdb/images/down.png create mode 100644 Ghidra/Features/PDB/src/main/help/help/topics/Pdb/images/error.png create mode 100644 Ghidra/Features/PDB/src/main/help/help/topics/Pdb/images/reload3.png create mode 100644 Ghidra/Features/PDB/src/main/help/help/topics/Pdb/images/up.png create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbAnalyzerCommon.java delete mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfo.java delete mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfoDotNet.java delete mode 100644 Ghidra/Features/PDB/src/main/java/pdb/AskPdbOptionsDialog.java delete mode 100644 Ghidra/Features/PDB/src/main/java/pdb/AskPdbUrlDialog.java delete mode 100644 Ghidra/Features/PDB/src/main/java/pdb/PdbInitializer.java delete mode 100644 Ghidra/Features/PDB/src/main/java/pdb/PdbSymbolServerPlugin.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/PdbUtils.java delete mode 100644 Ghidra/Features/PDB/src/main/java/pdb/URLChoice.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/AbstractSymbolServer.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/DisabledSymbolServer.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/FindOption.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/HttpSymbolServer.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/LocalSymbolStore.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/SameDirSymbolStore.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/SymbolFileInfo.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/SymbolFileLocation.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/SymbolServer.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/SymbolServerInputStream.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/SymbolServerInstanceCreatorContext.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/SymbolServerInstanceCreatorRegistry.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/SymbolServerService.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/SymbolStore.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/ConfigPdbDialog.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/FilePromptDialog.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/LoadPdbDialog.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolFilePanel.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolFileRow.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolFileTableModel.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolServerPanel.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolServerRow.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolServerTableModel.java create mode 100644 Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/WellKnownSymbolServerLocation.java create mode 100644 Ghidra/Features/PDB/src/test/java/pdb/symbolserver/DummySymbolServer.java create mode 100644 Ghidra/Features/PDB/src/test/java/pdb/symbolserver/HttpSymbolServerTest.java create mode 100644 Ghidra/Features/PDB/src/test/java/pdb/symbolserver/LocalSymbolServerTest.java create mode 100644 Ghidra/Features/PDB/src/test/java/pdb/symbolserver/SymbolServerInstanceCreatorRegistryTest.java create mode 100644 Ghidra/Features/PDB/src/test/java/pdb/symbolserver/SymbolServerServiceTest.java create mode 100644 Ghidra/Framework/Generic/src/main/java/ghidra/net/HttpClients.java create mode 100644 Ghidra/Framework/Generic/src/test/java/ghidra/net/http/HttpUtilTest.java create mode 100644 Ghidra/Test/IntegrationTest/src/test/java/pdb/symbolserver/SymbolServerService2Test.java diff --git a/GPL/CabExtract/build.gradle b/GPL/CabExtract/build.gradle index 46994edbc7..374a463115 100644 --- a/GPL/CabExtract/build.gradle +++ b/GPL/CabExtract/build.gradle @@ -17,6 +17,10 @@ eclipse.project.name = 'GPL CabExtract' project.ext.cabextract = "cabextract-1.6" +/********************************************************************************* + * Deprecated - will be removed + *********************************************************************************/ + /********************************************************************************* * CabExtract platform specific tasks * diff --git a/Ghidra/Configurations/Public_Release/data/PDB_SYMBOL_SERVER_URLS.pdburl b/Ghidra/Configurations/Public_Release/data/PDB_SYMBOL_SERVER_URLS.pdburl index a01d71bf03..06da4577c6 100644 --- a/Ghidra/Configurations/Public_Release/data/PDB_SYMBOL_SERVER_URLS.pdburl +++ b/Ghidra/Configurations/Public_Release/data/PDB_SYMBOL_SERVER_URLS.pdburl @@ -1 +1,6 @@ -Internet,https://msdl.microsoft.com/download/symbols +Internet|https://msdl.microsoft.com/download/symbols/|WARNING: Check your organization's security policy before downloading files from the internet. +Internet|https://chromium-browser-symsrv.commondatastorage.googleapis.com|WARNING: Check your organization's security policy before downloading files from the internet. +Internet|https://symbols.mozilla.org/|WARNING: Check your organization's security policy before downloading files from the internet. +Internet|https://software.intel.com/sites/downloads/symbols/|WARNING: Check your organization's security policy before downloading files from the internet. +Internet|https://driver-symbols.nvidia.com/|WARNING: Check your organization's security policy before downloading files from the internet. +Internet|https://download.amd.com/dir/bin|WARNING: Check your organization's security policy before downloading files from the internet. diff --git a/Ghidra/Features/Base/src/main/help/help/topics/ImporterPlugin/load_pdb.html b/Ghidra/Features/Base/src/main/help/help/topics/ImporterPlugin/load_pdb.html deleted file mode 100644 index e54775e07a..0000000000 --- a/Ghidra/Features/Base/src/main/help/help/topics/ImporterPlugin/load_pdb.html +++ /dev/null @@ -1,156 +0,0 @@ - - - -
- - -A program database (PDB) file holds debugging and project state information about a program
- and can be created in a number of ways. Historically, it has been created using a Microsoft
- compiler and written in C/C++
, C#
, and Visual Basic
.
- A user generates a PDB file using the /ZI or /Zi
flag (for C/C++ programs) or the
- /debug
flag (for Visual Basic/C# programs).
There are two mechanisms for processing a PDB file. First, the platform-independent - PDB Universal Reader/Analyzer, which can read a raw PDB file and apply it. Its capabilities - are expected to be expanded in future releases. Second, the legacy capability that uses the - DIA SDK to read information from the PDB file. This mechanism can only run - on a Windows platform, however it creates an XML representation of information gleaned using - the DIA SDK. These XML files can be saved and then used on Windows and non-Windows platforms - hosting Ghidra.
- -If loading a PDB, this should be done prior to other analysis, except in special cases, - such as when only loading data types.
- -Restricted loading of data types or public symbols is - supported by PDB Universal.
- --- --
- -- From the menu-bar of a tool, select File Load PDB File
- -- In the file chooser, select the PDB file (*.PDB or *.PDB.XML)
- -- Click the "Select PDB" button
-- --
- PDB Universal is automatically used for *.PDB on non-Windows platforms
-- PDB MSDIA is used for *.PDB.XML files
-When a user chooses a PDB or XML file to load for a program, Ghidra will verify its - signature to be valid for the program. At this time, the PDB MSDIA loader cannot be used to - force-load a mismatched PDB. To perform a force-load of a PDB file, the user must choose the - PDB Universal loader if given the option. Force-loading an mismatched file can have - consequences, such as loading incorrect data types and symbols located at the wrong - addresses.
- -- PDB files may also be loaded using the PDB Analyzer, which is available through - Auto Analysis or as - a One Shot Analyzer. -
-
-- --
-- Structure and union definitions
- -- Typedefs
- -- Enumerations
- -- Class definitions
- -- Function prototypes
- -- Stack variable names and data types
- -- Source line numbers
- -- Instruction and data symbols
-
-- -Before the PDB file is loaded into the program, then PDB signature and age are matched - against the information stored in the executable. If these values do not match, then the PDB - will not be loaded.
- - - -Figure 1
-
*.PDB.XML files can be created in three different ways: - -
- --
- From the Ghidra GUI in Windows, use the - Ghidra Script Manager - to run the CreatePdbXmlFilesScript.java script. Follow the prompts to choose - the .PDB file (or directory containing .PDB file(s)) to be converted to .PDB.XML form. - When given a directory, the script recursively traverses all subfolders to find .PDB - files. A created .PDB.XML file is placed in the same location as the corresponding original - .PDB file.
-
-- From a Windows command line, navigate to the following directory: - <ghidra install root>/support - and run the createPdbXmlFiles.bat script. The script takes one argument representing - either one .PDB file or a directory of .PDB files. When given a directory, the script - recursively traverses all subdirectories to find .PDB files. A created .PDB.XML file is - placed in the same location as the corresponding original .PDB file. Sample calls to the - script are shown below. -
-
-createPdbXmlFiles.bat C:\Symbols\samplePdb.pdb
-
-createPdbXmlFiles.bat C:\Symbols
-
-
-- Run the included pdb.exe executable (found in the <ghidra install - root>/Ghidra/Features/PDB/os/win64 directory) and redirect (save) its output to an - XML file as shown below: -
-
-pdb.exe samplePdb.pdb > samplePdb.pdb.xml
-
NOTE: Execution of pdb.exe has runtime dependencies which must be satisfied. - Please refer to the README_PDB document for details.
- --- - diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/BinaryReader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/BinaryReader.java index c07c127c00..c7006f9a4f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/BinaryReader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/BinaryReader.java @@ -66,11 +66,13 @@ public class BinaryReader { this.provider = provider; setLittleEndian(isLittleEndian); } - + /** - * Returns a clone of this reader positioned at the new index. + * Returns a clone of this reader, with its own independent current position, + * positioned at the new index. + * * @param newIndex the new index - * @return a clone of this reader positioned at the new index + * @return an independent clone of this reader positioned at the new index */ public BinaryReader clone(long newIndex) { BinaryReader clone = new BinaryReader(provider, isLittleEndian()); @@ -88,6 +90,36 @@ public class BinaryReader { return clone(currentIndex); } + /** + * Returns a BinaryReader that is in BigEndian mode. + * + * @return either this same instance (if already BigEndian), or a new instance + * (at the same location) in BigEndian mode + */ + public BinaryReader asBigEndian() { + if (isBigEndian()) { + return this; + } + BinaryReader result = clone(currentIndex); + result.setLittleEndian(false); + return result; + } + + /** + * Returns a BinaryReader that is in LittleEndian mode. + * + * @return either this same instance (if already LittleEndian), or a new instance + * (at the same location) in LittleEndian mode + */ + public BinaryReader asLittleEndian() { + if (!isBigEndian()) { + return this; + } + BinaryReader result = clone(currentIndex); + result.setLittleEndian(true); + return result; + } + /** * Returns true if this reader will extract values in little endian, * otherwise in big endian. @@ -97,6 +129,15 @@ public class BinaryReader { return converter instanceof LittleEndianDataConverter; } + /** + * Returns true if this reader will extract values in big endian. + * + * @return true is big endian, false is little endian + */ + public boolean isBigEndian() { + return converter instanceof BigEndianDataConverter; + } + /** * Sets the endian of this binary reader. * @param isLittleEndian true for little-endian and false for big-endian diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbFactory.java deleted file mode 100644 index 7dbf1cecaf..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbFactory.java +++ /dev/null @@ -1,53 +0,0 @@ -/* ### - * IP: GHIDRA - * REVIEWED: YES - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.app.util.bin.format.pdb; - -import java.io.*; - -import ghidra.app.util.bin.*; -import ghidra.framework.*; - -public class PdbFactory { - static { - PluggableServiceRegistry.registerPluggableService(PdbFactory.class, - new PdbFactory()); - } - - public static PdbInfoDotNetIface getPdbInfoDotNetInstance( - BinaryReader reader, int ptr) throws IOException { - PdbFactory factory = PluggableServiceRegistry - .getPluggableService(PdbFactory.class); - return factory.doGetPdbInfoDotNetInstance(reader, ptr); - } - - public static PdbInfoIface getPdbInfoInstance(BinaryReader reader, int ptr) - throws IOException { - PdbFactory factory = PluggableServiceRegistry - .getPluggableService(PdbFactory.class); - return factory.doGetPdbInfoInstance(reader, ptr); - } - - protected PdbInfoDotNetIface doGetPdbInfoDotNetInstance( - BinaryReader reader, int ptr) throws IOException { - return null; - } - - protected PdbInfoIface doGetPdbInfoInstance(BinaryReader reader, int ptr) - throws IOException { - return null; - } -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfo.java new file mode 100644 index 0000000000..4e841fc272 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfo.java @@ -0,0 +1,63 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.bin.format.pdb; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.framework.options.Options; + +/** + * Bag of information about a Pdb symbol file, usually extracted from information present in a PE + * binary. + * + */ +public interface PdbInfo { + + /** + * Read either a {@link PdbInfoCodeView} object or a {@link PdbInfoDotNet} object + * from the BinaryReader of a PE binary. + * + * @param reader BinaryReader + * @param offset position of the debug info + * @return new PdbInfoCodeView or PdbInfoDotNet object + * @throws IOException if error + */ + public static PdbInfo read(BinaryReader reader, long offset) throws IOException { + if (PdbInfoCodeView.isMatch(reader, offset)) { + return PdbInfoCodeView.read(reader, offset); + } + if (PdbInfoDotNet.isMatch(reader, offset)) { + return PdbInfoDotNet.read(reader, offset); + } + return null; + } + + /** + * Returns true if this instance is valid. + * + * @return boolean true if valid (magic signature matches and fields have valid data) + */ + boolean isValid(); + + /** + * Writes the various PDB info fields to a program's options. + * + * @param options Options of a Program to write to + */ + void serializeToOptions(Options options); + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfoCodeView.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfoCodeView.java new file mode 100644 index 0000000000..3a47e7bb1a --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfoCodeView.java @@ -0,0 +1,113 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.bin.format.pdb; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import org.apache.commons.io.FilenameUtils; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.pe.debug.DebugCodeViewConstants; +import ghidra.framework.options.Options; +import ghidra.program.model.data.*; +import ghidra.util.Conv; + +/** + * Older style pdb information, using a simple 32bit hash to link the pdb to its binary. + */ +public class PdbInfoCodeView implements StructConverter, PdbInfo { + private static final int MAGIC = + DebugCodeViewConstants.SIGNATURE_NB << 16 | DebugCodeViewConstants.VERSION_10; + + /** + * Returns true if the pdb information at the specified offset is a {@link PdbInfoCodeView} + * type (based on the signature at that offset). + * + * @param reader {@link BinaryReader} + * @param offset offset of the Pdb information + * @return boolean true if it is a {@link PdbInfoCodeView} type + * @throws IOException if error reading data + */ + public static boolean isMatch(BinaryReader reader, long offset) throws IOException { + //read value out as big endian + int value = reader.asBigEndian().readInt(offset); + return MAGIC == value; + } + + /** + * Reads the pdb information from a PE binary. + * + * @param reader {@link BinaryReader} + * @param offset offset of the Pdb information + * @return new {@link PdbInfoCodeView} instance, never null + * @throws IOException if error reading data + */ + public static PdbInfoCodeView read(BinaryReader reader, long offset) throws IOException { + reader = reader.clone(offset); + + PdbInfoCodeView result = new PdbInfoCodeView(); + result.magic = reader.readNextByteArray(4); + result.offset = reader.readNextInt(); + result.sig = reader.readNextInt(); + result.age = reader.readNextInt(); + result.pdbPath = reader.readNextAsciiString(); + result.pdbName = FilenameUtils.getName(result.pdbPath); + + return result; + } + + private byte[] magic; + private int offset; + private int sig; + private int age; + private String pdbName; + private String pdbPath; + + private PdbInfoCodeView() { + // nothing + } + + @Override + public boolean isValid() { + return magic.length == 4 && !pdbName.isBlank(); + } + + @Override + public void serializeToOptions(Options options) { + options.setString(PdbParserConstants.PDB_VERSION, + new String(magic, StandardCharsets.US_ASCII)); + options.setString(PdbParserConstants.PDB_SIGNATURE, Conv.toHexString(sig)); + options.setString(PdbParserConstants.PDB_AGE, Integer.toHexString(age)); + options.setString(PdbParserConstants.PDB_FILE, pdbName); + } + + @Override + public DataType toDataType() { + StructureDataType struct = new StructureDataType("PdbInfo", 0); + struct.add(new StringDataType(), magic.length, "signature", null); + struct.add(new DWordDataType(), "offset", null); + struct.add(new DWordDataType(), "sig", null); + struct.add(new DWordDataType(), "age", null); + if (pdbName.length() > 0) { + struct.add(new StringDataType(), pdbName.length(), "pdbname", null); + } + struct.setCategoryPath(new CategoryPath("/PDB")); + return struct; + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfoDotNet.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfoDotNet.java new file mode 100644 index 0000000000..605ff1aa51 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfoDotNet.java @@ -0,0 +1,131 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.bin.format.pdb; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import org.apache.commons.io.FilenameUtils; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.pe.debug.DebugCodeViewConstants; +import ghidra.app.util.datatype.microsoft.GUID; +import ghidra.app.util.datatype.microsoft.GuidDataType; +import ghidra.framework.options.Options; +import ghidra.program.model.data.*; + +/** + * Newer style pdb information, using a GUID to link the pdb to its binary. + */ +public class PdbInfoDotNet implements StructConverter, PdbInfo { + private static final int MAGIC = + DebugCodeViewConstants.SIGNATURE_DOT_NET << 16 | DebugCodeViewConstants.VERSION_DOT_NET; + + /** + * Returns true if the pdb information at the specified offset is a {@link PdbInfoDotNet} + * type (based on the signature at that offset). + * + * @param reader {@link BinaryReader} + * @param offset offset of the Pdb information + * @return boolean true if it is a {@link PdbInfoDotNet} type + * @throws IOException if error reading data + */ + public static boolean isMatch(BinaryReader reader, long offset) throws IOException { + //read value out as big endian + int value = reader.asBigEndian().readInt(offset); + return MAGIC == value; + } + + /** + * Reads an instance from the stream. + * + * @param reader {@link BinaryReader} to read from + * @param offset position of the pdb info + * @return new instance, never null + * @throws IOException if IO error or data format error + */ + public static PdbInfoDotNet read(BinaryReader reader, long offset) throws IOException { + reader = reader.clone(offset); + + PdbInfoDotNet result = new PdbInfoDotNet(); + result.magic = reader.readNextByteArray(4); + result.guid = new GUID(reader); + result.age = reader.readNextInt(); + result.pdbPath = reader.readNextAsciiString(); + result.pdbName = FilenameUtils.getName(result.pdbPath); + + return result; + } + + /** + * Creates an instance from explicit values. + * + * @param pdbPath String path / filename of the pdb file + * @param age age + * @param guid {@link GUID} + * @return new instance, never null + */ + public static PdbInfoDotNet fromValues(String pdbPath, int age, GUID guid) { + PdbInfoDotNet result = new PdbInfoDotNet(); + result.pdbPath = pdbPath; + result.pdbName = FilenameUtils.getName(result.pdbPath); + result.age = age; + result.guid = guid; + result.magic = "????".getBytes(); + + return result; + } + + + private byte[] magic; + private GUID guid; + private int age; + private String pdbName; + private String pdbPath; + + private PdbInfoDotNet() { + // empty + } + + @Override + public boolean isValid() { + return magic.length == 4 && !pdbName.isBlank() && guid != null; + } + + @Override + public void serializeToOptions(Options options) { + options.setString(PdbParserConstants.PDB_VERSION, + new String(magic, StandardCharsets.US_ASCII)); + options.setString(PdbParserConstants.PDB_GUID, guid.toString()); + options.setString(PdbParserConstants.PDB_AGE, Integer.toHexString(age)); + options.setString(PdbParserConstants.PDB_FILE, pdbName); + } + + @Override + public DataType toDataType() { + StructureDataType struct = new StructureDataType("DotNetPdbInfo", 0); + struct.add(new StringDataType(), magic.length, "signature", null); + struct.add(new GuidDataType(), "guid", null); + struct.add(new DWordDataType(), "age", null); + if (pdbName.length() > 0) { + struct.add(new StringDataType(), pdbName.length(), "pdbname", null); + } + struct.setCategoryPath(new CategoryPath("/PDB")); + return struct; + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfoDotNetIface.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfoDotNetIface.java deleted file mode 100644 index 381668ed56..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfoDotNetIface.java +++ /dev/null @@ -1,33 +0,0 @@ -/* ### - * IP: GHIDRA - * REVIEWED: YES - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.app.util.bin.format.pdb; - -import ghidra.app.util.bin.*; -import ghidra.app.util.datatype.microsoft.*; - -public interface PdbInfoDotNetIface extends StructConverter { - - public abstract String getPdbName(); - - public abstract int getAge(); - - public abstract int getSignature(); - - public abstract GUID getGUID(); - - public abstract byte[] getMagic(); -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfoIface.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfoIface.java deleted file mode 100644 index ebb4ffac61..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbInfoIface.java +++ /dev/null @@ -1,32 +0,0 @@ -/* ### - * IP: GHIDRA - * REVIEWED: YES - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.app.util.bin.format.pdb; - -import ghidra.app.util.bin.*; - -public interface PdbInfoIface extends StructConverter { - - public abstract byte[] getMagic(); - - public abstract int getOffset(); - - public abstract int getSig(); - - public abstract int getAge(); - - public abstract String getPdbName(); -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/DebugDataDirectory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/DebugDataDirectory.java index 4e9168a266..27569734f1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/DebugDataDirectory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/DebugDataDirectory.java @@ -19,8 +19,8 @@ import java.io.IOException; import java.io.RandomAccessFile; import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader; -import ghidra.app.util.bin.format.pdb.PdbInfoDotNetIface; -import ghidra.app.util.bin.format.pdb.PdbInfoIface; +import ghidra.app.util.bin.format.pdb.PdbInfoCodeView; +import ghidra.app.util.bin.format.pdb.PdbInfoDotNet; import ghidra.app.util.bin.format.pe.debug.*; import ghidra.app.util.importer.MessageLog; import ghidra.program.model.address.Address; @@ -112,12 +112,12 @@ public class DebugDataDirectory extends DataDirectory { if (dcv != null) { Address dataAddr = getDataAddress(dcv.getDebugDirectory(), isBinary, space, ntHeader); if (dataAddr != null) { - PdbInfoIface pdbInfo = dcv.getPdbInfo(); + PdbInfoCodeView pdbInfo = dcv.getPdbInfo(); if (pdbInfo != null) { setPlateComment(program, dataAddr, "CodeView PDB Info"); PeUtils.createData(program, dataAddr, pdbInfo.toDataType(), log); } - PdbInfoDotNetIface dotNetPdbInfo = dcv.getDotNetPdbInfo(); + PdbInfoDotNet dotNetPdbInfo = dcv.getDotNetPdbInfo(); if (dotNetPdbInfo != null) { setPlateComment(program, dataAddr, ".NET PDB Info"); PeUtils.createData(program, dataAddr, dotNetPdbInfo.toDataType(), log); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/debug/DebugCodeView.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/debug/DebugCodeView.java index e61a0522a1..1c9154eca1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/debug/DebugCodeView.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/debug/DebugCodeView.java @@ -15,30 +15,25 @@ */ package ghidra.app.util.bin.format.pe.debug; +import java.io.IOException; + import ghidra.app.util.bin.StructConverter; import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader; -import ghidra.app.util.bin.format.pdb.PdbFactory; -import ghidra.app.util.bin.format.pdb.PdbInfoDotNetIface; -import ghidra.app.util.bin.format.pdb.PdbInfoIface; +import ghidra.app.util.bin.format.pdb.PdbInfoCodeView; +import ghidra.app.util.bin.format.pdb.PdbInfoDotNet; import ghidra.app.util.bin.format.pe.OffsetValidator; -import ghidra.program.model.data.ArrayDataType; -import ghidra.program.model.data.CategoryPath; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.Structure; -import ghidra.program.model.data.StructureDataType; +import ghidra.program.model.data.*; import ghidra.util.Msg; import ghidra.util.exception.DuplicateNameException; -import java.io.IOException; - /** * A class to represent the code view debug information. */ public class DebugCodeView implements StructConverter { private DebugDirectory debugDir; private DebugCodeViewSymbolTable symbolTable; - private PdbInfoIface pdbInfo; - private PdbInfoDotNetIface dotNetPdbInfo; + private PdbInfoCodeView pdbInfo; + private PdbInfoDotNet dotNetPdbInfo; /** * Constructor. @@ -70,8 +65,8 @@ public class DebugCodeView implements StructConverter { return; } - dotNetPdbInfo = PdbFactory.getPdbInfoDotNetInstance(reader, ptr); - pdbInfo = PdbFactory.getPdbInfoInstance(reader, ptr); + dotNetPdbInfo = PdbInfoDotNet.isMatch(reader, ptr) ? PdbInfoDotNet.read(reader, ptr) : null; + pdbInfo = PdbInfoCodeView.isMatch(reader, ptr) ? PdbInfoCodeView.read(reader, ptr) : null; if (DebugCodeViewSymbolTable.isMatch(reader, ptr)) { symbolTable = DebugCodeViewSymbolTable.createDebugCodeViewSymbolTable(reader, @@ -106,17 +101,18 @@ public class DebugCodeView implements StructConverter { * Returns the code view .PDB info. * @return the code view .PDB info */ - public PdbInfoIface getPdbInfo() { + public PdbInfoCodeView getPdbInfo() { return pdbInfo; } - public PdbInfoDotNetIface getDotNetPdbInfo() { + public PdbInfoDotNet getDotNetPdbInfo() { return dotNetPdbInfo; } /** * @see ghidra.app.util.bin.StructConverter#toDataType() */ + @Override public DataType toDataType() throws DuplicateNameException { Structure es = new StructureDataType("DebugCodeView", 0); es.add(WORD, "Signature", null); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/microsoft/GUID.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/microsoft/GUID.java index 0d7d073536..82424c5b49 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/microsoft/GUID.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/microsoft/GUID.java @@ -21,11 +21,7 @@ import java.util.Arrays; import ghidra.app.util.bin.BinaryReader; import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.util.BigEndianDataConverter; -import ghidra.util.Conv; -import ghidra.util.DataConverter; -import ghidra.util.LittleEndianDataConverter; -import ghidra.util.NumericUtilities; +import ghidra.util.*; /** * GUIDs identify objects such as interfaces, manager entry-point vectors (EPVs), @@ -61,54 +57,52 @@ public class GUID { /** * Creates a GUID object using the GUID string form. - * @param guidString - "6B29FC40-CA47-1067-B31D-00DD010662DA" + * @param guidString - either with or without dashes between parts - + * "6B29FC40-CA47-1067-B31D-00DD010662DA", or "6B29FC40CA471067B31D00DD010662DA", and + * with or without leading and trailing "{" "}" characters * @throws IllegalArgumentException if string does not represent a valid GUID */ - public GUID(String guidString) { - if (guidString.length() != 36) { - throw new IllegalArgumentException("Invalid GUID string."); - } - int pos = guidString.indexOf('-'); - if (pos == -1) { - throw new IllegalArgumentException("Invalid GUID string."); - } - data1 = (int) NumericUtilities.parseHexLong(guidString.substring(0, pos)); - - guidString = guidString.substring(pos + 1); - pos = guidString.indexOf('-'); - if (pos == -1) { - throw new IllegalArgumentException("Invalid GUID string."); - } - data2 = (short) Integer.parseInt(guidString.substring(0, pos), 16); - - guidString = guidString.substring(pos + 1); - pos = guidString.indexOf('-'); - if (pos == -1) { - throw new IllegalArgumentException("Invalid GUID string."); - } - data3 = (short) Integer.parseInt(guidString.substring(0, pos), 16); - - guidString = guidString.substring(pos + 1); - pos = guidString.indexOf('-'); - if (pos == -1) { - throw new IllegalArgumentException("Invalid GUID string."); - } - int value = Integer.parseInt(guidString.substring(0, pos), 16); + public GUID(String guidString) throws IllegalArgumentException { + String[] parts = getGUIDParts(guidString); + data1 = (int) NumericUtilities.parseHexLong(parts[0]); + data2 = (short) Integer.parseInt(parts[1], 16); + data3 = (short) Integer.parseInt(parts[2], 16); + int value = Integer.parseInt(parts[3], 16); data4[0] = (byte) (value >> 8); data4[1] = (byte) (value & 0xff); + data4[2] = (byte) Integer.parseInt(parts[4].substring(0, 2), 16); + data4[3] = (byte) Integer.parseInt(parts[4].substring(2, 4), 16); + data4[4] = (byte) Integer.parseInt(parts[4].substring(4, 6), 16); + data4[5] = (byte) Integer.parseInt(parts[4].substring(6, 8), 16); + data4[6] = (byte) Integer.parseInt(parts[4].substring(8, 10), 16); + data4[7] = (byte) Integer.parseInt(parts[4].substring(10, 12), 16); + } - guidString = guidString.substring(pos + 1); - data4[2] = (byte) Integer.parseInt(guidString.substring(0, 2), 16); - guidString = guidString.substring(2); - data4[3] = (byte) Integer.parseInt(guidString.substring(0, 2), 16); - guidString = guidString.substring(2); - data4[4] = (byte) Integer.parseInt(guidString.substring(0, 2), 16); - guidString = guidString.substring(2); - data4[5] = (byte) Integer.parseInt(guidString.substring(0, 2), 16); - guidString = guidString.substring(2); - data4[6] = (byte) Integer.parseInt(guidString.substring(0, 2), 16); - guidString = guidString.substring(2); - data4[7] = (byte) Integer.parseInt(guidString.substring(0, 2), 16); + private String[] getGUIDParts(String guidString) throws IllegalArgumentException { + String[] results = new String[5]; + guidString = (guidString.startsWith("{") && guidString.endsWith("}")) + ? guidString.substring(1, guidString.length() - 1) + : guidString; + if (guidString.length() == 36 && guidString.charAt(8) == '-' && + guidString.charAt(13) == '-' && guidString.charAt(18) == '-' && + guidString.charAt(23) == '-') { + results[0] = guidString.substring(0, 8); + results[1] = guidString.substring(9, 13); + results[2] = guidString.substring(14, 18); + results[3] = guidString.substring(19, 23); + results[4] = guidString.substring(24); + } + else if (guidString.length() == 32) { + results[0] = guidString.substring(0, 8); + results[1] = guidString.substring(8, 12); + results[2] = guidString.substring(12, 16); + results[3] = guidString.substring(16, 20); + results[4] = guidString.substring(20); + } + else { + throw new IllegalArgumentException("Invalid GUID string."); + } + return results; } /** @@ -172,23 +166,23 @@ public class GUID { @Override public String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.append(Conv.toHexString(data1)); - buffer.append("-"); - buffer.append(Conv.toHexString(data2)); - buffer.append("-"); - buffer.append(Conv.toHexString(data3)); - buffer.append("-"); - buffer.append(Conv.toHexString(data4[0])); - buffer.append(Conv.toHexString(data4[1])); - buffer.append("-"); - buffer.append(Conv.toHexString(data4[2])); - buffer.append(Conv.toHexString(data4[3])); - buffer.append(Conv.toHexString(data4[4])); - buffer.append(Conv.toHexString(data4[5])); - buffer.append(Conv.toHexString(data4[6])); - buffer.append(Conv.toHexString(data4[7])); - return buffer.toString(); + StringBuilder sb = new StringBuilder(); + sb.append(Conv.toHexString(data1)); + sb.append("-"); + sb.append(Conv.toHexString(data2)); + sb.append("-"); + sb.append(Conv.toHexString(data3)); + sb.append("-"); + sb.append(Conv.toHexString(data4[0])); + sb.append(Conv.toHexString(data4[1])); + sb.append("-"); + sb.append(Conv.toHexString(data4[2])); + sb.append(Conv.toHexString(data4[3])); + sb.append(Conv.toHexString(data4[4])); + sb.append(Conv.toHexString(data4[5])); + sb.append(Conv.toHexString(data4[6])); + sb.append(Conv.toHexString(data4[7])); + return sb.toString(); } /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractPeDebugLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractPeDebugLoader.java index b5ac32c59c..a0215524ea 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractPeDebugLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractPeDebugLoader.java @@ -17,11 +17,11 @@ package ghidra.app.util.opinion; import java.util.*; -import ghidra.app.util.bin.format.pdb.*; +import ghidra.app.util.bin.format.pdb.PdbInfoCodeView; +import ghidra.app.util.bin.format.pdb.PdbInfoDotNet; import ghidra.app.util.bin.format.pe.FileHeader; import ghidra.app.util.bin.format.pe.SectionHeader; import ghidra.app.util.bin.format.pe.debug.*; -import ghidra.app.util.datatype.microsoft.GUID; import ghidra.app.util.demangler.DemangledObject; import ghidra.app.util.demangler.DemanglerUtil; import ghidra.framework.options.Options; @@ -112,56 +112,14 @@ abstract class AbstractPeDebugLoader extends AbstractLibrarySupportLoader { Options proplist = program.getOptions(Program.PROGRAM_INFO); - PdbInfoIface cvPdbInfo = dcv.getPdbInfo(); + PdbInfoCodeView cvPdbInfo = dcv.getPdbInfo(); if (cvPdbInfo != null) { - byte[] magic = cvPdbInfo.getMagic(); - int sig = cvPdbInfo.getSig(); - int age = cvPdbInfo.getAge(); - String name = cvPdbInfo.getPdbName(); - - proplist.setString(PdbParserConstants.PDB_VERSION, Conv.toString(magic)); - proplist.setString(PdbParserConstants.PDB_SIGNATURE, Conv.toHexString(sig)); - proplist.setString(PdbParserConstants.PDB_AGE, Integer.toHexString(age)); - proplist.setString(PdbParserConstants.PDB_FILE, name); -/* - DebugDirectory dd = dcv.getDebugDirectory(); - if (dd.getAddressOfRawData() > 0) { - Address address = space.getAddress(imageBase + dd.getAddressOfRawData()); - listing.setComment(address, CodeUnit.PLATE_COMMENT, "CodeView PDB Info"); - try { - listing.createData(address, cvPdbInfo.toDataType()); - } - catch (IOException e) {} - catch (DuplicateNameException e) {} - catch (CodeUnitInsertionException e) {} - } -*/ + cvPdbInfo.serializeToOptions(proplist); } - PdbInfoDotNetIface dotnetPdbInfo = dcv.getDotNetPdbInfo(); + PdbInfoDotNet dotnetPdbInfo = dcv.getDotNetPdbInfo(); if (dotnetPdbInfo != null) { - byte[] magic = dotnetPdbInfo.getMagic(); - GUID guid = dotnetPdbInfo.getGUID(); - int age = dotnetPdbInfo.getAge(); - String name = dotnetPdbInfo.getPdbName(); - - proplist.setString(PdbParserConstants.PDB_VERSION, Conv.toString(magic)); - proplist.setString(PdbParserConstants.PDB_GUID, guid.toString()); - proplist.setString(PdbParserConstants.PDB_AGE, Integer.toHexString(age)); - proplist.setString(PdbParserConstants.PDB_FILE, name); -/* - DebugDirectory dd = dcv.getDebugDirectory(); - if (dd.getAddressOfRawData() > 0) { - Address address = space.getAddress(imageBase + dd.getAddressOfRawData()); - listing.setComment(address, CodeUnit.PLATE_COMMENT, ".NET PDB Info"); - try { - listing.createData(address, dotnetPdbInfo.toDataType()); - } - catch (IOException e) {} - catch (DuplicateNameException e) {} - catch (CodeUnitInsertionException e) {} - } -*/ + dotnetPdbInfo.serializeToOptions(proplist); } DebugCodeViewSymbolTable dcvst = dcv.getSymbolTable(); diff --git a/Ghidra/Features/PDB/certification.manifest b/Ghidra/Features/PDB/certification.manifest index fa7172b4dc..dce9dc413e 100644 --- a/Ghidra/Features/PDB/certification.manifest +++ b/Ghidra/Features/PDB/certification.manifest @@ -1,4 +1,7 @@ ##VERSION: 2.0 +##MODULE IP: Crystal Clear Icons - LGPL 2.1 +##MODULE IP: FAMFAMFAM Icons - CC 2.5 +##MODULE IP: Nuvola Icons - LGPL 2.1 ##MODULE IP: Oxygen Icons - LGPL 3.0 Module.manifest||GHIDRA||||END| src/global/docs/README_PDB.html||GHIDRA||||END| @@ -13,13 +16,19 @@ src/main/help/help/shared/redo.png||GHIDRA||||END| src/main/help/help/shared/tip.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| src/main/help/help/shared/undo.png||GHIDRA||||END| src/main/help/help/shared/warning.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| +src/main/help/help/topics/Pdb/LoadPDBNew.html||GHIDRA||||END| src/main/help/help/topics/Pdb/PDB.htm||GHIDRA||||END| -src/main/help/help/topics/Pdb/download_pdb_file.html||GHIDRA||||END| -src/main/help/help/topics/Pdb/images/KnownSymbolServerURLsDialog.png||GHIDRA||||END| -src/main/help/help/topics/Pdb/images/PdbOrXmlDialog.png||GHIDRA||||END| -src/main/help/help/topics/Pdb/images/PeSpecifiedPathDialog.png||GHIDRA||||END| -src/main/help/help/topics/Pdb/images/SuccessDialog.png||GHIDRA||||END| -src/main/help/help/topics/Pdb/images/SymbolServerURLDialog.png||GHIDRA||||END| +src/main/help/help/topics/Pdb/images/LoadPdb_Advanced_NeedsConfig.png||GHIDRA||||END| +src/main/help/help/topics/Pdb/images/LoadPdb_Advanced_Screenshot.png||GHIDRA||||END| +src/main/help/help/topics/Pdb/images/LoadPdb_Initial_Screenshot.png||GHIDRA||||END| +src/main/help/help/topics/Pdb/images/Plus2.png||GHIDRA||||END| +src/main/help/help/topics/Pdb/images/SymbolServerConfig_AddButtonMenu.png||GHIDRA||||END| +src/main/help/help/topics/Pdb/images/SymbolServerConfig_Screenshot.png||GHIDRA||||END| +src/main/help/help/topics/Pdb/images/disk.png||FAMFAMFAM Icons - CC 2.5||||END| +src/main/help/help/topics/Pdb/images/down.png||GHIDRA||||END| +src/main/help/help/topics/Pdb/images/error.png||Nuvola Icons - LGPL 2.1||||END| +src/main/help/help/topics/Pdb/images/reload3.png||Crystal Clear Icons - LGPL 2.1||||END| +src/main/help/help/topics/Pdb/images/up.png||GHIDRA||||END| src/pdb/README.txt||GHIDRA||||END| src/pdb/pdb.sln||GHIDRA||||END| src/pdb/pdb.vcxproj||GHIDRA||||END| diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/GhidraPdbFactory.java b/Ghidra/Features/PDB/developer_scripts/PdbExamplePrescript.java similarity index 50% rename from Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/GhidraPdbFactory.java rename to Ghidra/Features/PDB/developer_scripts/PdbExamplePrescript.java index 66f34b5bbe..66f1a8dadf 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/GhidraPdbFactory.java +++ b/Ghidra/Features/PDB/developer_scripts/PdbExamplePrescript.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,29 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ghidra.app.util.bin.format.pdb; +//Example preScript to force a PdbAnalyzer to use a custom PDB +//symbol file when analyzing a binary. +//@category PDB +import java.io.File; -import ghidra.app.util.bin.*; +import ghidra.app.plugin.core.analysis.PdbAnalyzer; +import ghidra.app.script.GhidraScript; -import java.io.*; - -public class GhidraPdbFactory extends PdbFactory { +public class PdbExamplePrescript extends GhidraScript { @Override - protected PdbInfoDotNetIface doGetPdbInfoDotNetInstance( - BinaryReader reader, int ptr) throws IOException { - if (PdbInfoDotNet.isMatch(reader, ptr)) { - return new PdbInfoDotNet(reader, ptr); - } - return null; - } + protected void run() throws Exception { + // contrived example of choosing a pdb file with custom logic + File pdbFile = new File(getProgramFile().getPath() + ".pdb"); - @Override - protected PdbInfoIface doGetPdbInfoInstance(BinaryReader reader, int ptr) - throws IOException { - if (PdbInfo.isMatch(reader, ptr)) { - return new PdbInfo(reader, ptr); - } - return null; + PdbAnalyzer.setPdbFileOption(currentProgram, pdbFile); + // or + //PdbUniversalAnalyzer.setPdbFileOption(currentProgram, pdbFile); } } diff --git a/Ghidra/Features/PDB/developer_scripts/PdbSymbolServerExamplePrescript.java b/Ghidra/Features/PDB/developer_scripts/PdbSymbolServerExamplePrescript.java new file mode 100644 index 0000000000..f8b29e9d89 --- /dev/null +++ b/Ghidra/Features/PDB/developer_scripts/PdbSymbolServerExamplePrescript.java @@ -0,0 +1,53 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +//Example preScript to configure the PDB symbol server service to use the ~/symbols directory +//as the location to store symbol files, and to search Microsoft's public +//symbol server. +//The ~/symbols directory should already exist and be initialized as a symbol +//storage location. +//@category PDB +import java.util.List; + +import java.io.File; +import java.net.URI; + +import ghidra.app.plugin.core.analysis.PdbAnalyzer; +import ghidra.app.plugin.core.analysis.PdbUniversalAnalyzer; +import ghidra.app.script.GhidraScript; +import pdb.PdbPlugin; +import pdb.symbolserver.*; + +public class PdbSymbolServerExamplePrescript extends GhidraScript { + + @Override + protected void run() throws Exception { + File homeDir = new File(System.getProperty("user.home")); + File symDir = new File(homeDir, "symbols"); + LocalSymbolStore localSymbolStore = new LocalSymbolStore(symDir); + HttpSymbolServer msSymbolServer = + new HttpSymbolServer(URI.create("https://msdl.microsoft.com/download/symbols/")); + SymbolServerService symbolServerService = + new SymbolServerService(localSymbolStore, List.of(msSymbolServer)); + + PdbPlugin.saveSymbolServerServiceConfig(symbolServerService); + + // You only need to enable the "allow remote" option on the specific + // analyzer you are using + PdbUniversalAnalyzer.setAllowRemoteOption(currentProgram, true); + PdbAnalyzer.setAllowRemoteOption(currentProgram, true); + } +} + diff --git a/Ghidra/Features/PDB/src/global/docs/README_PDB.html b/Ghidra/Features/PDB/src/global/docs/README_PDB.html index 3b39a8ef11..decf438fcd 100644 --- a/Ghidra/Features/PDB/src/global/docs/README_PDB.html +++ b/Ghidra/Features/PDB/src/global/docs/README_PDB.html @@ -50,7 +50,7 @@ native execution issue and the use of an intermediate XML format.The Microsoft Debug Interface Access Software Development Kit (DIA SDK) provides access to - debug information stored in program database (.PDB) files generated by Microsoft - post-compiler tools. Because the format of the .PDB file generated by the post-compiler tools - undergoes constant revision, exposing the format is impractical. Using the DIA API, you can - develop applications that search for and browse debug information stored in a .PDB file. Such - applications could, for example, report stack trace-back information and analyze performance - data.
- -If you are attempting to load a PDB on a - Windows machine and see an error message such as "Unable to locate the DIA SDK," - you will need to add and register one or more files on your computer. Refer to the - README_PDB document for detailed instructions. -
-
Although GHIDRA has been primarily designed to utilize locally stored PDB files during analysis, the ability to interactively download individual PDB files from a web-based Microsoft Symbol Server is also provided. This capability is accessed via the GUI while a program is open via the -File->Download PDB File... action. +File → Load PDB File... action.
++ +In an effort to manage large collections of symbol files, Microsoft specified a scheme to organize + symbol files into directory structures.
+ +Ghidra can search Microsoft-style symbol servers (web-based HTTP/HTTPS) or local file system symbol + storage directories as well as unorganized, non-MS symbol storage directories for the PE executable's + matching PDB symbol file.
+ ++
+- Microsoft symbol servers / symbol storage directories:
++
+- Organize symbol files (typically PDB files) into a directory hierarchy using information + from the symbol file being stored.
+- In a single-level symbol server directory hierarchy, a symbol file named
+myprogram.pdb
might be stored + as:+
+- +
myprogram.pdb/012345670123012301230123456789AB1/myprogram.pdb
.- +
myprogram.pdb
is the name of the file and the name of the initial subdirectory off the root of the server.- +
012345670123012301230123456789AB
is the 32 character hexadecimal value (made up for this example) of the GUID + "012345678-0123-0123-0123-0123456789ABC" of the PDB file.+
- This value might instead be a 8 character hexadecimal value of the ID of the symbol file if it was created by an older version of the tool chain.
- +
1
is the hexadecimal value of the 'age' (build number) of the PDB file. Note: most PDB files will have an age value of 1.- In a two-level symbol server directory hierarchy, the same symbol file would be stored + as:
+my/myprogram.pdb/012345670123012301230123456789AB1/myprogram.pdb
, where the + first two letters of the symbol file's name are used to create a bucketing directory called "my" where all symbol files starting with + "my" are stored.+
- A two-level symbol server directory hierarchy is indicated by the presence of a file called
index2.txt
in the root directory of + the hierarchy.- Symbol storage directories are expected to have a
+pingme.txt
file and a special directory called000admin
.- Compressed symbol files (
+*.pd_
):+
+- Microsoft symbol server tools can compress symbol files to save space. The compressed file is stored in place of the original file, renamed + to have a trailing underscore ("_") character in the file extension.
+- Before use, Ghidra will decompress the file into the Local Symbol Storage directory, using whatever organization scheme + that directory is configured with to store the uncompressed version of the file.
+- Remote symbol files hosted on a HTTP server will be copied to and stored in the configured Local Symbol Storage directory before they + can be used.
+- Unorganized directories:
++
+- Symbol files are are found by matching the leading part of the filename found in the unorganized directory with the sought-after symbol + file's name.
++
+- +
helloworld.pdb
andhellokitty.pdb
would both be found as possible matches when searching for +hello.pdb
.- During searches, each possible matching PDB symbol file will be opened and partially parsed to extract its GUID and age values to determine if + it matches the user's full search criteria.
+
++ +Load PDB File
+++Allows the user to pick a PDB file or search for a PDB file and apply it to the currently open program in the CodeBrowser.
+Use this action instead of the PDB Analyzer if the PDB file can't be found automatically with the currently configured + symbol server search locations, if you need to force load a non-exact PDB file, or you need to use other PDB options.
+Steps:
++
+- Invoke File → Load PDB File... +
+- The PDB Location field will either have the path of an existing matching PDB file, or + it will prompt the user to use the browse button to select a file or use the + Advanced screen to search for the file.
++
- A
PDB.XML
file can be selected using the browse button. This will limit the selected parser to be the MSDIA parser.- Use the information displayed in the Program PDB Information panel to help you decide + which PDB file to choose.
+- If needed, click the Advanced button: +
+- The Local Symbol Storage location is required to enable searching. If missing, set it to a directory where Ghidra can store PDB files.
++
+- For example,
+/home/your_id/Symbols
orC:\Users\your_name\Symbols
.- If the location is a new empty directory, the user will be prompted to initialize the directory as a Microsoft symbol storage directory.
+- Add additional search locations by clicking the button. + The Microsoft symbol server and Program's Import Location are good defaults.
+- Save any changes to the configuration by clicking the button.
+- Set search options as needed.
+- Click the Search button to search the configured locations.
+ +- The Local Symbol Storage location is searched first, followed by any locations listed in the + Additional Search Paths list, in listed order.
+- Select one of the found PDB files and click the Load button to start the import process.
+- Remote symbol files will be downloaded to your Local Symbol Storage location before continuing.
+
++ +Symbol Server Config
+++Allows the user to configure the location where PDB symbol files are stored and additional locations to search for + existing PDB files. This is also available in the Load PDB File, Advanced screen.
+Steps:
++
+ +- Invoke Edit → Symbol Server Config +
+- The Local Symbol Storage location is required to be able to search. If missing, set it to + a directory where Ghidra can store PDB files.
++
+- For example,
+/home/your_id/Symbols
orC:\Users\your_name\Symbols
.- If the location is a new empty directory, the user will be prompted to initialize the directory as a Microsoft symbol storage directory.
+- Add additional search locations by clicking the button.
+- Save any changes to the configuration by clicking the button.
+- Search locations can be disabled by toggling the enabled checkbox at the beginning of the row.
+(Add)
+++ +Allows the user to add a location to the search path list. Pick from the offered types of locations, or pick + a predefined location.
+ ++
+- Directory - allows the user to pick an existing directory that will be searched for symbol files. + See level 1/level 2 or + unorganized directory descriptions.
+- URL - allows the user to enter a HTTP or HTTPS URL to a web-based symbol server.
+- Program's Import Location - automatically references the directory from which the program was imported.
+- Import _NT_SYMBOL_PATH - parses the current value of the
+_NT_SYMBOL_PATH
system environment variable to extract + URLs and symbol directory locations to be added to the Ghidra configuration. If no environment value is present, + the user can paste their own value into the text field.All items listed after the menu dividing line are automatically added from resource files that have a +
+*.pdburl
extension. The default file included with Ghidra is calledPDB_SYMBOL_SERVER_URLS.pdburl
and + is located in theGhidra/Configurations/Public_Release/data
directory under the Ghidra install directory.(Delete)
+++ +Deletes the currently selected locations from the Additional Search Paths table.
+(Up/Down)
+++ +Moves the currently selected item up or down in the Additional Search Paths table.
+(Refresh)
+++ +Updates the status column of the locations listed in the Additional Search Paths + table. Symbol servers or storage locations that are unreachable or misconfigured will show an error status in that column.
+(Save)
+++Saves the currently displayed search and storage locations to the preferences file. This is shared between all Ghidra tools.
+
++ +PDB Search - Search Options
+++These options control how PDB symbol files are found.
++
+- Ignore Age - allows matching symbol files with the correct GUID, but incorrect age value. Only affects searches of local symbol directories.
+- Ignore GUID/ID - allows matching symbol files with the correct name, but incorrect GUID or age. Only affects searches of local symbol directories.
+- Allow Remote - allows the searching of web-based symbol servers. Off by default to prevent sharing possibly sensitive information (PDB name, + GUID, age) with web-based symbol servers outside your organization.
+Additionally, there are override checkboxes in the Program PDB Information panel in the Advanced screen. These override values only + change the search criteria, they are not persisted to your program's metadata.
++
+- PDB Name Checkbox - this checkbox allows entering a custom value for the desired PDB file name.
+- PDB Unique Id Checkbox - this checkbox allows entering a custom GUID or ID value.
+- PDB Age Checkbox - this checkbox allows entering a custom age value.
+After changing a search option, you will need to perform another search to use the new options.
+
++ +PDB Parser
+++These options control which PDB parser will be used and any options used during parsing after the Load button is pressed.
++
+- Universal - Platform-independent PDB analyzer (No PDB.XML support).
+- MSDIA - Legacy PDB Analyzer. Requires MS DIA-SDK for raw PDB processing (Windows only), or preprocessed PDB.XML file.
+- Control - All, Data Types Only, Public Symbols Only.
+
++ ++
+- If you are connecting to a Symbol Server that requires user authentication using PKI, + you must first set your PKI Certificate before attempting to download from the server. See + + PKI Certificate for more details.
+
Ghidra offers the ability to download and apply PDB debug information for programs that run - on Microsoft Windows operating systems. - The Download PDB File feature allows users to - download and optionally load/apply a PDB file that matches the user's current program, given an - accessible Symbol Server. - The Load PDB File feature - allows users to apply a local PDB file to the current program. The PDB Analyzer also - automatically applies PDB symbols (attempting a search for matching PDB files locally) during - Auto-Analysis.
+A program database (PDB) file holds debugging and project state information about a program
+ and can be created in a number of ways. Historically, it has been created using a Microsoft
+ compiler and written in C/C++
, C#
, and Visual Basic
.
+ A user generates a PDB file using the /ZI or /Zi
flag (for C/C++ programs) or the
+ /debug
flag (for Visual Basic/C# programs).
There are two mechanisms for processing a PDB file. First, the platform-independent + PDB Universal Reader/Analyzer, which can read a raw PDB file and apply it. Its capabilities + are expected to be expanded in future releases. Second, the legacy capability that uses the + DIA SDK to read information from the PDB file. This mechanism can only run + on a Windows platform, however it creates an XML representation of information gleaned using + the DIA SDK. These XML files can be saved and then used on Windows and non-Windows platforms + hosting Ghidra.
+ +If loading a PDB, this should be done prior to other analysis, except in special cases, + such as when only loading data types.
+ +Restricted loading of data types or public symbols is + supported by PDB Universal.
+ +++ +PDB files can be loaded in two ways:
++
+- File → Load PDB File
+- PDB Analyzer via Analysis → + Auto Analyze or + Analysis → One Shot. +
++ ++
+- Structure and union definitions
+ +- Typedefs
+ +- Enumerations
+ +- Class definitions
+ +- Function prototypes
+ +- Stack variable names and data types
+ +- Source line numbers
+ +- Instruction and data symbols
+
*.PDB.XML files can be created in three different ways: + +
+ ++
- From the Ghidra GUI in Windows, use the + Ghidra Script Manager + to run the CreatePdbXmlFilesScript.java script. Follow the prompts to choose + the .PDB file (or directory containing .PDB file(s)) to be converted to .PDB.XML form. + When given a directory, the script recursively traverses all subfolders to find .PDB + files. A created .PDB.XML file is placed in the same location as the corresponding original + .PDB file.
+
+- From a Windows command line, navigate to the following directory: + <ghidra install root>/support + and run the createPdbXmlFiles.bat script. The script takes one argument representing + either one .PDB file or a directory of .PDB files. When given a directory, the script + recursively traverses all subdirectories to find .PDB files. A created .PDB.XML file is + placed in the same location as the corresponding original .PDB file. Sample calls to the + script are shown below. +
+
+createPdbXmlFiles.bat C:\Symbols\samplePdb.pdb
+
+createPdbXmlFiles.bat C:\Symbols
+
+
+- Run the included pdb.exe executable (found in the <ghidra install + root>/Ghidra/Features/PDB/os/win64 directory) and redirect (save) its output to an + XML file as shown below: +
+
+pdb.exe samplePdb.pdb > samplePdb.pdb.xml
+
NOTE: Execution of pdb.exe has runtime dependencies which must be satisfied. + Please refer to the README_PDB document for details.
+ ++diff --git a/Ghidra/Features/PDB/src/main/help/help/topics/Pdb/download_pdb_file.html b/Ghidra/Features/PDB/src/main/help/help/topics/Pdb/download_pdb_file.html deleted file mode 100644 index a161cc6e43..0000000000 --- a/Ghidra/Features/PDB/src/main/help/help/topics/Pdb/download_pdb_file.html +++ /dev/null @@ -1,184 +0,0 @@ - - - - - - -The Microsoft Debug Interface Access Software Development Kit (DIA SDK) provides access to + debug information stored in program database (.PDB) files generated by Microsoft + post-compiler tools. Because the format of the .PDB file generated by the post-compiler tools + undergoes constant revision, exposing the format is impractical. Using the DIA API, you can + develop applications that search for and browse debug information stored in a .PDB file. Such + applications could, for example, report stack trace-back information and analyze performance + data.
+ +If you are attempting to load a PDB on a + Windows machine and see an error message such as "Unable to locate the DIA SDK," + you will need to add and register one or more files on your computer. Refer to the + README_PDB document for detailed instructions. +
+
Ghidra offers the ability to download and apply a PDB file that corresponds to the program - currently open in the CodeBrowser. Successful downloading requires, at a minimum, that:
- --- --
-- A Symbol Server URL is available and accessible from the client or computer where you are running Ghidra.
-- The program open in the CodeBrowser is a PE file that was compiled by a Microsoft compiler.
-
-- -If set, Ghidra parses the
- -_NT_SYMBOL_PATH
- environment variable that is used to specify a PDB download location and Symbol Server URL(s). - The syntax for_NT_SYMBOL_PATH
is shown below:- -
srv*[local symbols location]*[Symbol Server URL]
The
- -_NT_SYMBOL_PATH
symbols location is used to pre-populate the dialog that asks - for the local storage location (as long as that location is valid). The_NT_SYMBOL_PATH
- Symbol Server URL is used to pre-populate the dialog that asks for the Symbol Server location.Although multiple Symbol Server URLs can be - specified in the
-_NT_SYMBOL_PATH
variable, Ghidra only uses the first listed URL.
- -- --
-- From the menu-bar of a tool, select File Download PDB File
- -
- -- A dialog appears asking whether you want to download a PDB or XML (PDB.XML) file. Select - the type of file you want to download and click OK.
- - - -A Symbol Server should always have PDB - files available for download. In contrast, .PDB.XML files are Ghidra-created files, and are - only available to download from the Symbol Server if Ghidra tools have been used to create - them and the server's admin has made them available. If you choose to download a .PDB.XML - file and it is not found on the server, you will see a dialog message telling you so. For - more information on creating and using .PDB.XML files, see the - Load PDB File section.
- -
- -- Before attempting to download the file, an attempt will first be made to locate it - using file and path names associated with the program. A dialog appears asking whether you - want to include the PE-Header-Specified Path, which could include a Universal Naming - Convention (UNC) path of a location that might not be trusted. Select OK if you want to - perform this potentially unsafe retrieval.
- - - -
- -- A dialog appears asking where to save the downloaded file. Pick a location to store your - PDB files. A common location on Windows is C:\Symbols.
- -
- -- At this point, if a PDB file of the type you have chosen (either .PDB or .PDB.XML) already - exists in the selected location, you will see a message indicating that a potential matching - PDB has been found. You will then be asked if you would like to continue with the download. -
--
- -- If you select "No", jump to Step 7.
-
-- If you select "Yes", please keep the following things in mind relating to a found - .PDB or .PDB.XML file:
-
--
-- If the found file is not in a directory that contains the current binary's GUID - (i.e., C:\Symbols\<pdbfilename>\<GUID>), then the file is not - guaranteed to be an exact match for the current binary (when there is no GUID subfolder, - a matching file is found based on expected PDB filename).
- -
- -- If there is any doubt about whether the found PDB file matches, it is a good - idea to try to download the matching file, anyway (the matching file will be saved - in a directory of the form <download location>/<pdbfilename>/ - <GUID>).
- -
- -- If you do choose to continue to apply the found PDB file, and its GUID does not - match the GUID of the current binary, you will be warned and given the option of - canceling the application of the PDB file.
-
- -- Next, you will see a dialog asking for the Symbol Server URL. - -
- -
- - - -
- - If a list of known URLs exists in your distribution (the file will have the extension -.pdburl
), the dialog will also include a button with the text "Choose from - known URLs". When this button is pressed, a separate dialog appears showing known Symbol - Server URLs. - -
- - - -
- - You may choose any of these URLs or manually type one in. If manually typing in a URL, - be sure to include the protocol (http or https). - -
- -Always be sure to check your organization's - security policy before downloading any file from the internet.
-
- -- Next, if the Symbol Server contains a matching PDB that is the same file type that you - chose earlier, it will return with a message indicating that the download was successful. - The message also contains the path where you can find the downloaded file.
- - -
- -- If the download was successful or an existing PDB file was found, you may be asked - whether you want to apply the PDB to the program.
- -If Yes is chosen, see - Load PDB File for continued help.
- -
-- - --
-- If you are connecting to a Symbol Server that requires user authentication using PKI, - you must first set your PKI Certificate before attempting to download from the server. See - - PKI Certificate for more details.
-
9>?NhVFc!p27lESRDrpi#R|Fz2mV!?xo`aC+~IWtDvqvn*B>_69Go+ zoH;q#83s-P3G?ba>aCtfhXc2g u{stb} zs<^k5^xkI4ub}rp&UfJv+EOwkblo|z$_80Wz4 )Mcz*89_*1Rg_-3Bt*%|v ta%)=DX YTIUL0UZE< zzLQBy7-i{E>WQBx4? zwpn7hv;2cty0w6I9G;(7Ks6DAWka^@k?n?g_ny@^%6tWkOHen{WT0AaYGD;wI}=xj z#P0gSJr=;Irssp%(&Q5C^arj#T>~Mc&*i{z2?;pf+g>^nl6*ECz`+G2yh_KiyGch~ zw?-E9!@DwXHc~6MUnWWV9g}@S?5kN3fk5rQIe1GkuT>Cgp4QP(cMsWQ`yT&tsF7^r z bp(fPsnE*ZftRTJ}!1pvytEV<`fc= zlA(EEgOmUb=PBHA?7cv#d;Ov`TiW66TH*J7*w?m*U2Nan;pyFuz&rdlZ)5f>Leqyc zunU*z>=Qy5=p_CS`mg@;@E;-k#}fYI1^@Aa|9HXwO)uc>6r*dG80i9j+5$!4QaZXl zZBAGu9UbeBZ!^&Plhbq|eFO#1Yj$!4)d`c2Ei6*zwh=CcaxLm8IR#hz72jrRk9yB9}Ct zvf8Bzr;2vEH-%8hWFvpN7nQz(AWkm@>AAF3GxqDbtu4^0#+h+$DO!@p?r!za7BO^Z z=SG&K@Q1f$`Rp*dlUAF!i30vjT~yRzX>M?}&P=0S+(d~NzX~L>cY(jD b93tY+ITJFKlYYH!Im)MTQFZ)h?{U z)Hw>)WTb7sSLCbR1Fa0^+?nkL_<<5q-LNXQ-Yt#r1nGwd3b!RZMa-mg?Mc8|9(!*d z;jDv;hJ?1%axVqSxuwWH+wxKga+!H=9h_>kdz_6rwA*`Jx&Lgn=P*eCyuzA1F*i4t zDyR!LxZ^#m?B+36_AB<{4HHIeNK#y!Ldf<<>2V?u0(dPMp_1e7(RT9bUDDcAvI6F8 zYL`5g_V&J~;ASrDt*=3FdVmnRiN(5VxC*7ou=Vn?{N_tAAP<$7#ndKEC sPeI5@vmSpMsJ%CuGJYBxE0A_^J0 zQa;h~XR(%v6F}^h#HV5ym zLy7=iVI&HOK3~!^25n4Ad-ky2NB!kf#Mr&Qw?Z?9^!KTXRV(lHbxksf3`-eow8_;B zWM#?s;ATSmKYZn3kFtgQo+$L54F`w3mewIomxOqZ6!$fm5TYjvM{qUV11`e_RY2MP zaF-}(DrM7nP2$t1PXKT6{`^&?Adma^U;I)7(t7n6mZZc)Jv}`eATE8yz%=%S@sALm zc9Xc_hq&Q4wwo nSJb *c~Wkp4G*lvr9>s4_BQ>DZu zE}G^kW?4k~c&wz*& Kq(zKw+!hl1N4kgMu z@hN!4E7`oy%u=?=w93lV44nc7XsXQ^{;1m&nuzQhAh~y|bWRLmn0w5cX#R9PgGlTt zi~|2& CfyhZyUiIhM)l8BGXDUjea= xtk?m0o7GL%@S{$~SA>X|F@H)l}!CN%?L4zZYn=tWtk=MD~@5Pe|oIueN_ zhpkKgv*PMbch{{SrLbuNT)JeP>Zm<3#FJX0SZ%mjuUg*GRLoL~k~=Uk(s^UBo(TAd z)q*Mi!sQn{NH!Sd(6c3ixVzSgEv-HZBamS|#_Rn_;YL|7T(hsz!E*l6QhIt=qzrAo z-Qmr@U$s7X*>^Z8@o!>H`S+dmO><%Qj4jl-RsOgcp{bP^ODwFU?x-|jkc>TI8c)YM zCg_1x1NeL3a2r5l#J PE9=^%`eyz9I5xhM0o&5rg&+RwHx=J-e ztM-c#_;@!W+hx4a`0LO^A=xmZ{*H(34f!y($IG$g2pN%_525hw)16RFu !Y@a1{Tgd-=%ToR_wAs)xrvEtje*KRByi9tiz5C zM`MZ?1Gfone?(`?&d2AKEXa8T &J1+ z3ZnDbDw2B46Pj>_^IViwl@2NsEN8?ax@&W!hGZJ!OS5l_8O$Pnv*r{ wMkwJEA585`9VvLd9o4TX5KEiddUZl7673ik72 zjFSS)TY)BYLp`SF=!W^pxybRUt$6{$FtYa_tvN56zI7bP^aMJFmYK_i4Du|1nBnMP zXQJ$>!$h@hMGbIVjGX*8Z+?a7$N8tB_qs;>5 UzH|N z5f1^K%c!Th>j(R1Y_-{@*6Zzc!ILgCYG^yyXNA`0mAWe66p#Hl#5ZvfsN?NQvv{`$ z|Jb?=5A5Q_i!u$-jI1Bzi_bAJDf!H`188m407h3@-a+4*w 0bg`D*))Zc+#MI z`tabO%A#fgs7l1J^2>261+4l2^oWS@mvl*6%p^UDy7vHB&x=!ipVHFQON%Fu_MSma zvbxyh@iBaG&r0g%RhV$Wty#Z#@fArcN$ !}3(-s;3kp0}YAiL@4f~oVIfcEJ&j;$%V%t&J5-OP>M z4Dl6FtJ#&cr>cf2gC~yF?XB;3!+Uk~^{UH+QiG2E@rbmk5S4&lMI6A=0^+i&b<_r0 z4_*O{g;plAn750-QDKVe=YdQO0}4y5dF;>y@Qx) Gq@& zt=IUTcTP7vNi|8xIb6m(XFkhOq0}&R>r9d3r~6txyhx@@zJS3fVM|!O$fb2k?1Jg+ zK5)CG4IoIDnK^WU4o8659j~?(8~D>F*i8xp3RBuf$Uc1@&l2v5N=pZ N$_i{j1UPE?{x9>s2wjanj#H$ zpY-Bc)<$q@300-aD1KKPv6YlIijbOA!+o}uD_I$4IKZ5U9`sTJ=)OR<>1K(?4aH8aarpb3VuKA|7(bCpE+ z1gz4eSXZa-X O`g zpJD(o+h0mE1ga1F$9uRe7DBW2&;kYE1=IEYnm@7^L}{MC_ZVwW%6%|UGT(q`sbEbF^t%!$!*6Sp}nlob8i$?M?y@8 z3RHM_c-*OR69Bmx$RBnmgD4bJ4Qc_?QUYfheHRzH625c~UI(dMA`#x7tEaWBe#IrU zW?F%tWeaD0=ym6?%mgrf{X^xkQKjZw*7JYf(`kKY;`p&EysV`69S#jazv?l4|7kD9 zu8M #`+wyju_U7RWxuiddvKT zQ~atBP6kk}udgp5R~I7vzfLYI__~!33>(^PN#1L?bY-qj_IAS=3*l5mv&KI&kIQmO z+Psth1)#_mh h=Xx z9Z+Eu0;}551uiZmkV5?F0p9kJVaSQq(-i8$VaQK9p^RzJP2jQ@=LwtRb+5A*3)q!a z|G#kq3Mh9!_oAm$=8ZF3Zwq$wI`hvX3_#JG+*5R{nxD~7;P%qa%5d8`Iv@5wcg0{p z7a{; ~4Q(P?WKJgR Iqd=lzNSTj{pDwUdu>}s{#N}(g46qN4S@ePp*Pt3;+N> zfQ-0^y1OAb16CbF2WQ}OF>0zhA_8rgIo8sm#C)xZgALAn*lTtDnj|H4a2Yv5NSJnY zIb2BYC)t?X^GpDG IkJV8+!^gw8CJ<8Gm{T_tlEl>FH4xH&wdLi40NO zYsiq#KkBK~a$3B0eD|;Z`v1jS(2GCcp#9(dMGGU?dah$B%xJdR9Kaff`i-K$WdTJh z)J0CmuNn%_up$0y_RFt>I-K(StlMw($IEV`{VM~XtFmvibthlbC-f9C=Q?FzR~BZK zYSY3zR6D%@C^K1{ ++ZArFOs$`2|8_MhqeY&u@ep({)AByP)^Xqkx%t=XQ1QN76uh; $*R%H?=Va(4Jh0NdNp%{t7eOypz!cbE%+tqVcVOYL{i#?@vQ z*q$PAl$;Yfl$yImo1!@36a$JhVFxQuC@vu1UHA20pcJ_7cXRhxyT8=mt1m@$z@u~l z_rlLfR(OeSgHNFX3|Q`Bq+a$=Jwym$I)#RPRIMF@%t`%xcS@>O6Gs>rJL9y1>v)R` z%fHwz1^e5mF0aX6z{f~1aNlILqPmbBfl`KTxQ>n%)#_huv^t&n`#BelN#v;w0*D%q zmy>vAJLbRGwLL)fm^?&f5%60@k#|SYb{Omk*(|$Zqyj>bh88kbUl6rkika9?I$iyc zOMd_B6fxgY>UL=OxSmn)XU#Fs&lJDG?y0w;C`|g>ojz&fduOc0{+Pi;ZC4ce MLXbe@O_ojzsU=wiW7Ej)IYCZW!^!J=ru;wBvC zr4PH}xTU