diff --git a/Ghidra/Debug/Debugger-gadp/Module.manifest b/Ghidra/Debug/Debugger-gadp/Module.manifest index 89174007c9..e69de29bb2 100644 --- a/Ghidra/Debug/Debugger-gadp/Module.manifest +++ b/Ghidra/Debug/Debugger-gadp/Module.manifest @@ -1 +0,0 @@ -MODULE FILE LICENSE: lib/protobuf-java-3.21.8.jar BSD-3-GOOGLE diff --git a/Ghidra/Debug/Debugger-gadp/build.gradle b/Ghidra/Debug/Debugger-gadp/build.gradle index abb436323e..f4dbd3cd0c 100644 --- a/Ghidra/Debug/Debugger-gadp/build.gradle +++ b/Ghidra/Debug/Debugger-gadp/build.gradle @@ -59,7 +59,6 @@ dependencies { } } - api 'com.google.protobuf:protobuf-java:3.21.8' api project(':Framework-AsyncComm') api project(':Framework-Debugging') api project(':ProposedUtils') diff --git a/Ghidra/Debug/Debugger-gadp/certification.manifest b/Ghidra/Debug/Debugger-gadp/certification.manifest index c163a88c69..895ac4b698 100644 --- a/Ghidra/Debug/Debugger-gadp/certification.manifest +++ b/Ghidra/Debug/Debugger-gadp/certification.manifest @@ -1,3 +1,2 @@ ##VERSION: 2.0 -##MODULE IP: BSD-3-GOOGLE Module.manifest||GHIDRA||||END| diff --git a/Ghidra/Debug/Debugger-isf/Module.manifest b/Ghidra/Debug/Debugger-isf/Module.manifest new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Ghidra/Debug/Debugger-isf/build.gradle b/Ghidra/Debug/Debugger-isf/build.gradle new file mode 100644 index 0000000000..6bf945c2e6 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/build.gradle @@ -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) } + } +} + diff --git a/Ghidra/Debug/Debugger-isf/certification.manifest b/Ghidra/Debug/Debugger-isf/certification.manifest new file mode 100644 index 0000000000..c471bc1a4c --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/certification.manifest @@ -0,0 +1,3 @@ +##VERSION: 2.0 +Module.manifest||GHIDRA||||END| +runISFServer||GHIDRA||||END| diff --git a/Ghidra/Debug/Debugger-isf/runISFServer b/Ghidra/Debug/Debugger-isf/runISFServer new file mode 100755 index 0000000000..6efa890ff0 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/runISFServer @@ -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 "$@" diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/app/plugin/core/datamgr/actions/ExportToIsfAction.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/app/plugin/core/datamgr/actions/ExportToIsfAction.java new file mode 100644 index 0000000000..893caf3bea --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/app/plugin/core/datamgr/actions/ExportToIsfAction.java @@ -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> classes = + ClassSearcher.getClasses(AnnotationHandler.class); + + List list = new ArrayList<>(); + Class[] constructorArgumentTypes = {}; + for (Class 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> 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>> entrySet = managersToDataTypesMap.entrySet(); + for (Entry> entry : entrySet) { + DataTypeManager dataTypeManager = entry.getKey(); + File file = getFile(gTree, fileChooser, dataTypeManager, handler); + if (file == null) { + return; // user cancelled + } + + List 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 dataTypeList; + private final File file; + private final GTree gTree; + + DataTypeWriterTask(GTree gTree, DataTypeManager programDataTypeMgr, + List 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> managersToDataTypesMap) { + Object last = path.getLastPathComponent(); + if (last instanceof DataTypeNode) { + DataTypeNode node = (DataTypeNode) last; + DataType dataType = node.getDataType(); + DataTypeManager dataTypeManager = dataType.getDataTypeManager(); + + List 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 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; + } +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfClientHandler.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfClientHandler.java new file mode 100644 index 0000000000..05f1b64011 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfClientHandler.java @@ -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 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(); + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfConnectionHandler.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfConnectionHandler.java new file mode 100644 index 0000000000..c2df510736 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfConnectionHandler.java @@ -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); + } + } +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfErrorException.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfErrorException.java new file mode 100644 index 0000000000..29937211e0 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfErrorException.java @@ -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; + } +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfServer.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfServer.java new file mode 100644 index 0000000000..898c7d2bbf --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfServer.java @@ -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 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(); + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfServerLauncher.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfServerLauncher.java new file mode 100644 index 0000000000..0fef4fcb24 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfServerLauncher.java @@ -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 "); + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfBuiltIn.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfBuiltIn.java new file mode 100644 index 0000000000..b4311bd6ee --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfBuiltIn.java @@ -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); + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfComponent.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfComponent.java new file mode 100644 index 0000000000..1c5f07b49c --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfComponent.java @@ -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(); + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfComposite.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfComposite.java new file mode 100644 index 0000000000..26d91e92d7 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfComposite.java @@ -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 comps = new HashMap<>(); + for (DataTypeComponent component : components) { + String key = component.getFieldName(); + if (key == null) { + key = component.getDefaultFieldName(); + } + comps.put(key, component); + } + ArrayList 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)); + } + + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeArray.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeArray.java new file mode 100644 index 0000000000..5478d3b574 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeArray.java @@ -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; + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeBitField.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeBitField.java new file mode 100644 index 0000000000..9ee584f02e --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeBitField.java @@ -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(); + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeDefault.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeDefault.java new file mode 100644 index 0000000000..2fb90b2912 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeDefault.java @@ -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(); + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeNull.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeNull.java new file mode 100644 index 0000000000..da8f9efadc --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeNull.java @@ -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"; + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeTypeDef.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeTypeDef.java new file mode 100644 index 0000000000..82e5b32857 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeTypeDef.java @@ -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; + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeWriter.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeWriter.java new file mode 100644 index 0000000000..73a72e55ea --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeWriter.java @@ -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 resolved = new HashMap<>(); + private Map resolvedTypeMap = new HashMap<>(); + private List 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
requestedAddresses = new ArrayList<>(); + private List requestedSymbols = new ArrayList<>(); + private List requestedTypes = new ArrayList<>(); + private List 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 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 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 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 entry : map.entrySet()) { + symbols.add(entry.getKey(), entry.getValue()); + } + for (Entry 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 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 keylist = new ArrayList<>(map.keySet()); + Collections.sort(keylist); + processMap(map, keylist, monitor); + + if (!deferredKeys.isEmpty()) { + Msg.warn(this, "Processing .conflict objects"); + List defkeys = new ArrayList<>(); + defkeys.addAll(deferredKeys); + processMap(map, defkeys, monitor); + } + } + + private void processMap(Map map, List 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 linkages, + Map 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 + * + * @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; + } +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDynamicComponent.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDynamicComponent.java new file mode 100644 index 0000000000..d25a0afe0e --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDynamicComponent.java @@ -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; + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfEnum.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfEnum.java new file mode 100644 index 0000000000..801a7620bb --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfEnum.java @@ -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])); + } + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfFunction.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfFunction.java new file mode 100644 index 0000000000..4af99c709b --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfFunction.java @@ -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"; + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfFunctionPointer.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfFunctionPointer.java new file mode 100644 index 0000000000..74183df1a2 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfFunctionPointer.java @@ -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? + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfLinuxOS.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfLinuxOS.java new file mode 100644 index 0000000000..43d9131b18 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfLinuxOS.java @@ -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 metaData) { + IsfLinuxProgram pgm = new IsfLinuxProgram(metaData); + symbols.add(gson.toJsonTree(pgm)); + types.add(gson.toJsonTree(pgm)); + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfLinuxProgram.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfLinuxProgram.java new file mode 100644 index 0000000000..162c216ce6 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfLinuxProgram.java @@ -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 metaData) { + kind = "dwarf"; + name = metaData.get("Program Name"); + hash_type = "sha256"; + hash_value = metaData.get("Executable SHA256"); + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfObject.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfObject.java new file mode 100644 index 0000000000..fbecf2737c --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfObject.java @@ -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 + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfProducer.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfProducer.java new file mode 100644 index 0000000000..d9c8af71b3 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfProducer.java @@ -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 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); + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfTypedObject.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfTypedObject.java new file mode 100644 index 0000000000..9f7ee6c1d4 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfTypedObject.java @@ -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; + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfTypedefBase.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfTypedefBase.java new file mode 100644 index 0000000000..03fae5baac --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfTypedefBase.java @@ -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); + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfTypedefIntegral.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfTypedefIntegral.java new file mode 100644 index 0000000000..8ebdb46d77 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfTypedefIntegral.java @@ -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(); + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfTypedefPointer.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfTypedefPointer.java new file mode 100644 index 0000000000..573292042a --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfTypedefPointer.java @@ -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); + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfTypedefUser.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfTypedefUser.java new file mode 100644 index 0000000000..84c664d5a5 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfTypedefUser.java @@ -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; + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfUtilities.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfUtilities.java new file mode 100644 index 0000000000..531a5ac070 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfUtilities.java @@ -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"; + } +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfWinOS.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfWinOS.java new file mode 100644 index 0000000000..653b696179 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfWinOS.java @@ -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 metaData) { + pe = new IsfWinPE(metaData); + pdb = new IsfWinPDB(metaData); + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfWinPDB.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfWinPDB.java new file mode 100644 index 0000000000..1a58116895 --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfWinPDB.java @@ -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 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")); //? + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfWinPE.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfWinPE.java new file mode 100644 index 0000000000..7157c80c1d --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfWinPE.java @@ -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 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]); + } + +} diff --git a/Ghidra/Debug/Debugger-isf/src/main/proto/isf.proto b/Ghidra/Debug/Debugger-isf/src/main/proto/isf.proto new file mode 100644 index 0000000000..494fbc2e8e --- /dev/null +++ b/Ghidra/Debug/Debugger-isf/src/main/proto/isf.proto @@ -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; + } +} diff --git a/Ghidra/Debug/Framework-AsyncComm/Module.manifest b/Ghidra/Debug/Framework-AsyncComm/Module.manifest index e69de29bb2..89174007c9 100644 --- a/Ghidra/Debug/Framework-AsyncComm/Module.manifest +++ b/Ghidra/Debug/Framework-AsyncComm/Module.manifest @@ -0,0 +1 @@ +MODULE FILE LICENSE: lib/protobuf-java-3.21.8.jar BSD-3-GOOGLE diff --git a/Ghidra/Debug/Framework-AsyncComm/build.gradle b/Ghidra/Debug/Framework-AsyncComm/build.gradle index 66363f73e5..a84e156808 100644 --- a/Ghidra/Debug/Framework-AsyncComm/build.gradle +++ b/Ghidra/Debug/Framework-AsyncComm/build.gradle @@ -22,6 +22,7 @@ apply plugin: 'eclipse' eclipse.project.name = 'Debug Framework-AsyncComm' dependencies { + api 'com.google.protobuf:protobuf-java:3.21.8' api project(':Generic') api project(':Graph') api project(':ProposedUtils') diff --git a/Ghidra/Debug/Framework-AsyncComm/certification.manifest b/Ghidra/Debug/Framework-AsyncComm/certification.manifest index 895ac4b698..c163a88c69 100644 --- a/Ghidra/Debug/Framework-AsyncComm/certification.manifest +++ b/Ghidra/Debug/Framework-AsyncComm/certification.manifest @@ -1,2 +1,3 @@ ##VERSION: 2.0 +##MODULE IP: BSD-3-GOOGLE Module.manifest||GHIDRA||||END|