Merge remote-tracking branch 'origin/GP-4017_dev747368_pdb_symbolserver_fsrl'

This commit is contained in:
Ryan Kurtz 2023-11-09 12:08:37 -05:00
commit 7fa03c9719
8 changed files with 350 additions and 19 deletions

View file

@ -0,0 +1,161 @@
/* ###
* 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 java.io.*;
import java.nio.file.Files;
import java.util.List;
import java.util.Set;
import org.apache.commons.io.FilenameUtils;
import ghidra.app.util.bin.ByteProvider;
import ghidra.formats.gfilesystem.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* Companion to the {@link SameDirSymbolStore}, handles the case where the imported binary
* was located in a container file (eg. zip file).
* <p>
* Instances of this class are conditionally created by the
* {@link SameDirSymbolStore#createInstance(String, SymbolServerInstanceCreatorContext) registry factory method}
* when it detects that the imported binary's {@link FSRL} isn't a simple local file.
*/
public class ContainerFileSymbolServer implements SymbolServer {
private final FileSystemService fsService;
private final FSRLRoot fsFSRL;
private final String subdir;
public ContainerFileSymbolServer(FSRL programFSRL) {
this.fsFSRL = programFSRL.getFS();
this.subdir = FilenameUtils.getFullPath(programFSRL.getPath());
this.fsService = FileSystemService.getInstance();
}
@Override
public String getName() {
return ".";
}
@Override
public String getDescriptiveName() {
return SameDirSymbolStore.PROGRAMS_IMPORT_LOCATION_DESCRIPTION_STR + " - " +
fsFSRL.toPrettyFullpathString();
}
@Override
public boolean isValid(TaskMonitor monitor) {
return true;
}
@Override
public boolean exists(String filename, TaskMonitor monitor) {
try (RefdFile file = getFile(filename, monitor)) {
return file != null;
}
catch (IOException e1) {
// fall thru
}
return false;
}
private RefdFile getFile(String filename, TaskMonitor monitor) {
try (FileSystemRef fsRef = fsService.getFilesystem(fsFSRL, monitor)) {
if (fsRef != null) {
GFileSystem fs = fsRef.getFilesystem();
String path = FSUtilities.appendPath(subdir, filename);
GFile file = fs.lookup(path);
if (file != null && !file.isDirectory()) {
return new RefdFile(fsRef.dup(), file);
}
}
}
catch (IOException | CancelledException e) {
// fall thru
}
return null;
}
@Override
public List<SymbolFileLocation> find(SymbolFileInfo fileInfo, Set<FindOption> findOptions,
TaskMonitor monitor) {
try (RefdFile fref = getFile(fileInfo.getName(), monitor)) {
// TODO: need to be able to read info from candidate pdb file using some type of stream
if (fref != null) {
GFile file = fref.file;
GFileSystem fs = file.getFilesystem();
try (ByteProvider bp = fs.getByteProvider(file, monitor)) {
File tmpPdbFile = fsService.createPlaintextTempFile(bp, "temp_pdb", monitor);
File tmpPdbDir =
Files.createTempDirectory(tmpPdbFile.getParentFile().toPath(), "temp_pdb")
.toFile();
File destPdbFile = new File(tmpPdbDir, file.getName()).getCanonicalFile();
if (!destPdbFile.getParentFile().equals(tmpPdbDir)) {
throw new IOException("Bad filename: " + destPdbFile);
}
if (!tmpPdbFile.renameTo(destPdbFile)) {
throw new IOException(
"Unable to move file: " + tmpPdbFile + " to " + destPdbFile);
}
SymbolFileInfo foundInfo = SymbolFileInfo.fromFile(destPdbFile, monitor);
destPdbFile.delete();
tmpPdbDir.delete();
return List.of(new SymbolFileLocation(file.getName(), this, foundInfo));
}
}
}
catch (IOException | CancelledException e) {
// fall thru
}
return List.of();
}
@Override
public SymbolServerInputStream getFileStream(String filename, TaskMonitor monitor)
throws IOException {
try (RefdFile fref = getFile(filename, monitor)) {
if (fref != null) {
GFile file = fref.file;
InputStream is = file.getFilesystem().getInputStream(file, monitor);
is = new RefdInputStream(fref.fsRef.dup(), is);
return new SymbolServerInputStream(is, file.getLength());
}
}
catch (CancelledException e) {
// fall thru
}
throw new IOException();
}
@Override
public String getFileLocation(String filename) {
return fsFSRL.withPath(filename).toPrettyFullpathString();
}
@Override
public boolean isLocal() {
return true;
}
@Override
public String toString() {
return "ContainerFileSymbolServer: [ fsrl: %s ]".formatted(fsFSRL);
}
}

View file

