WIP Ghidra plugin

This commit is contained in:
Guus Waals 2025-06-09 00:20:43 +08:00
parent b5805d39d4
commit 5638734828
2 changed files with 90 additions and 31 deletions

View File

@ -11,15 +11,18 @@ import ghidra.program.util.ProgramEvent;
import ghidra.util.Msg;
import ghidra.framework.model.*;
import ghidra.program.model.symbol.*;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Function;
import ghidra.program.util.*;
import ghidra.framework.cmd.Command;
import ghidra.framework.model.TransactionInfo;
@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",
description = "A plugin that monitors and logs all symbol and function rename events to the console, including undo/redo context",
servicesRequired = {},
servicesProvided = {}
)
@ -63,9 +66,44 @@ public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObj
}
}
/**
* Determines the context of the current operation (direct action, undo, or redo)
*/
private String getOperationContext() {
try {
Program program = getCurrentProgram();
if (program != null) {
TransactionInfo currentTransaction = program.getCurrentTransactionInfo();
if (currentTransaction != null) {
String description = currentTransaction.getDescription();
if (description != null) {
if (description.startsWith("Undo")) {
return "[UNDO] ";
} else if (description.startsWith("Redo")) {
return "[REDO] ";
}
}
}
}
} catch (Exception e) {
// Silently handle any exceptions in context detection
}
return ""; // Direct user action (no prefix)
}
/**
* Enhanced logging method that includes undo/redo context
*/
private void logWithContext(String message) {
String context = getOperationContext();
Msg.info(this, context + message);
}
private void handleProgramChange(ProgramChangeRecord record) {
ProgramEvent eventType = (ProgramEvent)record.getEventType();
Msg.info(this, "Event: " + record.toString());
// Handle symbol rename events
if (eventType == ProgramEvent.SYMBOL_RENAMED) {
handleSymbolRenamed(record);
@ -102,6 +140,27 @@ public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObj
else if (eventType == ProgramEvent.FUNCTION_CHANGED) {
handleFunctionSignatureChanged(record);
}
// Handle transaction events for better undo/redo tracking
// else if (eventType == ProgramEvent..TRANSACTION_STARTED) {
// handleTransactionStarted(record);
// }
// else if (eventType == ProgramEvent.TRANSACTION_ENDED) {
// handleTransactionEnded(record);
// }
}
private void handleTransactionStarted(ProgramChangeRecord record) {
String context = getOperationContext();
if (!context.isEmpty()) {
logWithContext("TRANSACTION STARTED");
}
}
private void handleTransactionEnded(ProgramChangeRecord record) {
String context = getOperationContext();
if (!context.isEmpty()) {
logWithContext("TRANSACTION ENDED");
}
}
private void handleSymbolRenamed(ProgramChangeRecord record) {
@ -111,7 +170,7 @@ public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObj
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",
logWithContext(String.format("SYMBOL RENAMED: '%s' -> '%s' at address %s",
oldName, newName, record.getStart()));
// Try to get additional information about the symbol
@ -124,14 +183,14 @@ public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObj
for (Symbol symbol : symbols) {
if (symbol.getName().equals(newName)) {
String symbolType = getSymbolTypeDescription(symbol);
Msg.info(this, String.format(" Symbol type: %s, Namespace: %s",
logWithContext(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",
logWithContext(String.format(" Function signature: %s",
function.getPrototypeString(false, false)));
}
}
@ -155,7 +214,7 @@ public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObj
// Check for name changes
if (!newFunc.getName().equals(oldFunc.getName())) {
Msg.info(this, String.format("FUNCTION RENAMED: '%s' -> '%s' at address %s",
logWithContext(String.format("FUNCTION RENAMED: '%s' -> '%s' at address %s",
oldFunc.getName(), newFunc.getName(), newFunc.getEntryPoint()));
}
@ -163,18 +222,18 @@ public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObj
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));
logWithContext(String.format("FUNCTION SIGNATURE CHANGED at address %s:", newFunc.getEntryPoint()));
logWithContext(String.format(" Old: %s", oldSignature));
logWithContext(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",
logWithContext(String.format("FUNCTION MODIFIED: %s at address %s",
function.getName(), function.getEntryPoint()));
Msg.info(this, String.format(" Signature: %s", function.getPrototypeString(false, false)));
logWithContext(String.format(" Signature: %s", function.getPrototypeString(false, false)));
}
}
@ -187,23 +246,23 @@ public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObj
Object newValue = record.getNewValue();
Object oldValue = record.getOldValue();
Msg.info(this, String.format("DATA TYPE CHANGED at address %s", record.getStart()));
logWithContext(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()));
logWithContext(String.format(" Old type: %s", oldValue.toString()));
logWithContext(String.format(" New type: %s", newValue.toString()));
} else if (newValue != null) {
Msg.info(this, String.format(" Type set to: %s", newValue.toString()));
logWithContext(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());
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()));
logWithContext(String.format(" Data label: %s", data.getLabel()));
logWithContext(String.format(" Data type: %s", data.getDataType().getName()));
}
}
} catch (Exception e) {
@ -214,18 +273,18 @@ public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObj
private void handleDataTypeAdded(ProgramChangeRecord record) {
Object newValue = record.getNewValue();
Msg.info(this, String.format("DATA TYPE ADDED at address %s", record.getStart()));
logWithContext(String.format("DATA TYPE ADDED at address %s", record.getStart()));
if (newValue != null) {
Msg.info(this, String.format(" Type: %s", newValue.toString()));
logWithContext(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()));
logWithContext(String.format("DATA TYPE REMOVED at address %s", record.getStart()));
if (oldValue != null) {
Msg.info(this, String.format(" Removed type: %s", oldValue.toString()));
logWithContext(String.format(" Removed type: %s", oldValue.toString()));
}
}
@ -236,7 +295,7 @@ public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObj
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",
logWithContext(String.format("DATA TYPE RENAMED: '%s' -> '%s' at address %s",
oldName, newName, record.getStart()));
}
@ -244,7 +303,7 @@ public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObj
try {
// Check return type changes
if (!oldFunc.getReturnType().equals(newFunc.getReturnType())) {
Msg.info(this, String.format(" Return type changed: %s -> %s",
logWithContext(String.format(" Return type changed: %s -> %s",
oldFunc.getReturnType().getName(), newFunc.getReturnType().getName()));
}
@ -252,7 +311,7 @@ public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObj
int oldParamCount = oldFunc.getParameterCount();
int newParamCount = newFunc.getParameterCount();
if (oldParamCount != newParamCount) {
Msg.info(this, String.format(" Parameter count changed: %d -> %d",
logWithContext(String.format(" Parameter count changed: %d -> %d",
oldParamCount, newParamCount));
}
@ -264,28 +323,28 @@ public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObj
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",
logWithContext(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",
logWithContext(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",
logWithContext(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",
logWithContext(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",
logWithContext(String.format(" Calling convention changed: %s -> %s",
oldFunc.getCallingConventionName(), newFunc.getCallingConventionName()));
}
@ -299,7 +358,7 @@ public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObj
if (newValue instanceof Symbol) {
Symbol symbol = (Symbol) newValue;
String symbolType = getSymbolTypeDescription(symbol);
Msg.info(this, String.format("SYMBOL ADDED: '%s' (%s) at address %s",
logWithContext(String.format("SYMBOL ADDED: '%s' (%s) at address %s",
symbol.getName(), symbolType, symbol.getAddress()));
}
}
@ -309,7 +368,7 @@ public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObj
if (oldValue instanceof Symbol) {
Symbol symbol = (Symbol) oldValue;
String symbolType = getSymbolTypeDescription(symbol);
Msg.info(this, String.format("SYMBOL REMOVED: '%s' (%s) at address %s",
logWithContext(String.format("SYMBOL REMOVED: '%s' (%s) at address %s",
symbol.getName(), symbolType, symbol.getAddress()));
}
}