Merge remote-tracking branch 'origin/GP-42_dev747368_PdbSymbolServer_for_10'

This commit is contained in:
ghidra1
2021-05-18 21:42:23 -04:00
97 changed files with 7862 additions and 3935 deletions

View File

@@ -15,102 +15,183 @@
*/
package help.screenshot;
import java.awt.Dimension;
import java.awt.Window;
import java.util.ArrayList;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.Set;
import org.junit.Test;
import org.apache.commons.io.FilenameUtils;
import org.junit.*;
import docking.widgets.dialogs.ObjectChooserDialog;
import ghidra.app.util.pdb.PdbLocator;
import ghidra.util.Msg;
import pdb.URLChoice;
import ghidra.app.util.bin.format.pdb.PdbInfo;
import ghidra.app.util.bin.format.pdb.PdbInfoDotNet;
import ghidra.app.util.datatype.microsoft.GUID;
import ghidra.framework.options.Options;
import ghidra.program.model.listing.Program;
import pdb.PdbPlugin;
import pdb.symbolserver.*;
import pdb.symbolserver.ui.ConfigPdbDialog;
import pdb.symbolserver.ui.LoadPdbDialog;
public class PdbScreenShots extends GhidraScreenShotGenerator {
@Test
public void testPdbOrXmlDialog() throws Exception {
private static final String GUID1_STR = "012345670123012301230123456789AB";
performAction("Download_PDB_File", "PdbSymbolServerPlugin", false);
private int tx;
private File temporaryDir;
Window pdbDialog = waitForWindow("pdb or pdb.xml");
pdbDialog.setSize(new Dimension(750, 200));
captureWindow(pdbDialog);
@Override
@Before
public void setUp() throws Exception {
super.setUp();
pressButtonByText(pdbDialog, "Cancel");
temporaryDir = createTempDirectory("example_pdb");
tx = program.startTransaction("set analyzed flag");
Options proplist = program.getOptions(Program.PROGRAM_INFO);
proplist.setBoolean(Program.ANALYZED, false);
PdbInfo pdbInfo = PdbInfoDotNet.fromValues("HelloWorld.pdb", 1, new GUID(GUID1_STR));
pdbInfo.serializeToOptions(proplist);
proplist.setString("Executable Location",
new File(temporaryDir, program.getName()).getPath());
}
@Override
@After
public void tearDown() throws Exception {
program.endTransaction(tx, false);
super.tearDown();
}
@Test
public void testPeSpecifiedPathDialog() throws Exception {
performAction("Download_PDB_File", "PdbSymbolServerPlugin", false);
Window pdbDialog = waitForWindow("pdb or pdb.xml");
pressButtonByText(pdbDialog, "PDB");
Window peSpecifiedPathDialog = waitForWindow("PE-specified PDB Path");
captureWindow(peSpecifiedPathDialog);
pressButtonByText(peSpecifiedPathDialog, "Cancel");
public void testSymbolServerConfig_Screenshot() throws IOException {
PdbPlugin.saveSymbolServerServiceConfig(null);
ConfigPdbDialog configPdbDialog = new ConfigPdbDialog();
showDialogWithoutBlocking(tool, configPdbDialog);
waitForSwing();
captureDialog(ConfigPdbDialog.class);
}
@Test
public void testSymbolServerURLDialog() throws Exception {
// Set up for local directory
PdbLocator.setDefaultPdbSymbolsDir(getTestDataDirectory());
performAction("Download_PDB_File", "PdbSymbolServerPlugin", false);
Window pdbDialog = waitForWindow("pdb or pdb.xml");
pressButtonByText(pdbDialog, "PDB");
Window peSpecifiedPathDialog = waitForWindow("PE-specified PDB Path");
pressButtonByText(peSpecifiedPathDialog, "Yes");
Window saveLocationDialog = waitForWindow("Select Location to Save Retrieved File");
pressButtonByText(saveLocationDialog, "OK");
Window urlDialog = waitForWindow("Symbol Server URL");
urlDialog.setSize(new Dimension(850, 135));
captureWindow(urlDialog);
pressButtonByText(urlDialog, "Cancel");
public void testLoadPdb_Initial_Screenshot() throws IOException {
LoadPdbDialog loadPdbDialog = new LoadPdbDialog(program);
showDialogWithoutBlocking(tool, loadPdbDialog);
captureDialog(loadPdbDialog);
pressButtonByText(loadPdbDialog, "Cancel");
}
@Test
public void testKnownSymbolServerURLsDialog() throws Exception {
List<URLChoice> urlChoices = new ArrayList<>();
urlChoices.add(new URLChoice("Internet", "https://msdl.microsoft.com/download/symbols"));
urlChoices.add(new URLChoice("My Network", "https://my_symbol_server.my.org"));
final ObjectChooserDialog<URLChoice> urlDialog = new ObjectChooserDialog<>("Choose a URL",
URLChoice.class, urlChoices, "getNetwork", "getUrl");
public void testSymbolServerConfig_AddButtonMenu() throws IOException {
File localSymbolStore1Root = new File(temporaryDir, "symbols");
LocalSymbolStore.create(localSymbolStore1Root, 1);
LocalSymbolStore localSymbolStore1 =
new LocalSymbolStoreWithFakePath(localSymbolStore1Root, "/home/user/symbols");
SymbolServerService symbolServerService =
new SymbolServerService(localSymbolStore1, List.of());
PdbPlugin.saveSymbolServerServiceConfig(symbolServerService);
LoadPdbDialog choosePdbDialog = new LoadPdbDialog(program);
showDialogWithoutBlocking(tool, choosePdbDialog);
waitForSwing();
pressButtonByText(choosePdbDialog, "Advanced >>");
runSwing(() -> {
// Do nothing
choosePdbDialog.pushAddLocationBution();
});
showDialogWithoutBlocking(tool, urlDialog);
captureDialog();
pressButtonByText(urlDialog, "Cancel");
waitForSwing();
captureMenu();
}
@Test
public void testSuccessDialog() throws Exception {
public void testLoadPdb_Advanced_NeedsConfig() throws IOException {
PdbPlugin.saveSymbolServerServiceConfig(null);
LoadPdbDialog choosePdbDialog = new LoadPdbDialog(program);
showDialogWithoutBlocking(tool, choosePdbDialog);
waitForSwing();
pressButtonByText(choosePdbDialog, "Advanced >>");
waitForSwing();
captureDialog(LoadPdbDialog.class);
pressButtonByText(choosePdbDialog, "Cancel");
}
// Can't really get success message without actually downloading a file.
// So, fake out the message by showing the same sort of dialog the user would see.
Msg.showInfo(getClass(), null, "File Retrieved",
"Downloaded and saved file 'example.pdb' to \n" +
"C:\\Symbols\\example.pdb\\1123A456B7889012C3DDFA4556789B011");
@Test
public void testLoadPdb_Advanced_Screenshot() throws IOException {
// Show the advanced side of the LoadPdbDialog, with
// some faked search locations and search results so we
// can have pretty paths
File localSymbolStore1Root = new File(temporaryDir, "symbols");
LocalSymbolStore.create(localSymbolStore1Root, 1);
LocalSymbolStore localSymbolStore1 =
new LocalSymbolStoreWithFakePath(localSymbolStore1Root, "/home/user/symbols");
SameDirSymbolStoreWithFakePath sameDirSymbolStoreWithFakePath =
new SameDirSymbolStoreWithFakePath(temporaryDir, "/home/user/examples");
List<SymbolServer> symbolServers = List.of(sameDirSymbolStoreWithFakePath,
new HttpSymbolServer(URI.create("https://msdl.microsoft.com/download/symbols/")));
SymbolServerService symbolServerService =
new SymbolServerService(localSymbolStore1, symbolServers);
PdbPlugin.saveSymbolServerServiceConfig(symbolServerService);
Window successDialog = waitForWindow("File Retrieved");
captureWindow(successDialog);
LoadPdbDialog loadPdbDialog = new LoadPdbDialog(program);
showDialogWithoutBlocking(tool, loadPdbDialog);
waitForSwing();
pressButtonByText(loadPdbDialog, "Advanced >>");
List<SymbolFileLocation> symbolFileLocations = List.of(
new SymbolFileLocation("HelloWorld.pdb/" + GUID1_STR + "1/HelloWorld.pdb",
localSymbolStore1, SymbolFileInfo.fromValues("HelloWorld.pdb", GUID1_STR, 1)),
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)));
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);
pressButtonByText(loadPdbDialog, "Cancel");
}
pressButtonByText(successDialog, "OK");
private static class LocalSymbolStoreWithFakePath extends LocalSymbolStore {
private String fakeRootDirPath;
public LocalSymbolStoreWithFakePath(File rootDir, String fakeRootDirPath) {
super(rootDir);
this.fakeRootDirPath = fakeRootDirPath;
}
@Override
public String getDescriptiveName() {
return fakeRootDirPath;
}
@Override
public String getFileLocation(String filename) {
return FilenameUtils.concat(fakeRootDirPath, filename);
}
}
private static class SameDirSymbolStoreWithFakePath extends SameDirSymbolStore {
private String fakeRootDirPath;
public SameDirSymbolStoreWithFakePath(File rootDir, String fakeRootDirPath) {
super(rootDir);
this.fakeRootDirPath = fakeRootDirPath;
}
@Override
public String getDescriptiveName() {
return String.format(PROGRAMS_IMPORT_LOCATION_DESCRIPTION_STR + " - %s",
fakeRootDirPath);
}
@Override
public String getFileLocation(String filename) {
return FilenameUtils.concat(fakeRootDirPath, filename);
}
}
}

View File

@@ -0,0 +1,138 @@
/* ###
* 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;
import static org.junit.Assert.assertEquals;
import java.util.List;
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FilenameUtils;
import org.junit.Before;
import org.junit.Test;
import com.google.common.io.BaseEncoding;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import utilities.util.FileUtilities;
/**
* Tests for Pdb SymbolServer stuff that need to be in the Integration module because they depend
* on FileFormat's file system stuff to decompress .cab files
*/
public class SymbolServerService2Test extends AbstractGhidraHeadedIntegrationTest {
private File temporaryDir;
private File localSymbolStore1Root;
private LocalSymbolStore localSymbolStore1;
// Bytes for a very small .cab file that contains a singleton file named 'test.pdb' with
// contents of "test"
byte[] smallCabFileBytes = BaseEncoding.base16()
.decode(("4d5343460000000055000000000000002c000000000000000301010001" +
"00000000000000450000000100010004000000000000000000a248bc5c2000746573742e7064620" +
"066652e4908000400434b2b492d2e0100").toUpperCase());
private File mkFile(File file, byte[] bytes) throws IOException {
FileUtilities.checkedMkdirs(file.getParentFile());
FileUtilities.writeBytes(file, bytes);
return file;
}
@Before
public void setup() throws IOException {
temporaryDir = createTempDirectory("symbolservers");
localSymbolStore1Root = new File(temporaryDir, "symbols1");
LocalSymbolStore.create(localSymbolStore1Root, 1);
localSymbolStore1 = new LocalSymbolStore(localSymbolStore1Root);
}
@Test
public void testLocalCab() throws IOException, CancelledException {
mkFile(new File(localSymbolStore1Root, "test.pdb/112233441/test.pd_"), smallCabFileBytes);
SymbolServerService symbolServerService =
new SymbolServerService(localSymbolStore1, List.of());
List<SymbolFileLocation> results =
symbolServerService.find(SymbolFileInfo.fromValues("test.pdb", "11223344", 1),
FindOption.NO_OPTIONS, TaskMonitor.DUMMY);
assertEquals(1, results.size());
assertEquals("test.pd_", FilenameUtils.getName(results.get(0).getPath()));
File pdbFile = symbolServerService.getSymbolFile(results.get(0), TaskMonitor.DUMMY);
assertEquals("test\n" /* extra \n because FileUtilities.getText() adds it */,
FileUtilities.getText(pdbFile));
// search again and we should only find the now decompressed pdb file
List<SymbolFileLocation> results2 =
symbolServerService.find(SymbolFileInfo.fromValues("test.pdb", "11223344", 1),
FindOption.NO_OPTIONS, TaskMonitor.DUMMY);
assertEquals(1, results2.size());
assertEquals("test.pdb", FilenameUtils.getName(results2.get(0).getPath()));
}
@Test
public void testRemoteCab() throws IOException, CancelledException {
SymbolServerService symbolServerService =
new SymbolServerService(localSymbolStore1,
List.of(new DummySymbolServer(smallCabFileBytes, true)));
List<SymbolFileLocation> results =
symbolServerService.find(SymbolFileInfo.fromValues("test.pdb", "11223344", 1),
FindOption.of(FindOption.ALLOW_REMOTE), TaskMonitor.DUMMY);
assertEquals(1, results.size());
System.out.println(results.get(0).getLocationStr());
File pdbFile = symbolServerService.getSymbolFile(results.get(0), TaskMonitor.DUMMY);
assertEquals("test\n" /* extra \n because FileUtilities.getText() adds it */,
FileUtilities.getText(pdbFile));
}
@Test
public void testRemoteCabAlreadyExistLocal() throws IOException, CancelledException {
SymbolServerService symbolServerService =
new SymbolServerService(localSymbolStore1,
List.of(new DummySymbolServer(smallCabFileBytes, true)));
List<SymbolFileLocation> results =
symbolServerService.find(SymbolFileInfo.fromValues("test.pdb", "11223344", 1),
FindOption.of(FindOption.ALLOW_REMOTE), TaskMonitor.DUMMY);
assertEquals(1, results.size());
System.out.println(results.get(0).getLocationStr());
// cheese the file into the local symbol store after the remote file has been found
// but before it has been downloaded
mkFile(new File(localSymbolStore1Root, "test.pdb/112233441/test.pdb"),
"nottest".getBytes());
// normally this would download the remote file and decompress it
File pdbFile = symbolServerService.getSymbolFile(results.get(0), TaskMonitor.DUMMY);
// ensure that the original file wasn't overwritten by the new file
assertEquals("nottest\n" /* extra \n because FileUtilities.getText() adds it */,
FileUtilities.getText(pdbFile));
}
}