@ -18,6 +18,7 @@ package pdb.symbolserver;
import java.io.*;
import java.util.*;
import ghidra.formats.gfilesystem.FSRL;
import ghidra.util.task.TaskMonitor;
/**
@ -61,6 +62,23 @@ public class SameDirSymbolStore implements SymbolStore {
return symbolFileLocation;
}
/**
* Creates a {@link SymbolServer} for the "Program's Import Location" item. May return either
* a {@link SameDirSymbolStore} instance, or a {@link ContainerFileSymbolServer}.
*
* @param locationString will be "."
* @param context {@link SymbolServerInstanceCreatorContext}
* @return new {@link SymbolServer}
*/
public static SymbolServer createInstance(String locationString,
SymbolServerInstanceCreatorContext context) {
FSRL programFSRL = context.getProgramFSRL();
if (programFSRL != null && programFSRL.getNestingDepth() != 1) {
return new ContainerFileSymbolServer(programFSRL);
}
return new SameDirSymbolStore(context.getRootDir());
}
private final File rootDir;
/**

View file

@ -17,6 +17,11 @@ package pdb.symbolserver;
import java.io.File;
import org.apache.commons.io.FilenameUtils;
import ghidra.formats.gfilesystem.FSRL;
import ghidra.program.model.listing.Program;
/**
* Context for the {@link SymbolServerInstanceCreatorRegistry} when creating new
* {@link SymbolServer} instances.
@ -30,6 +35,7 @@ import java.io.File;
*/
public class SymbolServerInstanceCreatorContext {
private final File rootDir;
private final FSRL programFSRL;
private final SymbolServerInstanceCreatorRegistry symbolServerInstanceCreatorRegistry;
SymbolServerInstanceCreatorContext(
@ -37,9 +43,16 @@ public class SymbolServerInstanceCreatorContext {
this(null, symbolServerInstanceCreatorRegistry);
}
SymbolServerInstanceCreatorContext(File rootDir,
SymbolServerInstanceCreatorContext(Program program,
SymbolServerInstanceCreatorRegistry symbolServerInstanceCreatorRegistry) {
this.rootDir = rootDir;
if (program != null) {
this.programFSRL = FSRL.fromProgram(program);
this.rootDir = new File(FilenameUtils.getFullPath(program.getExecutablePath()));
}
else {
this.programFSRL = null;
this.rootDir = null;
}
this.symbolServerInstanceCreatorRegistry = symbolServerInstanceCreatorRegistry;
}
@ -61,4 +74,13 @@ public class SymbolServerInstanceCreatorContext {
return rootDir;
}
/**
* Returns the FSRL of imported binary.
*
* @return {@link FSRL} of the imported binary, or null if not present
*/
public FSRL getProgramFSRL() {
return programFSRL;
}
}

View file

@ -15,13 +15,10 @@
*/
package pdb.symbolserver;
import java.util.*;
import java.util.function.Predicate;
import java.io.File;
import java.net.URI;
import org.apache.commons.io.FilenameUtils;
import java.util.*;
import java.util.function.Predicate;
import ghidra.program.model.listing.Program;
import ghidra.util.Msg;
@ -163,8 +160,7 @@ public class SymbolServerInstanceCreatorRegistry {
* @return new {@link SymbolServerInstanceCreatorContext}
*/
public SymbolServerInstanceCreatorContext getContext(Program program) {
File exeLocation = new File(FilenameUtils.getFullPath(program.getExecutablePath()));
return new SymbolServerInstanceCreatorContext(exeLocation, this);
return new SymbolServerInstanceCreatorContext(program, this);
}
private void registerDefaultSymbolServerInstanceCreators() {
@ -173,7 +169,7 @@ public class SymbolServerInstanceCreatorRegistry {
registerSymbolServerInstanceCreator(100, HttpSymbolServer::isHttpSymbolServerLocation,
(loc, context) -> new HttpSymbolServer(URI.create(loc)));
registerSymbolServerInstanceCreator(200, SameDirSymbolStore::isSameDirLocation,
(loc, context) -> new SameDirSymbolStore(context.getRootDir()));
SameDirSymbolStore::createInstance);
registerSymbolServerInstanceCreator(300, LocalSymbolStore::isLocalSymbolStoreLocation,
(loc, context) -> new LocalSymbolStore(new File(loc)));
}

View file

@ -787,10 +787,9 @@ public class LoadPdbDialog extends DialogComponentProvider {
return null;
}
SymbolServer symbolServer = symbolFileLocation.getSymbolServer();
if (!(symbolServer instanceof SymbolStore)) {
if (!(symbolServer instanceof SymbolStore symbolStore)) {
return null;
}
SymbolStore symbolStore = (SymbolStore) symbolServer;
File file = symbolStore.getFile(symbolFileLocation.getPath());
return SymbolStore.isCompressedFilename(file.getName()) ? null : file;
}

View file

@ -91,10 +91,9 @@ class SymbolServerPanel extends JPanel {
SymbolServerService temporarySymbolServerService =
PdbPlugin.getSymbolServerService(symbolServerInstanceCreatorContext);
if (temporarySymbolServerService.getSymbolStore() instanceof LocalSymbolStore) {
setSymbolStorageLocation(
((LocalSymbolStore) temporarySymbolServerService.getSymbolStore()).getRootDir(),
false);
if (temporarySymbolServerService
.getSymbolStore() instanceof LocalSymbolStore tempLocalSymbolStore) {
setSymbolStorageLocation(tempLocalSymbolStore.getRootDir(), false);
}
tableModel.addSymbolServers(temporarySymbolServerService.getSymbolServers());
setConfigChanged(false);
@ -368,8 +367,8 @@ class SymbolServerPanel extends JPanel {
SymbolServer symbolServer =
symbolServerInstanceCreatorContext.getSymbolServerInstanceCreatorRegistry()
.newSymbolServer(firstSearchPath, symbolServerInstanceCreatorContext);
if (symbolServer instanceof LocalSymbolStore &&
((LocalSymbolStore) symbolServer).isValid()) {
if (symbolServer instanceof LocalSymbolStore localSymbolStore &&
localSymbolStore.isValid()) {
int choice = OptionDialog.showYesNoCancelDialog(this, "Set Symbol Storage Location",
"Set symbol storage location to " + firstSearchPath + "?");
if (choice == OptionDialog.CANCEL_OPTION) {
@ -378,7 +377,7 @@ class SymbolServerPanel extends JPanel {
if (choice == OptionDialog.YES_OPTION) {
symbolServerPaths.remove(0);
configChanged = true;
setSymbolStorageLocation(((LocalSymbolStore) symbolServer).getRootDir(), true);
setSymbolStorageLocation(localSymbolStore.getRootDir(), true);
symbolStorageLocationTextField.setText(symbolServer.getName());
}
}