This is a simple skeleton help topic. For a better description of what should and should not
+ go in here, see the "sample" Ghidra extension in the Extensions/Ghidra directory, or see your
+ favorite help topic. In general, language modules do not have their own help topics.
+
+
diff --git a/GhidraPlugin/bin/main/images/README.txt b/GhidraPlugin/bin/main/images/README.txt
new file mode 100644
index 00000000..f20ae77b
--- /dev/null
+++ b/GhidraPlugin/bin/main/images/README.txt
@@ -0,0 +1,2 @@
+The "src/resources/images" directory is intended to hold all image/icon files used by
+this module.
diff --git a/GhidraPlugin/bin/scripts/README.txt b/GhidraPlugin/bin/scripts/README.txt
new file mode 100644
index 00000000..9e408f4b
--- /dev/null
+++ b/GhidraPlugin/bin/scripts/README.txt
@@ -0,0 +1 @@
+Java source directory to hold module-specific Ghidra scripts.
diff --git a/GhidraPlugin/build.gradle b/GhidraPlugin/build.gradle
index 328f0f4e..63365e84 100644
--- a/GhidraPlugin/build.gradle
+++ b/GhidraPlugin/build.gradle
@@ -1,44 +1,66 @@
-plugins {
- id 'java'
+/* ###
+ * 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.
+ */
+// Builds a Ghidra Extension for a given Ghidra installation.
+//
+// An absolute path to the Ghidra installation directory must be supplied either by setting the
+// GHIDRA_INSTALL_DIR environment variable or Gradle project property:
+//
+// > export GHIDRA_INSTALL_DIR=
+// > gradle
+//
+// or
+//
+// > gradle -PGHIDRA_INSTALL_DIR=
+//
+// Gradle should be invoked from the directory of the project to build. Please see the
+// application.gradle.version property in /Ghidra/application.properties
+// for the correction version of Gradle to use for the Ghidra installation you specify.
+
+//----------------------START "DO NOT MODIFY" SECTION------------------------------
+def ghidraInstallDir
+
+if (System.env.GHIDRA_INSTALL_DIR) {
+ ghidraInstallDir = System.env.GHIDRA_INSTALL_DIR
+}
+else if (project.hasProperty("GHIDRA_INSTALL_DIR")) {
+ ghidraInstallDir = project.getProperty("GHIDRA_INSTALL_DIR")
+}
+else {
+ ghidraInstallDir = ""
}
-sourceCompatibility = JavaVersion.VERSION_17
-targetCompatibility = JavaVersion.VERSION_17
+task distributeExtension {
+ group "Ghidra"
+
+ apply from: new File(ghidraInstallDir).getCanonicalPath() + "/support/buildExtension.gradle"
+ dependsOn ':buildExtension'
+}
+//----------------------END "DO NOT MODIFY" SECTION-------------------------------
repositories {
- flatDir {
- dirs System.getProperty('GHIDRA_INSTALL_DIR') + '/Ghidra/Features/Base/lib'
- dirs System.getProperty('GHIDRA_INSTALL_DIR') + '/Ghidra/Framework/SoftwareModeling/lib'
- dirs System.getProperty('GHIDRA_INSTALL_DIR') + '/Ghidra/Framework/Docking/lib'
- dirs System.getProperty('GHIDRA_INSTALL_DIR') + '/Ghidra/Framework/Generic/lib'
- dirs System.getProperty('GHIDRA_INSTALL_DIR') + '/Ghidra/Framework/Project/lib'
- dirs System.getProperty('GHIDRA_INSTALL_DIR') + '/Ghidra/Framework/Utility/lib'
- dirs System.getProperty('GHIDRA_INSTALL_DIR') + '/Ghidra/Framework/Gui/lib'
- }
+ // Declare dependency repositories here. This is not needed if dependencies are manually
+ // dropped into the lib/ directory.
+ // See https://docs.gradle.org/current/userguide/declaring_repositories.html for more info.
+ // Ex: mavenCentral()
}
dependencies {
- implementation name: 'Base', version: ''
- implementation name: 'SoftwareModeling', version: ''
- implementation name: 'Docking', version: ''
- implementation name: 'Generic', version: ''
- implementation name: 'Project', version: ''
- implementation name: 'Utility', version: ''
- implementation name: 'Gui', version: ''
+ // Any external dependencies added here will automatically be copied to the lib/ directory when
+ // this extension is built.
}
-compileJava {
- dependsOn configurations.compileClasspath
-}
-
-jar {
- manifest {
- attributes(
- 'Implementation-Title': 'Symbol Rename Logger Plugin',
- 'Implementation-Version': '1.0'
- )
- }
- from {
- configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
- }
-}
\ No newline at end of file
+// Exclude additional files from the built extension
+// Ex: buildExtension.exclude '.idea/**'
diff --git a/GhidraPlugin/data/README.txt b/GhidraPlugin/data/README.txt
new file mode 100644
index 00000000..1222f673
--- /dev/null
+++ b/GhidraPlugin/data/README.txt
@@ -0,0 +1,15 @@
+The "data" directory is intended to hold data files that will be used by this module and will
+not end up in the .jar file, but will be present in the zip or tar file. Typically, data
+files are placed here rather than in the resources directory if the user may need to edit them.
+
+An optional data/languages directory can exist for the purpose of containing various Sleigh language
+specification files and importer opinion files.
+
+The data/buildLanguage.xml is used for building the contents of the data/languages directory.
+
+The skel language definition has been commented-out within the skel.ldefs file so that the
+skeleton language does not show-up within Ghidra.
+
+See the Sleigh language documentation (docs/languages/index.html) for details Sleigh language
+specification syntax.
+
\ No newline at end of file
diff --git a/GhidraPlugin/extension.properties b/GhidraPlugin/extension.properties
index 999fb499..86a8a29a 100644
--- a/GhidraPlugin/extension.properties
+++ b/GhidraPlugin/extension.properties
@@ -1,5 +1,5 @@
name=@extname@
-description=A plugin that logs symbol and function rename events
-author=Your Name
+description=The extension description can be customized by editing the extension.properties file.
+author=
createdOn=
-version=@extversion@
\ No newline at end of file
+version=@extversion@
diff --git a/GhidraPlugin/ghidra_scripts/README.txt b/GhidraPlugin/ghidra_scripts/README.txt
new file mode 100644
index 00000000..9e408f4b
--- /dev/null
+++ b/GhidraPlugin/ghidra_scripts/README.txt
@@ -0,0 +1 @@
+Java source directory to hold module-specific Ghidra scripts.
diff --git a/GhidraPlugin/lib/README.txt b/GhidraPlugin/lib/README.txt
new file mode 100644
index 00000000..528dbc6c
--- /dev/null
+++ b/GhidraPlugin/lib/README.txt
@@ -0,0 +1,3 @@
+The "lib" directory is intended to hold Jar files which this module is dependent upon. Jar files
+may be placed in this directory manually, or automatically by maven via the dependencies block
+of this module's build.gradle file.
\ No newline at end of file
diff --git a/GhidraPlugin/os/linux_x86_64/README.txt b/GhidraPlugin/os/linux_x86_64/README.txt
new file mode 100644
index 00000000..7dd33ce2
--- /dev/null
+++ b/GhidraPlugin/os/linux_x86_64/README.txt
@@ -0,0 +1,3 @@
+The "os/linux_x86_64" directory is intended to hold Linux native binaries
+which this module is dependent upon. This directory may be eliminated for a specific
+module if native binaries are not provided for the corresponding platform.
diff --git a/GhidraPlugin/os/mac_x86_64/README.txt b/GhidraPlugin/os/mac_x86_64/README.txt
new file mode 100644
index 00000000..fbf2469e
--- /dev/null
+++ b/GhidraPlugin/os/mac_x86_64/README.txt
@@ -0,0 +1,3 @@
+The "os/mac_x86_64" directory is intended to hold macOS (OS X) native binaries
+which this module is dependent upon. This directory may be eliminated for a specific
+module if native binaries are not provided for the corresponding platform.
diff --git a/GhidraPlugin/os/win_x86_64/README.txt b/GhidraPlugin/os/win_x86_64/README.txt
new file mode 100644
index 00000000..e0359950
--- /dev/null
+++ b/GhidraPlugin/os/win_x86_64/README.txt
@@ -0,0 +1,3 @@
+The "os/win_x86_64" directory is intended to hold MS Windows native binaries (.exe)
+which this module is dependent upon. This directory may be eliminated for a specific
+module if native binaries are not provided for the corresponding platform.
diff --git a/GhidraPlugin/src/main/help/help/TOC_Source.xml b/GhidraPlugin/src/main/help/help/TOC_Source.xml
new file mode 100644
index 00000000..a34f62e8
--- /dev/null
+++ b/GhidraPlugin/src/main/help/help/TOC_Source.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
diff --git a/GhidraPlugin/src/main/help/help/topics/ghidraplugin/help.html b/GhidraPlugin/src/main/help/help/topics/ghidraplugin/help.html
new file mode 100644
index 00000000..1f9d6a1f
--- /dev/null
+++ b/GhidraPlugin/src/main/help/help/topics/ghidraplugin/help.html
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+ Skeleton Help File for a Module
+
+
+
+
+
Skeleton Help File for a Module
+
+
This is a simple skeleton help topic. For a better description of what should and should not
+ go in here, see the "sample" Ghidra extension in the Extensions/Ghidra directory, or see your
+ favorite help topic. In general, language modules do not have their own help topics.
+
+
diff --git a/GhidraPlugin/src/main/java/ghidraplugin/GhidraPluginAnalyzer.java b/GhidraPlugin/src/main/java/ghidraplugin/GhidraPluginAnalyzer.java
new file mode 100644
index 00000000..8718a0d9
--- /dev/null
+++ b/GhidraPlugin/src/main/java/ghidraplugin/GhidraPluginAnalyzer.java
@@ -0,0 +1,74 @@
+/* ###
+ * 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 ghidraplugin;
+
+import ghidra.app.services.AbstractAnalyzer;
+import ghidra.app.services.AnalyzerType;
+import ghidra.app.util.importer.MessageLog;
+import ghidra.framework.options.Options;
+import ghidra.program.model.address.AddressSetView;
+import ghidra.program.model.listing.Program;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.task.TaskMonitor;
+
+/**
+ * Provide class-level documentation that describes what this analyzer does.
+ */
+public class GhidraPluginAnalyzer extends AbstractAnalyzer {
+
+ public GhidraPluginAnalyzer() {
+
+ // Name the analyzer and give it a description.
+
+ super("My Analyzer", "Analyzer description goes here", AnalyzerType.BYTE_ANALYZER);
+ }
+
+ @Override
+ public boolean getDefaultEnablement(Program program) {
+
+ // Return true if analyzer should be enabled by default
+
+ return true;
+ }
+
+ @Override
+ public boolean canAnalyze(Program program) {
+
+ // Examine 'program' to determine of this analyzer should analyze it. Return true
+ // if it can.
+
+ return true;
+ }
+
+ @Override
+ public void registerOptions(Options options, Program program) {
+
+ // If this analyzer has custom options, register them here
+
+ options.registerOption("Option name goes here", false, null,
+ "Option description goes here");
+ }
+
+ @Override
+ public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
+ throws CancelledException {
+
+ // Perform analysis when things get added to the 'program'. Return true if the
+ // analysis succeeded.
+
+ return false;
+ }
+}
diff --git a/GhidraPlugin/src/main/java/ghidraplugin/GhidraPluginPlugin.java b/GhidraPlugin/src/main/java/ghidraplugin/GhidraPluginPlugin.java
new file mode 100644
index 00000000..92ecd6a9
--- /dev/null
+++ b/GhidraPlugin/src/main/java/ghidraplugin/GhidraPluginPlugin.java
@@ -0,0 +1,116 @@
+/* ###
+ * 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 ghidraplugin;
+
+import java.awt.BorderLayout;
+
+import javax.swing.*;
+
+import docking.ActionContext;
+import docking.ComponentProvider;
+import docking.action.DockingAction;
+import docking.action.ToolBarData;
+import ghidra.app.ExamplesPluginPackage;
+import ghidra.app.plugin.PluginCategoryNames;
+import ghidra.app.plugin.ProgramPlugin;
+import ghidra.framework.plugintool.*;
+import ghidra.framework.plugintool.util.PluginStatus;
+import ghidra.util.HelpLocation;
+import ghidra.util.Msg;
+import resources.Icons;
+
+/**
+ * Provide class-level documentation that describes what this plugin does.
+ */
+//@formatter:off
+@PluginInfo(
+ status = PluginStatus.STABLE,
+ packageName = ExamplesPluginPackage.NAME,
+ category = PluginCategoryNames.EXAMPLES,
+ shortDescription = "Plugin short description goes here.",
+ description = "Plugin long description goes here."
+)
+//@formatter:on
+public class GhidraPluginPlugin extends ProgramPlugin {
+
+ MyProvider provider;
+
+ /**
+ * Plugin constructor.
+ *
+ * @param tool The plugin tool that this plugin is added to.
+ */
+ public GhidraPluginPlugin(PluginTool tool) {
+ super(tool);
+
+ // Customize provider (or remove if a provider is not desired)
+ String pluginName = getName();
+ provider = new MyProvider(this, pluginName);
+
+ // Customize help (or remove if help is not desired)
+ String topicName = this.getClass().getPackage().getName();
+ String anchorName = "HelpAnchor";
+ provider.setHelpLocation(new HelpLocation(topicName, anchorName));
+ }
+
+ @Override
+ public void init() {
+ super.init();
+
+ // Acquire services if necessary
+ }
+
+ // If provider is desired, it is recommended to move it to its own file
+ private static class MyProvider extends ComponentProvider {
+
+ private JPanel panel;
+ private DockingAction action;
+
+ public MyProvider(Plugin plugin, String owner) {
+ super(plugin.getTool(), "Skeleton Provider", owner);
+ buildPanel();
+ createActions();
+ }
+
+ // Customize GUI
+ private void buildPanel() {
+ panel = new JPanel(new BorderLayout());
+ JTextArea textArea = new JTextArea(5, 25);
+ textArea.setEditable(false);
+ panel.add(new JScrollPane(textArea));
+ setVisible(true);
+ }
+
+ // Customize actions
+ private void createActions() {
+ action = new DockingAction("My Action", getOwner()) {
+ @Override
+ public void actionPerformed(ActionContext context) {
+ Msg.showInfo(getClass(), panel, "Custom Action", "Hello!");
+ }
+ };
+ action.setToolBarData(new ToolBarData(Icons.ADD_ICON, null));
+ action.setEnabled(true);
+ action.markHelpUnnecessary();
+ dockingTool.addLocalAction(this, action);
+ }
+
+ @Override
+ public JComponent getComponent() {
+ return panel;
+ }
+ }
+}
diff --git a/GhidraPlugin/src/main/java/ghidraplugin/SymbolRenameLoggerPlugin.java b/GhidraPlugin/src/main/java/ghidraplugin/SymbolRenameLoggerPlugin.java
new file mode 100644
index 00000000..4f0c3cf6
--- /dev/null
+++ b/GhidraPlugin/src/main/java/ghidraplugin/SymbolRenameLoggerPlugin.java
@@ -0,0 +1,350 @@
+package ghidraplugin;
+
+import ghidra.app.plugin.PluginCategoryNames;
+import ghidra.app.plugin.ProgramPlugin;
+import ghidra.framework.plugintool.PluginInfo;
+import ghidra.framework.plugintool.PluginTool;
+import ghidra.framework.plugintool.util.PluginStatus;
+import ghidra.program.model.listing.Program;
+import ghidra.program.util.ProgramChangeRecord;
+import ghidra.program.util.ProgramEvent;
+import ghidra.util.Msg;
+import ghidra.framework.model.*;
+import ghidra.program.model.symbol.*;
+import ghidra.program.model.listing.Function;
+import ghidra.program.util.*;
+
+@PluginInfo(
+ status = PluginStatus.STABLE,
+ packageName = "SymbolLogger",
+ category = PluginCategoryNames.COMMON,
+ shortDescription = "Logs symbol and function renames",
+ description = "A plugin that monitors and logs all symbol and function rename events to the console",
+ servicesRequired = {},
+ servicesProvided = {}
+)
+public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObjectListener {
+
+ public SymbolRenameLoggerPlugin(PluginTool tool) {
+ super(tool);
+ }
+
+ @Override
+ protected void init() {
+ super.init();
+ Msg.info(this, "SymbolRenameLoggerPlugin initialized");
+ }
+
+ @Override
+ protected void programActivated(Program program) {
+ super.programActivated(program);
+ if (program != null) {
+ program.addListener(this);
+ Msg.info(this, "Started listening for rename events in program: " + program.getName());
+ }
+ }
+
+ @Override
+ protected void programDeactivated(Program program) {
+ if (program != null) {
+ program.removeListener(this);
+ Msg.info(this, "Stopped listening for rename events in program: " + program.getName());
+ }
+ super.programDeactivated(program);
+ }
+
+ @Override
+ public void domainObjectChanged(DomainObjectChangedEvent ev) {
+ for (DomainObjectChangeRecord record : ev) {
+ if (record instanceof ProgramChangeRecord) {
+ ProgramChangeRecord progRecord = (ProgramChangeRecord) record;
+ handleProgramChange(progRecord);
+ }
+ }
+ }
+
+ private void handleProgramChange(ProgramChangeRecord record) {
+ ProgramEvent eventType = (ProgramEvent)record.getEventType();
+
+ // Handle symbol rename events
+ if (eventType == ProgramEvent.SYMBOL_RENAMED) {
+ handleSymbolRenamed(record);
+ }
+ // Handle function rename events (functions are also symbols, but we can be more specific)
+ else if (eventType == ProgramEvent.FUNCTION_CHANGED) {
+ handleFunctionChanged(record);
+ }
+ // Handle symbol added events (in case we want to track new symbols)
+ else if (eventType == ProgramEvent.SYMBOL_ADDED) {
+ handleSymbolAdded(record);
+ }
+ // Handle symbol removed events
+ else if (eventType == ProgramEvent.SYMBOL_REMOVED) {
+ handleSymbolRemoved(record);
+ }
+ // Handle data type changes (includes global type definitions, structures, etc.)
+ else if (eventType == ProgramEvent.DATA_TYPE_CHANGED) {
+ handleDataTypeChanged(record);
+ }
+ // Handle data type added events
+ else if (eventType == ProgramEvent.DATA_TYPE_ADDED) {
+ handleDataTypeAdded(record);
+ }
+ // Handle data type removed events
+ else if (eventType == ProgramEvent.DATA_TYPE_REMOVED) {
+ handleDataTypeRemoved(record);
+ }
+ // Handle data type renamed events
+ else if (eventType == ProgramEvent.DATA_TYPE_RENAMED) {
+ handleDataTypeRenamed(record);
+ }
+ // Handle function signature changes (parameters, return types, etc.)
+ else if (eventType == ProgramEvent.FUNCTION_CHANGED) {
+ handleFunctionSignatureChanged(record);
+ }
+ }
+
+ private void handleSymbolRenamed(ProgramChangeRecord record) {
+ Object newValue = record.getNewValue();
+ Object oldValue = record.getOldValue();
+
+ String newName = (newValue != null) ? newValue.toString() : "null";
+ String oldName = (oldValue != null) ? oldValue.toString() : "null";
+
+ Msg.info(this, String.format("SYMBOL RENAMED: '%s' -> '%s' at address %s",
+ oldName, newName, record.getStart()));
+
+ // Try to get additional information about the symbol
+ try {
+ Program program = getCurrentProgram();
+ if (program != null) {
+ SymbolTable symbolTable = program.getSymbolTable();
+ Symbol[] symbols = symbolTable.getSymbols(record.getStart());
+
+ for (Symbol symbol : symbols) {
+ if (symbol.getName().equals(newName)) {
+ String symbolType = getSymbolTypeDescription(symbol);
+ Msg.info(this, String.format(" Symbol type: %s, Namespace: %s",
+ symbolType, symbol.getParentNamespace().getName()));
+
+ // If it's a function, log additional function details
+ if (symbol.getSymbolType() == SymbolType.FUNCTION) {
+ Function function = (Function) symbol.getObject();
+ if (function != null) {
+ Msg.info(this, String.format(" Function signature: %s",
+ function.getPrototypeString(false, false)));
+ }
+ }
+ break;
+ }
+ }
+ }
+ } catch (Exception e) {
+ Msg.error(this, "Error getting symbol details: " + e.getMessage());
+ }
+ }
+
+ private void handleFunctionChanged(ProgramChangeRecord record) {
+ // This handles function-specific changes including renames and signature changes
+ Object newValue = record.getNewValue();
+ Object oldValue = record.getOldValue();
+
+ if (newValue instanceof Function && oldValue instanceof Function) {
+ Function newFunc = (Function) newValue;
+ Function oldFunc = (Function) oldValue;
+
+ // Check for name changes
+ if (!newFunc.getName().equals(oldFunc.getName())) {
+ Msg.info(this, String.format("FUNCTION RENAMED: '%s' -> '%s' at address %s",
+ oldFunc.getName(), newFunc.getName(), newFunc.getEntryPoint()));
+ }
+
+ // Check for signature changes
+ String oldSignature = oldFunc.getPrototypeString(false, false);
+ String newSignature = newFunc.getPrototypeString(false, false);
+ if (!oldSignature.equals(newSignature)) {
+ Msg.info(this, String.format("FUNCTION SIGNATURE CHANGED at address %s:", newFunc.getEntryPoint()));
+ Msg.info(this, String.format(" Old: %s", oldSignature));
+ Msg.info(this, String.format(" New: %s", newSignature));
+
+ // Log specific changes
+ logFunctionSignatureDetails(oldFunc, newFunc);
+ }
+ } else if (newValue instanceof Function) {
+ Function function = (Function) newValue;
+ Msg.info(this, String.format("FUNCTION MODIFIED: %s at address %s",
+ function.getName(), function.getEntryPoint()));
+ Msg.info(this, String.format(" Signature: %s", function.getPrototypeString(false, false)));
+ }
+ }
+
+ private void handleFunctionSignatureChanged(ProgramChangeRecord record) {
+ // Handle detailed function signature changes
+ handleFunctionChanged(record); // Reuse the existing logic
+ }
+
+ private void handleDataTypeChanged(ProgramChangeRecord record) {
+ Object newValue = record.getNewValue();
+ Object oldValue = record.getOldValue();
+
+ Msg.info(this, String.format("DATA TYPE CHANGED at address %s", record.getStart()));
+
+ if (oldValue != null && newValue != null) {
+ Msg.info(this, String.format(" Old type: %s", oldValue.toString()));
+ Msg.info(this, String.format(" New type: %s", newValue.toString()));
+ } else if (newValue != null) {
+ Msg.info(this, String.format(" Type set to: %s", newValue.toString()));
+ }
+
+ // Try to get more context about the data type change
+ try {
+ Program program = getCurrentProgram();
+ if (program != null && record.getStart() != null) {
+ ghidra.program.model.data.Data data = program.getListing().getDataAt(record.getStart());
+ if (data != null) {
+ Msg.info(this, String.format(" Data label: %s", data.getLabel()));
+ Msg.info(this, String.format(" Data type: %s", data.getDataType().getName()));
+ }
+ }
+ } catch (Exception e) {
+ Msg.error(this, "Error getting data type details: " + e.getMessage());
+ }
+ }
+
+ private void handleDataTypeAdded(ProgramChangeRecord record) {
+ Object newValue = record.getNewValue();
+
+ Msg.info(this, String.format("DATA TYPE ADDED at address %s", record.getStart()));
+ if (newValue != null) {
+ Msg.info(this, String.format(" Type: %s", newValue.toString()));
+ }
+ }
+
+ private void handleDataTypeRemoved(ProgramChangeRecord record) {
+ Object oldValue = record.getOldValue();
+
+ Msg.info(this, String.format("DATA TYPE REMOVED at address %s", record.getStart()));
+ if (oldValue != null) {
+ Msg.info(this, String.format(" Removed type: %s", oldValue.toString()));
+ }
+ }
+
+ private void handleDataTypeRenamed(ProgramChangeRecord record) {
+ Object newValue = record.getNewValue();
+ Object oldValue = record.getOldValue();
+
+ String newName = (newValue != null) ? newValue.toString() : "null";
+ String oldName = (oldValue != null) ? oldValue.toString() : "null";
+
+ Msg.info(this, String.format("DATA TYPE RENAMED: '%s' -> '%s' at address %s",
+ oldName, newName, record.getStart()));
+ }
+
+ private void logFunctionSignatureDetails(Function oldFunc, Function newFunc) {
+ try {
+ // Check return type changes
+ if (!oldFunc.getReturnType().equals(newFunc.getReturnType())) {
+ Msg.info(this, String.format(" Return type changed: %s -> %s",
+ oldFunc.getReturnType().getName(), newFunc.getReturnType().getName()));
+ }
+
+ // Check parameter count changes
+ int oldParamCount = oldFunc.getParameterCount();
+ int newParamCount = newFunc.getParameterCount();
+ if (oldParamCount != newParamCount) {
+ Msg.info(this, String.format(" Parameter count changed: %d -> %d",
+ oldParamCount, newParamCount));
+ }
+
+ // Check individual parameter changes
+ int maxParams = Math.max(oldParamCount, newParamCount);
+ for (int i = 0; i < maxParams; i++) {
+ if (i < oldParamCount && i < newParamCount) {
+ ghidra.program.model.listing.Parameter oldParam = oldFunc.getParameter(i);
+ ghidra.program.model.listing.Parameter newParam = newFunc.getParameter(i);
+
+ if (!oldParam.getDataType().equals(newParam.getDataType())) {
+ Msg.info(this, String.format(" Parameter %d type changed: %s -> %s",
+ i, oldParam.getDataType().getName(), newParam.getDataType().getName()));
+ }
+
+ if (!oldParam.getName().equals(newParam.getName())) {
+ Msg.info(this, String.format(" Parameter %d name changed: %s -> %s",
+ i, oldParam.getName(), newParam.getName()));
+ }
+ } else if (i < newParamCount) {
+ ghidra.program.model.listing.Parameter newParam = newFunc.getParameter(i);
+ Msg.info(this, String.format(" Parameter %d added: %s %s",
+ i, newParam.getDataType().getName(), newParam.getName()));
+ } else {
+ ghidra.program.model.listing.Parameter oldParam = oldFunc.getParameter(i);
+ Msg.info(this, String.format(" Parameter %d removed: %s %s",
+ i, oldParam.getDataType().getName(), oldParam.getName()));
+ }
+ }
+
+ // Check calling convention changes
+ if (!oldFunc.getCallingConventionName().equals(newFunc.getCallingConventionName())) {
+ Msg.info(this, String.format(" Calling convention changed: %s -> %s",
+ oldFunc.getCallingConventionName(), newFunc.getCallingConventionName()));
+ }
+
+ } catch (Exception e) {
+ Msg.error(this, "Error logging function signature details: " + e.getMessage());
+ }
+ }
+
+ private void handleSymbolAdded(ProgramChangeRecord record) {
+ Object newValue = record.getNewValue();
+ if (newValue instanceof Symbol) {
+ Symbol symbol = (Symbol) newValue;
+ String symbolType = getSymbolTypeDescription(symbol);
+ Msg.info(this, String.format("SYMBOL ADDED: '%s' (%s) at address %s",
+ symbol.getName(), symbolType, symbol.getAddress()));
+ }
+ }
+
+ private void handleSymbolRemoved(ProgramChangeRecord record) {
+ Object oldValue = record.getOldValue();
+ if (oldValue instanceof Symbol) {
+ Symbol symbol = (Symbol) oldValue;
+ String symbolType = getSymbolTypeDescription(symbol);
+ Msg.info(this, String.format("SYMBOL REMOVED: '%s' (%s) at address %s",
+ symbol.getName(), symbolType, symbol.getAddress()));
+ }
+ }
+
+ private String getSymbolTypeDescription(Symbol symbol) {
+ SymbolType type = symbol.getSymbolType();
+
+ if (type == SymbolType.FUNCTION) {
+ return "Function";
+ } else if (type == SymbolType.LABEL) {
+ return "Label";
+ } else if (type == SymbolType.CLASS) {
+ return "Class";
+ } else if (type == SymbolType.NAMESPACE) {
+ return "Namespace";
+ } else if (type == SymbolType.PARAMETER) {
+ return "Parameter";
+ } else if (type == SymbolType.LOCAL_VAR) {
+ return "Local Variable";
+ } else if (type == SymbolType.GLOBAL_VAR) {
+ return "Global Variable";
+ } else if (type == SymbolType.LIBRARY) {
+ return "Library";
+ } else {
+ return type.toString();
+ }
+ }
+
+ @Override
+ protected void dispose() {
+ Program program = getCurrentProgram();
+ if (program != null) {
+ program.removeListener(this);
+ }
+ super.dispose();
+ Msg.info(this, "SymbolRenameLoggerPlugin disposed");
+ }
+}
\ No newline at end of file
diff --git a/GhidraPlugin/src/main/java/symbollogger/SymbolRenameLoggerPlugin.java b/GhidraPlugin/src/main/java/symbollogger/SymbolRenameLoggerPlugin.java
deleted file mode 100644
index 774cd317..00000000
--- a/GhidraPlugin/src/main/java/symbollogger/SymbolRenameLoggerPlugin.java
+++ /dev/null
@@ -1,198 +0,0 @@
-package symbollogger;
-
-import ghidra.app.plugin.PluginCategoryNames;
-import ghidra.app.plugin.ProgramPlugin;
-import ghidra.framework.plugintool.PluginInfo;
-import ghidra.framework.plugintool.PluginTool;
-import ghidra.framework.plugintool.util.PluginStatus;
-import ghidra.program.model.listing.Program;
-import ghidra.program.util.ProgramChangeRecord;
-import ghidra.program.util.ProgramEvent;
-import ghidra.util.Msg;
-import ghidra.framework.model.*;
-import ghidra.program.model.symbol.*;
-import ghidra.program.model.listing.Function;
-import ghidra.program.util.*;
-
-@PluginInfo(
- status = PluginStatus.STABLE,
- packageName = "SymbolLogger",
- category = PluginCategoryNames.MISC,
- shortDescription = "Logs symbol and function renames",
- description = "A plugin that monitors and logs all symbol and function rename events to the console",
- servicesRequired = {},
- servicesProvided = {}
-)
-public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObjectListener {
-
- public SymbolRenameLoggerPlugin(PluginTool tool) {
- super(tool);
- }
-
- @Override
- protected void init() {
- super.init();
- Msg.info(this, "SymbolRenameLoggerPlugin initialized");
- }
-
- @Override
- protected void programActivated(Program program) {
- super.programActivated(program);
- if (program != null) {
- program.addListener(this);
- Msg.info(this, "Started listening for rename events in program: " + program.getName());
- }
- }
-
- @Override
- protected void programDeactivated(Program program) {
- if (program != null) {
- program.removeListener(this);
- Msg.info(this, "Stopped listening for rename events in program: " + program.getName());
- }
- super.programDeactivated(program);
- }
-
- @Override
- public void domainObjectChanged(DomainObjectChangedEvent ev) {
- for (DomainObjectChangeRecord record : ev) {
- if (record instanceof ProgramChangeRecord) {
- ProgramChangeRecord progRecord = (ProgramChangeRecord) record;
- handleProgramChange(progRecord);
- }
- }
- }
-
- private void handleProgramChange(ProgramChangeRecord record) {
- ProgramEvent eventType = record.getEventType();
-
- // Handle symbol rename events
- if (eventType == ProgramEvent.SYMBOL_RENAMED) {
- handleSymbolRenamed(record);
- }
- // Handle function rename events (functions are also symbols, but we can be more specific)
- else if (eventType == ProgramEvent.FUNCTION_CHANGED) {
- handleFunctionChanged(record);
- }
- // Handle symbol added events (in case we want to track new symbols)
- else if (eventType == ProgramEvent.SYMBOL_ADDED) {
- handleSymbolAdded(record);
- }
- // Handle symbol removed events
- else if (eventType == ProgramEvent.SYMBOL_REMOVED) {
- handleSymbolRemoved(record);
- }
- }
-
- private void handleSymbolRenamed(ProgramChangeRecord record) {
- Object newValue = record.getNewValue();
- Object oldValue = record.getOldValue();
-
- String newName = (newValue != null) ? newValue.toString() : "null";
- String oldName = (oldValue != null) ? oldValue.toString() : "null";
-
- Msg.info(this, String.format("SYMBOL RENAMED: '%s' -> '%s' at address %s",
- oldName, newName, record.getStart()));
-
- // Try to get additional information about the symbol
- try {
- Program program = getCurrentProgram();
- if (program != null) {
- SymbolTable symbolTable = program.getSymbolTable();
- Symbol[] symbols = symbolTable.getSymbols(record.getStart());
-
- for (Symbol symbol : symbols) {
- if (symbol.getName().equals(newName)) {
- String symbolType = getSymbolTypeDescription(symbol);
- Msg.info(this, String.format(" Symbol type: %s, Namespace: %s",
- symbolType, symbol.getParentNamespace().getName()));
-
- // If it's a function, log additional function details
- if (symbol.getSymbolType() == SymbolType.FUNCTION) {
- Function function = (Function) symbol.getObject();
- if (function != null) {
- Msg.info(this, String.format(" Function signature: %s",
- function.getPrototypeString(false, false)));
- }
- }
- break;
- }
- }
- }
- } catch (Exception e) {
- Msg.error(this, "Error getting symbol details: " + e.getMessage());
- }
- }
-
- private void handleFunctionChanged(ProgramChangeRecord record) {
- // This handles function-specific changes including renames
- Object newValue = record.getNewValue();
- Object oldValue = record.getOldValue();
-
- if (newValue instanceof Function && oldValue instanceof Function) {
- Function newFunc = (Function) newValue;
- Function oldFunc = (Function) oldValue;
-
- if (!newFunc.getName().equals(oldFunc.getName())) {
- Msg.info(this, String.format("FUNCTION RENAMED: '%s' -> '%s' at address %s",
- oldFunc.getName(), newFunc.getName(), newFunc.getEntryPoint()));
- Msg.info(this, String.format(" Function signature: %s",
- newFunc.getPrototypeString(false, false)));
- }
- }
- }
-
- private void handleSymbolAdded(ProgramChangeRecord record) {
- Object newValue = record.getNewValue();
- if (newValue instanceof Symbol) {
- Symbol symbol = (Symbol) newValue;
- String symbolType = getSymbolTypeDescription(symbol);
- Msg.info(this, String.format("SYMBOL ADDED: '%s' (%s) at address %s",
- symbol.getName(), symbolType, symbol.getAddress()));
- }
- }
-
- private void handleSymbolRemoved(ProgramChangeRecord record) {
- Object oldValue = record.getOldValue();
- if (oldValue instanceof Symbol) {
- Symbol symbol = (Symbol) oldValue;
- String symbolType = getSymbolTypeDescription(symbol);
- Msg.info(this, String.format("SYMBOL REMOVED: '%s' (%s) at address %s",
- symbol.getName(), symbolType, symbol.getAddress()));
- }
- }
-
- private String getSymbolTypeDescription(Symbol symbol) {
- SymbolType type = symbol.getSymbolType();
- switch (type) {
- case FUNCTION:
- return "Function";
- case LABEL:
- return "Label";
- case CLASS:
- return "Class";
- case NAMESPACE:
- return "Namespace";
- case PARAMETER:
- return "Parameter";
- case LOCAL_VAR:
- return "Local Variable";
- case GLOBAL_VAR:
- return "Global Variable";
- case LIBRARY:
- return "Library";
- default:
- return type.toString();
- }
- }
-
- @Override
- protected void dispose() {
- Program program = getCurrentProgram();
- if (program != null) {
- program.removeListener(this);
- }
- super.dispose();
- Msg.info(this, "SymbolRenameLoggerPlugin disposed");
- }
-}
\ No newline at end of file
diff --git a/GhidraPlugin/src/main/resources/images/README.txt b/GhidraPlugin/src/main/resources/images/README.txt
new file mode 100644
index 00000000..f20ae77b
--- /dev/null
+++ b/GhidraPlugin/src/main/resources/images/README.txt
@@ -0,0 +1,2 @@
+The "src/resources/images" directory is intended to hold all image/icon files used by
+this module.
diff --git a/game_re/gh_fix/r3_BNK_playMovie.cxx b/game_re/gh_fix/r3_BNK_playMovie.cxx
index d5c703fc..e24f3f16 100644
--- a/game_re/gh_fix/r3_BNK_playMovie.cxx
+++ b/game_re/gh_fix/r3_BNK_playMovie.cxx
@@ -167,7 +167,7 @@ LAB_00442549:
r3_validateBinkVideoQuality(g_bink_videoBpp, g_bink_realVideoQuality);
FUN_00485400(haveSoundtrack, 0);
FUN_004420f0(0);
- uVar7 = FUN_00401270();
+ uVar7 = FUN_00401270(0, 0);
FUN_0046f680(uVar7, 0);
FUN_0046ed40(0, 0, 1);
FUN_0046f410(0, 0xff);