mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-20 23:08:31 +08:00
GP-4408 Refactor of FillOutStructureCmd. Added FillOutStructureHelper and additional DecompilerUtils methods.
This commit is contained in:
+10
-9
@@ -108,7 +108,7 @@ public class AutoAnalysisManager {
|
||||
//private Integer currentTaskPriority = null;
|
||||
//private Stack<Integer> taskPriorityStack = new Stack<Integer>();
|
||||
|
||||
private PriorityQueue<BackgroundCommand> queue = new PriorityQueue<>();
|
||||
private PriorityQueue<BackgroundCommand<Program>> queue = new PriorityQueue<>();
|
||||
private Map<String, Long> timedTasks = new HashMap<>();
|
||||
// used for testing and performance monitoring; accessed via reflection
|
||||
private Map<String, Long> cumulativeTasks = new HashMap<>();
|
||||
@@ -231,7 +231,7 @@ public class AutoAnalysisManager {
|
||||
Options options = program.getOptions(Program.ANALYSIS_PROPERTIES);
|
||||
analyzer.optionsChanged(options.getOptions(analyzer.getName()), getProgram());
|
||||
|
||||
BackgroundCommand cmd = new OneShotAnalysisCommand(analyzer, set, log);
|
||||
OneShotAnalysisCommand cmd = new OneShotAnalysisCommand(analyzer, set, log);
|
||||
schedule(cmd, analyzer.getPriority().priority());
|
||||
}
|
||||
|
||||
@@ -643,13 +643,13 @@ public class AutoAnalysisManager {
|
||||
|
||||
private class AnalysisTaskWrapper {
|
||||
|
||||
private final BackgroundCommand task;
|
||||
private final BackgroundCommand<Program> task;
|
||||
Integer taskPriority;
|
||||
|
||||
private long timeAccumulator;
|
||||
private long startTime;
|
||||
|
||||
AnalysisTaskWrapper(BackgroundCommand task, int taskPriority) {
|
||||
AnalysisTaskWrapper(BackgroundCommand<Program> task, int taskPriority) {
|
||||
this.task = task;
|
||||
this.taskPriority = taskPriority;
|
||||
}
|
||||
@@ -845,7 +845,7 @@ public class AutoAnalysisManager {
|
||||
*/
|
||||
public synchronized void cancelQueuedTasks() {
|
||||
while (!queue.isEmpty()) {
|
||||
BackgroundCommand cmd = queue.getFirst();
|
||||
BackgroundCommand<Program> cmd = queue.getFirst();
|
||||
if (cmd instanceof AnalysisWorkerCommand) {
|
||||
AnalysisWorkerCommand workerCmd = (AnalysisWorkerCommand) cmd;
|
||||
if (!workerCmd.canCancel()) {
|
||||
@@ -857,7 +857,7 @@ public class AutoAnalysisManager {
|
||||
}
|
||||
}
|
||||
|
||||
synchronized boolean schedule(BackgroundCommand cmd, int priority) {
|
||||
synchronized boolean schedule(BackgroundCommand<Program> cmd, int priority) {
|
||||
|
||||
if (cmd == null) {
|
||||
throw new IllegalArgumentException("Can't schedule a null command");
|
||||
@@ -1583,7 +1583,8 @@ public class AutoAnalysisManager {
|
||||
* In a Headed environment a modal task dialog will be used to block user input if the
|
||||
* worker was scheduled with analyzeChanges==false
|
||||
*/
|
||||
private class AnalysisWorkerCommand extends BackgroundCommand implements CancelledListener {
|
||||
private class AnalysisWorkerCommand extends BackgroundCommand<Program>
|
||||
implements CancelledListener {
|
||||
|
||||
private AnalysisWorker worker;
|
||||
private Object workerContext;
|
||||
@@ -1651,7 +1652,7 @@ public class AutoAnalysisManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyTo(DomainObject obj, TaskMonitor analysisMonitor) {
|
||||
public boolean applyTo(Program p, TaskMonitor analysisMonitor) {
|
||||
|
||||
synchronized (this) {
|
||||
workerMonitor.removeCancelledListener(this);
|
||||
@@ -1660,7 +1661,7 @@ public class AutoAnalysisManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert (obj == program);
|
||||
assert (p == program);
|
||||
|
||||
if (analysisMonitor != workerMonitor) {
|
||||
if (!workerMonitor.isCancelEnabled()) {
|
||||
|
||||
+14
-14
@@ -148,11 +148,11 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
|
||||
return currentProgram != null;
|
||||
}
|
||||
};
|
||||
findTableAction.setHelpLocation(
|
||||
new HelpLocation(HelpTopics.SEARCH, findTableAction.getName()));
|
||||
findTableAction.setMenuBarData(new MenuData(
|
||||
new String[] { ToolConstants.MENU_SEARCH, "For Address Tables" }, null, "search for",
|
||||
-1, "AddressTables"));
|
||||
findTableAction
|
||||
.setHelpLocation(new HelpLocation(HelpTopics.SEARCH, findTableAction.getName()));
|
||||
findTableAction.setMenuBarData(
|
||||
new MenuData(new String[] { ToolConstants.MENU_SEARCH, "For Address Tables" }, null,
|
||||
"search for", -1, "AddressTables"));
|
||||
findTableAction.setDescription(getPluginDescription().getDescription());
|
||||
findTableAction.addToWindowWhen(NavigatableActionContext.class);
|
||||
tool.addAction(findTableAction);
|
||||
@@ -168,15 +168,15 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
|
||||
|
||||
int minimumTableSize = addressTableDialog.getMinTableSize();
|
||||
if (minimumTableSize < 2) {
|
||||
addressTableDialog.setDialogText(
|
||||
"Please enter a valid minimum search length. Must be >= 2");
|
||||
addressTableDialog
|
||||
.setDialogText("Please enter a valid minimum search length. Must be >= 2");
|
||||
return;
|
||||
}
|
||||
|
||||
int alignment = addressTableDialog.getAlignment();
|
||||
if (alignment <= 0 || alignment > 8) {
|
||||
addressTableDialog.setDialogText(
|
||||
"Please enter a valid alignment value. Must be > 0 and <= 8");
|
||||
addressTableDialog
|
||||
.setDialogText("Please enter a valid alignment value. Must be > 0 and <= 8");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -217,8 +217,8 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
|
||||
selectedAddresses[i] = model.getAddress(selectedRows[i]);
|
||||
}
|
||||
|
||||
CompoundBackgroundCommand backCmd =
|
||||
new CompoundBackgroundCommand("Disassemble Address Tables", false, true);
|
||||
CompoundBackgroundCommand<Program> backCmd =
|
||||
new CompoundBackgroundCommand<>("Disassemble Address Tables", false, true);
|
||||
offsetLen = addressTableDialog.getOffset();
|
||||
|
||||
// loop over selected table addresses
|
||||
@@ -237,7 +237,7 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
|
||||
tool.executeBackgroundCommand(backCmd, currentProgram);
|
||||
}
|
||||
|
||||
private void createDisassemblyCommandsForAddress(CompoundBackgroundCommand backCmd,
|
||||
private void createDisassemblyCommandsForAddress(CompoundBackgroundCommand<Program> backCmd,
|
||||
Address currentAddress) {
|
||||
|
||||
Listing listing = currentProgram.getListing();
|
||||
@@ -261,8 +261,8 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
|
||||
|
||||
// need to create a context for each one. Also disassembleCmd will align the address to disassemble
|
||||
DisassembleCommand disassembleCmd = new DisassembleCommand(addr, null, true);
|
||||
RegisterValue rval = PseudoDisassembler.getTargetContextRegisterValueForDisassembly(
|
||||
currentProgram, addr);
|
||||
RegisterValue rval = PseudoDisassembler
|
||||
.getTargetContextRegisterValueForDisassembly(currentProgram, addr);
|
||||
disassembleCmd.setInitialContext(rval);
|
||||
backCmd.add(disassembleCmd);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.util.bean.SetEquateDialog;
|
||||
import ghidra.app.util.bean.SetEquateDialog.SelectionType;
|
||||
import ghidra.app.util.datatype.ApplyEnumDialog;
|
||||
import ghidra.framework.cmd.BackgroundCommand;
|
||||
import ghidra.framework.cmd.CompoundBackgroundCommand;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
@@ -182,7 +181,7 @@ public class EquatePlugin extends Plugin {
|
||||
iter = listing.getCodeUnits(context.getProgram().getMemory(), true);
|
||||
}
|
||||
|
||||
BackgroundCommand cmd = new CreateEquateCmd(scalar, iter, dialog.getEquateName(),
|
||||
CreateEquateCmd cmd = new CreateEquateCmd(scalar, iter, dialog.getEquateName(),
|
||||
dialog.getOverwriteExisting(), context);
|
||||
tool.executeBackgroundCommand(cmd, context.getProgram());
|
||||
|
||||
@@ -297,8 +296,8 @@ public class EquatePlugin extends Plugin {
|
||||
|
||||
// Set up a background task that we'll populate with all the rename tasks we need
|
||||
// to perform.
|
||||
CompoundBackgroundCommand bckCmd =
|
||||
new CompoundBackgroundCommand("Rename Equates in Selection", false, true);
|
||||
CompoundBackgroundCommand<Program> bckCmd =
|
||||
new CompoundBackgroundCommand<>("Rename Equates in Selection", false, true);
|
||||
|
||||
// Now loop over all the code units and search for matching scalars...
|
||||
while (iter.hasNext()) {
|
||||
@@ -312,7 +311,7 @@ public class EquatePlugin extends Plugin {
|
||||
}
|
||||
|
||||
private void renameEquateForCodeUnit(ListingActionContext context, Enum enoom, Equate equate,
|
||||
String newName, String oldName, CompoundBackgroundCommand bgCmd, CodeUnit cu) {
|
||||
String newName, String oldName, CompoundBackgroundCommand<Program> bgCmd, CodeUnit cu) {
|
||||
|
||||
if (cu instanceof Instruction) {
|
||||
|
||||
@@ -348,8 +347,8 @@ public class EquatePlugin extends Plugin {
|
||||
CodeUnitIterator iter) {
|
||||
|
||||
// Create a background task to process all the remove tasks.
|
||||
CompoundBackgroundCommand bckCmd =
|
||||
new CompoundBackgroundCommand("Remove Equates in Selection", false, true);
|
||||
CompoundBackgroundCommand<Program> bckCmd =
|
||||
new CompoundBackgroundCommand<>("Remove Equates in Selection", false, true);
|
||||
|
||||
// Now iterate over all code units in the iterator.
|
||||
while (iter.hasNext()) {
|
||||
@@ -362,7 +361,7 @@ public class EquatePlugin extends Plugin {
|
||||
}
|
||||
|
||||
private void removeEquateForCodeUnit(ListingActionContext context, Equate equate,
|
||||
CompoundBackgroundCommand bckCmd, CodeUnit cu) {
|
||||
CompoundBackgroundCommand<Program> bckCmd, CodeUnit cu) {
|
||||
// A code unit can be either an instruction or data; we need to handle each
|
||||
// separately.
|
||||
if (cu instanceof Instruction) {
|
||||
|
||||
+2
-2
@@ -46,8 +46,8 @@ public class ApplyClassFunctionDefinitionUpdatesScript extends GhidraScript {
|
||||
return;
|
||||
}
|
||||
|
||||
RecoveredClassHelper classHelper = new RecoveredClassHelper(currentProgram, currentLocation,
|
||||
state.getTool(), this, false, false, false, monitor);
|
||||
RecoveredClassHelper classHelper = new RecoveredClassHelper(currentProgram, state.getTool(),
|
||||
this, false, false, false, monitor);
|
||||
|
||||
DataTypeManagerService dtms = state.getTool().getService(DataTypeManagerService.class);
|
||||
List<DataType> selectedDatatypes = dtms.getSelectedDatatypes();
|
||||
|
||||
+11
-14
@@ -46,20 +46,20 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
|
||||
return;
|
||||
}
|
||||
|
||||
RecoveredClassHelper classHelper = new RecoveredClassHelper(currentProgram, currentLocation,
|
||||
state.getTool(), this, false, false, false, monitor);
|
||||
|
||||
if(currentAddress == null) {
|
||||
RecoveredClassHelper classHelper = new RecoveredClassHelper(currentProgram, state.getTool(),
|
||||
this, false, false, false, monitor);
|
||||
|
||||
if (currentAddress == null) {
|
||||
println("Cursor must be in a class function.");
|
||||
return;
|
||||
}
|
||||
Function function = getFunctionContaining(currentAddress);
|
||||
if(function == null) {
|
||||
if (function == null) {
|
||||
println("Cursor must be in a class function.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(function.isThunk()) {
|
||||
|
||||
if (function.isThunk()) {
|
||||
println("User should not edit thunks as they are auto-updated from thunked function. " +
|
||||
"Please undo changes to thunk then edit thunked function and rerun script");
|
||||
return;
|
||||
@@ -69,14 +69,13 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
|
||||
println("Function definitions are not affected by purecall changes.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Namespace classNamespace = classHelper.getClassNamespace(currentAddress);
|
||||
if (classNamespace == null) {
|
||||
println("Cursor must be in a class function.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// get a vftable that points to this function - doesn't matter which since it will
|
||||
// be used to get the underlying function definition which will then be used to update
|
||||
// all related function signatures
|
||||
@@ -84,9 +83,8 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
|
||||
|
||||
// get all vftables that point to given function
|
||||
if (vftablesContainingFunction.isEmpty()) {
|
||||
println(
|
||||
"Function is not a virtual function so has no function definition or related " +
|
||||
"function signatures to update");
|
||||
println("Function is not a virtual function so has no function definition or related " +
|
||||
"function signatures to update");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -107,7 +105,7 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (vftableWithAppliedStructure == null) {
|
||||
println(
|
||||
"The vftable(s) containing this function do not have a valid vftable structure " +
|
||||
@@ -159,5 +157,4 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -33,15 +33,33 @@
|
||||
//@category Data Types
|
||||
//@keybinding F6
|
||||
|
||||
import ghidra.app.plugin.core.decompile.actions.FillOutStructureCmd;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.app.decompiler.DecompileOptions;
|
||||
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||
import ghidra.app.decompiler.util.FillOutStructureCmd;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
|
||||
public class CreateStructure extends GhidraScript {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
FillOutStructureCmd fillCmd =
|
||||
new FillOutStructureCmd(currentProgram, currentLocation, state.getTool());
|
||||
fillCmd.applyTo(currentProgram, this.monitor);
|
||||
|
||||
if (currentProgram == null || currentLocation == null) {
|
||||
popup("Requires open program and location");
|
||||
return;
|
||||
}
|
||||
|
||||
DecompileOptions decompileOptions =
|
||||
DecompilerUtils.getDecompileOptions(state.getTool(), currentProgram);
|
||||
FillOutStructureCmd cmd = new FillOutStructureCmd(currentLocation, decompileOptions);
|
||||
if (!cmd.applyTo(currentProgram, this.monitor)) {
|
||||
String detail = "";
|
||||
String msg = cmd.getStatusMsg();
|
||||
if (!StringUtils.isBlank(msg)) {
|
||||
detail = ": " + msg;
|
||||
}
|
||||
popup("Failed to fill-out structure" + detail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,10 +190,9 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
||||
|
||||
hasDebugSymbols = isPDBLoadedInProgram();
|
||||
nameVfunctions = !hasDebugSymbols;
|
||||
recoverClassesFromRTTI =
|
||||
new RTTIWindowsClassRecoverer(currentProgram, currentLocation, state.getTool(),
|
||||
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
|
||||
nameVfunctions, hasDebugSymbols, monitor);
|
||||
recoverClassesFromRTTI = new RTTIWindowsClassRecoverer(currentProgram, state.getTool(),
|
||||
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
|
||||
nameVfunctions, hasDebugSymbols, monitor);
|
||||
}
|
||||
else if (isPE() && isGcc()) {
|
||||
|
||||
@@ -213,10 +212,9 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
||||
}
|
||||
//run fixup old elf relocations script
|
||||
runScript("FixElfExternalOffsetDataRelocationScript.java");
|
||||
recoverClassesFromRTTI =
|
||||
new RTTIGccClassRecoverer(currentProgram, currentLocation, state.getTool(), this,
|
||||
BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
|
||||
nameVfunctions, hasDebugSymbols, monitor);
|
||||
recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, state.getTool(),
|
||||
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
|
||||
nameVfunctions, hasDebugSymbols, monitor);
|
||||
}
|
||||
else if (isGcc()) {
|
||||
|
||||
@@ -245,10 +243,9 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
||||
return;
|
||||
}
|
||||
nameVfunctions = !hasDebugSymbols;
|
||||
recoverClassesFromRTTI =
|
||||
new RTTIGccClassRecoverer(currentProgram, currentLocation, state.getTool(), this,
|
||||
BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
|
||||
nameVfunctions, hasDebugSymbols, monitor);
|
||||
recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, state.getTool(),
|
||||
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
|
||||
nameVfunctions, hasDebugSymbols, monitor);
|
||||
}
|
||||
else {
|
||||
println("This script will not work on this program type");
|
||||
|
||||
@@ -25,10 +25,9 @@
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import docking.options.OptionsService;
|
||||
import ghidra.app.decompiler.*;
|
||||
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.pcode.HighFunction;
|
||||
@@ -38,214 +37,215 @@ import ghidra.program.model.symbol.Symbol;
|
||||
|
||||
public class ShowCCallsScript extends GhidraScript {
|
||||
|
||||
private Address lastAddr = null;
|
||||
private Address lastAddr = null;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
|
||||
if (currentLocation == null) {
|
||||
println("No Location.");
|
||||
return;
|
||||
}
|
||||
|
||||
Listing listing = currentProgram.getListing();
|
||||
|
||||
Function func = listing.getFunctionContaining(currentAddress);
|
||||
|
||||
if (func == null) {
|
||||
println("No Function at address " + currentAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
DecompInterface decomplib = setUpDecompiler(currentProgram);
|
||||
|
||||
try {
|
||||
if (!decomplib.openProgram(currentProgram)) {
|
||||
println("Decompile Error: " + decomplib.getLastMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
// call decompiler for all refs to current function
|
||||
Symbol sym = this.getSymbolAt(func.getEntryPoint());
|
||||
|
||||
Reference refs[] = sym.getReferences(null);
|
||||
|
||||
for (int i = 0; i < refs.length; i++) {
|
||||
if (monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// get function containing.
|
||||
Address refAddr = refs[i].getFromAddress();
|
||||
Function refFunc = currentProgram.getFunctionManager()
|
||||
.getFunctionContaining(refAddr);
|
||||
|
||||
if (refFunc == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// decompile function
|
||||
// look for call to this function
|
||||
// display call
|
||||
analyzeFunction(decomplib, currentProgram, refFunc, refAddr);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
decomplib.dispose();
|
||||
}
|
||||
|
||||
lastAddr = null;
|
||||
}
|
||||
|
||||
private DecompInterface setUpDecompiler(Program program) {
|
||||
DecompInterface decomplib = new DecompInterface();
|
||||
|
||||
DecompileOptions options;
|
||||
options = new DecompileOptions();
|
||||
OptionsService service = state.getTool().getService(OptionsService.class);
|
||||
if (service != null) {
|
||||
ToolOptions opt = service.getOptions("Decompiler");
|
||||
options.grabFromToolAndProgram(null,opt,program);
|
||||
if (currentLocation == null) {
|
||||
println("No Location.");
|
||||
return;
|
||||
}
|
||||
decomplib.setOptions(options);
|
||||
|
||||
|
||||
Listing listing = currentProgram.getListing();
|
||||
|
||||
Function func = listing.getFunctionContaining(currentAddress);
|
||||
|
||||
if (func == null) {
|
||||
println("No Function at address " + currentAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
DecompInterface decomplib = setUpDecompiler(currentProgram);
|
||||
|
||||
try {
|
||||
if (!decomplib.openProgram(currentProgram)) {
|
||||
println("Decompile Error: " + decomplib.getLastMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
// call decompiler for all refs to current function
|
||||
Symbol sym = this.getSymbolAt(func.getEntryPoint());
|
||||
|
||||
Reference refs[] = sym.getReferences(null);
|
||||
|
||||
for (Reference ref : refs) {
|
||||
if (monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// get function containing.
|
||||
Address refAddr = ref.getFromAddress();
|
||||
Function refFunc =
|
||||
currentProgram.getFunctionManager().getFunctionContaining(refAddr);
|
||||
|
||||
if (refFunc == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// decompile function
|
||||
// look for call to this function
|
||||
// display call
|
||||
analyzeFunction(decomplib, currentProgram, refFunc, refAddr);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
decomplib.dispose();
|
||||
}
|
||||
|
||||
lastAddr = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to setup the decompiler interface for the given program
|
||||
* @param program the given program
|
||||
* @return the decompiler interface
|
||||
*/
|
||||
private DecompInterface setUpDecompiler(Program program) {
|
||||
|
||||
DecompileOptions options = DecompilerUtils.getDecompileOptions(state.getTool(), program);
|
||||
|
||||
DecompInterface decomplib = new DecompInterface();
|
||||
|
||||
decomplib.setOptions(options);
|
||||
|
||||
decomplib.toggleCCode(true);
|
||||
decomplib.toggleSyntaxTree(true);
|
||||
decomplib.setSimplificationStyle("decompile");
|
||||
|
||||
|
||||
return decomplib;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze a functions references
|
||||
*/
|
||||
public void analyzeFunction(DecompInterface decomplib, Program prog, Function f, Address refAddr) {
|
||||
/**
|
||||
* Analyze a functions references
|
||||
*/
|
||||
public void analyzeFunction(DecompInterface decomplib, Program prog, Function f,
|
||||
Address refAddr) {
|
||||
|
||||
if (f == null) {
|
||||
return;
|
||||
}
|
||||
if (f == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// don't decompile the function again if it was the same as the last one
|
||||
//
|
||||
if (!f.getEntryPoint().equals(lastAddr))
|
||||
decompileFunction(f, decomplib);
|
||||
lastAddr = f.getEntryPoint();
|
||||
// don't decompile the function again if it was the same as the last one
|
||||
//
|
||||
if (!f.getEntryPoint().equals(lastAddr))
|
||||
decompileFunction(f, decomplib);
|
||||
lastAddr = f.getEntryPoint();
|
||||
|
||||
Instruction instr = prog.getListing().getInstructionAt(refAddr);
|
||||
if (instr == null) {
|
||||
return;
|
||||
}
|
||||
Instruction instr = prog.getListing().getInstructionAt(refAddr);
|
||||
if (instr == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
println(printCall(f, refAddr));
|
||||
}
|
||||
println(printCall(f, refAddr));
|
||||
}
|
||||
|
||||
HighFunction hfunction = null;
|
||||
|
||||
ClangTokenGroup docroot = null;
|
||||
|
||||
HighFunction hfunction = null;
|
||||
public boolean decompileFunction(Function f, DecompInterface decomplib) {
|
||||
// decomplib.setSimplificationStyle("normalize", null);
|
||||
// HighFunction hfunction = decomplib.decompileFunction(f);
|
||||
|
||||
ClangTokenGroup docroot = null;
|
||||
DecompileResults decompRes =
|
||||
decomplib.decompileFunction(f, decomplib.getOptions().getDefaultTimeout(), monitor);
|
||||
//String statusMsg = decomplib.getDecompileMessage();
|
||||
|
||||
public boolean decompileFunction(Function f, DecompInterface decomplib) {
|
||||
// decomplib.setSimplificationStyle("normalize", null);
|
||||
// HighFunction hfunction = decomplib.decompileFunction(f);
|
||||
hfunction = decompRes.getHighFunction();
|
||||
docroot = decompRes.getCCodeMarkup();
|
||||
|
||||
DecompileResults decompRes = decomplib.decompileFunction(f, decomplib.getOptions().getDefaultTimeout(), monitor);
|
||||
//String statusMsg = decomplib.getDecompileMessage();
|
||||
if (hfunction == null)
|
||||
return false;
|
||||
|
||||
hfunction = decompRes.getHighFunction();
|
||||
docroot = decompRes.getCCodeMarkup();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hfunction == null)
|
||||
return false;
|
||||
/**
|
||||
* get the pcode ops that refer to an address
|
||||
*/
|
||||
public Iterator<PcodeOpAST> getPcodeOps(Address refAddr) {
|
||||
if (hfunction == null) {
|
||||
return null;
|
||||
}
|
||||
Iterator<PcodeOpAST> piter = hfunction.getPcodeOps(refAddr.getPhysicalAddress());
|
||||
return piter;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public String printCall(Function f, Address refAddr) {
|
||||
StringBuffer buff = new StringBuffer();
|
||||
|
||||
/**
|
||||
* get the pcode ops that refer to an address
|
||||
*/
|
||||
public Iterator<PcodeOpAST> getPcodeOps(Address refAddr) {
|
||||
if (hfunction == null) {
|
||||
return null;
|
||||
}
|
||||
Iterator<PcodeOpAST> piter = hfunction.getPcodeOps(refAddr.getPhysicalAddress());
|
||||
return piter;
|
||||
}
|
||||
printCall(refAddr, docroot, buff, false, false);
|
||||
|
||||
public String printCall(Function f, Address refAddr) {
|
||||
StringBuffer buff = new StringBuffer();
|
||||
return buff.toString();
|
||||
}
|
||||
|
||||
printCall(refAddr, docroot, buff, false, false);
|
||||
private boolean printCall(Address refAddr, ClangNode node, StringBuffer buff, boolean didStart,
|
||||
boolean isCall) {
|
||||
if (node == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return buff.toString();
|
||||
}
|
||||
Address min = node.getMinAddress();
|
||||
Address max = node.getMaxAddress();
|
||||
if (min == null)
|
||||
return false;
|
||||
|
||||
private boolean printCall(Address refAddr, ClangNode node, StringBuffer buff, boolean didStart, boolean isCall) {
|
||||
if (node == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Address min = node.getMinAddress();
|
||||
Address max = node.getMaxAddress();
|
||||
if (min == null)
|
||||
return false;
|
||||
if (refAddr.getPhysicalAddress().equals(max) && node instanceof ClangStatement) {
|
||||
ClangStatement stmt = (ClangStatement) node;
|
||||
// Don't check for an actual call. The call could be buried more deeply. As long as the original call reference site
|
||||
// is the max address, then display the results.
|
||||
// So this block assumes that the last address contained in the call will be the
|
||||
// address you are looking for.
|
||||
// - This could lead to strange behavior if the call reference is placed on some address
|
||||
// that is not the final call point used by the decompiler.
|
||||
// - Also if there is a delay slot, then the last address for the call reference point
|
||||
// might not be the last address for the block of PCode.
|
||||
//if (stmt.getPcodeOp().getOpcode() == PcodeOp.CALL) {
|
||||
if (!didStart) {
|
||||
Address nodeAddr = node.getMaxAddress();
|
||||
// Decompiler only knows base space.
|
||||
// If reference came from an overlay space, convert address back
|
||||
if (refAddr.getAddressSpace().isOverlaySpace()) {
|
||||
nodeAddr = refAddr.getAddressSpace().getOverlayAddress(nodeAddr);
|
||||
}
|
||||
buff.append(" " + nodeAddr + " : ");
|
||||
}
|
||||
|
||||
if (refAddr.getPhysicalAddress().equals(max) && node instanceof ClangStatement) {
|
||||
ClangStatement stmt = (ClangStatement) node;
|
||||
// Don't check for an actual call. The call could be buried more deeply. As long as the original call reference site
|
||||
// is the max address, then display the results.
|
||||
// So this block assumes that the last address contained in the call will be the
|
||||
// address you are looking for.
|
||||
// - This could lead to strange behavior if the call reference is placed on some address
|
||||
// that is not the final call point used by the decompiler.
|
||||
// - Also if there is a delay slot, then the last address for the call reference point
|
||||
// might not be the last address for the block of PCode.
|
||||
//if (stmt.getPcodeOp().getOpcode() == PcodeOp.CALL) {
|
||||
if (!didStart) {
|
||||
Address nodeAddr = node.getMaxAddress();
|
||||
// Decompiler only knows base space.
|
||||
// If reference came from an overlay space, convert address back
|
||||
if (refAddr.getAddressSpace().isOverlaySpace()) {
|
||||
nodeAddr = refAddr.getAddressSpace().getOverlayAddress(nodeAddr);
|
||||
}
|
||||
buff.append(" " + nodeAddr + " : ");
|
||||
}
|
||||
|
||||
buff.append(" " + toString(stmt));
|
||||
return true;
|
||||
//}
|
||||
}
|
||||
for (int j = 0; j < node.numChildren(); j++) {
|
||||
isCall = node instanceof ClangStatement;
|
||||
didStart |= printCall(refAddr, node.Child(j), buff, didStart, isCall);
|
||||
}
|
||||
return didStart;
|
||||
}
|
||||
buff.append(" " + toString(stmt));
|
||||
return true;
|
||||
//}
|
||||
}
|
||||
for (int j = 0; j < node.numChildren(); j++) {
|
||||
isCall = node instanceof ClangStatement;
|
||||
didStart |= printCall(refAddr, node.Child(j), buff, didStart, isCall);
|
||||
}
|
||||
return didStart;
|
||||
}
|
||||
|
||||
public String toString(ClangStatement node) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
int open=-1;
|
||||
for (int j = 0; j < node.numChildren(); j++) {
|
||||
ClangNode subNode = node.Child(j);
|
||||
if (subNode instanceof ClangSyntaxToken) {
|
||||
ClangSyntaxToken syntaxNode = (ClangSyntaxToken) subNode;
|
||||
if (syntaxNode.getOpen() != -1) {
|
||||
if (node.Child(j+2) instanceof ClangTypeToken) {
|
||||
open = syntaxNode.getOpen();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (syntaxNode.getClose() == open && open != -1) {
|
||||
open = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (open != -1) {
|
||||
continue;
|
||||
}
|
||||
buffer.append(subNode.toString());
|
||||
}
|
||||
return buffer.toString();
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
int open = -1;
|
||||
for (int j = 0; j < node.numChildren(); j++) {
|
||||
ClangNode subNode = node.Child(j);
|
||||
if (subNode instanceof ClangSyntaxToken) {
|
||||
ClangSyntaxToken syntaxNode = (ClangSyntaxToken) subNode;
|
||||
if (syntaxNode.getOpen() != -1) {
|
||||
if (node.Child(j + 2) instanceof ClangTypeToken) {
|
||||
open = syntaxNode.getOpen();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (syntaxNode.getClose() == open && open != -1) {
|
||||
open = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (open != -1) {
|
||||
continue;
|
||||
}
|
||||
buffer.append(subNode.toString());
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -254,8 +254,7 @@ public class ShowConstantUse extends GhidraScript {
|
||||
ConstUseLocation entry = (ConstUseLocation) rowObject;
|
||||
Function func = entry.getProgram()
|
||||
.getFunctionManager()
|
||||
.getFunctionContaining(
|
||||
entry.getAddress());
|
||||
.getFunctionContaining(entry.getAddress());
|
||||
if (func == null) {
|
||||
return "";
|
||||
}
|
||||
@@ -762,9 +761,7 @@ public class ShowConstantUse extends GhidraScript {
|
||||
if (defUseList == null || defUseList.size() <= 0) {
|
||||
return value;
|
||||
}
|
||||
Iterator<PcodeOp> iterator = defUseList.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
PcodeOp pcodeOp = iterator.next();
|
||||
for (PcodeOp pcodeOp : defUseList) {
|
||||
int opcode = pcodeOp.getOpcode();
|
||||
switch (opcode) {
|
||||
case PcodeOp.INT_AND:
|
||||
@@ -970,8 +967,7 @@ public class ShowConstantUse extends GhidraScript {
|
||||
}
|
||||
|
||||
private void followThroughGlobal(HashMap<Address, Long> constUse, ArrayList<PcodeOp> defUseList,
|
||||
HighVariable hvar,
|
||||
ArrayList<FunctionParamUse> funcList,
|
||||
HighVariable hvar, ArrayList<FunctionParamUse> funcList,
|
||||
HashSet<SequenceNumber> doneSet) {
|
||||
Address loc = hvar.getRepresentative().getAddress();
|
||||
PcodeOp def = hvar.getRepresentative().getDef();
|
||||
@@ -1013,6 +1009,7 @@ public class ShowConstantUse extends GhidraScript {
|
||||
private Address lastDecompiledFuncAddr = null;
|
||||
|
||||
private DecompInterface setUpDecompiler(Program program) {
|
||||
|
||||
DecompInterface decompInterface = new DecompInterface();
|
||||
|
||||
// call it to get results
|
||||
@@ -1021,13 +1018,8 @@ public class ShowConstantUse extends GhidraScript {
|
||||
return null;
|
||||
}
|
||||
|
||||
DecompileOptions options;
|
||||
options = new DecompileOptions();
|
||||
OptionsService service = state.getTool().getService(OptionsService.class);
|
||||
if (service != null) {
|
||||
ToolOptions opt = service.getOptions("Decompiler");
|
||||
options.grabFromToolAndProgram(null, opt, program);
|
||||
}
|
||||
DecompileOptions options = DecompilerUtils.getDecompileOptions(state.getTool(), program);
|
||||
|
||||
decompInterface.setOptions(options);
|
||||
|
||||
decompInterface.toggleCCode(true);
|
||||
|
||||
@@ -27,10 +27,11 @@
|
||||
//
|
||||
//@category Analysis
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.decompiler.*;
|
||||
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.PrototypeModel;
|
||||
@@ -39,10 +40,6 @@ import ghidra.program.model.pcode.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.exception.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import docking.options.OptionsService;
|
||||
|
||||
public class StringParameterPropagator extends GhidraScript {
|
||||
|
||||
// TODO!! Error handling needs a lot of work !!
|
||||
@@ -195,9 +192,10 @@ public class StringParameterPropagator extends GhidraScript {
|
||||
int maxParams = funcInfo.getMaxParamsSeen();
|
||||
boolean couldBeVararg = !funcInfo.numParamsAgree();
|
||||
if (!funcInfo.numParamsAgree()) {
|
||||
currentProgram.getBookmarkManager().setBookmark(calledFunc.getEntryPoint(),
|
||||
BookmarkType.NOTE, this.getClass().getName(),
|
||||
"Number of parameters disagree min: " + minParams + " max: " + maxParams);
|
||||
currentProgram.getBookmarkManager()
|
||||
.setBookmark(calledFunc.getEntryPoint(), BookmarkType.NOTE,
|
||||
this.getClass().getName(), "Number of parameters disagree min: " +
|
||||
minParams + " max: " + maxParams);
|
||||
|
||||
println("WARNING : Number of params disagree for " + calledFunc.getName() +
|
||||
" @ " + entry);
|
||||
@@ -317,9 +315,8 @@ public class StringParameterPropagator extends GhidraScript {
|
||||
ReferenceIterator dataRefIter = rData.getReferenceIteratorTo();
|
||||
while (dataRefIter.hasNext()) {
|
||||
Reference dataRef = dataRefIter.next();
|
||||
func =
|
||||
currentProgram.getFunctionManager().getFunctionContaining(
|
||||
dataRef.getFromAddress());
|
||||
func = currentProgram.getFunctionManager()
|
||||
.getFunctionContaining(dataRef.getFromAddress());
|
||||
if (func == null) {
|
||||
continue;
|
||||
}
|
||||
@@ -337,9 +334,8 @@ public class StringParameterPropagator extends GhidraScript {
|
||||
private void collectDataRefenceLocations(HashSet<Address> dataItemLocationSet,
|
||||
HashSet<Address> referringFuncLocationSet) {
|
||||
int count = 0;
|
||||
ReferenceIterator iter =
|
||||
currentProgram.getReferenceManager().getReferenceIterator(
|
||||
currentProgram.getMinAddress());
|
||||
ReferenceIterator iter = currentProgram.getReferenceManager()
|
||||
.getReferenceIterator(currentProgram.getMinAddress());
|
||||
while (iter.hasNext() && !monitor.isCancelled()) {
|
||||
Reference ref = iter.next();
|
||||
|
||||
@@ -412,7 +408,8 @@ public class StringParameterPropagator extends GhidraScript {
|
||||
if (convention == null) {
|
||||
convention = currentProgram.getCompilerSpec().getDefaultCallingConvention();
|
||||
}
|
||||
if (initialConvention != null && !convention.getName().equals(initialConvention.getName())) {
|
||||
if (initialConvention != null &&
|
||||
!convention.getName().equals(initialConvention.getName())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -452,8 +449,9 @@ public class StringParameterPropagator extends GhidraScript {
|
||||
if (param == null) {
|
||||
return false;
|
||||
}
|
||||
currentProgram.getBookmarkManager().setBookmark(func.getEntryPoint(), BookmarkType.NOTE,
|
||||
this.getClass().getName(), "Created " + dt.getName() + " parameter");
|
||||
currentProgram.getBookmarkManager()
|
||||
.setBookmark(func.getEntryPoint(), BookmarkType.NOTE, this.getClass().getName(),
|
||||
"Created " + dt.getName() + " parameter");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -497,9 +495,8 @@ public class StringParameterPropagator extends GhidraScript {
|
||||
if (i < f.getParameterCount()) {
|
||||
continue;
|
||||
}
|
||||
VariableStorage storage =
|
||||
convention.getArgLocation(i - 1, f.getParameters(), DataType.DEFAULT,
|
||||
currentProgram);
|
||||
VariableStorage storage = convention.getArgLocation(i - 1, f.getParameters(),
|
||||
DataType.DEFAULT, currentProgram);
|
||||
if (storage.isUnassignedStorage()) {
|
||||
break;
|
||||
}
|
||||
@@ -576,7 +573,8 @@ public class StringParameterPropagator extends GhidraScript {
|
||||
}
|
||||
|
||||
long mask =
|
||||
0xffffffffffffffffL >>> ((8 - entry.getAddressSpace().getPointerSize()) * 8);
|
||||
0xffffffffffffffffL >>> ((8 - entry.getAddressSpace().getPointerSize()) *
|
||||
8);
|
||||
Address possibleAddr = entry.getNewAddress(mask & value);
|
||||
if (stringLocationSet.contains(possibleAddr)) {
|
||||
markStringParam(constUse, possibleAddr, calledFuncAddr, i - 1,
|
||||
@@ -609,18 +607,11 @@ public class StringParameterPropagator extends GhidraScript {
|
||||
private Address lastDecompiledFuncAddr = null;
|
||||
|
||||
private DecompInterface setUpDecompiler(Program program) {
|
||||
|
||||
DecompileOptions options = DecompilerUtils.getDecompileOptions(state.getTool(), program);
|
||||
|
||||
DecompInterface decompInterface = new DecompInterface();
|
||||
|
||||
DecompileOptions options;
|
||||
options = new DecompileOptions();
|
||||
PluginTool tool = state.getTool();
|
||||
if (tool != null) {
|
||||
OptionsService service = tool.getService(OptionsService.class);
|
||||
if (service != null) {
|
||||
ToolOptions opt = service.getOptions("Decompiler");
|
||||
options.grabFromToolAndProgram(null, opt, program);
|
||||
}
|
||||
}
|
||||
decompInterface.setOptions(options);
|
||||
|
||||
decompInterface.toggleCCode(true);
|
||||
@@ -637,9 +628,8 @@ public class StringParameterPropagator extends GhidraScript {
|
||||
return true;
|
||||
|
||||
try {
|
||||
DecompileResults decompRes =
|
||||
decompInterface.decompileFunction(f,
|
||||
decompInterface.getOptions().getDefaultTimeout(), monitor);
|
||||
DecompileResults decompRes = decompInterface.decompileFunction(f,
|
||||
decompInterface.getOptions().getDefaultTimeout(), monitor);
|
||||
|
||||
hfunction = decompRes.getHighFunction();
|
||||
}
|
||||
|
||||
@@ -31,11 +31,9 @@ import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import docking.options.OptionsService;
|
||||
import ghidra.app.decompiler.*;
|
||||
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.pcode.*;
|
||||
@@ -55,7 +53,7 @@ public class WindowsResourceReference extends GhidraScript {
|
||||
ArrayList<ArrayList<PcodeOp>> defUseLists = new ArrayList<>();
|
||||
|
||||
protected AddressSetPropertyMap alreadyDoneAddressSetPropertyMap;
|
||||
|
||||
|
||||
// set of functions that decompilation failed on
|
||||
protected AddressSet badDecompFunctions = new AddressSet();
|
||||
|
||||
@@ -369,7 +367,7 @@ public class WindowsResourceReference extends GhidraScript {
|
||||
if (f == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// check if decompilation of this function failed previously
|
||||
if (badDecompFunctions.contains(f.getEntryPoint())) {
|
||||
return;
|
||||
@@ -462,13 +460,10 @@ public class WindowsResourceReference extends GhidraScript {
|
||||
private void addResourceReferences(HashMap<Address, Long> constLocs, String resourceName,
|
||||
boolean printScriptMsgs, boolean createBookmarks) throws CancelledException {
|
||||
Set<Address> keys;
|
||||
Iterator<Address> locIter;
|
||||
keys = constLocs.keySet();
|
||||
locIter = keys.iterator();
|
||||
while (locIter.hasNext()) {
|
||||
for (Address loc : keys) {
|
||||
monitor.checkCancelled();
|
||||
|
||||
Address loc = locIter.next();
|
||||
Instruction instr = currentProgram.getListing().getInstructionAt(loc);
|
||||
long rsrcID = constLocs.get(loc);
|
||||
Address rsrcAddr = findResource(resourceName + "_" + Long.toHexString(rsrcID), 0);
|
||||
@@ -488,9 +483,9 @@ public class WindowsResourceReference extends GhidraScript {
|
||||
|
||||
instr.addMnemonicReference(rsrcAddr, RefType.DATA, SourceType.ANALYSIS);
|
||||
if (createBookmarks) {
|
||||
currentProgram.getBookmarkManager().setBookmark(instr.getMinAddress(),
|
||||
BookmarkType.ANALYSIS, "WindowsResourceReference",
|
||||
"Added Resource Reference");
|
||||
currentProgram.getBookmarkManager()
|
||||
.setBookmark(instr.getMinAddress(), BookmarkType.ANALYSIS,
|
||||
"WindowsResourceReference", "Added Resource Reference");
|
||||
}
|
||||
if (printScriptMsgs) {
|
||||
println(" " + instr.getMinAddress().toString() + " : Found " + rsrcName +
|
||||
@@ -513,15 +508,13 @@ public class WindowsResourceReference extends GhidraScript {
|
||||
private void addResourceTableReferences(HashMap<Address, Long> constLocs, String tableName,
|
||||
boolean printScriptMsgs, boolean createBookmarks) throws CancelledException {
|
||||
Set<Address> keys;
|
||||
Iterator<Address> locIter;
|
||||
//Get the set of address locations which call the resource function
|
||||
keys = constLocs.keySet();
|
||||
locIter = keys.iterator();
|
||||
|
||||
//Iterate though the set of address locations
|
||||
while (locIter.hasNext()) {
|
||||
for (Address loc : keys) {
|
||||
monitor.checkCancelled();
|
||||
|
||||
Address loc = locIter.next();
|
||||
Instruction instr = currentProgram.getListing().getInstructionAt(loc);
|
||||
Long rsrcID = constLocs.get(loc);
|
||||
Address rsrcAddr = null;
|
||||
@@ -532,9 +525,9 @@ public class WindowsResourceReference extends GhidraScript {
|
||||
if (rsrcAddr != null) {
|
||||
instr.addMnemonicReference(rsrcAddr, RefType.DATA, SourceType.ANALYSIS);
|
||||
if (createBookmarks) {
|
||||
currentProgram.getBookmarkManager().setBookmark(instr.getMinAddress(),
|
||||
BookmarkType.ANALYSIS, "WindowsResourceReference",
|
||||
"Added Resource Table Reference");
|
||||
currentProgram.getBookmarkManager()
|
||||
.setBookmark(instr.getMinAddress(), BookmarkType.ANALYSIS,
|
||||
"WindowsResourceReference", "Added Resource Table Reference");
|
||||
}
|
||||
if (printScriptMsgs) {
|
||||
println(" " + instr.getMinAddress().toString() + " : Found " +
|
||||
@@ -622,9 +615,7 @@ public class WindowsResourceReference extends GhidraScript {
|
||||
if (defUseList == null || defUseList.size() <= 0) {
|
||||
return value;
|
||||
}
|
||||
Iterator<PcodeOp> iterator = defUseList.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
PcodeOp pcodeOp = iterator.next();
|
||||
for (PcodeOp pcodeOp : defUseList) {
|
||||
int opcode = pcodeOp.getOpcode();
|
||||
switch (opcode) {
|
||||
case PcodeOp.INT_AND:
|
||||
@@ -763,18 +754,11 @@ public class WindowsResourceReference extends GhidraScript {
|
||||
private Address lastDecompiledFuncAddr = null;
|
||||
|
||||
private DecompInterface setUpDecompiler(Program program) {
|
||||
|
||||
DecompileOptions options = DecompilerUtils.getDecompileOptions(state.getTool(), program);
|
||||
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
|
||||
DecompileOptions options;
|
||||
options = new DecompileOptions();
|
||||
PluginTool tool = state.getTool();
|
||||
if (tool != null) {
|
||||
OptionsService service = tool.getService(OptionsService.class);
|
||||
if (service != null) {
|
||||
ToolOptions opt = service.getOptions("Decompiler");
|
||||
options.grabFromToolAndProgram(null, opt, program);
|
||||
}
|
||||
}
|
||||
decompiler.setOptions(options);
|
||||
|
||||
decompiler.toggleCCode(true);
|
||||
|
||||
+12
-31
@@ -15,71 +15,55 @@
|
||||
*/
|
||||
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS.
|
||||
package classrecovery;
|
||||
|
||||
import docking.options.OptionsService;
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.decompiler.DecompileOptions;
|
||||
import ghidra.app.decompiler.DecompileResults;
|
||||
import ghidra.app.decompiler.*;
|
||||
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.ParameterDefinition;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.pcode.FunctionPrototype;
|
||||
import ghidra.program.model.pcode.HighFunction;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
import ghidra.program.model.pcode.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class DecompilerScriptUtils {
|
||||
|
||||
private Program program;
|
||||
private PluginTool tool;
|
||||
private ServiceProvider serviceProvider;
|
||||
private TaskMonitor monitor;
|
||||
|
||||
private DecompInterface decompInterface;
|
||||
|
||||
DecompilerScriptUtils(Program program, PluginTool tool, TaskMonitor monitor) {
|
||||
DecompilerScriptUtils(Program program, ServiceProvider serviceProvider, TaskMonitor monitor) {
|
||||
this.program = program;
|
||||
this.monitor = monitor;
|
||||
this.tool = tool;
|
||||
this.serviceProvider = serviceProvider;
|
||||
|
||||
decompInterface = setupDecompilerInterface();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to setup the decompiler interface for the given program
|
||||
* @return the interface to the decompiler
|
||||
* @return the interface to the decompiler or null if failed to open program
|
||||
*/
|
||||
public DecompInterface setupDecompilerInterface() {
|
||||
|
||||
decompInterface = new DecompInterface();
|
||||
|
||||
DecompileOptions options;
|
||||
options = new DecompileOptions();
|
||||
|
||||
if (tool == null) {
|
||||
options.grabFromProgram(program);
|
||||
}
|
||||
else {
|
||||
OptionsService service = tool.getService(OptionsService.class);
|
||||
if (service != null) {
|
||||
ToolOptions opt = service.getOptions("Decompiler");
|
||||
options.grabFromToolAndProgram(null, opt, program);
|
||||
}
|
||||
else {
|
||||
options.grabFromProgram(program);
|
||||
}
|
||||
}
|
||||
DecompileOptions options = DecompilerUtils.getDecompileOptions(serviceProvider, program);
|
||||
|
||||
decompInterface.setOptions(options);
|
||||
|
||||
decompInterface.toggleCCode(true);
|
||||
decompInterface.toggleSyntaxTree(true);
|
||||
decompInterface.setSimplificationStyle("decompile");
|
||||
|
||||
if (!decompInterface.openProgram(program)) {
|
||||
decompInterface.dispose();
|
||||
return null;
|
||||
}
|
||||
return decompInterface;
|
||||
@@ -90,7 +74,6 @@ public class DecompilerScriptUtils {
|
||||
return decompInterface;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method to decompile the given function and return the function's HighFunction
|
||||
* @param function the given function
|
||||
@@ -126,7 +109,6 @@ public class DecompilerScriptUtils {
|
||||
return decompRes.getHighFunction().getFunctionPrototype().getReturnType();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method to retrieve the function signature string from the decompiler function prototype. NOTE:
|
||||
* if there is a this param, it will not be included.
|
||||
@@ -153,7 +135,6 @@ public class DecompilerScriptUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
HighFunction highFunction = decompRes.getHighFunction();
|
||||
|
||||
FunctionPrototype functionPrototype = highFunction.getFunctionPrototype();
|
||||
|
||||
@@ -16,17 +16,17 @@
|
||||
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS.
|
||||
package classrecovery;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.NamespaceUtils;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.program.flatapi.FlatProgramAPI;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@@ -36,32 +36,21 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||
boolean programHasRTTIApplied = false;
|
||||
|
||||
String ghidraVersion;
|
||||
Program program;
|
||||
TaskMonitor monitor;
|
||||
|
||||
boolean hasDebugSymbols;
|
||||
|
||||
RTTIClassRecoverer(Program program, ServiceProvider serviceProvider, FlatProgramAPI api,
|
||||
boolean createBookmarks, boolean useShortTemplates, boolean nameVfunctions,
|
||||
boolean hasDebugSymbols, TaskMonitor monitor) throws Exception {
|
||||
|
||||
RTTIClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
|
||||
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
||||
boolean nameVfunctions, boolean hasDebugSymbols, TaskMonitor monitor) throws Exception {
|
||||
|
||||
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
|
||||
super(program, serviceProvider, api, createBookmarks, useShortTemplates, nameVfunctions,
|
||||
monitor);
|
||||
|
||||
this.program = program;
|
||||
this.monitor = monitor;
|
||||
this.location = location;
|
||||
this.tool = tool;
|
||||
this.api = api;
|
||||
this.createBookmarks = createBookmarks;
|
||||
this.useShortTemplates = useShortTemplates;
|
||||
this.nameVfunctions = nameVfunctions;
|
||||
this.hasDebugSymbols = hasDebugSymbols;
|
||||
|
||||
ghidraVersion = getVersionOfGhidra();
|
||||
}
|
||||
|
||||
|
||||
public DecompilerScriptUtils getDecompilerUtils() {
|
||||
return decompilerUtils;
|
||||
}
|
||||
@@ -100,21 +89,15 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||
return options.getString("Created With Ghidra Version", null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void fixUpProgram() throws CancelledException, Exception {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
public List<RecoveredClass> createRecoveredClasses() throws Exception {
|
||||
|
||||
return new ArrayList<RecoveredClass>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Method to promote the namespace is a class namespace.
|
||||
* @param namespace the namespace for the vftable
|
||||
@@ -123,18 +106,16 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||
*/
|
||||
public Namespace promoteToClassNamespace(Namespace namespace) throws InvalidInputException {
|
||||
|
||||
Namespace newClass = NamespaceUtils.convertNamespaceToClass(namespace);
|
||||
Namespace newClass = NamespaceUtils.convertNamespaceToClass(namespace);
|
||||
|
||||
SymbolType symbolType = newClass.getSymbol().getSymbolType();
|
||||
if (symbolType == SymbolType.CLASS) {
|
||||
return newClass;
|
||||
}
|
||||
Msg.debug(this,
|
||||
"Could not promote " + namespace.getName() + " to a class namespace");
|
||||
return null;
|
||||
SymbolType symbolType = newClass.getSymbol().getSymbolType();
|
||||
if (symbolType == SymbolType.CLASS) {
|
||||
return newClass;
|
||||
}
|
||||
Msg.debug(this, "Could not promote " + namespace.getName() + " to a class namespace");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method to iterate over all the RecoveredClass objects and see if there is an existing class structure data type already
|
||||
* if so, add it to the RecoveredClass object
|
||||
@@ -144,10 +125,8 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||
public void retrieveExistingClassStructures(List<RecoveredClass> recoveredClasses)
|
||||
throws CancelledException {
|
||||
|
||||
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
|
||||
while (recoveredClassIterator.hasNext()) {
|
||||
for (RecoveredClass recoveredClass : recoveredClasses) {
|
||||
monitor.checkCancelled();
|
||||
RecoveredClass recoveredClass = recoveredClassIterator.next();
|
||||
|
||||
// if class is non-virtual have to search for an existing class datatype
|
||||
|
||||
@@ -156,16 +135,16 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||
if (possibleExistingClassStructures.length == 0) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < possibleExistingClassStructures.length; i++) {
|
||||
for (DataType possibleExistingClassStructure : possibleExistingClassStructures) {
|
||||
monitor.checkCancelled();
|
||||
if (!(possibleExistingClassStructures[i] instanceof Structure)) {
|
||||
if (!(possibleExistingClassStructure instanceof Structure)) {
|
||||
continue;
|
||||
}
|
||||
if (possibleExistingClassStructures[i].isNotYetDefined()) {
|
||||
if (possibleExistingClassStructure.isNotYetDefined()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Structure existingClassStructure = (Structure) possibleExistingClassStructures[i];
|
||||
Structure existingClassStructure = (Structure) possibleExistingClassStructure;
|
||||
|
||||
recoveredClass.addExistingClassStructure(existingClassStructure);
|
||||
break;
|
||||
@@ -174,10 +153,8 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||
//Iterate over constructor/destructor functions
|
||||
List<Function> constructorOrDestructorFunctions =
|
||||
recoveredClass.getConstructorOrDestructorFunctions();
|
||||
Iterator<Function> constDestIterator = constructorOrDestructorFunctions.iterator();
|
||||
while (constDestIterator.hasNext()) {
|
||||
for (Function constDestFunction : constructorOrDestructorFunctions) {
|
||||
monitor.checkCancelled();
|
||||
Function constDestFunction = constDestIterator.next();
|
||||
Namespace parentNamespace = constDestFunction.getParentNamespace();
|
||||
if (!parentNamespace.equals(recoveredClass.getClassNamespace())) {
|
||||
continue;
|
||||
@@ -220,8 +197,6 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Method to get class data information from destructors if a class has no constructors
|
||||
* @param recoveredClasses list of classes
|
||||
@@ -234,11 +209,8 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||
throws CancelledException, DuplicateNameException, InvalidInputException,
|
||||
CircularDependencyException {
|
||||
|
||||
Iterator<RecoveredClass> classIterator = recoveredClasses.iterator();
|
||||
while (classIterator.hasNext()) {
|
||||
for (RecoveredClass recoveredClass : recoveredClasses) {
|
||||
monitor.checkCancelled();
|
||||
RecoveredClass recoveredClass = classIterator.next();
|
||||
|
||||
// we can only figure out structure info for functions with vftable since that is
|
||||
// what we use to determine which variable is being used to store the class structure
|
||||
if (!recoveredClass.hasVftable()) {
|
||||
@@ -257,11 +229,8 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||
memberFunctionsToProcess.addAll(recoveredClass.getIndeterminateList());
|
||||
memberFunctionsToProcess.addAll(recoveredClass.getInlinedConstructorList());
|
||||
|
||||
Iterator<Function> memberFunctionIterator = memberFunctionsToProcess.iterator();
|
||||
while (memberFunctionIterator.hasNext()) {
|
||||
for (Function memberFunction : memberFunctionsToProcess) {
|
||||
monitor.checkCancelled();
|
||||
Function memberFunction = memberFunctionIterator.next();
|
||||
|
||||
if (getVftableReferences(memberFunction) == null) {
|
||||
continue;
|
||||
}
|
||||
@@ -278,9 +247,4 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+111
-236
File diff suppressed because it is too large
Load Diff
+106
-196
File diff suppressed because it is too large
Load Diff
+227
-551
File diff suppressed because it is too large
Load Diff
@@ -776,22 +776,18 @@ public class DecompInterface {
|
||||
public synchronized DecompileResults decompileFunction(Function func, int timeoutSecs,
|
||||
TaskMonitor monitor) {
|
||||
|
||||
dtmanage.clearTemporaryIds();
|
||||
decompileMessage = "";
|
||||
if (monitor != null && monitor.isCancelled()) {
|
||||
return null;
|
||||
|
||||
if (program == null || (monitor != null && monitor.isCancelled())) {
|
||||
return new DecompileResults(func, pcodelanguage, compilerSpec, dtmanage,
|
||||
decompileMessage, null, DecompileProcess.DisposeState.DISPOSED_ON_CANCEL);
|
||||
}
|
||||
|
||||
if (monitor != null) {
|
||||
monitor.addCancelledListener(monitorListener);
|
||||
}
|
||||
|
||||
dtmanage.clearTemporaryIds();
|
||||
|
||||
if (program == null) {
|
||||
return new DecompileResults(func, pcodelanguage, null, dtmanage, decompileMessage, null,
|
||||
DecompileProcess.DisposeState.DISPOSED_ON_CANCEL);
|
||||
}
|
||||
|
||||
Decoder decoder = null;
|
||||
try {
|
||||
Address funcEntry = func.getEntryPoint();
|
||||
|
||||
+81
-2
@@ -17,18 +17,78 @@ package ghidra.app.decompiler.component;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import docking.options.OptionsService;
|
||||
import docking.widgets.fieldpanel.field.Field;
|
||||
import docking.widgets.fieldpanel.support.*;
|
||||
import ghidra.app.decompiler.*;
|
||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.data.MetaDataType;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.pcode.*;
|
||||
|
||||
public class DecompilerUtils {
|
||||
|
||||
/**
|
||||
* Gaither decompiler options from tool and program. If tool is null or does not provide
|
||||
* a {@link OptionsService} provider only options stored within the program will be consumed.
|
||||
* @param serviceProvider plugin tool or service provider providing access to {@link OptionsService}
|
||||
* @param program program
|
||||
* @return decompiler options
|
||||
*/
|
||||
public static DecompileOptions getDecompileOptions(ServiceProvider serviceProvider,
|
||||
Program program) {
|
||||
DecompileOptions options;
|
||||
options = new DecompileOptions();
|
||||
OptionsService service = null;
|
||||
if (serviceProvider != null) {
|
||||
service = serviceProvider.getService(OptionsService.class);
|
||||
}
|
||||
if (service != null) {
|
||||
ToolOptions opt = service.getOptions("Decompiler");
|
||||
options.grabFromToolAndProgram(null, opt, program);
|
||||
}
|
||||
else {
|
||||
options.grabFromProgram(program);
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data-type associated with a Varnode. If the Varnode is input to a CAST p-code
|
||||
* op, take the most specific data-type between what it was cast from and cast to.
|
||||
* @param vn is the Varnode to get the data-type for
|
||||
* @return the data-type
|
||||
*/
|
||||
public static DataType getDataTypeTraceForward(Varnode vn) {
|
||||
DataType res = vn.getHigh().getDataType();
|
||||
PcodeOp op = vn.getLoneDescend();
|
||||
if (op != null && op.getOpcode() == PcodeOp.CAST) {
|
||||
Varnode otherVn = op.getOutput();
|
||||
res = MetaDataType.getMostSpecificDataType(res, otherVn.getHigh().getDataType());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data-type associated with a Varnode. If the Varnode is produce by a CAST p-code
|
||||
* op, take the most specific data-type between what it was cast from and cast to.
|
||||
* @param vn is the Varnode to get the data-type for
|
||||
* @return the data-type
|
||||
*/
|
||||
public static DataType getDataTypeTraceBackward(Varnode vn) {
|
||||
DataType res = vn.getHigh().getDataType();
|
||||
PcodeOp op = vn.getDef();
|
||||
if (op != null && op.getOpcode() == PcodeOp.CAST) {
|
||||
Varnode otherVn = op.getInput(0);
|
||||
res = MetaDataType.getMostSpecificDataType(res, otherVn.getHigh().getDataType());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the token refers to an individual Varnode, return it. Otherwise return null
|
||||
*
|
||||
@@ -214,6 +274,25 @@ public class DecompilerUtils {
|
||||
return pcodeops;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test specified variable to see if it corresponds to the auto {@code this} parameter
|
||||
* of the specified {@link Function}
|
||||
* @param var decompiler {@link HighVariable variable}
|
||||
* @param function decompiled function
|
||||
* @return true if {@code var} corresponds to existing auto {@code this} parameter, else false
|
||||
*/
|
||||
public static boolean testForAutoParameterThis(HighVariable var, Function function) {
|
||||
if (var instanceof HighParam) {
|
||||
int slot = ((HighParam) var).getSlot();
|
||||
Parameter parameter = function.getParameter(slot);
|
||||
if ((parameter != null) &&
|
||||
(parameter.getAutoParameterType() == AutoParameterType.THIS)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the function represented by the given token. This will be either the
|
||||
* decompiled function or a function referenced within the decompiled function.
|
||||
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
/* ###
|
||||
* 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.decompiler.util;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import ghidra.app.decompiler.*;
|
||||
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||
import ghidra.framework.cmd.BackgroundCommand;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.pcode.*;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.util.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Automatically creates a structure definition based on the references found by the decompiler.
|
||||
*
|
||||
* If the parameter is already a structure pointer, any new references found will be added
|
||||
* to the structure, even if the structure must grow.
|
||||
*
|
||||
*/
|
||||
public class FillOutStructureCmd extends BackgroundCommand<Program> {
|
||||
|
||||
private DecompileOptions decompileOptions;
|
||||
private ProgramLocation location;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param location the current program location. Supported location types include:
|
||||
* {@link DecompilerLocation}, {@link VariableLocation} or
|
||||
* {@link FunctionParameterFieldLocation}.
|
||||
* @param decompileOptions decompiler options.
|
||||
* (see {@link DecompilerUtils#getDecompileOptions(ServiceProvider, Program)})
|
||||
*/
|
||||
public FillOutStructureCmd(ProgramLocation location, DecompileOptions decompileOptions) {
|
||||
super("Fill Out Structure", true, false, true);
|
||||
this.decompileOptions = Objects.requireNonNull(decompileOptions);
|
||||
this.location = Objects.requireNonNull(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyTo(Program program, TaskMonitor monitor) {
|
||||
|
||||
if (program != location.getProgram()) {
|
||||
throw new AssertionError("program does not match location");
|
||||
}
|
||||
|
||||
try {
|
||||
Function function =
|
||||
program.getFunctionManager().getFunctionContaining(location.getAddress());
|
||||
if (function == null) {
|
||||
setStatusMsg("Function not found at " + location.getAddress());
|
||||
return false;
|
||||
}
|
||||
|
||||
FillOutStructureHelper fillStructureHelper =
|
||||
new FillOutStructureHelper(program, decompileOptions, monitor);
|
||||
|
||||
HighVariable var = null;
|
||||
|
||||
if (!(location instanceof DecompilerLocation dloc)) {
|
||||
// if we don't have one, make one, and map variable to a varnode
|
||||
Address storageAddr = computeStorageAddress(function);
|
||||
var = fillStructureHelper.computeHighVariable(storageAddr, function);
|
||||
}
|
||||
else {
|
||||
|
||||
// get the Varnode under the cursor
|
||||
ClangToken token = dloc.getToken();
|
||||
if (token == null) {
|
||||
setStatusMsg("Unable to identify variable from decompiler token");
|
||||
return false;
|
||||
}
|
||||
|
||||
var = token.getHighVariable();
|
||||
Varnode exactSpot = token.getVarnode();
|
||||
|
||||
if ((var != null) && (exactSpot != null)) {
|
||||
HighFunction hfunc = var.getHighFunction();
|
||||
try { // Adjust HighVariable based on exact varnode selected, if there are merged groups
|
||||
var = hfunc.splitOutMergeGroup(var, exactSpot);
|
||||
}
|
||||
catch (PcodeException ex) {
|
||||
setStatusMsg("Unable to isolate variable from merged group");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Structure structDT = fillStructureHelper.processStructure(var, function, false, true);
|
||||
if (structDT == null) {
|
||||
setStatusMsg("Failed to fill-out structure");
|
||||
return false;
|
||||
}
|
||||
|
||||
DataType pointerDT = new PointerDataType(structDT);
|
||||
|
||||
// Delay adding to the manager until full structure is accumulated
|
||||
pointerDT = program.getDataTypeManager()
|
||||
.addDataType(pointerDT, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
|
||||
boolean isThisParam = DecompilerUtils.testForAutoParameterThis(var, function);
|
||||
if (!isThisParam) {
|
||||
commitVariable(var, pointerDT, isThisParam);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.showError(this, null, "Auto Create Structure Failed",
|
||||
"Failed to create Structure variable", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retype the HighVariable to a given data-type to the database
|
||||
* @param var is the decompiler variable to retype
|
||||
* @param newDt is the data-type
|
||||
* @param isThisParam is true if the variable is a 'this' pointer
|
||||
*/
|
||||
private void commitVariable(HighVariable var, DataType newDt, boolean isThisParam) {
|
||||
if (!isThisParam) {
|
||||
try {
|
||||
HighFunctionDBUtil.updateDBVariable(var.getSymbol(), null, newDt,
|
||||
SourceType.USER_DEFINED);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
throw new AssertException("Unexpected exception", e);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.error(this,
|
||||
"Failed to re-type variable " + var.getName() + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the storage address associated with a particular Location
|
||||
* @param function is the function owning the location
|
||||
* @return the corresponding storage address or null
|
||||
*/
|
||||
private Address computeStorageAddress(Function function) {
|
||||
|
||||
Address storageAddress = null;
|
||||
|
||||
// make sure what we are over can be mapped to decompiler
|
||||
// param, local, etc...
|
||||
|
||||
if (location instanceof VariableLocation) {
|
||||
VariableLocation varLoc = (VariableLocation) location;
|
||||
storageAddress = varLoc.getVariable().getVariableStorage().getMinAddress();
|
||||
}
|
||||
else if (location instanceof FunctionParameterFieldLocation) {
|
||||
FunctionParameterFieldLocation funcPFL = (FunctionParameterFieldLocation) location;
|
||||
storageAddress = funcPFL.getParameter().getVariableStorage().getMinAddress();
|
||||
}
|
||||
return storageAddress;
|
||||
}
|
||||
|
||||
}
|
||||
+192
-295
File diff suppressed because it is too large
Load Diff
+10
-47
@@ -21,14 +21,16 @@ import java.awt.event.KeyEvent;
|
||||
import docking.ActionContext;
|
||||
import docking.action.*;
|
||||
import ghidra.app.context.ListingActionContext;
|
||||
import ghidra.app.decompiler.DecompileOptions;
|
||||
import ghidra.app.decompiler.component.DecompilerController;
|
||||
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||
import ghidra.app.decompiler.util.FillOutStructureCmd;
|
||||
import ghidra.app.decompiler.util.FillOutStructureHelper;
|
||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||
import ghidra.app.util.HelpTopics;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.pcode.HighParam;
|
||||
import ghidra.program.model.pcode.HighVariable;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.Msg;
|
||||
@@ -47,46 +49,6 @@ public abstract class CreateStructureVariableAction extends DockingAction {
|
||||
setKeyBindingData(new KeyBindingData(KeyEvent.VK_OPEN_BRACKET, InputEvent.SHIFT_DOWN_MASK));
|
||||
}
|
||||
|
||||
static boolean testForAutoParameterThis(HighVariable var, Function f) {
|
||||
if (var instanceof HighParam) {
|
||||
int slot = ((HighParam) var).getSlot();
|
||||
Parameter parameter = f.getParameter(slot);
|
||||
if ((parameter != null) &&
|
||||
(parameter.getAutoParameterType() == AutoParameterType.THIS)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a variable has a data-type that is suitable for being extended.
|
||||
* If so return the structure data-type, otherwise return null.
|
||||
* Modulo typedefs, the data-type of the variable must be exactly a
|
||||
* "pointer to a structure". Not a "structure" itself, or a
|
||||
* "pointer to a pointer to ... a structure".
|
||||
* @param dt is the data-type of the variable to test
|
||||
* @return the extendable structure data-type or null
|
||||
*/
|
||||
public static Structure getStructureForExtending(DataType dt) {
|
||||
if (dt instanceof TypeDef) {
|
||||
dt = ((TypeDef) dt).getBaseDataType();
|
||||
}
|
||||
if (dt instanceof Pointer) {
|
||||
dt = ((Pointer) dt).getDataType();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
if (dt instanceof TypeDef) {
|
||||
dt = ((TypeDef) dt).getBaseDataType();
|
||||
}
|
||||
if (dt instanceof Structure) {
|
||||
return (Structure) dt;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract boolean isEnabledForContext(ActionContext context);
|
||||
|
||||
@@ -98,7 +60,7 @@ public abstract class CreateStructureVariableAction extends DockingAction {
|
||||
*/
|
||||
protected void adjustCreateStructureMenuText(DataType dt, boolean isThisParam) {
|
||||
|
||||
dt = getStructureForExtending(dt);
|
||||
dt = FillOutStructureHelper.getStructureForExtending(dt);
|
||||
String menuString = "Auto Create Structure";
|
||||
if (dt != null) {
|
||||
if (isThisParam) {
|
||||
@@ -145,7 +107,8 @@ public abstract class CreateStructureVariableAction extends DockingAction {
|
||||
return;
|
||||
}
|
||||
|
||||
FillOutStructureCmd task = new FillOutStructureCmd(program, location, tool);
|
||||
task.applyTo(program);
|
||||
DecompileOptions decompileOptions = DecompilerUtils.getDecompileOptions(tool, program);
|
||||
FillOutStructureCmd cmd = new FillOutStructureCmd(location, decompileOptions);
|
||||
tool.executeBackgroundCommand(cmd, program);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -17,8 +17,7 @@ package ghidra.app.plugin.core.decompile.actions;
|
||||
|
||||
import docking.ActionContext;
|
||||
import ghidra.app.decompiler.ClangToken;
|
||||
import ghidra.app.decompiler.component.DecompilerController;
|
||||
import ghidra.app.decompiler.component.DecompilerPanel;
|
||||
import ghidra.app.decompiler.component.*;
|
||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.data.DataType;
|
||||
@@ -62,7 +61,7 @@ public class DecompilerStructureVariableAction extends CreateStructureVariableAc
|
||||
HighVariable var = tokenAtCursor.getHighVariable();
|
||||
if (var != null && !(var instanceof HighConstant)) {
|
||||
dt = var.getDataType();
|
||||
isThisParam = testForAutoParameterThis(var, function);
|
||||
isThisParam = DecompilerUtils.testForAutoParameterThis(var, function);
|
||||
}
|
||||
|
||||
if (dt == null || dt.getLength() > maxPointerSize) {
|
||||
|
||||
@@ -20,18 +20,16 @@ import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.options.OptionsService;
|
||||
import generic.cache.CachingPool;
|
||||
import generic.cache.CountingBasicFactory;
|
||||
import generic.concurrent.QCallback;
|
||||
import ghidra.GhidraOptions;
|
||||
import ghidra.app.decompiler.*;
|
||||
import ghidra.app.decompiler.DecompileOptions.CommentStyleEnum;
|
||||
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||
import ghidra.app.decompiler.parallel.ChunkingParallelDecompiler;
|
||||
import ghidra.app.decompiler.parallel.ParallelDecompiler;
|
||||
import ghidra.app.util.*;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.data.*;
|
||||
@@ -245,20 +243,8 @@ public class CppExporter extends Exporter {
|
||||
|
||||
private void configureOptions(Program program) {
|
||||
if (!userSuppliedOptions) {
|
||||
options = new DecompileOptions();
|
||||
|
||||
if (provider != null) {
|
||||
OptionsService service = provider.getService(OptionsService.class);
|
||||
if (service != null) {
|
||||
ToolOptions fieldOptions =
|
||||
service.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
|
||||
ToolOptions opt = service.getOptions("Decompiler");
|
||||
options.grabFromToolAndProgram(fieldOptions, opt, program);
|
||||
}
|
||||
}
|
||||
else {
|
||||
options.grabFromProgram(program); // Let headless pull program specific options
|
||||
}
|
||||
options = DecompilerUtils.getDecompileOptions(provider, program);
|
||||
|
||||
if (isUseCppStyleComments) {
|
||||
options.setCommentStyle(CommentStyleEnum.CPPStyle);
|
||||
|
||||
+10
-15
@@ -27,7 +27,6 @@ import ghidra.app.util.pdb.pdbapplicator.DefaultPdbApplicator;
|
||||
import ghidra.app.util.pdb.pdbapplicator.PdbApplicatorOptions;
|
||||
import ghidra.framework.*;
|
||||
import ghidra.framework.cmd.BackgroundCommand;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.framework.options.OptionType;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
@@ -192,9 +191,8 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||
* @throws CancelledException upon user cancellation
|
||||
*/
|
||||
public static boolean doAnalysis(Program program, File pdbFile,
|
||||
PdbReaderOptions pdbReaderOptions,
|
||||
PdbApplicatorOptions pdbApplicatorOptions, MessageLog log, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
PdbReaderOptions pdbReaderOptions, PdbApplicatorOptions pdbApplicatorOptions,
|
||||
MessageLog log, TaskMonitor monitor) throws CancelledException {
|
||||
PdbLog.message(
|
||||
"================================================================================");
|
||||
PdbLog.message(new Date(System.currentTimeMillis()).toString() + "\n");
|
||||
@@ -236,8 +234,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||
AnalysisPriority.DATA_TYPE_PROPOGATION.after().after().after().priority());
|
||||
|
||||
// Following is intended to be the last PDB analysis background command
|
||||
aam.schedule(
|
||||
new PdbReportingBackgroundCommand(),
|
||||
aam.schedule(new PdbReportingBackgroundCommand(),
|
||||
AnalysisPriority.DATA_TYPE_PROPOGATION.after().after().after().after().priority());
|
||||
|
||||
}
|
||||
@@ -340,7 +337,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||
* local variables and other things that might make sense to process in the first phase
|
||||
* (for now, they will be in the second phase).
|
||||
*/
|
||||
private static class ProcessPdbFunctionInternalsCommand extends BackgroundCommand {
|
||||
private static class ProcessPdbFunctionInternalsCommand extends BackgroundCommand<Program> {
|
||||
|
||||
File pdbFile;
|
||||
private PdbReaderOptions pdbReaderOptions;
|
||||
@@ -357,14 +354,13 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
|
||||
Program program = (Program) obj;
|
||||
public boolean applyTo(Program program, TaskMonitor monitor) {
|
||||
try (AbstractPdb pdb = PdbParser.parse(pdbFile, pdbReaderOptions, monitor)) {
|
||||
monitor.setMessage("PDB: Parsing " + pdbFile + "...");
|
||||
pdb.deserialize();
|
||||
DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdb, program,
|
||||
program.getDataTypeManager(), program.getImageBase(), pdbApplicatorOptions,
|
||||
log);
|
||||
DefaultPdbApplicator applicator =
|
||||
new DefaultPdbApplicator(pdb, program, program.getDataTypeManager(),
|
||||
program.getImageBase(), pdbApplicatorOptions, log);
|
||||
applicator.applyFunctionInternalsAnalysis();
|
||||
return true;
|
||||
}
|
||||
@@ -382,15 +378,14 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||
/**
|
||||
* A background command that performs final PDB analysis reporting.
|
||||
*/
|
||||
private static class PdbReportingBackgroundCommand extends BackgroundCommand {
|
||||
private static class PdbReportingBackgroundCommand extends BackgroundCommand<Program> {
|
||||
|
||||
public PdbReportingBackgroundCommand() {
|
||||
super("PDB Universal Reporting", false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
|
||||
Program program = (Program) obj;
|
||||
public boolean applyTo(Program program, TaskMonitor monitor) {
|
||||
try {
|
||||
DefaultPdbApplicator.applyAnalysisReporting(program);
|
||||
return true;
|
||||
|
||||
+15
-25
@@ -16,11 +16,15 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.diff;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import docking.widgets.dialogs.ReadTextDialog;
|
||||
import ghidra.app.events.ProgramSelectionPluginEvent;
|
||||
import ghidra.app.plugin.core.analysis.AnalysisWorker;
|
||||
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
|
||||
import ghidra.framework.cmd.BackgroundCommand;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
@@ -28,17 +32,11 @@ import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import docking.widgets.dialogs.ReadTextDialog;
|
||||
|
||||
/**
|
||||
* Command to apply diffs to current program.
|
||||
*
|
||||
*/
|
||||
class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
|
||||
class ApplyDiffCommand extends BackgroundCommand<Program> implements AnalysisWorker {
|
||||
|
||||
private AddressSetView p1AddressSet;
|
||||
private DiffController diffControl;
|
||||
@@ -47,9 +45,6 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
|
||||
private boolean applied;
|
||||
private ProgramDiffPlugin plugin;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
ApplyDiffCommand(ProgramDiffPlugin plugin, AddressSetView program1AddressSet,
|
||||
DiffController diffControl) {
|
||||
super("Apply Differences", false, true, true);
|
||||
@@ -59,8 +54,8 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean analysisWorkerCallback(Program program, Object workerContext, TaskMonitor monitor)
|
||||
throws Exception, CancelledException {
|
||||
public boolean analysisWorkerCallback(Program program, Object workerContext,
|
||||
TaskMonitor monitor) throws Exception, CancelledException {
|
||||
// Diff apply done with analysis disabled
|
||||
return diffControl.apply(p1AddressSet, monitor);
|
||||
}
|
||||
@@ -70,11 +65,8 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
|
||||
return getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.framework.cmd.BackgroundCommand#applyTo(ghidra.framework.model.DomainObject, ghidra.util.task.TaskMonitor)
|
||||
*/
|
||||
@Override
|
||||
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
|
||||
public boolean applyTo(Program program, TaskMonitor monitor) {
|
||||
monitor.setMessage("ApplyDiffTask starting...");
|
||||
applied = false;
|
||||
final ProgramLocation origLocation = plugin.getProgramLocation();
|
||||
@@ -90,9 +82,8 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
|
||||
AutoAnalysisManager.getAnalysisManager(plugin.getFirstProgram());
|
||||
boolean merged = autoAnalysisManager.scheduleWorker(this, null, false, monitor);
|
||||
if (merged) {
|
||||
statusMsg =
|
||||
"Apply differences has finished."
|
||||
+ " If your expected change didn't occur, check your Diff Apply Settings.";
|
||||
statusMsg = "Apply differences has finished." +
|
||||
" If your expected change didn't occur, check your Diff Apply Settings.";
|
||||
title = "Program Diff: Apply differences has finished.";
|
||||
applied = true;
|
||||
}
|
||||
@@ -114,15 +105,14 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
|
||||
}
|
||||
}
|
||||
Msg.showError(this, plugin.getListingPanel(), "Error Applying Diff",
|
||||
"An error occurred while applying differences.\n"
|
||||
+ "Only some of the differences may have been applied.",
|
||||
"An error occurred while applying differences.\n" +
|
||||
"Only some of the differences may have been applied.",
|
||||
(t != null) ? t : e);
|
||||
applyMsg = message + diffControl.getApplyMessage();
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
statusMsg =
|
||||
"User cancelled \"Apply Differences\". "
|
||||
+ "Differences were only partially applied.";
|
||||
statusMsg = "User cancelled \"Apply Differences\". " +
|
||||
"Differences were only partially applied.";
|
||||
applyMsg = diffControl.getApplyMessage();
|
||||
}
|
||||
finally {
|
||||
|
||||
Reference in New Issue
Block a user