mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-22 10:02:49 +08:00
Merge remote-tracking branch 'origin/Ghidra_9.2'
This commit is contained in:
+1
-1
@@ -327,7 +327,7 @@ public class CreateThunkFunctionCmd extends BackgroundCommand {
|
||||
Symbol s = program.getSymbolTable().getPrimarySymbol(referencedFunctionAddr);
|
||||
if (s != null) {
|
||||
ExternalLocation extLoc = (ExternalLocation) s.getObject();
|
||||
Msg.debug(this,
|
||||
Msg.trace(this,
|
||||
"Converting external location to function as a result of thunk at: " + entry);
|
||||
return extLoc.createFunction();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
/* ###
|
||||
* 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.program.examiner;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.GhidraException;
|
||||
import ghidra.GhidraTestApplicationLayout;
|
||||
import ghidra.app.plugin.core.analysis.EmbeddedMediaAnalyzer;
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.app.util.importer.AutoImporter;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.HeadlessGhidraApplicationConfiguration;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.util.DefaultLanguageService;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
import utility.application.ApplicationLayout;
|
||||
|
||||
/**
|
||||
* Wrapper for Ghidra code to find images (and maybe other artifacts later) in a program
|
||||
*
|
||||
* NOTE: This is intended for end-user use and has no direct references within Ghidra.
|
||||
* Typical use of the class entails generating a ghidra.jar (see BuildGhidraJarScript.java)
|
||||
* and referencing this class from end-user code.
|
||||
*/
|
||||
public class ProgramExaminer {
|
||||
|
||||
private MessageLog messageLog;
|
||||
private Program program;
|
||||
|
||||
private static Language defaultLanguage;
|
||||
|
||||
/**
|
||||
* Constructs a new ProgramExaminer.
|
||||
* @param bytes the bytes of the potential program to be examined.
|
||||
* @throws GhidraException if any exception occurs while processing the bytes.
|
||||
*/
|
||||
public ProgramExaminer(byte[] bytes) throws GhidraException {
|
||||
this(createByteProvider(bytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ProgramExaminer.
|
||||
* @param file file object containing the bytes to be examined.
|
||||
* @throws GhidraException if any exception occurs while processing the bytes.
|
||||
*/
|
||||
public ProgramExaminer(File file) throws GhidraException {
|
||||
this(createByteProvider(file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string indication the program format. i.e. PE, elf, raw
|
||||
*/
|
||||
public String getType() {
|
||||
return program.getExecutableFormat();
|
||||
}
|
||||
|
||||
private ProgramExaminer(ByteProvider provider) throws GhidraException {
|
||||
initializeGhidra();
|
||||
messageLog = new MessageLog();
|
||||
try {
|
||||
program = AutoImporter.importByUsingBestGuess(provider, null, this, messageLog,
|
||||
TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
|
||||
if (program == null) {
|
||||
program = AutoImporter.importAsBinary(provider, null, defaultLanguage, null, this,
|
||||
messageLog, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
}
|
||||
if (program == null) {
|
||||
throw new GhidraException(
|
||||
"Can't create program from input: " + messageLog.toString());
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
messageLog.appendException(e);
|
||||
throw new GhidraException(e);
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
provider.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// tried to close
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized static void initializeGhidra() throws GhidraException {
|
||||
if (!Application.isInitialized()) {
|
||||
ApplicationLayout layout;
|
||||
try {
|
||||
layout =
|
||||
new GhidraTestApplicationLayout(new File(System.getProperty("java.io.tmpdir")));
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GhidraException(e);
|
||||
}
|
||||
HeadlessGhidraApplicationConfiguration config =
|
||||
new HeadlessGhidraApplicationConfiguration();
|
||||
config.setInitializeLogging(false);
|
||||
Application.initializeApplication(layout, config);
|
||||
}
|
||||
if (defaultLanguage == null) {
|
||||
LanguageService languageService = DefaultLanguageService.getLanguageService();
|
||||
try {
|
||||
defaultLanguage = languageService
|
||||
.getDefaultLanguage(Processor.findOrPossiblyCreateProcessor("DATA"));
|
||||
}
|
||||
catch (LanguageNotFoundException e) {
|
||||
throw new GhidraException("Can't load default language: DATA");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases file/database resources.
|
||||
*/
|
||||
public void dispose() {
|
||||
program.release(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of byte[] containing image data. The bytes will be either a png, a gif, or
|
||||
* a bitmap
|
||||
*/
|
||||
public List<byte[]> getImages() {
|
||||
runImageAnalyzer();
|
||||
|
||||
List<byte[]> imageList = new ArrayList<byte[]>();
|
||||
DataIterator it = program.getListing().getDefinedData(true);
|
||||
while (it.hasNext()) {
|
||||
accumulateImageData(imageList, it.next());
|
||||
}
|
||||
return imageList;
|
||||
}
|
||||
|
||||
private void accumulateImageData(List<byte[]> imageList, Data data) {
|
||||
if (!isImage(data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
imageList.add(data.getBytes());
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
// suppress (this shouldn't happen
|
||||
}
|
||||
}
|
||||
|
||||
private void runImageAnalyzer() {
|
||||
int txID = program.startTransaction("find images");
|
||||
try {
|
||||
EmbeddedMediaAnalyzer imageAnalyzer = new EmbeddedMediaAnalyzer();
|
||||
imageAnalyzer.added(program, program.getMemory(), TaskMonitorAdapter.DUMMY_MONITOR,
|
||||
messageLog);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// using Dummy, can't happen
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(txID, true);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isImage(Data data) {
|
||||
DataType dataType = data.getDataType();
|
||||
if (dataType instanceof PngDataType) {
|
||||
return true;
|
||||
}
|
||||
if (dataType instanceof GifDataType) {
|
||||
return true;
|
||||
}
|
||||
if (dataType instanceof BitmapResourceDataType) {
|
||||
return true;
|
||||
}
|
||||
if (dataType instanceof IconResourceDataType) {
|
||||
return true;
|
||||
}
|
||||
if (dataType instanceof JPEGDataType) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// static methods
|
||||
//==================================================================================================
|
||||
|
||||
private static ByteProvider createByteProvider(byte[] bytes) throws GhidraException {
|
||||
if (bytes == null) {
|
||||
throw new GhidraException("Attempted to process a null byte[].");
|
||||
}
|
||||
if (bytes.length == 0) {
|
||||
throw new GhidraException("Attempted to process an empty byte[].");
|
||||
}
|
||||
return new ByteArrayProvider("Bytes", bytes);
|
||||
}
|
||||
|
||||
private static ByteProvider createByteProvider(File file) throws GhidraException {
|
||||
if (file == null) {
|
||||
throw new GhidraException("Attempted to process a null file");
|
||||
}
|
||||
try {
|
||||
return new RandomAccessByteProvider(file);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GhidraException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+24
-14
@@ -17,10 +17,13 @@ package ghidra.app.plugin.core.analysis;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.util.bin.format.pdb.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.app.util.opinion.PeLoader;
|
||||
import ghidra.app.util.pdb.PdbLocator;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.preferences.Preferences;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
@@ -34,15 +37,19 @@ import ghidra.util.task.TaskMonitor;
|
||||
* Finds and applies PDB debug information to the given Windows executable.
|
||||
*/
|
||||
public class PdbAnalyzer extends AbstractAnalyzer {
|
||||
private static final String NAME = "PDB";
|
||||
private static final String DESCRIPTION = "Automatically loads a PDB file if found.";
|
||||
static final String NAME = "PDB";
|
||||
static final boolean DEFAULT_ENABLEMENT = !PdbUniversalAnalyzer.DEFAULT_ENABLEMENT;
|
||||
private static final String DESCRIPTION =
|
||||
"PDB Analyzer.\n" + "Requires MS DIA-SDK for raw PDB processing (Windows only).\n" +
|
||||
"Also supports pre-processed XML files.";
|
||||
|
||||
private static final String ERROR_TITLE = "Error in PDB Analyzer";
|
||||
|
||||
private static final String SYMBOLPATH_OPTION_NAME = "Symbol Repository Path";
|
||||
private static final String SYMBOLPATH_OPTION_DESCRIPTION =
|
||||
"Directory path to root of Microsoft Symbol Repository Directory";
|
||||
private static final String SYMBOLPATH_OPTION_DEFAULT_VALUE = "C:\\Symbols";
|
||||
private static final String SYMBOLPATH_OPTION_DEFAULT_VALUE =
|
||||
PdbLocator.DEFAULT_SYMBOLS_DIR.getAbsolutePath();
|
||||
|
||||
private String symbolsRepositoryPath = SYMBOLPATH_OPTION_DEFAULT_VALUE;
|
||||
|
||||
@@ -58,7 +65,7 @@ public class PdbAnalyzer extends AbstractAnalyzer {
|
||||
//==============================================================================================
|
||||
public PdbAnalyzer() {
|
||||
super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER);
|
||||
setDefaultEnablement(true);
|
||||
setDefaultEnablement(DEFAULT_ENABLEMENT);
|
||||
setPriority(AnalysisPriority.FORMAT_ANALYSIS.after());
|
||||
setSupportsOneTimeAnalysis();
|
||||
}
|
||||
@@ -70,12 +77,19 @@ public class PdbAnalyzer extends AbstractAnalyzer {
|
||||
return true;
|
||||
}
|
||||
|
||||
File pdb = lookForPdb(program, includePeSpecifiedPdbPath, log);
|
||||
|
||||
if (pdb == null) {
|
||||
if (PdbUniversalAnalyzer.isEnabled(program)) {
|
||||
log.appendMsg(getName(),
|
||||
"Stopped: Cannot run with " + PdbUniversalAnalyzer.NAME + " Analyzer enabled");
|
||||
return false;
|
||||
}
|
||||
Msg.info(this, getClass().getSimpleName() + " configured to use: " + pdb.getAbsolutePath());
|
||||
|
||||
File pdb = lookForPdb(program, log);
|
||||
|
||||
if (pdb == null) {
|
||||
Msg.info(this, "PDB analyzer failed to locate PDB file");
|
||||
return false;
|
||||
}
|
||||
Msg.info(this, "PDB analyzer parsing file: " + pdb.getAbsolutePath());
|
||||
|
||||
AutoAnalysisManager mgr = AutoAnalysisManager.getAnalysisManager(program);
|
||||
return parsePdb(pdb, program, mgr, monitor, log);
|
||||
@@ -85,7 +99,7 @@ public class PdbAnalyzer extends AbstractAnalyzer {
|
||||
// object existence indicates missing PDB has already been reported
|
||||
}
|
||||
|
||||
File lookForPdb(Program program, boolean includePeSpecifiedPdbPath, MessageLog log) {
|
||||
File lookForPdb(Program program, MessageLog log) {
|
||||
String message = "";
|
||||
File pdb;
|
||||
|
||||
@@ -104,7 +118,7 @@ public class PdbAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
String pdbName = program.getOptions(Program.PROGRAM_INFO).getString(
|
||||
PdbParserConstants.PDB_FILE, (String) null);
|
||||
if (pdbName == null) {
|
||||
if (StringUtils.isBlank(pdbName)) {
|
||||
message = "Program has no associated PDB file.";
|
||||
}
|
||||
else {
|
||||
@@ -125,9 +139,6 @@ public class PdbAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
return pdb;
|
||||
}
|
||||
catch (PdbException pe) {
|
||||
message += pe.getMessage();
|
||||
}
|
||||
finally {
|
||||
if (message.length() > 0) {
|
||||
log.appendMsg(getName(), message);
|
||||
@@ -135,7 +146,6 @@ public class PdbAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean parsePdb(File pdb, Program program, AutoAnalysisManager mgr, TaskMonitor monitor,
|
||||
|
||||
+79
-126
@@ -19,9 +19,10 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import docking.widgets.OkDialog;
|
||||
import docking.widgets.OptionDialog;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.util.bin.format.pdb.PdbParserConstants;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.app.util.opinion.PeLoader;
|
||||
@@ -31,14 +32,11 @@ import ghidra.app.util.pdb.pdbapplicator.*;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.options.OptionType;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.preferences.Preferences;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.data.CharsetInfo;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.bean.opteditor.OptionsVetoException;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
@@ -61,15 +59,12 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||
private static final boolean developerMode = false;
|
||||
|
||||
//==============================================================================================
|
||||
private static final String NAME = "PDB Universal Reader/Analyzer";
|
||||
static final String NAME = "PDB Universal";
|
||||
// TODO: decide which PDB Analyzer should be enabled by default for release
|
||||
static final boolean DEFAULT_ENABLEMENT = false;
|
||||
private static final String DESCRIPTION =
|
||||
"[PDB EVOLUTIONARY PROTOTYPE V1] [OPTIONS MAY CHANGE]\n" +
|
||||
"Platform-indepent PDB analysis\n" +
|
||||
"(No XML. Will not run with DIA-based PDB Analyzer.)";
|
||||
|
||||
private final static String PDB_STORAGE_PROPERTY = "PDB Storage Directory";
|
||||
// TODO; look into what we can do with the following (old analyzer says this is a "thing")
|
||||
//public final static File SPECIAL_PDB_LOCATION = new File("C:/WINDOWS/Symbols");
|
||||
"[Prototype V1] Platform-indepent PDB analyzer (No XML support).\n" +
|
||||
"NOTE: still undergoing development, so options may change.";
|
||||
|
||||
//==============================================================================================
|
||||
// Force-load a PDB file.
|
||||
@@ -82,14 +77,15 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||
private static final String OPTION_NAME_FORCELOAD_FILE = "Force-Load FilePath";
|
||||
private static final String OPTION_DESCRIPTION_FORCELOAD_FILE =
|
||||
"This file is force-loaded if the '" + OPTION_NAME_DO_FORCELOAD + "' option is checked";
|
||||
private File forceLoadFile = null;
|
||||
private File DEFAULT_FORCE_LOAD_FILE = new File(PdbLocator.DEFAULT_SYMBOLS_DIR, "sample.pdb");
|
||||
private File forceLoadFile;
|
||||
|
||||
// Symbol Repository Path.
|
||||
private static final String OPTION_NAME_SYMBOLPATH = "Symbol Repository Path";
|
||||
private static final String OPTION_DESCRIPTION_SYMBOLPATH =
|
||||
"Directory path to root of Microsoft Symbol Repository Directory";
|
||||
private File symbolsRepositoryPath = null; // value set in constructor
|
||||
private File defaultSymbolsRepositoryPath = Application.getUserTempDirectory();
|
||||
private File DEFAULT_SYMBOLS_DIR = PdbLocator.DEFAULT_SYMBOLS_DIR;
|
||||
private File symbolsRepositoryDir;
|
||||
|
||||
// Include the PE-Header-Specified PDB path for searching for appropriate PDB file.
|
||||
private static final String OPTION_NAME_INCLUDE_PE_PDB_PATH =
|
||||
@@ -208,53 +204,51 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||
public PdbUniversalAnalyzer() {
|
||||
super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER);
|
||||
setPrototype();
|
||||
// false for now; after proven... then TODO: true always
|
||||
setDefaultEnablement(false);
|
||||
// or...
|
||||
// false for now if on Windows; after proven... then TODO: true always
|
||||
// setDefaultEnablement(!onWindows);
|
||||
setDefaultEnablement(DEFAULT_ENABLEMENT);
|
||||
setPriority(AnalysisPriority.FORMAT_ANALYSIS.after());
|
||||
setSupportsOneTimeAnalysis();
|
||||
|
||||
String pdbStorageLocation = Preferences.getProperty(PDB_STORAGE_PROPERTY, null, true);
|
||||
if (pdbStorageLocation != null) {
|
||||
symbolsRepositoryPath = new File(pdbStorageLocation);
|
||||
}
|
||||
else {
|
||||
symbolsRepositoryPath = defaultSymbolsRepositoryPath;
|
||||
}
|
||||
if (!symbolsRepositoryPath.isDirectory()) {
|
||||
symbolsRepositoryPath = new File(File.separator);
|
||||
}
|
||||
pdbStorageLocation = symbolsRepositoryPath.getAbsolutePath();
|
||||
forceLoadFile = new File(pdbStorageLocation + File.separator + "sample.pdb");
|
||||
|
||||
pdbReaderOptions = new PdbReaderOptions();
|
||||
pdbApplicatorOptions = new PdbApplicatorOptions();
|
||||
}
|
||||
|
||||
static boolean isEnabled(Program program) {
|
||||
Options analysisOptions = program.getOptions(Program.ANALYSIS_PROPERTIES);
|
||||
return analysisOptions.getBoolean(NAME, DEFAULT_ENABLEMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
|
||||
throws CancelledException {
|
||||
|
||||
// NOTE: Legacy PDB Analyzer currently yields to this analyzer if both are enabled
|
||||
// if (PdbAnalyzer.isEnabled(program)) {
|
||||
// log.appendMsg(getName(),
|
||||
// "Stopped: Cannot run with Legacy PDB Analyzer enabled");
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// TODO:
|
||||
// Work on use cases...
|
||||
// Code for checking if the PDB is already loaded (... assumes it was analyzed as well).
|
||||
// Need different logic... perhaps we could have multiple PDBs loaded already and need
|
||||
// to decide if any of those is the "correct" one or even look for another one.
|
||||
// NOTE: if PDB previously applied the PDB load should be used instead of analyzer.
|
||||
// Probably still need to have a loader separate from the loader/analyzer, but then have
|
||||
// the ability to analyze (apply) any given already-loaded PDB to the program. A PDB
|
||||
// loader should probably be able to load an optionally apply data types to its own
|
||||
// category manager. Question would be if/how we "might" try to resolve any of these
|
||||
// against the "main" category data types.
|
||||
|
||||
if (oldPdbAnalyzerEnabled(program)) {
|
||||
log.appendMsg(getName(), "Stopped: Cannot run with DIA-based PDB Analyzer enabled");
|
||||
return false;
|
||||
}
|
||||
|
||||
PdbProgramAttributes programAttributes = new PdbProgramAttributes(program);
|
||||
if (failMissingFilename(programAttributes, log) ||
|
||||
if (programAttributes.isPdbLoaded()) {
|
||||
Msg.info(this, "Skipping PDB analysis since it has previouslu run.");
|
||||
Msg.info(this,
|
||||
">> Clear 'PDB Loaded' program property or use Load PDB action if " +
|
||||
"additional PDB processing required.");
|
||||
}
|
||||
if (programAttributes.isPdbLoaded() ||
|
||||
failMissingFilename(programAttributes, log) ||
|
||||
failMissingAttributes(programAttributes, log)) {
|
||||
return true;
|
||||
}
|
||||
@@ -263,18 +257,27 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
String pdbFilename;
|
||||
if (doForceLoad) {
|
||||
if (!confirmFile(forceLoadFile)) {
|
||||
logFailure("Force-load PDB file does not exist: " + forceLoadFile, log);
|
||||
return false;
|
||||
}
|
||||
pdbFilename = forceLoadFile.getAbsolutePath();
|
||||
}
|
||||
else {
|
||||
PdbLocator locator = new PdbLocator(symbolsRepositoryPath);
|
||||
PdbLocator locator = new PdbLocator(symbolsRepositoryDir);
|
||||
pdbFilename =
|
||||
locator.findPdb(program, programAttributes, !SystemUtilities.isInHeadlessMode(),
|
||||
includePeSpecifiedPdbPath, monitor, log, getName());
|
||||
if (pdbFilename == null) {
|
||||
if (!confirmDirectory(symbolsRepositoryDir)) {
|
||||
logFailure("PDB symbol repository directory not found: " + symbolsRepositoryDir,
|
||||
log);
|
||||
}
|
||||
Msg.info(this, "PDB analyzer failed to locate PDB file");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Msg.info(this, getClass().getSimpleName() + " configured to use: " + pdbFilename);
|
||||
Msg.info(this, "PDB analyzer parsing file: " + pdbFilename);
|
||||
|
||||
PdbLog.message(
|
||||
"================================================================================");
|
||||
@@ -290,17 +293,14 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||
PdbApplicator applicator = new PdbApplicator(pdbFilename, pdb);
|
||||
applicator.applyTo(program, program.getDataTypeManager(), program.getImageBase(),
|
||||
pdbApplicatorOptions, monitor, log);
|
||||
|
||||
Options options = program.getOptions(Program.PROGRAM_INFO);
|
||||
options.setBoolean(PdbParserConstants.PDB_LOADED, true);
|
||||
|
||||
}
|
||||
catch (PdbException e) {
|
||||
String message = "Issue processing PDB file: " + pdbFilename +
|
||||
". Detailed issues may follow:\n" + e.toString();
|
||||
log.appendMsg(getName(), message);
|
||||
return false;
|
||||
}
|
||||
catch (IOException e) {
|
||||
String message = "Issue processing PDB file: " + pdbFilename +
|
||||
". Detailed issues may follow:\n" + e.toString();
|
||||
log.appendMsg(getName(), message);
|
||||
catch (PdbException | IOException e) {
|
||||
log.appendMsg(getName(),
|
||||
"Issue processing PDB file: " + pdbFilename + ":\n " + e.toString());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -341,11 +341,12 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||
@Override
|
||||
public void registerOptions(Options options, Program program) {
|
||||
// PDB file location information
|
||||
options.registerOption(OPTION_NAME_DO_FORCELOAD, doForceLoad, null,
|
||||
options.registerOption(OPTION_NAME_DO_FORCELOAD, Boolean.FALSE, null,
|
||||
OPTION_DESCRIPTION_DO_FORCELOAD);
|
||||
options.registerOption(OPTION_NAME_FORCELOAD_FILE, OptionType.FILE_TYPE, forceLoadFile,
|
||||
options.registerOption(OPTION_NAME_FORCELOAD_FILE, OptionType.FILE_TYPE,
|
||||
DEFAULT_FORCE_LOAD_FILE,
|
||||
null, OPTION_DESCRIPTION_FORCELOAD_FILE);
|
||||
options.registerOption(OPTION_NAME_SYMBOLPATH, OptionType.FILE_TYPE, symbolsRepositoryPath,
|
||||
options.registerOption(OPTION_NAME_SYMBOLPATH, OptionType.FILE_TYPE, DEFAULT_SYMBOLS_DIR,
|
||||
null, OPTION_DESCRIPTION_SYMBOLPATH);
|
||||
options.registerOption(OPTION_NAME_INCLUDE_PE_PDB_PATH, includePeSpecifiedPdbPath, null,
|
||||
OPTION_DESCRIPTION_INCLUDE_PE_PDB_PATH);
|
||||
@@ -397,34 +398,11 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||
@Override
|
||||
public void optionsChanged(Options options, Program program) {
|
||||
|
||||
// This test can go away once this new analyzer completely replaces the old analyzer.
|
||||
if (!SystemUtilities.isInHeadlessMode() && oldPdbAnalyzerEnabled(program) &&
|
||||
thisPdbAnalyzerEnabled(program)) {
|
||||
OkDialog.show("Warning",
|
||||
"Cannot use PDB Universal Analyzer and DIA-based PDB Analyzer at the same time");
|
||||
}
|
||||
|
||||
doForceLoad = options.getBoolean(OPTION_NAME_DO_FORCELOAD, doForceLoad);
|
||||
|
||||
File pdbFile = options.getFile(OPTION_NAME_FORCELOAD_FILE, forceLoadFile);
|
||||
if (doForceLoad) {
|
||||
if (pdbFile == null) {
|
||||
throw new OptionsVetoException("Force-load file field is missing");
|
||||
}
|
||||
else if (!confirmFile(pdbFile)) {
|
||||
throw new OptionsVetoException(pdbFile + " force-load file does not exist");
|
||||
}
|
||||
}
|
||||
forceLoadFile = pdbFile;
|
||||
forceLoadFile = options.getFile(OPTION_NAME_FORCELOAD_FILE, forceLoadFile);
|
||||
|
||||
File path = options.getFile(OPTION_NAME_SYMBOLPATH, symbolsRepositoryPath);
|
||||
if (path == null) {
|
||||
throw new OptionsVetoException("Symbol Path field is missing");
|
||||
}
|
||||
else if (!confirmDirectory(path)) {
|
||||
throw new OptionsVetoException(path + " is not a valid directory");
|
||||
}
|
||||
symbolsRepositoryPath = path;
|
||||
symbolsRepositoryDir = options.getFile(OPTION_NAME_SYMBOLPATH, DEFAULT_SYMBOLS_DIR);
|
||||
|
||||
includePeSpecifiedPdbPath =
|
||||
options.getBoolean(OPTION_NAME_INCLUDE_PE_PDB_PATH, includePeSpecifiedPdbPath);
|
||||
@@ -459,67 +437,43 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
private boolean oldPdbAnalyzerEnabled(Program program) {
|
||||
String oldPdbNAME = "PDB";
|
||||
// This assert is just to catch us if we change the new NAME to what the old name is
|
||||
// without first eliminating the call to this method and this method altogether.
|
||||
if (NAME.contentEquals(oldPdbNAME)) {
|
||||
throw new AssertException(
|
||||
"Developer error: old and new PDB analyzers were not renamed correctly");
|
||||
}
|
||||
Options analysisOptions = program.getOptions(Program.ANALYSIS_PROPERTIES);
|
||||
// Don't have access to ghidra.app.plugin.core.analysis.PdbAnalyzer.NAME so using string.
|
||||
boolean isPdbEnabled = analysisOptions.getBoolean(oldPdbNAME, false);
|
||||
return isPdbEnabled;
|
||||
}
|
||||
|
||||
private boolean thisPdbAnalyzerEnabled(Program program) {
|
||||
Options analysisOptions = program.getOptions(Program.ANALYSIS_PROPERTIES);
|
||||
// Don't have access to ghidra.app.plugin.core.analysis.PdbAnalyzer.NAME so using string.
|
||||
boolean isPdbEnabled = analysisOptions.getBoolean(NAME, false);
|
||||
return isPdbEnabled;
|
||||
}
|
||||
|
||||
private boolean failMissingFilename(PdbProgramAttributes attributes, MessageLog log) {
|
||||
if (attributes.getPdbFile() == null || attributes.getPdbFile().isEmpty()) {
|
||||
String message = "No PdbFile specified in program... Skipping PDB processing.";
|
||||
log.appendMsg(getName(), message);
|
||||
log.setStatus(message);
|
||||
if (doForceLoad) {
|
||||
return false; // PDB File property not used for forced load
|
||||
}
|
||||
if (StringUtils.isEmpty(attributes.getPdbFile())) {
|
||||
logFailure("Missing 'PDB File' program property, unable to locate PDB", log);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void logFailure(String msg, MessageLog log) {
|
||||
log.appendMsg(getName(), msg);
|
||||
log.appendMsg(getName(), "Skipping PDB processing");
|
||||
log.setStatus(msg);
|
||||
}
|
||||
|
||||
private boolean failMissingAttributes(PdbProgramAttributes attributes, MessageLog log) {
|
||||
if (doForceLoad) {
|
||||
return false; // Attributes not used for forced load
|
||||
}
|
||||
// RSDS version should only have GUID; non-RSDS version should only have Signature.
|
||||
String warning;
|
||||
String error;
|
||||
if ("RSDS".equals(attributes.getPdbVersion())) {
|
||||
if (attributes.getPdbGuid() != null) {
|
||||
if (!StringUtils.isEmpty(attributes.getPdbGuid())) {
|
||||
return false; // Don't fail.
|
||||
}
|
||||
warning = "No Program GUID to match with PDB.";
|
||||
error = "Missing 'PDB GUID' program property, unable to locate PDB.";
|
||||
}
|
||||
else {
|
||||
if (attributes.getPdbSignature() != null) {
|
||||
if (!StringUtils.isEmpty(attributes.getPdbSignature())) {
|
||||
return false; // Don't fail.
|
||||
}
|
||||
warning = "No Program Signature to match with PDB.";
|
||||
error = "Missing 'PDB Signature' program property, unable to locate PDB.";
|
||||
}
|
||||
String message;
|
||||
if (!SystemUtilities.isInHeadlessMode()) {
|
||||
int option = OptionDialog.showYesNoDialog(null, "Continue Loading PDB?",
|
||||
warning + "\n " + "\nContinue anyway?" + "\n " +
|
||||
"\nPlease note: Invalid disassembly may be produced!");
|
||||
if (option == OptionDialog.OPTION_ONE) {
|
||||
message = warning + ".. Continuing PDB processing.";
|
||||
log.appendMsg(getName(), message);
|
||||
log.setStatus(message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
message = warning + ".. Skipping PDB processing.";
|
||||
log.appendMsg(getName(), message);
|
||||
log.setStatus(message);
|
||||
logFailure(error, log);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -530,8 +484,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||
catch (IOException e) {
|
||||
// Probably could not open the file.
|
||||
if (log != null) {
|
||||
log.appendMsg(getClass().getSimpleName(),
|
||||
"IOException when trying to open PdbLog file: ");
|
||||
log.appendMsg(getName(), "IOException when trying to open PDB log file: ");
|
||||
log.appendException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.xml.sax.SAXException;
|
||||
|
||||
import docking.widgets.OptionDialog;
|
||||
import ghidra.app.cmd.label.SetLabelPrimaryCmd;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DuplicateIdException;
|
||||
import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.app.util.NamespaceUtils;
|
||||
@@ -229,11 +230,10 @@ public class PdbParser {
|
||||
|
||||
/**
|
||||
* Open Windows Data Type Archives
|
||||
*
|
||||
* @throws IOException if an i/o error occurs opening the data type archive
|
||||
* @throws Exception if any other error occurs
|
||||
* @throws DuplicateIdException unexpected archive error
|
||||
*/
|
||||
public void openDataTypeArchives() throws IOException, Exception {
|
||||
public void openDataTypeArchives() throws IOException, DuplicateIdException {
|
||||
|
||||
if (program != null) {
|
||||
List<String> archiveList = DataTypeArchiveUtility.getArchiveList(program);
|
||||
@@ -315,7 +315,7 @@ public class PdbParser {
|
||||
checkPdbLoaded();
|
||||
|
||||
errHandler.setMessageLog(log);
|
||||
Msg.debug(this, "Found PDB for " + program.getName());
|
||||
Msg.debug(this, "Found PDB for " + program.getName() + ": " + pdbFile);
|
||||
try {
|
||||
|
||||
ApplyDataTypes applyDataTypes = null;
|
||||
@@ -391,7 +391,7 @@ public class PdbParser {
|
||||
options.setBoolean(PdbParserConstants.PDB_LOADED, true);
|
||||
|
||||
if (dataTypeParser != null && dataTypeParser.hasMissingBitOffsetError()) {
|
||||
log.error("PDB",
|
||||
log.appendMsg("PDB",
|
||||
"One or more bitfields were specified without bit-offset data.\nThe use of old pdb.xml data could be the cause.");
|
||||
}
|
||||
}
|
||||
@@ -619,8 +619,8 @@ public class PdbParser {
|
||||
pdbGuid = "{" + pdbGuid + "}";
|
||||
|
||||
if (!xmlGuid.equals(pdbGuid)) {
|
||||
warning = "PDB signature does not match.";
|
||||
}
|
||||
warning = "PDB signature does not match.\n" + "Program GUID: " + pdbGuid +
|
||||
"\nXML GUID: " + xmlGuid; }
|
||||
else {
|
||||
// Also check that PDB ages match, if they are both available
|
||||
if ((xmlAge != null) && (pdbAge != null)) {
|
||||
@@ -1045,13 +1045,13 @@ public class PdbParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the PDB associated with the given program using its attributes
|
||||
* Find the PDB associated with the given program using its attributes.
|
||||
* The PDB path information within the program information will not be used.
|
||||
*
|
||||
* @param program program for which to find a matching PDB
|
||||
* @return matching PDB for program, or null
|
||||
* @throws PdbException if there was a problem with the PDB attributes
|
||||
*/
|
||||
public static File findPDB(Program program) throws PdbException {
|
||||
public static File findPDB(Program program) {
|
||||
return findPDB(getPdbAttributes(program), false, null, null);
|
||||
}
|
||||
|
||||
@@ -1072,10 +1072,9 @@ public class PdbParser {
|
||||
* @param includePeSpecifiedPdbPath to also check the PE-header-specified PDB path
|
||||
* @param symbolsRepositoryPath location where downloaded symbols are stored
|
||||
* @return matching PDB for program, or null
|
||||
* @throws PdbException if there was a problem with the PDB attributes
|
||||
*/
|
||||
public static File findPDB(Program program, boolean includePeSpecifiedPdbPath,
|
||||
String symbolsRepositoryPath) throws PdbException {
|
||||
String symbolsRepositoryPath) {
|
||||
return findPDB(getPdbAttributes(program), includePeSpecifiedPdbPath, symbolsRepositoryPath,
|
||||
null);
|
||||
}
|
||||
@@ -1089,11 +1088,9 @@ public class PdbParser {
|
||||
* @param symbolsRepositoryPath location of the local symbols repository (can be null)
|
||||
* @param fileType type of file to search for (can be null)
|
||||
* @return matching PDB file (or null, if not found)
|
||||
* @throws PdbException if there was a problem with the PDB attributes
|
||||
*/
|
||||
public static File findPDB(PdbProgramAttributes pdbAttributes,
|
||||
boolean includePeSpecifiedPdbPath, String symbolsRepositoryPath, PdbFileType fileType)
|
||||
throws PdbException {
|
||||
boolean includePeSpecifiedPdbPath, String symbolsRepositoryPath, PdbFileType fileType) {
|
||||
|
||||
// Store potential names of PDB files and potential locations of those files,
|
||||
// so that all possible combinations can be searched.
|
||||
@@ -1102,9 +1099,7 @@ public class PdbParser {
|
||||
|
||||
String guidAgeString = pdbAttributes.getGuidAgeCombo();
|
||||
if (guidAgeString == null) {
|
||||
throw new PdbException(
|
||||
"Incomplete PDB information (GUID/Signature and/or age) associated with this program.\n" +
|
||||
"Either the program is not a PE, or it was not compiled with debug information.");
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> potentialPdbNames = pdbAttributes.getPotentialPdbFilenames();
|
||||
@@ -1150,7 +1145,8 @@ public class PdbParser {
|
||||
getSymbolsRepositoryPaths(symbolsRepositoryPath, guidSubdirPaths);
|
||||
Set<File> predefinedPaths =
|
||||
getPredefinedPaths(guidSubdirPaths, pdbAttributes, includePeSpecifiedPdbPath);
|
||||
boolean fileTypeSpecified = (fileType != null), checkForXml;
|
||||
boolean fileTypeSpecified = (fileType != null);
|
||||
boolean checkForXml;
|
||||
|
||||
// If the file type is specified, look for that type of file only.
|
||||
if (fileTypeSpecified) {
|
||||
|
||||
+61
-24
@@ -25,6 +25,7 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfStream;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
||||
import ghidra.app.util.datatype.microsoft.GUID;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
@@ -59,10 +60,11 @@ public abstract class AbstractPdb implements AutoCloseable {
|
||||
protected int versionNumber = 0;
|
||||
protected int signature = 0;
|
||||
//Number of times PDB updated.
|
||||
protected int age = 0;
|
||||
protected int pdbAge = 0;
|
||||
protected int dbiAge = 0;
|
||||
|
||||
protected AbstractTypeProgramInterface typeProgramInterface;
|
||||
protected AbstractDatabaseInterface databaseInterface;
|
||||
protected PdbDebugInfo debugInfo;
|
||||
|
||||
protected Processor targetProcessor = Processor.UNKNOWN;
|
||||
|
||||
@@ -141,9 +143,26 @@ public abstract class AbstractPdb implements AutoCloseable {
|
||||
/**
|
||||
* Returns the main {@link PdbIdentifiers} found in the PDB Directory.
|
||||
* @return {@link PdbIdentifiers} of information.
|
||||
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or
|
||||
* inability to read required bytes.
|
||||
* @throws PdbException Upon error in processing components.
|
||||
*/
|
||||
public PdbIdentifiers getIdentifiers() {
|
||||
return new PdbIdentifiers(versionNumber, signature, age, guid);
|
||||
public PdbIdentifiers getIdentifiers() throws IOException, PdbException {
|
||||
parseDBI();
|
||||
if (debugInfo != null) {
|
||||
try {
|
||||
// dbiAge and targetProcessor set during deserialization of new DBI header
|
||||
debugInfo.deserialize(true, TaskMonitor.DUMMY);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
throw new AssertException(e); // unexpected
|
||||
}
|
||||
}
|
||||
int age = pdbAge;
|
||||
if (dbiAge > 0) {
|
||||
age = dbiAge;
|
||||
}
|
||||
return new PdbIdentifiers(versionNumber, signature, age, guid, targetProcessor);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,7 +235,7 @@ public abstract class AbstractPdb implements AutoCloseable {
|
||||
* @return Age of the PDB.
|
||||
*/
|
||||
public int getAge() {
|
||||
return age;
|
||||
return pdbAge;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -259,12 +278,13 @@ public abstract class AbstractPdb implements AutoCloseable {
|
||||
* @see Processor
|
||||
* @see RegisterName
|
||||
*/
|
||||
// TODO: this method should be package protected
|
||||
public void setTargetProcessor(Processor targetProcessorIn) {
|
||||
/**
|
||||
* Should we allow an overwrite? The {@link DatabaseInterfaceNew} value (mapped from
|
||||
* Should we allow an overwrite? The {@link PdbNewDebugInfo} value (mapped from
|
||||
* {@link ImageFileMachine}) should be processed and laid down first. Subsequent values
|
||||
* can come from {@link AbstractCompile2MsSymbol} and {@link Compile3MsSymbol}. Note:
|
||||
* {@link DatabaseInterface} does not carry {@link ImageFileMachine}, and thus no mapping
|
||||
* {@link PdbDebugInfo} does not carry {@link ImageFileMachine}, and thus no mapping
|
||||
* is applied.
|
||||
*/
|
||||
if (targetProcessor == Processor.UNKNOWN) {
|
||||
@@ -272,9 +292,18 @@ public abstract class AbstractPdb implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the age as specified by the new DBI header. A value of 0 corresponds
|
||||
* to the old DBI header.
|
||||
* @param dbiAge age as specified by the new DBI header
|
||||
*/
|
||||
void setDbiAge(int dbiAge) {
|
||||
this.dbiAge = dbiAge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link AbstractTypeProgramInterface} component.
|
||||
* @return {@link AbstractTypeProgramInterface} component.
|
||||
* @return {@link AbstractTypeProgramInterface} component or null if not available.
|
||||
*/
|
||||
public AbstractTypeProgramInterface getTypeProgramInterface() {
|
||||
return typeProgramInterface;
|
||||
@@ -283,18 +312,19 @@ public abstract class AbstractPdb implements AutoCloseable {
|
||||
/**
|
||||
* Returns the ItemProgramInterface (of type {@link AbstractTypeProgramInterface})
|
||||
* component.
|
||||
* @return ItemProgramInterface (of type {@link AbstractTypeProgramInterface}) component.
|
||||
* @return ItemProgramInterface (of type {@link AbstractTypeProgramInterface}) component
|
||||
* or null if not available.
|
||||
*/
|
||||
public AbstractTypeProgramInterface getItemProgramInterface() {
|
||||
return itemProgramInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link AbstractDatabaseInterface} component.
|
||||
* @return {@link AbstractDatabaseInterface} component.
|
||||
* Returns the {@link PdbDebugInfo} component.
|
||||
* @return {@link PdbDebugInfo} component or null if not available.
|
||||
*/
|
||||
public AbstractDatabaseInterface getDatabaseInterface() {
|
||||
return databaseInterface;
|
||||
public PdbDebugInfo getDebugInfo() {
|
||||
return debugInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -302,7 +332,7 @@ public abstract class AbstractPdb implements AutoCloseable {
|
||||
* @return {@link SymbolRecords} component.
|
||||
*/
|
||||
public SymbolRecords getSymbolRecords() {
|
||||
return databaseInterface.getSymbolRecords();
|
||||
return debugInfo.getSymbolRecords();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -481,7 +511,6 @@ public abstract class AbstractPdb implements AutoCloseable {
|
||||
}
|
||||
|
||||
TypeProgramInterfaceParser tpiParser = new TypeProgramInterfaceParser();
|
||||
DatabaseInterfaceParser dbiParser = new DatabaseInterfaceParser();
|
||||
|
||||
typeProgramInterface = tpiParser.parse(this, monitor);
|
||||
if (typeProgramInterface != null) {
|
||||
@@ -500,14 +529,22 @@ public abstract class AbstractPdb implements AutoCloseable {
|
||||
//dumpDependencyGraph();
|
||||
}
|
||||
|
||||
databaseInterface = dbiParser.parse(this, monitor);
|
||||
if (databaseInterface != null) {
|
||||
databaseInterface.deserialize(monitor);
|
||||
parseDBI();
|
||||
if (debugInfo != null) {
|
||||
debugInfo.deserialize(false, monitor);
|
||||
}
|
||||
|
||||
substreamsDeserialized = true;
|
||||
}
|
||||
|
||||
private PdbDebugInfo parseDBI() throws IOException, PdbException {
|
||||
if (debugInfo == null) {
|
||||
PdbDebugInfoParser dbiParser = new PdbDebugInfoParser();
|
||||
debugInfo = dbiParser.parse(this);
|
||||
}
|
||||
return debugInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link PdbByteReader} initialized with the complete contents of the
|
||||
* {@link MsfStream} referenced by {@code streamNumber}.
|
||||
@@ -606,7 +643,7 @@ public abstract class AbstractPdb implements AutoCloseable {
|
||||
protected void deserializeVersionSignatureAge(PdbByteReader reader) throws PdbException {
|
||||
versionNumber = reader.parseInt();
|
||||
signature = reader.parseInt();
|
||||
age = reader.parseInt();
|
||||
pdbAge = reader.parseInt();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -621,7 +658,7 @@ public abstract class AbstractPdb implements AutoCloseable {
|
||||
builder.append("\nsignature: ");
|
||||
builder.append(Integer.toHexString(signature));
|
||||
builder.append("\nage: ");
|
||||
builder.append(age);
|
||||
builder.append(pdbAge);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@@ -704,10 +741,10 @@ public abstract class AbstractPdb implements AutoCloseable {
|
||||
itemProgramInterface.dump(writer);
|
||||
writer.write("End ItemProgramInterface------------------------------------\n");
|
||||
}
|
||||
if (databaseInterface != null) {
|
||||
writer.write("DatabaseInterface-------------------------------------------\n");
|
||||
databaseInterface.dump(writer);
|
||||
writer.write("End DatabaseInterface---------------------------------------\n");
|
||||
if (debugInfo != null) {
|
||||
writer.write("DebugInfo---------------------------------------------------\n");
|
||||
debugInfo.dump(writer);
|
||||
writer.write("End DebugInfo-----------------------------------------------\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-6
@@ -55,8 +55,6 @@ public abstract class AbstractSymbolInformation {
|
||||
protected List<Integer> hashBucketOffsets = new ArrayList<>();
|
||||
protected Set<SymbolHashRecord> hashRecords = new TreeSet<>();
|
||||
protected List<Long> modifiedHashRecordSymbolOffsets = new ArrayList<>();
|
||||
protected Map<Integer, Integer> thunkTargetOffsetsByTableOffset = new HashMap<>();
|
||||
protected Map<Integer, Integer> absoluteOffsetsBySectionNumber = new HashMap<>();
|
||||
|
||||
protected List<AbstractMsSymbol> symbols = new ArrayList<>();
|
||||
|
||||
@@ -170,8 +168,7 @@ public abstract class AbstractSymbolInformation {
|
||||
protected void generateSymbolsList(TaskMonitor monitor)
|
||||
throws PdbException, CancelledException {
|
||||
symbols = new ArrayList<>();
|
||||
Map<Long, AbstractMsSymbol> symbolsByOffset =
|
||||
pdb.getDatabaseInterface().getSymbolsByOffset();
|
||||
Map<Long, AbstractMsSymbol> symbolsByOffset = pdb.getDebugInfo().getSymbolsByOffset();
|
||||
for (SymbolHashRecord record : hashRecords) {
|
||||
monitor.checkCanceled();
|
||||
long offset = record.getOffset() - 2; // Modified offset
|
||||
@@ -190,10 +187,10 @@ public abstract class AbstractSymbolInformation {
|
||||
*/
|
||||
protected void dumpHashRecords(StringBuilder builder) {
|
||||
builder.append("HashRecords-------------------------------------------------\n");
|
||||
builder.append("numHashRecords: " + hashRecords.size());
|
||||
builder.append("numHashRecords: " + hashRecords.size() + "\n");
|
||||
for (SymbolHashRecord record : hashRecords) {
|
||||
builder.append(
|
||||
String.format("0X%08X 0X%04X", record.getOffset(), record.getReferenceCount()));
|
||||
String.format("0X%08X 0X%04X\n", record.getOffset(), record.getReferenceCount()));
|
||||
}
|
||||
builder.append("\nEnd HashRecords--------------------------------------------\n");
|
||||
}
|
||||
|
||||
+2
-2
@@ -269,9 +269,9 @@ public class DebugData {
|
||||
// }
|
||||
// TODO: More work possible. See XData processing and notes there. This is very
|
||||
// incomplete.
|
||||
if (pdb.getDatabaseInterface() instanceof DatabaseInterfaceNew) {
|
||||
if (pdb.getDebugInfo() instanceof PdbNewDebugInfo) {
|
||||
//Processor target = pdb.getTargetProcessor();
|
||||
DatabaseInterfaceNew dbi = (DatabaseInterfaceNew) pdb.getDatabaseInterface();
|
||||
PdbNewDebugInfo dbi = (PdbNewDebugInfo) pdb.getDebugInfo();
|
||||
ImageFileMachine machine = dbi.getMachineType();
|
||||
switch (machine) {
|
||||
case IA64:
|
||||
|
||||
+2
-2
@@ -22,11 +22,11 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractCompile2MsSymbol
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.Compile3MsSymbol;
|
||||
|
||||
/**
|
||||
* Machine Type seen in the {@link DatabaseInterfaceNew} header. We also map in the Processor.
|
||||
* Machine Type seen in the {@link PdbNewDebugInfo} header. We also map in the Processor.
|
||||
* We are not exactly sure about why there are different but similar items: Machine Type and
|
||||
* Processor. The {@link Processor} is what is specified in {@link AbstractCompile2MsSymbol} and
|
||||
* {@link Compile3MsSymbol} and what we save off in {@link AbstractPdb}, but
|
||||
* {@link ImageFileMachine} is what we see in the header of {@link DatabaseInterfaceNew}.
|
||||
* {@link ImageFileMachine} is what we see in the header of {@link PdbNewDebugInfo}.
|
||||
* @see <a href="https://docs.microsoft.com/en-us/windows/desktop/sysinfo/image-file-machine-constants">
|
||||
* Image File Machine Constants</a>
|
||||
* @see <a href="http://metadataconsulting.blogspot.com/2014/06/imagefilemachine-extensive-machine-type.html">
|
||||
|
||||
+3
-3
@@ -21,9 +21,9 @@ import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Image Section Header information, as part of {@link DebugData} structures within
|
||||
* {@link DatabaseInterfaceNew} of {@link AbstractPdb} types. Contains section information;
|
||||
* {@link PdbNewDebugInfo} of {@link AbstractPdb} types. Contains section information;
|
||||
* an older set of section information seems to be located in {@link SegmentMapDescription},
|
||||
* which might be used for {@link DatabaseInterface} types, but we do not yet have data to
|
||||
* which might be used for {@link PdbOldDebugInfo} types, but we do not yet have data to
|
||||
* confirm this.
|
||||
*/
|
||||
public class ImageSectionHeader {
|
||||
@@ -167,7 +167,7 @@ public class ImageSectionHeader {
|
||||
// TODO: See the to-do above regarding unionPAVS.
|
||||
writer.write(String.format("unionPAVS: 0X%08X\n", unionPAVS));
|
||||
writer.write(String.format("virtualAddress: 0X%08X\n", virtualAddress));
|
||||
writer.write(String.format("rawDataSize: 0X%08XX\n", rawDataSize));
|
||||
writer.write(String.format("rawDataSize: 0X%08X\n", rawDataSize));
|
||||
writer.write(String.format("rawDataPointer: 0X%08X\n", rawDataPointer));
|
||||
writer.write(String.format("relocationsPointer: 0X%08X\n", relocationsPointer));
|
||||
writer.write(String.format("lineNumbersPointer: 0X%08X\n", lineNumbersPointer));
|
||||
|
||||
+38
-23
@@ -24,13 +24,13 @@ import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* This class represents Database Interface component of a PDB file. This class is only
|
||||
* suitable for reading; not for writing or modifying a PDB.
|
||||
* This class represents DebugInfo (DBI) component of a PDB file.
|
||||
* This class is only suitable for reading; not for writing or modifying a PDB.
|
||||
* <P>
|
||||
* We have intended to implement according to the Microsoft PDB API (source); see the API for
|
||||
* truth.
|
||||
*/
|
||||
public abstract class AbstractDatabaseInterface {
|
||||
public abstract class PdbDebugInfo {
|
||||
|
||||
protected static final int VERSION_NUMBER_SIZE = 4;
|
||||
|
||||
@@ -81,7 +81,7 @@ public abstract class AbstractDatabaseInterface {
|
||||
* @param pdb {@link AbstractPdb} that owns this Database Interface.
|
||||
* @param streamNumber The stream number of the stream containing the Database Interface.
|
||||
*/
|
||||
public AbstractDatabaseInterface(AbstractPdb pdb, int streamNumber) {
|
||||
public PdbDebugInfo(AbstractPdb pdb, int streamNumber) {
|
||||
Objects.requireNonNull(pdb, "pdb cannot be null");
|
||||
this.pdb = pdb;
|
||||
this.streamNumber = streamNumber;
|
||||
@@ -99,7 +99,10 @@ public abstract class AbstractDatabaseInterface {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes the {@link AbstractDatabaseInterface}-based instance.
|
||||
* Deserializes the {@link PdbDebugInfo}-based instance.
|
||||
* The pdb is updated with dbiAge and targetProcessor during deserialization
|
||||
* of new DBI header.
|
||||
* @param headerOnly if true only the DBI header fields will be parsed
|
||||
* @param monitor {@link TaskMonitor} used for checking cancellation.
|
||||
* @return The version number of the Database Interface.
|
||||
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or
|
||||
@@ -107,13 +110,19 @@ public abstract class AbstractDatabaseInterface {
|
||||
* @throws PdbException upon error parsing a field.
|
||||
* @throws CancelledException Upon user cancellation.
|
||||
*/
|
||||
public long deserialize(TaskMonitor monitor)
|
||||
public long deserialize(boolean headerOnly, TaskMonitor monitor)
|
||||
throws IOException, PdbException, CancelledException {
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, monitor);
|
||||
deserializeHeader(reader);
|
||||
deserializeInternalSubstreams(reader, monitor);
|
||||
deserializeAdditionalSubstreams(monitor);
|
||||
|
||||
if (headerOnly) {
|
||||
PdbByteReader reader =
|
||||
pdb.getReaderForStreamNumber(streamNumber, 0, getHeaderLength(), monitor);
|
||||
deserializeHeader(reader);
|
||||
}
|
||||
else {
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, monitor);
|
||||
deserializeHeader(reader);
|
||||
deserializeInternalSubstreams(reader, monitor);
|
||||
deserializeAdditionalSubstreams(monitor);
|
||||
}
|
||||
return versionNumber;
|
||||
}
|
||||
|
||||
@@ -285,6 +294,12 @@ public abstract class AbstractDatabaseInterface {
|
||||
*/
|
||||
protected abstract void deserializeHeader(PdbByteReader reader) throws PdbException;
|
||||
|
||||
/**
|
||||
* Get the header length in bytes as it appears at offset 0 within the DBI stream
|
||||
* @return DBI header length
|
||||
*/
|
||||
protected abstract int getHeaderLength();
|
||||
|
||||
/**
|
||||
* Deserializes the SubStreams internal to the Database Interface stream.
|
||||
* @param reader {@link PdbByteReader} from which to deserialize the data.
|
||||
@@ -375,7 +390,7 @@ public abstract class AbstractDatabaseInterface {
|
||||
}
|
||||
//TODO: Don't know when SectionContribution200 is the type to use. Don't know if
|
||||
// this part could be the default of processSectionContribs within
|
||||
// DatabaseInterface and if the above part (test for SVC600 and SVC1400 would
|
||||
// DebugInfo and if the above part (test for SVC600 and SVC1400 would
|
||||
// be the override method for DatabaseInformationNew.
|
||||
else {
|
||||
while (substreamReader.hasMore()) {
|
||||
@@ -507,26 +522,26 @@ public abstract class AbstractDatabaseInterface {
|
||||
protected abstract String parseFileInfoName(PdbByteReader reader) throws PdbException;
|
||||
|
||||
/**
|
||||
* Debug method for dumping information from this {@link AbstractDatabaseInterface}-based
|
||||
* Debug method for dumping information from this {@link PdbDebugInfo}-based
|
||||
* instance.
|
||||
* @param writer {@link Writer} to which to dump the information.
|
||||
* @throws IOException Upon IOException writing to the {@link Writer}.
|
||||
*/
|
||||
protected void dump(Writer writer) throws IOException {
|
||||
writer.write("DatabaseInterfaceHeader-------------------------------------\n");
|
||||
writer.write("DebugInfoHeader-------------------------------------\n");
|
||||
dumpHeader(writer);
|
||||
writer.write("\nEnd DatabaseInterfaceHeader---------------------------------\n");
|
||||
writer.write("DatabaseInterfaceInternalSubstreams-------------------------\n");
|
||||
writer.write("\nEnd DebugInfoHeader---------------------------------\n");
|
||||
writer.write("DebugInfoInternalSubstreams-------------------------\n");
|
||||
dumpInternalSubstreams(writer);
|
||||
writer.write("\nEnd DatabaseInterfaceInternalSubstreams---------------------\n");
|
||||
writer.write("DatabaseInterfaceAdditionalSubstreams-----------------------\n");
|
||||
writer.write("\nEnd DebugInfoInternalSubstreams---------------------\n");
|
||||
writer.write("DebugInfoAdditionalSubstreams-----------------------\n");
|
||||
dumpAdditionalSubstreams(writer);
|
||||
writer.write("\nEnd DatabaseInterfaceAdditionalSubstreams-------------------\n");
|
||||
writer.write("\nEnd DebugInfoAdditionalSubstreams-------------------\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug method for dumping additional substreams from this
|
||||
* {@link AbstractDatabaseInterface}-based instance.
|
||||
* {@link PdbDebugInfo}-based instance.
|
||||
* @param writer {@link Writer} to which to dump the information.
|
||||
* @throws IOException Upon IOException writing to the {@link Writer}.
|
||||
*/
|
||||
@@ -540,7 +555,7 @@ public abstract class AbstractDatabaseInterface {
|
||||
|
||||
/**
|
||||
* Debug method for dumping module information for all of the {@link AbstractModuleInformation}
|
||||
* modules from this {@link AbstractDatabaseInterface}-based instance.
|
||||
* modules from this {@link PdbDebugInfo}-based instance.
|
||||
* @param writer {@link Writer} to which to dump the information.
|
||||
* @throws IOException Upon IOException writing to the {@link Writer}.
|
||||
*/
|
||||
@@ -554,7 +569,7 @@ public abstract class AbstractDatabaseInterface {
|
||||
/**
|
||||
* Debug method for dumping section contribution for all of the
|
||||
* {@link AbstractSectionContribution} components from this
|
||||
* {@link AbstractDatabaseInterface}-based instance.
|
||||
* {@link PdbDebugInfo}-based instance.
|
||||
* @param writer {@link Writer} to which to dump the information.
|
||||
* @throws IOException Upon IOException writing to the {@link Writer}.
|
||||
*/
|
||||
@@ -567,7 +582,7 @@ public abstract class AbstractDatabaseInterface {
|
||||
|
||||
/**
|
||||
* Debug method for dumping segment map information for all of the
|
||||
* {@link SegmentMapDescription} components from this {@link AbstractDatabaseInterface}-based
|
||||
* {@link SegmentMapDescription} components from this {@link PdbDebugInfo}-based
|
||||
* instance.
|
||||
* @param writer {@link Writer} to which to dump the information.
|
||||
* @throws IOException Upon IOException writing to the {@link Writer}.
|
||||
+39
-36
@@ -17,14 +17,15 @@ package ghidra.app.util.bin.format.pdb2.pdbreader;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Parser for detecting the appropriate {@link AbstractDatabaseInterface} format for the filename
|
||||
* given. It then creates and returns the appropriate {@link AbstractDatabaseInterface} object.
|
||||
* Parser for detecting the appropriate {@link PdbDebugInfo} format for the filename
|
||||
* given. It then creates and returns the appropriate {@link PdbDebugInfo} object.
|
||||
*/
|
||||
public class DatabaseInterfaceParser {
|
||||
public class PdbDebugInfoParser {
|
||||
|
||||
private static final int DATABASE_INTERFACE_STREAM_NUMBER = 3;
|
||||
|
||||
@@ -45,53 +46,55 @@ public class DatabaseInterfaceParser {
|
||||
/**
|
||||
* Parses information to determine the version of Database Interface to create.
|
||||
* @param pdb {@link AbstractPdb} that owns this Database Interface.
|
||||
* @param monitor {@link TaskMonitor} used for checking cancellation.
|
||||
* @return {@link AbstractDatabaseInterface} of the appropriate Database Interface or null if
|
||||
* @return {@link PdbDebugInfo} of the appropriate Database Interface or null if
|
||||
* the stream does not have enough information to be parsed.
|
||||
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or
|
||||
* inability to read required bytes.
|
||||
* @throws PdbException Upon error in processing components.
|
||||
* @throws CancelledException Upon user cancellation.
|
||||
*/
|
||||
public AbstractDatabaseInterface parse(AbstractPdb pdb, TaskMonitor monitor)
|
||||
throws IOException, PdbException, CancelledException {
|
||||
AbstractDatabaseInterface databaseInterface;
|
||||
public PdbDebugInfo parse(AbstractPdb pdb) throws IOException, PdbException {
|
||||
PdbDebugInfo debugInfo;
|
||||
try {
|
||||
int streamNumber = getStreamNumber();
|
||||
// Only reading 8-bytes - no need for monitor
|
||||
PdbByteReader reader =
|
||||
pdb.getReaderForStreamNumber(streamNumber, 0, 8, TaskMonitor.DUMMY);
|
||||
if (reader.getLimit() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int streamNumber = getStreamNumber();
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, 0, 8, monitor);
|
||||
if (reader.getLimit() == 0) {
|
||||
return null;
|
||||
}
|
||||
// In support of debug.
|
||||
debugReader = reader;
|
||||
PdbLog.message(this::debugDump);
|
||||
|
||||
// In support of debug.
|
||||
debugReader = reader;
|
||||
PdbLog.message(this::debugDump);
|
||||
int headerSignature = reader.parseInt();
|
||||
int versionNumber = reader.parseInt();
|
||||
|
||||
int headerSignature = reader.parseInt();
|
||||
int versionNumber = reader.parseInt();
|
||||
|
||||
if (headerSignature == DBIHDR700_SIG) {
|
||||
switch (versionNumber) {
|
||||
case DBI41_ID:
|
||||
case DBI50_ID:
|
||||
case DBI60_ID:
|
||||
case DBI70_ID:
|
||||
case DBI110_ID:
|
||||
databaseInterface = new DatabaseInterfaceNew(pdb, streamNumber);
|
||||
break;
|
||||
default:
|
||||
throw new PdbException("Unknown DBI Version");
|
||||
if (headerSignature == DBIHDR700_SIG) {
|
||||
switch (versionNumber) {
|
||||
case DBI41_ID:
|
||||
case DBI50_ID:
|
||||
case DBI60_ID:
|
||||
case DBI70_ID:
|
||||
case DBI110_ID:
|
||||
debugInfo = new PdbNewDebugInfo(pdb, streamNumber);
|
||||
break;
|
||||
default:
|
||||
throw new PdbException("Unknown DBI Version");
|
||||
}
|
||||
}
|
||||
else {
|
||||
debugInfo = new PdbOldDebugInfo(pdb, streamNumber);
|
||||
}
|
||||
}
|
||||
else {
|
||||
databaseInterface = new DatabaseInterface(pdb, streamNumber);
|
||||
catch (CancelledException e) {
|
||||
throw new AssertException();
|
||||
}
|
||||
|
||||
return databaseInterface;
|
||||
return debugInfo;
|
||||
}
|
||||
|
||||
private String debugDump() {
|
||||
return "DatabaseInterfaceParser data on stream " + getStreamNumber() + ":\n" +
|
||||
return "DebugInfoParser data on stream " + getStreamNumber() + ":\n" +
|
||||
debugReader.dump() + "\n";
|
||||
}
|
||||
|
||||
+8
-6
@@ -25,23 +25,25 @@ import ghidra.app.util.datatype.microsoft.GUID;
|
||||
*/
|
||||
public class PdbIdentifiers {
|
||||
|
||||
private int version;
|
||||
private int signature;
|
||||
private int age;
|
||||
private GUID guid;
|
||||
private final int version;
|
||||
private final int signature;
|
||||
private final int age;
|
||||
private final GUID guid;
|
||||
private final Processor processor;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param version The version number.
|
||||
* @param signature The signature.
|
||||
* @param age The age.
|
||||
* @param age age used to verify PDB against age stored in program
|
||||
* @param guid The GUID (can be null for older PDBs).
|
||||
*/
|
||||
PdbIdentifiers(int version, int signature, int age, GUID guid) {
|
||||
PdbIdentifiers(int version, int signature, int age, GUID guid, Processor processor) {
|
||||
this.version = version;
|
||||
this.signature = signature;
|
||||
this.age = age;
|
||||
this.guid = guid;
|
||||
this.processor = processor == null ? Processor.UNKNOWN : processor;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+26
-11
@@ -24,23 +24,24 @@ import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* This class is the version of {@link AbstractDatabaseInterface} for newer PDB files.
|
||||
* This class is the version of {@link PdbDebugInfo} for newer PDB files.
|
||||
* <P>
|
||||
* This class uses {@link ModuleInformation600}.
|
||||
*/
|
||||
public class DatabaseInterfaceNew extends AbstractDatabaseInterface {
|
||||
public class PdbNewDebugInfo extends PdbDebugInfo {
|
||||
|
||||
//==============================================================================================
|
||||
// Internals
|
||||
//==============================================================================================
|
||||
private static final long HEADER_MAGIC = 0xeffeeffeL;
|
||||
private static final int DBI_HEADER_LENGTH = 64;
|
||||
|
||||
protected Hasher hasher; //Might belong in parent? Used in parent (even older Hasher?)
|
||||
|
||||
// The source of these values can overlay other fields in older versions of this type.
|
||||
protected long versionSignature = 0; // unsigned 32-bit
|
||||
|
||||
protected long age = 0; // unsigned 32-bit
|
||||
protected long dbiAge = 0; // unsigned 32-bit
|
||||
protected int universalVersion = 0; // unsigned 16-bit
|
||||
protected int pdbDllBuildVersion = 0; // unsigned 16-bit
|
||||
protected int pdbDllReleaseBuildVersion = 0; // unsigned 16-bit
|
||||
@@ -63,10 +64,10 @@ public class DatabaseInterfaceNew extends AbstractDatabaseInterface {
|
||||
//==============================================================================================
|
||||
/**
|
||||
* Constructor.
|
||||
* @param pdb {@link AbstractPdb} that owns this {@link DatabaseInterfaceNew}.
|
||||
* @param streamNumber The stream number that contains the {@link DatabaseInterfaceNew} data.
|
||||
* @param pdb {@link AbstractPdb} that owns this {@link PdbNewDebugInfo}.
|
||||
* @param streamNumber The stream number that contains the {@link PdbNewDebugInfo} data.
|
||||
*/
|
||||
public DatabaseInterfaceNew(AbstractPdb pdb, int streamNumber) {
|
||||
public PdbNewDebugInfo(AbstractPdb pdb, int streamNumber) {
|
||||
super(pdb, streamNumber);
|
||||
debugData = new DebugData(pdb);
|
||||
}
|
||||
@@ -80,7 +81,7 @@ public class DatabaseInterfaceNew extends AbstractDatabaseInterface {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link DebugData} for this {@link DatabaseInterfaceNew}.
|
||||
* Returns the {@link DebugData} for this {@link PdbNewDebugInfo}.
|
||||
* @return the {@link DebugData}.
|
||||
*/
|
||||
public DebugData getDebugData() {
|
||||
@@ -95,7 +96,7 @@ public class DatabaseInterfaceNew extends AbstractDatabaseInterface {
|
||||
//System.out.println(reader.dump(0x200));
|
||||
versionSignature = reader.parseUnsignedIntVal();
|
||||
versionNumber = reader.parseUnsignedIntVal();
|
||||
age = reader.parseUnsignedIntVal();
|
||||
dbiAge = reader.parseUnsignedIntVal();
|
||||
|
||||
streamNumberGlobalStaticSymbolsHashMaybe = reader.parseUnsignedShortVal();
|
||||
|
||||
@@ -119,10 +120,16 @@ public class DatabaseInterfaceNew extends AbstractDatabaseInterface {
|
||||
|
||||
flags = reader.parseUnsignedShortVal();
|
||||
machineType = ImageFileMachine.fromValue(reader.parseUnsignedShortVal());
|
||||
pdb.setTargetProcessor(machineType.getProcessor());
|
||||
|
||||
padReserve = reader.parseUnsignedIntVal();
|
||||
|
||||
// update PDB with age and processor
|
||||
pdb.setTargetProcessor(machineType.getProcessor());
|
||||
pdb.setDbiAge((int) dbiAge);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getHeaderLength() {
|
||||
return DBI_HEADER_LENGTH;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -187,7 +194,7 @@ public class DatabaseInterfaceNew extends AbstractDatabaseInterface {
|
||||
builder.append("\nversionNumber: ");
|
||||
builder.append(versionNumber);
|
||||
builder.append("\nage: ");
|
||||
builder.append(age);
|
||||
builder.append(dbiAge);
|
||||
builder.append("\nstreamNumberGlobalStaticSymbols: ");
|
||||
builder.append(streamNumberGlobalStaticSymbolsHashMaybe);
|
||||
builder.append(String.format("\nuniversalVersion: 0x%04x", universalVersion));
|
||||
@@ -338,4 +345,12 @@ public class DatabaseInterfaceNew extends AbstractDatabaseInterface {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get age from deserialized DBI header
|
||||
* @return age from deserialized DBI header
|
||||
*/
|
||||
long getAge() {
|
||||
return dbiAge;
|
||||
}
|
||||
|
||||
}
|
||||
+12
-5
@@ -22,21 +22,23 @@ import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* This class is the version of {@link AbstractDatabaseInterface} for older PDB files.
|
||||
* This class is the version of {@link PdbDebugInfo} for older PDB files.
|
||||
* <P>
|
||||
* This class uses {@link ModuleInformation500}.
|
||||
*/
|
||||
class DatabaseInterface extends AbstractDatabaseInterface {
|
||||
class PdbOldDebugInfo extends PdbDebugInfo {
|
||||
|
||||
private static final int OLD_DBI_HEADER_LENGTH = 22;
|
||||
|
||||
//==============================================================================================
|
||||
// API
|
||||
//==============================================================================================
|
||||
/**
|
||||
* Constructor.
|
||||
* @param pdb {@link AbstractPdb} that owns this {@link DatabaseInterface}.
|
||||
* @param streamNumber The number of the stream that contains the {@link DatabaseInterface}.
|
||||
* @param pdb {@link AbstractPdb} that owns this {@link PdbOldDebugInfo}.
|
||||
* @param streamNumber The number of the stream that contains the {@link PdbOldDebugInfo}.
|
||||
*/
|
||||
public DatabaseInterface(AbstractPdb pdb, int streamNumber) {
|
||||
public PdbOldDebugInfo(AbstractPdb pdb, int streamNumber) {
|
||||
super(pdb, streamNumber);
|
||||
}
|
||||
|
||||
@@ -54,6 +56,11 @@ class DatabaseInterface extends AbstractDatabaseInterface {
|
||||
lengthFileInformation = reader.parseInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getHeaderLength() {
|
||||
return OLD_DBI_HEADER_LENGTH;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deserializeInternalSubstreams(PdbByteReader reader, TaskMonitor monitor)
|
||||
throws PdbException, CancelledException {
|
||||
+1
-1
@@ -878,7 +878,7 @@ public class PdbReaderMetrics {
|
||||
|
||||
public void witnessedSectionSegmentNumber(int segment) {
|
||||
if (numSegments == -1) {
|
||||
numSegments = pdb.getDatabaseInterface().getSegmentMapList().size();
|
||||
numSegments = pdb.getDebugInfo().getSegmentMapList().size();
|
||||
}
|
||||
if (segment < 0 || segment > numSegments) {
|
||||
PdbLog.message("segment " + segment + " out of range [0," + numSegments + ")");
|
||||
|
||||
+49
-9
@@ -17,8 +17,7 @@ package ghidra.app.util.bin.format.pdb2.pdbreader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@@ -50,6 +49,8 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
|
||||
|
||||
// These should correspond with symbolOffsets that come from HashRecords.
|
||||
private List<Long> addressMapSymbolOffsets = new ArrayList<>();
|
||||
private Map<Integer, Integer> thunkTargetOffsetsByTableOffset = new HashMap<>();
|
||||
private Map<Integer, Integer> absoluteOffsetsBySectionNumber = new HashMap<>();
|
||||
|
||||
//==============================================================================================
|
||||
// API
|
||||
@@ -180,12 +181,9 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
|
||||
dumpHashBasics(builder);
|
||||
dumpHashRecords(builder);
|
||||
|
||||
// deserializeAddressMap(addressMapReader, monitor);
|
||||
// deserializeThunkMap(thunkMapReader, monitor);
|
||||
// sectionMapLength = reader.numRemaining();
|
||||
// numSections = sectionMapLength / 8;
|
||||
// deserializeSectionMap(sectionMapReader, monitor);
|
||||
//
|
||||
dumpAddressMap(builder);
|
||||
dumpThunkMap(builder);
|
||||
dumpSectionMap(builder);
|
||||
|
||||
builder.append("\nEnd PublicSymbolInformation---------------------------------\n");
|
||||
writer.write(builder.toString());
|
||||
@@ -209,6 +207,20 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug method for dumping Address Map information from this {@link AbstractSymbolInformation}.
|
||||
* @param builder {@link StringBuilder} to which to dump the information.
|
||||
*/
|
||||
private void dumpAddressMap(StringBuilder builder) {
|
||||
builder.append("AddressMapSymbolOffsets-------------------------------------\n");
|
||||
builder.append("numAddressMapSymbolOffsets: " + addressMapSymbolOffsets.size() + "\n");
|
||||
int num = 0;
|
||||
for (Long val : addressMapSymbolOffsets) {
|
||||
builder.append(String.format("0X%08X: 0X%012X\n", num++, val));
|
||||
}
|
||||
builder.append("\nEnd AddressMapSymbolOffsets---------------------------------\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes the Thunk Map for these public symbols.
|
||||
* @param reader {@link PdbByteReader} containing the data buffer to process.
|
||||
@@ -227,6 +239,20 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug method for dumping Thunk Map information from this {@link AbstractSymbolInformation}.
|
||||
* @param builder {@link StringBuilder} to which to dump the information.
|
||||
*/
|
||||
private void dumpThunkMap(StringBuilder builder) {
|
||||
builder.append("ThunkMap----------------------------------------------------\n");
|
||||
builder.append(
|
||||
"numThunkTargetOffsetsByTableOffset: " + thunkTargetOffsetsByTableOffset.size() + "\n");
|
||||
for (Map.Entry<Integer, Integer> entry : thunkTargetOffsetsByTableOffset.entrySet()) {
|
||||
builder.append(String.format("0X%08X 0X%08X\n", entry.getKey(), entry.getValue()));
|
||||
}
|
||||
builder.append("\nEnd ThunkMap------------------------------------------------\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes the Section Map for these public symbols.
|
||||
* @param reader {@link PdbByteReader} containing the data buffer to process.
|
||||
@@ -245,6 +271,20 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug method for dumping Section Map information from this {@link AbstractSymbolInformation}.
|
||||
* @param builder {@link StringBuilder} to which to dump the information.
|
||||
*/
|
||||
private void dumpSectionMap(StringBuilder builder) {
|
||||
builder.append("SectionMap--------------------------------------------------\n");
|
||||
builder.append(
|
||||
"numAbsoluteOffsetsBySectionNumber: " + absoluteOffsetsBySectionNumber.size() + "\n");
|
||||
for (Map.Entry<Integer, Integer> entry : absoluteOffsetsBySectionNumber.entrySet()) {
|
||||
builder.append(String.format("0X%08X 0X%08X\n", entry.getKey(), entry.getValue()));
|
||||
}
|
||||
builder.append("\nEnd SectionMap----------------------------------------------\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug method for dumping the {@link PublicSymbolInformation} header.
|
||||
* @param builder {@link StringBuilder} to which to dump the information.
|
||||
@@ -269,7 +309,7 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
|
||||
builder.append(thunkMapLength);
|
||||
builder.append("\nthunkTableLength: ");
|
||||
builder.append(thunkTableLength);
|
||||
builder.append("\nEnd PublicSymbolInformationHeader--------------------------\n");
|
||||
builder.append("\nEnd PublicSymbolInformationHeader---------------------------\n");
|
||||
}
|
||||
|
||||
// Issue: MSFT does not initialize PSGSIHDR with nSects(0) (our numSections), so spurious
|
||||
|
||||
+2
-2
@@ -76,11 +76,11 @@ public class SymbolRecords {
|
||||
int streamNumber;
|
||||
PdbByteReader reader;
|
||||
|
||||
streamNumber = pdb.getDatabaseInterface().getSymbolRecordsStreamNumber();
|
||||
streamNumber = pdb.getDebugInfo().getSymbolRecordsStreamNumber();
|
||||
reader = pdb.getReaderForStreamNumber(streamNumber, monitor);
|
||||
symbolsByOffset = deserializeSymbolRecords(reader, monitor);
|
||||
|
||||
for (AbstractModuleInformation module : pdb.getDatabaseInterface().moduleInformationList) {
|
||||
for (AbstractModuleInformation module : pdb.getDebugInfo().moduleInformationList) {
|
||||
streamNumber = module.getStreamNumberDebugInformation();
|
||||
if (streamNumber != 0xffff) {
|
||||
// System.out.println("\n\nStreamNumber: " + streamNumber);
|
||||
|
||||
@@ -18,7 +18,7 @@ package ghidra.app.util.pdb;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.SymbolPath;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.AbstractDatabaseInterface;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbDebugInfo;
|
||||
import ghidra.program.model.data.Category;
|
||||
import ghidra.program.model.data.CategoryPath;
|
||||
|
||||
@@ -134,7 +134,7 @@ public class PdbCategories {
|
||||
|
||||
/**
|
||||
* Returns the {@link CategoryPath} for a typedef with the give {@link SymbolPath} and
|
||||
* module number; 1 <= moduleNumber <= {@link AbstractDatabaseInterface#getNumModules()},
|
||||
* module number; 1 <= moduleNumber <= {@link PdbDebugInfo#getNumModules()},
|
||||
* except that modeleNumber of 0 represents publics/globals.
|
||||
* @param moduleNumber module number
|
||||
* @param symbolPath SymbolPath of the symbol
|
||||
|
||||
@@ -70,10 +70,13 @@ import ghidra.util.task.TaskMonitor;
|
||||
*/
|
||||
public class PdbLocator {
|
||||
|
||||
public static final File SPECIAL_PDB_LOCATION = new File("C:/WINDOWS/Symbols");
|
||||
public static final boolean onWindows =
|
||||
(Platform.CURRENT_PLATFORM.getOperatingSystem() == OperatingSystem.WINDOWS);
|
||||
|
||||
private static final File USER_HOME = new File(System.getProperty("user.home"));
|
||||
public static final File DEFAULT_SYMBOLS_DIR =
|
||||
onWindows ? new File("C:\\Symbols") : new File(USER_HOME, "Symbols");
|
||||
|
||||
private File symbolsRepositoryPath;
|
||||
/**
|
||||
* Only holds identifies in PDBs up until a matching one was found--nothing beyond that.
|
||||
@@ -219,8 +222,8 @@ public class PdbLocator {
|
||||
includePeSpecifiedPdbPath, symbolsRepositoryPath.getAbsolutePath());
|
||||
if (orderedListOfExistingFileNames.isEmpty()) {
|
||||
|
||||
String pdbName = program.getOptions(Program.PROGRAM_INFO).getString(
|
||||
PdbParserConstants.PDB_FILE, (String) null);
|
||||
String pdbName = program.getOptions(Program.PROGRAM_INFO)
|
||||
.getString(PdbParserConstants.PDB_FILE, (String) null);
|
||||
if (pdbName == null) {
|
||||
message = "Program has no associated PDB file.";
|
||||
}
|
||||
@@ -452,6 +455,9 @@ public class PdbLocator {
|
||||
* a matching PDB
|
||||
* @param potentialPdbNames all potential filenames for the PDB file(s) that match the program
|
||||
* @param pdbAttributes PDB attributes associated with the program
|
||||
* @param includePeSpecifiedPdbPath if true include paths derived from the PDB file path
|
||||
* determined at time of import. NOTE: This option is considered unsafe and should not be
|
||||
* enabled unless binary source is trusted and PDB file path is reasonable for this system.
|
||||
* @return matching PDB file, if found (else null)
|
||||
*/
|
||||
private static List<String> checkPathsForPdb(String symbolsRepositoryPath,
|
||||
@@ -467,12 +473,12 @@ public class PdbLocator {
|
||||
|
||||
List<String> orderedListOfExistingFileNames = new ArrayList<>();
|
||||
if (symbolsRepositoryPath != null) {
|
||||
orderedListOfExistingFileNames.addAll(
|
||||
checkSpecificPathsForPdb(symbolsRepoPaths, potentialPdbNames));
|
||||
orderedListOfExistingFileNames
|
||||
.addAll(checkSpecificPathsForPdb(symbolsRepoPaths, potentialPdbNames));
|
||||
}
|
||||
|
||||
orderedListOfExistingFileNames.addAll(
|
||||
checkSpecificPathsForPdb(predefinedPaths, potentialPdbNames));
|
||||
orderedListOfExistingFileNames
|
||||
.addAll(checkSpecificPathsForPdb(predefinedPaths, potentialPdbNames));
|
||||
|
||||
return orderedListOfExistingFileNames;
|
||||
|
||||
@@ -561,12 +567,13 @@ public class PdbLocator {
|
||||
* <P>
|
||||
*/
|
||||
private static void getWindowsPaths(Set<String> guidSubdirPaths, Set<File> predefinedPaths) {
|
||||
// Don't have to call .exists(), since .isDirectory() does that already
|
||||
if (onWindows && SPECIAL_PDB_LOCATION.isDirectory()) {
|
||||
predefinedPaths.add(SPECIAL_PDB_LOCATION);
|
||||
// TODO: Need to provide better control of symbol directory preference
|
||||
// instead of only using default
|
||||
if (DEFAULT_SYMBOLS_DIR.isDirectory()) {
|
||||
predefinedPaths.add(DEFAULT_SYMBOLS_DIR);
|
||||
|
||||
// Check alternate locations
|
||||
String specialPdbPath = SPECIAL_PDB_LOCATION.getAbsolutePath();
|
||||
String specialPdbPath = DEFAULT_SYMBOLS_DIR.getAbsolutePath();
|
||||
|
||||
for (String guidSubdir : guidSubdirPaths) {
|
||||
File testDir = new File(specialPdbPath + guidSubdir);
|
||||
|
||||
@@ -17,6 +17,8 @@ package ghidra.app.util.pdb;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.app.util.bin.format.pdb.PdbParserConstants;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.model.listing.Program;
|
||||
@@ -119,10 +121,9 @@ public class PdbProgramAttributes {
|
||||
// Want to preserve add order while only keeping unique entries
|
||||
Set<String> set = new LinkedHashSet<>();
|
||||
|
||||
if (pdbFile != null) {
|
||||
if (!StringUtils.isBlank(pdbFile)) {
|
||||
set.add(getFilename(pdbFile).toLowerCase());
|
||||
set.add(getFilename(pdbFile));
|
||||
set.add(pdbFile);
|
||||
}
|
||||
|
||||
// getExecutablePath can return "unknown"
|
||||
@@ -162,17 +163,22 @@ public class PdbProgramAttributes {
|
||||
*/
|
||||
private void createGuidAgeString() {
|
||||
|
||||
if ((pdbGuid == null && pdbSignature == null) || pdbAge == null) {
|
||||
if ((StringUtils.isBlank(pdbGuid) && StringUtils.isBlank(pdbSignature)) ||
|
||||
StringUtils.isBlank(pdbAge)) {
|
||||
guidAgeCombo = null;
|
||||
return;
|
||||
}
|
||||
|
||||
guidAgeCombo = (pdbGuid == null) ? pdbSignature : pdbGuid;
|
||||
guidAgeCombo = guidAgeCombo.replaceAll("-", "");
|
||||
guidAgeCombo = guidAgeCombo.toUpperCase();
|
||||
|
||||
int pdbAgeDecimal = Integer.parseInt(pdbAge, 16);
|
||||
guidAgeCombo += pdbAgeDecimal;
|
||||
try {
|
||||
int pdbAgeDecimal = Integer.parseInt(pdbAge, 16);
|
||||
guidAgeCombo = (pdbGuid == null) ? pdbSignature : pdbGuid;
|
||||
guidAgeCombo = guidAgeCombo.replaceAll("-", "");
|
||||
guidAgeCombo = guidAgeCombo.toUpperCase();
|
||||
guidAgeCombo += pdbAgeDecimal;
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+8
-2
@@ -18,6 +18,7 @@ package ghidra.app.util.pdb.pdbapplicator;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.SymbolPath;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.AbstractTypeProgramInterface;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@@ -50,8 +51,13 @@ public class ComplexTypeApplierMapper {
|
||||
//==============================================================================================
|
||||
//==============================================================================================
|
||||
void mapAppliers(TaskMonitor monitor) throws CancelledException {
|
||||
int indexLimit = applicator.getPdb().getTypeProgramInterface().getTypeIndexMaxExclusive();
|
||||
int indexNumber = applicator.getPdb().getTypeProgramInterface().getTypeIndexMin();
|
||||
AbstractTypeProgramInterface typeProgramInterface =
|
||||
applicator.getPdb().getTypeProgramInterface();
|
||||
if (typeProgramInterface == null) {
|
||||
return;
|
||||
}
|
||||
int indexLimit = typeProgramInterface.getTypeIndexMaxExclusive();
|
||||
int indexNumber = typeProgramInterface.getTypeIndexMin();
|
||||
monitor.initialize(indexLimit - indexNumber);
|
||||
applicator.setMonitorMessage("PDB: Mapping Composites...");
|
||||
while (indexNumber < indexLimit) {
|
||||
|
||||
+11
-11
@@ -257,9 +257,9 @@ public class PdbAddressManager {
|
||||
// trying to use this.
|
||||
long segmentZeroLength = 0x7fffffff;
|
||||
allSegmentsInfo.add(new SegmentInfo(imageBase, segmentZeroLength));
|
||||
AbstractDatabaseInterface dbi = applicator.getPdb().getDatabaseInterface();
|
||||
if (dbi instanceof DatabaseInterfaceNew) {
|
||||
DebugData debugData = ((DatabaseInterfaceNew) dbi).getDebugData();
|
||||
PdbDebugInfo dbi = applicator.getPdb().getDebugInfo();
|
||||
if (dbi instanceof PdbNewDebugInfo) {
|
||||
DebugData debugData = ((PdbNewDebugInfo) dbi).getDebugData();
|
||||
List<ImageSectionHeader> imageSectionHeaders = debugData.getImageSectionHeaders();
|
||||
for (ImageSectionHeader imageSectionHeader : imageSectionHeaders) {
|
||||
long virtualAddress = imageSectionHeader.getVirtualAddress();
|
||||
@@ -270,12 +270,12 @@ public class PdbAddressManager {
|
||||
allSegmentsInfo.add(new SegmentInfo(imageBase.add(virtualAddress), size));
|
||||
}
|
||||
}
|
||||
// else instance of DatabaseInterface; TODO: what can we do here?
|
||||
// else instance of PdbDebugInfo; TODO: what can we do here?
|
||||
// Maybe get information from the program itself.
|
||||
|
||||
// TODO: what should we do with these? Not doing anything at the moment
|
||||
AbstractPdb pdb = applicator.getPdb();
|
||||
List<SegmentMapDescription> segmentMapList = pdb.getDatabaseInterface().getSegmentMapList();
|
||||
List<SegmentMapDescription> segmentMapList = pdb.getDebugInfo().getSegmentMapList();
|
||||
for (SegmentMapDescription segmentMapDescription : segmentMapList) {
|
||||
segmentMapDescription.getSegmentOffset();
|
||||
segmentMapDescription.getLength();
|
||||
@@ -428,7 +428,7 @@ public class PdbAddressManager {
|
||||
// future.
|
||||
/**
|
||||
* Tries to align section/segment information of the PDB in {@link SegmentMapDescription} from
|
||||
* the {@link AbstractDatabaseInterface} header substream with the memory blocks of the
|
||||
* the {@link PdbDebugInfo} header substream with the memory blocks of the
|
||||
* {@link Program}. Initializes the lookup table to be used for processing the PDB.
|
||||
* <P>
|
||||
* We have seen cases where blocks of the program are combined into a single block representing
|
||||
@@ -441,7 +441,7 @@ public class PdbAddressManager {
|
||||
@SuppressWarnings("unused") // for method not being called and local variables ununsed.
|
||||
private void reconcileMemoryBlocks() throws PdbException {
|
||||
// ImageSectionHeader imageSectionHeader =
|
||||
// pdb.getDatabaseInterface().getDebugData().getImageSectionHeader();
|
||||
// pdb.getDebugInfo().getDebugData().getImageSectionHeader();
|
||||
|
||||
AbstractPdb pdb = applicator.getPdb();
|
||||
Program program = applicator.getProgram();
|
||||
@@ -451,7 +451,7 @@ public class PdbAddressManager {
|
||||
|
||||
Memory mem = program.getMemory();
|
||||
MemoryBlock[] blocks = mem.getBlocks();
|
||||
List<SegmentMapDescription> segmentMapList = pdb.getDatabaseInterface().getSegmentMapList();
|
||||
List<SegmentMapDescription> segmentMapList = pdb.getDebugInfo().getSegmentMapList();
|
||||
/**
|
||||
* Program has additional "Headers" block set up by the {@link PeLoader}.
|
||||
*/
|
||||
@@ -510,15 +510,15 @@ public class PdbAddressManager {
|
||||
@SuppressWarnings("unused") // for method not being called.
|
||||
private boolean garnerSectionSegmentInformation() throws PdbException {
|
||||
AbstractPdb pdb = applicator.getPdb();
|
||||
if (pdb.getDatabaseInterface() == null) {
|
||||
if (pdb.getDebugInfo() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ImageSectionHeader imageSectionHeader =
|
||||
// pdb.getDatabaseInterface().getDebugData().getImageSectionHeader();
|
||||
// pdb.getDebugInfo().getDebugData().getImageSectionHeader();
|
||||
|
||||
int num = 1;
|
||||
for (AbstractModuleInformation module : pdb.getDatabaseInterface().getModuleInformationList()) {
|
||||
for (AbstractModuleInformation module : pdb.getDebugInfo().getModuleInformationList()) {
|
||||
if ("* Linker *".equals(module.getModuleName())) {
|
||||
List<AbstractMsSymbol> linkerSymbolList =
|
||||
applicator.getSymbolGroupForModule(num).getSymbols();
|
||||
|
||||
+25
-16
@@ -356,12 +356,12 @@ public class PdbApplicator {
|
||||
|
||||
private List<SymbolGroup> createSymbolGroups() throws CancelledException, PdbException {
|
||||
List<SymbolGroup> mySymbolGroups = new ArrayList<>();
|
||||
int num = pdb.getDatabaseInterface().getNumModules();
|
||||
int num = pdb.getDebugInfo().getNumModules();
|
||||
// moduleNumber zero is our global/public group.
|
||||
for (int moduleNumber = 0; moduleNumber <= num; moduleNumber++) {
|
||||
monitor.checkCanceled();
|
||||
Map<Long, AbstractMsSymbol> symbols =
|
||||
pdb.getDatabaseInterface().getModuleSymbolsByOffset(moduleNumber);
|
||||
pdb.getDebugInfo().getModuleSymbolsByOffset(moduleNumber);
|
||||
SymbolGroup symbolGroup = new SymbolGroup(symbols, moduleNumber);
|
||||
mySymbolGroups.add(symbolGroup);
|
||||
}
|
||||
@@ -491,7 +491,7 @@ public class PdbApplicator {
|
||||
|
||||
/**
|
||||
* Returns the {@link CategoryPath} for a typedef with with the give {@link SymbolPath} and
|
||||
* module number; 1 <= moduleNumber <= {@link AbstractDatabaseInterface#getNumModules()},
|
||||
* module number; 1 <= moduleNumber <= {@link PdbDebugInfo#getNumModules()},
|
||||
* except that modeleNumber of 0 represents publics/globals.
|
||||
* @param moduleNumber module number
|
||||
* @param symbolPath SymbolPath of the symbol
|
||||
@@ -539,11 +539,11 @@ public class PdbApplicator {
|
||||
throws CancelledException, PdbException {
|
||||
|
||||
List<String> categoryNames = new ArrayList<>();
|
||||
int num = pdb.getDatabaseInterface().getNumModules();
|
||||
int num = pdb.getDebugInfo().getNumModules();
|
||||
for (int index = 1; index <= num; index++) {
|
||||
monitor.checkCanceled();
|
||||
String moduleName =
|
||||
pdb.getDatabaseInterface().getModuleInformation(index).getModuleName();
|
||||
pdb.getDebugInfo().getModuleInformation(index).getModuleName();
|
||||
categoryNames.add(moduleName);
|
||||
}
|
||||
|
||||
@@ -610,7 +610,7 @@ public class PdbApplicator {
|
||||
//==============================================================================================
|
||||
//==============================================================================================
|
||||
int findModuleNumberBySectionOffsetContribution(int section, long offset) throws PdbException {
|
||||
for (AbstractSectionContribution sectionContribution : pdb.getDatabaseInterface().getSectionContributionList()) {
|
||||
for (AbstractSectionContribution sectionContribution : pdb.getDebugInfo().getSectionContributionList()) {
|
||||
int sectionContributionOffset = sectionContribution.getOffset();
|
||||
int maxSectionContributionOffset =
|
||||
sectionContributionOffset + sectionContribution.getLength();
|
||||
@@ -624,6 +624,9 @@ public class PdbApplicator {
|
||||
//==============================================================================================
|
||||
private void processDataTypesSequentially() throws CancelledException, PdbException {
|
||||
AbstractTypeProgramInterface tpi = pdb.getTypeProgramInterface();
|
||||
if (tpi == null) {
|
||||
return;
|
||||
}
|
||||
int num = tpi.getTypeIndexMaxExclusive() - tpi.getTypeIndexMin();
|
||||
monitor.initialize(num);
|
||||
setMonitorMessage("PDB: Processing " + num + " data type components...");
|
||||
@@ -688,6 +691,9 @@ public class PdbApplicator {
|
||||
//==============================================================================================
|
||||
private void processItemTypesSequentially() throws CancelledException, PdbException {
|
||||
AbstractTypeProgramInterface ipi = pdb.getItemProgramInterface();
|
||||
if (ipi == null) {
|
||||
return;
|
||||
}
|
||||
int num = ipi.getTypeIndexMaxExclusive() - ipi.getTypeIndexMin();
|
||||
monitor.initialize(num);
|
||||
setMonitorMessage("PDB: Processing " + num + " item type components...");
|
||||
@@ -725,6 +731,9 @@ public class PdbApplicator {
|
||||
//==============================================================================================
|
||||
private void resolveSequentially() throws CancelledException {
|
||||
AbstractTypeProgramInterface tpi = pdb.getTypeProgramInterface();
|
||||
if (tpi == null) {
|
||||
return;
|
||||
}
|
||||
int num = tpi.getTypeIndexMaxExclusive() - tpi.getTypeIndexMin();
|
||||
monitor.initialize(num);
|
||||
setMonitorMessage("PDB: Resolving " + num + " data type components...");
|
||||
@@ -772,7 +781,7 @@ public class PdbApplicator {
|
||||
|
||||
// public AbstractMsSymbol getSymbolForModuleAndOffset(int moduleNumber, long offset)
|
||||
// throws PdbException {
|
||||
// return pdb.getDatabaseInterface().getSymbolForModuleAndOffsetOfRecord(moduleNumber, offset);
|
||||
// return pdb.getDebugInfo().getSymbolForModuleAndOffsetOfRecord(moduleNumber, offset);
|
||||
// }
|
||||
|
||||
//==============================================================================================
|
||||
@@ -931,7 +940,7 @@ public class PdbApplicator {
|
||||
//==============================================================================================
|
||||
private void processModuleSymbols() throws CancelledException {
|
||||
int totalCount = 0;
|
||||
int num = pdb.getDatabaseInterface().getNumModules();
|
||||
int num = pdb.getDebugInfo().getNumModules();
|
||||
for (int moduleNumber = 1; moduleNumber <= num; moduleNumber++) {
|
||||
monitor.checkCanceled();
|
||||
SymbolGroup symbolGroup = getSymbolGroupForModule(moduleNumber);
|
||||
@@ -990,7 +999,7 @@ public class PdbApplicator {
|
||||
SymbolGroup symbolGroup = getSymbolGroup();
|
||||
|
||||
PublicSymbolInformation publicSymbolInformation =
|
||||
pdb.getDatabaseInterface().getPublicSymbolInformation();
|
||||
pdb.getDebugInfo().getPublicSymbolInformation();
|
||||
List<Long> offsets = publicSymbolInformation.getModifiedHashRecordSymbolOffsets();
|
||||
setMonitorMessage("PDB: Applying " + offsets.size() + " public symbol components...");
|
||||
monitor.initialize(offsets.size());
|
||||
@@ -1020,7 +1029,7 @@ public class PdbApplicator {
|
||||
SymbolGroup symbolGroup = getSymbolGroup();
|
||||
|
||||
GlobalSymbolInformation globalSymbolInformation =
|
||||
pdb.getDatabaseInterface().getGlobalSymbolInformation();
|
||||
pdb.getDebugInfo().getGlobalSymbolInformation();
|
||||
List<Long> offsets = globalSymbolInformation.getModifiedHashRecordSymbolOffsets();
|
||||
setMonitorMessage("PDB: Applying global symbols...");
|
||||
monitor.initialize(offsets.size());
|
||||
@@ -1051,7 +1060,7 @@ public class PdbApplicator {
|
||||
SymbolGroup symbolGroup = getSymbolGroup();
|
||||
|
||||
GlobalSymbolInformation globalSymbolInformation =
|
||||
pdb.getDatabaseInterface().getGlobalSymbolInformation();
|
||||
pdb.getDebugInfo().getGlobalSymbolInformation();
|
||||
List<Long> offsets = globalSymbolInformation.getModifiedHashRecordSymbolOffsets();
|
||||
setMonitorMessage("PDB: Applying typedefs...");
|
||||
monitor.initialize(offsets.size());
|
||||
@@ -1081,11 +1090,11 @@ public class PdbApplicator {
|
||||
@SuppressWarnings("unused") // for method not being called.
|
||||
private void processNonPublicOrGlobalSymbols() throws CancelledException, PdbException {
|
||||
Set<Long> offsetsRemaining = getSymbolGroup().getOffsets();
|
||||
for (long off : pdb.getDatabaseInterface().getPublicSymbolInformation().getModifiedHashRecordSymbolOffsets()) {
|
||||
for (long off : pdb.getDebugInfo().getPublicSymbolInformation().getModifiedHashRecordSymbolOffsets()) {
|
||||
monitor.checkCanceled();
|
||||
offsetsRemaining.remove(off);
|
||||
}
|
||||
for (long off : pdb.getDatabaseInterface().getGlobalSymbolInformation().getModifiedHashRecordSymbolOffsets()) {
|
||||
for (long off : pdb.getDebugInfo().getGlobalSymbolInformation().getModifiedHashRecordSymbolOffsets()) {
|
||||
monitor.checkCanceled();
|
||||
offsetsRemaining.remove(off);
|
||||
}
|
||||
@@ -1108,9 +1117,9 @@ public class PdbApplicator {
|
||||
|
||||
//==============================================================================================
|
||||
private int findLinkerModuleNumber() {
|
||||
if (pdb.getDatabaseInterface() != null) {
|
||||
if (pdb.getDebugInfo() != null) {
|
||||
int num = 1;
|
||||
for (AbstractModuleInformation module : pdb.getDatabaseInterface().getModuleInformationList()) {
|
||||
for (AbstractModuleInformation module : pdb.getDebugInfo().getModuleInformationList()) {
|
||||
if (isLinkerModule(module.getModuleName())) {
|
||||
return num;
|
||||
}
|
||||
@@ -1159,7 +1168,7 @@ public class PdbApplicator {
|
||||
int linkerModuleNumber = findLinkerModuleNumber();
|
||||
|
||||
int totalCount = 0;
|
||||
int num = pdb.getDatabaseInterface().getNumModules();
|
||||
int num = pdb.getDebugInfo().getNumModules();
|
||||
for (int index = 1; index <= num; index++) {
|
||||
monitor.checkCanceled();
|
||||
if (index == linkerModuleNumber) {
|
||||
|
||||
+5
-5
@@ -411,7 +411,7 @@ public class PdbResearch {
|
||||
throws CancelledException, PdbException {
|
||||
SymbolGroup symbolGroup = applicator.getSymbolGroup();
|
||||
GlobalSymbolInformation globalSymbolInformation =
|
||||
applicator.getPdb().getDatabaseInterface().getGlobalSymbolInformation();
|
||||
applicator.getPdb().getDebugInfo().getGlobalSymbolInformation();
|
||||
List<Long> offsets = globalSymbolInformation.getModifiedHashRecordSymbolOffsets();
|
||||
applicator.setMonitorMessage("PDB: Applying typedefs...");
|
||||
monitor.initialize(offsets.size());
|
||||
@@ -619,7 +619,7 @@ public class PdbResearch {
|
||||
SymbolGroup symbolGroup = applicator.getSymbolGroup();
|
||||
|
||||
PublicSymbolInformation publicSymbolInformation =
|
||||
pdb.getDatabaseInterface().getPublicSymbolInformation();
|
||||
pdb.getDebugInfo().getPublicSymbolInformation();
|
||||
List<Long> offsets = publicSymbolInformation.getModifiedHashRecordSymbolOffsets();
|
||||
applicator.setMonitorMessage(
|
||||
"PDB: Applying " + offsets.size() + " public symbol components...");
|
||||
@@ -646,7 +646,7 @@ public class PdbResearch {
|
||||
SymbolGroup symbolGroup = applicator.getSymbolGroup();
|
||||
|
||||
GlobalSymbolInformation globalSymbolInformation =
|
||||
pdb.getDatabaseInterface().getGlobalSymbolInformation();
|
||||
pdb.getDebugInfo().getGlobalSymbolInformation();
|
||||
List<Long> offsets = globalSymbolInformation.getModifiedHashRecordSymbolOffsets();
|
||||
applicator.setMonitorMessage("PDB: Applying global symbols...");
|
||||
monitor.initialize(offsets.size());
|
||||
@@ -670,7 +670,7 @@ public class PdbResearch {
|
||||
Map<Address, List<Stuff>> map, TaskMonitor monitor) throws CancelledException {
|
||||
AbstractPdb pdb = applicator.getPdb();
|
||||
int totalCount = 0;
|
||||
int num = pdb.getDatabaseInterface().getNumModules();
|
||||
int num = pdb.getDebugInfo().getNumModules();
|
||||
for (int moduleNumber = 1; moduleNumber <= num; moduleNumber++) {
|
||||
monitor.checkCanceled();
|
||||
SymbolGroup symbolGroup = applicator.getSymbolGroupForModule(moduleNumber);
|
||||
@@ -688,7 +688,7 @@ public class PdbResearch {
|
||||
monitor.checkCanceled();
|
||||
|
||||
// String moduleName =
|
||||
// pdb.getDatabaseInterface().getModuleInformation(index).getModuleName();
|
||||
// pdb.getDebugInfo().getModuleInformation(index).getModuleName();
|
||||
|
||||
// Process module symbols list
|
||||
SymbolGroup symbolGroup = applicator.getSymbolGroupForModule(moduleNumber);
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ public class PdbVbtManager extends VbtManager {
|
||||
Map<String, Address> myAddressByMangledName = new HashMap<>();
|
||||
|
||||
PublicSymbolInformation publicSymbolInformation =
|
||||
applicator.getPdb().getDatabaseInterface().getPublicSymbolInformation();
|
||||
applicator.getPdb().getDebugInfo().getPublicSymbolInformation();
|
||||
List<Long> offsets = publicSymbolInformation.getModifiedHashRecordSymbolOffsets();
|
||||
applicator.setMonitorMessage("PDB: Searching for virtual base table symbols...");
|
||||
monitor.initialize(offsets.size());
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/* ###
|
||||
* 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 pdb;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import docking.DialogComponentProvider;
|
||||
import docking.DockingWindowManager;
|
||||
import docking.widgets.combobox.GComboBox;
|
||||
import ghidra.app.util.bin.format.pdb.PdbParser;
|
||||
import ghidra.app.util.pdb.pdbapplicator.PdbApplicatorRestrictions;
|
||||
import ghidra.util.layout.PairLayout;
|
||||
|
||||
class AskPdbOptionsDialog extends DialogComponentProvider {
|
||||
|
||||
private boolean isCanceled;
|
||||
|
||||
private boolean useMsDiaParser = true;
|
||||
private PdbApplicatorRestrictions restrictions = PdbApplicatorRestrictions.NONE;
|
||||
|
||||
/**
|
||||
* Popup PDB loader options
|
||||
* @param parent parent component or null
|
||||
* @param isPdbFile true if file to be loaded is a PDB file, false
|
||||
* if MsDia XML file.
|
||||
*/
|
||||
AskPdbOptionsDialog(Component parent, boolean isPdbFile) {
|
||||
super("Load PDB Options", true, true, true, false);
|
||||
|
||||
JPanel panel = new JPanel(new BorderLayout(10, 10));
|
||||
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
|
||||
JPanel optionsPanel = new JPanel(new PairLayout(10, 10));
|
||||
|
||||
final GComboBox<PdbApplicatorRestrictions> restrictionsCombo =
|
||||
new GComboBox<>(PdbApplicatorRestrictions.values());
|
||||
restrictionsCombo.setSelectedItem(PdbApplicatorRestrictions.NONE);
|
||||
restrictionsCombo.addActionListener(e -> {
|
||||
restrictions = (PdbApplicatorRestrictions) restrictionsCombo.getSelectedItem();
|
||||
});
|
||||
|
||||
optionsPanel.add(new JLabel("PDB Parser:"));
|
||||
|
||||
if (isPdbFile) {
|
||||
if (PdbParser.onWindows) {
|
||||
final GComboBox<String> combo =
|
||||
new GComboBox<>(new String[] { "PDB MSDIA", "PDB Universal (Prototype)" });
|
||||
combo.setSelectedIndex(0);
|
||||
restrictionsCombo.setEnabled(!useMsDiaParser);
|
||||
combo.addActionListener(e -> {
|
||||
useMsDiaParser = (combo.getSelectedIndex() == 0);
|
||||
restrictionsCombo.setEnabled(!useMsDiaParser);
|
||||
if (useMsDiaParser) {
|
||||
restrictionsCombo.setSelectedItem(PdbApplicatorRestrictions.NONE);
|
||||
}
|
||||
});
|
||||
optionsPanel.add(combo);
|
||||
}
|
||||
else {
|
||||
useMsDiaParser = false;
|
||||
JLabel label = new JLabel("PDB Universal (Prototype)");
|
||||
label.setForeground(Color.red); // set color to emphasize prototype status
|
||||
optionsPanel.add(label);
|
||||
}
|
||||
}
|
||||
else {
|
||||
useMsDiaParser = true; // XML file only supported by MsDia parser
|
||||
return; // no interaction currently required
|
||||
}
|
||||
|
||||
optionsPanel.add(new JLabel("Restrictions:"));
|
||||
optionsPanel.add(restrictionsCombo);
|
||||
|
||||
panel.add(optionsPanel, BorderLayout.CENTER);
|
||||
|
||||
addWorkPanel(panel);
|
||||
|
||||
addApplyButton();
|
||||
addCancelButton();
|
||||
|
||||
setDefaultButton(applyButton);
|
||||
setRememberSize(false);
|
||||
|
||||
DockingWindowManager.showDialog(parent, AskPdbOptionsDialog.this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void applyCallback() {
|
||||
isCanceled = false;
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cancelCallback() {
|
||||
isCanceled = true;
|
||||
close();
|
||||
}
|
||||
|
||||
boolean isCanceled() {
|
||||
return isCanceled;
|
||||
}
|
||||
|
||||
boolean useMsDiaParser() {
|
||||
return useMsDiaParser;
|
||||
}
|
||||
|
||||
PdbApplicatorRestrictions getApplicatorRestrictions() {
|
||||
return restrictions;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,7 +19,6 @@ import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
@@ -98,18 +97,8 @@ public class AskPdbUrlDialog extends DialogComponentProvider {
|
||||
|
||||
setDefaultButton(okButton);
|
||||
setRememberSize(false);
|
||||
if (SwingUtilities.isEventDispatchThread()) {
|
||||
DockingWindowManager.showDialog(parent, this);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(
|
||||
() -> DockingWindowManager.showDialog(parent, AskPdbUrlDialog.this));
|
||||
}
|
||||
catch (InvocationTargetException | InterruptedException e) {
|
||||
// TODO: handle this?
|
||||
}
|
||||
}
|
||||
|
||||
DockingWindowManager.showDialog(parent, AskPdbUrlDialog.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,15 +16,20 @@
|
||||
package pdb;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import docking.DockingWindowManager;
|
||||
import docking.widgets.dialogs.MultiLineMessageDialog;
|
||||
import ghidra.app.plugin.core.analysis.*;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DuplicateIdException;
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.app.util.bin.format.pdb.PdbException;
|
||||
import ghidra.app.util.bin.format.pdb.PdbParser;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.AbstractPdb;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbReaderOptions;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.app.util.pdb.pdbapplicator.*;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.listing.Program;
|
||||
@@ -37,11 +42,16 @@ class LoadPdbTask extends Task {
|
||||
private File pdbFile;
|
||||
private DataTypeManagerService service;
|
||||
private final Program program;
|
||||
private final boolean useMsDiaParser;
|
||||
private final PdbApplicatorRestrictions restrictions; // PDB Universal Parser only
|
||||
|
||||
LoadPdbTask(Program program, File pdbFile, DataTypeManagerService service) {
|
||||
LoadPdbTask(Program program, File pdbFile, boolean useMsDiaParser,
|
||||
PdbApplicatorRestrictions restrictions, DataTypeManagerService service) {
|
||||
super("Loading PDB...", true, false, false);
|
||||
this.program = program;
|
||||
this.pdbFile = pdbFile;
|
||||
this.useMsDiaParser = useMsDiaParser;
|
||||
this.restrictions = restrictions;
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@@ -58,33 +68,38 @@ class LoadPdbTask extends Task {
|
||||
|
||||
@Override
|
||||
public boolean analysisWorkerCallback(Program currentProgram, Object workerContext,
|
||||
TaskMonitor currentMonitor) throws Exception, CancelledException, PdbException {
|
||||
TaskMonitor currentMonitor) throws CancelledException {
|
||||
|
||||
PdbParser parser =
|
||||
new PdbParser(pdbFile, program, service, true, currentMonitor);
|
||||
|
||||
parser.parse();
|
||||
parser.openDataTypeArchives();
|
||||
parser.applyTo(log);
|
||||
|
||||
analyzeSymbols(currentMonitor, log);
|
||||
return !monitor.isCancelled();
|
||||
try {
|
||||
if (useMsDiaParser) {
|
||||
if (!parseWithMsDiaParser(log, monitor)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!parseWithNewParser(log, monitor)) {
|
||||
return false;
|
||||
}
|
||||
analyzeSymbols(currentMonitor, log);
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg("PDB IO Error: " + e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
boolean analyzed =
|
||||
program.getOptions(Program.PROGRAM_INFO).getBoolean(Program.ANALYZED, false);
|
||||
if (analyzed) {
|
||||
Msg.showWarn(this, null, "PDB Warning",
|
||||
"Loading PDB after analysis has been performed will produce" +
|
||||
"\npoor results. PDBs should be loaded prior to analysis or" +
|
||||
"\nautomatically during auto-analysis.");
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
AutoAnalysisManager.getAnalysisManager(program)
|
||||
.scheduleWorker(worker, null, true,
|
||||
monitor);
|
||||
if (log.hasMessages()) {
|
||||
MultiLineMessageDialog dialog = new MultiLineMessageDialog("Load PDB File",
|
||||
"There were warnings/errors loading the PDB file.", log.toString(),
|
||||
MultiLineMessageDialog.WARNING_MESSAGE, false);
|
||||
DockingWindowManager.showDialog(null, dialog);
|
||||
}
|
||||
}
|
||||
catch (InterruptedException | CancelledException e1) {
|
||||
// ignore
|
||||
@@ -105,17 +120,53 @@ class LoadPdbTask extends Task {
|
||||
}
|
||||
}
|
||||
|
||||
message = "Error processing PDB file: " + pdbFile + ".\n" + message;
|
||||
|
||||
Msg.showError(getClass(), null, "Load PDB Failed", message, t);
|
||||
}
|
||||
|
||||
if (log.hasMessages()) {
|
||||
MultiLineMessageDialog dialog = new MultiLineMessageDialog("Load PDB File",
|
||||
"There were warnings/errors loading the PDB file.", log.toString(),
|
||||
MultiLineMessageDialog.WARNING_MESSAGE, false);
|
||||
DockingWindowManager.showDialog(null, dialog);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean parseWithMsDiaParser(MessageLog log, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
PdbParser parser = new PdbParser(pdbFile, program, service, true, monitor);
|
||||
try {
|
||||
parser.parse();
|
||||
parser.openDataTypeArchives();
|
||||
parser.applyTo(log);
|
||||
return true;
|
||||
}
|
||||
catch (PdbException | DuplicateIdException e) {
|
||||
log.appendMsg("PDB Error: " + e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean parseWithNewParser(MessageLog log, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
|
||||
PdbReaderOptions pdbReaderOptions = new PdbReaderOptions(); // use defaults
|
||||
|
||||
PdbApplicatorOptions pdbApplicatorOptions = new PdbApplicatorOptions();
|
||||
|
||||
pdbApplicatorOptions.setRestrictions(restrictions);
|
||||
|
||||
try (AbstractPdb pdb =
|
||||
ghidra.app.util.bin.format.pdb2.pdbreader.PdbParser.parse(pdbFile.getAbsolutePath(),
|
||||
pdbReaderOptions, monitor)) {
|
||||
monitor.setMessage("PDB: Parsing " + pdbFile + "...");
|
||||
pdb.deserialize(monitor);
|
||||
PdbApplicator applicator = new PdbApplicator(pdbFile.getAbsolutePath(), pdb);
|
||||
applicator.applyTo(program, program.getDataTypeManager(), program.getImageBase(),
|
||||
pdbApplicatorOptions, monitor, log);
|
||||
return true;
|
||||
}
|
||||
catch (ghidra.app.util.bin.format.pdb2.pdbreader.PdbException e) {
|
||||
log.appendMsg("PDB Error: " + e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void analyzeSymbols(TaskMonitor monitor, MessageLog log) {
|
||||
|
||||
MicrosoftDemanglerAnalyzer demanglerAnalyzer = new MicrosoftDemanglerAnalyzer();
|
||||
@@ -135,9 +186,8 @@ class LoadPdbTask extends Task {
|
||||
demanglerAnalyzer.added(program, addrs, monitor, log);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// Don't care about CancelledException
|
||||
// ignore cancel
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package pdb;
|
||||
import java.io.File;
|
||||
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.filechooser.GhidraFileChooser;
|
||||
import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.context.ProgramActionContext;
|
||||
@@ -25,8 +26,8 @@ import ghidra.app.context.ProgramContextAction;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.app.util.bin.format.pdb.PdbException;
|
||||
import ghidra.app.util.bin.format.pdb.PdbParser;
|
||||
import ghidra.app.util.pdb.pdbapplicator.PdbApplicatorRestrictions;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.program.model.listing.Program;
|
||||
@@ -89,13 +90,40 @@ public class PdbPlugin extends Plugin {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean analyzed =
|
||||
program.getOptions(Program.PROGRAM_INFO).getBoolean(Program.ANALYZED, false);
|
||||
|
||||
if (analyzed) {
|
||||
int response =
|
||||
OptionDialog.showOptionDialogWithCancelAsDefaultButton(null, "Load PDB Warning",
|
||||
"Loading PDB after running analysis may produce poor results." +
|
||||
"\nPDBs should generally be loaded prior to analysis or" +
|
||||
"\nautomatically during auto-analysis.",
|
||||
"Continue");
|
||||
if (response != OptionDialog.OPTION_ONE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
File pdb = getPdbFile(program);
|
||||
if (pdb == null) {
|
||||
tool.setStatusInfo("Loading PDB was cancelled.");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isPdbFile = pdb.getName().toLowerCase().endsWith(".pdb");
|
||||
|
||||
AskPdbOptionsDialog optionsDialog = new AskPdbOptionsDialog(null, isPdbFile);
|
||||
if (optionsDialog.isCanceled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean useMsDiaParser = optionsDialog.useMsDiaParser();
|
||||
PdbApplicatorRestrictions restrictions = optionsDialog.getApplicatorRestrictions();
|
||||
|
||||
tool.setStatusInfo("");
|
||||
|
||||
DataTypeManagerService service = tool.getService(DataTypeManagerService.class);
|
||||
if (service == null) {
|
||||
Msg.showWarn(getClass(), null, "Load PDB",
|
||||
@@ -103,14 +131,15 @@ public class PdbPlugin extends Plugin {
|
||||
return;
|
||||
}
|
||||
|
||||
TaskLauncher.launch(new LoadPdbTask(program, pdb, service));
|
||||
TaskLauncher
|
||||
.launch(new LoadPdbTask(program, pdb, useMsDiaParser, restrictions, service));
|
||||
}
|
||||
catch (Exception pe) {
|
||||
Msg.showError(getClass(), null, "Error", pe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private File getPdbFile(Program program) throws PdbException {
|
||||
private File getPdbFile(Program program) {
|
||||
File pdbFile = PdbParser.findPDB(program);
|
||||
if (pdbChooser == null) {
|
||||
pdbChooser = new GhidraFileChooser(tool.getToolFrame());
|
||||
@@ -121,7 +150,9 @@ public class PdbPlugin extends Plugin {
|
||||
"Program Database Files and PDB XML Representations"));
|
||||
}
|
||||
|
||||
pdbChooser.setSelectedFile(pdbFile);
|
||||
if (pdbFile != null) {
|
||||
pdbChooser.setSelectedFile(pdbFile);
|
||||
}
|
||||
|
||||
File selectedFile = pdbChooser.getSelectedFile();
|
||||
return selectedFile;
|
||||
|
||||
@@ -30,10 +30,13 @@ import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.context.ProgramActionContext;
|
||||
import ghidra.app.context.ProgramContextAction;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.app.util.bin.format.pdb.*;
|
||||
import ghidra.app.util.bin.format.pdb.PdbException;
|
||||
import ghidra.app.util.bin.format.pdb.PdbParser;
|
||||
import ghidra.app.util.bin.format.pdb.PdbParser.PdbFileType;
|
||||
import ghidra.app.util.pdb.PdbProgramAttributes;
|
||||
import ghidra.app.util.pdb.pdbapplicator.PdbApplicatorRestrictions;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
@@ -193,6 +196,12 @@ public class PdbSymbolServerPlugin extends Plugin {
|
||||
try {
|
||||
PdbProgramAttributes pdbAttributes = PdbParser.getPdbAttributes(program);
|
||||
|
||||
if (pdbAttributes.getGuidAgeCombo() == null) {
|
||||
throw new PdbException(
|
||||
"Incomplete PDB information (GUID/Signature and/or age) associated with this program.\n" +
|
||||
"Either the program is not a PE, or it was not compiled with debug information.");
|
||||
}
|
||||
|
||||
// 1. Ask if user wants .pdb or .pdb.xml file
|
||||
fileType = askForFileExtension();
|
||||
|
||||
@@ -298,7 +307,7 @@ public class PdbSymbolServerPlugin extends Plugin {
|
||||
int choice = OptionDialog.showOptionDialog(
|
||||
null,
|
||||
"pdb or pdb.xml",
|
||||
"Download a .pdb or .pdb.xml file? (.pdb.xml can be processed on non-Windows systems)",
|
||||
"Download a .pdb or .pdb.xml file?",
|
||||
"PDB",
|
||||
"XML");
|
||||
//@formatter:on
|
||||
@@ -697,6 +706,8 @@ public class PdbSymbolServerPlugin extends Plugin {
|
||||
File tempSaveDirectory, File finalSaveDirectory, RetrieveFileType retrieveFileType)
|
||||
throws IOException, PdbException {
|
||||
|
||||
// TODO: This should be performed by a monitored Task with ability to cancel
|
||||
|
||||
String guidAgeString = pdbAttributes.getGuidAgeCombo();
|
||||
List<String> potentialPdbFilenames = pdbAttributes.getPotentialPdbFilenames();
|
||||
File tempFile = null;
|
||||
@@ -775,34 +786,39 @@ public class PdbSymbolServerPlugin extends Plugin {
|
||||
|
||||
private void tryToLoadPdb(File downloadedPdb, Program currentProgram) {
|
||||
|
||||
// Only ask to load PDB if file type is applicable for current OS
|
||||
if (fileType == PdbFileType.PDB && !PdbParser.onWindows) {
|
||||
AutoAnalysisManager aam = AutoAnalysisManager.getAnalysisManager(currentProgram);
|
||||
if (aam.isAnalyzing()) {
|
||||
Msg.showWarn(getClass(), null, "Load PDB",
|
||||
"Unable to load PDB file while analysis is running.");
|
||||
return;
|
||||
}
|
||||
|
||||
String htmlString =
|
||||
HTMLUtilities.toWrappedHTML("Would you like to apply the following PDB:\n\n" +
|
||||
downloadedPdb.getAbsolutePath() + "\n\n to " + currentProgram.getName() + "?");
|
||||
boolean analyzed =
|
||||
currentProgram.getOptions(Program.PROGRAM_INFO).getBoolean(Program.ANALYZED, false);
|
||||
|
||||
int response = OptionDialog.showYesNoDialog(null, "Load PDB?", htmlString);
|
||||
|
||||
switch (response) {
|
||||
case 0:
|
||||
// User cancelled
|
||||
return;
|
||||
|
||||
case 1:
|
||||
// Yes -- do nothing here
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// No
|
||||
return;
|
||||
|
||||
default:
|
||||
// do nothing
|
||||
String message = "Would you like to apply the following PDB:\n\n" +
|
||||
downloadedPdb.getAbsolutePath() + "\n\n to " + currentProgram.getName() + "?";
|
||||
if (analyzed) {
|
||||
message += "\n \nWARNING: Loading PDB after analysis has been performed may produce" +
|
||||
"\npoor results. PDBs should generally be loaded prior to analysis or" +
|
||||
"\nautomatically during auto-analysis.";
|
||||
}
|
||||
|
||||
String htmlString = HTMLUtilities.toWrappedHTML(message);
|
||||
int response = OptionDialog.showYesNoDialog(null, "Load PDB?", htmlString);
|
||||
if (response != OptionDialog.YES_OPTION) {
|
||||
return;
|
||||
}
|
||||
|
||||
AskPdbOptionsDialog optionsDialog =
|
||||
new AskPdbOptionsDialog(null, fileType == PdbFileType.PDB);
|
||||
if (optionsDialog.isCanceled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean useMsDiaParser = optionsDialog.useMsDiaParser();
|
||||
PdbApplicatorRestrictions restrictions = optionsDialog.getApplicatorRestrictions();
|
||||
|
||||
tool.setStatusInfo("");
|
||||
|
||||
try {
|
||||
@@ -813,7 +829,10 @@ public class PdbSymbolServerPlugin extends Plugin {
|
||||
return;
|
||||
}
|
||||
|
||||
TaskLauncher.launch(new LoadPdbTask(currentProgram, downloadedPdb, service));
|
||||
TaskLauncher
|
||||
.launch(
|
||||
new LoadPdbTask(currentProgram, downloadedPdb, useMsDiaParser, restrictions,
|
||||
service));
|
||||
}
|
||||
catch (Exception pe) {
|
||||
Msg.showError(getClass(), null, "Error", pe.getMessage());
|
||||
|
||||
+53
-100
@@ -358,17 +358,13 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
@Test
|
||||
public void testFindPdb2() throws Exception {
|
||||
|
||||
try {
|
||||
createdFiles = createFiles(PdbLocation.SYMBOLS_SUBDIR, PdbXmlLocation.NONE);
|
||||
createdFiles = createFiles(PdbLocation.SYMBOLS_SUBDIR, PdbXmlLocation.NONE);
|
||||
|
||||
File pdb = PdbParser.findPDB(testProgram, false, symbolsFolder.getAbsolutePath());
|
||||
File pdb = PdbParser.findPDB(testProgram, false, symbolsFolder.getAbsolutePath());
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
}
|
||||
catch (PdbException pdbe) {
|
||||
fail("Unexpected PdbException!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -411,17 +407,13 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
@Test
|
||||
public void testFindPdb4() throws Exception {
|
||||
|
||||
try {
|
||||
createdFiles = createFiles(PdbLocation.SYMBOLS_SUBDIR, PdbXmlLocation.OWN_DIR);
|
||||
createdFiles = createFiles(PdbLocation.SYMBOLS_SUBDIR, PdbXmlLocation.OWN_DIR);
|
||||
|
||||
File pdb = PdbParser.findPDB(testProgram, false, symbolsFolder.getAbsolutePath());
|
||||
File pdb = PdbParser.findPDB(testProgram, false, symbolsFolder.getAbsolutePath());
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdb.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdb.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
}
|
||||
catch (PdbException pdbe) {
|
||||
fail("Unexpected PdbException!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -464,17 +456,13 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
@Test
|
||||
public void testFindPdb6() throws Exception {
|
||||
|
||||
try {
|
||||
createdFiles = createFiles(PdbLocation.SYMBOLS_NO_SUBDIR, PdbXmlLocation.NONE);
|
||||
createdFiles = createFiles(PdbLocation.SYMBOLS_NO_SUBDIR, PdbXmlLocation.NONE);
|
||||
|
||||
File pdb = PdbParser.findPDB(testProgram, false, symbolsFolder.getAbsolutePath());
|
||||
File pdb = PdbParser.findPDB(testProgram, false, symbolsFolder.getAbsolutePath());
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
}
|
||||
catch (PdbException pdbe) {
|
||||
fail("Unexpected PdbException!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -537,17 +525,13 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
@Test
|
||||
public void testFindPdb9() throws Exception {
|
||||
|
||||
try {
|
||||
createdFiles = createFiles(PdbLocation.SYMBOLS_NO_SUBDIR, PdbXmlLocation.OWN_DIR);
|
||||
createdFiles = createFiles(PdbLocation.SYMBOLS_NO_SUBDIR, PdbXmlLocation.OWN_DIR);
|
||||
|
||||
File pdb = PdbParser.findPDB(testProgram, false, symbolsFolder.getAbsolutePath());
|
||||
File pdb = PdbParser.findPDB(testProgram, false, symbolsFolder.getAbsolutePath());
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
}
|
||||
catch (PdbException pdbe) {
|
||||
fail("Unexpected PdbException!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -590,17 +574,13 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
@Test
|
||||
public void testFindPdb11() throws Exception {
|
||||
|
||||
try {
|
||||
createdFiles = createFiles(PdbLocation.SAME_AS_EXE_SUBDIR, PdbXmlLocation.NONE);
|
||||
createdFiles = createFiles(PdbLocation.SAME_AS_EXE_SUBDIR, PdbXmlLocation.NONE);
|
||||
|
||||
File pdb = PdbParser.findPDB(testProgram, false, pdbFile.getParent());
|
||||
File pdb = PdbParser.findPDB(testProgram, false, pdbFile.getParent());
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
}
|
||||
catch (PdbException pdbe) {
|
||||
fail("Unexpected PdbException!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -663,17 +643,13 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
@Test
|
||||
public void testFindPdb14() throws Exception {
|
||||
|
||||
try {
|
||||
createdFiles = createFiles(PdbLocation.SAME_AS_EXE_SUBDIR, PdbXmlLocation.OWN_DIR);
|
||||
createdFiles = createFiles(PdbLocation.SAME_AS_EXE_SUBDIR, PdbXmlLocation.OWN_DIR);
|
||||
|
||||
File pdb = PdbParser.findPDB(testProgram, false, pdbFile.getParent());
|
||||
File pdb = PdbParser.findPDB(testProgram, false, pdbFile.getParent());
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
}
|
||||
catch (PdbException pdbe) {
|
||||
fail("Unexpected PdbException!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -719,17 +695,13 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
@Test
|
||||
public void testFindPdb16() throws Exception {
|
||||
|
||||
try {
|
||||
createdFiles = createFiles(PdbLocation.SAME_AS_EXE_NO_SUBDIR, PdbXmlLocation.NONE);
|
||||
createdFiles = createFiles(PdbLocation.SAME_AS_EXE_NO_SUBDIR, PdbXmlLocation.NONE);
|
||||
|
||||
File pdb = PdbParser.findPDB(testProgram, false, defaultSymbolsRepoPath);
|
||||
File pdb = PdbParser.findPDB(testProgram, false, defaultSymbolsRepoPath);
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
}
|
||||
catch (PdbException pdbe) {
|
||||
fail("Unexpected PdbException!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -745,17 +717,13 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
@Test
|
||||
public void testFindPdb17() throws Exception {
|
||||
|
||||
try {
|
||||
createdFiles = createFiles(PdbLocation.SAME_AS_EXE_NO_SUBDIR, PdbXmlLocation.NONE);
|
||||
createdFiles = createFiles(PdbLocation.SAME_AS_EXE_NO_SUBDIR, PdbXmlLocation.NONE);
|
||||
|
||||
File pdb = PdbParser.findPDB(testProgram, false, pdbFile.getParent());
|
||||
File pdb = PdbParser.findPDB(testProgram, false, pdbFile.getParent());
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
}
|
||||
catch (PdbException pdbe) {
|
||||
fail("Unexpected PdbException!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -774,17 +742,13 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
@Test
|
||||
public void testFindPdb18() throws Exception {
|
||||
|
||||
try {
|
||||
createdFiles = createFiles(PdbLocation.SAME_AS_EXE_NO_SUBDIR, PdbXmlLocation.NONE);
|
||||
createdFiles = createFiles(PdbLocation.SAME_AS_EXE_NO_SUBDIR, PdbXmlLocation.NONE);
|
||||
|
||||
File pdb = PdbParser.findPDB(testProgram, false, pdbXmlDir.getAbsolutePath());
|
||||
File pdb = PdbParser.findPDB(testProgram, false, pdbXmlDir.getAbsolutePath());
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
}
|
||||
catch (PdbException pdbe) {
|
||||
fail("Unexpected PdbException!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -857,17 +821,12 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
@Test
|
||||
public void testFindPdb21() throws Exception {
|
||||
|
||||
try {
|
||||
createdFiles = createFiles(PdbLocation.SAME_AS_EXE_NO_SUBDIR, PdbXmlLocation.OWN_DIR);
|
||||
createdFiles = createFiles(PdbLocation.SAME_AS_EXE_NO_SUBDIR, PdbXmlLocation.OWN_DIR);
|
||||
|
||||
File pdb = PdbParser.findPDB(testProgram, false, defaultSymbolsRepoPath);
|
||||
File pdb = PdbParser.findPDB(testProgram, false, defaultSymbolsRepoPath);
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
}
|
||||
catch (PdbException pdbe) {
|
||||
fail("Unexpected PdbException!");
|
||||
}
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -883,18 +842,12 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
@Test
|
||||
public void testFindPdb22() throws Exception {
|
||||
|
||||
try {
|
||||
createdFiles = createFiles(PdbLocation.SAME_AS_EXE_NO_SUBDIR, PdbXmlLocation.OWN_DIR);
|
||||
createdFiles = createFiles(PdbLocation.SAME_AS_EXE_NO_SUBDIR, PdbXmlLocation.OWN_DIR);
|
||||
|
||||
File pdb =
|
||||
PdbParser.findPDB(testProgram, false, pdbFile.getParentFile().getAbsolutePath());
|
||||
File pdb = PdbParser.findPDB(testProgram, false, pdbFile.getParentFile().getAbsolutePath());
|
||||
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
}
|
||||
catch (PdbException pdbe) {
|
||||
fail("Unexpected PdbException!");
|
||||
}
|
||||
assertNotNull(pdb);
|
||||
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+4
-7
@@ -15,15 +15,12 @@
|
||||
*/
|
||||
package ghidra.app.util.bin.format.pdb2.pdbreader;
|
||||
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.AbstractPdb;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.DatabaseInterface;
|
||||
|
||||
/**
|
||||
* This class is an extension of {@link DatabaseInterface}, whose sole purpose
|
||||
* This class is an extension of {@link PdbOldDebugInfo}, whose sole purpose
|
||||
* is to allow for testing of internal components of {@link AbstractPdb} classes. It is not
|
||||
* part of the production PDB Reader.
|
||||
*/
|
||||
class DummyDatabaseInterface extends DatabaseInterface {
|
||||
class DummyDebugInfo extends PdbOldDebugInfo {
|
||||
|
||||
//==============================================================================================
|
||||
// Package-Protected Internals
|
||||
@@ -31,9 +28,9 @@ class DummyDatabaseInterface extends DatabaseInterface {
|
||||
/**
|
||||
* IMPORTANT: This method is for testing only. It allows us to set a basic object.
|
||||
* Note: not all values are initialized.
|
||||
* @param pdb The AbstractPdb foundation for the DatabaseInterface.
|
||||
* @param pdb The AbstractPdb foundation for the {@link PdbOldDebugInfo}.
|
||||
*/
|
||||
DummyDatabaseInterface(AbstractPdb pdb) {
|
||||
DummyDebugInfo(AbstractPdb pdb) {
|
||||
super(pdb, 0);
|
||||
}
|
||||
|
||||
|
||||
+4
-7
@@ -15,15 +15,12 @@
|
||||
*/
|
||||
package ghidra.app.util.bin.format.pdb2.pdbreader;
|
||||
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.AbstractPdb;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.DatabaseInterfaceNew;
|
||||
|
||||
/**
|
||||
* This class is an extension of {@link DatabaseInterfaceNew}, whose sole purpose
|
||||
* This class is an extension of {@link PdbNewDebugInfo}, whose sole purpose
|
||||
* is to allow for testing of internal components of {@link AbstractPdb} classes. It is not
|
||||
* part of the production PDB Reader.
|
||||
*/
|
||||
class DummyDatabaseInterfaceNew extends DatabaseInterfaceNew {
|
||||
class DummyDebugInfoNew extends PdbNewDebugInfo {
|
||||
|
||||
//==============================================================================================
|
||||
// Package-Protected Internals
|
||||
@@ -31,9 +28,9 @@ class DummyDatabaseInterfaceNew extends DatabaseInterfaceNew {
|
||||
/**
|
||||
* IMPORTANT: This method is for testing only. It allows us to set a basic object.
|
||||
* Note: not all values are initialized.
|
||||
* @param pdb The AbstractPdb foundation for the DatabaseInterface.
|
||||
* @param pdb The AbstractPdb foundation for the {@link PdbNewDebugInfo}.
|
||||
*/
|
||||
DummyDatabaseInterfaceNew(AbstractPdb pdb) {
|
||||
DummyDebugInfoNew(AbstractPdb pdb) {
|
||||
super(pdb, -1);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ public class DummyPdb700 extends Pdb700 {
|
||||
super(null, new PdbReaderOptions());
|
||||
typeProgramInterface =
|
||||
new DummyTypeProgramInterface800(this, tpiIndexMin, tpiIndexMaxExclusive);
|
||||
databaseInterface = new DummyDatabaseInterfaceNew(this);
|
||||
debugInfo = new DummyDebugInfoNew(this);
|
||||
hasIdStream = true;
|
||||
itemProgramInterface =
|
||||
new DummyTypeProgramInterface800(this, ipiIndexMin, ipiIndexMaxExclusive);
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ public class DummyTypeProgramInterface800 extends TypeProgramInterface800 {
|
||||
/**
|
||||
* IMPORTANT: This method is for testing only. It allows us to set a basic object.
|
||||
* Note: not all values are initialized.
|
||||
* @param pdb The AbstractPdb foundation for the DatabaseInterface.
|
||||
* @param pdb The AbstractPdb foundation for the {@link TypeProgramInterface800}.
|
||||
* @param typeIndexMin int. The IndexMin to set/use.
|
||||
* @param typeIndexMaxExclusive int. One greater than the MaxIndex to set/use
|
||||
*/
|
||||
|
||||
@@ -165,10 +165,9 @@ public class MessageLog {
|
||||
private String toStringWithWarning() {
|
||||
StringBuilder output = new StringBuilder();
|
||||
if (count > maxSize) {
|
||||
output.append('\n').append('\n');
|
||||
output.append("There were too many messages to display.\n");
|
||||
output.append((count - maxSize)).append(" messages have been truncated.");
|
||||
output.append('\n').append('\n');
|
||||
output.append((count - maxSize)).append(" messages have been truncated.\n");
|
||||
output.append('\n');
|
||||
}
|
||||
|
||||
for (String s : messages) {
|
||||
|
||||
Reference in New Issue
Block a user