Merge remote-tracking branch 'origin/GP-984_dev747368_simplify_loadpdb_gui--SQUASHED' into Ghidra_10.0
@ -16,13 +16,14 @@ src/main/help/help/shared/redo.png||GHIDRA||||END|
|
||||
src/main/help/help/shared/tip.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
|
||||
src/main/help/help/shared/undo.png||GHIDRA||||END|
|
||||
src/main/help/help/shared/warning.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
|
||||
src/main/help/help/topics/Pdb/LoadPDBNew.html||GHIDRA||||END|
|
||||
src/main/help/help/topics/Pdb/LoadPDB.html||GHIDRA||||END|
|
||||
src/main/help/help/topics/Pdb/PDB.htm||GHIDRA||||END|
|
||||
src/main/help/help/topics/Pdb/images/LoadPdb_Advanced_NeedsConfig.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Pdb/images/LoadPdb_Advanced_Screenshot.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Pdb/images/LoadPdb_Initial_Screenshot.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Pdb/images/Plus2.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Pdb/images/SymbolServerConfig_AddButtonMenu.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Pdb/images/SymbolServerConfig_Configured.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Pdb/images/SymbolServerConfig_Screenshot.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Pdb/images/disk.png||FAMFAMFAM Icons - CC 2.5||||END|
|
||||
src/main/help/help/topics/Pdb/images/down.png||GHIDRA||||END|
|
||||
|
@ -51,7 +51,7 @@
|
||||
<tocroot>
|
||||
<tocref id="Program Annotation">
|
||||
<tocdef id="PDB" sortgroup="q" text="PDB" target="help/topics/Pdb/PDB.htm" >
|
||||
<tocdef id="LoadPDBNew" sortgroup="a" text="Load PDB File" target="help/topics/Pdb/LoadPDBNew.html" />
|
||||
<tocdef id="LoadPDB" sortgroup="a" text="Load PDB File" target="help/topics/Pdb/LoadPDB.html" />
|
||||
<tocdef id="README_PDB" sortgroup="b" text="PDB Parser (README_PDB)" target="docs/README_PDB.html" />
|
||||
</tocdef>
|
||||
</tocref>
|
||||
|
@ -33,7 +33,7 @@
|
||||
<LI><CODE><FONT COLOR="BLUE">myprogram.pdb</FONT>/<FONT COLOR="RED">012345670123012301230123456789AB</FONT><FONT COLOR="GREEN">1</FONT>/<FONT COLOR="BLUE">myprogram.pdb</FONT></CODE>.</LI>
|
||||
<LI><CODE><FONT COLOR="BLUE">myprogram.pdb</FONT></CODE> is the name of the file and the name of the initial subdirectory off the root of the server.</LI>
|
||||
<LI><CODE><FONT COLOR="RED">012345670123012301230123456789AB</FONT></CODE> is the 32 character hexadecimal value (made up for this example) of the GUID
|
||||
"012345678-0123-0123-0123-0123456789AB" of the PDB file.</LI>
|
||||
"01234567-0123-0123-0123-0123456789AB" of the PDB file.</LI>
|
||||
<UL><LI>This value might instead be a 8 character hexadecimal value of the ID of the symbol file if it was created by an older version of the tool chain.</LI></UL>
|
||||
<LI><CODE><FONT COLOR="GREEN">1</FONT></CODE> is the hexadecimal value of the 'age' (build number) of the PDB file. Note: most PDB files will have an age value of 1.</LI>
|
||||
</UL>
|
||||
@ -56,14 +56,8 @@
|
||||
</UL>
|
||||
<LI><A name="Unorganized_SymbolDirectory"></A>Unorganized directories:</LI>
|
||||
<UL>
|
||||
<LI>Symbol files are are found by matching the leading part of the filename found in the unorganized directory with the sought-after symbol
|
||||
file's name.</LI>
|
||||
<UL>
|
||||
<LI><CODE>helloworld.pdb</CODE> and <CODE>hellokitty.pdb</CODE> would both be found as possible matches when searching for
|
||||
<CODE>hello.pdb</CODE>.</LI>
|
||||
<LI>During searches, each possible matching PDB symbol file will be opened and partially parsed to extract its GUID and age values to determine if
|
||||
it matches the user's full search criteria.</LI>
|
||||
</UL>
|
||||
<LI>Symbol files are matched by their filename and the GUID / ID / age values extracted from
|
||||
the information inside the PDB symbol file.</LI>
|
||||
</UL>
|
||||
</UL>
|
||||
</BLOCKQUOTE>
|
||||
@ -88,16 +82,10 @@
|
||||
which PDB file to choose.</LI>
|
||||
<LI>If needed, click the <B>Advanced</B> button:
|
||||
<BLOCKQUOTE><IMG border="0" src="images/LoadPdb_Advanced_NeedsConfig.png"></BLOCKQUOTE></LI>
|
||||
<LI>The <b>Local Symbol Storage</b> location is required to enable searching. If missing, set it to a directory where Ghidra can store PDB files.</LI>
|
||||
<UL>
|
||||
<LI>For example, <CODE>/home/your_id/Symbols</CODE> or <CODE>C:\Users\your_name\Symbols</CODE>.</LI>
|
||||
<LI>If the location is a new empty directory, the user will be prompted to initialize the directory as a Microsoft symbol storage directory.</LI>
|
||||
</UL>
|
||||
<LI><A href="#SymbolServerConfig_Add">Add</A> additional search locations by clicking the <img border="0" src="images/Plus2.png"> button.
|
||||
The Microsoft symbol server and <b>Program's Import Location</b> are good defaults.</LI>
|
||||
<LI>Save any changes to the configuration by clicking the <img border="0" src="images/disk.png"> button.</LI>
|
||||
<LI>The <b>Local Symbol Storage</b> location (in the <A href="#Symbol_Server_Config">Symbol Server Config</A> screen) is required
|
||||
to enable searching. If missing, click the <B>Config...</B> button.</LI>
|
||||
<LI>Set <A href="#PDB_Search_Search_Options">search options</A> as needed.</LI>
|
||||
<LI>Click the <b>Search</b> button to search the configured locations.</LI>
|
||||
<LI>Click the <b>Search Local</b> or <b>Search All</b> button to search the configured locations.</LI>
|
||||
<BLOCKQUOTE><IMG border="0" src="images/LoadPdb_Advanced_Screenshot.png"></BLOCKQUOTE></LI>
|
||||
<LI>The <b>Local Symbol Storage</b> location is searched first, followed by any locations listed in the
|
||||
<b>Additional Search Paths</b> list, in listed order.</LI>
|
||||
@ -111,7 +99,7 @@
|
||||
<H3><A name="Symbol_Server_Config"></A>Symbol Server Config</H3>
|
||||
<BLOCKQUOTE>
|
||||
<P>Allows the user to configure the location where PDB symbol files are stored and additional locations to search for
|
||||
existing PDB files. This is also available in the <b>Load PDB File</b>, <b>Advanced</b> screen.</P>
|
||||
existing PDB files.</P>
|
||||
<H4>Steps:</H4>
|
||||
<UL>
|
||||
<LI>Invoke <b>Edit → Symbol Server Config</b>
|
||||
@ -125,6 +113,7 @@
|
||||
<LI><a href="#SymbolServerConfig_Add">Add</a> additional search locations by clicking the <img border="0" src="images/Plus2.png"> button.</LI>
|
||||
<LI>Save any changes to the configuration by clicking the <img border="0" src="images/disk.png"> button.</LI>
|
||||
<LI>Search locations can be disabled by toggling the <b>enabled</b> checkbox at the beginning of the row.</LI>
|
||||
<LI>A typical configuration: <BLOCKQUOTE><IMG border="0" src="images/SymbolServerConfig_Configured.png"></BLOCKQUOTE></LI>
|
||||
</UL>
|
||||
|
||||
<H4><A name="SymbolServerConfig_Add"></A><img border="0" src="images/Plus2.png"> (Add)</H4>
|
@ -37,7 +37,7 @@
|
||||
<BLOCKQUOTE>
|
||||
<P>PDB files can be loaded in two ways:</P>
|
||||
<UL>
|
||||
<LI><B>File → <a href="LoadPDBNew.html#Load_PDB_File">Load PDB File</a></B></LI>
|
||||
<LI><B>File → <a href="LoadPDB.html#Load_PDB_File">Load PDB File</a></B></LI>
|
||||
<LI>PDB Analyzer via <B>Analysis →
|
||||
<A HREF="help/topics/AutoAnalysisPlugin/AutoAnalysis.htm#Auto_Analyze">Auto Analyze</A></B> or
|
||||
<B>Analysis → <A HREF="help/topics/AutoAnalysisPlugin/AutoAnalysis.htm#Analyze_One_Shot">One Shot</A></B>.
|
||||
@ -124,7 +124,7 @@
|
||||
<P class="relatedtopic">Related Topics:</P>
|
||||
|
||||
<UL>
|
||||
<LI><A href="LoadPDBNew.html">Load PDB File</A></LI>
|
||||
<LI><A href="LoadPDB.html">Load PDB File</A></LI>
|
||||
<LI><A href="help/topics/AutoAnalysisPlugin/AutoAnalysis.htm">Auto Analysis</A></LI>
|
||||
</UL>
|
||||
|
||||
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 20 KiB |
@ -204,26 +204,22 @@ public class LocalSymbolStore extends AbstractSymbolServer implements SymbolStor
|
||||
|
||||
List<SymbolFileLocation> matches = new ArrayList<>();
|
||||
|
||||
// search for exact matches using the built-in logic in AbstractSymbolServer
|
||||
if (storageLevel != 0) {
|
||||
// search for exact matches using the built-in logic in AbstractSymbolServer
|
||||
matches.addAll(super.find(symbolFileInfo, options, monitor));
|
||||
}
|
||||
|
||||
if (storageLevel == 0 || options.contains(FindOption.ANY_AGE) ||
|
||||
options.contains(FindOption.ANY_ID)) {
|
||||
|
||||
try {
|
||||
if (storageLevel == 0) {
|
||||
searchLevel0(rootDir, this, symbolFileInfo, options, matches, monitor);
|
||||
}
|
||||
else {
|
||||
if (options.contains(FindOption.ANY_AGE) || options.contains(FindOption.ANY_ID)) {
|
||||
try {
|
||||
searchLevelN(symbolFileInfo, options, matches, monitor);
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
Msg.warn(this,
|
||||
"Error searching for " + symbolFileInfo.getName() + " in " + rootDir, ioe);
|
||||
}
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
Msg.warn(this, "Error searching for " + symbolFileInfo.getName() + " in " + rootDir,
|
||||
ioe);
|
||||
}
|
||||
}
|
||||
else {
|
||||
searchLevel0(rootDir, this, symbolFileInfo, options, matches, monitor);
|
||||
}
|
||||
|
||||
return matches;
|
||||
@ -232,18 +228,14 @@ public class LocalSymbolStore extends AbstractSymbolServer implements SymbolStor
|
||||
static void searchLevel0(File rootDir, SymbolStore symbolStore, SymbolFileInfo symbolFileInfo,
|
||||
Set<FindOption> options, List<SymbolFileLocation> matches, TaskMonitor monitor) {
|
||||
|
||||
// if its a "0 level" bag-of-files, we have to open each Pdb to find its UID and
|
||||
// AGE (after filtering for similar filenames as requested pdb file)
|
||||
for (File f : list(rootDir,
|
||||
ff -> ff.isFile() && isFilenameStartsWithMatch(symbolFileInfo, ff))) {
|
||||
if (monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
SymbolFileInfo fileInfo = SymbolFileInfo.fromFile(f, monitor);
|
||||
if (fileInfo != null) {
|
||||
if (hasSymbolFileInfoMatch(symbolFileInfo, fileInfo, options)) {
|
||||
matches.add(new SymbolFileLocation(f.getName(), symbolStore, fileInfo));
|
||||
}
|
||||
File f = new File(rootDir, symbolFileInfo.getName());
|
||||
if (!f.isFile()) {
|
||||
return;
|
||||
}
|
||||
SymbolFileInfo fileInfo = SymbolFileInfo.fromFile(f, monitor);
|
||||
if (fileInfo != null) {
|
||||
if (hasSymbolFileInfoMatch(symbolFileInfo, fileInfo, options)) {
|
||||
matches.add(new SymbolFileLocation(f.getName(), symbolStore, fileInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -402,24 +394,6 @@ public class LocalSymbolStore extends AbstractSymbolServer implements SymbolStor
|
||||
return files != null ? files : new File[] {};
|
||||
}
|
||||
|
||||
static boolean isFilenameStartsWithMatch(SymbolFileInfo symbolFileInfo, File file) {
|
||||
String symbolFilenameNoExtension = FilenameUtils.getBaseName(symbolFileInfo.getName());
|
||||
String fileNoExtension = FilenameUtils.getBaseName(file.getName());
|
||||
|
||||
// use case-insensitive compare since these are PDB files, which
|
||||
// come from a Windows env
|
||||
if (!fileNoExtension.toLowerCase().startsWith(symbolFilenameNoExtension.toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// match on ext ("pdb"), compressed ext ("pd_")
|
||||
String symbolFilenameExtension =
|
||||
FilenameUtils.getExtension(symbolFileInfo.getName()).toLowerCase();
|
||||
String fileExtension = FilenameUtils.getExtension(file.getName()).toLowerCase();
|
||||
return fileExtension.equals(symbolFilenameExtension) ||
|
||||
fileExtension.equals(makeCompressedExtension(symbolFilenameExtension));
|
||||
}
|
||||
|
||||
static boolean hasSymbolFileInfoMatch(SymbolFileInfo symbolFileInfo,
|
||||
SymbolFileInfo otherSymbolFileInfo, Set<FindOption> options) {
|
||||
boolean idMatches =
|
||||
|
@ -15,9 +15,8 @@
|
||||
*/
|
||||
package pdb.symbolserver;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
@ -25,8 +24,6 @@ import ghidra.util.task.TaskMonitor;
|
||||
* A Pdb symbol server / symbol store, similar to the {@link LocalSymbolStore},
|
||||
* but limited to searching just the single directory that the original executable is located in.
|
||||
* <p>
|
||||
* Matches symbol files that have a similar name to the requested symbol file (but the identifier
|
||||
* info - guid/id & age must still match as per the find options specified).
|
||||
*
|
||||
*/
|
||||
public class SameDirSymbolStore implements SymbolStore {
|
||||
@ -105,8 +102,8 @@ public class SameDirSymbolStore implements SymbolStore {
|
||||
|
||||
@Override
|
||||
public String getDescriptiveName() {
|
||||
return String.format(PROGRAMS_IMPORT_LOCATION_DESCRIPTION_STR + " - %s",
|
||||
isValid() ? rootDir.getPath() : "unspecified");
|
||||
return PROGRAMS_IMPORT_LOCATION_DESCRIPTION_STR +
|
||||
(isValid() ? " - " + rootDir.getPath() : "");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -15,23 +15,25 @@
|
||||
*/
|
||||
package pdb.symbolserver.ui;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import docking.DialogComponentProvider;
|
||||
import docking.DockingWindowManager;
|
||||
import docking.widgets.OptionDialog;
|
||||
import pdb.symbolserver.SymbolServerInstanceCreatorRegistry;
|
||||
import pdb.symbolserver.SymbolServerService;
|
||||
import pdb.symbolserver.*;
|
||||
|
||||
/**
|
||||
* Dialog that allows the user to configure the Pdb search locations and symbol directory
|
||||
*/
|
||||
public class ConfigPdbDialog extends DialogComponentProvider {
|
||||
|
||||
public static void showSymbolServerConfig() {
|
||||
public static boolean showSymbolServerConfig() {
|
||||
ConfigPdbDialog choosePdbDialog = new ConfigPdbDialog();
|
||||
DockingWindowManager.showDialog(choosePdbDialog);
|
||||
return choosePdbDialog.wasSuccess;
|
||||
}
|
||||
|
||||
private SymbolServerPanel symbolServerConfigPanel;
|
||||
private boolean wasSuccess;
|
||||
|
||||
public ConfigPdbDialog() {
|
||||
super("Configure Symbol Server Search", true, false, true, false);
|
||||
@ -46,12 +48,10 @@ public class ConfigPdbDialog extends DialogComponentProvider {
|
||||
|
||||
@Override
|
||||
protected void okCallback() {
|
||||
if (symbolServerConfigPanel.isConfigChanged() &&
|
||||
OptionDialog.showYesNoDialog(getComponent(),
|
||||
"Save Configuration",
|
||||
"Symbol server configuration changed. Save?") == OptionDialog.YES_OPTION) {
|
||||
if (symbolServerConfigPanel.isConfigChanged()) {
|
||||
symbolServerConfigPanel.saveConfig();
|
||||
}
|
||||
wasSuccess = true;
|
||||
close();
|
||||
}
|
||||
|
||||
@ -76,4 +76,23 @@ public class ConfigPdbDialog extends DialogComponentProvider {
|
||||
addCancelButton();
|
||||
setDefaultButton(cancelButton);
|
||||
}
|
||||
|
||||
/**
|
||||
* Screen shot usage only
|
||||
*/
|
||||
public void pushAddLocationButton() {
|
||||
symbolServerConfigPanel.pushAddLocationButton();
|
||||
}
|
||||
|
||||
/**
|
||||
* Screen shot only
|
||||
*
|
||||
* @param fakeDirectoryText fake text to display in the storage directory text field
|
||||
* @param symbolServers list of symbol servers to force set
|
||||
*/
|
||||
public void setSymbolServerService(String fakeDirectoryText,
|
||||
List<SymbolServer> symbolServers) {
|
||||
symbolServerConfigPanel.setSymbolServers(symbolServers);
|
||||
symbolServerConfigPanel.setSymbolStorageDirectoryTextOnly(fakeDirectoryText);
|
||||
}
|
||||
}
|
||||
|
@ -107,10 +107,10 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
||||
private List<Supplier<StatusText>> statusTextSuppliers = new ArrayList<>();
|
||||
private Set<FindOption> lastSearchOptions;
|
||||
private boolean searchCanceled;
|
||||
private boolean hasShownAdvanced;
|
||||
|
||||
private Program program;
|
||||
|
||||
private SymbolServerPanel symbolServerConfigPanel;
|
||||
private SymbolFilePanel symbolFilePanel;
|
||||
|
||||
private JTextField programNameTextField;
|
||||
@ -123,6 +123,7 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
||||
private HintTextField pdbLocationTextField;
|
||||
private GIconLabel exactMatchIconLabel;
|
||||
|
||||
private JButton configButton;
|
||||
private JToggleButton advancedToggleButton;
|
||||
|
||||
private GhidraFileChooser chooser;
|
||||
@ -153,14 +154,17 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
||||
if (programSymbolFileInfo == null) {
|
||||
programSymbolFileInfo = SymbolFileInfo.unknown("missing");
|
||||
}
|
||||
this.symbolServerInstanceCreatorContext =
|
||||
SymbolServerInstanceCreatorRegistry.getInstance().getContext(program);
|
||||
this.symbolServerService =
|
||||
PdbPlugin.getSymbolServerService(symbolServerInstanceCreatorContext);
|
||||
|
||||
updateSymbolServerServiceInstanceFromPreferences();
|
||||
build();
|
||||
}
|
||||
|
||||
private void updateSymbolServerServiceInstanceFromPreferences() {
|
||||
symbolServerInstanceCreatorContext =
|
||||
SymbolServerInstanceCreatorRegistry.getInstance().getContext(program);
|
||||
symbolServerService =
|
||||
PdbPlugin.getSymbolServerService(symbolServerInstanceCreatorContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dialogShown() {
|
||||
pdbPathTextField.setText(programSymbolFileInfo.getPath());
|
||||
@ -169,32 +173,7 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
||||
programNameTextField.setText(program.getName());
|
||||
cancelButton.requestFocusInWindow();
|
||||
|
||||
executeMonitoredRunnable("Search for PDB using built-in locations", true, true, 0,
|
||||
this::doInitialDefaultSearch);
|
||||
}
|
||||
|
||||
private void doInitialDefaultSearch(TaskMonitor monitor) {
|
||||
try {
|
||||
List<SymbolFileLocation> results =
|
||||
symbolServerService.find(programSymbolFileInfo, FindOption.NO_OPTIONS, monitor);
|
||||
if (!results.isEmpty()) {
|
||||
SymbolFileLocation symbolFileLocation =
|
||||
symbolServerService.getLocalSymbolFileLocation(results.get(0), monitor);
|
||||
File symbolFile = getLocalSymbolFile(symbolFileLocation);
|
||||
Swing.runLater(() -> {
|
||||
setSearchResults(results, null);
|
||||
setPdbLocationValue(symbolFileLocation, symbolFile);
|
||||
setSelectedPdbFile(symbolFileLocation);
|
||||
selectRowByLocation(symbolFileLocation);
|
||||
updateStatusText();
|
||||
updateButtonEnablement();
|
||||
updateParserOptionEnablement(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (CancelledException | IOException e) {
|
||||
// ignore
|
||||
}
|
||||
searchForPdbs(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -212,33 +191,9 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
||||
symbolFilePanel.setFindOptions(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* For screenshot use only
|
||||
*
|
||||
* @param pathStr path of symbol storage directory
|
||||
*/
|
||||
public void setSymbolStorageDirectoryTextOnly(String pathStr) {
|
||||
symbolServerConfigPanel.setSymbolStorageDirectoryTextOnly(pathStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* For screenshot use only
|
||||
*
|
||||
* @param symbolServers list of symbol servers
|
||||
*/
|
||||
public void setSymbolServers(List<SymbolServer> symbolServers) {
|
||||
symbolServerConfigPanel.setSymbolServers(symbolServers);
|
||||
}
|
||||
|
||||
/**
|
||||
* For screenshot use only
|
||||
*/
|
||||
public void pushAddLocationBution() {
|
||||
symbolServerConfigPanel.pushAddLocationButton();
|
||||
}
|
||||
|
||||
private void setSelectedPdbFile(SymbolFileLocation symbolFileLocation) {
|
||||
this.selectedSymbolFile = symbolFileLocation;
|
||||
setPdbLocationValue(symbolFileLocation, getLocalSymbolFile(symbolFileLocation));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -247,6 +202,7 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
||||
* Public only for screenshot usage, treat as private otherwise.
|
||||
*
|
||||
* @param results list of {@link SymbolFileLocation}s to add to results
|
||||
* @param findOptions the options used to search
|
||||
*/
|
||||
public void setSearchResults(List<SymbolFileLocation> results, Set<FindOption> findOptions) {
|
||||
lastSearchOptions = findOptions;
|
||||
@ -304,13 +260,11 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
||||
|
||||
private void updateButtonEnablement() {
|
||||
boolean hasLocation = selectedSymbolFile != null;
|
||||
boolean hasGoodService = symbolServerService.isValid();
|
||||
loadPdbButton.setEnabled(hasLocation);
|
||||
}
|
||||
|
||||
private void setSymbolServerService(SymbolServerService symbolServerService) {
|
||||
this.symbolServerService = symbolServerService;
|
||||
symbolFilePanel.setEnablement(symbolServerService != null);
|
||||
updateStatusText();
|
||||
configButton.setIcon(hasGoodService ? null : MATCH_BAD_ICON);
|
||||
configButton.setToolTipText(hasGoodService ? null : "Missing configuration");
|
||||
symbolFilePanel.setEnablement(hasGoodService);
|
||||
}
|
||||
|
||||
private SymbolFileInfo getCurrentSymbolFileInfo() {
|
||||
@ -322,9 +276,6 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
||||
}
|
||||
|
||||
private void searchForPdbs(boolean allowRemote) {
|
||||
if (symbolServerService == null || !symbolServerService.isValid()) {
|
||||
return;
|
||||
}
|
||||
if (pdbAgeTextField.getText().isBlank() ||
|
||||
pdbAgeTextField.getValue() > NumericUtilities.MAX_UNSIGNED_INT32_AS_LONG) {
|
||||
Msg.showWarn(this, null, "Bad PDB Age", "Invalid PDB Age value");
|
||||
@ -347,11 +298,12 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
||||
symbolServerService.find(symbolFileInfo, findOptions, monitor);
|
||||
Swing.runLater(() -> {
|
||||
setSearchResults(results, findOptions);
|
||||
if (results.size() == 1) {
|
||||
if (!results.isEmpty()) {
|
||||
selectRowByLocation(results.get(0));
|
||||
}
|
||||
updateStatusText();
|
||||
updateButtonEnablement();
|
||||
updateParserOptionEnablement(true);
|
||||
});
|
||||
}
|
||||
catch (CancelledException e1) {
|
||||
@ -364,17 +316,15 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
||||
|
||||
private void build() {
|
||||
buildSymbolFilePanel();
|
||||
buildSSConfigPanel();
|
||||
buildPdbLocationPanel();
|
||||
buildProgramPdbPanel();
|
||||
buildParserOptionsPanel();
|
||||
setHelpLocation(new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "Load PDB File"));
|
||||
|
||||
addStatusTextSupplier(() -> lastSearchOptions != null && advancedToggleButton.isSelected()
|
||||
? symbolServerConfigPanel.getSymbolServerWarnings()
|
||||
? SymbolServerPanel.getSymbolServerWarnings(symbolServerService.getSymbolServers())
|
||||
: null);
|
||||
addStatusTextSupplier(this::getSelectedPdbNoticeText);
|
||||
addStatusTextSupplier(this::getConfigChangedWarning);
|
||||
addStatusTextSupplier(this::getAllowRemoteWarning);
|
||||
addStatusTextSupplier(this::getFoundCountInfo);
|
||||
|
||||
@ -386,11 +336,6 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
||||
// later dialogShow() will be called
|
||||
}
|
||||
|
||||
private void buildSSConfigPanel() {
|
||||
symbolServerConfigPanel =
|
||||
new SymbolServerPanel(this::setSymbolServerService, symbolServerInstanceCreatorContext);
|
||||
}
|
||||
|
||||
private void buildSymbolFilePanel() {
|
||||
// panel will be added in layoutAdvanced()
|
||||
symbolFilePanel = new SymbolFilePanel(this::searchForPdbs);
|
||||
@ -398,7 +343,7 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
||||
symbolFilePanel.getTable()
|
||||
.getSelectionModel()
|
||||
.addListSelectionListener(e -> updateSelectedRow());
|
||||
symbolFilePanel.addMouseListener(new GMouseListenerAdapter() {
|
||||
symbolFilePanel.getTable().addMouseListener(new GMouseListenerAdapter() {
|
||||
@Override
|
||||
public void doubleClickTriggered(MouseEvent e) {
|
||||
if (loadPdbButton.isEnabled()) {
|
||||
@ -618,6 +563,17 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
||||
addCancelButton();
|
||||
setDefaultButton(cancelButton);
|
||||
|
||||
configButton = new JButton("Config...");
|
||||
configButton.addActionListener(e -> {
|
||||
if (ConfigPdbDialog.showSymbolServerConfig()) {
|
||||
updateSymbolServerServiceInstanceFromPreferences();
|
||||
updateButtonEnablement();
|
||||
updateStatusText();
|
||||
searchForPdbs(false);
|
||||
}
|
||||
});
|
||||
addButton(configButton);
|
||||
|
||||
advancedToggleButton = new JToggleButton("Advanced >>");
|
||||
advancedToggleButton.addActionListener(e -> toggleAdvancedSearch());
|
||||
buttonPanel.add(advancedToggleButton);
|
||||
@ -625,7 +581,7 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
||||
|
||||
private void prepareSelectedSymbolFileAndClose(TaskMonitor monitor) {
|
||||
try {
|
||||
if (selectedSymbolFile != null && symbolServerService != null) {
|
||||
if (selectedSymbolFile != null) {
|
||||
selectedSymbolFile =
|
||||
symbolServerService.getLocalSymbolFileLocation(selectedSymbolFile, monitor);
|
||||
}
|
||||
@ -640,17 +596,8 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private StatusText getConfigChangedWarning() {
|
||||
return advancedToggleButton.isSelected() && symbolServerConfigPanel.isConfigChanged()
|
||||
? new StatusText(
|
||||
"Symbol Server Search Config Changed. Click \"Save Configuration\" button to save.",
|
||||
MessageType.INFO, false)
|
||||
: null;
|
||||
}
|
||||
|
||||
private StatusText getAllowRemoteWarning() {
|
||||
int remoteSymbolServerCount =
|
||||
symbolServerService != null ? symbolServerService.getRemoteSymbolServerCount() : 0;
|
||||
int remoteSymbolServerCount = symbolServerService.getRemoteSymbolServerCount();
|
||||
return lastSearchOptions != null && advancedToggleButton.isSelected() &&
|
||||
remoteSymbolServerCount != 0 && !lastSearchOptions.contains(FindOption.ALLOW_REMOTE)
|
||||
? new StatusText(
|
||||
@ -681,31 +628,21 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
||||
overridePdbAgeCheckBox.setVisible(isAdvanced);
|
||||
overridePdbPathCheckBox.setVisible(isAdvanced);
|
||||
overridePdbUniqueIdCheckBox.setVisible(isAdvanced);
|
||||
setPdbLocationValue(null, null);
|
||||
|
||||
if (isAdvanced) {
|
||||
if (symbolServerService == null || !symbolServerService.isValid()) {
|
||||
setSelectedPdbFile(null);
|
||||
}
|
||||
layoutAdvanced();
|
||||
}
|
||||
else {
|
||||
if (selectedSymbolFile != null) {
|
||||
File localSymbolFile = getLocalSymbolFile(selectedSymbolFile);
|
||||
if (localSymbolFile != null) {
|
||||
setPdbLocationValue(selectedSymbolFile, localSymbolFile);
|
||||
}
|
||||
}
|
||||
else {
|
||||
setSelectedPdbFile(null);
|
||||
}
|
||||
layoutSimple();
|
||||
}
|
||||
|
||||
updateStatusText();
|
||||
updateButtonEnablement();
|
||||
updateParserOptionEnablement(false);
|
||||
repack();
|
||||
if (isAdvanced && !hasShownAdvanced) {
|
||||
hasShownAdvanced = true;
|
||||
repack();
|
||||
}
|
||||
}
|
||||
|
||||
private void layoutSimple() {
|
||||
@ -720,21 +657,17 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
||||
overrideWorkPanel(panel);
|
||||
}
|
||||
|
||||
private void overrideWorkPanel(JComponent workComp) {
|
||||
private void overrideWorkPanel(JComponent newWorkComp) {
|
||||
if (this.workComp != null && this.workComp.getParent() != null) {
|
||||
this.workComp.getParent().remove(this.workComp);
|
||||
}
|
||||
this.workComp = workComp;
|
||||
addWorkPanel(workComp);
|
||||
this.workComp = newWorkComp;
|
||||
addWorkPanel(newWorkComp);
|
||||
}
|
||||
|
||||
private void layoutAdvanced() {
|
||||
Box topPanel = Box.createHorizontalBox();
|
||||
topPanel.add(programPdbPanel);
|
||||
topPanel.add(symbolServerConfigPanel);
|
||||
|
||||
JPanel mainPanel = new JPanel(new BorderLayout());
|
||||
mainPanel.add(topPanel, BorderLayout.NORTH);
|
||||
mainPanel.add(programPdbPanel, BorderLayout.NORTH);
|
||||
mainPanel.add(symbolFilePanel, BorderLayout.CENTER);
|
||||
mainPanel.add(parserOptionsPanel, BorderLayout.SOUTH);
|
||||
|
||||
|
@ -117,7 +117,7 @@ class SymbolFilePanel extends JPanel {
|
||||
private JPanel buildWelcomePanel() {
|
||||
welcomePanel = new JPanel();
|
||||
welcomePanel.add(new GHtmlLabel(
|
||||
"<html><br><center><font color=red>Local Symbol Storage location must be set first!"));
|
||||
"<html><br><center><font color=red>Configuration must be set first!"));
|
||||
welcomePanel.setPreferredSize(tablePanel.getPreferredSize());
|
||||
|
||||
return welcomePanel;
|
||||
|
@ -52,7 +52,7 @@ import utilities.util.FileUtilities;
|
||||
class SymbolServerPanel extends JPanel {
|
||||
private static final String MS_SYMBOLSERVER_ENVVAR = "_NT_SYMBOL_PATH";
|
||||
|
||||
private List<WellKnownSymbolServerLocation> knownSymbolServers =
|
||||
private static List<WellKnownSymbolServerLocation> knownSymbolServers =
|
||||
WellKnownSymbolServerLocation.loadAll();
|
||||
|
||||
private SymbolStore localSymbolStore;
|
||||
@ -297,23 +297,6 @@ class SymbolServerPanel extends JPanel {
|
||||
updateLayout(hasLocalSymbolStore);
|
||||
}
|
||||
|
||||
StatusText getSymbolServerWarnings() {
|
||||
Map<String, String> warningsByLocation = new HashMap<>();
|
||||
for (WellKnownSymbolServerLocation ssloc : knownSymbolServers) {
|
||||
if (ssloc.getWarning() != null && !ssloc.getWarning().isBlank()) {
|
||||
warningsByLocation.put(ssloc.getLocation(), ssloc.getWarning());
|
||||
}
|
||||
}
|
||||
String warning = tableModel.getDataSource()
|
||||
.stream()
|
||||
.map(row -> warningsByLocation.get(row.getSymbolServer().getName()))
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.collect(Collectors.joining("<br>\n"));
|
||||
|
||||
return !warning.isEmpty() ? new StatusText(warning, MessageType.WARNING, false) : null;
|
||||
}
|
||||
|
||||
private void setSymbolStorageLocation(File symbolStorageDir, boolean allowGUIPrompt) {
|
||||
if (symbolStorageDir == null) {
|
||||
return;
|
||||
@ -601,5 +584,22 @@ class SymbolServerPanel extends JPanel {
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
static StatusText getSymbolServerWarnings(List<SymbolServer> symbolServers) {
|
||||
Map<String, String> warningsByLocation = new HashMap<>();
|
||||
for (WellKnownSymbolServerLocation ssloc : knownSymbolServers) {
|
||||
if (ssloc.getWarning() != null && !ssloc.getWarning().isBlank()) {
|
||||
warningsByLocation.put(ssloc.getLocation(), ssloc.getWarning());
|
||||
}
|
||||
}
|
||||
String warning = symbolServers
|
||||
.stream()
|
||||
.map(symbolServer -> warningsByLocation.get(symbolServer.getName()))
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.collect(Collectors.joining("<br>\n"));
|
||||
|
||||
return !warning.isEmpty() ? new StatusText(warning, MessageType.WARNING, false) : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -69,11 +69,30 @@ public class PdbScreenShots extends GhidraScreenShotGenerator {
|
||||
ConfigPdbDialog configPdbDialog = new ConfigPdbDialog();
|
||||
showDialogWithoutBlocking(tool, configPdbDialog);
|
||||
waitForSwing();
|
||||
captureDialog(ConfigPdbDialog.class);
|
||||
captureDialog(ConfigPdbDialog.class, 410, 280);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPdb_Initial_Screenshot() throws IOException {
|
||||
public void testSymbolServerConfig_Configured() throws IOException {
|
||||
File localSymbolStore1Root = new File(temporaryDir, "symbols");
|
||||
LocalSymbolStore.create(localSymbolStore1Root, 1);
|
||||
LocalSymbolStore localSymbolStore1 = new LocalSymbolStore(localSymbolStore1Root);
|
||||
SameDirSymbolStore sameDirSymbolStore = new SameDirSymbolStore(null);
|
||||
List<SymbolServer> symbolServers = List.of(sameDirSymbolStore,
|
||||
new HttpSymbolServer(URI.create("https://msdl.microsoft.com/download/symbols/")));
|
||||
SymbolServerService symbolServerService =
|
||||
new SymbolServerService(localSymbolStore1, symbolServers);
|
||||
PdbPlugin.saveSymbolServerServiceConfig(symbolServerService);
|
||||
|
||||
ConfigPdbDialog configPdbDialog = new ConfigPdbDialog();
|
||||
configPdbDialog.setSymbolServerService("/home/user/symbols", symbolServers);
|
||||
showDialogWithoutBlocking(tool, configPdbDialog);
|
||||
waitForSwing();
|
||||
captureDialog(ConfigPdbDialog.class, 410, 280);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPdb_Initial_Screenshot() {
|
||||
LoadPdbDialog loadPdbDialog = new LoadPdbDialog(program);
|
||||
showDialogWithoutBlocking(tool, loadPdbDialog);
|
||||
captureDialog(loadPdbDialog);
|
||||
@ -84,32 +103,30 @@ public class PdbScreenShots extends GhidraScreenShotGenerator {
|
||||
public void testSymbolServerConfig_AddButtonMenu() throws IOException {
|
||||
File localSymbolStore1Root = new File(temporaryDir, "symbols");
|
||||
LocalSymbolStore.create(localSymbolStore1Root, 1);
|
||||
LocalSymbolStore localSymbolStore1 =
|
||||
new LocalSymbolStoreWithFakePath(localSymbolStore1Root, "/home/user/symbols");
|
||||
LocalSymbolStore localSymbolStore1 = new LocalSymbolStore(localSymbolStore1Root);
|
||||
SymbolServerService symbolServerService =
|
||||
new SymbolServerService(localSymbolStore1, List.of());
|
||||
PdbPlugin.saveSymbolServerServiceConfig(symbolServerService);
|
||||
|
||||
LoadPdbDialog choosePdbDialog = new LoadPdbDialog(program);
|
||||
showDialogWithoutBlocking(tool, choosePdbDialog);
|
||||
ConfigPdbDialog configPdbDialog = new ConfigPdbDialog();
|
||||
showDialogWithoutBlocking(tool, configPdbDialog);
|
||||
waitForSwing();
|
||||
pressButtonByText(choosePdbDialog, "Advanced >>");
|
||||
runSwing(() -> {
|
||||
choosePdbDialog.pushAddLocationBution();
|
||||
configPdbDialog.pushAddLocationButton();
|
||||
});
|
||||
waitForSwing();
|
||||
captureMenu();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPdb_Advanced_NeedsConfig() throws IOException {
|
||||
public void testLoadPdb_Advanced_NeedsConfig() {
|
||||
PdbPlugin.saveSymbolServerServiceConfig(null);
|
||||
LoadPdbDialog choosePdbDialog = new LoadPdbDialog(program);
|
||||
showDialogWithoutBlocking(tool, choosePdbDialog);
|
||||
waitForSwing();
|
||||
pressButtonByText(choosePdbDialog, "Advanced >>");
|
||||
waitForSwing();
|
||||
captureDialog(LoadPdbDialog.class);
|
||||
captureDialog(LoadPdbDialog.class, 600, 500);
|
||||
pressButtonByText(choosePdbDialog, "Cancel");
|
||||
}
|
||||
|
||||
@ -140,19 +157,15 @@ public class PdbScreenShots extends GhidraScreenShotGenerator {
|
||||
new SymbolFileLocation("HelloWorld.pdb/" + GUID1_STR + "2/HelloWorld.pdb",
|
||||
localSymbolStore1, SymbolFileInfo.fromValues("HelloWorld.pdb", GUID1_STR, 2)),
|
||||
new SymbolFileLocation("HelloWorld.pdb", sameDirSymbolStoreWithFakePath,
|
||||
SymbolFileInfo.fromValues("HelloWorld.pdb", GUID1_STR, 1)),
|
||||
new SymbolFileLocation("HelloWorld_ver2.pdb", sameDirSymbolStoreWithFakePath,
|
||||
SymbolFileInfo.fromValues("HelloWorld.pdb", GUID1_STR, 2)));
|
||||
SymbolFileInfo.fromValues("HelloWorld.pdb", GUID1_STR, 1)));
|
||||
Set<FindOption> findOptions = FindOption.of(FindOption.ALLOW_REMOTE, FindOption.ANY_AGE);
|
||||
runSwing(() -> {
|
||||
loadPdbDialog.setSearchOptions(findOptions);
|
||||
loadPdbDialog.setSymbolServers(symbolServers);
|
||||
loadPdbDialog.setSymbolStorageDirectoryTextOnly("/home/user/symbols");
|
||||
loadPdbDialog.setSearchResults(symbolFileLocations, findOptions);
|
||||
loadPdbDialog.selectRowByLocation(symbolFileLocations.get(0));
|
||||
});
|
||||
waitForSwing();
|
||||
captureDialog(LoadPdbDialog.class);
|
||||
captureDialog(LoadPdbDialog.class, 600, 600);
|
||||
pressButtonByText(loadPdbDialog, "Cancel");
|
||||
}
|
||||
|
||||
|