mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-3222: Adds ability to export/serve symbols & types as Volatility ISF
JSON
This commit is contained in:
parent
7891d26115
commit
94166ac349
43 changed files with 2802 additions and 3 deletions
|
@ -1 +0,0 @@
|
|||
MODULE FILE LICENSE: lib/protobuf-java-3.21.8.jar BSD-3-GOOGLE
|
|
@ -59,7 +59,6 @@ dependencies {
|
|||
}
|
||||
}
|
||||
|
||||
api 'com.google.protobuf:protobuf-java:3.21.8'
|
||||
api project(':Framework-AsyncComm')
|
||||
api project(':Framework-Debugging')
|
||||
api project(':ProposedUtils')
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
##VERSION: 2.0
|
||||
##MODULE IP: BSD-3-GOOGLE
|
||||
Module.manifest||GHIDRA||||END|
|
||||
|
|
0
Ghidra/Debug/Debugger-isf/Module.manifest
Normal file
0
Ghidra/Debug/Debugger-isf/Module.manifest
Normal file
108
Ghidra/Debug/Debugger-isf/build.gradle
Normal file
108
Ghidra/Debug/Debugger-isf/build.gradle
Normal file
|
@ -0,0 +1,108 @@
|
|||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
|
||||
apply from: "${rootProject.projectDir}/gradle/javaProject.gradle"
|
||||
apply from: "${rootProject.projectDir}/gradle/jacocoProject.gradle"
|
||||
apply from: "${rootProject.projectDir}/gradle/javaTestProject.gradle"
|
||||
apply from: "${rootProject.projectDir}/gradle/distributableGhidraModule.gradle"
|
||||
|
||||
apply plugin: 'eclipse'
|
||||
eclipse.project.name = 'Debug Debugger-isf'
|
||||
|
||||
configurations {
|
||||
allProtocArtifacts
|
||||
protocArtifact
|
||||
}
|
||||
|
||||
def platform = getCurrentPlatformName()
|
||||
|
||||
dependencies {
|
||||
allProtocArtifacts 'com.google.protobuf:protoc:3.21.8:windows-x86_64@exe'
|
||||
allProtocArtifacts 'com.google.protobuf:protoc:3.21.8:linux-x86_64@exe'
|
||||
allProtocArtifacts 'com.google.protobuf:protoc:3.21.8:linux-aarch_64@exe'
|
||||
allProtocArtifacts 'com.google.protobuf:protoc:3.21.8:osx-x86_64@exe'
|
||||
allProtocArtifacts 'com.google.protobuf:protoc:3.21.8:osx-aarch_64@exe'
|
||||
|
||||
if (isCurrentWindows()) {
|
||||
protocArtifact 'com.google.protobuf:protoc:3.21.8:windows-x86_64@exe'
|
||||
}
|
||||
if (isCurrentLinux()) {
|
||||
if (platform.endsWith("x86_64")) {
|
||||
protocArtifact 'com.google.protobuf:protoc:3.21.8:linux-x86_64@exe'
|
||||
}
|
||||
else {
|
||||
protocArtifact 'com.google.protobuf:protoc:3.21.8:linux-aarch_64@exe'
|
||||
}
|
||||
}
|
||||
if (isCurrentMac()) {
|
||||
if (platform.endsWith("x86_64")) {
|
||||
protocArtifact 'com.google.protobuf:protoc:3.21.8:osx-x86_64@exe'
|
||||
}
|
||||
else {
|
||||
protocArtifact 'com.google.protobuf:protoc:3.21.8:osx-aarch_64@exe'
|
||||
}
|
||||
}
|
||||
|
||||
api project(':Framework-AsyncComm')
|
||||
api project(':Framework-Debugging')
|
||||
api project(':ProposedUtils')
|
||||
|
||||
testImplementation project(path: ':Framework-AsyncComm', configuration: 'testArtifacts')
|
||||
testImplementation project(path: ':Framework-Debugging', configuration: 'testArtifacts')
|
||||
}
|
||||
|
||||
task generateProto {
|
||||
ext.srcdir = file("src/main/proto")
|
||||
ext.src = fileTree(srcdir) {
|
||||
include "**/*.proto"
|
||||
}
|
||||
ext.outdir = file("build/generated/source/proto/main/java")
|
||||
outputs.dir(outdir)
|
||||
inputs.files(src)
|
||||
dependsOn(configurations.protocArtifact)
|
||||
doLast {
|
||||
def exe = configurations.protocArtifact.first()
|
||||
if (!isCurrentWindows()) {
|
||||
exe.setExecutable(true)
|
||||
}
|
||||
exec {
|
||||
commandLine exe, "--java_out=$outdir", "-I$srcdir"
|
||||
args src
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.compileJava.dependsOn(tasks.generateProto)
|
||||
tasks.eclipse.dependsOn(tasks.generateProto)
|
||||
rootProject.tasks.prepDev.dependsOn(tasks.generateProto)
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDir tasks.generateProto.outdir
|
||||
}
|
||||
}
|
||||
}
|
||||
zipSourceSubproject.dependsOn generateProto
|
||||
|
||||
// Include buildable native source in distribution
|
||||
rootProject.assembleDistribution {
|
||||
from (this.project.projectDir.toString()) {
|
||||
include "runISFServer"
|
||||
into { getZipPath(this.project) }
|
||||
}
|
||||
}
|
||||
|
3
Ghidra/Debug/Debugger-isf/certification.manifest
Normal file
3
Ghidra/Debug/Debugger-isf/certification.manifest
Normal file
|
@ -0,0 +1,3 @@
|
|||
##VERSION: 2.0
|
||||
Module.manifest||GHIDRA||||END|
|
||||
runISFServer||GHIDRA||||END|
|
36
Ghidra/Debug/Debugger-isf/runISFServer
Executable file
36
Ghidra/Debug/Debugger-isf/runISFServer
Executable file
|
@ -0,0 +1,36 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
#------------------------------------
|
||||
# Ghidra headless ISF Server launch
|
||||
#------------------------------------
|
||||
|
||||
# Maximum heap memory may be changed if default is inadequate. This will generally be up to 1/4 of
|
||||
# the physical memory available to the OS. Uncomment MAXMEM setting if non-default value is needed.
|
||||
MAXMEM=2G
|
||||
|
||||
# Launch mode can be changed to one of the following: fg, debug, debug-suspend
|
||||
LAUNCH_MODE=fg
|
||||
|
||||
# Set the debug address to listen on.
|
||||
# NOTE: This variable is ignored if not launching in a debugging mode.
|
||||
DEBUG_ADDRESS=127.0.0.1:13002
|
||||
|
||||
# Limit the # of garbage collection and JIT compiler threads in case many headless
|
||||
# instances are run in parallel. By default, Java will assign one thread per core
|
||||
# which does not scale well on servers with many cores.
|
||||
VMARG_LIST="-XX:ParallelGCThreads=2 -XX:CICompilerCount=2 "
|
||||
|
||||
# Resolve symbolic link if present and get the directory this script lives in.
|
||||
# NOTE: "readlink -f" is best but works on Linux only, "readlink" will only work if your PWD
|
||||
# contains the link you are calling (which is the best we can do on macOS), and the "echo" is the
|
||||
# fallback, which doesn't attempt to do anything with links.
|
||||
SCRIPT_FILE="$(readlink -f "$0" 2>/dev/null || readlink "$0" 2>/dev/null || echo "$0")"
|
||||
SCRIPT_DIR="${SCRIPT_FILE%/*}"
|
||||
SUPPORT_DIR="${SCRIPT_DIR}/../../../support"
|
||||
if ! [ -f "${SUPPORT_DIR}/launch.properties" ]; then
|
||||
SUPPORT_DIR="${SCRIPT_DIR}/../../RuntimeScripts/Linux/support"
|
||||
fi
|
||||
|
||||
# Launch ISF Server.
|
||||
# DEBUG_ADDRESS set via environment for launch.sh
|
||||
DEBUG_ADDRESS=${DEBUG_ADDRESS} "${SUPPORT_DIR}"/launch.sh "${LAUNCH_MODE}" jdk Ghidra-ISF "${MAXMEM}" "${VMARG_LIST}" ghidra.dbg.isf.IsfServerLauncher "$@"
|
|
@ -0,0 +1,305 @@
|
|||
/* ###
|
||||
* 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.datamgr.actions;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.filechooser.GhidraFileChooser;
|
||||
import docking.widgets.tree.GTree;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.tree.CategoryNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeNode;
|
||||
import ghidra.framework.preferences.Preferences;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.ISF.IsfDataTypeWriter;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.classfinder.ClassSearcher;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.filechooser.ExtensionFileFilter;
|
||||
import ghidra.util.task.*;
|
||||
|
||||
// This action was originally referenced by DataTypeProvider::createLocalActions to support testing.
|
||||
// It may (?) be of general use at some point, but including it in the original location introduces
|
||||
// a dependency on this project, which seems undesirable right now.
|
||||
|
||||
public class ExportToIsfAction extends DockingAction {
|
||||
private static final String LAST_DATA_TYPE_EXPORT_DIRECTORY = "LAST_DATA_TYPE_EXPORT_DIRECTORY";
|
||||
|
||||
private final DataTypeManagerPlugin plugin;
|
||||
|
||||
public ExportToIsfAction(DataTypeManagerPlugin plugin) {
|
||||
super("Export Data Types (ISF)", plugin.getName());
|
||||
this.plugin = plugin;
|
||||
|
||||
setPopupMenuData(new MenuData(new String[] { "Export to ISF..." }, null, "VeryLast"));
|
||||
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
if (!(context instanceof DataTypesActionContext)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object contextObject = context.getContextObject();
|
||||
GTree gtree = (GTree) contextObject;
|
||||
TreePath[] selectionPaths = gtree.getSelectionPaths();
|
||||
for (TreePath path : selectionPaths) {
|
||||
GTreeNode node = (GTreeNode) path.getLastPathComponent();
|
||||
if (!isValidNode(node)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isValidNode(GTreeNode node) {
|
||||
if (node instanceof CategoryNode) {
|
||||
CategoryNode categoryNode = (CategoryNode) node;
|
||||
return categoryNode.isEnabled();
|
||||
}
|
||||
else if (node instanceof DataTypeNode) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
DataTypesActionContext dtActionContext = (DataTypesActionContext) context;
|
||||
GTree gTree = (GTree) dtActionContext.getContextObject();
|
||||
Program program = dtActionContext.getProgram();
|
||||
if (program == null) {
|
||||
Msg.showError(this, gTree, "Archive Export Failed",
|
||||
"A suitable program must be open and activated before\n" +
|
||||
"an archive export may be performed.");
|
||||
return;
|
||||
}
|
||||
if (OptionDialog.showYesNoDialog(gTree, "Confirm Archive Export",
|
||||
"Export selected archive(s) using program " + program.getName() +
|
||||
"'s compiler specification?") != OptionDialog.YES_OPTION) {
|
||||
return;
|
||||
}
|
||||
exportToIsf(gTree, program.getDataTypeManager());
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the selection out to a file of the user's choosing. One file will be written for each
|
||||
* DataTypeManager in the selection.
|
||||
*
|
||||
* @param gTree The tree that contains the selected nodes.
|
||||
*/
|
||||
private void exportToIsf(GTree gTree, DataTypeManager programDataTypeMgr) {
|
||||
|
||||
List<Class<? extends AnnotationHandler>> classes =
|
||||
ClassSearcher.getClasses(AnnotationHandler.class);
|
||||
|
||||
List<AnnotationHandler> list = new ArrayList<>();
|
||||
Class<?>[] constructorArgumentTypes = {};
|
||||
for (Class<? extends AnnotationHandler> clazz : classes) {
|
||||
|
||||
if (clazz == DefaultAnnotationHandler.class) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
Constructor<?> constructor = clazz.getConstructor(constructorArgumentTypes);
|
||||
Object obj = constructor.newInstance();
|
||||
list.add(AnnotationHandler.class.cast(obj));
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.showError(this, plugin.getTool().getToolFrame(), "Export Data Types",
|
||||
"Error creating " + clazz.getName() + "\n" + e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
AnnotationHandler handler = null;
|
||||
if (!list.isEmpty()) {
|
||||
list.add(0, new DefaultAnnotationHandler());
|
||||
AnnotationHandlerDialog dlg = new AnnotationHandlerDialog(list);
|
||||
plugin.getTool().showDialog(dlg);
|
||||
if (!dlg.wasSuccessful()) {
|
||||
return;
|
||||
}
|
||||
handler = dlg.getHandler();
|
||||
}
|
||||
else {
|
||||
handler = new DefaultAnnotationHandler();
|
||||
}
|
||||
|
||||
TreePath[] paths = gTree.getSelectionPaths();
|
||||
Map<DataTypeManager, List<DataType>> managersToDataTypesMap = new HashMap<>();
|
||||
|
||||
for (TreePath path : paths) {
|
||||
addToManager(path, managersToDataTypesMap);
|
||||
}
|
||||
|
||||
GhidraFileChooser fileChooser = new GhidraFileChooser(gTree);
|
||||
|
||||
// filter the files if we can
|
||||
String[] fileExtensions = handler.getFileExtensions();
|
||||
if (fileExtensions.length > 0) {
|
||||
fileChooser.setFileFilter(
|
||||
new ExtensionFileFilter(fileExtensions, handler.getLanguageName() + " Files"));
|
||||
}
|
||||
|
||||
Set<Entry<DataTypeManager, List<DataType>>> entrySet = managersToDataTypesMap.entrySet();
|
||||
for (Entry<DataTypeManager, List<DataType>> entry : entrySet) {
|
||||
DataTypeManager dataTypeManager = entry.getKey();
|
||||
File file = getFile(gTree, fileChooser, dataTypeManager, handler);
|
||||
if (file == null) {
|
||||
return; // user cancelled
|
||||
}
|
||||
|
||||
List<DataType> dataTypeList = entry.getValue();
|
||||
new TaskLauncher(
|
||||
new DataTypeWriterTask(gTree, programDataTypeMgr, dataTypeList, file),
|
||||
gTree);
|
||||
}
|
||||
|
||||
fileChooser.dispose();
|
||||
}
|
||||
|
||||
private class DataTypeWriterTask extends Task {
|
||||
|
||||
private final DataTypeManager programDataTypeMgr;
|
||||
private final List<DataType> dataTypeList;
|
||||
private final File file;
|
||||
private final GTree gTree;
|
||||
|
||||
DataTypeWriterTask(GTree gTree, DataTypeManager programDataTypeMgr,
|
||||
List<DataType> dataTypeList, File file) {
|
||||
super("Export Data Types", true, false, true);
|
||||
this.gTree = gTree;
|
||||
this.programDataTypeMgr = programDataTypeMgr;
|
||||
this.dataTypeList = dataTypeList;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(TaskMonitor monitor) {
|
||||
try {
|
||||
monitor.setMessage("Export to " + file.getName() + "...");
|
||||
IsfDataTypeWriter dataTypeWriter =
|
||||
new IsfDataTypeWriter(programDataTypeMgr, new FileWriter(file));
|
||||
|
||||
try {
|
||||
for (DataType dataType : dataTypeList) {
|
||||
dataTypeWriter.requestType(dataType);
|
||||
}
|
||||
JsonObject object = dataTypeWriter.getRootObject(monitor);
|
||||
dataTypeWriter.write(object);
|
||||
}
|
||||
finally {
|
||||
dataTypeWriter.close();
|
||||
}
|
||||
plugin.getTool()
|
||||
.setStatusInfo(
|
||||
"Successfully exported data type(s) to " + file.getAbsolutePath());
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// user cancelled; ignore
|
||||
}
|
||||
catch (IOException e) {
|
||||
Msg.showError(getClass(), gTree, "Export Data Types Failed",
|
||||
"Error exporting Data Types: " + e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addToManager(TreePath path,
|
||||
Map<DataTypeManager, List<DataType>> managersToDataTypesMap) {
|
||||
Object last = path.getLastPathComponent();
|
||||
if (last instanceof DataTypeNode) {
|
||||
DataTypeNode node = (DataTypeNode) last;
|
||||
DataType dataType = node.getDataType();
|
||||
DataTypeManager dataTypeManager = dataType.getDataTypeManager();
|
||||
|
||||
List<DataType> dataTypeList = managersToDataTypesMap.get(dataTypeManager);
|
||||
if (dataTypeList == null) {
|
||||
dataTypeList = new ArrayList<>();
|
||||
managersToDataTypesMap.put(dataTypeManager, dataTypeList);
|
||||
}
|
||||
|
||||
dataTypeList.add(dataType);
|
||||
}
|
||||
else if (last instanceof CategoryNode) {
|
||||
CategoryNode node = (CategoryNode) last;
|
||||
List<GTreeNode> children = node.getChildren();
|
||||
for (GTreeNode cnode : children) {
|
||||
addToManager(cnode.getTreePath(), managersToDataTypesMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private File getFile(GTree gTree, GhidraFileChooser fileChooser,
|
||||
DataTypeManager dataTypeManager, AnnotationHandler handler) {
|
||||
|
||||
fileChooser.setTitle("Select File For Export: " + dataTypeManager.getName());
|
||||
fileChooser.setSelectedFile(null);
|
||||
|
||||
String defaultExtendsionSuffix = ".json";
|
||||
|
||||
String lastDirSelected = Preferences.getProperty(LAST_DATA_TYPE_EXPORT_DIRECTORY);
|
||||
if (lastDirSelected != null) {
|
||||
File file = new File(lastDirSelected);
|
||||
if (file.exists()) {
|
||||
fileChooser.setCurrentDirectory(file);
|
||||
}
|
||||
}
|
||||
|
||||
fileChooser.rescanCurrentDirectory(); // pick up any recently added archives
|
||||
File currentDirectory = fileChooser.getCurrentDirectory();
|
||||
File newFile =
|
||||
new File(currentDirectory, dataTypeManager.getName() + defaultExtendsionSuffix);
|
||||
fileChooser.setSelectedFile(newFile);
|
||||
|
||||
// show the chooser
|
||||
File file = fileChooser.getSelectedFile();
|
||||
if (file == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (file.exists()) {
|
||||
if (OptionDialog.showYesNoDialog(gTree, "Overwrite Existing File?",
|
||||
"Do you want to overwrite the existing file \"" + file.getAbsolutePath() +
|
||||
"\"?") == OptionDialog.OPTION_TWO) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// save the directory off for the next export
|
||||
Preferences.setProperty(LAST_DATA_TYPE_EXPORT_DIRECTORY, file.getAbsolutePath());
|
||||
|
||||
return file;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,219 @@
|
|||
/* ###
|
||||
* 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.dbg.isf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import ghidra.async.AsyncUtils;
|
||||
import ghidra.dbg.isf.protocol.Isf;
|
||||
import ghidra.dbg.isf.protocol.Isf.ErrorCode;
|
||||
import ghidra.dbg.isf.protocol.Isf.RootMessage;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.ISF.IsfDataTypeWriter;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class IsfClientHandler {
|
||||
protected static final boolean LOG_ERROR_REPLY_STACKS = false;
|
||||
|
||||
protected final static AtomicInteger sequencer = new AtomicInteger();
|
||||
|
||||
protected static <T> T errorSendNotify(Throwable e) {
|
||||
Msg.error(IsfClientHandler.class, "Could not send notification: " + e);
|
||||
return null;
|
||||
}
|
||||
|
||||
private IsfServer server;
|
||||
|
||||
// Keeps strong references and tells level of subscription
|
||||
|
||||
public IsfClientHandler(IsfServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
protected Isf.RootMessage buildError(Isf.RootMessage req, ErrorCode code, String message) {
|
||||
return Isf.RootMessage.newBuilder()
|
||||
.setSequence(req.getSequence())
|
||||
.setErrorReply(Isf.ErrorReply.newBuilder().setCode(code).setMessage(message))
|
||||
.build();
|
||||
}
|
||||
|
||||
protected RootMessage replyError(Isf.RootMessage req, Throwable e) {
|
||||
Throwable t = AsyncUtils.unwrapThrowable(e);
|
||||
if (LOG_ERROR_REPLY_STACKS) {
|
||||
Msg.debug(this, "Error caused by request " + req, e);
|
||||
}
|
||||
else {
|
||||
Msg.debug(this, "Error caused by request " + req + ": " + e);
|
||||
}
|
||||
if (t instanceof UnsupportedOperationException) {
|
||||
return buildError(req, ErrorCode.EC_NOT_SUPPORTED, t.getMessage());
|
||||
}
|
||||
return buildError(req, ErrorCode.EC_UNKNOWN, "Unknown server-side error");
|
||||
}
|
||||
|
||||
protected String getVersion() {
|
||||
return "V1";
|
||||
}
|
||||
|
||||
protected RootMessage processMessage(Isf.RootMessage msg) throws IOException {
|
||||
switch (msg.getMsgCase()) {
|
||||
case PING_REQUEST:
|
||||
return processPing(msg.getSequence(), msg.getPingRequest());
|
||||
case FULL_EXPORT_REQUEST:
|
||||
return processFullExport(msg.getSequence(), msg.getFullExportRequest());
|
||||
case LOOK_TYPE_REQUEST:
|
||||
return processLookType(msg.getSequence(), msg.getLookTypeRequest());
|
||||
case LOOK_SYMBOL_REQUEST:
|
||||
return processLookSym(msg.getSequence(), msg.getLookSymbolRequest());
|
||||
case LOOK_ADDRESS_REQUEST:
|
||||
return processLookAddr(msg.getSequence(), msg.getLookAddressRequest());
|
||||
case ENUM_TYPES_REQUEST:
|
||||
return processEnumTypes(msg.getSequence(), msg.getEnumTypesRequest());
|
||||
case ENUM_SYMBOLS_REQUEST:
|
||||
return processEnumSyms(msg.getSequence(), msg.getEnumSymbolsRequest());
|
||||
default:
|
||||
throw new IsfErrorException(Isf.ErrorCode.EC_BAD_REQUEST,
|
||||
"Unrecognized request: " + msg.getMsgCase());
|
||||
}
|
||||
}
|
||||
|
||||
protected RootMessage processPing(int seqno, Isf.PingRequest req) {
|
||||
return Isf.RootMessage.newBuilder()
|
||||
.setSequence(seqno)
|
||||
.setPingReply(Isf.PingReply.newBuilder().setContent(req.getContent()))
|
||||
.build();
|
||||
}
|
||||
|
||||
protected RootMessage processFullExport(int seqno, Isf.FullExportRequest req)
|
||||
throws IOException {
|
||||
String data = fullExport(req.getNs());
|
||||
return Isf.RootMessage.newBuilder()
|
||||
.setSequence(seqno)
|
||||
.setFullExportReply(Isf.FullExportReply.newBuilder()
|
||||
.setValue(data))
|
||||
.build();
|
||||
}
|
||||
|
||||
private String fullExport(String ns) throws IOException {
|
||||
IsfDataTypeWriter isfWriter = createDataTypeWriter(server.getDataTypeManager(ns));
|
||||
return writeFrom(isfWriter);
|
||||
}
|
||||
|
||||
protected RootMessage processLookType(int seqno, Isf.LookTypeRequest req) throws IOException {
|
||||
String data = lookType(req.getNs(), req.getKey());
|
||||
return Isf.RootMessage.newBuilder()
|
||||
.setSequence(seqno)
|
||||
.setLookTypeReply(Isf.LookTypeReply.newBuilder()
|
||||
.setValue(data))
|
||||
.build();
|
||||
}
|
||||
|
||||
private String lookType(String ns, String key) throws IOException {
|
||||
IsfDataTypeWriter isfWriter = createDataTypeWriter(server.getDataTypeManager(ns));
|
||||
isfWriter.setSkipSymbols(true);
|
||||
isfWriter.requestType(key);
|
||||
return writeFrom(isfWriter);
|
||||
}
|
||||
|
||||
protected RootMessage processLookSym(int seqno, Isf.LookSymRequest req) throws IOException {
|
||||
String data = lookSym(req.getNs(), req.getKey());
|
||||
return Isf.RootMessage.newBuilder()
|
||||
.setSequence(seqno)
|
||||
.setLookSymbolReply(Isf.LookSymReply.newBuilder()
|
||||
.setValue(data))
|
||||
.build();
|
||||
}
|
||||
|
||||
private String lookSym(String ns, String key) throws IOException {
|
||||
IsfDataTypeWriter isfWriter = createDataTypeWriter(server.getDataTypeManager(ns));
|
||||
isfWriter.setSkipTypes(true);
|
||||
isfWriter.requestSymbol(key);
|
||||
return writeFrom(isfWriter);
|
||||
}
|
||||
|
||||
protected RootMessage processLookAddr(int seqno, Isf.LookAddrRequest req) throws IOException {
|
||||
String data = lookAddr(req.getNs(), req.getKey());
|
||||
return Isf.RootMessage.newBuilder()
|
||||
.setSequence(seqno)
|
||||
.setLookAddressReply(Isf.LookAddrReply.newBuilder()
|
||||
.setValue(data))
|
||||
.build();
|
||||
}
|
||||
|
||||
private String lookAddr(String ns, String key) throws IOException {
|
||||
IsfDataTypeWriter isfWriter = createDataTypeWriter(server.getDataTypeManager(ns));
|
||||
isfWriter.setSkipTypes(true);
|
||||
isfWriter.requestAddress(key);
|
||||
return writeFrom(isfWriter);
|
||||
}
|
||||
|
||||
protected RootMessage processEnumTypes(int seqno, Isf.EnumTypesRequest req) throws IOException {
|
||||
String data = enumTypes(req.getNs());
|
||||
return Isf.RootMessage.newBuilder()
|
||||
.setSequence(seqno)
|
||||
.setEnumTypesReply(Isf.EnumTypesReply.newBuilder()
|
||||
.setValue(data))
|
||||
.build();
|
||||
}
|
||||
|
||||
private String enumTypes(String ns) throws IOException {
|
||||
IsfDataTypeWriter isfWriter = createDataTypeWriter(server.getDataTypeManager(ns));
|
||||
isfWriter.setSkipSymbols(true);
|
||||
return writeFrom(isfWriter);
|
||||
}
|
||||
|
||||
protected RootMessage processEnumSyms(int seqno, Isf.EnumSymsRequest req) throws IOException {
|
||||
String data = enumSyms(req.getNs());
|
||||
return Isf.RootMessage.newBuilder()
|
||||
.setSequence(seqno)
|
||||
.setEnumSymbolsReply(Isf.EnumSymsReply.newBuilder()
|
||||
.setValue(data))
|
||||
.build();
|
||||
}
|
||||
|
||||
private String enumSyms(String ns) throws IOException {
|
||||
IsfDataTypeWriter isfWriter = createDataTypeWriter(server.getDataTypeManager(ns));
|
||||
isfWriter.setSkipTypes(true);
|
||||
return writeFrom(isfWriter);
|
||||
}
|
||||
|
||||
private IsfDataTypeWriter createDataTypeWriter(DataTypeManager dtm) throws IOException {
|
||||
StringWriter out = new StringWriter();
|
||||
return new IsfDataTypeWriter(dtm, out);
|
||||
}
|
||||
|
||||
private String writeFrom(IsfDataTypeWriter dataTypeWriter) throws IOException {
|
||||
try {
|
||||
JsonObject object =
|
||||
dataTypeWriter.getRootObject(TaskMonitor.DUMMY);
|
||||
dataTypeWriter.write(object);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// NOTHING
|
||||
}
|
||||
finally {
|
||||
dataTypeWriter.close();
|
||||
}
|
||||
return dataTypeWriter.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -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.dbg.isf;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.Socket;
|
||||
|
||||
import com.google.protobuf.AbstractMessage;
|
||||
|
||||
import ghidra.dbg.isf.protocol.Isf.RootMessage;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class IsfConnectionHandler extends Thread {
|
||||
|
||||
private Socket socket;
|
||||
private IsfClientHandler handler;
|
||||
|
||||
public IsfConnectionHandler(Socket socket, IsfClientHandler handler) {
|
||||
this.socket = socket;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Msg.info(this, "Handler started...");
|
||||
InputStream inputStream = socket.getInputStream();
|
||||
while (!socket.isClosed()) {
|
||||
RootMessage root = RootMessage.parseDelimitedFrom(inputStream);
|
||||
if (root != null) {
|
||||
AbstractMessage msg = handler.processMessage(root);
|
||||
OutputStream out = socket.getOutputStream();
|
||||
msg.writeDelimitedTo(out);
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
Msg.error(this, e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/* ###
|
||||
* 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.dbg.isf;
|
||||
|
||||
import ghidra.dbg.isf.protocol.Isf.ErrorCode;
|
||||
|
||||
public class IsfErrorException extends RuntimeException {
|
||||
private ErrorCode code;
|
||||
|
||||
public IsfErrorException(ErrorCode code, String message) {
|
||||
super(code + ": " + message);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public ErrorCode getCode() {
|
||||
return code;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
/* ###
|
||||
* 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.dbg.isf;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import db.DBConstants;
|
||||
import db.DBHandle;
|
||||
import generic.test.AbstractGTest;
|
||||
import ghidra.GhidraApplicationLayout;
|
||||
import ghidra.GhidraTestApplicationLayout;
|
||||
import ghidra.base.project.GhidraProject;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.GhidraApplicationConfiguration;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.model.ProjectData;
|
||||
import ghidra.framework.store.db.PackedDatabase;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
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 {
|
||||
private ServerSocket server;
|
||||
|
||||
private boolean running = false;
|
||||
private GhidraProject project;
|
||||
private int port = 54321;
|
||||
private IsfClientHandler handler;
|
||||
|
||||
private Map<String, DataTypeManager> managers = new HashMap<>();
|
||||
|
||||
public IsfServer(GhidraProject project, int port) {
|
||||
this.project = project;
|
||||
this.port = port;
|
||||
handler = new IsfClientHandler(this);
|
||||
}
|
||||
|
||||
public void startServer() {
|
||||
try {
|
||||
server = new ServerSocket(port);
|
||||
this.start();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException("Could not start server");
|
||||
}
|
||||
}
|
||||
|
||||
public void stopServer() {
|
||||
running = false;
|
||||
this.interrupt();
|
||||
for (DataTypeManager m : managers.values()) {
|
||||
m.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
running = true;
|
||||
while (running) {
|
||||
try {
|
||||
Msg.info(this, "Listening for a connection...");
|
||||
|
||||
Socket socket = server.accept();
|
||||
socket.setTcpNoDelay(true);
|
||||
|
||||
Msg.info(this, "Connected - starting handler...");
|
||||
IsfConnectionHandler connectionHandler = new IsfConnectionHandler(socket, handler);
|
||||
connectionHandler.start();
|
||||
}
|
||||
catch (IOException e) {
|
||||
Msg.error(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DataTypeManager getDataTypeManager(String ns) {
|
||||
synchronized (managers) {
|
||||
if (managers.containsKey(ns)) {
|
||||
return managers.get(ns);
|
||||
}
|
||||
try {
|
||||
DataTypeManager dtm;
|
||||
if (ns.endsWith(".gdt")) {
|
||||
dtm = openAsArchive(ns);
|
||||
}
|
||||
else if (ns.endsWith(".gzf")) {
|
||||
dtm = openAsDatabase(ns);
|
||||
}
|
||||
else {
|
||||
dtm = openAsDomainFile(ns);
|
||||
}
|
||||
managers.put(ns, dtm);
|
||||
return dtm;
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.error(this, ns + " undefined namespace (should be .gdt, .gzf, or domain file)");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DataTypeManager openAsDomainFile(String ns) throws Exception {
|
||||
ProjectData projectData = project.getProjectData();
|
||||
DomainFile df = projectData.getFile(ns);
|
||||
Program program = (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
|
||||
return program.getDataTypeManager();
|
||||
}
|
||||
|
||||
private DataTypeManager openAsArchive(String ns) throws Exception {
|
||||
File gdt = new File(ns);
|
||||
return FileDataTypeManager.openFileArchive(gdt, false);
|
||||
}
|
||||
|
||||
private DataTypeManager openAsDatabase(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;
|
||||
try {
|
||||
p = new ProgramDB(dbh, DBConstants.UPDATE, dummy, this);
|
||||
}
|
||||
catch (VersionException e) {
|
||||
if (!e.isUpgradable()) {
|
||||
throw new RuntimeException(p + " uses an older version and is not upgradable.");
|
||||
}
|
||||
}
|
||||
finally {
|
||||
dbh.close();
|
||||
}
|
||||
|
||||
dbh = db.openForUpdate(dummy);
|
||||
p = new ProgramDB(dbh, DBConstants.UPGRADE, dummy, this);
|
||||
|
||||
if (!p.isChanged()) {
|
||||
throw new RuntimeException(p + " uses an older version and was not upgraded.");
|
||||
}
|
||||
|
||||
return p.getListing().getDataTypeManager();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws FileNotFoundException, IOException {
|
||||
GhidraApplicationLayout layout = new GhidraTestApplicationLayout(
|
||||
new File(AbstractGTest.getTestDirectoryPath()));
|
||||
GhidraApplicationConfiguration config = new GhidraApplicationConfiguration();
|
||||
config.setShowSplashScreen(false);
|
||||
Application.initializeApplication(layout, config);
|
||||
|
||||
IsfServer server = new IsfServer(null, 54321);
|
||||
server.startServer();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/* ###
|
||||
* 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.dbg.isf;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.GhidraApplicationLayout;
|
||||
import ghidra.GhidraLaunchable;
|
||||
import ghidra.base.project.GhidraProject;
|
||||
import ghidra.framework.*;
|
||||
import ghidra.framework.model.ProjectLocator;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
// To be run using runISFServer
|
||||
|
||||
public class IsfServerLauncher implements GhidraLaunchable {
|
||||
|
||||
private GhidraProject project = null;
|
||||
private IsfServer server;
|
||||
private int port;
|
||||
|
||||
@Override
|
||||
public void launch(GhidraApplicationLayout layout, String[] args) throws Exception {
|
||||
|
||||
ApplicationConfiguration config = new HeadlessGhidraApplicationConfiguration();
|
||||
if (!Application.isInitialized()) {
|
||||
Application.initializeApplication(layout, config);
|
||||
}
|
||||
|
||||
GhidraProject proj = parseArgs(args);
|
||||
server = new IsfServer(proj, port);
|
||||
server.startServer();
|
||||
}
|
||||
|
||||
GhidraProject parseArgs(String[] args) throws IOException {
|
||||
if (args != null && args.length < 1) {
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
port = Integer.parseInt(args[0]);
|
||||
if (args.length > 1) {
|
||||
String projectLocation = args[1];
|
||||
String projectName = args[2];
|
||||
|
||||
File dir = new File(projectLocation);
|
||||
if (dir.exists()) {
|
||||
ProjectLocator locator = new ProjectLocator(dir.getAbsolutePath(), projectName);
|
||||
|
||||
if (locator.getProjectDir().exists()) {
|
||||
project = GhidraProject.openProject(projectLocation, projectName);
|
||||
}
|
||||
}
|
||||
}
|
||||
return project;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
server.stopServer();
|
||||
if (project != null) {
|
||||
project.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void usage() {
|
||||
Msg.error(this, "Usage: runISFServer <port> <project_location> <project_name> ");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import ghidra.program.model.data.BuiltInDataType;
|
||||
|
||||
public class IsfBuiltIn implements IsfObject {
|
||||
|
||||
public Integer size;
|
||||
public Boolean signed;
|
||||
public String kind;
|
||||
public String endian;
|
||||
|
||||
public IsfBuiltIn(BuiltInDataType builtin) {
|
||||
size = IsfUtilities.getLength(builtin);
|
||||
signed = IsfUtilities.getSigned(builtin);
|
||||
kind = IsfUtilities.getBuiltInKind(builtin);
|
||||
endian = IsfUtilities.getEndianness(builtin);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import ghidra.program.model.data.DataTypeComponent;
|
||||
import ghidra.program.model.data.ISF.IsfDataTypeWriter.Exclude;
|
||||
|
||||
public class IsfComponent implements IsfObject {
|
||||
|
||||
public Integer offset;
|
||||
public IsfObject type;
|
||||
|
||||
@Exclude
|
||||
public int ordinal;
|
||||
@Exclude
|
||||
public int length;
|
||||
@Exclude
|
||||
public String field_name;
|
||||
@Exclude
|
||||
public String comment;
|
||||
|
||||
public IsfComponent(DataTypeComponent component, IsfObject typeObj) {
|
||||
offset = component.getOffset();
|
||||
type = typeObj;
|
||||
|
||||
field_name = component.getFieldName();
|
||||
ordinal = component.getOrdinal();
|
||||
length = component.getLength();
|
||||
comment = component.getComment();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.ISF.IsfDataTypeWriter.Exclude;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class IsfComposite implements IsfObject {
|
||||
|
||||
public String kind;
|
||||
public Integer size;
|
||||
public JsonObject fields;
|
||||
|
||||
@Exclude
|
||||
public int alignment;
|
||||
|
||||
public IsfComposite(Composite composite, IsfDataTypeWriter writer, TaskMonitor monitor) {
|
||||
size = composite.getLength();
|
||||
kind = composite instanceof Structure ? "struct" : "union";
|
||||
alignment = composite.getAlignment();
|
||||
|
||||
DataTypeComponent[] components = composite.getComponents();
|
||||
Map<String, DataTypeComponent> comps = new HashMap<>();
|
||||
for (DataTypeComponent component : components) {
|
||||
String key = component.getFieldName();
|
||||
if (key == null) {
|
||||
key = component.getDefaultFieldName();
|
||||
}
|
||||
comps.put(key, component);
|
||||
}
|
||||
ArrayList<String> keylist = new ArrayList<>(comps.keySet());
|
||||
Collections.sort(keylist);
|
||||
|
||||
fields = new JsonObject();
|
||||
for (String key : keylist) {
|
||||
if (monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
|
||||
DataTypeComponent component = comps.get(key);
|
||||
IsfObject type = writer.getObjectTypeDeclaration(component);
|
||||
IsfComponent cobj = new IsfComponent(component, type);
|
||||
fields.add(key, writer.getTree(cobj));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import ghidra.program.model.data.Array;
|
||||
|
||||
public class IsfDataTypeArray implements IsfObject {
|
||||
|
||||
public String kind;
|
||||
public Integer count;
|
||||
public IsfObject subtype;
|
||||
|
||||
public IsfDataTypeArray(Array arr, IsfObject typeObj) {
|
||||
kind = IsfUtilities.getKind(arr);
|
||||
count = arr.getNumElements();
|
||||
subtype = typeObj;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import ghidra.program.model.data.BitFieldDataType;
|
||||
import ghidra.program.model.data.ISF.IsfDataTypeWriter.Exclude;
|
||||
|
||||
public class IsfDataTypeBitField implements IsfObject {
|
||||
|
||||
public String kind;
|
||||
public Integer bit_length;
|
||||
public Integer bit_position;
|
||||
public IsfObject type;
|
||||
|
||||
@Exclude
|
||||
public Integer bit_offset;
|
||||
@Exclude
|
||||
private int storage_size;
|
||||
|
||||
public IsfDataTypeBitField(BitFieldDataType bf, int componentOffset, IsfObject typeObj) {
|
||||
kind = IsfUtilities.getKind(bf);
|
||||
bit_length = bf.getBitSize();
|
||||
bit_offset = bf.getBitOffset();
|
||||
bit_position = componentOffset % 4 * 8 + bit_offset;
|
||||
type = typeObj;
|
||||
|
||||
storage_size = bf.getStorageSize();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import ghidra.program.model.data.DataType;
|
||||
|
||||
public class IsfDataTypeDefault implements IsfObject {
|
||||
|
||||
public String kind;
|
||||
public String name;
|
||||
|
||||
public IsfDataTypeDefault(DataType dt) {
|
||||
kind = IsfUtilities.getKind(dt);
|
||||
name = dt.getName();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
public class IsfDataTypeNull implements IsfObject {
|
||||
|
||||
public String kind;
|
||||
public String name;
|
||||
|
||||
public IsfDataTypeNull() {
|
||||
kind = "base";
|
||||
name = "void";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import ghidra.program.model.data.DataType;
|
||||
|
||||
public class IsfDataTypeTypeDef implements IsfObject {
|
||||
|
||||
public String kind;
|
||||
public IsfObject subtype;
|
||||
|
||||
public IsfDataTypeTypeDef(DataType dt, IsfObject typeObj) {
|
||||
kind = IsfUtilities.getKind(dt);
|
||||
subtype = typeObj;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,629 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.lang.annotation.*;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import ghidra.program.database.data.ProgramDataTypeManager;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressFormatException;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* A class used to export data types and symbols as ISF JSON.
|
||||
*
|
||||
* The ISF JSON should be valid for Volatility is STRICT==true.
|
||||
*/
|
||||
public class IsfDataTypeWriter {
|
||||
|
||||
private Map<DataType, IsfObject> resolved = new HashMap<>();
|
||||
private Map<String, DataType> resolvedTypeMap = new HashMap<>();
|
||||
private List<String> deferredKeys = new ArrayList<>();
|
||||
|
||||
private Writer baseWriter;
|
||||
private JsonWriter writer;
|
||||
private Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
private DataTypeManager dtm;
|
||||
private DataOrganization dataOrganization;
|
||||
|
||||
private JsonObject data = new JsonObject();
|
||||
private JsonObject metadata = new JsonObject();
|
||||
private JsonObject baseTypes = new JsonObject();
|
||||
private JsonObject userTypes = new JsonObject();
|
||||
private JsonObject enums = new JsonObject();
|
||||
private JsonObject symbols = new JsonObject();
|
||||
|
||||
private List<Address> requestedAddresses = new ArrayList<>();
|
||||
private List<String> requestedSymbols = new ArrayList<>();
|
||||
private List<String> requestedTypes = new ArrayList<>();
|
||||
private List<DataType> requestedDataTypes = new ArrayList<>();
|
||||
private boolean skipSymbols = false;
|
||||
private boolean skipTypes = false;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of this class using the given writer
|
||||
*
|
||||
* @param dtm data-type manager corresponding to target program or null for default
|
||||
* @param baseWriter the writer to use when writing data types
|
||||
* @throws IOException if there is an exception writing the output
|
||||
*/
|
||||
public IsfDataTypeWriter(DataTypeManager dtm, Writer baseWriter) throws IOException {
|
||||
this.dtm = dtm;
|
||||
if (dtm != null) {
|
||||
dataOrganization = dtm.getDataOrganization();
|
||||
}
|
||||
if (dataOrganization == null) {
|
||||
dataOrganization = DataOrganizationImpl.getDefaultOrganization();
|
||||
}
|
||||
this.baseWriter = baseWriter;
|
||||
this.writer = new JsonWriter(baseWriter);
|
||||
writer.setIndent(" ");
|
||||
this.gson = new GsonBuilder()
|
||||
.addSerializationExclusionStrategy(strategy)
|
||||
.setPrettyPrinting()
|
||||
.create();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Exclude {
|
||||
//EMPTY
|
||||
}
|
||||
|
||||
// Am setting this as the default, but it's possible we may want more latitude in the future
|
||||
private boolean STRICT = true;
|
||||
|
||||
// @Exclude used for properties that might be desirable for a non-STRICT implementation.
|
||||
ExclusionStrategy strategy = new ExclusionStrategy() {
|
||||
@Override
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldSkipField(FieldAttributes field) {
|
||||
return STRICT && field.getAnnotation(Exclude.class) != null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Exports all data types in the list as ISF JSON.
|
||||
*
|
||||
* @param monitor the task monitor
|
||||
* @return the resultant JSON object
|
||||
* @throws IOException if there is an exception writing the output
|
||||
* @throws CancelledException if the action is cancelled by the user
|
||||
*/
|
||||
public JsonObject getRootObject(TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
|
||||
genMetadata();
|
||||
genTypes(monitor);
|
||||
genSymbols();
|
||||
genRoot();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private void genRoot() {
|
||||
data.add("metadata", metadata);
|
||||
data.add("base_types", baseTypes);
|
||||
data.add("user_types", userTypes);
|
||||
data.add("enums", enums);
|
||||
// Would be nice to support this in the futere, but Volatility does not
|
||||
//data.add("typedefs", typedefs);
|
||||
data.add("symbols", symbols);
|
||||
}
|
||||
|
||||
private void genMetadata() {
|
||||
String oskey = "UNKNOWN";
|
||||
if (dtm instanceof ProgramDataTypeManager) {
|
||||
ProgramDataTypeManager pgmDtm = (ProgramDataTypeManager) dtm;
|
||||
Program program = pgmDtm.getProgram();
|
||||
Map<String, String> metaData = program.getMetadata();
|
||||
|
||||
JsonElement producer = gson.toJsonTree(new IsfProducer(program));
|
||||
JsonElement os = new JsonObject();
|
||||
oskey = metaData.get("Compiler ID");
|
||||
if (metaData.containsKey("PDB Loaded")) {
|
||||
os = gson.toJsonTree(new IsfWinOS(metaData));
|
||||
}
|
||||
else if (metaData.containsKey("Executable Format")) {
|
||||
if (metaData.get("Executable Format").contains("ELF")) {
|
||||
oskey = "linux";
|
||||
os = gson.toJsonTree(new IsfLinuxOS(gson, metaData));
|
||||
}
|
||||
}
|
||||
metadata.addProperty("format", "6.2.0");
|
||||
metadata.add("producer", producer);
|
||||
metadata.add(oskey, os);
|
||||
}
|
||||
}
|
||||
|
||||
private void genSymbols() {
|
||||
if (!skipSymbols && dtm instanceof ProgramDataTypeManager) {
|
||||
ProgramDataTypeManager pgmDtm = (ProgramDataTypeManager) dtm;
|
||||
Program program = pgmDtm.getProgram();
|
||||
Address imageBase = program.getImageBase();
|
||||
SymbolTable symbolTable = program.getSymbolTable();
|
||||
ReferenceManager referenceManager = program.getReferenceManager();
|
||||
ReferenceIterator xrefs = referenceManager.getExternalReferences();
|
||||
Map<String, Symbol> linkages = new HashMap<>();
|
||||
for (Reference reference : xrefs) {
|
||||
Address fromAddress = reference.getFromAddress();
|
||||
Address toAddress = reference.getToAddress();
|
||||
Symbol fromSymbol = symbolTable.getPrimarySymbol(fromAddress);
|
||||
Symbol toSymbol = symbolTable.getPrimarySymbol(toAddress);
|
||||
if (fromSymbol != null) {
|
||||
linkages.put(toSymbol.getName(), fromSymbol);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, JsonObject> map = new HashMap<>();
|
||||
if (requestedSymbols.isEmpty()) {
|
||||
if (requestedAddresses.isEmpty()) {
|
||||
SymbolIterator iterator = symbolTable.getSymbolIterator();
|
||||
while (iterator.hasNext()) {
|
||||
Symbol symbol = iterator.next();
|
||||
symbolToJson(imageBase, symbolTable, linkages, map, symbol);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (Address addr : requestedAddresses) {
|
||||
Symbol[] symsFromAddr =
|
||||
symbolTable.getSymbols(addr.add(imageBase.getOffset()));
|
||||
for (Symbol symbol : symsFromAddr) {
|
||||
symbolToJson(imageBase, symbolTable, linkages, map, symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (String key : requestedSymbols) {
|
||||
SymbolIterator iter = symbolTable.getSymbols(key);
|
||||
while (iter.hasNext()) {
|
||||
Symbol symbol = iter.next();
|
||||
symbolToJson(imageBase, symbolTable, linkages, map, symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Entry<String, JsonObject> entry : map.entrySet()) {
|
||||
symbols.add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
for (Entry<String, JsonObject> entry : map.entrySet()) {
|
||||
if (entry.getKey().startsWith("_")) {
|
||||
String nu = entry.getKey().substring(1);
|
||||
if (symbols.get(nu) == null) {
|
||||
symbols.add(nu, entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void genTypes(TaskMonitor monitor)
|
||||
throws CancelledException, IOException {
|
||||
if (skipTypes) {
|
||||
return;
|
||||
}
|
||||
Map<String, DataType> map = new HashMap<>();
|
||||
if (requestedDataTypes.isEmpty()) {
|
||||
dtm.getAllDataTypes(requestedDataTypes);
|
||||
baseTypes.add("pointer", getTree(new IsfTypedefPointer()));
|
||||
baseTypes.add("undefined", getTree(new IsfTypedefPointer()));
|
||||
}
|
||||
monitor.initialize(requestedDataTypes.size());
|
||||
for (DataType dataType : requestedDataTypes) {
|
||||
String key = dataType.getName();
|
||||
map.put(key, dataType);
|
||||
}
|
||||
|
||||
List<String> keylist = new ArrayList<>(map.keySet());
|
||||
Collections.sort(keylist);
|
||||
processMap(map, keylist, monitor);
|
||||
|
||||
if (!deferredKeys.isEmpty()) {
|
||||
Msg.warn(this, "Processing .conflict objects");
|
||||
List<String> defkeys = new ArrayList<>();
|
||||
defkeys.addAll(deferredKeys);
|
||||
processMap(map, defkeys, monitor);
|
||||
}
|
||||
}
|
||||
|
||||
private void processMap(Map<String, DataType> map, List<String> keylist, TaskMonitor monitor)
|
||||
throws CancelledException, IOException {
|
||||
JsonObject obj = new JsonObject();
|
||||
int cnt = 0;
|
||||
for (String key : keylist) {
|
||||
DataType dataType = map.get(key);
|
||||
monitor.checkCanceled();
|
||||
if (key.contains(".conflict")) {
|
||||
continue;
|
||||
}
|
||||
obj = getObjectForDataType(dataType, monitor);
|
||||
if (obj == null) {
|
||||
continue;
|
||||
}
|
||||
if (dataType instanceof FunctionDefinition) {
|
||||
// Would be nice to support this in the futere, but Volatility does not
|
||||
//typedefs.add(dataType.getName(), obj);
|
||||
}
|
||||
else if (IsfUtilities.isBaseDataType(dataType)) {
|
||||
baseTypes.add(dataType.getName(), obj);
|
||||
}
|
||||
else if (dataType instanceof TypeDef) {
|
||||
DataType baseDataType = ((TypeDef) dataType).getBaseDataType();
|
||||
if (IsfUtilities.isBaseDataType(baseDataType)) {
|
||||
baseTypes.add(dataType.getName(), obj);
|
||||
}
|
||||
else if (baseDataType instanceof Enum) {
|
||||
enums.add(dataType.getName(), obj);
|
||||
}
|
||||
else {
|
||||
userTypes.add(dataType.getName(), obj);
|
||||
}
|
||||
}
|
||||
else if (dataType instanceof Enum) {
|
||||
enums.add(dataType.getName(), obj);
|
||||
}
|
||||
else if (dataType instanceof Composite) {
|
||||
userTypes.add(dataType.getName(), obj);
|
||||
}
|
||||
monitor.setProgress(++cnt);
|
||||
}
|
||||
}
|
||||
|
||||
private void symbolToJson(Address imageBase, SymbolTable symbolTable,
|
||||
Map<String, Symbol> linkages,
|
||||
Map<String, JsonObject> map, Symbol symbol) {
|
||||
String key = symbol.getName();
|
||||
Address address = symbol.getAddress();
|
||||
JsonObject sym = map.containsKey(key) ? map.get(key) : new JsonObject();
|
||||
if (address.isExternalAddress()) {
|
||||
sym.addProperty("address", address.getOffset());
|
||||
if (linkages.containsKey(key)) {
|
||||
Symbol linkage = linkages.get(key);
|
||||
sym.addProperty("linkage_name", linkage.getName());
|
||||
sym.addProperty("address", linkage.getAddress().getOffset());
|
||||
}
|
||||
}
|
||||
else {
|
||||
sym.addProperty("address", address.subtract(imageBase));
|
||||
}
|
||||
map.put(symbol.getName(), sym);
|
||||
if (!symbol.isPrimary()) {
|
||||
Symbol primarySymbol = symbolTable.getPrimarySymbol(address);
|
||||
String primaryName = primarySymbol.getName();
|
||||
if (symbol.getName().contains(primaryName)) {
|
||||
sym.addProperty("linkage_name", symbol.getName());
|
||||
map.put(primaryName, sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void write(JsonObject obj) {
|
||||
gson.toJson(obj, writer);
|
||||
}
|
||||
|
||||
JsonObject getObjectForDataType(DataType dt, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
IsfObject isf = getIsfObject(dt, monitor);
|
||||
if (isf != null) {
|
||||
JsonObject jobj = (JsonObject) getTree(isf);
|
||||
resolved.put(dt, isf);
|
||||
return jobj;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the data type as ISF JSON using the underlying writer. For now, ignoring top-level
|
||||
* bit-fields and function defs as unsupported by ISF. Typedefs really deserve their own
|
||||
* category, but again unsupported.
|
||||
*
|
||||
* @param dt the data type to write as ISF JSON
|
||||
* @param monitor the task monitor
|
||||
* @throws IOException if there is an exception writing the output
|
||||
*/
|
||||
private IsfObject getIsfObject(DataType dt, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
if (dt == null) {
|
||||
Msg.error(this, "Shouldn't get here - null datatype passed");
|
||||
return null;
|
||||
}
|
||||
if (dt instanceof FactoryDataType) {
|
||||
Msg.error(this, "Factory data types may not be written - type: " + dt);
|
||||
}
|
||||
if (dt instanceof Pointer || dt instanceof Array || dt instanceof BitFieldDataType) {
|
||||
IsfObject type = getObjectDataType(IsfUtilities.getBaseDataType(dt));
|
||||
IsfObject obj = new IsfTypedObject(dt, type);
|
||||
return obj;
|
||||
}
|
||||
|
||||
dt = dt.clone(dtm); // force resize/repack for target data organization
|
||||
|
||||
IsfObject res = resolve(dt);
|
||||
if (res != null) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (dt instanceof Dynamic dynamic) {
|
||||
DataType rep = dynamic.getReplacementBaseType();
|
||||
return rep == null ? null : getIsfObject(rep, monitor);
|
||||
}
|
||||
else if (dt instanceof TypeDef typedef) {
|
||||
return getObjectTypeDef(typedef, monitor);
|
||||
}
|
||||
else if (dt instanceof Composite composite) {
|
||||
return new IsfComposite(composite, this, monitor);
|
||||
}
|
||||
else if (dt instanceof Enum enumm) {
|
||||
return new IsfEnum(enumm);
|
||||
}
|
||||
else if (dt instanceof BuiltInDataType builtin) {
|
||||
return new IsfBuiltIn(builtin);
|
||||
}
|
||||
else if (dt instanceof BitFieldDataType) {
|
||||
// skip - not hit
|
||||
}
|
||||
else if (dt instanceof FunctionDefinition) { ///FAIL
|
||||
// skip - not hit
|
||||
}
|
||||
else if (dt.equals(DataType.DEFAULT)) {
|
||||
// skip - not hit
|
||||
}
|
||||
else {
|
||||
Msg.warn(this, "Unable to write datatype. Type unrecognized: " + dt.getClass());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private IsfObject resolve(DataType dt) {
|
||||
if (resolved.containsKey(dt)) {
|
||||
return resolved.get(dt);
|
||||
}
|
||||
|
||||
DataType resolvedType = resolvedTypeMap.get(dt.getName());
|
||||
if (resolvedType != null) {
|
||||
if (resolvedType.isEquivalent(dt)) {
|
||||
return resolved.get(dt); // skip equivalent type with same name as a resolved type
|
||||
}
|
||||
if (dt instanceof TypeDef) {
|
||||
DataType baseType = ((TypeDef) dt).getBaseDataType();
|
||||
if (resolvedType instanceof Composite || resolvedType instanceof Enum) {
|
||||
if (baseType.isEquivalent(resolvedType)) {
|
||||
// auto-typedef already generated for Composite or Enum
|
||||
return resolved.get(dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
Msg.warn(this, "WARNING! conflicting data type names: " + dt.getPathName() +
|
||||
" - " + resolvedType.getPathName());
|
||||
return resolved.get(dt);
|
||||
}
|
||||
|
||||
resolvedTypeMap.put(dt.getName(), dt);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void clearResolve(String typedefName, DataType baseType) {
|
||||
if (baseType instanceof Composite || baseType instanceof Enum) {
|
||||
// auto-typedef generated with composite and enum
|
||||
if (typedefName.equals(baseType.getName())) {
|
||||
resolvedTypeMap.remove(typedefName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Inherited from DataTypeWriter (logic lost to time):
|
||||
// A comment explaining the special 'P' case would be helpful!! Smells like fish.
|
||||
else if (baseType instanceof Pointer && typedefName.startsWith("P")) {
|
||||
DataType dt = ((Pointer) baseType).getDataType();
|
||||
if (dt instanceof TypeDef) {
|
||||
dt = ((TypeDef) dt).getBaseDataType();
|
||||
}
|
||||
if (dt instanceof Composite && dt.getName().equals(typedefName.substring(1))) {
|
||||
// auto-pointer-typedef generated with composite
|
||||
resolvedTypeMap.remove(typedefName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IsfObject getObjectTypeDeclaration(DataTypeComponent component) {
|
||||
|
||||
DataType dataType = component.getDataType();
|
||||
if (dataType instanceof Dynamic dynamic) {
|
||||
if (dynamic.canSpecifyLength()) {
|
||||
DataType replacementBaseType = dynamic.getReplacementBaseType();
|
||||
if (replacementBaseType != null) {
|
||||
replacementBaseType = replacementBaseType.clone(dtm);
|
||||
IsfObject type = getObjectDataType(replacementBaseType);
|
||||
int elementLen = replacementBaseType.getLength();
|
||||
if (elementLen > 0) {
|
||||
int elementCnt = (component.getLength() + elementLen - 1) / elementLen;
|
||||
return new IsfDynamicComponent(dynamic, type, elementCnt);
|
||||
|
||||
}
|
||||
Msg.error(this,
|
||||
dynamic.getClass().getSimpleName() +
|
||||
" returned bad replacementBaseType: " +
|
||||
replacementBaseType.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
DataType baseDataType = IsfUtilities.getBaseDataType(dataType);
|
||||
if (baseDataType instanceof FunctionDefinition def) {
|
||||
return new IsfFunctionPointer(def, baseDataType);
|
||||
}
|
||||
return getObjectDataType(dataType, component.getOffset());
|
||||
}
|
||||
|
||||
public IsfObject getObjectDataType(DataType dataType) {
|
||||
return getObjectDataType(dataType, -1);
|
||||
}
|
||||
|
||||
private IsfObject getObjectDataType(DataType dataType, int componentOffset) {
|
||||
if (dataType == null) {
|
||||
return new IsfDataTypeNull();
|
||||
}
|
||||
DataType baseType = IsfUtilities.getBaseDataType(dataType);
|
||||
if (!dataType.equals(baseType)) {
|
||||
if (dataType instanceof Array arr) {
|
||||
IsfObject type = getObjectDataType(arr.getDataType());
|
||||
return new IsfDataTypeArray(arr, type);
|
||||
}
|
||||
if (dataType instanceof BitFieldDataType bf) {
|
||||
IsfObject type = getObjectDataType(bf.getBaseDataType());
|
||||
return new IsfDataTypeBitField(bf, componentOffset, type);
|
||||
}
|
||||
IsfObject baseObject = getObjectDataType(IsfUtilities.getBaseDataType(dataType));
|
||||
return new IsfDataTypeTypeDef(dataType, baseObject);
|
||||
}
|
||||
if (dataType.getName().contains(".conflict")) {
|
||||
if (!deferredKeys.contains(dataType.getName())) {
|
||||
deferredKeys.add(dataType.getName());
|
||||
}
|
||||
}
|
||||
return new IsfDataTypeDefault(dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Typedef Format: typedef <TYPE_DEF_NAME> <BASE_TYPE_NAME>
|
||||
*
|
||||
* @throws CancelledException if the action is cancelled by the user
|
||||
*/
|
||||
private IsfObject getObjectTypeDef(TypeDef typeDef, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
//UNVERIFIED
|
||||
DataType dataType = typeDef.getDataType();
|
||||
String typedefName = typeDef.getDisplayName();
|
||||
String dataTypeName = dataType.getDisplayName();
|
||||
if (IsfUtilities.isIntegral(typedefName, dataTypeName)) {
|
||||
return new IsfTypedefIntegral(typeDef);
|
||||
}
|
||||
|
||||
DataType baseType = typeDef.getBaseDataType();
|
||||
try {
|
||||
if (baseType instanceof BuiltInDataType builtin) {
|
||||
return new IsfTypedefBase(typeDef);
|
||||
}
|
||||
if (!(baseType instanceof Pointer)) {
|
||||
return getIsfObject(dataType, monitor);
|
||||
}
|
||||
return new IsfTypedefPointer();
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.error(this, "TypeDef error: " + e);
|
||||
}
|
||||
clearResolve(typedefName, baseType);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public JsonElement getTree(Object obj) {
|
||||
return gson.toJsonTree(obj);
|
||||
}
|
||||
|
||||
public void requestAddress(String key) {
|
||||
if (dtm instanceof ProgramDataTypeManager pgmDtm) {
|
||||
try {
|
||||
Address address = pgmDtm.getProgram().getMinAddress().getAddress(key);
|
||||
if (address == null) {
|
||||
Msg.error(this, address + " not found");
|
||||
return;
|
||||
}
|
||||
requestedAddresses.add(address);
|
||||
}
|
||||
catch (AddressFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void requestSymbol(String symbol) {
|
||||
if (symbol == null) {
|
||||
Msg.error(this, symbol + " not found");
|
||||
return;
|
||||
}
|
||||
requestedSymbols.add(symbol);
|
||||
}
|
||||
|
||||
public void requestType(String path) {
|
||||
requestedTypes.add(path);
|
||||
DataType dataType = dtm.getDataType(path);
|
||||
if (dataType == null) {
|
||||
Msg.error(this, path + " not found");
|
||||
return;
|
||||
}
|
||||
requestedDataTypes.add(dataType);
|
||||
}
|
||||
|
||||
public void requestType(DataType dataType) {
|
||||
if (dataType == null) {
|
||||
Msg.error(this, dataType + " not found");
|
||||
return;
|
||||
}
|
||||
requestedDataTypes.add(dataType);
|
||||
}
|
||||
|
||||
public JsonWriter getWriter() {
|
||||
return writer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return baseWriter.toString();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void setSkipSymbols(boolean val) {
|
||||
skipSymbols = val;
|
||||
}
|
||||
|
||||
public void setSkipTypes(boolean val) {
|
||||
skipTypes = val;
|
||||
}
|
||||
|
||||
public void setStrict(boolean val) {
|
||||
STRICT = val;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import ghidra.program.model.data.Dynamic;
|
||||
|
||||
public class IsfDynamicComponent implements IsfObject {
|
||||
|
||||
public String kind;
|
||||
public Integer count;
|
||||
public IsfObject subtype;
|
||||
|
||||
public IsfDynamicComponent(Dynamic dynamicType, IsfObject type, int elementCnt) {
|
||||
kind = "array";
|
||||
subtype = type;
|
||||
count = elementCnt;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import ghidra.program.model.data.Enum;
|
||||
|
||||
public class IsfEnum implements IsfObject {
|
||||
|
||||
public Integer size;
|
||||
public String base;
|
||||
public JsonObject constants = new JsonObject();
|
||||
|
||||
public IsfEnum(Enum enumm) {
|
||||
size = enumm.getLength();
|
||||
base = "int";
|
||||
String[] names = enumm.getNames();
|
||||
for (int j = 0; j < names.length; j++) {
|
||||
constants.addProperty(names[j], enumm.getValue(names[j]));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
public class IsfFunction implements IsfObject {
|
||||
|
||||
public String kind;
|
||||
|
||||
public IsfFunction() {
|
||||
kind = "function";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.FunctionDefinition;
|
||||
|
||||
public class IsfFunctionPointer implements IsfObject {
|
||||
|
||||
public String kind;
|
||||
public IsfObject subtype;
|
||||
|
||||
public IsfFunctionPointer(FunctionDefinition def, DataType dt) {
|
||||
kind = "pointer";
|
||||
subtype = new IsfFunction();
|
||||
//TODO?
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
|
||||
public class IsfLinuxOS implements IsfObject {
|
||||
|
||||
public JsonArray symbols = new JsonArray();
|
||||
public JsonArray types = new JsonArray();
|
||||
|
||||
public IsfLinuxOS(Gson gson, Map<String, String> metaData) {
|
||||
IsfLinuxProgram pgm = new IsfLinuxProgram(metaData);
|
||||
symbols.add(gson.toJsonTree(pgm));
|
||||
types.add(gson.toJsonTree(pgm));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class IsfLinuxProgram implements IsfObject {
|
||||
|
||||
public String kind;
|
||||
public String name;
|
||||
public String hash_type;
|
||||
public String hash_value;
|
||||
|
||||
public IsfLinuxProgram(Map<String, String> metaData) {
|
||||
kind = "dwarf";
|
||||
name = metaData.get("Program Name");
|
||||
hash_type = "sha256";
|
||||
hash_value = metaData.get("Executable SHA256");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
public interface IsfObject {
|
||||
|
||||
// EMPTY by design
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
public class IsfProducer implements IsfObject {
|
||||
|
||||
public String datetime;
|
||||
public String name;
|
||||
public String version;
|
||||
|
||||
public IsfProducer(Program program) {
|
||||
Map<String, String> metaData = program.getMetadata();
|
||||
Date creationDate = program.getCreationDate();
|
||||
SimpleDateFormat dataFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS");
|
||||
|
||||
datetime = dataFormat.format(creationDate);
|
||||
name = "Ghidra";
|
||||
version = metaData.get(Program.CREATED_WITH_GHIDRA_VERSION);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import ghidra.program.model.data.DataType;
|
||||
|
||||
public class IsfTypedObject implements IsfObject {
|
||||
|
||||
public String kind;
|
||||
public Integer size;
|
||||
public IsfObject type;
|
||||
|
||||
public IsfTypedObject(DataType dt, IsfObject typeObj) {
|
||||
kind = IsfUtilities.getKind(dt);
|
||||
size = dt.getLength();
|
||||
type = typeObj;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import ghidra.program.model.data.BuiltInDataType;
|
||||
import ghidra.program.model.data.TypeDef;
|
||||
|
||||
public class IsfTypedefBase implements IsfObject {
|
||||
|
||||
public Integer size;
|
||||
public String kind;
|
||||
public Boolean signed;
|
||||
public String endian;
|
||||
|
||||
public IsfTypedefBase(TypeDef typeDef) {
|
||||
BuiltInDataType builtin = (BuiltInDataType) typeDef.getBaseDataType();
|
||||
size = typeDef.getLength();
|
||||
kind = IsfUtilities.getBuiltInKind(builtin);
|
||||
signed = IsfUtilities.getSigned(typeDef);
|
||||
endian = IsfUtilities.getEndianness(typeDef);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import ghidra.program.model.data.TypeDef;
|
||||
|
||||
public class IsfTypedefIntegral implements IsfObject {
|
||||
|
||||
public Integer size;
|
||||
|
||||
public IsfTypedefIntegral(TypeDef td) {
|
||||
size = td.getLength();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import ghidra.program.model.data.PointerDataType;
|
||||
|
||||
public class IsfTypedefPointer implements IsfObject {
|
||||
|
||||
public Integer size;
|
||||
public Boolean signed;
|
||||
public String kind;
|
||||
public String endian;
|
||||
|
||||
public IsfTypedefPointer() {
|
||||
PointerDataType ptr = new PointerDataType();
|
||||
size = ptr.getLength();
|
||||
signed = false; //IsfUtilities.getSigned(ptr);
|
||||
kind = IsfUtilities.getBuiltInKind(ptr);
|
||||
endian = IsfUtilities.getEndianness(ptr);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.TypeDef;
|
||||
|
||||
public class IsfTypedefUser implements IsfObject {
|
||||
|
||||
public Integer size;
|
||||
public String kind;
|
||||
public IsfObject type;
|
||||
|
||||
public IsfTypedefUser(TypeDef typeDef, IsfObject typeObj) {
|
||||
DataType baseType = typeDef.getBaseDataType();
|
||||
size = typeDef.getLength();
|
||||
kind = IsfUtilities.getKind(baseType);
|
||||
type = typeObj;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
|
||||
public class IsfUtilities {
|
||||
|
||||
// list of Ghidra built-in type names which correspond to C primitive types
|
||||
private static String[] INTEGRAL_TYPES = { "char", "short", "int", "long", "long long",
|
||||
"__int64", "float", "double", "long double", "void" };
|
||||
|
||||
private static String[] INTEGRAL_MODIFIERS =
|
||||
{ "signed", "unsigned", "const", "static", "volatile", "mutable", };
|
||||
|
||||
public static boolean isIntegral(String typedefName, String basetypeName) {
|
||||
for (String type : INTEGRAL_TYPES) {
|
||||
if (typedefName.equals(type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
boolean endsWithIntegralType = false;
|
||||
for (String type : INTEGRAL_TYPES) {
|
||||
if (typedefName.endsWith(" " + type)) {
|
||||
endsWithIntegralType = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
boolean containsIntegralModifier = false;
|
||||
for (String modifier : INTEGRAL_MODIFIERS) {
|
||||
if (typedefName.indexOf(modifier + " ") >= 0 ||
|
||||
typedefName.indexOf(" " + modifier) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (endsWithIntegralType && containsIntegralModifier) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typedefName.endsWith(" " + basetypeName)) {
|
||||
return containsIntegralModifier;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static DataType getBaseDataType(DataType dt) {
|
||||
while (dt != null) {
|
||||
if (dt instanceof Array) {
|
||||
Array array = (Array) dt;
|
||||
dt = array.getDataType();
|
||||
}
|
||||
else if (dt instanceof Pointer) {
|
||||
Pointer pointer = (Pointer) dt;
|
||||
dt = pointer.getDataType();
|
||||
}
|
||||
else if (dt instanceof BitFieldDataType) {
|
||||
BitFieldDataType bitfieldDt = (BitFieldDataType) dt;
|
||||
dt = bitfieldDt.getBaseDataType();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
public static DataType getArrayBaseType(Array arrayDt) {
|
||||
DataType dataType = arrayDt.getDataType();
|
||||
while (dataType instanceof Array) {
|
||||
dataType = ((Array) dataType).getDataType();
|
||||
}
|
||||
return dataType;
|
||||
}
|
||||
|
||||
public static DataType getPointerBaseDataType(Pointer p) {
|
||||
DataType dt = p.getDataType();
|
||||
while (dt instanceof Pointer) {
|
||||
dt = ((Pointer) dt).getDataType();
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
public static String getKind(DataType dt) {
|
||||
if (dt instanceof Array) {
|
||||
return "array";
|
||||
}
|
||||
if (dt instanceof Structure) {
|
||||
return "struct";
|
||||
}
|
||||
if (dt instanceof Union) {
|
||||
return "union";
|
||||
}
|
||||
if (dt instanceof BuiltInDataType) {
|
||||
return "base";
|
||||
}
|
||||
if (dt instanceof Pointer) {
|
||||
return "pointer";
|
||||
}
|
||||
if (dt instanceof Enum) {
|
||||
return "enum";
|
||||
}
|
||||
if (dt instanceof TypeDef) {
|
||||
return "base"; //"typedef";
|
||||
}
|
||||
if (dt instanceof FunctionDefinition) {
|
||||
return "function";
|
||||
}
|
||||
if (dt instanceof BitFieldDataType) {
|
||||
return "bitfield";
|
||||
}
|
||||
if (dt instanceof DefaultDataType) {
|
||||
return "base";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
public static String getBuiltInKind(BuiltInDataType dt) {
|
||||
if (dt instanceof AbstractIntegerDataType) {
|
||||
return dt.getLength() == 1 ? "char" : "int";
|
||||
}
|
||||
if (dt instanceof AbstractFloatDataType) {
|
||||
return "float";
|
||||
}
|
||||
if (dt instanceof AbstractComplexDataType) {
|
||||
return "complex";
|
||||
}
|
||||
if (dt instanceof AbstractStringDataType) {
|
||||
return "char"; // "string";
|
||||
}
|
||||
if (dt instanceof PointerDataType) {
|
||||
return "void"; //"pointer";
|
||||
}
|
||||
if (dt instanceof VoidDataType) {
|
||||
return "void";
|
||||
}
|
||||
if (dt instanceof Undefined) {
|
||||
return "void";
|
||||
}
|
||||
return "char";
|
||||
}
|
||||
|
||||
public static boolean isBaseDataType(DataType dt) {
|
||||
if (dt instanceof AbstractIntegerDataType) {
|
||||
return true;
|
||||
}
|
||||
if (dt instanceof AbstractFloatDataType) {
|
||||
return true;
|
||||
}
|
||||
if (dt instanceof AbstractComplexDataType) {
|
||||
return true;
|
||||
}
|
||||
if (dt instanceof AbstractStringDataType) {
|
||||
return true;
|
||||
}
|
||||
if (dt instanceof Pointer) {
|
||||
return true;
|
||||
}
|
||||
if (dt instanceof VoidDataType) {
|
||||
return true;
|
||||
}
|
||||
if (dt instanceof Undefined) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Integer getLength(DataType dt) {
|
||||
return dt.getLength();
|
||||
}
|
||||
|
||||
public static Boolean getSigned(DataType dt) {
|
||||
return dt.getDataOrganization().isSignedChar();
|
||||
}
|
||||
|
||||
public static String getEndianness(DataType dt) {
|
||||
return dt.getDataOrganization().isBigEndian() ? "big" : "little";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class IsfWinOS implements IsfObject {
|
||||
|
||||
public IsfWinPE pe;
|
||||
public IsfWinPDB pdb;
|
||||
|
||||
public IsfWinOS(Map<String, String> metaData) {
|
||||
pe = new IsfWinPE(metaData);
|
||||
pdb = new IsfWinPDB(metaData);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class IsfWinPDB implements IsfObject {
|
||||
|
||||
public String GUID;
|
||||
public Integer age;
|
||||
public String database;
|
||||
public Integer machine_type;
|
||||
|
||||
public IsfWinPDB(Map<String, String> metaData) {
|
||||
GUID = metaData.get("PDB GUID");
|
||||
age = Integer.valueOf(metaData.get("PDB Age"));
|
||||
database = metaData.get("PDB File");
|
||||
machine_type = 0; //metaData.get("PDB Version")); //?
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/* ###
|
||||
* 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.program.model.data.ISF;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class IsfWinPE implements IsfObject {
|
||||
|
||||
public Integer build;
|
||||
public Integer major;
|
||||
public Integer minor;
|
||||
public Integer revision;
|
||||
|
||||
public IsfWinPE(Map<String, String> metaData) {
|
||||
String data = metaData.get("PE Property[ProductVersion]");
|
||||
String[] quad = data.split("\\.");
|
||||
build = Integer.valueOf(quad[3]);
|
||||
major = Integer.valueOf(quad[0]);
|
||||
minor = Integer.valueOf(quad[1]);
|
||||
revision = Integer.valueOf(quad[2]);
|
||||
}
|
||||
|
||||
}
|
128
Ghidra/Debug/Debugger-isf/src/main/proto/isf.proto
Normal file
128
Ghidra/Debug/Debugger-isf/src/main/proto/isf.proto
Normal file
|
@ -0,0 +1,128 @@
|
|||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
syntax = "proto3";
|
||||
package ghidra.dbg.isf.protocol;
|
||||
|
||||
enum ErrorCode {
|
||||
EC_UNKNOWN = 0;
|
||||
EC_BAD_REQUEST = 1;
|
||||
EC_NOT_SUPPORTED = 2;
|
||||
}
|
||||
|
||||
// For testing: cause the server to report an unrecognized request error
|
||||
message ErrorRequest {
|
||||
}
|
||||
|
||||
message ErrorReply {
|
||||
ErrorCode code = 1;
|
||||
string message = 2;
|
||||
}
|
||||
|
||||
message PingRequest {
|
||||
string content = 1;
|
||||
}
|
||||
|
||||
message PingReply {
|
||||
string content = 1;
|
||||
}
|
||||
|
||||
message FullExportRequest {
|
||||
string ns = 1;
|
||||
}
|
||||
|
||||
message FullExportReply {
|
||||
string value = 1;
|
||||
}
|
||||
|
||||
message LookAddrRequest {
|
||||
string ns = 1;
|
||||
string key = 2;
|
||||
}
|
||||
|
||||
message LookAddrReply {
|
||||
string value = 1;
|
||||
}
|
||||
|
||||
message LookTypeRequest {
|
||||
string ns = 1;
|
||||
string key = 2;
|
||||
}
|
||||
|
||||
message LookTypeReply {
|
||||
string value = 1;
|
||||
}
|
||||
|
||||
message EnumTypesRequest {
|
||||
string ns = 1;
|
||||
}
|
||||
|
||||
message EnumTypesReply {
|
||||
string ns = 1;
|
||||
string value = 2;
|
||||
}
|
||||
|
||||
|
||||
message LookSymRequest {
|
||||
string ns = 1;
|
||||
string key = 2;
|
||||
}
|
||||
|
||||
message LookSymReply {
|
||||
string value = 1;
|
||||
}
|
||||
|
||||
message EnumSymsRequest {
|
||||
string ns = 1;
|
||||
}
|
||||
|
||||
message EnumSymsReply {
|
||||
string value = 1;
|
||||
}
|
||||
|
||||
|
||||
message RootAddedEvent {
|
||||
}
|
||||
|
||||
|
||||
message RootMessage {
|
||||
int32 sequence = 1;
|
||||
|
||||
oneof msg {
|
||||
ErrorRequest error_request = 100;
|
||||
ErrorReply error_reply = 200;
|
||||
|
||||
PingRequest ping_request = 101;
|
||||
PingReply ping_reply = 201;
|
||||
|
||||
FullExportRequest full_export_request = 102;
|
||||
FullExportReply full_export_reply = 202;
|
||||
|
||||
LookTypeRequest look_type_request = 103;
|
||||
LookTypeReply look_type_reply = 203;
|
||||
|
||||
LookSymRequest look_symbol_request = 104;
|
||||
LookSymReply look_symbol_reply = 204;
|
||||
|
||||
LookAddrRequest look_address_request = 105;
|
||||
LookAddrReply look_address_reply = 205;
|
||||
|
||||
EnumTypesRequest enum_types_request = 106;
|
||||
EnumTypesReply enum_types_reply = 206;
|
||||
|
||||
EnumSymsRequest enum_symbols_request = 107;
|
||||
EnumSymsReply enum_symbols_reply = 207;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
MODULE FILE LICENSE: lib/protobuf-java-3.21.8.jar BSD-3-GOOGLE
|
|
@ -22,6 +22,7 @@ apply plugin: 'eclipse'
|
|||
eclipse.project.name = 'Debug Framework-AsyncComm'
|
||||
|
||||
dependencies {
|
||||
api 'com.google.protobuf:protobuf-java:3.21.8'
|
||||
api project(':Generic')
|
||||
api project(':Graph')
|
||||
api project(':ProposedUtils')
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
##VERSION: 2.0
|
||||
##MODULE IP: BSD-3-GOOGLE
|
||||
Module.manifest||GHIDRA||||END|
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue