mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-08-08 07:40:39 -09:00
Merge remote-tracking branch 'origin/patch'
This commit is contained in:
@@ -36,7 +36,6 @@ import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class IsfServer extends Thread {
|
||||
@@ -101,13 +100,13 @@ public class IsfServer extends Thread {
|
||||
try {
|
||||
DataTypeManager dtm;
|
||||
if (ns.endsWith(".gdt")) {
|
||||
dtm = openAsArchive(ns);
|
||||
dtm = openAsDataTypeArchive(ns);
|
||||
}
|
||||
else if (ns.endsWith(".gzf")) {
|
||||
dtm = openAsDatabase(ns);
|
||||
dtm = openAsProgramDatabase(ns);
|
||||
}
|
||||
else {
|
||||
dtm = openAsDomainFile(ns);
|
||||
dtm = openAsProgramFile(ns);
|
||||
}
|
||||
managers.put(ns, dtm);
|
||||
return dtm;
|
||||
@@ -119,43 +118,43 @@ public class IsfServer extends Thread {
|
||||
}
|
||||
}
|
||||
|
||||
private DataTypeManager openAsDomainFile(String ns) throws Exception {
|
||||
private DataTypeManager openAsProgramFile(String ns) throws Exception {
|
||||
ProjectData projectData = project.getProjectData();
|
||||
DomainFile df = projectData.getFile(ns);
|
||||
if (!Program.class.isAssignableFrom(df.getDomainObjectClass())) {
|
||||
throw new IOException("File does not correspond to Program content: " + ns);
|
||||
}
|
||||
|
||||
// FIXME: Need to track and release Program instance after DTM use is complete (GP-6895)
|
||||
Program program = (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
|
||||
return program.getDataTypeManager();
|
||||
}
|
||||
|
||||
private DataTypeManager openAsArchive(String ns) throws Exception {
|
||||
private DataTypeManager openAsDataTypeArchive(String ns) throws Exception {
|
||||
File gdt = new File(ns);
|
||||
return FileDataTypeManager.openFileArchive(gdt, false);
|
||||
}
|
||||
|
||||
private DataTypeManager openAsDatabase(String ns) throws Exception {
|
||||
private DataTypeManager openAsProgramDatabase(String ns) throws Exception {
|
||||
File gzf = new File(ns);
|
||||
TaskMonitor dummy = TaskMonitor.DUMMY;
|
||||
PackedDatabase db = PackedDatabase.getPackedDatabase(gzf, dummy);
|
||||
|
||||
DBHandle dbh = db.openForUpdate(dummy);
|
||||
ProgramDB p = null;
|
||||
|
||||
Program p;
|
||||
boolean success = false;
|
||||
try {
|
||||
p = new ProgramDB(dbh, OpenMode.UPDATE, dummy, this);
|
||||
}
|
||||
catch (VersionException e) {
|
||||
if (!e.isUpgradable()) {
|
||||
throw new RuntimeException(p + " uses an older version and is not upgradable.");
|
||||
}
|
||||
p = new ProgramDB(dbh, OpenMode.UPGRADE, dummy, this);
|
||||
success = true;
|
||||
}
|
||||
finally {
|
||||
dbh.close();
|
||||
}
|
||||
|
||||
dbh = db.openForUpdate(dummy);
|
||||
p = new ProgramDB(dbh, OpenMode.UPGRADE, dummy, this);
|
||||
|
||||
if (!p.isChanged()) {
|
||||
throw new RuntimeException(p + " uses an older version and was not upgraded.");
|
||||
if (!success) {
|
||||
dbh.close();
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Need to track and release Program instance after DTM use is complete (GP-6895)
|
||||
return p.getListing().getDataTypeManager();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/* ###
|
||||
* 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 ghidra.app.plugin.core.debug.export;
|
||||
|
||||
import ghidra.app.util.exporter.AsciiExporter;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.trace.model.Trace;
|
||||
|
||||
public class TraceViewAsciiExporter extends AsciiExporter {
|
||||
@Override
|
||||
public boolean canExportDomainObject(Class<? extends DomainObject> domainObjectClass) {
|
||||
return Trace.class.isAssignableFrom(domainObjectClass);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/* ###
|
||||
* 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 ghidra.app.plugin.core.debug.export;
|
||||
|
||||
import ghidra.app.util.exporter.BinaryExporter;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.trace.model.Trace;
|
||||
|
||||
public class TraceViewBinaryExporter extends BinaryExporter {
|
||||
@Override
|
||||
public boolean canExportDomainObject(Class<? extends DomainObject> domainObjectClass) {
|
||||
return Trace.class.isAssignableFrom(domainObjectClass);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/* ###
|
||||
* 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 ghidra.app.plugin.core.debug.export;
|
||||
|
||||
import ghidra.app.util.exporter.HtmlExporter;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.trace.model.Trace;
|
||||
|
||||
public class TraceViewHtmlExporter extends HtmlExporter {
|
||||
@Override
|
||||
public boolean canExportDomainObject(Class<? extends DomainObject> domainObjectClass) {
|
||||
return Trace.class.isAssignableFrom(domainObjectClass);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/* ###
|
||||
* 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 ghidra.app.plugin.core.debug.export;
|
||||
|
||||
import ghidra.app.util.exporter.IntelHexExporter;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.trace.model.Trace;
|
||||
|
||||
public class TraceViewIntelHexExporter extends IntelHexExporter {
|
||||
@Override
|
||||
public boolean canExportDomainObject(Class<? extends DomainObject> domainObjectClass) {
|
||||
return Trace.class.isAssignableFrom(domainObjectClass);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/* ###
|
||||
* 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 ghidra.app.plugin.core.debug.export;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ghidra.app.util.*;
|
||||
import ghidra.app.util.exporter.XmlExporter;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.trace.model.Trace;
|
||||
|
||||
// TODO: perhaps getApplicableExporters should use domainObject's class, not file's object class.
|
||||
// TODO: Where un-supported, be less abrasive, e.g., present empty managers.
|
||||
public class TraceViewXmlExporter extends XmlExporter {
|
||||
private final Map<String, Boolean> hideOpts = Map.of(
|
||||
"Properties", false,
|
||||
"Relocation Table", false,
|
||||
"External Libraries", false);
|
||||
|
||||
@Override
|
||||
public boolean canExportDomainObject(Class<? extends DomainObject> domainObjectClass) {
|
||||
return Trace.class.isAssignableFrom(domainObjectClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Option> getOptions(DomainObjectService domainObjectService) {
|
||||
List<Option> options = super.getOptions(domainObjectService);
|
||||
return options.stream()
|
||||
.filter(o -> !hideOpts.keySet().contains(o.getName()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOptions(List<Option> options) throws OptionException {
|
||||
List<Option> opts = new ArrayList<>(options);
|
||||
options.stream().filter(o -> !hideOpts.keySet().contains(o.getName())).forEach(opts::add);
|
||||
for (Map.Entry<String, Boolean> ent : hideOpts.entrySet()) {
|
||||
opts.add(Option.newBoolean(ent.getKey()).value(ent.getValue()).build());
|
||||
}
|
||||
super.setOptions(opts);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
/* ###
|
||||
* 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 ghidra.app.plugin.core.debug.gui.export;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.builder.ActionBuilder;
|
||||
import docking.tool.ToolConstants;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.filechooser.GhidraFileChooser;
|
||||
import docking.widgets.filechooser.GhidraFileChooserMode;
|
||||
import ghidra.app.context.ProgramActionContext;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
||||
import ghidra.app.plugin.core.debug.utils.GztExporter;
|
||||
import ghidra.app.plugin.core.help.AboutDomainObjectUtils;
|
||||
import ghidra.app.services.CodeViewerService;
|
||||
import ghidra.app.services.DebuggerTraceManagerService;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.framework.preferences.Preferences;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.ProgramSelection;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.program.TraceProgramView;
|
||||
import ghidra.util.Swing;
|
||||
import ghidra.util.filechooser.ExtensionFileFilter;
|
||||
import ghidra.util.filechooser.GhidraFileFilter;
|
||||
import ghidra.util.task.TaskLauncher;
|
||||
|
||||
//@formatter:off
|
||||
@PluginInfo(
|
||||
status = PluginStatus.RELEASED,
|
||||
category = PluginCategoryNames.DEBUGGER,
|
||||
packageName = DebuggerPluginPackage.NAME,
|
||||
shortDescription = "Export Debugger Trace",
|
||||
description = "This plugin exports a Debugger Trace to an external file.",
|
||||
servicesRequired = {
|
||||
DebuggerTraceManagerService.class
|
||||
}
|
||||
)
|
||||
//@formatter:on
|
||||
public class TraceExportPlugin extends Plugin {
|
||||
|
||||
private DebuggerTraceManagerService traceMgrSvc;
|
||||
|
||||
public TraceExportPlugin(PluginTool tool) {
|
||||
super(tool);
|
||||
createToolAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
traceMgrSvc = tool.getService(DebuggerTraceManagerService.class);
|
||||
}
|
||||
|
||||
private void createToolAction() {
|
||||
|
||||
new ActionBuilder("Export Trace", getName())
|
||||
.description("Export Debbuger Trace as compressed GZT file.")
|
||||
// .helpLocation(new HelpLocation("ExporterPlugin", "Export"))
|
||||
.menuPath(ToolConstants.MENU_FILE, "Export Trace...")
|
||||
.menuGroup("DomainObjectSaveExport")
|
||||
.enabledWhen(c -> getTrace(c) != null)
|
||||
.onAction(c -> exportTrace(c))
|
||||
.buildAndInstall(tool);
|
||||
}
|
||||
|
||||
private Trace getTrace(ActionContext ctx) {
|
||||
if (ctx instanceof ProgramActionContext programCtx) {
|
||||
Program p = programCtx.getProgram();
|
||||
if (p instanceof TraceProgramView traceProgrmView) {
|
||||
return traceProgrmView.getTrace();
|
||||
}
|
||||
}
|
||||
return traceMgrSvc.getCurrentTrace();
|
||||
}
|
||||
|
||||
private void exportTrace(ActionContext ctx) {
|
||||
|
||||
Trace trace = getTrace(ctx);
|
||||
if (trace == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
File file = chooseDestinationFile(ctx);
|
||||
if (file == null) {
|
||||
return; // file chooser cancelled
|
||||
}
|
||||
|
||||
File gztFile = file;
|
||||
GztExporter exporter = new GztExporter();
|
||||
|
||||
TaskLauncher.launchModal("Export Trace", m -> {
|
||||
exporter.export(gztFile, trace, null, m);
|
||||
});
|
||||
|
||||
displaySummaryResults(trace, gztFile, exporter.getMessageLog());
|
||||
}
|
||||
|
||||
private File chooseDestinationFile(ActionContext ctx) {
|
||||
GhidraFileChooser chooser = new GhidraFileChooser(ctx.getSourceComponent());
|
||||
chooser.setCurrentDirectory(getLastExportDirectory());
|
||||
chooser.setTitle("Select Trace Output File");
|
||||
chooser.setApproveButtonText("Export Trace");
|
||||
chooser.setApproveButtonToolTipText("Export Debugger Trace");
|
||||
chooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY);
|
||||
chooser.setSelectedFileFilter(GhidraFileFilter.ALL);
|
||||
chooser.setFileFilter(
|
||||
new ExtensionFileFilter(GztExporter.EXTENSION, GztExporter.NAME));
|
||||
|
||||
File file;
|
||||
while (true) {
|
||||
file = chooser.getSelectedFile();
|
||||
if (file == null) {
|
||||
break;
|
||||
}
|
||||
setLastExportDirectory(file);
|
||||
if (!file.getName().endsWith(GztExporter.SUFFIX)) {
|
||||
file = new File(file.getParent(), file.getName() + GztExporter.SUFFIX);
|
||||
}
|
||||
if (!file.exists()) {
|
||||
break; // continue with file return
|
||||
}
|
||||
if (!file.isFile()) {
|
||||
chooser.setStatusText("Invalid File Selection");
|
||||
continue;
|
||||
}
|
||||
int rc = OptionDialog.showYesNoCancelDialog(chooser.getComponent(),
|
||||
"Overwrite Confirmation",
|
||||
"Overwrite Trace export file?\n" + file);
|
||||
if (rc == OptionDialog.YES_OPTION) {
|
||||
break; // continue with file return
|
||||
}
|
||||
file = null; // don't overwrite
|
||||
if (rc != OptionDialog.NO_OPTION) {
|
||||
break; // continue with null return / export cancelled
|
||||
}
|
||||
}
|
||||
chooser.dispose();
|
||||
return file;
|
||||
}
|
||||
|
||||
private File getLastExportDirectory() {
|
||||
String lastDirStr = Preferences.getProperty(Preferences.LAST_EXPORT_DIRECTORY,
|
||||
System.getProperty("user.home"), true);
|
||||
return new File(lastDirStr);
|
||||
}
|
||||
|
||||
private void setLastExportDirectory(File file) {
|
||||
Preferences.setProperty(Preferences.LAST_EXPORT_DIRECTORY, file.getParent());
|
||||
Preferences.store();
|
||||
}
|
||||
|
||||
protected ProgramSelection getSelection() {
|
||||
CodeViewerService service = tool.getService(CodeViewerService.class);
|
||||
if (service != null) {
|
||||
return service.getCurrentSelection();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void displaySummaryResults(Trace trace, File outputFile, MessageLog log) {
|
||||
|
||||
StringBuffer resultsBuffer = new StringBuffer();
|
||||
|
||||
resultsBuffer.append("Destination file: " + outputFile.getAbsolutePath() + "\n\n");
|
||||
resultsBuffer.append("Destination file Size: " + outputFile.length() + "\n");
|
||||
resultsBuffer.append("Format: " + GztExporter.NAME + "\n\n");
|
||||
resultsBuffer.append(log.toString());
|
||||
|
||||
Map<String, String> metadata = trace.getMetadata();
|
||||
|
||||
Swing.runLater(() -> {
|
||||
AboutDomainObjectUtils.displayInformation(tool, trace.getDomainFile(), metadata,
|
||||
"Trace Export Results Summary", resultsBuffer.toString(), null);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -625,18 +625,9 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
|
||||
return newCurrent;
|
||||
}
|
||||
|
||||
protected String getTraceDisplayName(Trace trace) {
|
||||
DomainFile file = trace.getDomainFile();
|
||||
String name = file.getName();
|
||||
if (!name.isBlank()) {
|
||||
return name;
|
||||
}
|
||||
return trace.getName();
|
||||
}
|
||||
|
||||
protected void contextChanged() {
|
||||
Trace trace = current.getTrace();
|
||||
String itemName = trace == null ? "..." : getTraceDisplayName(trace);
|
||||
String itemName = trace == null ? "..." : trace.getDomainFile().getName();
|
||||
actionCloseTrace.getMenuBarData().setMenuItemName(CloseTraceAction.NAME_PREFIX + itemName);
|
||||
actionSaveTrace.getMenuBarData().setMenuItemName(SaveTraceAction.NAME_PREFIX + itemName);
|
||||
tool.contextChanged(null);
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/* ###
|
||||
* 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 ghidra.app.plugin.core.debug.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.DomainObjectService;
|
||||
import ghidra.app.util.Option;
|
||||
import ghidra.app.util.exporter.Exporter;
|
||||
import ghidra.app.util.exporter.ExporterException;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.trace.database.DBTrace;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class GztExporter extends Exporter {
|
||||
|
||||
public static final String EXTENSION = "gzt";
|
||||
public static final String SUFFIX = "." + EXTENSION;
|
||||
|
||||
public static final String NAME = "Ghidra Trace Zip File";
|
||||
|
||||
public GztExporter() {
|
||||
super(NAME, EXTENSION, new HelpLocation("ExporterPlugin", "gzt"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canExportDomainFile(DomainFile domainFile) {
|
||||
// Avoid exporting link-files or non-Trace files
|
||||
return !domainFile.isLink() && canExportDomainObject(domainFile.getDomainObjectClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canExportDomainObject(Class<? extends DomainObject> domainObjectClass) {
|
||||
return DBTrace.class.isAssignableFrom(domainObjectClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return (obj instanceof GztExporter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean export(File file, DomainObject domainObj, AddressSetView addrSet,
|
||||
TaskMonitor monitor) {
|
||||
if (!canExportDomainObject(domainObj.getClass())) {
|
||||
throw new UnsupportedOperationException("only DBTrace objects are supported");
|
||||
}
|
||||
try {
|
||||
file.delete();
|
||||
domainObj.saveToPackedFile(file, monitor);
|
||||
}
|
||||
catch (UnsupportedOperationException e) {
|
||||
log.appendMsg("Content does not support packed file export!");
|
||||
log.appendException(e);
|
||||
return false;
|
||||
}
|
||||
catch (CancelledException ce) {
|
||||
return false;
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.appendMsg("Unexpected exception exporting file: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean export(File file, DomainFile domainFile, TaskMonitor monitor)
|
||||
throws ExporterException, IOException {
|
||||
if (!canExportDomainFile(domainFile)) {
|
||||
throw new UnsupportedOperationException("only DBTrace files are supported");
|
||||
}
|
||||
try {
|
||||
domainFile.packFile(file, monitor);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
return false;
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.appendMsg("Unexpected exception exporting file: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Option> getOptions(DomainObjectService domainObjectService) {
|
||||
return EMPTY_OPTIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOptions(List<Option> options) {
|
||||
// no options for this exporter
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false. GZT export only supports entire database.
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsAddressRestrictedExport() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/* ###
|
||||
* 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 ghidra.app.plugin.core.debug.utils;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
import db.DBHandle;
|
||||
import ghidra.app.util.Option;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.opinion.*;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.data.OpenMode;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.framework.store.db.PackedDatabase;
|
||||
import ghidra.framework.store.local.ItemSerializer;
|
||||
import ghidra.program.model.lang.LanguageNotFoundException;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.trace.database.DBTrace;
|
||||
import ghidra.trace.database.DBTraceContentHandler;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import utilities.util.FileUtilities;
|
||||
|
||||
/**
|
||||
* Loads a packed Ghidra Trace file.
|
||||
*/
|
||||
public class GztLoader implements Loader {
|
||||
|
||||
public final static String GZT_NAME = "GZT Input Format";
|
||||
|
||||
@Override
|
||||
public LoaderTier getTier() {
|
||||
return LoaderTier.SPECIALIZED_TARGET_LOADER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTierPriority() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
|
||||
Program program) {
|
||||
if (options != null && options.size() > 0) {
|
||||
return "GztLoader takes no options";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Option> getDefaultOptions(ByteProvider provider, LoadSpec loadSpec,
|
||||
DomainObject domainObject, boolean loadIntoProgram, boolean mirrorFsLayout) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoadResults<? extends DomainObject> load(ImporterSettings settings)
|
||||
throws IOException, CancelledException, VersionException {
|
||||
|
||||
Trace trace = loadPackedTraceDatabase(settings.provider(), settings.importName(),
|
||||
settings.consumer(), settings.monitor());
|
||||
return new LoadResults<>(new Loaded<>(trace, settings));
|
||||
}
|
||||
|
||||
private Trace loadPackedTraceDatabase(ByteProvider provider, String traceName,
|
||||
Object consumer, TaskMonitor monitor)
|
||||
throws IOException, CancelledException, VersionException, LanguageNotFoundException {
|
||||
Trace trace;
|
||||
File file = provider.getFile();
|
||||
File tmpFile = null;
|
||||
if (file == null) {
|
||||
file = tmpFile = createTmpFile(provider, monitor);
|
||||
}
|
||||
|
||||
try {
|
||||
PackedDatabase packedDatabase = PackedDatabase.getPackedDatabase(file, true, monitor);
|
||||
boolean success = false;
|
||||
DBHandle dbh = null;
|
||||
try {
|
||||
if (!DBTraceContentHandler.TRACE_CONTENT_TYPE
|
||||
.equals(packedDatabase.getContentType())) {
|
||||
throw new IOException("File imported is not a Trace: " + traceName);
|
||||
}
|
||||
|
||||
monitor.setMessage("Restoring " + provider.getName());
|
||||
|
||||
dbh = packedDatabase.open(monitor);
|
||||
|
||||
trace = new DBTrace(dbh, OpenMode.UPGRADE, monitor, consumer);
|
||||
success = true;
|
||||
}
|
||||
finally {
|
||||
if (!success) {
|
||||
if (dbh != null) {
|
||||
dbh.close(); // also disposes packed database object
|
||||
}
|
||||
else {
|
||||
packedDatabase.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
return trace;
|
||||
}
|
||||
finally {
|
||||
if (tmpFile != null) {
|
||||
tmpFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadInto(Program program, ImporterSettings settings)
|
||||
throws IOException, LoadException, CancelledException {
|
||||
throw new LoadException("Cannot add GZT to program");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
|
||||
List<LoadSpec> loadSpecs = new ArrayList<>();
|
||||
if (isGztFile(provider)) {
|
||||
loadSpecs.add(new LoadSpec(this, 0, false));
|
||||
}
|
||||
return loadSpecs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreferredFileName(ByteProvider provider) {
|
||||
return FilenameUtils.removeExtension(provider.getName());
|
||||
}
|
||||
|
||||
private static File createTmpFile(ByteProvider provider, TaskMonitor monitor)
|
||||
throws IOException {
|
||||
File tmpFile = Application.createTempFile("ghidra_gzt_loader", null);
|
||||
try (InputStream is = provider.getInputStream(0);
|
||||
FileOutputStream fos = new FileOutputStream(tmpFile)) {
|
||||
FileUtilities.copyStreamToStream(is, fos, monitor);
|
||||
}
|
||||
return tmpFile;
|
||||
}
|
||||
|
||||
private static boolean isGztFile(ByteProvider provider) {
|
||||
if (!provider.getName().toLowerCase().endsWith(".gzt")) {
|
||||
return false;
|
||||
}
|
||||
boolean isGZT = false;
|
||||
try (InputStream inputStream = provider.getInputStream(0)) {
|
||||
isGZT = ItemSerializer.isPackedFile(inputStream);
|
||||
}
|
||||
catch (IOException e) {
|
||||
// ignore
|
||||
}
|
||||
return isGZT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return GZT_NAME;
|
||||
}
|
||||
}
|
||||
@@ -823,7 +823,7 @@ public abstract class AbstractGhidraHeadedDebuggerTest
|
||||
|
||||
protected File pack(DomainObject object) throws Exception {
|
||||
File tempDir = Files.createTempDirectory("ghidra-" + name.getMethodName()).toFile();
|
||||
File pack = new File(tempDir, "obj" + System.identityHashCode(object) + ".gzf");
|
||||
File pack = new File(tempDir, "obj" + System.identityHashCode(object) + ".gzt");
|
||||
object.saveToPackedFile(pack, monitor);
|
||||
return pack;
|
||||
}
|
||||
|
||||
@@ -236,9 +236,9 @@ public class ToyDBTraceBuilder implements AutoCloseable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a .gzf compressed trace
|
||||
* Open a .gzt packed trace
|
||||
*
|
||||
* @param file the .gzf file containing the trace
|
||||
* @param file the .gzt file containing the trace
|
||||
* @throws CancelledException never, since the monitor cannot be cancelled
|
||||
* @throws VersionException if the trace's version is not as expected
|
||||
* @throws LanguageNotFoundException if the trace's language cannot be found
|
||||
@@ -936,7 +936,7 @@ public class ToyDBTraceBuilder implements AutoCloseable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the trace to a temporary .gzf file
|
||||
* Save the trace to a temporary packed .gzt file
|
||||
*
|
||||
* @return the new file
|
||||
* @throws IOException if the trace could not be saved
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
<BODY lang="EN-US">
|
||||
<H1><A name="Export"></A>Exporting Files</H1>
|
||||
|
||||
<P>Ghidra provides an <I>Exporter</I> that allows a user to output program information into a
|
||||
file in various formats. </P>
|
||||
<P>Ghidra provides an <I>Exporter</I> that allows a user to output Program information into a
|
||||
file in various formats.</P>
|
||||
|
||||
<P>Some of the formats the <I>Exporter</I> supports are:</P>
|
||||
<P>Some of the Program file formats the <I>Exporter</I> supports are:</P>
|
||||
<A name="Exporter_Formats">
|
||||
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
<LI><A href="#c_cpp">C/C++</A></LI>
|
||||
|
||||
<LI><A href="#gzf">Ghidra Zip File (GZF)</A></LI>
|
||||
|
||||
<LI><A href="#gdt">Ghidra Data Type Archive File (GDT)</a></LI>
|
||||
|
||||
<LI><A href="#html">HTML</A></LI>
|
||||
|
||||
@@ -40,6 +38,12 @@
|
||||
|
||||
<LI><A href="#sarif">SARIF Export Format</A></LI>
|
||||
</UL>
|
||||
|
||||
<P><I><IMG src="help/shared/note.png"> Content types other than Program may support
|
||||
export and will present those export formats which are supported. Example: A
|
||||
Debugger Trace may be exported as a Ghidra Zip Debugger Trace file (GZT). A data
|
||||
type archive may be exported as a compressed Ghidra Data Type (GDT) archive file.
|
||||
</P>
|
||||
|
||||
<H2>Export Action</H2>
|
||||
|
||||
|
||||
@@ -599,11 +599,23 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
|
||||
The global namespace is the default namespace.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H2><A name="gdt"></A>gdt</H2>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>File extension given to a compressed Ghidra Data Type Archive database file.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H2><A name="gzf"></A>gzf</H2>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>File extension given to Ghidra program database files that have been "zipped up".</P>
|
||||
<P>File extension given to a compressed Ghidra Program database file.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H2><A name="gzt"></A>gzt</H2>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>File extension given to a compressed Ghidra Debugger Trace database file.</P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P><A name="h"></A><FONT size="7"><B>H</B></FONT></P>
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
<LI>Executable and Linking Format (ELF)</LI>
|
||||
<LI>Ghidra Data Type Archive File (GDT)</LI>
|
||||
<LI>Ghidra Zip File (GZF)</LI>
|
||||
<LI>Ghidra Zip Debugger Trace File (GZT)</LI>
|
||||
<LI>Intel Hex</LI>
|
||||
<LI>Java Class File</LI>
|
||||
<LI>Mac OS X Mach-O</LI>
|
||||
@@ -96,10 +97,12 @@
|
||||
<UL>
|
||||
<LI><B>Project Window</B>: Drag a file from the system file explorer application and drop
|
||||
onto the Ghidra Project Tree destination folder. Dropping onto the table view is not
|
||||
supported. In the case of Ghidra Zip File (GZF) or Ghidra Data Type Archive (GDT) file
|
||||
supported. In the case of Ghidra Zip File (GZF), Ghidra Zip Debugger Trace file (GZT),
|
||||
or Ghidra Data Type Archive (GDT) file
|
||||
imports, an immediate unpack can be performed wthout a popup dialog if the Front End option
|
||||
<I>Enable simple GZF/GDT unpack</I> is enabled (
|
||||
<B>Edit<IMG src="help/shared/arrow.gif">Tool Options...<IMG src="help/shared/arrow.gif">File Import<IMG src="help/shared/arrow.gif">Enable simple GZF/GDT unpack</B>).
|
||||
<I>Enable simple GZF/GZT/GDT unpack</I> is enabled (
|
||||
<B>Edit<IMG src="help/shared/arrow.gif">Tool Options...<IMG src="help/shared/arrow.gif">
|
||||
File Import<IMG src="help/shared/arrow.gif">Enable simple GZF/GZT/GDT unpack</B>).
|
||||
</LI>
|
||||
|
||||
<LI>or <B>Running Tool</B>: Drag a file from the system file explorer application and drop
|
||||
@@ -274,9 +277,10 @@
|
||||
folder, otherwise the root folder will be the default. The <B>...</B> will bring up a
|
||||
dialog for changing the destination folder.</LI><BR>
|
||||
|
||||
<LI><B>Program Name</B> - This field specifies the name for the newly imported program.
|
||||
<LI><B>Program Name</B> - This field specifies the name for the newly imported file into
|
||||
the active project.
|
||||
By default, it will be the name of the imported file with any format specific extenstion
|
||||
removed (e.g., .xml, .gzf). Path information at the beginning of this field
|
||||
removed (e.g., .xml, .gzf, .gzt, .gdt). Path information at the beginning of this field
|
||||
will be used to create a destination folder in the current project under the root folder
|
||||
specified by the <B>Destination Folder</B> field.</LI><BR>
|
||||
|
||||
|
||||
@@ -317,7 +317,7 @@ public class ExporterDialog extends DialogComponentProvider implements AddressFa
|
||||
|
||||
private void chooseDestinationFile() {
|
||||
GhidraFileChooser chooser = new GhidraFileChooser(getComponent());
|
||||
chooser.setSelectedFile(getLastExportDirectory());
|
||||
chooser.setCurrentDirectory(getLastExportDirectory());
|
||||
chooser.setTitle("Select Output File");
|
||||
chooser.setApproveButtonText("Select Output File");
|
||||
chooser.setApproveButtonToolTipText("Select File");
|
||||
|
||||
@@ -18,19 +18,25 @@ package ghidra.app.plugin.core.exporter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.List;
|
||||
|
||||
import docking.action.*;
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.action.builder.ActionBuilder;
|
||||
import docking.tool.ToolConstants;
|
||||
import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.context.NavigatableActionContext;
|
||||
import ghidra.app.context.NavigatableContextAction;
|
||||
import ghidra.app.context.ProgramLocationActionContext;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.services.CodeViewerService;
|
||||
import ghidra.app.plugin.ProgramPlugin;
|
||||
import ghidra.framework.main.ApplicationLevelPlugin;
|
||||
import ghidra.framework.main.FrontEndService;
|
||||
import ghidra.framework.main.datatable.FrontendProjectTreeAction;
|
||||
import ghidra.framework.main.datatable.ProjectDataContext;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.model.DomainFolder;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.PluginInfo;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.ProgramSelection;
|
||||
@@ -45,7 +51,7 @@ import ghidra.util.HelpLocation;
|
||||
description = "This plugin exports a program or datatype archive to an external file."
|
||||
)
|
||||
//@formatter:on
|
||||
public class ExporterPlugin extends Plugin implements ApplicationLevelPlugin {
|
||||
public class ExporterPlugin extends ProgramPlugin implements ApplicationLevelPlugin {
|
||||
|
||||
private FrontEndService frontEndService;
|
||||
|
||||
@@ -64,32 +70,39 @@ public class ExporterPlugin extends Plugin implements ApplicationLevelPlugin {
|
||||
return; // do not add File menu Export Program action to front-end
|
||||
}
|
||||
|
||||
DockingAction action = new NavigatableContextAction("Export Program", getName()) {
|
||||
|
||||
@Override
|
||||
protected void actionPerformed(NavigatableActionContext context) {
|
||||
Program program = context.getProgram();
|
||||
DomainFile domainFile = program.getDomainFile();
|
||||
ExporterDialog.showExporterDialog(tool, domainFile, program,
|
||||
context.getSelection());
|
||||
}
|
||||
};
|
||||
MenuData menuData =
|
||||
new MenuData(new String[] { "&File", "Export Program..." }, "Import Export");
|
||||
menuData.setMenuSubGroup("z"); // last in the "Save" group
|
||||
action.setMenuBarData(menuData);
|
||||
action.setKeyBindingData(new KeyBindingData(KeyEvent.VK_O, 0));
|
||||
action.setHelpLocation(new HelpLocation("ExporterPlugin", "Export"));
|
||||
action.setDescription(getPluginDescription().getDescription());
|
||||
tool.addAction(action);
|
||||
new ActionBuilder("Export Program", getName())
|
||||
.description(getPluginDescription().getDescription())
|
||||
.helpLocation(new HelpLocation("ExporterPlugin", "Export"))
|
||||
.menuPath(ToolConstants.MENU_FILE, "Export Program...")
|
||||
.menuGroup("DomainObjectSaveExport")
|
||||
.keyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_O, 0))
|
||||
.enabledWhen(c -> getProgram(c) != null)
|
||||
.onAction(c -> doExport(c))
|
||||
.buildAndInstall(tool);
|
||||
}
|
||||
|
||||
protected ProgramSelection getSelection() {
|
||||
CodeViewerService service = tool.getService(CodeViewerService.class);
|
||||
if (service != null) {
|
||||
return service.getCurrentSelection();
|
||||
private Program getProgram(ActionContext ctx) {
|
||||
if (ctx instanceof ProgramLocationActionContext programCtx) {
|
||||
Program p = programCtx.getProgram();
|
||||
if (p != null) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return getCurrentProgram();
|
||||
}
|
||||
|
||||
private ProgramSelection getProgramSelection(ActionContext ctx) {
|
||||
if (ctx instanceof ProgramLocationActionContext programCtx) {
|
||||
return programCtx.getSelection();
|
||||
}
|
||||
return getProgramSelection();
|
||||
}
|
||||
|
||||
private void doExport(ActionContext ctx) {
|
||||
Program program = getProgram(ctx);
|
||||
DomainFile domainFile = program.getDomainFile();
|
||||
ExporterDialog.showExporterDialog(tool, domainFile, program,
|
||||
getProgramSelection(ctx));
|
||||
}
|
||||
|
||||
private void createFrontEndAction() {
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -76,8 +76,23 @@ class MultiProgramManager implements TransactionListener {
|
||||
};
|
||||
}
|
||||
|
||||
void addProgram(Program p, ProgramLocator locator, int state) {
|
||||
/**
|
||||
* Add specified program.
|
||||
* <p>
|
||||
* NOTE: If this is the first program to be added it will be forced to CURRENT state.
|
||||
*
|
||||
* @param p program to be added
|
||||
* @param locator program location source information
|
||||
* @param state initial state
|
||||
* @return true if program is the current program
|
||||
*/
|
||||
boolean addProgram(Program p, ProgramLocator locator, int state) {
|
||||
if (programMap.isEmpty()) {
|
||||
// Tool does not handle case where single open program is not current program
|
||||
state = ProgramManager.OPEN_CURRENT;
|
||||
}
|
||||
addProgram(new ProgramInfo(p, locator, state != ProgramManager.OPEN_HIDDEN), state);
|
||||
return state == ProgramManager.OPEN_CURRENT;
|
||||
}
|
||||
|
||||
private void addProgram(ProgramInfo programInfo, int state) {
|
||||
|
||||
@@ -484,8 +484,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager, Opti
|
||||
}
|
||||
|
||||
Runnable r = () -> {
|
||||
programMgr.addProgram(p, locator, state);
|
||||
if (state == ProgramManager.OPEN_CURRENT) {
|
||||
if (programMgr.addProgram(p, locator, state)) {
|
||||
programMgr.saveLocation();
|
||||
}
|
||||
contextChanged();
|
||||
|
||||
@@ -161,14 +161,22 @@ public class SourceFilesTablePlugin extends ProgramPlugin implements OptionsChan
|
||||
}
|
||||
|
||||
private boolean isEnabled(ListingActionContext context) {
|
||||
Program p = getCurrentProgram();
|
||||
if (p == null || p != context.getProgram()) {
|
||||
return false;
|
||||
}
|
||||
Address address = context.getAddress();
|
||||
SourceFileManager manager = getCurrentProgram().getSourceFileManager();
|
||||
SourceFileManager manager = p.getSourceFileManager();
|
||||
return manager.getSourceMapEntries(address).size() > 0;
|
||||
}
|
||||
|
||||
private void viewSourceFile(ListingActionContext context) {
|
||||
Program p = getCurrentProgram();
|
||||
if (p == null || p != context.getProgram()) {
|
||||
return;
|
||||
}
|
||||
Address address = context.getAddress();
|
||||
SourceFileManager manager = getCurrentProgram().getSourceFileManager();
|
||||
SourceFileManager manager = p.getSourceFileManager();
|
||||
List<SourceMapEntry> entries = manager.getSourceMapEntries(address);
|
||||
if (entries.isEmpty()) {
|
||||
return; // sanity check
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -30,7 +30,7 @@ import ghidra.util.task.TaskMonitor;
|
||||
* An implementation of exporter that creates
|
||||
* an Ascii representation of the program.
|
||||
*/
|
||||
public class AsciiExporter extends Exporter {
|
||||
public class AsciiExporter extends ProgramExporter {
|
||||
private ProgramTextOptions options;
|
||||
|
||||
/**
|
||||
@@ -60,11 +60,14 @@ public class AsciiExporter extends Exporter {
|
||||
|
||||
log.clear();
|
||||
|
||||
if (!(domainObj instanceof Program)) {
|
||||
Program program;
|
||||
try {
|
||||
program = getProgram(domainObj);
|
||||
}
|
||||
catch (ClassCastException e) {
|
||||
log.appendMsg("Unsupported type: " + domainObj.getClass().getName());
|
||||
return false;
|
||||
}
|
||||
Program program = (Program) domainObj;
|
||||
|
||||
getOptions(() -> program);
|
||||
new ProgramTextWriter(file, program, addressSet, monitor, options, provider);
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -23,14 +23,15 @@ import ghidra.app.util.Option;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* An {@link Exporter} that can export memory blocks as raw bytes
|
||||
*/
|
||||
public class BinaryExporter extends Exporter {
|
||||
public class BinaryExporter extends ProgramExporter {
|
||||
|
||||
public BinaryExporter() {
|
||||
super("Raw Bytes", "bin", new HelpLocation("ExporterPlugin", "binary"));
|
||||
@@ -40,30 +41,27 @@ public class BinaryExporter extends Exporter {
|
||||
public boolean export(File file, DomainObject domainObj, AddressSetView addrSet,
|
||||
TaskMonitor monitor) throws IOException, ExporterException {
|
||||
|
||||
if (!(domainObj instanceof Program)) {
|
||||
Program program;
|
||||
try {
|
||||
program = getProgram(domainObj);
|
||||
}
|
||||
catch (ClassCastException e) {
|
||||
log.appendMsg("Unsupported type: " + domainObj.getClass().getName());
|
||||
return false;
|
||||
}
|
||||
Program program = (Program) domainObj;
|
||||
|
||||
Memory memory = program.getMemory();
|
||||
AddressSetView initializedAddressSet = memory.getAllInitializedAddressSet();
|
||||
|
||||
if (addrSet == null) {
|
||||
addrSet = memory;
|
||||
addrSet = initializedAddressSet;
|
||||
}
|
||||
|
||||
AddressSet set = new AddressSet(addrSet);
|
||||
|
||||
//skip blocks that are not initialized...
|
||||
MemoryBlock[] blocks = memory.getBlocks();
|
||||
for (int i = 0; i < blocks.length; ++i) {
|
||||
if (!blocks[i].isInitialized()) {
|
||||
set.delete(new AddressRangeImpl(blocks[i].getStart(), blocks[i].getEnd()));
|
||||
}
|
||||
else {
|
||||
addrSet = addrSet.intersect(initializedAddressSet);
|
||||
}
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
AddressRangeIterator iter = set.getAddressRanges();
|
||||
AddressRangeIterator iter = addrSet.getAddressRanges();
|
||||
while (iter.hasNext()) {
|
||||
AddressRange range = iter.next();
|
||||
byte[] mem = new byte[(int) range.getLength()];
|
||||
|
||||
@@ -25,7 +25,6 @@ import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.classfinder.ExtensionPoint;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@@ -101,34 +100,32 @@ abstract public class Exporter implements ExtensionPoint {
|
||||
/**
|
||||
* Returns true if this exporter is capable of exporting the given domain file/object content
|
||||
* type. For example, some exporters have the ability to export programs, other exporters can
|
||||
* export project data type archives.
|
||||
* export other {@link DomainFile} or {@link DomainObject} types such as project data type
|
||||
* archives.
|
||||
* <p>
|
||||
* NOTE: This method should only be used as a preliminary check, if neccessary, to identify
|
||||
* NOTE: This method should only be used as a preliminary check, if necessary, to identify
|
||||
* exporter implementations that are capable of handling a specified content type/class. Prior
|
||||
* to export a final check should be performed based on the export or either a
|
||||
* {@link DomainFile} or {@link DomainObject}:
|
||||
* <p>
|
||||
* {@link DomainFile} export - the method {@link #canExportDomainFile(DomainFile)} should be
|
||||
* used to verify a direct project file export is possible using the
|
||||
* {@link #export(File, DomainFile, TaskMonitor)} method.
|
||||
* {@link #export(File, DomainFile, TaskMonitor)} method which may avoid opening the file first.
|
||||
* <p>
|
||||
* {@link DomainObject} export - the method {@link #canExportDomainObject(DomainObject)} should
|
||||
* be used to verify an export of a specific object is possible using the
|
||||
* be used to verify an export of a specific object is possible before using the
|
||||
* {@link #export(File, DomainObject, AddressSetView, TaskMonitor)} method.
|
||||
*
|
||||
* avoid opening DomainFile when possible.
|
||||
* @param domainObjectClass the class of the domain object to test for exporting.
|
||||
* @return true if this exporter knows how to export the given domain object type.
|
||||
*/
|
||||
public boolean canExportDomainObject(Class<? extends DomainObject> domainObjectClass) {
|
||||
return Program.class.isAssignableFrom(domainObjectClass);
|
||||
}
|
||||
public abstract boolean canExportDomainObject(Class<? extends DomainObject> domainObjectClass);
|
||||
|
||||
/**
|
||||
* Returns true if exporter can export the specified {@link DomainFile} without instantiating
|
||||
* a {@link DomainObject}. This method should be used prior to exporting using the
|
||||
* {@link #export(File, DomainFile, TaskMonitor)} method. All exporter capable of a
|
||||
* {@link DomainFile} export must also support a export of a {@link DomainObject} so that any
|
||||
* {@link #export(File, DomainFile, TaskMonitor)} method. All exporters capable of a
|
||||
* {@link DomainFile} export must also support an export of a {@link DomainObject} so that any
|
||||
* possible data modification/upgrade is included within resulting export.
|
||||
*
|
||||
* @param domainFile domain file
|
||||
|
||||
@@ -47,7 +47,7 @@ public class GdtExporter extends Exporter {
|
||||
|
||||
@Override
|
||||
public boolean canExportDomainFile(DomainFile domainFile) {
|
||||
// Avoid exporting link-file itself
|
||||
// Avoid exporting link-file itself or non-Datatype Archives
|
||||
return !domainFile.isLink() && canExportDomainObject(domainFile.getDomainObjectClass());
|
||||
}
|
||||
|
||||
@@ -59,6 +59,9 @@ public class GdtExporter extends Exporter {
|
||||
@Override
|
||||
public boolean export(File file, DomainObject domainObj, AddressSetView addrSet,
|
||||
TaskMonitor monitor) {
|
||||
if (!canExportDomainObject(domainObj.getClass())) {
|
||||
throw new UnsupportedOperationException("only DataTypeArchiveDB objects are supported");
|
||||
}
|
||||
try {
|
||||
file.delete();
|
||||
domainObj.saveToPackedFile(file, monitor);
|
||||
|
||||
@@ -42,7 +42,7 @@ public class GzfExporter extends Exporter {
|
||||
|
||||
@Override
|
||||
public boolean canExportDomainFile(DomainFile domainFile) {
|
||||
// Avoid exporting link-file itself
|
||||
// Avoid exporting link-file itself or non-Program files
|
||||
return !domainFile.isLink() && canExportDomainObject(domainFile.getDomainObjectClass());
|
||||
}
|
||||
|
||||
@@ -59,6 +59,9 @@ public class GzfExporter extends Exporter {
|
||||
@Override
|
||||
public boolean export(File file, DomainObject domainObj, AddressSetView addrSet,
|
||||
TaskMonitor monitor) {
|
||||
if (!canExportDomainObject(domainObj.getClass())) {
|
||||
throw new UnsupportedOperationException("only ProgramDB objects are supported");
|
||||
}
|
||||
try {
|
||||
file.delete();
|
||||
domainObj.saveToPackedFile(file, monitor);
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -30,7 +30,7 @@ import ghidra.util.task.TaskMonitor;
|
||||
* An implementation of exporter that creates
|
||||
* an HTML representation of the program.
|
||||
*/
|
||||
public class HtmlExporter extends Exporter {
|
||||
public class HtmlExporter extends ProgramExporter {
|
||||
private ProgramTextOptions options;
|
||||
|
||||
/**
|
||||
@@ -58,11 +58,14 @@ public class HtmlExporter extends Exporter {
|
||||
public boolean export(File file, DomainObject domainObj, AddressSetView addressSet,
|
||||
TaskMonitor monitor) throws IOException, ExporterException {
|
||||
|
||||
if (!(domainObj instanceof Program)) {
|
||||
Program program;
|
||||
try {
|
||||
program = getProgram(domainObj);
|
||||
}
|
||||
catch (ClassCastException e) {
|
||||
log.appendMsg("Unsupported type: " + domainObj.getClass().getName());
|
||||
return false;
|
||||
}
|
||||
Program program = (Program) domainObj;
|
||||
|
||||
getOptions(() -> program);
|
||||
new ProgramTextWriter(file, program, addressSet, monitor, options, provider);
|
||||
|
||||
@@ -44,7 +44,7 @@ import ghidra.util.task.TaskMonitor;
|
||||
* cause only lines that match the max record size to be printed; any other
|
||||
* bytes will be dropped. If this option is not set, every byte will be represented in the output.
|
||||
*/
|
||||
public class IntelHexExporter extends Exporter {
|
||||
public class IntelHexExporter extends ProgramExporter {
|
||||
|
||||
/** Option allowing the user to select the address space */
|
||||
protected Option addressSpaceOption;
|
||||
@@ -151,7 +151,11 @@ public class IntelHexExporter extends Exporter {
|
||||
|
||||
log.clear();
|
||||
|
||||
if (!(domainObj instanceof Program program)) {
|
||||
Program program;
|
||||
try {
|
||||
program = getProgram(domainObj);
|
||||
}
|
||||
catch (ClassCastException e) {
|
||||
log.appendMsg("Unsupported type: " + domainObj.getClass().getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ import utilities.util.FileUtilities;
|
||||
* WARNING: Programs written to disk with this exporter may be runnable on your native platform.
|
||||
* Use caution when exporting potentially malicious programs.
|
||||
*/
|
||||
public class OriginalFileExporter extends Exporter {
|
||||
public class OriginalFileExporter extends ProgramExporter {
|
||||
|
||||
private static final String USER_MODS_OPTION_NAME = "Export User Byte Modifications";
|
||||
private static final boolean USER_MODS_OPTION_DEFAULT = true;
|
||||
@@ -63,6 +63,11 @@ public class OriginalFileExporter extends Exporter {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canExportDomainObject(Class<? extends DomainObject> domainObjectClass) {
|
||||
return Program.class.isAssignableFrom(domainObjectClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canExportDomainObject(DomainObject domainObject) {
|
||||
if (domainObject instanceof Program program) {
|
||||
@@ -75,13 +80,15 @@ public class OriginalFileExporter extends Exporter {
|
||||
public boolean export(File file, DomainObject domainObj, AddressSetView addrSet,
|
||||
TaskMonitor monitor) throws IOException, ExporterException {
|
||||
|
||||
if (!(domainObj instanceof Program)) {
|
||||
log.appendMsg("Unsupported type: " + domainObj.getClass().getSimpleName());
|
||||
Program program;
|
||||
try {
|
||||
program = getProgram(domainObj);
|
||||
}
|
||||
catch (ClassCastException e) {
|
||||
log.appendMsg("Unsupported type: " + domainObj.getClass().getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
Program program = (Program) domainObj;
|
||||
|
||||
List<FileBytes> allFileBytes = program.getMemory().getAllFileBytes();
|
||||
if (allFileBytes.isEmpty()) {
|
||||
log.appendMsg("Exporting a program with no file source bytes is not supported");
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/* ###
|
||||
* 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 ghidra.app.util.exporter;
|
||||
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
||||
/**
|
||||
* {@link ProgramExporter} provides an abstract {@link Exporter} implementation for
|
||||
* {@link Program} objects.
|
||||
*/
|
||||
public abstract class ProgramExporter extends Exporter {
|
||||
|
||||
/**
|
||||
* Constructs a new {@link Program} exporter.
|
||||
* @param name the display name of this exporter
|
||||
* @param extension the default extension for this exporter
|
||||
* @param help the help location for this exporter
|
||||
*/
|
||||
protected ProgramExporter(String name, String extension, HelpLocation help) {
|
||||
super(name, extension, help);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an exportable Program instance from the specified DomainObject instance.
|
||||
* The specified instance must satisfy {@link #canExportDomainObject(Class)}.
|
||||
* @param domainObj domain object from which a Program may be derived.
|
||||
* @return Program instance
|
||||
* @throws ClassCastException if domain object class does not satisfy
|
||||
* {@link #canExportDomainObject(Class)}.
|
||||
*/
|
||||
protected Program getProgram(DomainObject domainObj) throws ClassCastException {
|
||||
return (Program) domainObj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canExportDomainObject(Class<? extends DomainObject> domainObjectClass) {
|
||||
return Program.class.isAssignableFrom(domainObjectClass);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -33,7 +33,7 @@ import ghidra.util.task.TaskMonitor;
|
||||
* An implementation of exporter that creates
|
||||
* an XML representation of the program.
|
||||
*/
|
||||
public class XmlExporter extends Exporter {
|
||||
public class XmlExporter extends ProgramExporter {
|
||||
private XmlProgramOptions options = new XmlProgramOptions();
|
||||
|
||||
/**
|
||||
@@ -62,11 +62,14 @@ public class XmlExporter extends Exporter {
|
||||
|
||||
log.clear();
|
||||
|
||||
if (!(domainObj instanceof Program)) {
|
||||
log.appendMsg("Unsupported type: "+domainObj.getClass().getName());
|
||||
Program program;
|
||||
try {
|
||||
program = getProgram(domainObj);
|
||||
}
|
||||
catch (ClassCastException e) {
|
||||
log.appendMsg("Unsupported type: " + domainObj.getClass().getName());
|
||||
return false;
|
||||
}
|
||||
Program program = (Program)domainObj;
|
||||
|
||||
if (addrSet == null) {
|
||||
addrSet = program.getMemory();
|
||||
|
||||
@@ -47,7 +47,7 @@ public class GdtLoader implements Loader {
|
||||
@Override
|
||||
public List<Option> getDefaultOptions(ByteProvider provider, LoadSpec loadSpec,
|
||||
DomainObject domainObject, boolean loadIntoProgram, boolean mirrorFsLayout) {
|
||||
return Collections.emptyList();
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -66,7 +66,7 @@ public class GzfLoader implements Loader {
|
||||
@Override
|
||||
public List<Option> getDefaultOptions(ByteProvider provider, LoadSpec loadSpec,
|
||||
DomainObject domainObject, boolean loadIntoProgram, boolean mirrorFsLayout) {
|
||||
return Collections.emptyList();
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -131,7 +131,6 @@ public class GzfLoader implements Loader {
|
||||
|
||||
@Override
|
||||
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
|
||||
// TODO WRONG! try to parse a bit and tell for real
|
||||
List<LoadSpec> loadSpecs = new ArrayList<>();
|
||||
if (isGzfFile(provider)) {
|
||||
loadSpecs.add(new LoadSpec(this, 0, false));
|
||||
|
||||
@@ -86,7 +86,7 @@ public class ImporterPlugin extends Plugin
|
||||
"This plugin manages importing files, including those contained within " +
|
||||
"firmware/filesystem images.";
|
||||
|
||||
private static final String SIMPLE_UNPACK_OPTION = "Enable simple GZF/GDT unpack";
|
||||
private static final String SIMPLE_UNPACK_OPTION = "Enable simple GZF/GZT/GDT unpack";
|
||||
private static final boolean SIMPLE_UNPACK_OPTION_DEFAULT = false;
|
||||
|
||||
private DockingAction importAction;
|
||||
|
||||
@@ -450,7 +450,7 @@ public class ImporterUtilities {
|
||||
ProgramManager programManager, LoadResults<? extends DomainObject> loadResults,
|
||||
String importMessages, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
boolean firstProgram = true;
|
||||
boolean firstFile = true;
|
||||
Set<DomainFile> importedFilesSet = new HashSet<>();
|
||||
for (Loaded<? extends DomainObject> loaded : loadResults) {
|
||||
monitor.checkCancelled();
|
||||
@@ -460,7 +460,7 @@ public class ImporterUtilities {
|
||||
try {
|
||||
if (obj instanceof Program) {
|
||||
if (programManager != null) {
|
||||
int openState = firstProgram
|
||||
int openState = firstFile
|
||||
? ProgramManager.OPEN_CURRENT
|
||||
: ProgramManager.OPEN_VISIBLE;
|
||||
programManager.openProgram((Program) obj, openState);
|
||||
@@ -477,16 +477,16 @@ public class ImporterUtilities {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (firstProgram) {
|
||||
if (firstFile) {
|
||||
// currently we only show results for the imported program, not any libraries
|
||||
displayResults(pluginTool, obj, df, importMessages);
|
||||
displayResults(pluginTool, obj, importMessages);
|
||||
|
||||
// Optionally echo loader message log to application.log
|
||||
if (!Loader.loggingDisabled && !importMessages.isEmpty()) {
|
||||
Msg.info(ImporterUtilities.class, "Additional info:\n" + importMessages);
|
||||
}
|
||||
}
|
||||
firstProgram = false;
|
||||
firstFile = false;
|
||||
importedFilesSet.add(df);
|
||||
}
|
||||
finally {
|
||||
@@ -518,7 +518,7 @@ public class ImporterUtilities {
|
||||
program.getDomainFile().getPathname(), false, loadSpec, options, consumer,
|
||||
messageLog, monitor);
|
||||
loadSpec.getLoader().loadInto(program, settings);
|
||||
displayResults(tool, program, program.getDomainFile(), messageLog.toString());
|
||||
displayResults(tool, program, messageLog.toString());
|
||||
|
||||
// Optionally echo loader message log to application.log
|
||||
if (!Loader.loggingDisabled && messageLog.hasMessages()) {
|
||||
@@ -538,18 +538,9 @@ public class ImporterUtilities {
|
||||
|
||||
}
|
||||
|
||||
private static void displayResults(PluginTool tool, DomainObject obj, DomainFile df,
|
||||
String info) {
|
||||
|
||||
DomainFile domainFile = obj.getDomainFile();
|
||||
Map<String, String> metadata = obj.getMetadata();
|
||||
if (df != null) {
|
||||
domainFile = df;
|
||||
metadata = df.getMetadata();
|
||||
}
|
||||
|
||||
private static void displayResults(PluginTool tool, DomainObject obj, String info) {
|
||||
HelpLocation helpLocation = new HelpLocation(GenericHelpTopics.ABOUT, "About_Program");
|
||||
AboutDomainObjectUtils.displayInformation(tool, domainFile, metadata,
|
||||
AboutDomainObjectUtils.displayInformation(tool, obj.getDomainFile(), obj.getMetadata(),
|
||||
"Import Results Summary", info, helpLocation);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.*;
|
||||
import util.CollectionUtils;
|
||||
|
||||
public class CppExporter extends Exporter {
|
||||
public class CppExporter extends ProgramExporter {
|
||||
|
||||
public static final String CREATE_C_FILE = "Create C File (.c)";
|
||||
public static final String CREATE_HEADER_FILE = "Create Header File (.h)";
|
||||
@@ -90,13 +90,16 @@ public class CppExporter extends Exporter {
|
||||
@Override
|
||||
public boolean export(File file, DomainObject domainObj, AddressSetView addrSet,
|
||||
TaskMonitor monitor) throws IOException, ExporterException {
|
||||
if (!(domainObj instanceof Program)) {
|
||||
|
||||
Program program;
|
||||
try {
|
||||
program = getProgram(domainObj);
|
||||
}
|
||||
catch (ClassCastException e) {
|
||||
log.appendMsg("Unsupported type: " + domainObj.getClass().getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
Program program = (Program) domainObj;
|
||||
|
||||
configureOptions(program);
|
||||
configureFunctionTags(program);
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.*;
|
||||
import ghidra.app.util.exporter.Exporter;
|
||||
import ghidra.app.util.exporter.ExporterException;
|
||||
import ghidra.app.util.exporter.ProgramExporter;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
@@ -36,7 +36,7 @@ import sarif.managers.ProgramSarifMgr;
|
||||
* An implementation of exporter that creates
|
||||
* an SARIF representation of the program.
|
||||
*/
|
||||
public class SarifExporter extends Exporter {
|
||||
public class SarifExporter extends ProgramExporter {
|
||||
private SarifProgramOptions options = new SarifProgramOptions();
|
||||
|
||||
/**
|
||||
@@ -59,17 +59,21 @@ public class SarifExporter extends Exporter {
|
||||
this.options.setOptions(options);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean export(File file, DomainObject domainObj, AddressSetView addrSet, TaskMonitor monitor)
|
||||
throws IOException, ExporterException {
|
||||
|
||||
log.clear();
|
||||
|
||||
if (!(domainObj instanceof Program)) {
|
||||
log.appendMsg("Unsupported type: "+domainObj.getClass().getName());
|
||||
Program program;
|
||||
try {
|
||||
program = getProgram(domainObj);
|
||||
}
|
||||
catch (ClassCastException e) {
|
||||
log.appendMsg("Unsupported type: " + domainObj.getClass().getName());
|
||||
return false;
|
||||
}
|
||||
Program program = (Program)domainObj;
|
||||
|
||||
if (addrSet == null) {
|
||||
addrSet = program.getMemory();
|
||||
|
||||
@@ -276,8 +276,8 @@ public interface FolderItem {
|
||||
/**
|
||||
* Update the checkout version associated with this versioned item.
|
||||
* @param checkoutId id corresponding to an existing checkout
|
||||
* @param checkoutVersion
|
||||
* @param user
|
||||
* @param checkoutVersion current checkout version
|
||||
* @param user user performing update
|
||||
* @throws IOException if an IO error occurs.
|
||||
*/
|
||||
void updateCheckoutVersion(long checkoutId, int checkoutVersion, String user)
|
||||
@@ -289,7 +289,7 @@ public interface FolderItem {
|
||||
* @param version if this item is versioned, specifies the version to be output, otherwise
|
||||
* -1 should be specified.
|
||||
* @param monitor progress monitor
|
||||
* @throws IOException
|
||||
* @throws IOException if failed to save packed file
|
||||
* @throws CancelledException if monitor cancels operation
|
||||
*/
|
||||
public void output(File outputFile, int version, TaskMonitor monitor)
|
||||
@@ -297,6 +297,8 @@ public interface FolderItem {
|
||||
|
||||
/**
|
||||
* Returns this instance after refresh or null if item no longer exists
|
||||
* @return refreshed item
|
||||
* @throws IOException if error occured during refresh
|
||||
*/
|
||||
public FolderItem refresh() throws IOException;
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -15,15 +15,15 @@
|
||||
*/
|
||||
package ghidra.framework.store.local;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.util.MonitoredInputStream;
|
||||
import ghidra.util.exception.IOCancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
/**
|
||||
* <code>ItemDeserializer</code> facilitates the reading of a compressed data stream
|
||||
* contained within a "packed" file. A "packed" file contains the following meta-data
|
||||
|
||||
@@ -15,16 +15,16 @@
|
||||
*/
|
||||
package ghidra.framework.store.local;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.framework.store.DataFileItem;
|
||||
import ghidra.framework.store.FolderItem;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.DuplicateFileException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* <code>LocalDataFileItem</code> provides a FolderItem implementation
|
||||
* for a local serialized data file. This implementation supports
|
||||
@@ -186,8 +186,7 @@ public class LocalDataFileItem extends LocalFolderItem implements DataFileItem {
|
||||
@Override
|
||||
public void output(File outputFile, int version, TaskMonitor monitor) throws IOException {
|
||||
|
||||
throw new UnsupportedOperationException("Output not yet supported for DataFiles");
|
||||
|
||||
throw new IOException("Packed output not yet supported for DataFiles");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -600,13 +600,18 @@ public class LocalDatabaseItem extends LocalFolderItem implements DatabaseItem {
|
||||
public void output(File outputFile, int version, TaskMonitor monitor)
|
||||
throws CancelledException, IOException {
|
||||
synchronized (fileSystem) {
|
||||
|
||||
String contentType = getContentType();
|
||||
if (UnknownFolderItem.UNKNOWN_CONTENT_TYPE.equals(contentType)) {
|
||||
throw new IOException("Unknown content type");
|
||||
}
|
||||
|
||||
if (isVersioned) {
|
||||
versionedDb.output(version, outputFile, getName(), DATABASE_FILE_TYPE,
|
||||
getContentType(), monitor);
|
||||
versionedDb.output(version, outputFile, getName(), DATABASE_FILE_TYPE, contentType,
|
||||
monitor);
|
||||
}
|
||||
else {
|
||||
privateDb.output(outputFile, getName(), DATABASE_FILE_TYPE, getContentType(),
|
||||
monitor);
|
||||
privateDb.output(outputFile, getName(), DATABASE_FILE_TYPE, contentType, monitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ public class LocalTextDataItem extends LocalFolderItem implements TextDataItem {
|
||||
|
||||
@Override
|
||||
public void output(File outputFile, int version, TaskMonitor monitor) throws IOException {
|
||||
throw new IOException("Output not supported");
|
||||
throw new IOException("Packed output not supported for text data");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -115,7 +115,8 @@ public class LocalUnknownFolderItem extends LocalFolderItem implements UnknownFo
|
||||
|
||||
@Override
|
||||
public void output(File outputFile, int version, TaskMonitor monitor) throws IOException {
|
||||
throw new UnsupportedOperationException("Output not supported for UnknownFolderItems");
|
||||
throw new UnsupportedOperationException(
|
||||
"Packed output not supported for UnknownFolderItems");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -158,7 +158,7 @@ public interface DomainObject {
|
||||
* Saves (i.e., serializes) the current content to a packed file.
|
||||
* @param outputFile packed output file
|
||||
* @param monitor progress monitor
|
||||
* @throws IOException if an exception occurs
|
||||
* @throws IOException if an error occurs during operation
|
||||
* @throws CancelledException if the user cancels
|
||||
* @throws UnsupportedOperationException if not supported by object implementation
|
||||
*/
|
||||
|
||||
@@ -50,6 +50,12 @@ public class SkeletonExporter extends Exporter {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canExportDomainObject(Class<? extends DomainObject> domainObjectClass) {
|
||||
// return Program.class.isAssignableFrom(domainObjectClass);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean export(File file, DomainObject domainObj, AddressSetView addrSet,
|
||||
TaskMonitor monitor) throws ExporterException, IOException {
|
||||
|
||||
Reference in New Issue
Block a user