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-AsyncComm')
|
||||||
api project(':Framework-Debugging')
|
api project(':Framework-Debugging')
|
||||||
api project(':ProposedUtils')
|
api project(':ProposedUtils')
|
||||||
|
|
|
@ -1,3 +1,2 @@
|
||||||
##VERSION: 2.0
|
##VERSION: 2.0
|
||||||
##MODULE IP: BSD-3-GOOGLE
|
|
||||||
Module.manifest||GHIDRA||||END|
|
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'
|
eclipse.project.name = 'Debug Framework-AsyncComm'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
api 'com.google.protobuf:protobuf-java:3.21.8'
|
||||||
api project(':Generic')
|
api project(':Generic')
|
||||||
api project(':Graph')
|
api project(':Graph')
|
||||||
api project(':ProposedUtils')
|
api project(':ProposedUtils')
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
##VERSION: 2.0
|
##VERSION: 2.0
|
||||||
|
##MODULE IP: BSD-3-GOOGLE
|
||||||
Module.manifest||GHIDRA||||END|
|
Module.manifest||GHIDRA||||END|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue