Corrected issue with Program metadata which included CustomerOption.

Cleanup PDB analyzer related error reporting.
This commit is contained in:
ghidra1 2020-10-08 12:44:41 -04:00
parent 4295690e0b
commit 3cd26120a3
13 changed files with 240 additions and 187 deletions

View file

@ -19,6 +19,7 @@ import java.util.*;
import ghidra.framework.options.*; import ghidra.framework.options.*;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.StringUtilities;
/** /**
* <code>StoredAnalyzerTimes</code> provides a custom option container for * <code>StoredAnalyzerTimes</code> provides a custom option container for
@ -29,6 +30,7 @@ public class StoredAnalyzerTimes implements CustomOption {
public static final String OPTIONS_LIST = Program.PROGRAM_INFO + ".Analysis Times"; public static final String OPTIONS_LIST = Program.PROGRAM_INFO + ".Analysis Times";
public static final String OPTION_NAME = "Times"; public static final String OPTION_NAME = "Times";
// all times maintained in milliseconds
private Map<String, Long> taskTimes = new HashMap<>(); private Map<String, Long> taskTimes = new HashMap<>();
private Long totalTime; private Long totalTime;
private String[] names; private String[] names;
@ -80,7 +82,7 @@ public class StoredAnalyzerTimes implements CustomOption {
/** /**
* Add the specified time corresponding to the specified analysis taskName * Add the specified time corresponding to the specified analysis taskName
* @param taskName analysis task name * @param taskName analysis task name
* @param t time increment * @param t time increment in milliseconds
*/ */
public void addTime(String taskName, long t) { public void addTime(String taskName, long t) {
long cumulativeTime = taskTimes.getOrDefault(taskName, 0L) + t; long cumulativeTime = taskTimes.getOrDefault(taskName, 0L) + t;
@ -92,7 +94,7 @@ public class StoredAnalyzerTimes implements CustomOption {
/** /**
* Get the accumulated time for the specified analysis taskName * Get the accumulated time for the specified analysis taskName
* @param taskName analysis task name * @param taskName analysis task name
* @return accumulated task time or null if entry not found * @return accumulated task time in milliseconds or null if entry not found
*/ */
public Long getTime(String taskName) { public Long getTime(String taskName) {
return taskTimes.get(taskName); return taskTimes.get(taskName);
@ -100,7 +102,8 @@ public class StoredAnalyzerTimes implements CustomOption {
/** /**
* Get the total accumulated task time for all task entries * Get the total accumulated task time for all task entries
* @return total accumuated task time * in milliseconds
* @return total accumuated task time in milliseconds
*/ */
public long getTotalTime() { public long getTotalTime() {
if (totalTime == null) { if (totalTime == null) {
@ -113,6 +116,11 @@ public class StoredAnalyzerTimes implements CustomOption {
return totalTime; return totalTime;
} }
@Override
public String toString() {
return formatTimeMS(getTotalTime()) + " seconds";
}
/** /**
* Get all task names for which time entries exist * Get all task names for which time entries exist
* @return array of task names * @return array of task names
@ -167,4 +175,11 @@ public class StoredAnalyzerTimes implements CustomOption {
options.putObject(StoredAnalyzerTimes.OPTION_NAME, times); options.putObject(StoredAnalyzerTimes.OPTION_NAME, times);
} }
static String formatTimeMS(long timeMS) {
String str = Long.toUnsignedString(timeMS / 1000L);
str += ".";
str += StringUtilities.pad(Long.toUnsignedString(timeMS % 1000L), '0', 3);
return str;
}
} }

View file

@ -22,7 +22,6 @@ import javax.swing.*;
import docking.widgets.label.GDLabel; import docking.widgets.label.GDLabel;
import ghidra.framework.options.CustomOptionsEditor; import ghidra.framework.options.CustomOptionsEditor;
import ghidra.util.StringUtilities;
import ghidra.util.layout.PairLayout; import ghidra.util.layout.PairLayout;
/** /**
@ -102,7 +101,7 @@ public class StoredAnalyzerTimesPropertyEditor extends PropertyEditorSupport
continue; continue;
} }
JTextField valueField = new JTextField(formatTimeMS(timeMS)); JTextField valueField = new JTextField(StoredAnalyzerTimes.formatTimeMS(timeMS));
valueField.setEditable(false); valueField.setEditable(false);
valueField.setHorizontalAlignment(SwingConstants.RIGHT); valueField.setHorizontalAlignment(SwingConstants.RIGHT);
panel.add(valueField); panel.add(valueField);
@ -112,7 +111,8 @@ public class StoredAnalyzerTimesPropertyEditor extends PropertyEditorSupport
label.setFont(label.getFont().deriveFont(Font.BOLD)); label.setFont(label.getFont().deriveFont(Font.BOLD));
panel.add(label); panel.add(label);
JTextField valueField = new JTextField(formatTimeMS(times.getTotalTime())); JTextField valueField =
new JTextField(StoredAnalyzerTimes.formatTimeMS(times.getTotalTime()));
valueField.setEditable(false); valueField.setEditable(false);
valueField.setHorizontalAlignment(SwingConstants.RIGHT); valueField.setHorizontalAlignment(SwingConstants.RIGHT);
valueField.setBorder(BorderFactory.createLineBorder(Color.black, 2)); valueField.setBorder(BorderFactory.createLineBorder(Color.black, 2));
@ -121,11 +121,6 @@ public class StoredAnalyzerTimesPropertyEditor extends PropertyEditorSupport
return panel; return panel;
} }
private String formatTimeMS(long timeMS) {
String str = Long.toUnsignedString(timeMS / 1000L);
str += ".";
str += StringUtilities.pad(Long.toUnsignedString(timeMS % 1000L), '0', 3);
return str;
}
} }

View file

@ -121,7 +121,7 @@ abstract class AbstractPeDebugLoader extends AbstractLibrarySupportLoader {
proplist.setString(PdbParserConstants.PDB_VERSION, Conv.toString(magic)); proplist.setString(PdbParserConstants.PDB_VERSION, Conv.toString(magic));
proplist.setString(PdbParserConstants.PDB_SIGNATURE, Conv.toHexString(sig)); proplist.setString(PdbParserConstants.PDB_SIGNATURE, Conv.toHexString(sig));
proplist.setString(PdbParserConstants.PDB_AGE, Conv.toHexString(age)); proplist.setString(PdbParserConstants.PDB_AGE, Integer.toHexString(age));
proplist.setString(PdbParserConstants.PDB_FILE, name); proplist.setString(PdbParserConstants.PDB_FILE, name);
/* /*
DebugDirectory dd = dcv.getDebugDirectory(); DebugDirectory dd = dcv.getDebugDirectory();
@ -147,7 +147,7 @@ abstract class AbstractPeDebugLoader extends AbstractLibrarySupportLoader {
proplist.setString(PdbParserConstants.PDB_VERSION, Conv.toString(magic)); proplist.setString(PdbParserConstants.PDB_VERSION, Conv.toString(magic));
proplist.setString(PdbParserConstants.PDB_GUID, guid.toString()); proplist.setString(PdbParserConstants.PDB_GUID, guid.toString());
proplist.setString(PdbParserConstants.PDB_AGE, Conv.toHexString(age)); proplist.setString(PdbParserConstants.PDB_AGE, Integer.toHexString(age));
proplist.setString(PdbParserConstants.PDB_FILE, name); proplist.setString(PdbParserConstants.PDB_FILE, name);
/* /*
DebugDirectory dd = dcv.getDebugDirectory(); DebugDirectory dd = dcv.getDebugDirectory();

View file

@ -24,6 +24,7 @@ import ghidra.app.util.bin.format.pdb.*;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.PeLoader; import ghidra.app.util.opinion.PeLoader;
import ghidra.app.util.pdb.PdbLocator; import ghidra.app.util.pdb.PdbLocator;
import ghidra.framework.options.OptionType;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.framework.preferences.Preferences; import ghidra.framework.preferences.Preferences;
import ghidra.program.model.address.AddressSetView; import ghidra.program.model.address.AddressSetView;
@ -48,10 +49,8 @@ public class PdbAnalyzer extends AbstractAnalyzer {
private static final String SYMBOLPATH_OPTION_NAME = "Symbol Repository Path"; private static final String SYMBOLPATH_OPTION_NAME = "Symbol Repository Path";
private static final String SYMBOLPATH_OPTION_DESCRIPTION = private static final String SYMBOLPATH_OPTION_DESCRIPTION =
"Directory path to root of Microsoft Symbol Repository Directory"; "Directory path to root of Microsoft Symbol Repository Directory";
private static final String SYMBOLPATH_OPTION_DEFAULT_VALUE =
PdbLocator.DEFAULT_SYMBOLS_DIR.getAbsolutePath();
private String symbolsRepositoryPath = SYMBOLPATH_OPTION_DEFAULT_VALUE; private File symbolsRepositoryDir = PdbLocator.DEFAULT_SYMBOLS_DIR;
//============================================================================================== //==============================================================================================
// Include the PE-Header-Specified PDB path for searching for appropriate PDB file. // Include the PE-Header-Specified PDB path for searching for appropriate PDB file.
@ -62,6 +61,9 @@ public class PdbAnalyzer extends AbstractAnalyzer {
private boolean includePeSpecifiedPdbPath = false; private boolean includePeSpecifiedPdbPath = false;
// only try once per transaction due to extensive error logging which may get duplicated
private long lastTransactionId = -1;
//============================================================================================== //==============================================================================================
public PdbAnalyzer() { public PdbAnalyzer() {
super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER); super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER);
@ -73,7 +75,24 @@ public class PdbAnalyzer extends AbstractAnalyzer {
@Override @Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) { public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) {
// Only run once per transaction - avoid message duplication
long txId = program.getCurrentTransaction().getID();
if (txId == lastTransactionId) {
return false;
}
lastTransactionId = txId;
// Only run if restricted set corresponds to entire program
if (!set.contains(program.getMemory())) {
return false;
}
if (PdbParser.isAlreadyLoaded(program)) { if (PdbParser.isAlreadyLoaded(program)) {
if (!PdbUniversalAnalyzer.isEnabled(program)) { // yield to other analyzer complaining
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.");
}
return true; return true;
} }
@ -105,7 +124,7 @@ public class PdbAnalyzer extends AbstractAnalyzer {
try { try {
pdb = PdbParser.findPDB(program, includePeSpecifiedPdbPath, symbolsRepositoryPath); pdb = PdbParser.findPDB(program, includePeSpecifiedPdbPath, symbolsRepositoryDir);
if (pdb == null) { if (pdb == null) {
@ -191,18 +210,15 @@ public class PdbAnalyzer extends AbstractAnalyzer {
String pdbStorageLocation = String pdbStorageLocation =
Preferences.getProperty(PdbParser.PDB_STORAGE_PROPERTY, null, true); Preferences.getProperty(PdbParser.PDB_STORAGE_PROPERTY, null, true);
if (pdbStorageLocation != null) { if (pdbStorageLocation != null) {
File pdbDirectory = new File(pdbStorageLocation); File pdbDirectory = new File(pdbStorageLocation);
if (pdbDirectory.isDirectory()) { if (pdbDirectory.isDirectory()) {
options.registerOption(SYMBOLPATH_OPTION_NAME, pdbStorageLocation, null, symbolsRepositoryDir = pdbDirectory;
SYMBOLPATH_OPTION_DESCRIPTION);
} }
} }
else { options.registerOption(SYMBOLPATH_OPTION_NAME, OptionType.FILE_TYPE, symbolsRepositoryDir,
options.registerOption(SYMBOLPATH_OPTION_NAME, SYMBOLPATH_OPTION_DEFAULT_VALUE, null, null, SYMBOLPATH_OPTION_DESCRIPTION);
SYMBOLPATH_OPTION_DESCRIPTION);
}
options.registerOption(OPTION_NAME_INCLUDE_PE_PDB_PATH, includePeSpecifiedPdbPath, null, options.registerOption(OPTION_NAME_INCLUDE_PE_PDB_PATH, includePeSpecifiedPdbPath, null,
OPTION_DESCRIPTION_INCLUDE_PE_PDB_PATH); OPTION_DESCRIPTION_INCLUDE_PE_PDB_PATH);
@ -210,19 +226,16 @@ public class PdbAnalyzer extends AbstractAnalyzer {
@Override @Override
public void optionsChanged(Options options, Program program) { public void optionsChanged(Options options, Program program) {
String symbolPath =
options.getString(SYMBOLPATH_OPTION_NAME, SYMBOLPATH_OPTION_DEFAULT_VALUE); symbolsRepositoryDir =
setSymbolsRepositoryPath(symbolPath); options.getFile(SYMBOLPATH_OPTION_NAME, PdbLocator.DEFAULT_SYMBOLS_DIR);
Preferences.setProperty(PdbParser.PDB_STORAGE_PROPERTY, symbolPath); Preferences.setProperty(PdbParser.PDB_STORAGE_PROPERTY,
symbolsRepositoryDir != null ? symbolsRepositoryDir.getAbsolutePath() : null);
Preferences.store(); Preferences.store();
includePeSpecifiedPdbPath = includePeSpecifiedPdbPath =
options.getBoolean(OPTION_NAME_INCLUDE_PE_PDB_PATH, includePeSpecifiedPdbPath); options.getBoolean(OPTION_NAME_INCLUDE_PE_PDB_PATH, includePeSpecifiedPdbPath);
} }
public void setSymbolsRepositoryPath(String symbolPath) {
symbolsRepositoryPath = symbolPath;
}
} }

View file

@ -199,6 +199,9 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
private PdbReaderOptions pdbReaderOptions; private PdbReaderOptions pdbReaderOptions;
private PdbApplicatorOptions pdbApplicatorOptions; private PdbApplicatorOptions pdbApplicatorOptions;
// only try once per transaction due to extensive error logging which may get duplicated
private long lastTransactionId = -1;
//============================================================================================== //==============================================================================================
//============================================================================================== //==============================================================================================
public PdbUniversalAnalyzer() { public PdbUniversalAnalyzer() {
@ -221,6 +224,18 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException { throws CancelledException {
// Only run once per transaction - avoid message duplication
long txId = program.getCurrentTransaction().getID();
if (txId == lastTransactionId) {
return false;
}
lastTransactionId = txId;
// Only run if restricted set corresponds to entire program
if (!set.contains(program.getMemory())) {
return false;
}
// NOTE: Legacy PDB Analyzer currently yields to this analyzer if both are enabled // NOTE: Legacy PDB Analyzer currently yields to this analyzer if both are enabled
// if (PdbAnalyzer.isEnabled(program)) { // if (PdbAnalyzer.isEnabled(program)) {
// log.appendMsg(getName(), // log.appendMsg(getName(),
@ -246,9 +261,10 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
Msg.info(this, Msg.info(this,
">> Clear 'PDB Loaded' program property or use Load PDB action if " + ">> Clear 'PDB Loaded' program property or use Load PDB action if " +
"additional PDB processing required."); "additional PDB processing required.");
return true;
} }
if (programAttributes.isPdbLoaded() ||
failMissingFilename(programAttributes, log) || if (failMissingFilename(programAttributes, log) ||
failMissingAttributes(programAttributes, log)) { failMissingAttributes(programAttributes, log)) {
return true; return true;
} }

View file

@ -29,6 +29,7 @@ import ghidra.app.util.NamespaceUtils;
import ghidra.app.util.SymbolPath; import ghidra.app.util.SymbolPath;
import ghidra.app.util.importer.LibrarySearchPathManager; import ghidra.app.util.importer.LibrarySearchPathManager;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.pdb.PdbLocator;
import ghidra.app.util.pdb.PdbProgramAttributes; import ghidra.app.util.pdb.PdbProgramAttributes;
import ghidra.framework.*; import ghidra.framework.*;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
@ -53,7 +54,6 @@ public class PdbParser {
private static final String README_FILENAME = private static final String README_FILENAME =
Application.getInstallationDirectory() + "\\docs\\README_PDB.html"; Application.getInstallationDirectory() + "\\docs\\README_PDB.html";
public final static File SPECIAL_PDB_LOCATION = new File("C:/WINDOWS/Symbols");
public final static String PDB_STORAGE_PROPERTY = "PDB Storage Directory"; public final static String PDB_STORAGE_PROPERTY = "PDB Storage Directory";
static final String STRUCTURE_KIND = "Structure"; static final String STRUCTURE_KIND = "Structure";
@ -1070,12 +1070,12 @@ public class PdbParser {
* *
* @param program program for which to find a matching PDB * @param program program for which to find a matching PDB
* @param includePeSpecifiedPdbPath to also check the PE-header-specified PDB path * @param includePeSpecifiedPdbPath to also check the PE-header-specified PDB path
* @param symbolsRepositoryPath location where downloaded symbols are stored * @param symbolsRepositoryDir location where downloaded symbols are stored
* @return matching PDB for program, or null * @return matching PDB for program, or null
*/ */
public static File findPDB(Program program, boolean includePeSpecifiedPdbPath, public static File findPDB(Program program, boolean includePeSpecifiedPdbPath,
String symbolsRepositoryPath) { File symbolsRepositoryDir) {
return findPDB(getPdbAttributes(program), includePeSpecifiedPdbPath, symbolsRepositoryPath, return findPDB(getPdbAttributes(program), includePeSpecifiedPdbPath, symbolsRepositoryDir,
null); null);
} }
@ -1085,12 +1085,12 @@ public class PdbParser {
* *
* @param pdbAttributes PDB attributes associated with the program * @param pdbAttributes PDB attributes associated with the program
* @param includePeSpecifiedPdbPath to also check the PE-header-specified PDB path * @param includePeSpecifiedPdbPath to also check the PE-header-specified PDB path
* @param symbolsRepositoryPath location of the local symbols repository (can be null) * @param symbolsRepositoryDir location of the local symbols repository (can be null)
* @param fileType type of file to search for (can be null) * @param fileType type of file to search for (can be null)
* @return matching PDB file (or null, if not found) * @return matching PDB file (or null, if not found)
*/ */
public static File findPDB(PdbProgramAttributes pdbAttributes, public static File findPDB(PdbProgramAttributes pdbAttributes,
boolean includePeSpecifiedPdbPath, String symbolsRepositoryPath, PdbFileType fileType) { boolean includePeSpecifiedPdbPath, File symbolsRepositoryDir, PdbFileType fileType) {
// Store potential names of PDB files and potential locations of those files, // Store potential names of PDB files and potential locations of those files,
// so that all possible combinations can be searched. // so that all possible combinations can be searched.
@ -1107,7 +1107,7 @@ public class PdbParser {
guidSubdirPaths.add(File.separator + potentialName + File.separator + guidAgeString); guidSubdirPaths.add(File.separator + potentialName + File.separator + guidAgeString);
} }
return checkPathsForPdb(symbolsRepositoryPath, guidSubdirPaths, potentialPdbNames, fileType, return checkPathsForPdb(symbolsRepositoryDir, guidSubdirPaths, potentialPdbNames, fileType,
pdbAttributes, includePeSpecifiedPdbPath); pdbAttributes, includePeSpecifiedPdbPath);
} }
@ -1128,7 +1128,7 @@ public class PdbParser {
* symbolsRepositoryPath, then look for .pdb.xml file, then .pdb.xml file in other * symbolsRepositoryPath, then look for .pdb.xml file, then .pdb.xml file in other
* directories. * directories.
* *
* @param symbolsRepositoryPath location of the local symbols repository (can be null) * @param symbolsRepositoryDir location of the local symbols repository (can be null)
* @param guidSubdirPaths subdirectory paths (that include the PDB's GUID) that may contain * @param guidSubdirPaths subdirectory paths (that include the PDB's GUID) that may contain
* a matching PDB * a matching PDB
* @param potentialPdbNames all potential filenames for the PDB file(s) that match the program * @param potentialPdbNames all potential filenames for the PDB file(s) that match the program
@ -1136,13 +1136,13 @@ public class PdbParser {
* @param pdbAttributes PDB attributes associated with the program * @param pdbAttributes PDB attributes associated with the program
* @return matching PDB file, if found (else null) * @return matching PDB file, if found (else null)
*/ */
private static File checkPathsForPdb(String symbolsRepositoryPath, Set<String> guidSubdirPaths, private static File checkPathsForPdb(File symbolsRepositoryDir, Set<String> guidSubdirPaths,
List<String> potentialPdbNames, PdbFileType fileType, List<String> potentialPdbNames, PdbFileType fileType,
PdbProgramAttributes pdbAttributes, boolean includePeSpecifiedPdbPath) { PdbProgramAttributes pdbAttributes, boolean includePeSpecifiedPdbPath) {
File foundPdb = null; File foundPdb = null;
Set<File> symbolsRepoPaths = Set<File> symbolsRepoPaths =
getSymbolsRepositoryPaths(symbolsRepositoryPath, guidSubdirPaths); getSymbolsRepositoryPaths(symbolsRepositoryDir, guidSubdirPaths);
Set<File> predefinedPaths = Set<File> predefinedPaths =
getPredefinedPaths(guidSubdirPaths, pdbAttributes, includePeSpecifiedPdbPath); getPredefinedPaths(guidSubdirPaths, pdbAttributes, includePeSpecifiedPdbPath);
boolean fileTypeSpecified = (fileType != null); boolean fileTypeSpecified = (fileType != null);
@ -1169,7 +1169,7 @@ public class PdbParser {
checkForXml = onWindows ? false : true; checkForXml = onWindows ? false : true;
// Start by searching in symbolsRepositoryPath, if available. // Start by searching in symbolsRepositoryPath, if available.
if (symbolsRepositoryPath != null) { if (!symbolsRepoPaths.isEmpty()) {
foundPdb = checkSpecificPathsForPdb(symbolsRepoPaths, potentialPdbNames, checkForXml); foundPdb = checkSpecificPathsForPdb(symbolsRepoPaths, potentialPdbNames, checkForXml);
} }
@ -1195,26 +1195,23 @@ public class PdbParser {
return foundPdb; return foundPdb;
} }
private static Set<File> getSymbolsRepositoryPaths(String symbolsRepositoryPath, private static Set<File> getSymbolsRepositoryPaths(File symbolsRepositoryDir,
Set<String> guidSubdirPaths) { Set<String> guidSubdirPaths) {
Set<File> symbolsRepoPaths = new LinkedHashSet<>(); Set<File> symbolsRepoPaths = new LinkedHashSet<>();
// Collect sub-directories of the symbol repository that exist // Collect sub-directories of the symbol repository that exist
File symRepoFile; if (symbolsRepositoryDir != null && symbolsRepositoryDir.isDirectory()) {
if (symbolsRepositoryPath != null &&
(symRepoFile = new File(symbolsRepositoryPath)).isDirectory()) {
for (String guidSubdir : guidSubdirPaths) { for (String guidSubdir : guidSubdirPaths) {
File testDir = new File(symRepoFile, guidSubdir); File testDir = new File(symbolsRepositoryDir, guidSubdir);
if (testDir.isDirectory()) { if (testDir.isDirectory()) {
symbolsRepoPaths.add(testDir); symbolsRepoPaths.add(testDir);
} }
} }
// Check outer folder last // Check outer folder last
symbolsRepoPaths.add(symRepoFile); symbolsRepoPaths.add(symbolsRepositoryDir);
} }
return symbolsRepoPaths; return symbolsRepoPaths;
@ -1227,7 +1224,8 @@ public class PdbParser {
Set<File> predefinedPaths = new LinkedHashSet<>(); Set<File> predefinedPaths = new LinkedHashSet<>();
getPathsFromAttributes(pdbAttributes, includePeSpecifiedPdbPath, predefinedPaths); getPathsFromAttributes(pdbAttributes, includePeSpecifiedPdbPath, predefinedPaths);
getWindowsPaths(guidSubdirPaths, predefinedPaths); getSymbolPaths(PdbLocator.DEFAULT_SYMBOLS_DIR, guidSubdirPaths, predefinedPaths);
getSymbolPaths(PdbLocator.WINDOWS_SYMBOLS_DIR, guidSubdirPaths, predefinedPaths);
getLibraryPaths(guidSubdirPaths, predefinedPaths); getLibraryPaths(guidSubdirPaths, predefinedPaths);
return predefinedPaths; return predefinedPaths;
@ -1253,19 +1251,21 @@ public class PdbParser {
} }
} }
private static void getWindowsPaths(Set<String> guidSubdirPaths, Set<File> predefinedPaths) { private static void getSymbolPaths(File symbolsDir, Set<String> guidSubdirPaths,
Set<File> predefinedPaths) {
// Don't have to call .exists(), since .isDirectory() does that already // Don't have to call .exists(), since .isDirectory() does that already
if (onWindows && SPECIAL_PDB_LOCATION.isDirectory()) { if (symbolsDir == null || !symbolsDir.isDirectory()) {
predefinedPaths.add(SPECIAL_PDB_LOCATION); return;
}
predefinedPaths.add(symbolsDir);
// Check alternate locations // Check alternate locations
String specialPdbPath = SPECIAL_PDB_LOCATION.getAbsolutePath(); String specialPdbPath = symbolsDir.getAbsolutePath();
for (String guidSubdir : guidSubdirPaths) { for (String guidSubdir : guidSubdirPaths) {
File testDir = new File(specialPdbPath + guidSubdir); File testDir = new File(specialPdbPath + guidSubdir);
if (testDir.isDirectory()) { if (testDir.isDirectory()) {
predefinedPaths.add(testDir); predefinedPaths.add(testDir);
}
} }
} }
} }

View file

@ -76,15 +76,17 @@ public class PdbLocator {
private static final File USER_HOME = new File(System.getProperty("user.home")); private static final File USER_HOME = new File(System.getProperty("user.home"));
public static final File DEFAULT_SYMBOLS_DIR = public static final File DEFAULT_SYMBOLS_DIR =
onWindows ? new File("C:\\Symbols") : new File(USER_HOME, "Symbols"); onWindows ? new File("C:\\Symbols") : new File(USER_HOME, "Symbols");
public final static File WINDOWS_SYMBOLS_DIR =
onWindows ? new File("C:/WINDOWS/Symbols") : null;
private File symbolsRepositoryPath; private File symbolsRepositoryDir;
/** /**
* Only holds identifies in PDBs up until a matching one was found--nothing beyond that. * Only holds identifies in PDBs up until a matching one was found--nothing beyond that.
*/ */
private Map<String, PdbIdentifiers> identifiersByFilePath = new HashMap<>(); private Map<String, PdbIdentifiers> identifiersByFilePath = new HashMap<>();
public PdbLocator(File symbolsRepositoryPath) { public PdbLocator(File symbolsRepositoryDir) {
this.symbolsRepositoryPath = symbolsRepositoryPath; this.symbolsRepositoryDir = symbolsRepositoryDir;
} }
//============================================================================================== //==============================================================================================
@ -219,7 +221,7 @@ public class PdbLocator {
try { try {
List<String> orderedListOfExistingFileNames = findPDB(new PdbProgramAttributes(program), List<String> orderedListOfExistingFileNames = findPDB(new PdbProgramAttributes(program),
includePeSpecifiedPdbPath, symbolsRepositoryPath.getAbsolutePath()); includePeSpecifiedPdbPath, symbolsRepositoryDir);
if (orderedListOfExistingFileNames.isEmpty()) { if (orderedListOfExistingFileNames.isEmpty()) {
String pdbName = program.getOptions(Program.PROGRAM_INFO) String pdbName = program.getOptions(Program.PROGRAM_INFO)
@ -371,7 +373,7 @@ public class PdbLocator {
Integer signature = (attributes.getPdbSignature() == null) ? null Integer signature = (attributes.getPdbSignature() == null) ? null
: Integer.valueOf(attributes.getPdbSignature()); : Integer.valueOf(attributes.getPdbSignature());
return formatPdbIdentifiers(attributes.getPdbFile(), signature, return formatPdbIdentifiers(attributes.getPdbFile(), signature,
Integer.valueOf(attributes.getPdbAge()), attributes.getPdbGuid()); Integer.valueOf(attributes.getPdbAge(), 16), attributes.getPdbGuid());
} }
private StringBuilder formatPdbIdentifiers(String file, PdbIdentifiers identifiers) { private StringBuilder formatPdbIdentifiers(String file, PdbIdentifiers identifiers) {
@ -386,8 +388,8 @@ public class PdbLocator {
if (signature != null) { if (signature != null) {
builder.append(String.format("; Signature: 0X%08X", signature)); builder.append(String.format("; Signature: 0X%08X", signature));
} }
builder.append("; Age: "); builder.append("; Age: 0x");
builder.append(age); builder.append(Integer.toHexString(age));
if (guidString != null) { if (guidString != null) {
builder.append("; GUID: "); builder.append("; GUID: ");
builder.append(guidString); builder.append(guidString);
@ -404,12 +406,12 @@ public class PdbLocator {
* @param pdbAttributes PDB attributes associated with the program. * @param pdbAttributes PDB attributes associated with the program.
* @param includePeSpecifiedPdbPath {@code true} if looking for PDB in PE-Header-Specified * @param includePeSpecifiedPdbPath {@code true} if looking for PDB in PE-Header-Specified
* path location, which may be unsafe security-wise. * path location, which may be unsafe security-wise.
* @param symbolsRepositoryPathIn Location of the local symbols repository (can be null). * @param symbolsRepositoryDir Location of the local symbols repository (can be null).
* @return matching PDB file (or null, if not found). * @return matching PDB file (or null, if not found).
* @throws PdbException if there was a problem with the PDB attributes. * @throws PdbException if there was a problem with the PDB attributes.
*/ */
private List<String> findPDB(PdbProgramAttributes pdbAttributes, private static List<String> findPDB(PdbProgramAttributes pdbAttributes,
boolean includePeSpecifiedPdbPath, String symbolsRepositoryPathIn) throws PdbException { boolean includePeSpecifiedPdbPath, File symbolsRepositoryDir) throws PdbException {
// Store potential names of PDB files and potential locations of those files, // Store potential names of PDB files and potential locations of those files,
// so that all possible combinations can be searched. // so that all possible combinations can be searched.
@ -428,7 +430,7 @@ public class PdbLocator {
guidSubdirPaths.add(File.separator + potentialName + File.separator + guidAgeString); guidSubdirPaths.add(File.separator + potentialName + File.separator + guidAgeString);
} }
return checkPathsForPdb(symbolsRepositoryPathIn, guidSubdirPaths, potentialPdbNames, return checkPathsForPdb(symbolsRepositoryDir, guidSubdirPaths, potentialPdbNames,
pdbAttributes, includePeSpecifiedPdbPath); pdbAttributes, includePeSpecifiedPdbPath);
} }
@ -450,7 +452,7 @@ public class PdbLocator {
* symbolsRepositoryPath, then look for .pdb.xml file, then .pdb.xml file in other * symbolsRepositoryPath, then look for .pdb.xml file, then .pdb.xml file in other
* directories. * directories.
* *
* @param symbolsRepositoryPath location of the local symbols repository (can be null) * @param symbolsRepositoryDir location of the local symbols repository (can be null)
* @param guidSubdirPaths subdirectory paths (that include the PDB's GUID) that may contain * @param guidSubdirPaths subdirectory paths (that include the PDB's GUID) that may contain
* a matching PDB * a matching PDB
* @param potentialPdbNames all potential filenames for the PDB file(s) that match the program * @param potentialPdbNames all potential filenames for the PDB file(s) that match the program
@ -460,19 +462,19 @@ public class PdbLocator {
* enabled unless binary source is trusted and PDB file path is reasonable for this system. * enabled unless binary source is trusted and PDB file path is reasonable for this system.
* @return matching PDB file, if found (else null) * @return matching PDB file, if found (else null)
*/ */
private static List<String> checkPathsForPdb(String symbolsRepositoryPath, private static List<String> checkPathsForPdb(File symbolsRepositoryDir,
Set<String> guidSubdirPaths, List<String> potentialPdbNames, Set<String> guidSubdirPaths, List<String> potentialPdbNames,
PdbProgramAttributes pdbAttributes, boolean includePeSpecifiedPdbPath) { PdbProgramAttributes pdbAttributes, boolean includePeSpecifiedPdbPath) {
Set<File> symbolsRepoPaths = Set<File> symbolsRepoPaths =
getSymbolsRepositoryPaths(symbolsRepositoryPath, guidSubdirPaths); getSymbolsRepositoryPaths(symbolsRepositoryDir, guidSubdirPaths);
Set<File> predefinedPaths = Set<File> predefinedPaths =
getPredefinedPaths(guidSubdirPaths, pdbAttributes, includePeSpecifiedPdbPath); getPredefinedPaths(guidSubdirPaths, pdbAttributes, includePeSpecifiedPdbPath);
// Start by searching in symbolsRepositoryPath, if available. // Start by searching in symbolsRepositoryDir, if available.
List<String> orderedListOfExistingFileNames = new ArrayList<>(); List<String> orderedListOfExistingFileNames = new ArrayList<>();
if (symbolsRepositoryPath != null) { if (!symbolsRepoPaths.isEmpty()) {
orderedListOfExistingFileNames orderedListOfExistingFileNames
.addAll(checkSpecificPathsForPdb(symbolsRepoPaths, potentialPdbNames)); .addAll(checkSpecificPathsForPdb(symbolsRepoPaths, potentialPdbNames));
} }
@ -494,26 +496,23 @@ public class PdbLocator {
} }
//============================================================================================== //==============================================================================================
private static Set<File> getSymbolsRepositoryPaths(String symbolsRepositoryPath, private static Set<File> getSymbolsRepositoryPaths(File symbolsRepositoryDir,
Set<String> guidSubdirPaths) { Set<String> guidSubdirPaths) {
Set<File> symbolsRepoPaths = new LinkedHashSet<>(); Set<File> symbolsRepoPaths = new LinkedHashSet<>();
// Collect sub-directories of the symbol repository that exist // Collect sub-directories of the symbol repository that exist
File symRepoFile; if (symbolsRepositoryDir != null && symbolsRepositoryDir.isDirectory()) {
if (symbolsRepositoryPath != null &&
(symRepoFile = new File(symbolsRepositoryPath)).isDirectory()) {
for (String guidSubdir : guidSubdirPaths) { for (String guidSubdir : guidSubdirPaths) {
File testDir = new File(symRepoFile, guidSubdir); File testDir = new File(symbolsRepositoryDir, guidSubdir);
if (testDir.isDirectory()) { if (testDir.isDirectory()) {
symbolsRepoPaths.add(testDir); symbolsRepoPaths.add(testDir);
} }
} }
// Check outer folder last // Check outer folder last
symbolsRepoPaths.add(symRepoFile); symbolsRepoPaths.add(symbolsRepositoryDir);
} }
return symbolsRepoPaths; return symbolsRepoPaths;
@ -527,7 +526,8 @@ public class PdbLocator {
Set<File> predefinedPaths = new LinkedHashSet<>(); Set<File> predefinedPaths = new LinkedHashSet<>();
getPathsFromAttributes(pdbAttributes, includePeSpecifiedPdbPath, predefinedPaths); getPathsFromAttributes(pdbAttributes, includePeSpecifiedPdbPath, predefinedPaths);
getWindowsPaths(guidSubdirPaths, predefinedPaths); getSymbolPaths(DEFAULT_SYMBOLS_DIR, guidSubdirPaths, predefinedPaths);
getSymbolPaths(WINDOWS_SYMBOLS_DIR, guidSubdirPaths, predefinedPaths);
getLibraryPaths(guidSubdirPaths, predefinedPaths); getLibraryPaths(guidSubdirPaths, predefinedPaths);
return predefinedPaths; return predefinedPaths;
@ -566,20 +566,22 @@ public class PdbLocator {
* <li>C:\MySymbols\symbols\ext * <li>C:\MySymbols\symbols\ext
* <P> * <P>
*/ */
private static void getWindowsPaths(Set<String> guidSubdirPaths, Set<File> predefinedPaths) { private static void getSymbolPaths(File symbolsDir, Set<String> guidSubdirPaths,
Set<File> predefinedPaths) {
// TODO: Need to provide better control of symbol directory preference // TODO: Need to provide better control of symbol directory preference
// instead of only using default // instead of only using default
if (DEFAULT_SYMBOLS_DIR.isDirectory()) { if (symbolsDir == null || !symbolsDir.isDirectory()) {
predefinedPaths.add(DEFAULT_SYMBOLS_DIR); return;
}
predefinedPaths.add(symbolsDir);
// Check alternate locations // Check alternate locations
String specialPdbPath = DEFAULT_SYMBOLS_DIR.getAbsolutePath(); String specialPdbPath = symbolsDir.getAbsolutePath();
for (String guidSubdir : guidSubdirPaths) { for (String guidSubdir : guidSubdirPaths) {
File testDir = new File(specialPdbPath + guidSubdir); File testDir = new File(specialPdbPath + guidSubdir);
if (testDir.isDirectory()) { if (testDir.isDirectory()) {
predefinedPaths.add(testDir); predefinedPaths.add(testDir);
}
} }
} }
} }

View file

@ -28,7 +28,7 @@ import ghidra.program.model.listing.Program;
*/ */
public class PdbProgramAttributes { public class PdbProgramAttributes {
private String pdbAge; private String pdbAge; // hex format
private String pdbGuid; private String pdbGuid;
private String pdbSignature; private String pdbSignature;
@ -78,6 +78,10 @@ public class PdbProgramAttributes {
createGuidAgeString(); createGuidAgeString();
} }
/**
* PDB Age as a hex value
* @return PDB Age as a hex value
*/
public String getPdbAge() { public String getPdbAge() {
return pdbAge; return pdbAge;
} }

View file

@ -217,8 +217,7 @@ public class PdbSymbolServerPlugin extends Plugin {
localDir = askForLocalStorageLocation(); localDir = askForLocalStorageLocation();
// 3. See if PDB can be found locally // 3. See if PDB can be found locally
File pdbFile = PdbParser.findPDB(pdbAttributes, includePePdbPath, File pdbFile = PdbParser.findPDB(pdbAttributes, includePePdbPath, localDir, fileType);
localDir.getAbsolutePath(), fileType);
// 4. If not found locally, ask if it should be retrieved // 4. If not found locally, ask if it should be retrieved
if (pdbFile != null && pdbFile.getName().endsWith(fileType.toString())) { if (pdbFile != null && pdbFile.getName().endsWith(fileType.toString())) {

View file

@ -44,7 +44,7 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
private static String notepadGUID = "36cfd5f9-888c-4483-b522-b9db242d8478"; private static String notepadGUID = "36cfd5f9-888c-4483-b522-b9db242d8478";
// Note: this is in hex. Code should translate it to decimal when creating GUID/Age folder name // Note: this is in hex. Code should translate it to decimal when creating GUID/Age folder name
private static String notepadAge = "00000021"; private static String notepadAge = "21";
// Name of subfolder that stores the actual PDB file // Name of subfolder that stores the actual PDB file
private static String guidAgeCombo = "36CFD5F9888C4483B522B9DB242D847833"; private static String guidAgeCombo = "36CFD5F9888C4483B522B9DB242D847833";
@ -54,8 +54,8 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
private Program testProgram; private Program testProgram;
//private static String guidAgeCombo = PdbParserNEW.getGuidAgeString(notepadGUID, notepadAge); //private static String guidAgeCombo = PdbParserNEW.getGuidAgeString(notepadGUID, notepadAge);
// Default repo path that is hard-coded into the PDB analyzer settings // Bogus symbol repository directory or null directory should not break anything
private static String defaultSymbolsRepoPath = "C:/Symbols"; private static final File noSuchSymbolsRepoDir = null;
private String pdbFilename, pdbXmlFilename; private String pdbFilename, pdbXmlFilename;
private String exeFolderName = "exe", pdbXmlFolderName = "pdb_xml", private String exeFolderName = "exe", pdbXmlFolderName = "pdb_xml",
@ -269,28 +269,24 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
assertNotNull(pdbFile); assertNotNull(pdbFile);
expectedDir1 = new File(fileLocation, pdbFilename); expectedDir1 = new File(fileLocation, pdbFilename);
expectedDir2 = new File(expectedDir1, guidAgeCombo); expectedDir2 = new File(expectedDir1, guidAgeCombo);
assertEquals(expectedDir2.getAbsolutePath(), assertEquals(expectedDir2, pdbFile.getParentFile());
pdbFile.getParentFile().getAbsolutePath());
break; break;
case SAME_AS_EXE_NO_SUBDIR: case SAME_AS_EXE_NO_SUBDIR:
assertNotNull(pdbFile); assertNotNull(pdbFile);
assertEquals(fileLocation.getAbsolutePath(), assertEquals(fileLocation, pdbFile.getParentFile());
pdbFile.getParentFile().getAbsolutePath());
break; break;
case SYMBOLS_SUBDIR: case SYMBOLS_SUBDIR:
assertNotNull(pdbFile); assertNotNull(pdbFile);
expectedDir1 = new File(symbolsFolder, pdbFilename); expectedDir1 = new File(symbolsFolder, pdbFilename);
expectedDir2 = new File(expectedDir1, guidAgeCombo); expectedDir2 = new File(expectedDir1, guidAgeCombo);
assertEquals(expectedDir2.getAbsolutePath(), assertEquals(expectedDir2, pdbFile.getParentFile());
pdbFile.getParentFile().getAbsolutePath());
break; break;
case SYMBOLS_NO_SUBDIR: case SYMBOLS_NO_SUBDIR:
assertNotNull(pdbFile); assertNotNull(pdbFile);
assertEquals(symbolsFolder.getAbsolutePath(), assertEquals(symbolsFolder, pdbFile.getParentFile());
pdbFile.getParentFile().getAbsolutePath());
break; break;
default: default:
@ -300,14 +296,12 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
switch (pdbXmlLoc) { switch (pdbXmlLoc) {
case SAME_AS_PDB: case SAME_AS_PDB:
assertNotNull(pdbXmlFile); assertNotNull(pdbXmlFile);
assertEquals(pdbXmlFile.getParentFile().getAbsolutePath(), assertEquals(pdbXmlFile.getParentFile(), pdbFile.getParentFile());
pdbFile.getParentFile().getAbsolutePath());
break; break;
case OWN_DIR: case OWN_DIR:
assertNotNull(pdbXmlFile); assertNotNull(pdbXmlFile);
assertEquals(pdbXmlFile.getParentFile().getAbsolutePath(), assertEquals(pdbXmlFile.getParentFile(), pdbXmlDir);
pdbXmlDir.getAbsolutePath());
break; break;
case NONE: case NONE:
@ -338,7 +332,7 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
createdFiles = null; createdFiles = null;
createdFiles = createFiles(PdbLocation.SYMBOLS_SUBDIR, PdbXmlLocation.NONE); createdFiles = createFiles(PdbLocation.SYMBOLS_SUBDIR, PdbXmlLocation.NONE);
File pdb = PdbParser.findPDB(testProgram, false, defaultSymbolsRepoPath); File pdb = PdbParser.findPDB(testProgram, false, noSuchSymbolsRepoDir);
// Should not find anything since repo is set to an invalid path // Should not find anything since repo is set to an invalid path
assertNull(pdb); assertNull(pdb);
@ -360,10 +354,10 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
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);
assertNotNull(pdb); assertNotNull(pdb);
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbFile, pdb);
} }
@ -382,15 +376,15 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
createdFiles = createFiles(PdbLocation.SYMBOLS_SUBDIR, PdbXmlLocation.SAME_AS_PDB); createdFiles = createFiles(PdbLocation.SYMBOLS_SUBDIR, PdbXmlLocation.SAME_AS_PDB);
File pdb = PdbParser.findPDB(testProgram, false, symbolsFolder.getAbsolutePath()); File pdb = PdbParser.findPDB(testProgram, false, symbolsFolder);
assertNotNull(pdb); assertNotNull(pdb);
if (PdbParser.onWindows) { if (PdbParser.onWindows) {
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbFile, pdb);
} }
else { else {
assertEquals(pdbXmlFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbXmlFile, pdb);
} }
} }
@ -409,10 +403,10 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
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);
assertNotNull(pdb); assertNotNull(pdb);
assertEquals(pdb.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdb, pdb);
} }
@ -431,15 +425,15 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
createdFiles = createFiles(PdbLocation.SYMBOLS_SUBDIR, PdbXmlLocation.OWN_DIR); createdFiles = createFiles(PdbLocation.SYMBOLS_SUBDIR, PdbXmlLocation.OWN_DIR);
File pdb = PdbParser.findPDB(testProgram, false, pdbXmlDir.getAbsolutePath()); File pdb = PdbParser.findPDB(testProgram, false, pdbXmlDir);
assertNotNull(pdb); assertNotNull(pdb);
if (PdbParser.onWindows) { if (PdbParser.onWindows) {
assertEquals(pdbXmlFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbXmlFile, pdb);
} }
else { else {
assertEquals(pdbXmlFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbXmlFile, pdb);
} }
} }
@ -458,10 +452,10 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
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);
assertNotNull(pdb); assertNotNull(pdb);
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbFile, pdb);
} }
@ -479,7 +473,7 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
createdFiles = createFiles(PdbLocation.SYMBOLS_NO_SUBDIR, PdbXmlLocation.NONE); createdFiles = createFiles(PdbLocation.SYMBOLS_NO_SUBDIR, PdbXmlLocation.NONE);
File pdb = PdbParser.findPDB(testProgram, false, pdbXmlDir.getAbsolutePath()); File pdb = PdbParser.findPDB(testProgram, false, pdbXmlDir);
// Should not find anything since repo is set to an invalid path // Should not find anything since repo is set to an invalid path
assertNull(pdb); assertNull(pdb);
@ -500,15 +494,15 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
createdFiles = createFiles(PdbLocation.SYMBOLS_NO_SUBDIR, PdbXmlLocation.SAME_AS_PDB); createdFiles = createFiles(PdbLocation.SYMBOLS_NO_SUBDIR, PdbXmlLocation.SAME_AS_PDB);
File pdb = PdbParser.findPDB(testProgram, false, symbolsFolder.getAbsolutePath()); File pdb = PdbParser.findPDB(testProgram, false, symbolsFolder);
assertNotNull(pdb); assertNotNull(pdb);
if (PdbParser.onWindows) { if (PdbParser.onWindows) {
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbFile, pdb);
} }
else { else {
assertEquals(pdbXmlFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbXmlFile, pdb);
} }
} }
@ -527,10 +521,10 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
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);
assertNotNull(pdb); assertNotNull(pdb);
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbFile, pdb);
} }
@ -549,15 +543,15 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
createdFiles = createFiles(PdbLocation.SYMBOLS_NO_SUBDIR, PdbXmlLocation.OWN_DIR); createdFiles = createFiles(PdbLocation.SYMBOLS_NO_SUBDIR, PdbXmlLocation.OWN_DIR);
File pdb = PdbParser.findPDB(testProgram, false, pdbXmlDir.getAbsolutePath()); File pdb = PdbParser.findPDB(testProgram, false, pdbXmlDir);
assertNotNull(pdb); assertNotNull(pdb);
if (PdbParser.onWindows) { if (PdbParser.onWindows) {
assertEquals(pdbXmlFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbXmlFile, pdb);
} }
else { else {
assertEquals(pdbXmlFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbXmlFile, pdb);
} }
} }
@ -576,10 +570,10 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
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.getParentFile());
assertNotNull(pdb); assertNotNull(pdb);
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbFile, pdb);
} }
@ -597,7 +591,7 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
createdFiles = createFiles(PdbLocation.SAME_AS_EXE_SUBDIR, PdbXmlLocation.SAME_AS_PDB); createdFiles = createFiles(PdbLocation.SAME_AS_EXE_SUBDIR, PdbXmlLocation.SAME_AS_PDB);
File pdb = PdbParser.findPDB(testProgram, false, defaultSymbolsRepoPath); File pdb = PdbParser.findPDB(testProgram, false, noSuchSymbolsRepoDir);
// Should not find anything since repo is set to an invalid path // Should not find anything since repo is set to an invalid path
assertNull(pdb); assertNull(pdb);
@ -618,15 +612,15 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
createdFiles = createFiles(PdbLocation.SAME_AS_EXE_SUBDIR, PdbXmlLocation.SAME_AS_PDB); createdFiles = createFiles(PdbLocation.SAME_AS_EXE_SUBDIR, PdbXmlLocation.SAME_AS_PDB);
File pdb = PdbParser.findPDB(testProgram, false, pdbFile.getParent()); File pdb = PdbParser.findPDB(testProgram, false, pdbFile.getParentFile());
assertNotNull(pdb); assertNotNull(pdb);
if (PdbParser.onWindows) { if (PdbParser.onWindows) {
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbFile, pdb);
} }
else { else {
assertEquals(pdbXmlFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbXmlFile, pdb);
} }
} }
@ -645,10 +639,10 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
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.getParentFile());
assertNotNull(pdb); assertNotNull(pdb);
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbFile, pdb);
} }
@ -667,15 +661,15 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
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, pdbXmlFile.getParent()); File pdb = PdbParser.findPDB(testProgram, false, pdbXmlFile.getParentFile());
assertNotNull(pdb); assertNotNull(pdb);
if (PdbParser.onWindows) { if (PdbParser.onWindows) {
assertEquals(pdbXmlFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbXmlFile, pdb);
} }
else { else {
assertEquals(pdbXmlFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbXmlFile, pdb);
} }
} }
@ -697,10 +691,10 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
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, noSuchSymbolsRepoDir);
assertNotNull(pdb); assertNotNull(pdb);
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbFile, pdb);
} }
@ -719,10 +713,10 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
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.getParentFile());
assertNotNull(pdb); assertNotNull(pdb);
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbFile, pdb);
} }
@ -744,10 +738,10 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
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);
assertNotNull(pdb); assertNotNull(pdb);
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbFile, pdb);
} }
@ -769,15 +763,15 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
createdFiles = createFiles(PdbLocation.SAME_AS_EXE_NO_SUBDIR, PdbXmlLocation.SAME_AS_PDB); createdFiles = createFiles(PdbLocation.SAME_AS_EXE_NO_SUBDIR, PdbXmlLocation.SAME_AS_PDB);
File pdb = PdbParser.findPDB(testProgram, false, defaultSymbolsRepoPath); File pdb = PdbParser.findPDB(testProgram, false, noSuchSymbolsRepoDir);
assertNotNull(pdb); assertNotNull(pdb);
if (PdbParser.onWindows) { if (PdbParser.onWindows) {
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbFile, pdb);
} }
else { else {
assertEquals(pdbXmlFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbXmlFile, pdb);
} }
} }
@ -796,15 +790,15 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
createdFiles = createFiles(PdbLocation.SAME_AS_EXE_NO_SUBDIR, PdbXmlLocation.SAME_AS_PDB); createdFiles = createFiles(PdbLocation.SAME_AS_EXE_NO_SUBDIR, PdbXmlLocation.SAME_AS_PDB);
File pdb = PdbParser.findPDB(testProgram, false, pdbFile.getParent()); File pdb = PdbParser.findPDB(testProgram, false, pdbFile.getParentFile());
assertNotNull(pdb); assertNotNull(pdb);
if (PdbParser.onWindows) { if (PdbParser.onWindows) {
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbFile, pdb);
} }
else { else {
assertEquals(pdbXmlFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbXmlFile, pdb);
} }
} }
@ -823,10 +817,10 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
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, noSuchSymbolsRepoDir);
assertNotNull(pdb); assertNotNull(pdb);
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbFile, pdb);
} }
/** /**
@ -844,10 +838,10 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
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());
assertNotNull(pdb); assertNotNull(pdb);
assertEquals(pdbFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbFile, pdb);
} }
/** /**
@ -868,15 +862,15 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
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, pdbXmlDir.getAbsolutePath()); File pdb = PdbParser.findPDB(testProgram, false, pdbXmlDir);
assertNotNull(pdb); assertNotNull(pdb);
if (PdbParser.onWindows) { if (PdbParser.onWindows) {
assertEquals(pdbXmlFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbXmlFile, pdb);
} }
else { else {
assertEquals(pdbXmlFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbXmlFile, pdb);
} }
} }
@ -895,7 +889,7 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
createdFiles = createFiles(PdbLocation.NONE, PdbXmlLocation.NONE); createdFiles = createFiles(PdbLocation.NONE, PdbXmlLocation.NONE);
File pdb = PdbParser.findPDB(testProgram, false, defaultSymbolsRepoPath); File pdb = PdbParser.findPDB(testProgram, false, noSuchSymbolsRepoDir);
assertNull(pdb); assertNull(pdb);
} }
@ -915,7 +909,7 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
createdFiles = createFiles(PdbLocation.NONE, PdbXmlLocation.OWN_DIR); createdFiles = createFiles(PdbLocation.NONE, PdbXmlLocation.OWN_DIR);
File pdb = PdbParser.findPDB(testProgram, false, defaultSymbolsRepoPath); File pdb = PdbParser.findPDB(testProgram, false, noSuchSymbolsRepoDir);
assertNull(pdb); assertNull(pdb);
} }
@ -935,22 +929,22 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
createdFiles = createFiles(PdbLocation.NONE, PdbXmlLocation.OWN_DIR); createdFiles = createFiles(PdbLocation.NONE, PdbXmlLocation.OWN_DIR);
File pdb = PdbParser.findPDB(testProgram, false, pdbXmlDir.getAbsolutePath()); File pdb = PdbParser.findPDB(testProgram, false, pdbXmlDir);
assertNotNull(pdb); assertNotNull(pdb);
if (PdbParser.onWindows) { if (PdbParser.onWindows) {
assertEquals(pdbXmlFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbXmlFile, pdb);
} }
else { else {
assertEquals(pdbXmlFile.getAbsolutePath(), pdb.getAbsolutePath()); assertEquals(pdbXmlFile, pdb);
} }
} }
private void createDirectory(File directory) { private void createDirectory(File directory) {
directory.mkdir(); directory.mkdir();
if (!directory.isDirectory()) { if (!directory.isDirectory()) {
fail("Should have created directory: " + directory.getAbsolutePath()); fail("Should have created directory: " + directory);
} }
} }
@ -961,7 +955,7 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
createSuccess = file.createNewFile(); createSuccess = file.createNewFile();
if (!createSuccess) { if (!createSuccess) {
fail("Failed creation of file: " + file.getAbsolutePath()); fail("Failed creation of file: " + file);
} }
} }
catch (IOException ioe) { catch (IOException ioe) {
@ -1002,7 +996,7 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
xmlBuffWriter.close(); xmlBuffWriter.close();
} }
catch (IOException ioe) { catch (IOException ioe) {
fail("IOException writing to temporary file (" + pdbXmlFile.getAbsolutePath() + "). " + fail("IOException writing to temporary file (" + pdbXmlFile + "). " +
ioe.toString()); ioe.toString());
} }
@ -1015,7 +1009,7 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
buildPdbXml(); buildPdbXml();
File pdb = PdbParser.findPDB(testProgram, false, pdbXmlDir.getAbsolutePath()); File pdb = PdbParser.findPDB(testProgram, false, pdbXmlDir);
AutoAnalysisManager mgr = AutoAnalysisManager.getAnalysisManager(testProgram); AutoAnalysisManager mgr = AutoAnalysisManager.getAnalysisManager(testProgram);
DataTypeManagerService dataTypeManagerService = mgr.getDataTypeManagerService(); DataTypeManagerService dataTypeManagerService = mgr.getDataTypeManagerService();

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -32,4 +31,14 @@ public interface CustomOption {
*/ */
public void writeState(SaveState saveState); public void writeState(SaveState saveState);
/**
* CustomOption should implement this method to provide a formatted
* string value of this option value. The returned value will
* be used in support of the {@link Options#getValueAsString(String)}
* and {@link Options#getDefaultValueAsString(String)}.
* @return option value as string
*/
@Override
public String toString();
} }

View file

@ -540,18 +540,18 @@ public class DataTypeArchiveDB extends DomainObjectAdapterDB
Options propList = getOptions(Program.PROGRAM_INFO); Options propList = getOptions(Program.PROGRAM_INFO);
List<String> propNames = propList.getOptionNames(); List<String> propNames = propList.getOptionNames();
Collections.sort(propNames); Collections.sort(propNames);
for (String name : propNames) { for (String propName : propNames) {
metadata.put(name, propList.getValueAsString(name)); if (propName.indexOf(Options.DELIMITER) >= 0) {
continue; // ignore second tier options
}
String valueAsString = propList.getValueAsString(propName);
if (valueAsString != null) {
metadata.put(propName, propList.getValueAsString(propName));
}
} }
return metadata; return metadata;
} }
// private static String getString(Object obj) {
// if (obj != null) {
// return obj.toString();
// }
// return null;
// }
@Override @Override
protected void updateMetadata() throws IOException { protected void updateMetadata() throws IOException {
getMetadata(); // updates metadata map getMetadata(); // updates metadata map

View file

@ -2360,7 +2360,13 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
List<String> propNames = propList.getOptionNames(); List<String> propNames = propList.getOptionNames();
Collections.sort(propNames); Collections.sort(propNames);
for (String propName : propNames) { for (String propName : propNames) {
metadata.put(propName, propList.getValueAsString(propName)); if (propName.indexOf(Options.DELIMITER) >= 0) {
continue; // ignore second tier options
}
String valueAsString = propList.getValueAsString(propName);
if (valueAsString != null) {
metadata.put(propName, propList.getValueAsString(propName));
}
} }
return metadata; return metadata;
} }