mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-02 06:27:31 +08:00
Merge remote-tracking branch 'origin/GP-4735_dev747368_pdb_trusted_symbolserver--SQUASHED'
This commit is contained in:
@@ -19,13 +19,9 @@
|
|||||||
//The ~/symbols directory should already exist and be initialized as a symbol
|
//The ~/symbols directory should already exist and be initialized as a symbol
|
||||||
//storage location.
|
//storage location.
|
||||||
//@category PDB
|
//@category PDB
|
||||||
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.net.URI;
|
|
||||||
|
|
||||||
import ghidra.app.plugin.core.analysis.PdbAnalyzer;
|
|
||||||
import ghidra.app.plugin.core.analysis.PdbUniversalAnalyzer;
|
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import pdb.PdbPlugin;
|
import pdb.PdbPlugin;
|
||||||
import pdb.symbolserver.*;
|
import pdb.symbolserver.*;
|
||||||
@@ -38,16 +34,11 @@ public class PdbSymbolServerExamplePrescript extends GhidraScript {
|
|||||||
File symDir = new File(homeDir, "symbols");
|
File symDir = new File(homeDir, "symbols");
|
||||||
LocalSymbolStore localSymbolStore = new LocalSymbolStore(symDir);
|
LocalSymbolStore localSymbolStore = new LocalSymbolStore(symDir);
|
||||||
HttpSymbolServer msSymbolServer =
|
HttpSymbolServer msSymbolServer =
|
||||||
new HttpSymbolServer(URI.create("https://msdl.microsoft.com/download/symbols/"));
|
HttpSymbolServer.createTrusted("https://msdl.microsoft.com/download/symbols/");
|
||||||
SymbolServerService symbolServerService =
|
SymbolServerService symbolServerService =
|
||||||
new SymbolServerService(localSymbolStore, List.of(msSymbolServer));
|
new SymbolServerService(localSymbolStore, List.of(msSymbolServer));
|
||||||
|
|
||||||
PdbPlugin.saveSymbolServerServiceConfig(symbolServerService);
|
PdbPlugin.saveSymbolServerServiceConfig(symbolServerService);
|
||||||
|
|
||||||
// You only need to enable the "allow remote" option on the specific
|
|
||||||
// analyzer you are using
|
|
||||||
PdbUniversalAnalyzer.setAllowRemoteOption(currentProgram, true);
|
|
||||||
PdbAnalyzer.setAllowRemoteOption(currentProgram, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
|
||||||
import java.nio.file.AccessMode;
|
import java.nio.file.AccessMode;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -44,8 +43,8 @@ public class GetMSDownloadLinkScript extends GhidraScript {
|
|||||||
@Override
|
@Override
|
||||||
protected void run() throws Exception {
|
protected void run() throws Exception {
|
||||||
SymbolServerService symbolService =
|
SymbolServerService symbolService =
|
||||||
new SymbolServerService(new SameDirSymbolStore(null), List.of(
|
new SymbolServerService(new SameDirSymbolStore(null),
|
||||||
new HttpSymbolServer(URI.create(MS_PUBLIC_SYMBOL_SERVER_URL))));
|
List.of(HttpSymbolServer.createTrusted(MS_PUBLIC_SYMBOL_SERVER_URL)));
|
||||||
|
|
||||||
File f = askFile("File To Scan", "Select");
|
File f = askFile("File To Scan", "Select");
|
||||||
if (f == null) {
|
if (f == null) {
|
||||||
@@ -63,9 +62,7 @@ public class GetMSDownloadLinkScript extends GhidraScript {
|
|||||||
", sizeOfImage: " + Integer.toHexString(sizeOfImage));
|
", sizeOfImage: " + Integer.toHexString(sizeOfImage));
|
||||||
SymbolFileInfo symbolFileInfo = SymbolFileInfo.fromValues(f.getName().toLowerCase(),
|
SymbolFileInfo symbolFileInfo = SymbolFileInfo.fromValues(f.getName().toLowerCase(),
|
||||||
Integer.toHexString(timeDateStamp), sizeOfImage);
|
Integer.toHexString(timeDateStamp), sizeOfImage);
|
||||||
List<SymbolFileLocation> findResults =
|
List<SymbolFileLocation> findResults = symbolService.find(symbolFileInfo, monitor);
|
||||||
symbolService.find(symbolFileInfo, FindOption.of(FindOption.ALLOW_REMOTE),
|
|
||||||
monitor);
|
|
||||||
if (findResults.isEmpty()) {
|
if (findResults.isEmpty()) {
|
||||||
println("Not found on " + MS_PUBLIC_SYMBOL_SERVER_URL);
|
println("Not found on " + MS_PUBLIC_SYMBOL_SERVER_URL);
|
||||||
return;
|
return;
|
||||||
|
|||||||
+13
-13
@@ -42,7 +42,7 @@ public class PdbAnalyzer extends AbstractAnalyzer {
|
|||||||
|
|
||||||
private static final String ERROR_TITLE = "Error in PDB Analyzer";
|
private static final String ERROR_TITLE = "Error in PDB Analyzer";
|
||||||
|
|
||||||
private boolean searchRemoteLocations = false;
|
private boolean searchUntrustedLocations = false;
|
||||||
|
|
||||||
// only try once per transaction due to extensive error logging which may get duplicated
|
// only try once per transaction due to extensive error logging which may get duplicated
|
||||||
private long lastTransactionId = -1;
|
private long lastTransactionId = -1;
|
||||||
@@ -85,7 +85,7 @@ public class PdbAnalyzer extends AbstractAnalyzer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
File pdbFile = PdbAnalyzerCommon.findPdb(this, program, searchRemoteLocations, monitor);
|
File pdbFile = PdbAnalyzerCommon.findPdb(this, program, searchUntrustedLocations, monitor);
|
||||||
if (pdbFile == null) {
|
if (pdbFile == null) {
|
||||||
// warnings have already been logged
|
// warnings have already been logged
|
||||||
return false;
|
return false;
|
||||||
@@ -138,15 +138,15 @@ public class PdbAnalyzer extends AbstractAnalyzer {
|
|||||||
@Override
|
@Override
|
||||||
public void registerOptions(Options options, Program program) {
|
public void registerOptions(Options options, Program program) {
|
||||||
|
|
||||||
options.registerOption(PdbAnalyzerCommon.OPTION_NAME_SEARCH_REMOTE_LOCATIONS,
|
options.registerOption(PdbAnalyzerCommon.OPTION_NAME_SEARCH_UNTRUSTED_LOCATIONS,
|
||||||
searchRemoteLocations, null,
|
searchUntrustedLocations, null,
|
||||||
PdbAnalyzerCommon.OPTION_DESCRIPTION_SEARCH_REMOTE_LOCATIONS);
|
PdbAnalyzerCommon.OPTION_DESCRIPTION_SEARCH_UNTRUSTED_LOCATIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void optionsChanged(Options options, Program program) {
|
public void optionsChanged(Options options, Program program) {
|
||||||
searchRemoteLocations = options.getBoolean(
|
searchUntrustedLocations = options.getBoolean(
|
||||||
PdbAnalyzerCommon.OPTION_NAME_SEARCH_REMOTE_LOCATIONS, searchRemoteLocations);
|
PdbAnalyzerCommon.OPTION_NAME_SEARCH_UNTRUSTED_LOCATIONS, searchUntrustedLocations);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -165,18 +165,18 @@ public class PdbAnalyzer extends AbstractAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the "allow remote" option that will be used by the analyzer when it is next invoked
|
* Sets the "allow untrusted" option that will be used by the analyzer when it is next invoked
|
||||||
* on the specified program.
|
* on the specified program.
|
||||||
* <p>
|
* <p>
|
||||||
* Normally when the analyzer attempts to locate a matching PDB file it
|
* Normally when the analyzer attempts to locate a matching PDB file it
|
||||||
* will default to NOT searching remote symbol servers. A headless script could
|
* will default to NOT searching untrusted symbol servers. A headless script could
|
||||||
* use this method to allow the analyzer to search remote symbol servers.
|
* use this method to allow the analyzer to search untrusted symbol servers.
|
||||||
*
|
*
|
||||||
* @param program {@link Program}
|
* @param program {@link Program}
|
||||||
* @param allowRemote boolean flag, true means analyzer can search remote symbol
|
* @param allowUntrusted boolean flag, true means analyzer can search untrusted symbol
|
||||||
* servers
|
* servers
|
||||||
*/
|
*/
|
||||||
public static void setAllowRemoteOption(Program program, boolean allowRemote) {
|
public static void setAllowUntrustedOption(Program program, boolean allowUntrusted) {
|
||||||
PdbAnalyzerCommon.setAllowRemoteOption(NAME, program, allowRemote);
|
PdbAnalyzerCommon.setAllowUntrustedOption(NAME, program, allowUntrusted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-7
@@ -33,9 +33,9 @@ import pdb.symbolserver.SymbolFileInfo;
|
|||||||
* Shared configuration values and pdb searching logic
|
* Shared configuration values and pdb searching logic
|
||||||
*/
|
*/
|
||||||
public class PdbAnalyzerCommon {
|
public class PdbAnalyzerCommon {
|
||||||
static final String OPTION_DESCRIPTION_SEARCH_REMOTE_LOCATIONS =
|
static final String OPTION_DESCRIPTION_SEARCH_UNTRUSTED_LOCATIONS =
|
||||||
"If checked, allow searching remote symbol servers for PDB files.";
|
"If checked, allow searching untrusted symbol servers for PDB files.";
|
||||||
static final String OPTION_NAME_SEARCH_REMOTE_LOCATIONS = "Search remote symbol servers";
|
static final String OPTION_NAME_SEARCH_UNTRUSTED_LOCATIONS = "Search untrusted symbol servers";
|
||||||
|
|
||||||
static final String OPTION_DESCRIPTION_PDB_FILE = "Path to a manually chosen PDB file.";
|
static final String OPTION_DESCRIPTION_PDB_FILE = "Path to a manually chosen PDB file.";
|
||||||
static final String OPTION_NAME_PDB_FILE = "PDB File";
|
static final String OPTION_NAME_PDB_FILE = "PDB File";
|
||||||
@@ -101,12 +101,13 @@ public class PdbAnalyzerCommon {
|
|||||||
*
|
*
|
||||||
* @param analyzerName name of analyzer
|
* @param analyzerName name of analyzer
|
||||||
* @param program {@link Program}
|
* @param program {@link Program}
|
||||||
* @param allowRemote boolean flag, true means the analyzer can search remote
|
* @param allowUntrusted boolean flag, true means the analyzer can search remote
|
||||||
* symbol servers
|
* symbol servers
|
||||||
*/
|
*/
|
||||||
static void setAllowRemoteOption(String analyzerName, Program program, boolean allowRemote) {
|
static void setAllowUntrustedOption(String analyzerName, Program program, boolean allowUntrusted) {
|
||||||
Options options = program.getOptions(Program.ANALYSIS_PROPERTIES);
|
Options options = program.getOptions(Program.ANALYSIS_PROPERTIES);
|
||||||
options.setBoolean(analyzerName + "." + OPTION_NAME_SEARCH_REMOTE_LOCATIONS, allowRemote);
|
options.setBoolean(analyzerName + "." + OPTION_NAME_SEARCH_UNTRUSTED_LOCATIONS,
|
||||||
|
allowUntrusted);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -141,7 +142,7 @@ public class PdbAnalyzerCommon {
|
|||||||
: null;
|
: null;
|
||||||
if (pdbFile == null) {
|
if (pdbFile == null) {
|
||||||
Set<FindOption> findOpts = allowRemote
|
Set<FindOption> findOpts = allowRemote
|
||||||
? FindOption.of(FindOption.ALLOW_REMOTE)
|
? FindOption.of(FindOption.ALLOW_UNTRUSTED)
|
||||||
: FindOption.NO_OPTIONS;
|
: FindOption.NO_OPTIONS;
|
||||||
pdbFile = PdbPlugin.findPdb(program, findOpts, monitor);
|
pdbFile = PdbPlugin.findPdb(program, findOpts, monitor);
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-13
@@ -83,7 +83,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
|||||||
private File DEFAULT_FORCE_LOAD_FILE = new File(DEFAULT_SYMBOLS_DIR, "sample.pdb");
|
private File DEFAULT_FORCE_LOAD_FILE = new File(DEFAULT_SYMBOLS_DIR, "sample.pdb");
|
||||||
private File forceLoadFile;
|
private File forceLoadFile;
|
||||||
|
|
||||||
private boolean searchRemoteLocations = false;
|
private boolean searchUntrustedLocations = false;
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
// Additional instance data
|
// Additional instance data
|
||||||
@@ -164,7 +164,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
|||||||
pdbFile = forceLoadFile;
|
pdbFile = forceLoadFile;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pdbFile = PdbAnalyzerCommon.findPdb(this, program, searchRemoteLocations, monitor);
|
pdbFile = PdbAnalyzerCommon.findPdb(this, program, searchUntrustedLocations, monitor);
|
||||||
}
|
}
|
||||||
if (pdbFile == null) {
|
if (pdbFile == null) {
|
||||||
// warnings have already been logged
|
// warnings have already been logged
|
||||||
@@ -262,9 +262,9 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
|||||||
options.registerOption(OPTION_NAME_FORCELOAD_FILE, OptionType.FILE_TYPE,
|
options.registerOption(OPTION_NAME_FORCELOAD_FILE, OptionType.FILE_TYPE,
|
||||||
DEFAULT_FORCE_LOAD_FILE, null, OPTION_DESCRIPTION_FORCELOAD_FILE);
|
DEFAULT_FORCE_LOAD_FILE, null, OPTION_DESCRIPTION_FORCELOAD_FILE);
|
||||||
}
|
}
|
||||||
options.registerOption(PdbAnalyzerCommon.OPTION_NAME_SEARCH_REMOTE_LOCATIONS,
|
options.registerOption(PdbAnalyzerCommon.OPTION_NAME_SEARCH_UNTRUSTED_LOCATIONS,
|
||||||
searchRemoteLocations, null,
|
searchUntrustedLocations, null,
|
||||||
PdbAnalyzerCommon.OPTION_DESCRIPTION_SEARCH_REMOTE_LOCATIONS);
|
PdbAnalyzerCommon.OPTION_DESCRIPTION_SEARCH_UNTRUSTED_LOCATIONS);
|
||||||
|
|
||||||
pdbReaderOptions.registerOptions(options);
|
pdbReaderOptions.registerOptions(options);
|
||||||
pdbApplicatorOptions.registerAnalyzerOptions(options);
|
pdbApplicatorOptions.registerAnalyzerOptions(options);
|
||||||
@@ -281,8 +281,8 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
|||||||
forceLoadFile = options.getFile(OPTION_NAME_FORCELOAD_FILE, forceLoadFile);
|
forceLoadFile = options.getFile(OPTION_NAME_FORCELOAD_FILE, forceLoadFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
searchRemoteLocations = options.getBoolean(
|
searchUntrustedLocations = options.getBoolean(
|
||||||
PdbAnalyzerCommon.OPTION_NAME_SEARCH_REMOTE_LOCATIONS, searchRemoteLocations);
|
PdbAnalyzerCommon.OPTION_NAME_SEARCH_UNTRUSTED_LOCATIONS, searchUntrustedLocations);
|
||||||
|
|
||||||
pdbReaderOptions.loadOptions(options);
|
pdbReaderOptions.loadOptions(options);
|
||||||
pdbApplicatorOptions.loadAnalyzerOptions(options);
|
pdbApplicatorOptions.loadAnalyzerOptions(options);
|
||||||
@@ -312,19 +312,19 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the "allow remote" option that will be used by the analyzer when it is next invoked
|
* Sets the "allow untrusted" option that will be used by the analyzer when it is next invoked
|
||||||
* on the specified program.
|
* on the specified program.
|
||||||
* <p>
|
* <p>
|
||||||
* Normally when the analyzer attempts to locate a matching PDB file it
|
* Normally when the analyzer attempts to locate a matching PDB file it
|
||||||
* will default to NOT searching remote symbol servers. A headless script could
|
* will default to NOT searching untrusted symbol servers. A headless script could
|
||||||
* use this method to allow the analyzer to search remote symbol servers.
|
* use this method to allow the analyzer to search untrusted symbol servers.
|
||||||
*
|
*
|
||||||
* @param program {@link Program}
|
* @param program {@link Program}
|
||||||
* @param allowRemote boolean flag, true means analyzer can search remote symbol
|
* @param allowUntrusted boolean flag, true means analyzer can search remote symbol
|
||||||
* servers
|
* servers
|
||||||
*/
|
*/
|
||||||
public static void setAllowRemoteOption(Program program, boolean allowRemote) {
|
public static void setAllowUntrustedOption(Program program, boolean allowUntrusted) {
|
||||||
PdbAnalyzerCommon.setAllowRemoteOption(NAME, program, allowRemote);
|
PdbAnalyzerCommon.setAllowUntrustedOption(NAME, program, allowUntrusted);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
|||||||
@@ -136,11 +136,6 @@ public class ContainerFileSymbolServer implements SymbolServer {
|
|||||||
return fsFSRL.withPath(filename).toPrettyFullpathString();
|
return fsFSRL.withPath(filename).toPrettyFullpathString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLocal() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ContainerFileSymbolServer: [ fsrl: %s ]".formatted(fsFSRL);
|
return "ContainerFileSymbolServer: [ fsrl: %s ]".formatted(fsFSRL);
|
||||||
|
|||||||
@@ -114,11 +114,6 @@ public class DisabledSymbolServer implements SymbolServer {
|
|||||||
return delegate.getFileLocation(filename);
|
return delegate.getFileLocation(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLocal() {
|
|
||||||
return delegate.isLocal();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("DisabledSymbolServer: [ %s ]", delegate.toString());
|
return String.format("DisabledSymbolServer: [ %s ]", delegate.toString());
|
||||||
|
|||||||
@@ -15,18 +15,16 @@
|
|||||||
*/
|
*/
|
||||||
package pdb.symbolserver;
|
package pdb.symbolserver;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options that control how Pdb files are searched for on a SymbolServer.
|
* Options that control how Pdb files are searched for on a SymbolServer.
|
||||||
*/
|
*/
|
||||||
public enum FindOption {
|
public enum FindOption {
|
||||||
/**
|
/**
|
||||||
* Allow connections to remote symbol servers
|
* Allow connections to untrusted symbol servers
|
||||||
*/
|
*/
|
||||||
ALLOW_REMOTE,
|
ALLOW_UNTRUSTED,
|
||||||
/**
|
/**
|
||||||
* Only return the first result
|
* Only return the first result
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -25,23 +25,31 @@ import java.net.http.HttpResponse;
|
|||||||
import java.net.http.HttpResponse.BodyHandlers;
|
import java.net.http.HttpResponse.BodyHandlers;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import ghidra.net.HttpClients;
|
import ghidra.net.HttpClients;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.CancelledListener;
|
import ghidra.util.task.CancelledListener;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
import pdb.symbolserver.SymbolServer.MutableTrust;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link SymbolServer} that is accessed via HTTP.
|
* A {@link SymbolServer} that is accessed via HTTP.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class HttpSymbolServer extends AbstractSymbolServer {
|
public class HttpSymbolServer extends AbstractSymbolServer implements MutableTrust {
|
||||||
private static final String GHIDRA_USER_AGENT = "Ghidra_HttpSymbolServer_client";
|
private static final String GHIDRA_USER_AGENT = "Ghidra_HttpSymbolServer_client";
|
||||||
private static final int HTTP_STATUS_OK = HttpURLConnection.HTTP_OK;
|
private static final int HTTP_STATUS_OK = HttpURLConnection.HTTP_OK;
|
||||||
private static final int HTTP_REQUEST_TIMEOUT_MS = 10 * 1000; // 10 seconds
|
private static final int HTTP_REQUEST_TIMEOUT_MS = 10 * 1000; // 10 seconds
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pattern to match an optional "!" in front of a typical url string
|
||||||
|
*/
|
||||||
|
private static final Pattern NAMEPAT = Pattern.compile("(\\!?)(http(s?)://.*)");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Predicate that tests if the location string is an instance of a HttpSymbolServer location.
|
* Predicate that tests if the location string is an instance of a HttpSymbolServer location.
|
||||||
*
|
*
|
||||||
@@ -49,10 +57,48 @@ public class HttpSymbolServer extends AbstractSymbolServer {
|
|||||||
* @return boolean true if the string should be handled by the HttpSymbolServer class
|
* @return boolean true if the string should be handled by the HttpSymbolServer class
|
||||||
*/
|
*/
|
||||||
public static boolean isHttpSymbolServerLocation(String locationString) {
|
public static boolean isHttpSymbolServerLocation(String locationString) {
|
||||||
return locationString.startsWith("http://") || locationString.startsWith("https://");
|
return NAMEPAT.matcher(locationString).matches();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new HttpSymbolServer instance from a locationString.
|
||||||
|
*
|
||||||
|
* @param locationString string previously returned by {@link #getName()}
|
||||||
|
* @param context {@link SymbolServerInstanceCreatorContext}
|
||||||
|
* @return new instance
|
||||||
|
*/
|
||||||
|
public static SymbolServer createInstance(String locationString,
|
||||||
|
SymbolServerInstanceCreatorContext context) {
|
||||||
|
Matcher m = NAMEPAT.matcher(locationString);
|
||||||
|
if (!m.matches()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
boolean isTrusted = "!".equals(m.group(1));
|
||||||
|
String url = m.group(2);
|
||||||
|
return new HttpSymbolServer(URI.create(url), isTrusted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a trusted http symbol server
|
||||||
|
*
|
||||||
|
* @param url string url
|
||||||
|
* @return new {@link HttpSymbolServer} instance
|
||||||
|
*/
|
||||||
|
public static HttpSymbolServer createTrusted(String url) {
|
||||||
|
return new HttpSymbolServer(URI.create(url), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an untrusted http symbol server
|
||||||
|
* @param url string url
|
||||||
|
* @return new {@link HttpSymbolServer} instance
|
||||||
|
*/
|
||||||
|
public static HttpSymbolServer createUntrusted(String url) {
|
||||||
|
return new HttpSymbolServer(URI.create(url), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final URI serverURI;
|
private final URI serverURI;
|
||||||
|
private boolean trusted;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of a HttpSymbolServer.
|
* Creates a new instance of a HttpSymbolServer.
|
||||||
@@ -60,13 +106,29 @@ public class HttpSymbolServer extends AbstractSymbolServer {
|
|||||||
* @param serverURI URI / URL of the symbol server
|
* @param serverURI URI / URL of the symbol server
|
||||||
*/
|
*/
|
||||||
public HttpSymbolServer(URI serverURI) {
|
public HttpSymbolServer(URI serverURI) {
|
||||||
|
this(serverURI, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of a HttpSymbolServer.
|
||||||
|
*
|
||||||
|
* @param serverURI URI / URL of the symbol server
|
||||||
|
* @param isTrusted flag, if true the the http server can be trusted when querying and downloading
|
||||||
|
*/
|
||||||
|
public HttpSymbolServer(URI serverURI, boolean isTrusted) {
|
||||||
String path = serverURI.getPath();
|
String path = serverURI.getPath();
|
||||||
this.serverURI =
|
this.serverURI =
|
||||||
path.endsWith("/") ? serverURI : serverURI.resolve(serverURI.getPath() + "/");
|
path.endsWith("/") ? serverURI : serverURI.resolve(serverURI.getPath() + "/");
|
||||||
|
this.trusted = isTrusted;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
return (trusted ? "!" : "") + serverURI.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescriptiveName() {
|
||||||
return serverURI.toString();
|
return serverURI.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,14 +232,19 @@ public class HttpSymbolServer extends AbstractSymbolServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLocal() {
|
public boolean isTrusted() {
|
||||||
return false;
|
return trusted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTrusted(boolean isTrusted) {
|
||||||
|
this.trusted = isTrusted;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("HttpSymbolServer: [ url: %s, storageLevel: %d]", serverURI.toString(),
|
return String.format("HttpSymbolServer: [ url: %s, trusted: %b, storageLevel: %d]",
|
||||||
storageLevel);
|
serverURI.toString(), trusted, storageLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String logPrefix() {
|
private String logPrefix() {
|
||||||
|
|||||||
@@ -371,11 +371,6 @@ public class LocalSymbolStore extends AbstractSymbolServer implements SymbolStor
|
|||||||
return new SymbolServerInputStream(new FileInputStream(file), file.length());
|
return new SymbolServerInputStream(new FileInputStream(file), file.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLocal() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("LocalSymbolStore: [ rootDir: %s, storageLevel: %d]",
|
return String.format("LocalSymbolStore: [ rootDir: %s, storageLevel: %d]",
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import java.util.*;
|
|||||||
|
|
||||||
import ghidra.formats.gfilesystem.FSRL;
|
import ghidra.formats.gfilesystem.FSRL;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
import pdb.symbolserver.SymbolServer.StatusRequiresContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Pdb symbol server / symbol store, similar to the {@link LocalSymbolStore},
|
* A Pdb symbol server / symbol store, similar to the {@link LocalSymbolStore},
|
||||||
@@ -27,7 +28,7 @@ import ghidra.util.task.TaskMonitor;
|
|||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class SameDirSymbolStore implements SymbolStore {
|
public class SameDirSymbolStore implements SymbolStore, StatusRequiresContext {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Descriptive string
|
* Descriptive string
|
||||||
@@ -166,11 +167,6 @@ public class SameDirSymbolStore implements SymbolStore {
|
|||||||
return getFile(filename).getPath();
|
return getFile(filename).getPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLocal() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("SameDirSymbolStore: [ dir: %s ]", rootDir);
|
return String.format("SameDirSymbolStore: [ dir: %s ]", rootDir);
|
||||||
|
|||||||
@@ -17,8 +17,7 @@ package pdb.symbolserver;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
@@ -29,6 +28,27 @@ import ghidra.util.task.TaskMonitor;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public interface SymbolServer {
|
public interface SymbolServer {
|
||||||
|
/**
|
||||||
|
* Optional add-on interface for {@link SymbolServer}s that flag server types as requiring a
|
||||||
|
* valid context object to be queried for {@link SymbolServer#isValid(TaskMonitor)}
|
||||||
|
*/
|
||||||
|
interface StatusRequiresContext {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional add-on interface for {@link SymbolServer}s that allow their trusted-ness value to
|
||||||
|
* be modified.
|
||||||
|
*/
|
||||||
|
public interface MutableTrust {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the trusted attribute of this symbol server.
|
||||||
|
*
|
||||||
|
* @param isTrusted boolean flag, if true this symbolserver will be marked as trusted
|
||||||
|
*/
|
||||||
|
void setTrusted(boolean isTrusted);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of the symbol server, suitable to use as the identity of this instance,
|
* Name of the symbol server, suitable to use as the identity of this instance,
|
||||||
@@ -55,6 +75,16 @@ public interface SymbolServer {
|
|||||||
*/
|
*/
|
||||||
boolean isValid(TaskMonitor monitor);
|
boolean isValid(TaskMonitor monitor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this {@link SymbolServer} is 'trusted', meaning
|
||||||
|
* it can be searched without security issues / warning the user.
|
||||||
|
*
|
||||||
|
* @return boolean true if this symbolserver is trusted, false if untrusted
|
||||||
|
*/
|
||||||
|
default boolean isTrusted() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the raw filename exists in the symbol server.
|
* Returns true if the raw filename exists in the symbol server.
|
||||||
*
|
*
|
||||||
@@ -103,10 +133,13 @@ public interface SymbolServer {
|
|||||||
String getFileLocation(String filename);
|
String getFileLocation(String filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this {@link SymbolServer} is 'local', meaning
|
* Returns the number of configured symbol servers that are considered 'untrusted'.
|
||||||
* it can be searched without security issues / warning the user.
|
|
||||||
*
|
*
|
||||||
* @return boolean true if this symbolserver is 'local', false if remote
|
* @param symbolServers list of {@link SymbolServer}s
|
||||||
|
* @return number of untrusted symbol servers
|
||||||
*/
|
*/
|
||||||
boolean isLocal();
|
static int getUntrustedCount(Collection<SymbolServer> symbolServers) {
|
||||||
|
return (int) symbolServers.stream().filter(ss -> !ss.isTrusted()).count();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -16,7 +16,6 @@
|
|||||||
package pdb.symbolserver;
|
package pdb.symbolserver;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URI;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
@@ -167,7 +166,7 @@ public class SymbolServerInstanceCreatorRegistry {
|
|||||||
registerSymbolServerInstanceCreator(0, DisabledSymbolServer::isDisabledSymbolServerLocation,
|
registerSymbolServerInstanceCreator(0, DisabledSymbolServer::isDisabledSymbolServerLocation,
|
||||||
DisabledSymbolServer::createInstance);
|
DisabledSymbolServer::createInstance);
|
||||||
registerSymbolServerInstanceCreator(100, HttpSymbolServer::isHttpSymbolServerLocation,
|
registerSymbolServerInstanceCreator(100, HttpSymbolServer::isHttpSymbolServerLocation,
|
||||||
(loc, context) -> new HttpSymbolServer(URI.create(loc)));
|
HttpSymbolServer::createInstance);
|
||||||
registerSymbolServerInstanceCreator(200, SameDirSymbolStore::isSameDirLocation,
|
registerSymbolServerInstanceCreator(200, SameDirSymbolStore::isSameDirLocation,
|
||||||
SameDirSymbolStore::createInstance);
|
SameDirSymbolStore::createInstance);
|
||||||
registerSymbolServerInstanceCreator(300, LocalSymbolStore::isLocalSymbolStoreLocation,
|
registerSymbolServerInstanceCreator(300, LocalSymbolStore::isLocalSymbolStoreLocation,
|
||||||
|
|||||||
@@ -15,11 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package pdb.symbolserver;
|
package pdb.symbolserver;
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@@ -31,8 +30,7 @@ import pdb.PdbUtils;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A (lowercase-'S') service that searches for and fetches symbol files
|
* A (lowercase-'S') service that searches for and fetches symbol files
|
||||||
* from a set of local and remote {@link SymbolServer symbolservers}. (not to be
|
* from a set of {@link SymbolServer symbolservers}. (not to be confused with a Plugin service)
|
||||||
* confused with a Plugin service)
|
|
||||||
* <p>
|
* <p>
|
||||||
* Instances of this class are meant to be easily created when needed
|
* Instances of this class are meant to be easily created when needed
|
||||||
* and just as easily thrown away when not used or when the search
|
* and just as easily thrown away when not used or when the search
|
||||||
@@ -50,9 +48,8 @@ public class SymbolServerService {
|
|||||||
/**
|
/**
|
||||||
* Creates a new SymbolServerService instance.
|
* Creates a new SymbolServerService instance.
|
||||||
* <p>
|
* <p>
|
||||||
* @param symbolStore a {@link SymbolStore} - where all
|
* @param symbolStore a {@link SymbolStore} - where all remote files are placed when
|
||||||
* remote files are placed when downloaded. Also treated as a SymbolServer
|
* downloaded. Also treated as a SymbolServer and searched first
|
||||||
* and searched first
|
|
||||||
* @param symbolServers a list of {@link SymbolServer symbol servers} - searched in order
|
* @param symbolServers a list of {@link SymbolServer symbol servers} - searched in order
|
||||||
*/
|
*/
|
||||||
public SymbolServerService(SymbolStore symbolStore, List<SymbolServer> symbolServers) {
|
public SymbolServerService(SymbolStore symbolStore, List<SymbolServer> symbolServers) {
|
||||||
@@ -91,19 +88,6 @@ public class SymbolServerService {
|
|||||||
return new ArrayList<>(symbolServers.subList(1, symbolServers.size()));
|
return new ArrayList<>(symbolServers.subList(1, symbolServers.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of configured symbol servers that are considered 'remote'.
|
|
||||||
* @return number of remote symbol servers
|
|
||||||
*/
|
|
||||||
public int getRemoteSymbolServerCount() {
|
|
||||||
int remoteSymbolServerCount = (int) getSymbolServers()
|
|
||||||
.stream()
|
|
||||||
.filter(ss -> !ss.isLocal())
|
|
||||||
.count();
|
|
||||||
|
|
||||||
return remoteSymbolServerCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches all {@link SymbolServer symbol servers} for a matching pdb symbol file.
|
* Searches all {@link SymbolServer symbol servers} for a matching pdb symbol file.
|
||||||
*
|
*
|
||||||
@@ -150,9 +134,9 @@ public class SymbolServerService {
|
|||||||
|
|
||||||
for_each_symbol_server_loop: for (SymbolServer symbolServer : symbolServers) {
|
for_each_symbol_server_loop: for (SymbolServer symbolServer : symbolServers) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
if (!symbolServer.isLocal() && !findOptions.contains(FindOption.ALLOW_REMOTE)) {
|
if (!symbolServer.isTrusted() && !findOptions.contains(FindOption.ALLOW_UNTRUSTED)) {
|
||||||
Msg.debug(this,
|
Msg.debug(this,
|
||||||
logPrefix() + ": skipping non-local symbol server " +
|
logPrefix() + ": skipping untrusted symbol server " +
|
||||||
symbolServer.getDescriptiveName());
|
symbolServer.getDescriptiveName());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -72,6 +72,8 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
|||||||
ExtensionFileFilter.forExtensions("Microsoft Program Databases", "pdb", "pd_", "pdb.xml");
|
ExtensionFileFilter.forExtensions("Microsoft Program Databases", "pdb", "pd_", "pdb.xml");
|
||||||
|
|
||||||
private static final SymbolFileInfo UNKNOWN_SYMFILE = makeUnknownSymbolFileInstance("");
|
private static final SymbolFileInfo UNKNOWN_SYMFILE = makeUnknownSymbolFileInstance("");
|
||||||
|
private static final List<WellKnownSymbolServerLocation> knownSymbolServers =
|
||||||
|
WellKnownSymbolServerLocation.loadAll();
|
||||||
|
|
||||||
public static class LoadPdbResults {
|
public static class LoadPdbResults {
|
||||||
public File pdbFile;
|
public File pdbFile;
|
||||||
@@ -270,7 +272,7 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
|||||||
return SymbolFileInfo.fromValues(pdbPath, uid, age);
|
return SymbolFileInfo.fromValues(pdbPath, uid, age);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void searchForPdbs(boolean allowRemote) {
|
private void searchForPdbs(boolean allowUntrusted) {
|
||||||
if (pdbAgeTextField.getText().isBlank() ||
|
if (pdbAgeTextField.getText().isBlank() ||
|
||||||
pdbAgeTextField.getValue() > NumericUtilities.MAX_UNSIGNED_INT32_AS_LONG) {
|
pdbAgeTextField.getValue() > NumericUtilities.MAX_UNSIGNED_INT32_AS_LONG) {
|
||||||
Msg.showWarn(this, null, "Bad PDB Age", "Invalid PDB Age value");
|
Msg.showWarn(this, null, "Bad PDB Age", "Invalid PDB Age value");
|
||||||
@@ -282,8 +284,8 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Set<FindOption> findOptions = symbolFilePanel.getFindOptions();
|
Set<FindOption> findOptions = symbolFilePanel.getFindOptions();
|
||||||
if (allowRemote) {
|
if (allowUntrusted) {
|
||||||
findOptions.add(FindOption.ALLOW_REMOTE);
|
findOptions.add(FindOption.ALLOW_UNTRUSTED);
|
||||||
}
|
}
|
||||||
executeMonitoredRunnable("Search for PDBs", true, true, 0, monitor -> {
|
executeMonitoredRunnable("Search for PDBs", true, true, 0, monitor -> {
|
||||||
try {
|
try {
|
||||||
@@ -316,10 +318,11 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
|||||||
setHelpLocation(new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "Load PDB File"));
|
setHelpLocation(new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "Load PDB File"));
|
||||||
|
|
||||||
addStatusTextSupplier(() -> lastSearchOptions != null && advancedToggleButton.isSelected()
|
addStatusTextSupplier(() -> lastSearchOptions != null && advancedToggleButton.isSelected()
|
||||||
? SymbolServerPanel.getSymbolServerWarnings(symbolServerService.getSymbolServers())
|
? WellKnownSymbolServerLocation.getWarningsFor(knownSymbolServers,
|
||||||
|
symbolServerService.getSymbolServers())
|
||||||
: null);
|
: null);
|
||||||
addStatusTextSupplier(this::getSelectedPdbNoticeText);
|
addStatusTextSupplier(this::getSelectedPdbNoticeText);
|
||||||
addStatusTextSupplier(this::getAllowRemoteWarning);
|
addStatusTextSupplier(this::getAllowUntrustedWarning);
|
||||||
addStatusTextSupplier(this::getFoundCountInfo);
|
addStatusTextSupplier(this::getFoundCountInfo);
|
||||||
|
|
||||||
addButtons();
|
addButtons();
|
||||||
@@ -600,12 +603,13 @@ public class LoadPdbDialog extends DialogComponentProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private StatusText getAllowRemoteWarning() {
|
private StatusText getAllowUntrustedWarning() {
|
||||||
int remoteSymbolServerCount = symbolServerService.getRemoteSymbolServerCount();
|
int untrustedSymbolServerCount =
|
||||||
|
SymbolServer.getUntrustedCount(symbolServerService.getSymbolServers());
|
||||||
return lastSearchOptions != null && advancedToggleButton.isSelected() &&
|
return lastSearchOptions != null && advancedToggleButton.isSelected() &&
|
||||||
remoteSymbolServerCount != 0 && !lastSearchOptions.contains(FindOption.ALLOW_REMOTE)
|
untrustedSymbolServerCount != 0 && !lastSearchOptions.contains(FindOption.ALLOW_UNTRUSTED)
|
||||||
? new StatusText(
|
? new StatusText(
|
||||||
"Remote servers were excluded. Use \"Search All\" button to also search remote servers.",
|
"Untrusted servers were excluded. Use \"Search All\" button to also include untrusted servers.",
|
||||||
MessageType.INFO, false)
|
MessageType.INFO, false)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import pdb.symbolserver.FindOption;
|
|||||||
*/
|
*/
|
||||||
class SymbolFilePanel extends JPanel {
|
class SymbolFilePanel extends JPanel {
|
||||||
interface SearchCallback {
|
interface SearchCallback {
|
||||||
void searchForPdbs(boolean allowRemote);
|
void searchForPdbs(boolean allowUntrusted);
|
||||||
}
|
}
|
||||||
|
|
||||||
static final String SEARCH_OPTIONS_HELP_ANCHOR = "PDB_Search_Search_Options";
|
static final String SEARCH_OPTIONS_HELP_ANCHOR = "PDB_Search_Search_Options";
|
||||||
@@ -149,10 +149,10 @@ class SymbolFilePanel extends JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private JPanel buildButtonPanel() {
|
private JPanel buildButtonPanel() {
|
||||||
searchLocalButton = new JButton("Search Local");
|
searchLocalButton = new JButton("Search");
|
||||||
searchLocalButton.setToolTipText("Search local symbol servers only.");
|
searchLocalButton.setToolTipText("Search trusted symbol servers only.");
|
||||||
searchAllButton = new JButton("Search All");
|
searchAllButton = new JButton("Search All");
|
||||||
searchAllButton.setToolTipText("Search local and remote symbol servers.");
|
searchAllButton.setToolTipText("Search trusted and untrusted symbol servers.");
|
||||||
|
|
||||||
ignorePdbUid = new GCheckBox("Ignore GUID/ID");
|
ignorePdbUid = new GCheckBox("Ignore GUID/ID");
|
||||||
ignorePdbUid.setToolTipText(
|
ignorePdbUid.setToolTipText(
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -15,8 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package pdb.symbolserver.ui;
|
package pdb.symbolserver.ui;
|
||||||
|
|
||||||
|
import static pdb.symbolserver.ui.SymbolServerRow.LocationStatus.*;
|
||||||
|
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
import pdb.symbolserver.DisabledSymbolServer;
|
import pdb.symbolserver.DisabledSymbolServer;
|
||||||
import pdb.symbolserver.SymbolServer;
|
import pdb.symbolserver.SymbolServer;
|
||||||
|
import pdb.symbolserver.SymbolServer.MutableTrust;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a row in the {@link SymbolServerTableModel}
|
* Represents a row in the {@link SymbolServerTableModel}
|
||||||
@@ -59,6 +63,16 @@ class SymbolServerRow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isTrusted() {
|
||||||
|
return symbolServer.isTrusted();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTrusted(boolean isTrusted) {
|
||||||
|
if (symbolServer instanceof MutableTrust sswt) {
|
||||||
|
sswt.setTrusted(isTrusted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LocationStatus getStatus() {
|
LocationStatus getStatus() {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -67,6 +81,12 @@ class SymbolServerRow {
|
|||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateStatus(TaskMonitor monitor) {
|
||||||
|
if (!(symbolServer instanceof SymbolServer.StatusRequiresContext)) {
|
||||||
|
this.status = symbolServer.isValid(monitor) ? VALID : INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("SymbolServerRow: [ status: %s, server: %s]", status.toString(),
|
return String.format("SymbolServerRow: [ status: %s, server: %s]", status.toString(),
|
||||||
|
|||||||
@@ -15,30 +15,28 @@
|
|||||||
*/
|
*/
|
||||||
package pdb.symbolserver.ui;
|
package pdb.symbolserver.ui;
|
||||||
|
|
||||||
import static java.util.stream.Collectors.toList;
|
import static java.util.stream.Collectors.*;
|
||||||
import static pdb.symbolserver.ui.SymbolServerRow.LocationStatus.INVALID;
|
|
||||||
import static pdb.symbolserver.ui.SymbolServerRow.LocationStatus.VALID;
|
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.FontMetrics;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import java.awt.Component;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
import javax.swing.table.TableColumn;
|
||||||
|
|
||||||
import docking.widgets.table.*;
|
import docking.widgets.table.*;
|
||||||
|
import generic.theme.GIcon;
|
||||||
import ghidra.docking.settings.Settings;
|
import ghidra.docking.settings.Settings;
|
||||||
import ghidra.framework.plugintool.ServiceProvider;
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
import ghidra.framework.plugintool.ServiceProviderStub;
|
import ghidra.framework.plugintool.ServiceProviderStub;
|
||||||
import ghidra.util.Swing;
|
|
||||||
import ghidra.util.table.column.AbstractGColumnRenderer;
|
import ghidra.util.table.column.AbstractGColumnRenderer;
|
||||||
import ghidra.util.table.column.GColumnRenderer;
|
import ghidra.util.table.column.GColumnRenderer;
|
||||||
import ghidra.util.task.TaskLauncher;
|
|
||||||
import pdb.symbolserver.SymbolServer;
|
import pdb.symbolserver.SymbolServer;
|
||||||
import resources.Icons;
|
import resources.Icons;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table model for the {@link SymbolServerPanel} table
|
* Table model for the {@link ConfigPdbDialog} table
|
||||||
*/
|
*/
|
||||||
class SymbolServerTableModel
|
class SymbolServerTableModel
|
||||||
extends GDynamicColumnTableModel<SymbolServerRow, List<SymbolServerRow>> {
|
extends GDynamicColumnTableModel<SymbolServerRow, List<SymbolServerRow>> {
|
||||||
@@ -64,9 +62,7 @@ class SymbolServerTableModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<SymbolServer> getSymbolServers() {
|
List<SymbolServer> getSymbolServers() {
|
||||||
return rows.stream()
|
return rows.stream().map(SymbolServerRow::getSymbolServer).collect(toList());
|
||||||
.map(SymbolServerRow::getSymbolServer)
|
|
||||||
.collect(toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addSymbolServer(SymbolServer ss) {
|
void addSymbolServer(SymbolServer ss) {
|
||||||
@@ -92,26 +88,6 @@ class SymbolServerTableModel
|
|||||||
fireTableDataChanged();
|
fireTableDataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void refreshSymbolServerLocationStatus() {
|
|
||||||
List<SymbolServerRow> rowsCopy = new ArrayList<>(this.rows);
|
|
||||||
TaskLauncher.launchNonModal("Refresh Symbol Server Location Status", monitor -> {
|
|
||||||
monitor.initialize(rowsCopy.size());
|
|
||||||
monitor.setMessage("Refreshing symbol server status");
|
|
||||||
try {
|
|
||||||
for (SymbolServerRow row : rowsCopy) {
|
|
||||||
if (monitor.isCancelled()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
monitor.setMessage("Checking " + row.getSymbolServer().getName());
|
|
||||||
row.setStatus(row.getSymbolServer().isValid(monitor) ? VALID : INVALID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
Swing.runLater(SymbolServerTableModel.this::fireTableDataChanged);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void moveRow(int rowIndex, int deltaIndex) {
|
void moveRow(int rowIndex, int deltaIndex) {
|
||||||
int destIndex = rowIndex + deltaIndex;
|
int destIndex = rowIndex + deltaIndex;
|
||||||
if (rowIndex < 0 || rowIndex >= rows.size() || destIndex < 0 || destIndex >= rows.size()) {
|
if (rowIndex < 0 || rowIndex >= rows.size() || destIndex < 0 || destIndex >= rows.size()) {
|
||||||
@@ -159,18 +135,24 @@ class SymbolServerTableModel
|
|||||||
@Override
|
@Override
|
||||||
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
||||||
DynamicTableColumn<SymbolServerRow, ?, ?> column = getColumn(columnIndex);
|
DynamicTableColumn<SymbolServerRow, ?, ?> column = getColumn(columnIndex);
|
||||||
if (column instanceof EnabledColumn) {
|
if (column instanceof EnabledColumn && aValue instanceof Boolean) {
|
||||||
SymbolServerRow row = getRowObject(rowIndex);
|
SymbolServerRow row = getRowObject(rowIndex);
|
||||||
row.setEnabled((Boolean) aValue);
|
row.setEnabled((Boolean) aValue);
|
||||||
dataChanged = true;
|
dataChanged = true;
|
||||||
fireTableDataChanged();
|
fireTableDataChanged();
|
||||||
}
|
}
|
||||||
|
else if (column instanceof TrustedColumn && aValue instanceof Boolean) {
|
||||||
|
SymbolServerRow row = getRowObject(rowIndex);
|
||||||
|
row.setTrusted((Boolean) aValue);
|
||||||
|
dataChanged = true;
|
||||||
|
fireTableDataChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||||
DynamicTableColumn<SymbolServerRow, ?, ?> column = getColumn(columnIndex);
|
DynamicTableColumn<SymbolServerRow, ?, ?> column = getColumn(columnIndex);
|
||||||
return column instanceof EnabledColumn;
|
return column instanceof EnabledColumn || column instanceof TrustedColumn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -178,6 +160,7 @@ class SymbolServerTableModel
|
|||||||
TableColumnDescriptor<SymbolServerRow> descriptor = new TableColumnDescriptor<>();
|
TableColumnDescriptor<SymbolServerRow> descriptor = new TableColumnDescriptor<>();
|
||||||
|
|
||||||
descriptor.addVisibleColumn(new EnabledColumn());
|
descriptor.addVisibleColumn(new EnabledColumn());
|
||||||
|
descriptor.addVisibleColumn(new TrustedColumn());
|
||||||
descriptor.addVisibleColumn(new StatusColumn());
|
descriptor.addVisibleColumn(new StatusColumn());
|
||||||
descriptor.addVisibleColumn(new LocationColumn());
|
descriptor.addVisibleColumn(new LocationColumn());
|
||||||
|
|
||||||
@@ -187,9 +170,10 @@ class SymbolServerTableModel
|
|||||||
//-------------------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
private static class StatusColumn extends
|
private static class StatusColumn extends
|
||||||
AbstractDynamicTableColumnStub<SymbolServerRow, SymbolServerRow.LocationStatus> {
|
AbstractDynamicTableColumnStub<SymbolServerRow, SymbolServerRow.LocationStatus>
|
||||||
|
implements TableColumnInitializer {
|
||||||
|
|
||||||
private static final Icon VALID_ICON = Icons.get("images/checkmark_green.gif");
|
private static final Icon VALID_ICON = new GIcon("icon.checkmark.green");
|
||||||
private static final Icon INVALID_ICON = Icons.ERROR_ICON;
|
private static final Icon INVALID_ICON = Icons.ERROR_ICON;
|
||||||
|
|
||||||
private static Icon[] icons = new Icon[] { null, VALID_ICON, INVALID_ICON };
|
private static Icon[] icons = new Icon[] { null, VALID_ICON, INVALID_ICON };
|
||||||
@@ -206,7 +190,7 @@ class SymbolServerTableModel
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getColumnDisplayName(Settings settings) {
|
public String getColumnDisplayName(Settings settings) {
|
||||||
return "";
|
return "Status";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -219,14 +203,23 @@ class SymbolServerTableModel
|
|||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initializeTableColumn(TableColumn col, FontMetrics fm, int padding) {
|
||||||
|
int colWidth = fm.stringWidth("Status") + padding;
|
||||||
|
col.setPreferredWidth(colWidth);
|
||||||
|
col.setMaxWidth(colWidth * 2);
|
||||||
|
col.setMinWidth(colWidth);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class EnabledColumn
|
private static class EnabledColumn
|
||||||
extends AbstractDynamicTableColumnStub<SymbolServerRow, Boolean> {
|
extends AbstractDynamicTableColumnStub<SymbolServerRow, Boolean>
|
||||||
|
implements TableColumnInitializer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getColumnDisplayName(Settings settings) {
|
public String getColumnDisplayName(Settings settings) {
|
||||||
return "";
|
return "Enabled";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -240,6 +233,43 @@ class SymbolServerTableModel
|
|||||||
return "Enabled";
|
return "Enabled";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initializeTableColumn(TableColumn col, FontMetrics fm, int padding) {
|
||||||
|
int colWidth = fm.stringWidth("Enabled") + padding;
|
||||||
|
col.setPreferredWidth(colWidth);
|
||||||
|
col.setMaxWidth(colWidth * 2);
|
||||||
|
col.setMinWidth(colWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TrustedColumn
|
||||||
|
extends AbstractDynamicTableColumnStub<SymbolServerRow, Boolean>
|
||||||
|
implements TableColumnInitializer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getColumnDisplayName(Settings settings) {
|
||||||
|
return "Trusted";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean getValue(SymbolServerRow rowObject, Settings settings,
|
||||||
|
ServiceProvider serviceProvider) throws IllegalArgumentException {
|
||||||
|
return rowObject.isTrusted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getColumnName() {
|
||||||
|
return "Trusted";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initializeTableColumn(TableColumn col, FontMetrics fm, int padding) {
|
||||||
|
int colWidth = fm.stringWidth("Trusted") + padding;
|
||||||
|
col.setPreferredWidth(colWidth);
|
||||||
|
col.setMaxWidth(colWidth * 2);
|
||||||
|
col.setMinWidth(colWidth);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class LocationColumn
|
private static class LocationColumn
|
||||||
@@ -305,5 +335,6 @@ class SymbolServerTableModel
|
|||||||
public String getFilterString(E t, Settings settings) {
|
public String getFilterString(E t, Settings settings) {
|
||||||
return t == null ? "" : t.toString();
|
return t == null ? "" : t.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package pdb.symbolserver.ui;
|
||||||
|
|
||||||
|
import java.awt.FontMetrics;
|
||||||
|
|
||||||
|
import javax.swing.table.TableColumn;
|
||||||
|
import javax.swing.table.TableColumnModel;
|
||||||
|
|
||||||
|
import docking.ComponentProvider;
|
||||||
|
import docking.DialogComponentProvider;
|
||||||
|
import docking.widgets.table.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For Pdb symbolserver gui stuff only.
|
||||||
|
*
|
||||||
|
* Add on interface for DynamicTableColumn classes that let them control aspects of the
|
||||||
|
* matching TableColumn.
|
||||||
|
*/
|
||||||
|
public interface TableColumnInitializer {
|
||||||
|
/**
|
||||||
|
* Best called during {@link DialogComponentProvider#dialogShown} or
|
||||||
|
* {@link ComponentProvider#componentShown}
|
||||||
|
*
|
||||||
|
* @param table table component
|
||||||
|
* @param model table model
|
||||||
|
*/
|
||||||
|
static void initializeTableColumns(GTable table, GDynamicColumnTableModel<?, ?> model) {
|
||||||
|
TableColumnModel colModel = table.getColumnModel();
|
||||||
|
|
||||||
|
FontMetrics fm = table.getTableHeader().getFontMetrics(table.getTableHeader().getFont());
|
||||||
|
int padding = fm.stringWidth("WW"); // w.a.g. for the left+right padding on the header column component
|
||||||
|
|
||||||
|
for (int colIndex = 0; colIndex < model.getColumnCount(); colIndex++) {
|
||||||
|
DynamicTableColumn<?, ?, ?> dtableCol = model.getColumn(colIndex);
|
||||||
|
if (dtableCol instanceof TableColumnInitializer colInitializer) {
|
||||||
|
TableColumn tableCol = colModel.getColumn(colIndex);
|
||||||
|
colInitializer.initializeTableColumn(tableCol, fm, padding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to allow the initializer to modify the specified TableColumn
|
||||||
|
*
|
||||||
|
* @param col {@link TableColumn}
|
||||||
|
* @param fm {@link FontMetrics} used by the table header gui component
|
||||||
|
* @param padding padding to use in the column
|
||||||
|
*/
|
||||||
|
void initializeTableColumn(TableColumn col, FontMetrics fm, int padding);
|
||||||
|
}
|
||||||
+38
-52
@@ -17,68 +17,27 @@ package pdb.symbolserver.ui;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import generic.jar.ResourceFile;
|
import generic.jar.ResourceFile;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
|
import ghidra.util.MessageType;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
import pdb.symbolserver.SymbolServer;
|
||||||
|
import pdb.symbolserver.ui.LoadPdbDialog.StatusText;
|
||||||
import utilities.util.FileUtilities;
|
import utilities.util.FileUtilities;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a well-known symbol server location.
|
* Represents a well-known symbol server location.
|
||||||
* <p>
|
* <p>
|
||||||
* See the PDB_SYMBOL_SERVER_URLS.pdburl file.
|
* See the PDB_SYMBOL_SERVER_URLS.pdburl file.
|
||||||
|
* @param location url string
|
||||||
|
* @param locationCategory grouping criteria
|
||||||
|
* @param warning string
|
||||||
|
* @param fileOrigin file name that contained this info
|
||||||
*/
|
*/
|
||||||
class WellKnownSymbolServerLocation {
|
public record WellKnownSymbolServerLocation(String location, String locationCategory,
|
||||||
private String locationCategory;
|
String warning, String fileOrigin) {
|
||||||
private String location;
|
|
||||||
private String warning;
|
|
||||||
private String fileOrigin;
|
|
||||||
|
|
||||||
WellKnownSymbolServerLocation(String location, String locationCategory, String warning,
|
|
||||||
String fileOrigin) {
|
|
||||||
this.location = location;
|
|
||||||
this.locationCategory = locationCategory;
|
|
||||||
this.warning = warning;
|
|
||||||
this.fileOrigin = fileOrigin;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getLocationCategory() {
|
|
||||||
return locationCategory;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getLocation() {
|
|
||||||
return location;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getWarning() {
|
|
||||||
return warning;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getFileOrigin() {
|
|
||||||
return fileOrigin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(location, locationCategory, warning);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (obj == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (getClass() != obj.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
WellKnownSymbolServerLocation other = (WellKnownSymbolServerLocation) obj;
|
|
||||||
return Objects.equals(location, other.location) &&
|
|
||||||
Objects.equals(locationCategory, other.locationCategory) &&
|
|
||||||
Objects.equals(warning, other.warning);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all symbol server location files (*.pdburl) and returns a list of entries.
|
* Loads all symbol server location files (*.pdburl) and returns a list of entries.
|
||||||
@@ -103,10 +62,37 @@ class WellKnownSymbolServerLocation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
Msg.warn(WellKnownSymbolServerLocation.class, "Unable to read pdburl file: " + file);
|
Msg.warn(WellKnownSymbolServerLocation.class,
|
||||||
|
"Unable to read pdburl file: " + file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a formatted StatusText containing all the warnings published by any untrusted
|
||||||
|
* {@link WellKnownSymbolServerLocation} found in the list of symbolservers.
|
||||||
|
*
|
||||||
|
* @param knownSymbolServers list
|
||||||
|
* @param symbolServers list
|
||||||
|
* @return StatusText
|
||||||
|
*/
|
||||||
|
public static StatusText getWarningsFor(List<WellKnownSymbolServerLocation> knownSymbolServers,
|
||||||
|
List<SymbolServer> symbolServers) {
|
||||||
|
Map<String, String> warningsByLocation = new HashMap<>();
|
||||||
|
for (WellKnownSymbolServerLocation ssloc : knownSymbolServers) {
|
||||||
|
if (ssloc.warning() != null && !ssloc.warning().isBlank()) {
|
||||||
|
warningsByLocation.put(ssloc.location(), ssloc.warning());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String warning = symbolServers.stream()
|
||||||
|
.filter(symbolServer -> !symbolServer.isTrusted())
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,14 +21,16 @@ import java.util.List;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
import pdb.symbolserver.SymbolServer.MutableTrust;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A "remote" symbol server that answers affirmatively for any query.
|
* A "remote" symbol server that answers affirmatively for any query.
|
||||||
*/
|
*/
|
||||||
public class DummySymbolServer implements SymbolServer {
|
public class DummySymbolServer implements SymbolServer, MutableTrust {
|
||||||
|
|
||||||
private final byte[] dummyPayload;
|
private final byte[] dummyPayload;
|
||||||
private final boolean returnCompressedFilenames;
|
private final boolean returnCompressedFilenames;
|
||||||
|
private boolean trusted;
|
||||||
|
|
||||||
public DummySymbolServer(String dummyPayload) {
|
public DummySymbolServer(String dummyPayload) {
|
||||||
this(dummyPayload.getBytes(), false);
|
this(dummyPayload.getBytes(), false);
|
||||||
@@ -78,8 +80,13 @@ public class DummySymbolServer implements SymbolServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLocal() {
|
public boolean isTrusted() {
|
||||||
return false;
|
return trusted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTrusted(boolean isTrusted) {
|
||||||
|
this.trusted = isTrusted;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,16 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package pdb.symbolserver;
|
package pdb.symbolserver;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -128,14 +126,14 @@ public class SymbolServerServiceTest extends AbstractGenericTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_Remote() throws IOException, CancelledException {
|
public void test_Trusted() throws IOException, CancelledException {
|
||||||
String payload = "testdummy";
|
String payload = "testdummy";
|
||||||
SymbolServerService symbolServerService =
|
SymbolServerService symbolServerService =
|
||||||
new SymbolServerService(localSymbolStore1,
|
new SymbolServerService(localSymbolStore1,
|
||||||
List.of(localSymbolStore2, new DummySymbolServer(payload)));
|
List.of(localSymbolStore2, new DummySymbolServer(payload)));
|
||||||
SymbolFileInfo searchPdb = SymbolFileInfo.fromValues("file1.pdb", "11223344", 0);
|
SymbolFileInfo searchPdb = SymbolFileInfo.fromValues("file1.pdb", "11223344", 0);
|
||||||
List<SymbolFileLocation> results =
|
List<SymbolFileLocation> results =
|
||||||
symbolServerService.find(searchPdb, FindOption.of(FindOption.ALLOW_REMOTE),
|
symbolServerService.find(searchPdb, FindOption.of(FindOption.ALLOW_UNTRUSTED),
|
||||||
TaskMonitor.DUMMY);
|
TaskMonitor.DUMMY);
|
||||||
|
|
||||||
assertEquals(1, results.size());
|
assertEquals(1, results.size());
|
||||||
@@ -148,8 +146,9 @@ public class SymbolServerServiceTest extends AbstractGenericTest {
|
|||||||
@Test
|
@Test
|
||||||
public void test_NoRemote() throws CancelledException {
|
public void test_NoRemote() throws CancelledException {
|
||||||
String payload = "testdummy";
|
String payload = "testdummy";
|
||||||
|
DummySymbolServer dummySymbolServer = new DummySymbolServer(payload);
|
||||||
SymbolServerService symbolServerService =
|
SymbolServerService symbolServerService =
|
||||||
new SymbolServerService(localSymbolStore1, List.of(new DummySymbolServer(payload)));
|
new SymbolServerService(localSymbolStore1, List.of(dummySymbolServer));
|
||||||
SymbolFileInfo searchPdb = SymbolFileInfo.fromValues("file1.pdb", "11223344", 0);
|
SymbolFileInfo searchPdb = SymbolFileInfo.fromValues("file1.pdb", "11223344", 0);
|
||||||
List<SymbolFileLocation> results =
|
List<SymbolFileLocation> results =
|
||||||
symbolServerService.find(searchPdb, FindOption.NO_OPTIONS, TaskMonitor.DUMMY);
|
symbolServerService.find(searchPdb, FindOption.NO_OPTIONS, TaskMonitor.DUMMY);
|
||||||
|
|||||||
@@ -31,8 +31,7 @@ import ghidra.framework.options.Options;
|
|||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import pdb.PdbPlugin;
|
import pdb.PdbPlugin;
|
||||||
import pdb.symbolserver.*;
|
import pdb.symbolserver.*;
|
||||||
import pdb.symbolserver.ui.ConfigPdbDialog;
|
import pdb.symbolserver.ui.*;
|
||||||
import pdb.symbolserver.ui.LoadPdbDialog;
|
|
||||||
|
|
||||||
public class PdbScreenShots extends GhidraScreenShotGenerator {
|
public class PdbScreenShots extends GhidraScreenShotGenerator {
|
||||||
|
|
||||||
@@ -64,7 +63,7 @@ public class PdbScreenShots extends GhidraScreenShotGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSymbolServerConfig_Screenshot() throws IOException {
|
public void testSymbolServerConfig_Screenshot() {
|
||||||
PdbPlugin.saveSymbolServerServiceConfig(null);
|
PdbPlugin.saveSymbolServerServiceConfig(null);
|
||||||
ConfigPdbDialog configPdbDialog = new ConfigPdbDialog();
|
ConfigPdbDialog configPdbDialog = new ConfigPdbDialog();
|
||||||
showDialogWithoutBlocking(tool, configPdbDialog);
|
showDialogWithoutBlocking(tool, configPdbDialog);
|
||||||
@@ -79,7 +78,7 @@ public class PdbScreenShots extends GhidraScreenShotGenerator {
|
|||||||
LocalSymbolStore localSymbolStore1 = new LocalSymbolStore(localSymbolStore1Root);
|
LocalSymbolStore localSymbolStore1 = new LocalSymbolStore(localSymbolStore1Root);
|
||||||
SameDirSymbolStore sameDirSymbolStore = new SameDirSymbolStore(null);
|
SameDirSymbolStore sameDirSymbolStore = new SameDirSymbolStore(null);
|
||||||
List<SymbolServer> symbolServers = List.of(sameDirSymbolStore,
|
List<SymbolServer> symbolServers = List.of(sameDirSymbolStore,
|
||||||
new HttpSymbolServer(URI.create("https://msdl.microsoft.com/download/symbols/")));
|
HttpSymbolServer.createTrusted("https://msdl.microsoft.com/download/symbols/"));
|
||||||
SymbolServerService symbolServerService =
|
SymbolServerService symbolServerService =
|
||||||
new SymbolServerService(localSymbolStore1, symbolServers);
|
new SymbolServerService(localSymbolStore1, symbolServers);
|
||||||
PdbPlugin.saveSymbolServerServiceConfig(symbolServerService);
|
PdbPlugin.saveSymbolServerServiceConfig(symbolServerService);
|
||||||
@@ -88,7 +87,7 @@ public class PdbScreenShots extends GhidraScreenShotGenerator {
|
|||||||
configPdbDialog.setSymbolServerService("/home/user/symbols", symbolServers);
|
configPdbDialog.setSymbolServerService("/home/user/symbols", symbolServers);
|
||||||
showDialogWithoutBlocking(tool, configPdbDialog);
|
showDialogWithoutBlocking(tool, configPdbDialog);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
captureDialog(ConfigPdbDialog.class, 410, 280);
|
captureDialog(ConfigPdbDialog.class, 520, 280);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -112,12 +111,29 @@ public class PdbScreenShots extends GhidraScreenShotGenerator {
|
|||||||
showDialogWithoutBlocking(tool, configPdbDialog);
|
showDialogWithoutBlocking(tool, configPdbDialog);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
runSwing(() -> {
|
runSwing(() -> {
|
||||||
|
configPdbDialog.setWellknownSymbolServers(createFakeWellKnowns());
|
||||||
configPdbDialog.pushAddLocationButton();
|
configPdbDialog.pushAddLocationButton();
|
||||||
});
|
});
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
captureMenu();
|
captureMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<WellKnownSymbolServerLocation> createFakeWellKnowns() {
|
||||||
|
// due to module dependencies, this screen shot test can't see the contents of the normal
|
||||||
|
// PDBURL file loaded from the 'z public release' module.
|
||||||
|
return List.of( // should be same as the PDB_SYMBOL_SERVERS.PDBURL file
|
||||||
|
new WellKnownSymbolServerLocation("", "https://msdl.microsoft.com/download/symbols/",
|
||||||
|
"WARNING: Check your organization's security policy before downloading files from the internet.",
|
||||||
|
"screen shot"),
|
||||||
|
new WellKnownSymbolServerLocation("",
|
||||||
|
"https://chromium-browser-symsrv.commondatastorage.googleapis.com",
|
||||||
|
"WARNING: Check your organization's security policy before downloading files from the internet.",
|
||||||
|
"screen shot"),
|
||||||
|
new WellKnownSymbolServerLocation("", "https://symbols.mozilla.org/",
|
||||||
|
"WARNING: Check your organization's security policy before downloading files from the internet.",
|
||||||
|
"screen shot"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLoadPdb_Advanced_NeedsConfig() {
|
public void testLoadPdb_Advanced_NeedsConfig() {
|
||||||
PdbPlugin.saveSymbolServerServiceConfig(null);
|
PdbPlugin.saveSymbolServerServiceConfig(null);
|
||||||
@@ -158,7 +174,7 @@ public class PdbScreenShots extends GhidraScreenShotGenerator {
|
|||||||
localSymbolStore1, SymbolFileInfo.fromValues("HelloWorld.pdb", GUID1_STR, 2)),
|
localSymbolStore1, SymbolFileInfo.fromValues("HelloWorld.pdb", GUID1_STR, 2)),
|
||||||
new SymbolFileLocation("HelloWorld.pdb", sameDirSymbolStoreWithFakePath,
|
new SymbolFileLocation("HelloWorld.pdb", sameDirSymbolStoreWithFakePath,
|
||||||
SymbolFileInfo.fromValues("HelloWorld.pdb", GUID1_STR, 1)));
|
SymbolFileInfo.fromValues("HelloWorld.pdb", GUID1_STR, 1)));
|
||||||
Set<FindOption> findOptions = FindOption.of(FindOption.ALLOW_REMOTE, FindOption.ANY_AGE);
|
Set<FindOption> findOptions = FindOption.of(FindOption.ALLOW_UNTRUSTED, FindOption.ANY_AGE);
|
||||||
runSwing(() -> {
|
runSwing(() -> {
|
||||||
loadPdbDialog.setSearchOptions(findOptions);
|
loadPdbDialog.setSearchOptions(findOptions);
|
||||||
loadPdbDialog.setSearchResults(symbolFileLocations, findOptions);
|
loadPdbDialog.setSearchResults(symbolFileLocations, findOptions);
|
||||||
|
|||||||
+2
-2
@@ -99,7 +99,7 @@ public class SymbolServerService2Test extends AbstractGhidraHeadedIntegrationTes
|
|||||||
|
|
||||||
List<SymbolFileLocation> results =
|
List<SymbolFileLocation> results =
|
||||||
symbolServerService.find(SymbolFileInfo.fromValues("test.pdb", "11223344", 1),
|
symbolServerService.find(SymbolFileInfo.fromValues("test.pdb", "11223344", 1),
|
||||||
FindOption.of(FindOption.ALLOW_REMOTE), TaskMonitor.DUMMY);
|
FindOption.of(FindOption.ALLOW_UNTRUSTED), TaskMonitor.DUMMY);
|
||||||
|
|
||||||
assertEquals(1, results.size());
|
assertEquals(1, results.size());
|
||||||
System.out.println(results.get(0).getLocationStr());
|
System.out.println(results.get(0).getLocationStr());
|
||||||
@@ -118,7 +118,7 @@ public class SymbolServerService2Test extends AbstractGhidraHeadedIntegrationTes
|
|||||||
|
|
||||||
List<SymbolFileLocation> results =
|
List<SymbolFileLocation> results =
|
||||||
symbolServerService.find(SymbolFileInfo.fromValues("test.pdb", "11223344", 1),
|
symbolServerService.find(SymbolFileInfo.fromValues("test.pdb", "11223344", 1),
|
||||||
FindOption.of(FindOption.ALLOW_REMOTE), TaskMonitor.DUMMY);
|
FindOption.of(FindOption.ALLOW_UNTRUSTED), TaskMonitor.DUMMY);
|
||||||
|
|
||||||
assertEquals(1, results.size());
|
assertEquals(1, results.size());
|
||||||
System.out.println(results.get(0).getLocationStr());
|
System.out.println(results.get(0).getLocationStr());
|
||||||
|
|||||||
Reference in New Issue
Block a user