From 624a3c4e9e9e55db903296eba544fa696cc1ecaf Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Wed, 3 Apr 2024 09:53:53 -0400 Subject: [PATCH] GP-4408 Refactor of FillOutStructureCmd. Added FillOutStructureHelper and additional DecompilerUtils methods. --- .../core/analysis/AutoAnalysisManager.java | 19 +- .../AutoTableDisassemblerPlugin.java | 28 +- .../app/plugin/core/equate/EquatePlugin.java | 15 +- ...yClassFunctionDefinitionUpdatesScript.java | 4 +- ...lyClassFunctionSignatureUpdatesScript.java | 25 +- .../ghidra_scripts/CreateStructure.java | 26 +- .../RecoverClassesFromRTTIScript.java | 21 +- .../ghidra_scripts/ShowCCallsScript.java | 362 ++++---- .../ghidra_scripts/ShowConstantUse.java | 20 +- .../StringParameterPropagator.java | 60 +- .../WindowsResourceReference.java | 48 +- .../classrecovery/DecompilerScriptUtils.java | 43 +- .../classrecovery/RTTIClassRecoverer.java | 82 +- .../classrecovery/RTTIGccClassRecoverer.java | 347 +++----- .../RTTIWindowsClassRecoverer.java | 302 +++---- .../classrecovery/RecoveredClassHelper.java | 778 +++++------------- .../app/decompiler/DecompInterface.java | 14 +- .../decompiler/component/DecompilerUtils.java | 83 +- .../decompiler/util/FillOutStructureCmd.java | 182 ++++ .../util/FillOutStructureHelper.java} | 487 +++++------ .../CreateStructureVariableAction.java | 57 +- .../DecompilerStructureVariableAction.java | 5 +- .../ghidra/app/util/exporter/CppExporter.java | 18 +- .../core/analysis/PdbUniversalAnalyzer.java | 25 +- .../plugin/core/diff/ApplyDiffCommand.java | 40 +- 25 files changed, 1281 insertions(+), 1810 deletions(-) create mode 100644 Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/util/FillOutStructureCmd.java rename Ghidra/Features/Decompiler/src/main/java/ghidra/app/{plugin/core/decompile/actions/FillOutStructureCmd.java => decompiler/util/FillOutStructureHelper.java} (60%) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AutoAnalysisManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AutoAnalysisManager.java index 1a0b51c6e7..f526125903 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AutoAnalysisManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AutoAnalysisManager.java @@ -108,7 +108,7 @@ public class AutoAnalysisManager { //private Integer currentTaskPriority = null; //private Stack taskPriorityStack = new Stack(); - private PriorityQueue queue = new PriorityQueue<>(); + private PriorityQueue> queue = new PriorityQueue<>(); private Map timedTasks = new HashMap<>(); // used for testing and performance monitoring; accessed via reflection private Map 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 task; Integer taskPriority; private long timeAccumulator; private long startTime; - AnalysisTaskWrapper(BackgroundCommand task, int taskPriority) { + AnalysisTaskWrapper(BackgroundCommand 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 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 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 + 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()) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AutoTableDisassemblerPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AutoTableDisassemblerPlugin.java index 80a720cc64..5814b1deb2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AutoTableDisassemblerPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AutoTableDisassemblerPlugin.java @@ -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 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 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); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/EquatePlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/EquatePlugin.java index 19f9ee5d35..8a535920ec 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/EquatePlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/EquatePlugin.java @@ -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 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 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 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 bckCmd, CodeUnit cu) { // A code unit can be either an instruction or data; we need to handle each // separately. if (cu instanceof Instruction) { diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionDefinitionUpdatesScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionDefinitionUpdatesScript.java index 6cee69dfc7..bbfe26013e 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionDefinitionUpdatesScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionDefinitionUpdatesScript.java @@ -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 selectedDatatypes = dtms.getSelectedDatatypes(); diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionSignatureUpdatesScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionSignatureUpdatesScript.java index d904d1f96d..22cd12c5ab 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionSignatureUpdatesScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionSignatureUpdatesScript.java @@ -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 { } - } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/CreateStructure.java b/Ghidra/Features/Decompiler/ghidra_scripts/CreateStructure.java index adf00d2602..dca343b96a 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/CreateStructure.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/CreateStructure.java @@ -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); + } } } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java index 40166304b8..8b25e52ac3 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java @@ -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"); diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/ShowCCallsScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/ShowCCallsScript.java index 1761f4533e..e004b7b139 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/ShowCCallsScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/ShowCCallsScript.java @@ -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 getPcodeOps(Address refAddr) { + if (hfunction == null) { + return null; + } + Iterator 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 getPcodeOps(Address refAddr) { - if (hfunction == null) { - return null; - } - Iterator 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(); } } - diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/ShowConstantUse.java b/Ghidra/Features/Decompiler/ghidra_scripts/ShowConstantUse.java index bbcd7198d9..ebfc4f0ff2 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/ShowConstantUse.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/ShowConstantUse.java @@ -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 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 constUse, ArrayList defUseList, - HighVariable hvar, - ArrayList funcList, + HighVariable hvar, ArrayList funcList, HashSet 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); diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/StringParameterPropagator.java b/Ghidra/Features/Decompiler/ghidra_scripts/StringParameterPropagator.java index 1cadb8e6df..070d1fdcff 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/StringParameterPropagator.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/StringParameterPropagator.java @@ -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
dataItemLocationSet, HashSet
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(); } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/WindowsResourceReference.java b/Ghidra/Features/Decompiler/ghidra_scripts/WindowsResourceReference.java index fcdd801561..e54e418390 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/WindowsResourceReference.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/WindowsResourceReference.java @@ -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> 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 constLocs, String resourceName, boolean printScriptMsgs, boolean createBookmarks) throws CancelledException { Set
keys; - Iterator
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 constLocs, String tableName, boolean printScriptMsgs, boolean createBookmarks) throws CancelledException { Set
keys; - Iterator
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 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); diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/DecompilerScriptUtils.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/DecompilerScriptUtils.java index b6356ccb39..2cc9ca3d51 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/DecompilerScriptUtils.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/DecompilerScriptUtils.java @@ -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(); diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java index 094fe04463..0989b189a9 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java @@ -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 createRecoveredClasses() throws Exception { return new ArrayList(); } - - - /** * 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 recoveredClasses) throws CancelledException { - Iterator 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 constructorOrDestructorFunctions = recoveredClass.getConstructorOrDestructorFunctions(); - Iterator 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 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 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 { } } - - - - - } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java index cf2a16d977..e14a589395 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java @@ -17,84 +17,28 @@ package classrecovery; import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import ghidra.app.cmd.label.DemanglerCmd; import ghidra.app.plugin.core.analysis.ReferenceAddressPair; import ghidra.app.util.NamespaceUtils; import ghidra.app.util.demangler.DemangledObject; import ghidra.app.util.demangler.DemanglerUtil; -import ghidra.framework.plugintool.PluginTool; +import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.flatapi.FlatProgramAPI; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressIterator; -import ghidra.program.model.address.AddressOutOfBoundsException; -import ghidra.program.model.address.AddressRange; -import ghidra.program.model.address.AddressRangeIterator; -import ghidra.program.model.address.AddressSet; -import ghidra.program.model.address.AddressSetView; -import ghidra.program.model.data.ArrayDataType; -import ghidra.program.model.data.CategoryPath; -import ghidra.program.model.data.CharDataType; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.DataTypeComponent; -import ghidra.program.model.data.DataTypeConflictHandler; -import ghidra.program.model.data.DataUtilities; +import ghidra.program.model.address.*; +import ghidra.program.model.data.*; import ghidra.program.model.data.DataUtilities.ClearDataMode; -import ghidra.program.model.data.InvalidDataTypeException; -import ghidra.program.model.data.LongDataType; -import ghidra.program.model.data.LongLongDataType; -import ghidra.program.model.data.Pointer; -import ghidra.program.model.data.PointerDataType; -import ghidra.program.model.data.PointerTypedef; -import ghidra.program.model.data.StringDataType; -import ghidra.program.model.data.Structure; -import ghidra.program.model.data.StructureDataType; -import ghidra.program.model.data.TerminatedStringDataType; -import ghidra.program.model.data.UnsignedIntegerDataType; import ghidra.program.model.lang.Register; -import ghidra.program.model.listing.Bookmark; -import ghidra.program.model.listing.BookmarkType; -import ghidra.program.model.listing.CircularDependencyException; -import ghidra.program.model.listing.Data; -import ghidra.program.model.listing.Function; -import ghidra.program.model.listing.FunctionManager; -import ghidra.program.model.listing.Instruction; -import ghidra.program.model.listing.InstructionIterator; -import ghidra.program.model.listing.Listing; -import ghidra.program.model.listing.Program; -import ghidra.program.model.mem.DumbMemBufferImpl; -import ghidra.program.model.mem.MemBuffer; -import ghidra.program.model.mem.Memory; -import ghidra.program.model.mem.MemoryAccessException; -import ghidra.program.model.mem.MemoryBlock; +import ghidra.program.model.listing.*; +import ghidra.program.model.mem.*; import ghidra.program.model.scalar.Scalar; -import ghidra.program.model.symbol.Namespace; -import ghidra.program.model.symbol.Reference; -import ghidra.program.model.symbol.ReferenceIterator; -import ghidra.program.model.symbol.ReferenceManager; -import ghidra.program.model.symbol.SourceType; -import ghidra.program.model.symbol.Symbol; -import ghidra.program.model.symbol.SymbolIterator; +import ghidra.program.model.symbol.*; import ghidra.program.model.util.CodeUnitInsertionException; -import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramMemoryUtil; import ghidra.util.Msg; -import ghidra.util.bytesearch.GenericByteSequencePattern; -import ghidra.util.bytesearch.GenericMatchAction; -import ghidra.util.bytesearch.Match; -import ghidra.util.bytesearch.MemoryBytePatternSearcher; -import ghidra.util.exception.CancelledException; -import ghidra.util.exception.DuplicateNameException; -import ghidra.util.exception.InvalidInputException; +import ghidra.util.bytesearch.*; +import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; public class RTTIGccClassRecoverer extends RTTIClassRecoverer { @@ -151,23 +95,20 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { private Map> classToParentOffsetMap = new HashMap>(); - - private Map> classToVftableMap = new HashMap<>(); boolean isDwarfLoaded; boolean replaceClassStructs; - FunctionManager functionManager = null; - Listing listing; + protected final FunctionManager functionManager; + protected final Listing listing; - public RTTIGccClassRecoverer(Program program, ProgramLocation location, PluginTool tool, - FlatProgramAPI api, - boolean createBookmarks, boolean useShortTemplates, boolean nameVfunctions, - boolean isDwarfLoaded, - TaskMonitor monitor) throws Exception { + public RTTIGccClassRecoverer(Program program, ServiceProvider serviceProvider, + FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates, + boolean nameVfunctions, boolean isDwarfLoaded, TaskMonitor monitor) throws Exception { - super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions, + super(program, serviceProvider, api, createBookmarks, useShortTemplates, nameVfunctions, isDwarfLoaded, monitor); + this.isDwarfLoaded = isDwarfLoaded; functionManager = program.getFunctionManager(); @@ -208,8 +149,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { List directReferenceList = new ArrayList(); ProgramMemoryUtil.loadDirectReferenceList(program, 1, initializedMem.getMinAddress(), - initializedMem, - directReferenceList, monitor); + initializedMem, directReferenceList, monitor); createGlobalDirectRefMap(directReferenceList); Msg.debug(this, "Creating Special Typeinfos"); @@ -287,7 +227,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { /** * Method to update the labels of vftables that belong to classes with multiple vftables in * order to distinguish which base class the vftable is for. - * @param recoveredClasses the list of RecoveredClass objects * @throws CancelledException if cancelled * @throws InvalidInputException if bad chars trying to label * @throws DuplicateNameException if duplicate name @@ -364,8 +303,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } private GccTypeinfo findSpecialTypeinfoSymbol(String namespaceName, - String mangledNamespaceString) - throws CancelledException { + String mangledNamespaceString) throws CancelledException { // try finding with normal symbol name and namespace Symbol typeinfoSymbol = @@ -384,9 +322,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { if (typeinfoSymbol == null) { // then try finding with mangled namespace string in memory - typeinfoSymbol = - findTypeinfoSymbolUsingMangledNamespaceString(mangledNamespaceString, - namespaceName); + typeinfoSymbol = findTypeinfoSymbolUsingMangledNamespaceString( + mangledNamespaceString, namespaceName); } } } @@ -397,8 +334,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } private Symbol findTypeinfoUsingNotInProgramMemoryVtableSymbol(String namespaceName, - String mangledNamespaceString) - throws CancelledException { + String mangledNamespaceString) throws CancelledException { // try finding with normal symbol name and namespace Symbol vtableSymbol = @@ -433,8 +369,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { Symbol typeinfoSymbol; try { typeinfoSymbol = symbolTable.createLabel(vtableAddress, "typeinfo", - vtableSymbol.getParentNamespace(), - SourceType.ANALYSIS); + vtableSymbol.getParentNamespace(), SourceType.ANALYSIS); // api.setPlateComment(typeinfoAddress, "typeinfo for " + namespace); } catch (InvalidInputException e) { @@ -484,8 +419,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // TODO: this assumes only one and returns the first found - have never seen // more than one but should probably check private Symbol findAndReturnDemangledSymbol(String mangledSymbolName, - String specialClassNamespaceName, - String classNamespaceName, String label) { + String specialClassNamespaceName, String classNamespaceName, String label) { SymbolIterator symbolIterator = symbolTable.getSymbolIterator(mangledSymbolName, true); if (symbolIterator.hasNext()) { @@ -504,9 +438,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } try { - Symbol demangledSymbol = - symbolTable.createLabel(symbolAddress, label, classNamespace, - SourceType.ANALYSIS); + Symbol demangledSymbol = symbolTable.createLabel(symbolAddress, label, + classNamespace, SourceType.ANALYSIS); demangledSymbol.setPrimary(); return demangledSymbol; } @@ -520,8 +453,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // TODO: can this be used for regular ones too? private Symbol findTypeinfoSymbolUsingMangledNamespaceString(String mangledNamespace, - String namespaceName) - throws CancelledException { + String namespaceName) throws CancelledException { Symbol specialTypeinfoSymbol = findTypeinfoUsingMangledString(mangledNamespace); if (specialTypeinfoSymbol == null) { @@ -539,9 +471,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { boolean isExternal = typeinfoAddress.isExternalAddress() || inExternalBlock(typeinfoAddress); - GccTypeinfo gccTypeinfo = - new GccTypeinfo(typeinfoSymbol.getAddress(), typeinfoSymbol.getParentNamespace(), - isSpecial, !isExternal); + GccTypeinfo gccTypeinfo = new GccTypeinfo(typeinfoSymbol.getAddress(), + typeinfoSymbol.getParentNamespace(), isSpecial, !isExternal); return gccTypeinfo; } @@ -578,10 +509,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { boolean isGcc; - boolean isCompilerSpecGcc = program.getCompilerSpec() - .getCompilerSpecID() - .getIdAsString() - .equalsIgnoreCase("gcc"); + boolean isCompilerSpecGcc = + program.getCompilerSpec().getCompilerSpecID().getIdAsString().equalsIgnoreCase("gcc"); if (isCompilerSpecGcc) { return true; } @@ -605,8 +534,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { byte[] maskBytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; Address found = program.getMemory() - .findBytes(commentBlock.getStart(), commentBlock.getEnd(), gccBytes, - maskBytes, true, monitor); + .findBytes(commentBlock.getStart(), commentBlock.getEnd(), gccBytes, maskBytes, + true, monitor); if (found == null) { isGcc = false; } @@ -726,9 +655,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // parent isn't a known class - cannot continue processing recoveredClass if (parentClass == null) { - Msg.error(this, - "Removing class: " + recoveredClass.getName() + " from list to" + - " process since parent information is not availalbe."); + Msg.error(this, "Removing class: " + recoveredClass.getName() + + " from list to" + " process since parent information is not availalbe."); recoveredClasses.remove(recoveredClass); } continue; @@ -801,9 +729,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { Vtable vtable = processMainVtable(mainVtable, map.get(mainVtable)); if (vtable == null) { - Msg.debug(this, - "MISSING expected vtable for simple class " + - typeinfo.getNamespace().getName(true)); + Msg.debug(this, "MISSING expected vtable for simple class " + + typeinfo.getNamespace().getName(true)); continue; } @@ -1051,8 +978,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } private boolean isPossibleVttStart(Address address, List vtables, - List
knownVtts) - throws CancelledException { + List
knownVtts) throws CancelledException { // make list of all vtable tops and vftable tops List
vtableAndVftableAddrs = getListOfVtableAndVftableTops(vtables); @@ -1164,7 +1090,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { * construction ones to the passed in list * * @param typeinfo + * @param map * @param constructionVtables + * @param numBaseRefs * @return address of main vtable for this class * @throws CancelledException */ @@ -1468,8 +1396,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } private Address getMainVtableUsingSymbols(List
vtableAddresses, - List
constructionVtables) - throws CancelledException { + List
constructionVtables) throws CancelledException { List
mainVtableCandidates = new ArrayList
(); for (Address vtableAddress : vtableAddresses) { @@ -1662,8 +1589,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } symbolTable.createLabel(vtableAddress, internalString + constructionString + VTABLE_LABEL, - classNamespace, - SourceType.ANALYSIS); + classNamespace, SourceType.ANALYSIS); } @@ -1690,8 +1616,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } symbolTable.createLabel(vtable.getVfunctionTop(), - internalString + constructionString + VFTABLE_LABEL, - classNamespace, SourceType.ANALYSIS); + internalString + constructionString + VFTABLE_LABEL, classNamespace, + SourceType.ANALYSIS); } @@ -1871,8 +1797,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { Namespace newNamespace; try { newNamespace = NamespaceUtils.createNamespaceHierarchy(name, - namespaceIn.getParentNamespace(), program, - SourceType.ANALYSIS); + namespaceIn.getParentNamespace(), program, SourceType.ANALYSIS); } catch (InvalidInputException e) { return null; @@ -1893,8 +1818,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } public Map> findTypeinfoReferencesNotInTypeinfoStructsOld( - List
typeinfoAddresses) - throws CancelledException { + List
typeinfoAddresses) throws CancelledException { MemoryBytePatternSearcher searcher = new MemoryBytePatternSearcher("Typeinfo References"); @@ -1934,7 +1858,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { searchSet.add(addressRange.getMinAddress(), addressRange.getMaxAddress()); } - Map> directRefMap = new HashMap>(); + Map> refMap = new HashMap>(); AddressIterator addrIter = initializedSet.getAddresses(initializedSet.getMinAddress(), true); @@ -1944,11 +1868,11 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // check direct refs to see if they are in undefined area or not in function byte[] bytes = ProgramMemoryUtil.getDirectAddressBytes(program, address); - addByteSearchPatternDirRefs(searcher, directRefMap, address, bytes, monitor); + addByteSearchPatternDirRefs(searcher, refMap, address, bytes, monitor); } searcher.search(program, searchSet, monitor); - return directRefMap; + return refMap; } /** @@ -1997,8 +1921,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } public Map> findTypeinfoReferencesNotInTypeinfoStructs( - List typeinfos) - throws CancelledException { + List typeinfos) throws CancelledException { MemoryBytePatternSearcher searcher = new MemoryBytePatternSearcher("Typeinfo References"); @@ -2104,8 +2027,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { * @param taskMonitor a cancellable monitor */ private void addByteSearchPattern(MemoryBytePatternSearcher searcher, - Map> typeinfoRefMap, - Address typeinfoAddress, byte[] bytes, TaskMonitor taskMonitor) { + Map> typeinfoRefMap, Address typeinfoAddress, byte[] bytes, + TaskMonitor taskMonitor) { // no pattern bytes. if (bytes == null) { @@ -2195,8 +2118,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { * @throws CancelledException if cancelled */ private Vtable processVtable(Address vtableAddress, GccTypeinfoRef typeinfoRef, - Boolean isConstruction) - throws CancelledException { + Boolean isConstruction) throws CancelledException { Vtable vtable = null; boolean isSpecial = false; @@ -2296,9 +2218,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { api.clearListing(vtableAddress); - SpecialVtable specialVtable = - new SpecialVtable(program, vtableAddress, typeinfoRef, isExternal, - vtableSymbol.getParentNamespace(), monitor); + SpecialVtable specialVtable = new SpecialVtable(program, vtableAddress, typeinfoRef, + isExternal, vtableSymbol.getParentNamespace(), monitor); return specialVtable; } @@ -2421,9 +2342,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { .equals(VMI_CLASS_TYPEINFO_NAMESPACE)) { specialTypeinfoNamespaceName = VMI_CLASS_TYPEINFO_NAMESPACE; typeinfoToStructuretypeMap.put(typeinfoAddress, VMI_CLASS_TYPE_INFO_STRUCTURE); - Structure vmiClassTypeinfoStructure = - getOrCreateVmiTypeinfoStructure(typeinfoAddress, - baseClassTypeInfoStructure); + Structure vmiClassTypeinfoStructure = getOrCreateVmiTypeinfoStructure( + typeinfoAddress, baseClassTypeInfoStructure); if (vmiClassTypeinfoStructure != null) { newStructure = applyTypeinfoStructure(vmiClassTypeinfoStructure, typeinfoAddress); @@ -2500,8 +2420,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } private void updateTypeinfosWithBases(List typeinfos, - Map typeinfoMap) - throws CancelledException { + Map typeinfoMap) throws CancelledException { List invalidTypeinfos = new ArrayList(); for (GccTypeinfo typeinfo : typeinfos) { @@ -2549,9 +2468,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // SI_CLASS_TYPE_INFO_STRUCTURE if (!isTypeinfoStruct(siTypeinfoStructure)) { - throw new IllegalArgumentException( - siTypeinfoStructure.getAddressString(false, false) + - " is not a typeinfo structure"); + throw new IllegalArgumentException(siTypeinfoStructure.getAddressString(false, false) + + " is not a typeinfo structure"); } Data baseClassPointer = siTypeinfoStructure.getComponent(2); @@ -2604,9 +2522,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { extendedFlatAPI.getReferencedAddress(baseClassStructureAddress, false); if (baseTypeinfoAddress == null) { - Msg.debug(this, - typeinfo.getAddress() + - ": invalid typeinfo - cannot get address at baseTypeinfo[" + i + "]"); + Msg.debug(this, typeinfo.getAddress() + + ": invalid typeinfo - cannot get address at baseTypeinfo[" + i + "]"); return false; } @@ -2674,8 +2591,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { DataType inheritanceFlagDataType = inheritanceFlagComponent.getDataType(); MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), flagAddress); Scalar scalar = (Scalar) inheritanceFlagDataType.getValue(buf, - inheritanceFlagDataType.getDefaultSettings(), - inheritanceFlagDataType.getLength()); + inheritanceFlagDataType.getDefaultSettings(), inheritanceFlagDataType.getLength()); long inheritanceFlagValue = scalar.getUnsignedValue(); return inheritanceFlagValue; } @@ -2693,8 +2609,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { DataType numBaseClassesDataType = numBaseClassesComponent.getDataType(); MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), numBaseClassesAddress); Scalar scalar = (Scalar) numBaseClassesDataType.getValue(buf, - numBaseClassesDataType.getDefaultSettings(), - numBaseClassesDataType.getLength()); + numBaseClassesDataType.getDefaultSettings(), numBaseClassesDataType.getLength()); int numBaseClasses = (int) scalar.getUnsignedValue(); return numBaseClasses; @@ -2810,9 +2725,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } // get or create the vmiClassTypeInfoStruct - Structure vmiClassTypeinfoStructure = - (Structure) dataTypeManager.getDataType(classDataTypesCategoryPath, - VMI_CLASS_TYPE_INFO_STRUCTURE + numBases); + Structure vmiClassTypeinfoStructure = (Structure) dataTypeManager + .getDataType(classDataTypesCategoryPath, VMI_CLASS_TYPE_INFO_STRUCTURE + numBases); if (vmiClassTypeinfoStructure == null) { vmiClassTypeinfoStructure = createVmiClassTypeInfoStructure(baseClassTypeInfoStructure, numBases); @@ -2821,7 +2735,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } private Symbol createDemangledTypeinfoSymbol(Address typeinfoAddress) - throws DuplicateNameException, InvalidInputException, CancelledException { + throws DuplicateNameException, InvalidInputException { // TODO: 1. see if there is a mangled name that didn't get demangled at // TODO: 2 - refactor the three places that call this to just call getSymbolAt @@ -2919,9 +2833,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { Namespace classNamespace = typeinfoNameSymbol.getParentNamespace(); if (classNamespace.isGlobal()) { - Msg.debug(this, - typeinfoAddress.toString() + - "Could not create a class namespace for demangled namespace string "); + Msg.debug(this, typeinfoAddress.toString() + + "Could not create a class namespace for demangled namespace string "); return null; } @@ -2987,7 +2900,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { private String getDefinedStringAt(Address address) { - Listing listing = program.getListing(); Data stringData = listing.getDataAt(address); if (stringData == null) { @@ -3218,15 +3130,11 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } public void assignConstructorsAndDestructorsUsingExistingNameNew( - List recoveredClasses) - throws CancelledException, InvalidInputException, DuplicateNameException, - CircularDependencyException { + List recoveredClasses) throws CancelledException, InvalidInputException, + DuplicateNameException, CircularDependencyException { - Iterator recoveredClassIterator = recoveredClasses.iterator(); - while (recoveredClassIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = recoveredClassIterator.next(); - Namespace classNamespace = recoveredClass.getClassNamespace(); String name = classNamespace.getName(); SymbolIterator classSymbols = symbolTable.getSymbols(classNamespace); @@ -3353,8 +3261,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } private void removeFromIndeterminateLists(List recoveredClasses, - Function function) - throws CancelledException { + Function function) throws CancelledException { for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); @@ -3373,8 +3280,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { if (hasExternalRelocations()) { PointerTypedef classTypeInfoPtr = - new PointerTypedef(null, null, -1, program.getDataTypeManager(), - componentOffset); + new PointerTypedef(null, null, -1, program.getDataTypeManager(), componentOffset); classTypeInfoStructure.add(classTypeInfoPtr, "classTypeinfoPtr", null); } @@ -3393,18 +3299,15 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } private StructureDataType createSiClassTypeInfoStructure( - StructureDataType classTypeInfoStructure) - throws CancelledException { + StructureDataType classTypeInfoStructure) throws CancelledException { - StructureDataType siClassTypeInfoStructure = - new StructureDataType(classDataTypesCategoryPath, - SI_CLASS_TYPE_INFO_STRUCTURE, 0, dataTypeManager); + StructureDataType siClassTypeInfoStructure = new StructureDataType( + classDataTypesCategoryPath, SI_CLASS_TYPE_INFO_STRUCTURE, 0, dataTypeManager); CharDataType characterDT = new CharDataType(); PointerTypedef classTypeInfoPtr = - new PointerTypedef(null, null, -1, program.getDataTypeManager(), - componentOffset); + new PointerTypedef(null, null, -1, program.getDataTypeManager(), componentOffset); siClassTypeInfoStructure.add(classTypeInfoPtr, "classTypeinfoPtr", null); DataType charPointer = dataTypeManager.getPointer(characterDT); @@ -3420,12 +3323,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } private StructureDataType createBaseClassTypeInfoStructure( - StructureDataType classTypeInfoStructure) - throws InvalidDataTypeException { + StructureDataType classTypeInfoStructure) throws InvalidDataTypeException { - StructureDataType baseclassTypeInfoStructure = - new StructureDataType(classDataTypesCategoryPath, - BASE_CLASS_TYPE_INFO_STRUCTURE, 0, dataTypeManager); + StructureDataType baseclassTypeInfoStructure = new StructureDataType( + classDataTypesCategoryPath, BASE_CLASS_TYPE_INFO_STRUCTURE, 0, dataTypeManager); DataType classTypeInfoPointer = dataTypeManager.getPointer(classTypeInfoStructure); @@ -3460,8 +3361,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } private StructureDataType createVmiClassTypeInfoStructure( - StructureDataType baseClassTypeInfoStructure, - int numBaseClasses) throws CancelledException { + StructureDataType baseClassTypeInfoStructure, int numBaseClasses) + throws CancelledException { StructureDataType vmiClassTypeInfoStructure = new StructureDataType(classDataTypesCategoryPath, @@ -3471,8 +3372,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { UnsignedIntegerDataType unsignedIntDT = new UnsignedIntegerDataType(); PointerTypedef classTypeInfoPtr = - new PointerTypedef(null, null, -1, program.getDataTypeManager(), - componentOffset); + new PointerTypedef(null, null, -1, program.getDataTypeManager(), componentOffset); vmiClassTypeInfoStructure.add(classTypeInfoPtr, "classTypeinfoPtr", null); DataType charPointer = dataTypeManager.getPointer(characterDT); @@ -3564,8 +3464,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { * @throws CancelledException if cancelled */ private List addClassParentsAndFlagsForVmiClass(RecoveredClass recoveredClass, - GccTypeinfo typeinfo) - throws CancelledException { + GccTypeinfo typeinfo) throws CancelledException { long inheritanceFlagValue = typeinfo.getInheritanceFlagValue(); @@ -3646,8 +3545,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } private Address findSpecialVtable(GccTypeinfo specialTypeinfo, - List specialTypeinfos) - throws CancelledException { + List specialTypeinfos) throws CancelledException { String namespaceName = specialTypeinfo.getNamespace().getName(); String mangledNamespaceString = specialTypeinfo.getMangledNamespaceString(); @@ -3663,9 +3561,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // then try finding top of special vtable by finding ref to special typeinfo if (vtableSymbol == null) { - Address vtableAddress = - findSpecialVtableUsingSpecialTypeinfo(specialTypeinfo.getAddress(), - specialTypeinfos); + Address vtableAddress = findSpecialVtableUsingSpecialTypeinfo( + specialTypeinfo.getAddress(), specialTypeinfos); if (vtableAddress == null) { return null; @@ -3673,14 +3570,13 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { try { vtableSymbol = symbolTable.createLabel(vtableAddress, VTABLE_LABEL, - specialTypeinfo.getNamespace(), - SourceType.ANALYSIS); + specialTypeinfo.getNamespace(), SourceType.ANALYSIS); api.setPlateComment(vtableAddress, "vtable for " + specialTypeinfo.getNamespace()); } catch (InvalidInputException e) { - vtableSymbol = null; + // ignore } } @@ -3729,8 +3625,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { * len between the two */ private Address findSpecialVtableUsingSpecialTypeinfo(Address typeinfoAddress, - List specialTypeinfos) - throws CancelledException { + List specialTypeinfos) throws CancelledException { List
referencesTo = getAllReferencesTo(typeinfoAddress); @@ -3805,8 +3700,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { try { symbolTable.createLabel(findSingleMangledString, mangledNamespaceString, - globalNamespace, - SourceType.ANALYSIS); + globalNamespace, SourceType.ANALYSIS); } catch (InvalidInputException e) { @@ -4096,7 +3990,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { monitor.checkCancelled(); baseOffsets.add(baseTypeinfo.getOffset()); } - if (baseOffsets.size() != vftableAddresses.size()) { @@ -4127,13 +4020,12 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { continue; } recoveredClass.addVftableToBaseClassMapping(correspondingVftableAddress, baseClass); - + //TODO: populate the new Vftable objects } } } - /** * Use information from RTTI Base class Arrays to create class hierarchy lists * and maps @@ -4188,10 +4080,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { RecoveredClass recoveredClass = recoveredClassIterator.next(); List parentList = recoveredClass.getParentList(); - Iterator parentIterator = parentList.iterator(); - while (parentIterator.hasNext()) { + for (RecoveredClass parentClass : parentList) { monitor.checkCancelled(); - RecoveredClass parentClass = parentIterator.next(); recoveredClass.addClassHierarchyMapping(parentClass, parentClass.getClassHierarchy()); } @@ -4224,10 +4114,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { private boolean hasVirtualAncestor(RecoveredClass recoveredClass) throws CancelledException { List classHierarchy = recoveredClass.getClassHierarchy(); - Iterator classIterator = classHierarchy.iterator(); - while (classIterator.hasNext()) { + for (RecoveredClass ancestor : classHierarchy) { monitor.checkCancelled(); - RecoveredClass ancestor = classIterator.next(); if (ancestor.inheritsVirtualAncestor()) { return true; } @@ -4287,11 +4175,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { classHierarchyList.add(recoveredClass); List parentList = recoveredClass.getParentList(); - Iterator parentIterator = parentList.iterator(); - while (parentIterator.hasNext()) { + for (RecoveredClass parentClass : parentList) { monitor.checkCancelled(); - RecoveredClass parentClass = parentIterator.next(); if (nonInheritedClasses.contains(parentClass)) { classHierarchyList.addAll(parentClass.getClassHierarchy()); continue; @@ -4403,8 +4289,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { disassemble = api.disassemble(address); Bookmark bookmark = getBookmarkAt(possibleFunctionPointer, BookmarkType.ERROR, - "Bad Instruction", - "conflicting data"); + "Bad Instruction", "conflicting data"); if (bookmark != null) { api.removeBookmark(bookmark); } @@ -4418,8 +4303,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } private Bookmark getBookmarkAt(Address address, String bookmarkType, String category, - String commentContains) - throws CancelledException { + String commentContains) throws CancelledException { Bookmark[] bookmarks = program.getBookmarkManager().getBookmarks(address); @@ -4544,10 +4428,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { for (RecoveredClass parent : parentList) { monitor.checkCancelled(); if (parent.getName().endsWith("_class_type_info")) { - Msg.debug(this, - "Not creating class data type for " + - recoveredClass.getClassNamespace().getName(true) + - " because it has a parent that is one of the special typeinfo classes."); + Msg.debug(this, "Not creating class data type for " + + recoveredClass.getClassNamespace().getName(true) + + " because it has a parent that is one of the special typeinfo classes."); return; } } @@ -4570,8 +4453,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { recoveredClass.getClassNamespace().getName(true)); } - updateClassFunctionsNotUsingNewClassStructure(recoveredClass, - classStructure); + updateClassFunctionsNotUsingNewClassStructure(recoveredClass, classStructure); // return in this case because if there is no vftable for a class the script cannot // identify any member functions so there is no need to process the rest of this // method @@ -4664,8 +4546,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // simple case the offset for vftablePtr is 0 // if can fit or grow structure, add the vftablePtr to it EditStructureUtils.addDataTypeToStructure(classStructureDataType, 0, - classVftablePointer, - CLASS_VTABLE_PTR_FIELD_EXT, monitor); + classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor); } // if single inheritance or multi non-virtual (wouldn't have called this method // if it were virtually inherited) put parent struct and data into class struct @@ -4674,18 +4555,16 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { Map orderToParentMap = classToParentOrderMap.get(recoveredClass); if (orderToParentMap == null || orderToParentMap.isEmpty()) { - Msg.error(this, - "Vmi class " + recoveredClass.getClassNamespace().getName(true) + - " should have a parent in the classToParentOrderMap but doesn't"); + Msg.error(this, "Vmi class " + recoveredClass.getClassNamespace().getName(true) + + " should have a parent in the classToParentOrderMap but doesn't"); return null; } Map parentToOffsetMap = classToParentOffsetMap.get(recoveredClass); if (parentToOffsetMap.isEmpty()) { - Msg.error(this, - "Vmi class " + recoveredClass.getClassNamespace().getName(true) + - " should have a parent in the classToParentOffsetMap but doesn't"); + Msg.error(this, "Vmi class " + recoveredClass.getClassNamespace().getName(true) + + " should have a parent in the classToParentOffsetMap but doesn't"); return null; } @@ -4705,8 +4584,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { if (baseClassStructure == null) { Msg.error(this, "Parent structure: " + - parent.getClassNamespace().getName(true) + - " should exist but doesn't."); + parent.getClassNamespace().getName(true) + " should exist but doesn't."); return null; } // if it fits at offset or is at the end and class structure can be grown, @@ -4728,22 +4606,19 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { int dataLen = UNKNOWN; if (dataOffset != NONE) { dataLen = EditStructureUtils.getNumberOfUndefinedsStartingAtOffset( - classStructureDataType, dataOffset, - monitor); + classStructureDataType, dataOffset, monitor); } if (dataLen != UNKNOWN && dataLen > 0) { - Structure recoveredClassDataStruct = - createClassMemberDataStructure(recoveredClass, classStructureDataType, - dataLen, dataOffset); + Structure recoveredClassDataStruct = createClassMemberDataStructure(recoveredClass, + classStructureDataType, dataLen, dataOffset); if (recoveredClassDataStruct != null) { // if it fits at offset or is at the end and class structure can be grown, // copy the whole baseClass structure to the class Structure at the given offset EditStructureUtils.addDataTypeToStructure(classStructureDataType, dataOffset, - recoveredClassDataStruct, - "data", monitor); + recoveredClassDataStruct, "data", monitor); } } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java index d5058b625f..ded513386f 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java @@ -16,56 +16,26 @@ //DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS. package classrecovery; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Set; +import java.util.*; -import ghidra.app.plugin.core.decompile.actions.FillOutStructureCmd; -import ghidra.app.plugin.core.decompile.actions.FillOutStructureCmd.OffsetPcodeOpPair; +import ghidra.app.decompiler.DecompileOptions; +import ghidra.app.decompiler.component.DecompilerUtils; +import ghidra.app.decompiler.util.FillOutStructureHelper; +import ghidra.app.decompiler.util.FillOutStructureHelper.OffsetPcodeOpPair; import ghidra.app.util.opinion.PeLoader; import ghidra.app.util.opinion.PeLoader.CompilerOpinion.CompilerEnum; -import ghidra.framework.plugintool.PluginTool; +import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.flatapi.FlatProgramAPI; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressOutOfBoundsException; -import ghidra.program.model.address.AddressRange; -import ghidra.program.model.address.AddressSet; -import ghidra.program.model.address.AddressSetView; -import ghidra.program.model.data.ArrayDataType; -import ghidra.program.model.data.Category; -import ghidra.program.model.data.CategoryPath; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.DataTypeConflictHandler; -import ghidra.program.model.data.IntegerDataType; -import ghidra.program.model.data.PointerDataType; -import ghidra.program.model.data.Structure; -import ghidra.program.model.data.StructureDataType; -import ghidra.program.model.listing.CircularDependencyException; -import ghidra.program.model.listing.Data; -import ghidra.program.model.listing.FlowOverride; -import ghidra.program.model.listing.Function; -import ghidra.program.model.listing.Instruction; -import ghidra.program.model.listing.Program; +import ghidra.program.model.address.*; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.*; import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.pcode.HighFunction; import ghidra.program.model.pcode.HighVariable; -import ghidra.program.model.symbol.Namespace; -import ghidra.program.model.symbol.Reference; -import ghidra.program.model.symbol.SourceType; -import ghidra.program.model.symbol.Symbol; -import ghidra.program.model.symbol.SymbolIterator; -import ghidra.program.model.symbol.SymbolType; -import ghidra.program.util.ProgramLocation; +import ghidra.program.model.symbol.*; import ghidra.util.Msg; -import ghidra.util.exception.CancelledException; -import ghidra.util.exception.DuplicateNameException; -import ghidra.util.exception.InvalidInputException; +import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { @@ -85,7 +55,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { private static final String RTTI_CLASS_HIERARCHY_DESCRIPTOR_DATA_NAME = "RTTIClassHierarchyDescriptor"; private static final String VFTABLE_META_PTR_LABEL = "vftable_meta_ptr"; - private static final String VFTABLE_LABEL = "vftable"; +// private static final String VFTABLE_LABEL = "vftable"; private static final String CLASS_VTABLE_STRUCT_NAME = "_vbtable"; private static final String CLASS_VTABLE_PTR_FIELD_EXT = "vftablePtr"; @@ -102,15 +72,14 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { boolean isPDBLoaded; - public RTTIWindowsClassRecoverer(Program program, ProgramLocation location, PluginTool tool, + public RTTIWindowsClassRecoverer(Program program, ServiceProvider serviceProvider, FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates, boolean nameVFunctions, boolean isPDBLoaded, TaskMonitor monitor) throws Exception { - super(program, location, tool, api, createBookmarks, useShortTemplates, nameVFunctions, + super(program, serviceProvider, api, createBookmarks, useShortTemplates, nameVFunctions, isPDBLoaded, monitor); this.isPDBLoaded = isPDBLoaded; - } @Override @@ -241,60 +210,60 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { return false; } - /** - * Method to determine if the current program has RTTI data applied to it - * @return true if the current program has RTTI data applied to it - * @throws CancelledException if cancelled - */ - private boolean programHasRTTIApplied() throws CancelledException { - - // First check to see if the RTTICompleteObjectLocator data type exists. If not there has - // been no RTTI applied - DataType completeObjLocatorDataType = dataTypeManager.getDataType(CategoryPath.ROOT, - RTTI_BASE_COMPLETE_OBJECT_LOADER_DATA_NAME); - if (completeObjLocatorDataType == null) { - return false; - } - - // Next check that a RTTICompleteObjectLocator has been applied somewhere to make sure that - // we don't have the case where pdb ran and created the data type but rtti didn't run so didn't - // apply any of the data types - return hasSymbolAndDataType(RTTI_BASE_COMPLETE_OBJECT_LOADER_LABEL, - completeObjLocatorDataType); - } - - private void runRTTIAnalyzer() throws Exception { -// Analyzer analyzer = new RttiAnalyzer(); -// analyzer.added(program, program.getAddressFactory().getAddressSet(), monitor, -// new MessageLog()); - } - - /** - * Method to find all the vftables in the program - * @return list of all vftable symbols - * @throws CancelledException when cancelled - */ - //TODO: pull into separate methods and check separately above - private boolean hasSymbolAndDataType(String symbolName, DataType datatype) - throws CancelledException { - - String pdbName = "`" + symbolName + "'"; - SymbolIterator symbols = - program.getSymbolTable().getSymbolIterator("*" + symbolName + "*", true); - - while (symbols.hasNext()) { - monitor.checkCancelled(); - Symbol symbol = symbols.next(); - if (symbol.getName().equals(symbolName) || symbol.getName().equals(pdbName)) { - Data dataAt = program.getListing().getDefinedDataAt(symbol.getAddress()); - if (dataAt.getDataType().equals(datatype)) { - return true; - } - } - - } - return false; - } +// /** +// * Method to determine if the current program has RTTI data applied to it +// * @return true if the current program has RTTI data applied to it +// * @throws CancelledException if cancelled +// */ +// private boolean programHasRTTIApplied() throws CancelledException { +// +// // First check to see if the RTTICompleteObjectLocator data type exists. If not there has +// // been no RTTI applied +// DataType completeObjLocatorDataType = dataTypeManager.getDataType(CategoryPath.ROOT, +// RTTI_BASE_COMPLETE_OBJECT_LOADER_DATA_NAME); +// if (completeObjLocatorDataType == null) { +// return false; +// } +// +// // Next check that a RTTICompleteObjectLocator has been applied somewhere to make sure that +// // we don't have the case where pdb ran and created the data type but rtti didn't run so didn't +// // apply any of the data types +// return hasSymbolAndDataType(RTTI_BASE_COMPLETE_OBJECT_LOADER_LABEL, +// completeObjLocatorDataType); +// } +// +// private void runRTTIAnalyzer() throws Exception { +//// Analyzer analyzer = new RttiAnalyzer(); +//// analyzer.added(program, program.getAddressFactory().getAddressSet(), monitor, +//// new MessageLog()); +// } +// +// /** +// * Method to find all the vftables in the program +// * @return list of all vftable symbols +// * @throws CancelledException when cancelled +// */ +// //TODO: pull into separate methods and check separately above +// private boolean hasSymbolAndDataType(String symbolName, DataType datatype) +// throws CancelledException { +// +// String pdbName = "`" + symbolName + "'"; +// SymbolIterator symbols = +// program.getSymbolTable().getSymbolIterator("*" + symbolName + "*", true); +// +// while (symbols.hasNext()) { +// monitor.checkCancelled(); +// Symbol symbol = symbols.next(); +// if (symbol.getName().equals(symbolName) || symbol.getName().equals(pdbName)) { +// Data dataAt = program.getListing().getDefinedDataAt(symbol.getAddress()); +// if (dataAt.getDataType().equals(datatype)) { +// return true; +// } +// } +// +// } +// return false; +// } public void fixUpRttiAnalysis() throws CancelledException, Exception { applyMissingRTTIStructures(); @@ -512,10 +481,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { List
classHierarchyDescriptorAddresses = new ArrayList
(); - Iterator baseClassDescriptorIterator = baseClassDescriptors.iterator(); - while (baseClassDescriptorIterator.hasNext()) { + for (Symbol symbol : baseClassDescriptors) { monitor.checkCancelled(); - Symbol symbol = baseClassDescriptorIterator.next(); Address classHierarchyDescriptorAddress = createClassHierarchyDescriptor( symbol.getAddress().add(24), symbol.getParentNamespace()); @@ -526,10 +493,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { } - Iterator completeObjectLocatorIterator = completeObjectLocators.iterator(); - while (completeObjectLocatorIterator.hasNext()) { + for (Symbol symbol : completeObjectLocators) { monitor.checkCancelled(); - Symbol symbol = completeObjectLocatorIterator.next(); Address classHierarchyDescriptorAddress = createClassHierarchyDescriptor( symbol.getAddress().add(16), symbol.getParentNamespace()); if (classHierarchyDescriptorAddress != null && @@ -621,13 +586,10 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { List
baseClassArrayAddresses = new ArrayList
(); - Iterator
classHierarchyDescriptorIterator = classHierarchyDescriptors.iterator(); - - while (classHierarchyDescriptorIterator.hasNext()) { + for (Address classHierarchyDescriptorAddress : classHierarchyDescriptors) { monitor.checkCancelled(); - Address classHierarchyDescriptorAddress = classHierarchyDescriptorIterator.next(); Symbol classHierarchyDescriptorSymbol = symbolTable.getPrimarySymbol(classHierarchyDescriptorAddress); Namespace classNamespace = classHierarchyDescriptorSymbol.getParentNamespace(); @@ -725,11 +687,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { List vftables = new ArrayList(); - Iterator iterator = completeObjectLocatorSymbols.iterator(); - while (iterator.hasNext()) { + for (Symbol completeObjectLocatorSymbol : completeObjectLocatorSymbols) { monitor.checkCancelled(); - Symbol completeObjectLocatorSymbol = iterator.next(); - Address completeObjectLocatorAddress = completeObjectLocatorSymbol.getAddress(); Namespace classNamespace = completeObjectLocatorSymbol.getParentNamespace(); @@ -903,10 +862,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { List classHierarchyDescriptorList = getListOfClassHierarchyDescriptors(); - Iterator classHierarchyDescriptorIterator = classHierarchyDescriptorList.iterator(); - while (classHierarchyDescriptorIterator.hasNext()) { + for (Symbol classHierarchyDescriptorSymbol : classHierarchyDescriptorList) { monitor.checkCancelled(); - Symbol classHierarchyDescriptorSymbol = classHierarchyDescriptorIterator.next(); Address classHierarchyDescriptorAddress = classHierarchyDescriptorSymbol.getAddress(); // Get class name from class vftable is in @@ -1000,16 +957,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { PointerDataType pointerDataType = new PointerDataType(); - Iterator recoveredClassIterator = recoveredClasses.iterator(); - while (recoveredClassIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = recoveredClassIterator.next(); - List
vftableAddresses = recoveredClass.getVftableAddresses(); - Iterator
vftableIterator = vftableAddresses.iterator(); - while (vftableIterator.hasNext()) { + for (Address vftableAddress : vftableAddresses) { monitor.checkCancelled(); - Address vftableAddress = vftableIterator.next(); Address ptrToColAddress = vftableAddress.subtract(defaultPointerSize); Data pointerToCompleteObjLocator = extendedFlatAPI.getDataAt(vftableAddress); @@ -1396,12 +1348,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { private void determineParentClassInfoFromBaseClassArray(List recoveredClasses) throws Exception { - Iterator recoveredClassIterator = recoveredClasses.iterator(); - while (recoveredClassIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = recoveredClassIterator.next(); - boolean hasVirtualAncestor = false; int vbaseOffset = NONE; @@ -1531,22 +1480,22 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { } } - Iterator constructorIterator = constructorList.iterator(); - while (constructorIterator.hasNext()) { + DecompileOptions decompileOptions = + DecompilerUtils.getDecompileOptions(serviceProvider, program); + FillOutStructureHelper fillStructHelper = + new FillOutStructureHelper(program, decompileOptions, monitor); + + for (Function constructor : constructorList) { monitor.checkCancelled(); - Function constructor = constructorIterator.next(); - HighFunction highFunction = decompilerUtils.getHighFunction(constructor); if (highFunction == null) { continue; } - FillOutStructureCmd fillCmd = new FillOutStructureCmd(program, location, tool); - - Address vbtableAddress = getVbtableAddressFromDecompiledFunction(fillCmd, highFunction, - recoveredClass, constructor, vbtableOffset); + Address vbtableAddress = getVbtableAddressFromDecompiledFunction(fillStructHelper, + highFunction, recoveredClass, constructor, vbtableOffset); if (vbtableAddress != null) { return vbtableAddress; @@ -1561,22 +1510,17 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { } } - Iterator indeterminateIterator = indeterminateList.iterator(); - while (indeterminateIterator.hasNext()) { + for (Function constructor : indeterminateList) { monitor.checkCancelled(); - Function constructor = indeterminateIterator.next(); - HighFunction highFunction = decompilerUtils.getHighFunction(constructor); if (highFunction == null) { continue; } - FillOutStructureCmd fillCmd = new FillOutStructureCmd(program, location, tool); - - Address vbtableAddress = getVbtableAddressFromDecompiledFunction(fillCmd, highFunction, - recoveredClass, constructor, vbtableOffset); + Address vbtableAddress = getVbtableAddressFromDecompiledFunction(fillStructHelper, + highFunction, recoveredClass, constructor, vbtableOffset); if (vbtableAddress != null) { return vbtableAddress; @@ -1589,7 +1533,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { /** * Method to find the address of the vbtable referenced at the given offset in the given function - * @param fillCmd the decompiler's filled out structure for a particular variable + * @param fillStructHelper a reusable {@link FillOutStructureHelper} instance to be used + * with decompiler for a particular variable * @param highFunction the high function for the given function * @param recoveredClass the given class * @param function the given function @@ -1597,7 +1542,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { * @return the address of the found vbtable or null if none is found * @throws CancelledException if cancelled */ - private Address getVbtableAddressFromDecompiledFunction(FillOutStructureCmd fillCmd, + private Address getVbtableAddressFromDecompiledFunction(FillOutStructureHelper fillStructHelper, HighFunction highFunction, RecoveredClass recoveredClass, Function function, int offset) throws CancelledException { @@ -1619,22 +1564,16 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { } } - Iterator highVariableIterator = highVariables.iterator(); + for (HighVariable highVariable : highVariables) { - while (highVariableIterator.hasNext()) { - - HighVariable highVariable = highVariableIterator.next(); monitor.checkCancelled(); - fillCmd.processStructure(highVariable, function); - List stores = fillCmd.getStorePcodeOps(); + fillStructHelper.processStructure(highVariable, function, true, false); + List stores = fillStructHelper.getStorePcodeOps(); stores = removePcodeOpsNotInFunction(function, stores); - // this method checks the storedPcodeOps to see if one is a vftable address - Iterator iterator = stores.iterator(); - while (iterator.hasNext()) { + for (OffsetPcodeOpPair offsetPcodeOpPair : stores) { monitor.checkCancelled(); - OffsetPcodeOpPair offsetPcodeOpPair = iterator.next(); int pcodeOffset = offsetPcodeOpPair.getOffset().intValue(); if (pcodeOffset == offset) { @@ -1664,11 +1603,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { private void assignParentClassToVftables(List recoveredClasses) throws Exception { - Iterator recoveredClassIterator = recoveredClasses.iterator(); - while (recoveredClassIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = recoveredClassIterator.next(); - if (!recoveredClass.hasVftable()) { continue; } @@ -1726,10 +1662,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { // iterate over the hierarchy list and use it to get the order of the parentsParents and assign // to correct vftable List classHierarchy = recoveredClass.getClassHierarchy(); - Iterator classHierarchyIterator = classHierarchy.iterator(); - while (classHierarchyIterator.hasNext()) { + for (RecoveredClass ancestor : classHierarchy) { monitor.checkCancelled(); - RecoveredClass ancestor = classHierarchyIterator.next(); if (grandParents.contains(ancestor)) { Integer index = sortedOrder.get(order); Address vftableAddress = orderToVftableMap.get(index); @@ -1817,12 +1751,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { List classHierarchy = recoveredClass.getClassHierarchy(); - Iterator hierarchyIterator = classHierarchy.iterator(); - - while (hierarchyIterator.hasNext()) { + for (RecoveredClass ancestorClass : classHierarchy) { monitor.checkCancelled(); - RecoveredClass ancestorClass = hierarchyIterator.next(); - RecoveredClass firstVirtuallyInheritedAncestorWithVfunctions = getVirtuallyInheritedParentWithVfunctions(ancestorClass); if (firstVirtuallyInheritedAncestorWithVfunctions != null) { @@ -1857,11 +1787,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { Map parentToBaseTypeMap = recoveredClass.getParentToBaseTypeMap(); List parents = new ArrayList(classHierarchyMap.keySet()); - Iterator parentIterator = parents.iterator(); - - while (parentIterator.hasNext()) { + for (RecoveredClass parent : parents) { monitor.checkCancelled(); - RecoveredClass parent = parentIterator.next(); Boolean isVirtuallyInherited = parentToBaseTypeMap.get(parent); if (isVirtuallyInherited != null && isVirtuallyInherited && parent.hasVftable()) { @@ -1898,10 +1825,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { return; } - Iterator orderIterator = sortedOrder.iterator(); - while (orderIterator.hasNext()) { + for (Integer order : sortedOrder) { monitor.checkCancelled(); - Integer order = orderIterator.next(); Address vftableAddress = orderToVftableMap.get(order); RecoveredClass parentClass = parentOrderMap.get(order); recoveredClass.addVftableToBaseClassMapping(vftableAddress, parentClass); @@ -1970,13 +1895,10 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { return parentOrderMap; } - Iterator functionIterator = functionList.iterator(); - while (functionIterator.hasNext()) { + for (Function function : functionList) { monitor.checkCancelled(); - Function function = functionIterator.next(); - parentOrderMap = new HashMap(); Map referenceToParentMap = @@ -1986,12 +1908,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { new HashMap(); List
classReferences = new ArrayList
(referenceToParentMap.keySet()); - Iterator
classReferenceIterator = classReferences.iterator(); - while (classReferenceIterator.hasNext()) { + for (Address classReferenceAddress : classReferences) { monitor.checkCancelled(); - Address classReferenceAddress = classReferenceIterator.next(); - // if the address refers to a vftable and that vftable is in the current class then it is not a parent class so do not add to map Address possibleVftable = getVftableAddress(classReferenceAddress); @@ -2029,11 +1948,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { Collections.sort(parentReferences, Collections.reverseOrder()); } - // iterate over the ordered parents and add to the order to parent map - Iterator
parentRefIterator = parentReferences.iterator(); - while (parentRefIterator.hasNext()) { + // iterate over the ordered parents and add the order to the parent map + for (Address refAddress : parentReferences) { monitor.checkCancelled(); - Address refAddress = parentRefIterator.next(); RecoveredClass parentClass = referenceToParentMap.get(refAddress); parentOrderMap.put(order, parentClass); order++; @@ -2074,11 +1991,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { List updatedParentClasses = new ArrayList(parentClasses); // now iterate over the direct parents and map that parent to each ancestor on the ancestor with vfunction list - Iterator parentIterator = parentClasses.iterator(); - while (parentIterator.hasNext()) { + for (RecoveredClass parentClass : parentClasses) { monitor.checkCancelled(); - RecoveredClass parentClass = parentIterator.next(); List ancestors = new ArrayList(parentClass.getClassHierarchy()); ancestors.remove(parentClass); @@ -2088,12 +2003,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { continue; } - Iterator ancestorIterator = ancestors.iterator(); - while (ancestorIterator.hasNext()) { + for (RecoveredClass ancestor : ancestors) { monitor.checkCancelled(); - RecoveredClass ancestor = ancestorIterator.next(); - List decendentList = ancestorToCommonChild.get(ancestor); if (decendentList == null) { List newDecendentList = new ArrayList(); @@ -2119,10 +2031,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { // now iterate over the ancestor map and update the parent list by adding any ancestor // that has common parents and removing those parents from the list - Iterator ancestorsIterator = keySet.iterator(); - while (ancestorsIterator.hasNext()) { + for (RecoveredClass ancestor : keySet) { monitor.checkCancelled(); - RecoveredClass ancestor = ancestorsIterator.next(); List commonChildList = ancestorToCommonChild.get(ancestor); if (commonChildList != null && commonChildList.size() >= 2) { if (!updatedParentClasses.contains(ancestor)) { diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java index ed9a8a31ee..5371244860 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java @@ -16,104 +16,37 @@ //DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS. package classrecovery; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; import ghidra.app.cmd.function.ApplyFunctionSignatureCmd; import ghidra.app.cmd.label.AddLabelCmd; import ghidra.app.cmd.label.SetLabelPrimaryCmd; -import ghidra.app.plugin.core.decompile.actions.FillOutStructureCmd; -import ghidra.app.plugin.core.decompile.actions.FillOutStructureCmd.OffsetPcodeOpPair; +import ghidra.app.decompiler.DecompileOptions; +import ghidra.app.decompiler.component.DecompilerUtils; +import ghidra.app.decompiler.util.FillOutStructureHelper; +import ghidra.app.decompiler.util.FillOutStructureHelper.OffsetPcodeOpPair; import ghidra.app.plugin.core.navigation.locationreferences.LocationReference; import ghidra.app.plugin.core.navigation.locationreferences.ReferenceUtils; import ghidra.app.util.NamespaceUtils; -import ghidra.framework.plugintool.PluginTool; +import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.database.data.DataTypeUtilities; import ghidra.program.flatapi.FlatProgramAPI; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressOutOfBoundsException; -import ghidra.program.model.address.AddressRange; -import ghidra.program.model.address.AddressRangeIterator; -import ghidra.program.model.address.AddressSet; -import ghidra.program.model.address.AddressSetView; -import ghidra.program.model.address.GlobalNamespace; -import ghidra.program.model.data.ArrayDataType; -import ghidra.program.model.data.Category; -import ghidra.program.model.data.CategoryPath; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.DataTypeComponent; -import ghidra.program.model.data.DataTypeConflictHandler; -import ghidra.program.model.data.DataTypeDependencyException; -import ghidra.program.model.data.DataTypeManager; -import ghidra.program.model.data.FunctionDefinition; -import ghidra.program.model.data.FunctionDefinitionDataType; -import ghidra.program.model.data.NoisyStructureBuilder; -import ghidra.program.model.data.ParameterDefinition; -import ghidra.program.model.data.Pointer; -import ghidra.program.model.data.PointerDataType; -import ghidra.program.model.data.Structure; -import ghidra.program.model.data.StructureDataType; -import ghidra.program.model.data.Undefined1DataType; -import ghidra.program.model.data.Undefined4DataType; -import ghidra.program.model.data.Undefined8DataType; -import ghidra.program.model.data.VoidDataType; +import ghidra.program.model.address.*; +import ghidra.program.model.data.*; import ghidra.program.model.lang.CompilerSpec; import ghidra.program.model.lang.PrototypeModel; -import ghidra.program.model.listing.Bookmark; -import ghidra.program.model.listing.BookmarkManager; -import ghidra.program.model.listing.BookmarkType; -import ghidra.program.model.listing.CircularDependencyException; -import ghidra.program.model.listing.Data; -import ghidra.program.model.listing.FlowOverride; -import ghidra.program.model.listing.Function; +import ghidra.program.model.listing.*; import ghidra.program.model.listing.Function.FunctionUpdateType; -import ghidra.program.model.listing.FunctionManager; -import ghidra.program.model.listing.FunctionSignature; -import ghidra.program.model.listing.Instruction; -import ghidra.program.model.listing.InstructionIterator; -import ghidra.program.model.listing.Listing; -import ghidra.program.model.listing.Parameter; -import ghidra.program.model.listing.Program; -import ghidra.program.model.listing.ReturnParameterImpl; -import ghidra.program.model.listing.Variable; import ghidra.program.model.mem.MemoryBlock; -import ghidra.program.model.pcode.HighFunction; -import ghidra.program.model.pcode.HighVariable; -import ghidra.program.model.pcode.PcodeOp; -import ghidra.program.model.pcode.PcodeOpAST; -import ghidra.program.model.pcode.Varnode; -import ghidra.program.model.symbol.Namespace; -import ghidra.program.model.symbol.RefType; -import ghidra.program.model.symbol.Reference; -import ghidra.program.model.symbol.ReferenceIterator; -import ghidra.program.model.symbol.ReferenceManager; -import ghidra.program.model.symbol.SourceType; -import ghidra.program.model.symbol.Symbol; -import ghidra.program.model.symbol.SymbolIterator; -import ghidra.program.model.symbol.SymbolTable; -import ghidra.program.model.symbol.SymbolType; -import ghidra.program.util.ProgramLocation; +import ghidra.program.model.pcode.*; +import ghidra.program.model.symbol.*; import ghidra.program.util.ProgramMemoryUtil; import ghidra.util.InvalidNameException; import ghidra.util.Msg; -import ghidra.util.bytesearch.GenericByteSequencePattern; -import ghidra.util.bytesearch.GenericMatchAction; -import ghidra.util.bytesearch.Match; -import ghidra.util.bytesearch.MemoryBytePatternSearcher; +import ghidra.util.bytesearch.*; import ghidra.util.datastruct.ListAccumulator; -import ghidra.util.exception.CancelledException; -import ghidra.util.exception.DuplicateNameException; -import ghidra.util.exception.InvalidInputException; +import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; public class RecoveredClassHelper { @@ -189,34 +122,31 @@ public class RecoveredClassHelper { private static Function atexit = null; List atexitCalledFunctions = new ArrayList(); - GlobalNamespace globalNamespace; - DataTypeManager dataTypeManager; - int defaultPointerSize; - SymbolTable symbolTable; + protected final GlobalNamespace globalNamespace; + protected final DataTypeManager dataTypeManager; + protected final int defaultPointerSize; + protected final SymbolTable symbolTable; - ExtendedFlatProgramAPI extendedFlatAPI; + protected final ExtendedFlatProgramAPI extendedFlatAPI; - DecompilerScriptUtils decompilerUtils; - CategoryPath classDataTypesCategoryPath; + protected final DecompilerScriptUtils decompilerUtils; + protected final CategoryPath classDataTypesCategoryPath; - private TaskMonitor monitor; - private Program program; - ProgramLocation location; - PluginTool tool; - FlatProgramAPI api; - boolean createBookmarks; - boolean useShortTemplates; - boolean nameVfunctions; + protected final TaskMonitor monitor; + protected final Program program; + protected final ServiceProvider serviceProvider; + protected final FlatProgramAPI api; + protected final boolean createBookmarks; + protected final boolean useShortTemplates; + protected final boolean nameVfunctions; - public RecoveredClassHelper(Program program, ProgramLocation location, PluginTool tool, + public RecoveredClassHelper(Program program, ServiceProvider serviceProvider, FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates, - boolean nameVunctions, TaskMonitor monitor) - throws Exception { + boolean nameVunctions, TaskMonitor monitor) throws Exception { this.monitor = monitor; this.program = program; - this.location = location; - this.tool = tool; + this.serviceProvider = serviceProvider; this.api = api; extendedFlatAPI = new ExtendedFlatProgramAPI(program, monitor); @@ -230,7 +160,7 @@ public class RecoveredClassHelper { globalNamespace = (GlobalNamespace) program.getGlobalNamespace(); - decompilerUtils = new DecompilerScriptUtils(program, tool, monitor); + decompilerUtils = new DecompilerScriptUtils(program, serviceProvider, monitor); dataTypeManager = program.getDataTypeManager(); symbolTable = program.getSymbolTable(); @@ -257,9 +187,7 @@ public class RecoveredClassHelper { public void addReferenceToVtableMapping(List
referencesToVftable, Address vftableAddress) throws CancelledException { - Iterator
referencesIterator = referencesToVftable.iterator(); - while (referencesIterator.hasNext()) { - Address vtableReference = referencesIterator.next(); + for (Address vtableReference : referencesToVftable) { monitor.checkCancelled(); vftableRefToVftableMap.put(vtableReference, vftableAddress); } @@ -278,10 +206,8 @@ public class RecoveredClassHelper { Map vftableRefToFunctionMapping) throws CancelledException { Set
keySet = vftableRefToFunctionMapping.keySet(); - Iterator
referencesIterator = keySet.iterator(); - while (referencesIterator.hasNext()) { + for (Address vtableReference : keySet) { monitor.checkCancelled(); - Address vtableReference = referencesIterator.next(); Function function = vftableRefToFunctionMapping.get(vtableReference); if (functionToVftableRefsMap.containsKey(function)) { List
referenceList = functionToVftableRefsMap.get(function); @@ -314,10 +240,8 @@ public class RecoveredClassHelper { public void addFunctionsToClassMapping(List functions, RecoveredClass recoveredClass) throws CancelledException { - Iterator functionIterator = functions.iterator(); - while (functionIterator.hasNext()) { + for (Function function : functions) { monitor.checkCancelled(); - Function function = functionIterator.next(); // if the map already contains a mapping for function and if // the associated class list doesn't contain the new class, then // add the new class and update the mapping @@ -393,26 +317,27 @@ public class RecoveredClassHelper { if (symbol.getParentNamespace().getName().equals(namespaceName)) { Namespace namespace = symbol.getParentNamespace(); Namespace parentNamespace = namespace.getParentNamespace(); - + // make this exact parent-namespace-name is global and is not in yet a further namespace - if (parentNamespace.getName().equals(parentNamespaceName) && parentNamespace.getParentNamespace().isGlobal()) { + if (parentNamespace.getName().equals(parentNamespaceName) && + parentNamespace.getParentNamespace().isGlobal()) { return symbol; } } } return null; } - + /** * Method to return a list symbol in the given namespace which is in the given * parent namespace or null if one is not found * @param parentNamespaceName name of parent namespace * @param namespaceName name of symbol namespace - * @param symbolName name of symbol * @return Symbol with given name, namespace and parent namespace or null if doesn't exist * @throws CancelledException if cancelled */ - public List getSymbolsInNamespaces(String parentNamespaceName, String namespaceName) throws CancelledException { + public List getSymbolsInNamespaces(String parentNamespaceName, String namespaceName) + throws CancelledException { List symbolsInNamespace = new ArrayList(); SymbolIterator symbols = program.getSymbolTable().getAllSymbols(false); @@ -453,7 +378,7 @@ public class RecoveredClassHelper { } return null; } - + public List getSymbolsContainingBothStrings(String string1, String string2) throws CancelledException { @@ -465,14 +390,14 @@ public class RecoveredClassHelper { while (symbols.hasNext()) { monitor.checkCancelled(); Symbol symbol = symbols.next(); - + if (symbol.getName().contains(string2)) { symbolList.add(symbol); } } - + return symbolList; - + } /** @@ -584,7 +509,6 @@ public class RecoveredClassHelper { } - public Set getAllPossibleConstructorDestructors(List
vftables) throws CancelledException { @@ -678,10 +602,8 @@ public class RecoveredClassHelper { List classes = new ArrayList(); - Iterator
iterator = vftableReferences.iterator(); - while (iterator.hasNext()) { + for (Address vftableReference : vftableReferences) { monitor.checkCancelled(); - Address vftableReference = iterator.next(); Address vftableAddress = vftableRefToVftableMap.get(vftableReference); RecoveredClass recoveredClass = vftableToClassMap.get(vftableAddress); if (!classes.contains(recoveredClass)) { @@ -712,11 +634,8 @@ public class RecoveredClassHelper { Collections.sort(vftableReferenceList); - Iterator
vftableRefs = vftableReferenceList.iterator(); - while (vftableRefs.hasNext()) { + for (Address vftableRef : vftableReferenceList) { monitor.checkCancelled(); - Address vftableRef = vftableRefs.next(); - Address vftableAddress = vftableRefToVftableMap.get(vftableRef); if (vftableAddress == null) { continue; @@ -751,17 +670,14 @@ public class RecoveredClassHelper { Map referenceToClassMapForFunction = getReferenceToClassMap(recoveredClass, function); - // get a list of all ancestor classes referenced in the map List classHierarchy = recoveredClass.getClassHierarchy(); // make a list of all related class references List
listOfAncestorRefs = new ArrayList
(); Set
ancestorRefs = referenceToClassMapForFunction.keySet(); - Iterator
ancestorRefIterator = ancestorRefs.iterator(); - while (ancestorRefIterator.hasNext()) { + for (Address ancestorRef : ancestorRefs) { monitor.checkCancelled(); - Address ancestorRef = ancestorRefIterator.next(); RecoveredClass mappedClass = referenceToClassMapForFunction.get(ancestorRef); if (classHierarchy.contains(mappedClass)) { listOfAncestorRefs.add(ancestorRef); @@ -793,12 +709,10 @@ public class RecoveredClassHelper { } // iterate through all vftable refs in the function and add it to ref/Parent map - Iterator
vftableRefIterator = vftableRefs.iterator(); - while (vftableRefIterator.hasNext()) { + for (Address vftableRef : vftableRefs) { monitor.checkCancelled(); - Address vftableRef = vftableRefIterator.next(); Address vftableAddress = extendedFlatAPI.getSingleReferencedAddress(vftableRef); if (vftableAddress == null) { @@ -886,12 +800,10 @@ public class RecoveredClassHelper { List
vftableRefList = new ArrayList
(vftableRefs); Collections.sort(vftableRefList); - Iterator
vftableRefIterator = vftableRefList.iterator(); RecoveredClass lastClass = null; Address lastVftableRef = null; - while (vftableRefIterator.hasNext()) { + for (Address vftableRef : vftableRefList) { monitor.checkCancelled(); - Address vftableRef = vftableRefIterator.next(); RecoveredClass currentClass = map.get(vftableRef); if (lastClass != null && lastClass.equals(currentClass)) { @@ -952,10 +864,8 @@ public class RecoveredClassHelper { new ArrayList(recoveredClass.getClassHierarchyMap().keySet()); // try direct parents first - Iterator parentsIterator = parentClasses.iterator(); - while (parentsIterator.hasNext()) { + for (RecoveredClass parentClass : parentClasses) { monitor.checkCancelled(); - RecoveredClass parentClass = parentsIterator.next(); List constructorDestructorList = new ArrayList(parentClass.getConstructorList()); constructorDestructorList.addAll(parentClass.getDestructorList()); @@ -1022,11 +932,10 @@ public class RecoveredClassHelper { throws CancelledException { if (storedPcodeOps.size() > 0) { - Iterator iterator = storedPcodeOps.iterator(); + // figure out if vftable is referenced - while (iterator.hasNext()) { + for (OffsetPcodeOpPair offsetPcodeOpPair : storedPcodeOps) { monitor.checkCancelled(); - OffsetPcodeOpPair offsetPcodeOpPair = iterator.next(); PcodeOp pcodeOp = offsetPcodeOpPair.getPcodeOp(); Varnode storedValue = pcodeOp.getInput(2); Address vftableAddress = decompilerUtils.getAssignedAddressFromPcode(storedValue); @@ -1079,11 +988,8 @@ public class RecoveredClassHelper { } return true; } - Iterator functionClassesIterator = functionClasses.iterator(); - while (functionClassesIterator.hasNext()) { + for (RecoveredClass recoveredClass : functionClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = functionClassesIterator.next(); - if (recoveredClass.getInlinedDestructorList().contains(function)) { return true; } @@ -1228,21 +1134,23 @@ public class RecoveredClassHelper { // add the other high variables that store vftable pointer highVariables .addAll(getVariableThatStoresVftablePointer(highFunction, firstVftableReference)); - Iterator highVariableIterator = highVariables.iterator(); + + DecompileOptions decompileOptions = + DecompilerUtils.getDecompileOptions(serviceProvider, program); + FillOutStructureHelper fillStructHelper = + new FillOutStructureHelper(program, decompileOptions, monitor); Address vftableAddress = null; - while (highVariableIterator.hasNext()) { + for (HighVariable highVariable : highVariables) { - HighVariable highVariable = highVariableIterator.next(); monitor.checkCancelled(); - FillOutStructureCmd fillCmd = new FillOutStructureCmd(program, location, tool); + Structure structure = + fillStructHelper.processStructure(highVariable, function, true, false); - Structure structure = fillCmd.processStructure(highVariable, function); + NoisyStructureBuilder componentMap = fillStructHelper.getComponentMap(); - NoisyStructureBuilder componentMap = fillCmd.getComponentMap(); - - List stores = fillCmd.getStorePcodeOps(); + List stores = fillStructHelper.getStorePcodeOps(); stores = removePcodeOpsNotInFunction(function, stores); // this method checks the storedPcodeOps to see if one is the desired vftable address @@ -1255,7 +1163,7 @@ public class RecoveredClassHelper { recoveredClass.updateClassMemberStructureUndefineds(componentMap); } - List loads = fillCmd.getLoadPcodeOps(); + List loads = fillStructHelper.getLoadPcodeOps(); loads = removePcodeOpsNotInFunction(function, loads); //functionToStorePcodeOps.put(function, stores); @@ -1372,11 +1280,8 @@ public class RecoveredClassHelper { public boolean isClassAnAncestorOfAnyOnList(List recoveredClasses, RecoveredClass possibleAncestor) throws Exception { - Iterator classIterator = recoveredClasses.iterator(); - while (classIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = classIterator.next(); - if (isClassAnAncestor(recoveredClass, possibleAncestor)) { return true; } @@ -1487,10 +1392,8 @@ public class RecoveredClassHelper { List classesWithVFunctions = new ArrayList(); - Iterator classIterator = recoveredClasses.iterator(); - while (classIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = classIterator.next(); if (recoveredClass.hasVftable()) { classesWithVFunctions.add(recoveredClass); } @@ -1521,12 +1424,10 @@ public class RecoveredClassHelper { List parentClassList = new ArrayList(classHierarchyMap.keySet()); - Iterator parentIterator = parentClassList.iterator(); - while (parentIterator.hasNext()) { + for (RecoveredClass parentClass : parentClassList) { monitor.checkCancelled(); - RecoveredClass parentClass = parentIterator.next(); if (parentClass.hasVftable()) { parentsWithVFunctions.add(parentClass); } @@ -1553,12 +1454,10 @@ public class RecoveredClassHelper { List classHierarchyList = recoveredClass.getClassHierarchy(); - Iterator ancestorIterator = classHierarchyList.iterator(); - while (ancestorIterator.hasNext()) { + for (RecoveredClass parentClass : classHierarchyList) { monitor.checkCancelled(); - RecoveredClass parentClass = ancestorIterator.next(); if (parentClass.hasVftable()) { ancestorsWithVFunctions.add(parentClass); } @@ -1580,12 +1479,8 @@ public class RecoveredClassHelper { List classHierarchy = recoveredClass.getClassHierarchy(); - Iterator hierarchyIterator = classHierarchy.iterator(); - - while (hierarchyIterator.hasNext()) { + for (RecoveredClass ancestorClass : classHierarchy) { monitor.checkCancelled(); - RecoveredClass ancestorClass = hierarchyIterator.next(); - // skip self if (ancestorClass.equals(recoveredClass)) { continue; @@ -1607,10 +1502,8 @@ public class RecoveredClassHelper { public boolean hasNonVirtualFunctionAncestor(RecoveredClass recoveredClass) throws CancelledException { List classHierarchy = recoveredClass.getClassHierarchy(); - Iterator recoveredClassIterator = classHierarchy.iterator(); - while (recoveredClassIterator.hasNext()) { + for (RecoveredClass currentClass : classHierarchy) { monitor.checkCancelled(); - RecoveredClass currentClass = recoveredClassIterator.next(); if (!currentClass.hasVftable()) { return true; } @@ -1628,17 +1521,15 @@ public class RecoveredClassHelper { throws CancelledException { List allAncestorConstructors = new ArrayList(); - - List classHierarchy = recoveredClass.getClassHierarchy(); - if(classHierarchy == null) { - Msg.debug(this, recoveredClass.getName() + " has null class hierarchy list"); + if (classHierarchy == null) { + Msg.debug(this, recoveredClass.getName() + " has null class hierarchy list"); return allAncestorConstructors; } - - if(classHierarchy.isEmpty()) { - Msg.debug(this, recoveredClass.getName() + " has empty class hierarchy list"); + + if (classHierarchy.isEmpty()) { + Msg.debug(this, recoveredClass.getName() + " has empty class hierarchy list"); return allAncestorConstructors; } ListIterator classHierarchyIterator = classHierarchy.listIterator(1); @@ -1650,10 +1541,8 @@ public class RecoveredClassHelper { List constructorList = new ArrayList(currentClass.getConstructorList()); constructorList.addAll(currentClass.getInlinedConstructorList()); - Iterator constructors = constructorList.iterator(); - while (constructors.hasNext()) { + for (Function constructor : constructorList) { monitor.checkCancelled(); - Function constructor = constructors.next(); if (!allAncestorConstructors.contains(constructor)) { allAncestorConstructors.add(constructor); } @@ -1674,17 +1563,17 @@ public class RecoveredClassHelper { List allAncestorDestructors = new ArrayList(); List classHierarchy = recoveredClass.getClassHierarchy(); - - if(classHierarchy == null) { - Msg.debug(this, recoveredClass.getName() + " has null class hierarchy list"); + + if (classHierarchy == null) { + Msg.debug(this, recoveredClass.getName() + " has null class hierarchy list"); return allAncestorDestructors; } - - if(classHierarchy.isEmpty()) { - Msg.debug(this, recoveredClass.getName() + " has empty class hierarchy list"); + + if (classHierarchy.isEmpty()) { + Msg.debug(this, recoveredClass.getName() + " has empty class hierarchy list"); return allAncestorDestructors; } - + ListIterator classHierarchyIterator = classHierarchy.listIterator(1); while (classHierarchyIterator.hasNext()) { @@ -1694,10 +1583,8 @@ public class RecoveredClassHelper { List destructorList = new ArrayList(parentClass.getDestructorList()); destructorList.addAll(parentClass.getInlinedDestructorList()); - Iterator destructors = destructorList.iterator(); - while (destructors.hasNext()) { + for (Function destructor : destructorList) { monitor.checkCancelled(); - Function destructor = destructors.next(); if (!allAncestorDestructors.contains(destructor)) { allAncestorDestructors.add(destructor); } @@ -1718,18 +1605,13 @@ public class RecoveredClassHelper { List allDescendantConstructors = new ArrayList(); List childClasses = recoveredClass.getChildClasses(); - Iterator childClassIterator = childClasses.iterator(); - while (childClassIterator.hasNext()) { + for (RecoveredClass childClass : childClasses) { monitor.checkCancelled(); - RecoveredClass childClass = childClassIterator.next(); - List constructorList = new ArrayList(childClass.getConstructorList()); constructorList.addAll(childClass.getInlinedConstructorList()); - Iterator constructors = constructorList.iterator(); - while (constructors.hasNext()) { + for (Function constructor : constructorList) { monitor.checkCancelled(); - Function constructor = constructors.next(); if (!allDescendantConstructors.contains(constructor)) { allDescendantConstructors.add(constructor); } @@ -1752,17 +1634,12 @@ public class RecoveredClassHelper { List allDescendantDestructors = new ArrayList(); List childClasses = recoveredClass.getChildClasses(); - Iterator childClassIterator = childClasses.iterator(); - while (childClassIterator.hasNext()) { + for (RecoveredClass childClass : childClasses) { monitor.checkCancelled(); - RecoveredClass childClass = childClassIterator.next(); - List destructorList = new ArrayList(childClass.getDestructorList()); destructorList.addAll(childClass.getInlinedDestructorList()); - Iterator destructors = destructorList.iterator(); - while (destructors.hasNext()) { + for (Function destructor : destructorList) { monitor.checkCancelled(); - Function destructor = destructors.next(); if (!allDescendantDestructors.contains(destructor)) { allDescendantDestructors.add(destructor); } @@ -1941,12 +1818,9 @@ public class RecoveredClassHelper { List childConstructors = getAllClassConstructors(recoveredClass); List childDestructors = getAllClassDestructors(recoveredClass); - Iterator constDestIterator = constDestFunctions.iterator(); - while (constDestIterator.hasNext()) { + for (Function constDestFunction : constDestFunctions) { monitor.checkCancelled(); - Function constDestFunction = constDestIterator.next(); - // based on call order get possible parent constructors for the given function List possibleParentConstructors = getPossibleParentConstructors(constDestFunction); @@ -1999,10 +1873,8 @@ public class RecoveredClassHelper { // once all checks pass, add both the child and parent constructors to their class // constructor list and remove from the indeterminate lists // the addConstructor method processes the offsets and types for the initialized class data - Iterator childConstructorIterator = constructorKeySet.iterator(); - while (childConstructorIterator.hasNext()) { + for (Function childConstructor : constructorKeySet) { monitor.checkCancelled(); - Function childConstructor = childConstructorIterator.next(); addConstructorToClass(recoveredClass, childConstructor); recoveredClass.removeIndeterminateConstructorOrDestructor(childConstructor); Function parentConstructor = childParentConstructorMap.get(childConstructor); @@ -2011,10 +1883,8 @@ public class RecoveredClassHelper { } // Do the same for the child/parent destructors - Iterator childDestructorIterator = destructorKeySet.iterator(); - while (childDestructorIterator.hasNext()) { + for (Function childDestructor : destructorKeySet) { monitor.checkCancelled(); - Function childDestructor = childDestructorIterator.next(); addDestructorToClass(recoveredClass, childDestructor); recoveredClass.removeIndeterminateConstructorOrDestructor(childDestructor); Function parentDestructor = childParentDestructorMap.get(childDestructor); @@ -2162,10 +2032,8 @@ public class RecoveredClassHelper { Collections.sort(offsetList); int order = 0; - Iterator offsetIterator = offsetList.iterator(); - while (offsetIterator.hasNext()) { + for (Integer offset : offsetList) { monitor.checkCancelled(); - Integer offset = offsetIterator.next(); Address vftableAddress = classOffsetToVftableMap.get(offset); recoveredClass.addOrderToVftableMapping(order, vftableAddress); order++; @@ -2179,12 +2047,8 @@ public class RecoveredClassHelper { */ public void createVftableOrderMap(List recoveredClasses) throws CancelledException { - Iterator recoveredClassIterator = recoveredClasses.iterator(); - - while (recoveredClassIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = recoveredClassIterator.next(); - // create a mapping of the order of the vftable to the vftable address and save to class createVftableOrderMapping(recoveredClass); } @@ -2203,11 +2067,9 @@ public class RecoveredClassHelper { List
referencesToConstructors) throws CancelledException, InvalidInputException, DuplicateNameException, CircularDependencyException { - Iterator
constructorIterator = referencesToConstructors.iterator(); - while (constructorIterator.hasNext()) { + for (Address constructorReference : referencesToConstructors) { monitor.checkCancelled(); - Address constructorReference = constructorIterator.next(); RecoveredClass recoveredClass = referenceToClassMap.get(constructorReference); Function constructor = @@ -2248,10 +2110,8 @@ public class RecoveredClassHelper { List
referencesToVftables = new ArrayList
(); List
referenceAddresses = new ArrayList
(referenceToClassMap.keySet()); - Iterator
referenceIterator = referenceAddresses.iterator(); - while (referenceIterator.hasNext()) { + for (Address reference : referenceAddresses) { monitor.checkCancelled(); - Address reference = referenceIterator.next(); Address vftableAddress = getVftableAddress(reference); if (vftableAddress != null) { referencesToVftables.add(reference); @@ -2267,10 +2127,8 @@ public class RecoveredClassHelper { int numRefs = referencesToVftables.size(); Address lastRef = referencesToVftables.get(numRefs - 1); - Iterator
refToVtablesIterator = referencesToVftables.iterator(); - while (refToVtablesIterator.hasNext()) { + for (Address refToVftable : referencesToVftables) { monitor.checkCancelled(); - Address refToVftable = refToVtablesIterator.next(); RecoveredClass referencedClass = referenceToClassMap.get(refToVftable); // last reference is the constructor @@ -2309,10 +2167,8 @@ public class RecoveredClassHelper { List
referencesToVftables = new ArrayList
(); List
referenceAddresses = new ArrayList
(referenceToClassMap.keySet()); - Iterator
referenceIterator = referenceAddresses.iterator(); - while (referenceIterator.hasNext()) { + for (Address reference : referenceAddresses) { monitor.checkCancelled(); - Address reference = referenceIterator.next(); Address vftableAddress = getVftableAddress(reference); if (vftableAddress != null) { referencesToVftables.add(reference); @@ -2329,10 +2185,8 @@ public class RecoveredClassHelper { int numRefs = referencesToVftables.size(); Address lastRef = referencesToVftables.get(numRefs - 1); - Iterator
refToVtablesIterator = referencesToVftables.iterator(); - while (refToVtablesIterator.hasNext()) { + for (Address refToVftable : referencesToVftables) { monitor.checkCancelled(); - Address refToVftable = refToVtablesIterator.next(); RecoveredClass referencedClass = referenceToClassMap.get(refToVftable); // last reference is the constructor @@ -2448,8 +2302,6 @@ public class RecoveredClassHelper { return false; } - - /** * Method to get the total number of constructors in the given list of classes * @param recoveredClasses list of classes to process @@ -2460,10 +2312,8 @@ public class RecoveredClassHelper { throws CancelledException { int total = 0; - Iterator classIterator = recoveredClasses.iterator(); - while (classIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = classIterator.next(); List constructorList = recoveredClass.getConstructorList(); total += constructorList.size(); } @@ -2480,11 +2330,8 @@ public class RecoveredClassHelper { throws CancelledException { int total = 0; - Iterator classIterator = recoveredClasses.iterator(); - while (classIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = classIterator.next(); - int numDestructors = recoveredClass.getDestructorList().size(); total += numDestructors; } @@ -2501,11 +2348,8 @@ public class RecoveredClassHelper { throws CancelledException { int total = 0; - Iterator classIterator = recoveredClasses.iterator(); - while (classIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = classIterator.next(); - int numInlinedDestructors = recoveredClass.getInlinedDestructorList().size(); total += numInlinedDestructors; } @@ -2522,11 +2366,8 @@ public class RecoveredClassHelper { throws CancelledException { int total = 0; - Iterator classIterator = recoveredClasses.iterator(); - while (classIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = classIterator.next(); - List deletingDestructors = recoveredClass.getDeletingDestructors(); total += deletingDestructors.size(); } @@ -2543,10 +2384,8 @@ public class RecoveredClassHelper { throws CancelledException { int total = 0; - Iterator classIterator = recoveredClasses.iterator(); - while (classIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = classIterator.next(); List cloneFunctions = recoveredClass.getCloneFunctions(); total += cloneFunctions.size(); } @@ -2563,11 +2402,8 @@ public class RecoveredClassHelper { throws CancelledException { int total = 0; - Iterator classIterator = recoveredClasses.iterator(); - while (classIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = classIterator.next(); - Function cloneFunction = recoveredClass.getVBaseDestructor(); if (cloneFunction != null) { total++; @@ -2586,11 +2422,8 @@ public class RecoveredClassHelper { throws CancelledException { int total = 0; - Iterator classIterator = recoveredClasses.iterator(); - while (classIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = classIterator.next(); - List vfunctionList = recoveredClass.getAllVirtualFunctions(); if (vfunctionList == null) { continue; @@ -2614,11 +2447,8 @@ public class RecoveredClassHelper { throws CancelledException { List remainingIndeterminates = new ArrayList(); - Iterator classIterator = recoveredClasses.iterator(); - while (classIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = classIterator.next(); - List indeterminateConstructorOrDestructorList = recoveredClass.getIndeterminateList(); remainingIndeterminates.addAll(indeterminateConstructorOrDestructorList); @@ -2642,15 +2472,12 @@ public class RecoveredClassHelper { List
referencesToDestructors) throws CancelledException, InvalidInputException, DuplicateNameException { - Iterator
destructorIterator = referencesToDestructors.iterator(); - while (destructorIterator.hasNext()) { + for (Address destructorReference : referencesToDestructors) { monitor.checkCancelled(); - Address destructorReference = destructorIterator.next(); RecoveredClass recoveredClass = referenceToClassMap.get(destructorReference); - Function destructor = - extendedFlatAPI.getReferencedFunction(destructorReference, true); + Function destructor = extendedFlatAPI.getReferencedFunction(destructorReference, true); if (recoveredClass.getIndeterminateList().contains(destructor)) { addDestructorToClass(recoveredClass, destructor); @@ -2676,10 +2503,8 @@ public class RecoveredClassHelper { List recoveredClasses) throws CancelledException, InvalidInputException, DuplicateNameException, CircularDependencyException { - Iterator recoveredClassIterator = recoveredClasses.iterator(); - while (recoveredClassIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = recoveredClassIterator.next(); List indeterminateFunctions = recoveredClass.getIndeterminateList(); Iterator functionIterator = indeterminateFunctions.iterator(); while (functionIterator.hasNext()) { @@ -2706,8 +2531,6 @@ public class RecoveredClassHelper { } } - - /** * Method to determine if a class's identified vbase_destructor is valid or not @@ -2752,10 +2575,8 @@ public class RecoveredClassHelper { throws CancelledException { if (recoveredClass.hasChildClass()) { List childClasses = recoveredClass.getChildClasses(); - Iterator childIterator = childClasses.iterator(); - while (childIterator.hasNext()) { + for (RecoveredClass childClass : childClasses) { monitor.checkCancelled(); - RecoveredClass childClass = childIterator.next(); if (childClass.getDestructorList().size() == 1 && childClass.getVBaseDestructor() != null) { return true; @@ -2777,8 +2598,8 @@ public class RecoveredClassHelper { String className = namespace.getName(); - CategoryPath classPath = extendedFlatAPI - .createDataTypeCategoryPath(classDataTypesCategoryPath, namespace); + CategoryPath classPath = + extendedFlatAPI.createDataTypeCategoryPath(classDataTypesCategoryPath, namespace); RecoveredClass newClass = new RecoveredClass(className, classPath, namespace, dataTypeManager); @@ -2814,10 +2635,8 @@ public class RecoveredClassHelper { List recoveredClasses = new ArrayList(); - Iterator vftableSymbolsIterator = vftableSymbolList.iterator(); - while (vftableSymbolsIterator.hasNext()) { + for (Symbol vftableSymbol : vftableSymbolList) { monitor.checkCancelled(); - Symbol vftableSymbol = vftableSymbolsIterator.next(); Address vftableAddress = vftableSymbol.getAddress(); // Get class name from class vftable is in @@ -2888,7 +2707,7 @@ public class RecoveredClassHelper { } // end of looping over vfTables return recoveredClasses; } - + //TODO: rework above method to call this so it works with both that and other calls protected void updateClassWithVftable(RecoveredClass recoveredClass, Symbol vftableSymbol, boolean allowNullFunctionPtrs, boolean allowDefaultRefsInMiddle) throws Exception { @@ -2899,8 +2718,8 @@ public class RecoveredClassHelper { Address vftableAddress = vftableSymbol.getAddress(); Namespace vftableNamespace = vftableSymbol.getParentNamespace(); - List virtualFunctions = getFunctionsFromVftable(vftableAddress, vftableSymbol, allowNullFunctionPtrs, - allowDefaultRefsInMiddle); + List virtualFunctions = getFunctionsFromVftable(vftableAddress, vftableSymbol, + allowNullFunctionPtrs, allowDefaultRefsInMiddle); // the vftable has already been processed - skip it if (virtualFunctions == null) { @@ -2919,7 +2738,8 @@ public class RecoveredClassHelper { // add it to the running list of RecoveredClass objects // recoveredClasses.add(recoveredClass); - } else { + } + else { recoveredClass.addVftableAddress(vftableAddress); recoveredClass.addVftableVfunctionsMapping(vftableAddress, virtualFunctions); // if (!recoveredClasses.contains(recoveredClass)) { @@ -2934,12 +2754,12 @@ public class RecoveredClassHelper { List
referencesToVftable = getReferencesToVftable(vftableAddress); addReferenceToVtableMapping(referencesToVftable, vftableAddress); - Map vftableReferenceToFunctionMapping = createVftableReferenceToFunctionMapping( - referencesToVftable); + Map vftableReferenceToFunctionMapping = + createVftableReferenceToFunctionMapping(referencesToVftable); // vftableReferenceToFunctionMapping - List possibleConstructorDestructorsForThisClass = findPossibleConstructorDestructors( - vftableReferenceToFunctionMapping); + List possibleConstructorDestructorsForThisClass = + findPossibleConstructorDestructors(vftableReferenceToFunctionMapping); addFunctionsToClassMapping(possibleConstructorDestructorsForThisClass, recoveredClass); @@ -2948,7 +2768,8 @@ public class RecoveredClassHelper { // add the possible constructor/destructor list to the class recoveredClass.addConstructorDestructorList(possibleConstructorDestructorsForThisClass); - recoveredClass.addIndeterminateConstructorOrDestructorList(possibleConstructorDestructorsForThisClass); + recoveredClass.addIndeterminateConstructorOrDestructorList( + possibleConstructorDestructorsForThisClass); // } // end of looping over vfTables } @@ -2956,11 +2777,9 @@ public class RecoveredClassHelper { public void promoteClassNamespaces(List recoveredClasses) throws CancelledException { - Iterator classIterator = recoveredClasses.iterator(); - while (classIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = classIterator.next(); Namespace classNamespace = recoveredClass.getClassNamespace(); promoteNamespaces(classNamespace); } @@ -3039,10 +2858,8 @@ public class RecoveredClassHelper { List
referencesToVftable) throws CancelledException { Map vftableRefToFunctionMapping = new HashMap(); - Iterator
referencesIterator = referencesToVftable.iterator(); - while (referencesIterator.hasNext()) { + for (Address vftableReference : referencesToVftable) { monitor.checkCancelled(); - Address vftableReference = referencesIterator.next(); Function functionContaining = extendedFlatAPI.getFunctionContaining(vftableReference); if (functionContaining != null) { vftableRefToFunctionMapping.put(vftableReference, functionContaining); @@ -3063,10 +2880,8 @@ public class RecoveredClassHelper { List cdFunctions = new ArrayList(); Set
keySet = vftableReferenceToFunctionMapping.keySet(); - Iterator
referencesIterator = keySet.iterator(); - while (referencesIterator.hasNext()) { + for (Address vtableReference : keySet) { monitor.checkCancelled(); - Address vtableReference = referencesIterator.next(); Function function = vftableReferenceToFunctionMapping.get(vtableReference); if (!cdFunctions.contains(function)) { cdFunctions.add(function); @@ -3075,7 +2890,6 @@ public class RecoveredClassHelper { return cdFunctions; } - /** * Method to get functions from vftable * @param vftableAddress the address of the vftable @@ -3228,10 +3042,8 @@ public class RecoveredClassHelper { List
notInFunctionVftableRefs = new ArrayList
(); List
newFunctions = new ArrayList
(); - Iterator vftableSymbolIterator = vftableSymbols.iterator(); - while (vftableSymbolIterator.hasNext()) { + for (Symbol vftableSymbol : vftableSymbols) { monitor.checkCancelled(); - Symbol vftableSymbol = vftableSymbolIterator.next(); Address vftableAddress = vftableSymbol.getAddress(); vftableAddresses.add(vftableAddress); @@ -3246,12 +3058,9 @@ public class RecoveredClassHelper { searcher.search(program, searchSet, monitor); // check existing refs to see if in instruction but not in function - Iterator
vftableAddressIterator = vftableAddresses.iterator(); - while (vftableAddressIterator.hasNext()) { + for (Address vftableAddress : vftableAddresses) { monitor.checkCancelled(); - Address vftableAddress = vftableAddressIterator.next(); - ReferenceIterator referencesIterator = program.getReferenceManager().getReferencesTo(vftableAddress); @@ -3372,10 +3181,8 @@ public class RecoveredClassHelper { Map parentToBaseTypeMap = recoveredClass.getParentToBaseTypeMap(); Set ancestors = parentToBaseTypeMap.keySet(); - Iterator ancestorIterator = ancestors.iterator(); - while (ancestorIterator.hasNext()) { + for (RecoveredClass ancestor : ancestors) { monitor.checkCancelled(); - RecoveredClass ancestor = ancestorIterator.next(); if (directParents.contains(ancestor)) { Boolean isVirtualParent = parentToBaseTypeMap.get(ancestor); @@ -3460,12 +3267,8 @@ public class RecoveredClassHelper { String className = recoveredClass.getName(); List constructorList = recoveredClass.getConstructorList(); - Iterator constructorsIterator = constructorList.iterator(); - - while (constructorsIterator.hasNext()) { + for (Function constructorFunction : constructorList) { monitor.checkCancelled(); - Function constructorFunction = constructorsIterator.next(); - // cannot edit external functions if (constructorFunction.isExternal()) { continue; @@ -3553,11 +3356,8 @@ public class RecoveredClassHelper { String className = recoveredClass.getName(); List destructorList = recoveredClass.getDestructorList(); - Iterator destructorIterator = destructorList.iterator(); - while (destructorIterator.hasNext()) { + for (Function destructorFunction : destructorList) { monitor.checkCancelled(); - Function destructorFunction = destructorIterator.next(); - // cannot edit external functions if (destructorFunction.isExternal()) { continue; @@ -3585,11 +3385,8 @@ public class RecoveredClassHelper { String className = recoveredClass.getName(); List nonThisDestructorList = recoveredClass.getNonThisDestructors(); - Iterator destructorIterator = nonThisDestructorList.iterator(); - while (destructorIterator.hasNext()) { + for (Function destructorFunction : nonThisDestructorList) { monitor.checkCancelled(); - Function destructorFunction = destructorIterator.next(); - // cannot edit external functions if (destructorFunction.isExternal()) { continue; @@ -3683,10 +3480,8 @@ public class RecoveredClassHelper { } //put the same name one in the namespace else { - Iterator iterator = symbolsByNameAtAddress.iterator(); - while (iterator.hasNext()) { + for (Symbol sameNameSymbol : symbolsByNameAtAddress) { monitor.checkCancelled(); - Symbol sameNameSymbol = iterator.next(); sameNameSymbol.setNamespace(namespace); } } @@ -3730,7 +3525,6 @@ public class RecoveredClassHelper { } } - /** * Method to create a new symbol at the given function * @param function the given function @@ -3797,10 +3591,8 @@ public class RecoveredClassHelper { } //put the same name one in the namespace else { - Iterator iterator = symbolsByNameAtAddress.iterator(); - while (iterator.hasNext()) { + for (Symbol sameNameSymbol : symbolsByNameAtAddress) { monitor.checkCancelled(); - Symbol sameNameSymbol = iterator.next(); sameNameSymbol.setNamespace(namespace); } } @@ -3925,10 +3717,8 @@ public class RecoveredClassHelper { // find all functions that call this function and do the same fixBadSignatures(function, badStructureDataTypes); // add all the new bad dts to the list of bad ones - Iterator badStructuresIterator = badStructureDataTypes.iterator(); - while (badStructuresIterator.hasNext()) { + for (Structure structure : badStructureDataTypes) { monitor.checkCancelled(); - Structure structure = badStructuresIterator.next(); if (!badFIDStructures.contains(structure)) { badFIDStructures.add(structure); } @@ -3969,10 +3759,8 @@ public class RecoveredClassHelper { callingFunctions.addAll(moreCallingFunctions); } - Iterator functionsToFixIterator = allFunctionsToFix.iterator(); - while (functionsToFixIterator.hasNext()) { + for (Function functionToFix : allFunctionsToFix) { monitor.checkCancelled(); - Function functionToFix = functionsToFixIterator.next(); if (!functionToFix.isThunk()) { removeBadReturnType(functionToFix, badStructureDataTypes); @@ -4250,12 +4038,9 @@ public class RecoveredClassHelper { public void findBasicCloneFunctions(List recoveredClasses) throws CancelledException { - Iterator recoveredClassIterator = recoveredClasses.iterator(); - while (recoveredClassIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = recoveredClassIterator.next(); - List constructorList = recoveredClass.getConstructorList(); List allVirtualFunctions = recoveredClass.getAllVirtualFunctions(); @@ -4330,11 +4115,8 @@ public class RecoveredClassHelper { */ public void removeEmptyClassesAndStructures() throws CancelledException { - Iterator badNamespaceIterator = badFIDNamespaces.iterator(); - while (badNamespaceIterator.hasNext()) { + for (Namespace badNamespace : badFIDNamespaces) { monitor.checkCancelled(); - Namespace badNamespace = badNamespaceIterator.next(); - // global namespace shouldn't be on list but check anyway if (badNamespace.isGlobal()) { continue; @@ -4377,13 +4159,10 @@ public class RecoveredClassHelper { */ private void removeEmptyStructures() throws CancelledException { - Iterator badStructureIterator = badFIDStructures.iterator(); - while (badStructureIterator.hasNext()) { + for (Structure badStructure : badFIDStructures) { monitor.checkCancelled(); - // if not used by anything remove it - Structure badStructure = badStructureIterator.next(); ListAccumulator accumulator = new ListAccumulator<>(); boolean discoverTypes = true; @@ -4559,17 +4338,14 @@ public class RecoveredClassHelper { CategoryPath classPath = recoveredClass.getClassPath(); List
vftableAddresses = recoveredClass.getVftableAddresses(); - Iterator
vftableAddressIterator = vftableAddresses.iterator(); - - while (vftableAddressIterator.hasNext()) { + for (Address vftableAddress : vftableAddresses) { monitor.checkCancelled(); - Address vftableAddress = vftableAddressIterator.next(); - PointerDataType vftablePointerDataType = (PointerDataType) vftableToStructureMap.get(vftableAddress); - - if(vftablePointerDataType == null) { - Msg.debug(this, "vftablePointerDataType is null for vftableAddress: " + vftableAddress); + + if (vftablePointerDataType == null) { + Msg.debug(this, + "vftablePointerDataType is null for vftableAddress: " + vftableAddress); } DataType vftableDataType = vftablePointerDataType.getDataType(); @@ -4587,13 +4363,9 @@ public class RecoveredClassHelper { List vFunctions = recoveredClass.getVirtualFunctions(vftableAddress); int vfunctionNumber = 1; - Iterator vfIterator = vFunctions.iterator(); - - while (vfIterator.hasNext()) { + for (Function vfunction : vFunctions) { monitor.checkCancelled(); - Function vfunction = vfIterator.next(); - if (vfunction == null) { Pointer nullPointer = dataTypeManager.getPointer(DataType.DEFAULT); vftableStruct.add(nullPointer, "null pointer", null); @@ -4775,9 +4547,6 @@ public class RecoveredClassHelper { List deletingDestructors = recoveredClass.getDeletingDestructors(); List cloneFunctions = recoveredClass.getCloneFunctions(); - Iterator vfIterator = - recoveredClass.getVirtualFunctions(vftableAddress).iterator(); - String vfunctionName; int tableEntry = 1; @@ -4785,10 +4554,8 @@ public class RecoveredClassHelper { // string for those with single vftable String vfunctionSuffix = getForClassSuffix(vftableStructureName); - while (vfIterator.hasNext()) { + for (Function vfunction : recoveredClass.getVirtualFunctions(vftableAddress)) { monitor.checkCancelled(); - Function vfunction = vfIterator.next(); - // create a one-up number for the next virtual function int entryNumber = tableEntry++; @@ -4896,7 +4663,7 @@ public class RecoveredClassHelper { if (function.isThunk()) { continue; } - + PrototypeModel callingConvention = function.getCallingConvention(); if (callingConvention == null) { Msg.debug(this, "no calling convention for: " + function.getEntryPoint()); @@ -4926,15 +4693,15 @@ public class RecoveredClassHelper { newParamList.add(param); } - + FunctionUpdateType updateType = FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS; if (function.hasCustomVariableStorage()) { updateType = FunctionUpdateType.CUSTOM_STORAGE; } newParamList.get(0).setDataType(classStructurePointer, SourceType.ANALYSIS); - function.replaceParameters(newParamList, - updateType, false, SourceType.ANALYSIS); + function.replaceParameters(newParamList, updateType, false, + SourceType.ANALYSIS); } catch (InvalidInputException | DuplicateNameException e) { Msg.error(this, "Could not update function at " + function.getEntryPoint() + @@ -5110,12 +4877,8 @@ public class RecoveredClassHelper { String className = recoveredClass.getName(); List inlinedConstructorList = recoveredClass.getInlinedConstructorList(); - Iterator inlinedConstructorsIterator = inlinedConstructorList.iterator(); - - while (inlinedConstructorsIterator.hasNext()) { + for (Function inlinedFunction : inlinedConstructorList) { monitor.checkCancelled(); - Function inlinedFunction = inlinedConstructorsIterator.next(); - List
listOfClassRefsInFunction = getSortedListOfAncestorRefsInFunction(inlinedFunction, recoveredClass); @@ -5150,10 +4913,8 @@ public class RecoveredClassHelper { String className = recoveredClass.getName(); List inlinedDestructorList = recoveredClass.getInlinedDestructorList(); - Iterator inlinedDestructorIterator = inlinedDestructorList.iterator(); - while (inlinedDestructorIterator.hasNext()) { + for (Function destructorFunction : inlinedDestructorList) { monitor.checkCancelled(); - Function destructorFunction = inlinedDestructorIterator.next(); Address classVftableRef = getFirstClassVftableReference(recoveredClass, destructorFunction); @@ -5178,12 +4939,8 @@ public class RecoveredClassHelper { Namespace classNamespace = recoveredClass.getClassNamespace(); List functionsContainingInlineList = recoveredClass.getIndeterminateInlineList(); - Iterator functionsContainingInlineIterator = - functionsContainingInlineList.iterator(); - while (functionsContainingInlineIterator.hasNext()) { + for (Function functionContainingInline : functionsContainingInlineList) { monitor.checkCancelled(); - Function functionContainingInline = functionsContainingInlineIterator.next(); - Address classVftableRef = getFirstClassVftableReference(recoveredClass, functionContainingInline); @@ -5212,11 +4969,8 @@ public class RecoveredClassHelper { String className = recoveredClass.getName(); List unknownIfConstructorOrDestructorLIst = recoveredClass.getIndeterminateList(); - Iterator unknownsIterator = unknownIfConstructorOrDestructorLIst.iterator(); - while (unknownsIterator.hasNext()) { + for (Function indeterminateFunction : unknownIfConstructorOrDestructorLIst) { monitor.checkCancelled(); - Function indeterminateFunction = unknownsIterator.next(); - // cannot edit external functions if (indeterminateFunction.isExternal()) { continue; @@ -5458,8 +5212,8 @@ public class RecoveredClassHelper { */ private Set findOperatorDeletesUsingCalledCommonFunction( Set allPossibleConstructorDestructorsNew, - Set twoCallCommonFunctions, - List
vftables) throws CancelledException { + Set twoCallCommonFunctions, List
vftables) + throws CancelledException { Set operatorDeletesSet = new HashSet(); HashMap operatorDeleteCountMap = new HashMap(); @@ -5529,8 +5283,8 @@ public class RecoveredClassHelper { private Set findOperatorNewsUsingCalledCommonFunction( Set allPossibleConstructorDestructorsNew, - Set twoCallCommonFunctions, - List
vftables) throws CancelledException { + Set twoCallCommonFunctions, List
vftables) + throws CancelledException { Set operatorNewsSet = new HashSet(); @@ -5628,11 +5382,8 @@ public class RecoveredClassHelper { public void separateInlinedConstructorDestructors(List recoveredClasses) throws CancelledException { - Iterator recoveredClassIterator = recoveredClasses.iterator(); - - while (recoveredClassIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = recoveredClassIterator.next(); List indeterminateFunctions = recoveredClass.getIndeterminateList(); Iterator indeterminateIterator = indeterminateFunctions.iterator(); while (indeterminateIterator.hasNext()) { @@ -5820,11 +5571,9 @@ public class RecoveredClassHelper { Map parentToBaseTypeMap = recoveredClass.getParentToBaseTypeMap(); Set parentClasses = parentToBaseTypeMap.keySet(); - Iterator parentClassIterator = parentClasses.iterator(); - while (parentClassIterator.hasNext()) { + for (RecoveredClass parentClass : parentClasses) { monitor.checkCancelled(); - RecoveredClass parentClass = parentClassIterator.next(); if (parentClass.getName().equals(parentClassName)) { Boolean isVirtualParent = parentToBaseTypeMap.get(parentClass); if (isVirtualParent) { @@ -5886,12 +5635,9 @@ public class RecoveredClassHelper { List virtualParents = new ArrayList(); Set parentClasses = parentToBaseTypeMap.keySet(); - Iterator parentClassIterator = parentClasses.iterator(); - while (parentClassIterator.hasNext()) { + for (RecoveredClass parentClass : parentClasses) { monitor.checkCancelled(); - RecoveredClass parentClass = parentClassIterator.next(); - Boolean isVirtualParent = parentToBaseTypeMap.get(parentClass); if (isVirtualParent) { virtualParents.add(parentClass); @@ -5925,12 +5671,10 @@ public class RecoveredClassHelper { public void findDestructorsWithNoParamsOrReturn(List recoveredClasses) throws CancelledException { - Iterator recoveredClassIterator = recoveredClasses.iterator(); - while (recoveredClassIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = recoveredClassIterator.next(); List indeterminateFunctions = recoveredClass.getIndeterminateList(); Iterator indeterminateIterator = indeterminateFunctions.iterator(); while (indeterminateIterator.hasNext()) { @@ -5964,15 +5708,15 @@ public class RecoveredClassHelper { continue; } - FillOutStructureCmd fillCmd = - runFillOutStructureCmd(indeterminateFunction, firstVftableReference); + FillOutStructureHelper fillStructHelper = + runFillOutStructureHelper(indeterminateFunction, firstVftableReference); - if (fillCmd == null) { + if (fillStructHelper == null) { continue; } - List stores = fillCmd.getStorePcodeOps(); - List loads = fillCmd.getLoadPcodeOps(); + List stores = fillStructHelper.getStorePcodeOps(); + List loads = fillStructHelper.getLoadPcodeOps(); stores = removePcodeOpsNotInFunction(indeterminateFunction, stores); loads = removePcodeOpsNotInFunction(indeterminateFunction, loads); @@ -5999,11 +5743,8 @@ public class RecoveredClassHelper { */ public void findMoreInlinedConstructors(List recoveredClasses) throws CancelledException, InvalidInputException, DuplicateNameException { - Iterator recoveredClassIterator = recoveredClasses.iterator(); - - while (recoveredClassIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = recoveredClassIterator.next(); List constructorList = recoveredClass.getConstructorList(); Iterator constructorIterator = constructorList.iterator(); while (constructorIterator.hasNext()) { @@ -6035,8 +5776,8 @@ public class RecoveredClassHelper { // the constructor function is really another function with the constructor // function inlined in it if (firstVftableReferenceAddress.compareTo(firstEndOfBlock) > 0) { - if (doesFunctionCallAnyNonConstructorsBeforeVtableReference( - recoveredClass, constructor, firstVftableReferenceAddress)) { + if (doesFunctionCallAnyNonConstructorsBeforeVtableReference(recoveredClass, + constructor, firstVftableReferenceAddress)) { // remove from the allConstructors too addInlinedConstructorToClass(recoveredClass, constructor); @@ -6080,16 +5821,16 @@ public class RecoveredClassHelper { } /** - * Method to run the FillOutStructureCmd and return a FillOutStructureCmd object when - * a high variable used to run the cmd is found that stores the given firstVftableReference - * address. + * Method to run the FillOutStructureHelper and return it after processing + * a high variable that stores the given firstVftableReference address. If not found + * a null is returned. * @param function the given function * @param firstVftableReference the first vftableReference in the given function - * @return FillOutStructureCmd for the highVariable that stores the firstVftableReference address - * or null if one isn't found. + * @return FillOutStructureHelper instance for the highVariable that stores the + * firstVftableReference address or null if one isn't found. * @throws CancelledException if cancelled */ - public FillOutStructureCmd runFillOutStructureCmd(Function function, + public FillOutStructureHelper runFillOutStructureHelper(Function function, Address firstVftableReference) throws CancelledException { Address vftableAddress = getVftableAddress(firstVftableReference); @@ -6122,16 +5863,17 @@ public class RecoveredClassHelper { highVariables .addAll(getVariableThatStoresVftablePointer(highFunction, firstVftableReference)); - Iterator highVariableIterator = highVariables.iterator(); + DecompileOptions decompileOptions = + DecompilerUtils.getDecompileOptions(serviceProvider, program); + FillOutStructureHelper fillStructHelper = + new FillOutStructureHelper(program, decompileOptions, monitor); - while (highVariableIterator.hasNext()) { + for (HighVariable highVariable : highVariables) { - HighVariable highVariable = highVariableIterator.next(); monitor.checkCancelled(); - FillOutStructureCmd fillCmd = new FillOutStructureCmd(program, location, tool); - fillCmd.processStructure(highVariable, function); - List stores = fillCmd.getStorePcodeOps(); + fillStructHelper.processStructure(highVariable, function, true, false); + List stores = fillStructHelper.getStorePcodeOps(); stores = removePcodeOpsNotInFunction(function, stores); // this method checks the storedPcodeOps to see if one is the vftable address @@ -6141,7 +5883,7 @@ public class RecoveredClassHelper { } if (storedVftableAddress.equals(vftableAddress)) { - return fillCmd; + return fillStructHelper; } } @@ -6164,21 +5906,14 @@ public class RecoveredClassHelper { throws CancelledException, InvalidInputException, DuplicateNameException, CircularDependencyException { - Iterator recoveredClassIterator = recoveredClasses.iterator(); - - while (recoveredClassIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = recoveredClassIterator.next(); - List inlineFunctionsList = new ArrayList<>(recoveredClass.getIndeterminateInlineList()); - Iterator inlineIterator = inlineFunctionsList.iterator(); - while (inlineIterator.hasNext()) { + for (Function inlineFunction : inlineFunctionsList) { monitor.checkCancelled(); - Function inlineFunction = inlineIterator.next(); - // get the addresses in the function that refer to classes either by // referencing a vftable in a class or by calling a function in a class Map referenceToClassMap = @@ -6193,11 +5928,9 @@ public class RecoveredClassHelper { List
referenceToIndeterminates = new ArrayList
(); if (!referencesToFunctions.isEmpty()) { - Iterator
functionReferenceIterator = referencesToFunctions.iterator(); - while (functionReferenceIterator.hasNext()) { + for (Address functionReference : referencesToFunctions) { monitor.checkCancelled(); - Address functionReference = functionReferenceIterator.next(); Function function = extendedFlatAPI.getReferencedFunction(functionReference, true); @@ -6250,16 +5983,16 @@ public class RecoveredClassHelper { if (firstVftableReferenceInFunction == null) { continue; } - FillOutStructureCmd fillOutStructureCmd = - runFillOutStructureCmd(inlineFunction, firstVftableReferenceInFunction); - if (fillOutStructureCmd == null) { + FillOutStructureHelper fillStructHelper = runFillOutStructureHelper( + inlineFunction, firstVftableReferenceInFunction); + if (fillStructHelper == null) { continue; } - loads = fillOutStructureCmd.getLoadPcodeOps(); + loads = fillStructHelper.getLoadPcodeOps(); loads = removePcodeOpsNotInFunction(inlineFunction, loads); - stores = fillOutStructureCmd.getStorePcodeOps(); + stores = fillStructHelper.getStorePcodeOps(); stores = removePcodeOpsNotInFunction(inlineFunction, stores); updateFunctionToStorePcodeOpsMap(inlineFunction, stores); @@ -6350,11 +6083,8 @@ public class RecoveredClassHelper { List recoveredClasses) throws CancelledException, InvalidInputException, DuplicateNameException, CircularDependencyException { - Iterator classIterator = recoveredClasses.iterator(); - while (classIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = classIterator.next(); - List indeterminateList = recoveredClass.getIndeterminateList(); Iterator indeterminateIterator = indeterminateList.iterator(); while (indeterminateIterator.hasNext()) { @@ -6410,16 +6140,16 @@ public class RecoveredClassHelper { if (firstVftableReferenceInFunction == null) { continue; } - FillOutStructureCmd fillOutStructureCmd = runFillOutStructureCmd( - indeterminateFunction, firstVftableReferenceInFunction); - if (fillOutStructureCmd == null) { + FillOutStructureHelper fillStructHelper = runFillOutStructureHelper( + indeterminateFunction, firstVftableReferenceInFunction); + if (fillStructHelper == null) { continue; } - loads = fillOutStructureCmd.getLoadPcodeOps(); + loads = fillStructHelper.getLoadPcodeOps(); loads = removePcodeOpsNotInFunction(indeterminateFunction, loads); - stores = fillOutStructureCmd.getStorePcodeOps(); + stores = fillStructHelper.getStorePcodeOps(); stores = removePcodeOpsNotInFunction(indeterminateFunction, stores); updateFunctionToStorePcodeOpsMap(indeterminateFunction, stores); @@ -6588,10 +6318,8 @@ public class RecoveredClassHelper { if (vftableReferences == null) { return false; } - Iterator
vftableReferencesIterator = vftableReferences.iterator(); - while (vftableReferencesIterator.hasNext()) { + for (Address vftableReference : vftableReferences) { monitor.checkCancelled(); - Address vftableReference = vftableReferencesIterator.next(); Address vftableAddress = getVftableAddress(vftableReference); if (vftableAddress == null) { continue; @@ -6620,12 +6348,9 @@ public class RecoveredClassHelper { List classConstructorOrDestructorFunctions = recoveredClass.getConstructorOrDestructorFunctions(); - Iterator functionIterator = classConstructorOrDestructorFunctions.iterator(); - while (functionIterator.hasNext()) { + for (Function function : classConstructorOrDestructorFunctions) { monitor.checkCancelled(); - Function function = functionIterator.next(); - if (extendedFlatAPI.doesFunctionACallFunctionB(vfunction, function)) { recoveredClass.addDeletingDestructor(vfunction); @@ -6653,25 +6378,18 @@ public class RecoveredClassHelper { List recoveredClasses) throws CancelledException, InvalidInputException, DuplicateNameException, CircularDependencyException { - Iterator recoveredClassIterator = recoveredClasses.iterator(); - - while (recoveredClassIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = recoveredClassIterator.next(); - List parentsToProcess = recoveredClass.getParentList(); if (parentsToProcess.isEmpty()) { continue; } - Iterator parentsToProcessIterator = parentsToProcess.iterator(); - - while (parentsToProcessIterator.hasNext()) { + for (RecoveredClass parentToProcess : parentsToProcess) { monitor.checkCancelled(); - RecoveredClass parentToProcess = parentsToProcessIterator.next(); processConstructorsAndDestructorsUsingParent(recoveredClass, parentToProcess); } } @@ -6693,12 +6411,8 @@ public class RecoveredClassHelper { List recoveredClasses) throws CancelledException, InvalidInputException, DuplicateNameException, CircularDependencyException { - Iterator recoveredClassIterator = recoveredClasses.iterator(); - - while (recoveredClassIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = recoveredClassIterator.next(); - List indeterminateList = recoveredClass.getIndeterminateList(); if (indeterminateList.isEmpty()) { continue; @@ -6750,7 +6464,6 @@ public class RecoveredClassHelper { } - /** * Method to classify indeterminate inline functions as either constructors or destructors * using called ancestor information (may call parent or higher ancestor) or might be the same @@ -6767,12 +6480,8 @@ public class RecoveredClassHelper { List recoveredClasses) throws CancelledException, InvalidInputException, DuplicateNameException, CircularDependencyException { - Iterator recoveredClassIterator = recoveredClasses.iterator(); - - while (recoveredClassIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = recoveredClassIterator.next(); - List indeterminateList = new ArrayList(recoveredClass.getIndeterminateInlineList()); @@ -6783,11 +6492,8 @@ public class RecoveredClassHelper { List allRelatedConstructors = getAllAncestorConstructors(recoveredClass); List allRelatedDestructors = getAncestorDestructors(recoveredClass); - Iterator indeterminateIterator = indeterminateList.iterator(); - while (indeterminateIterator.hasNext()) { + for (Function indeterminateFunction : indeterminateList) { monitor.checkCancelled(); - Function indeterminateFunction = indeterminateIterator.next(); - // get the addresses in the function that refer to classes either by // referencing a vftable in a class or by calling a function in a class Map referenceToClassMap = @@ -6860,12 +6566,8 @@ public class RecoveredClassHelper { public void findDestructorsUsingAtexitCalledFunctions(List recoveredClasses) throws CancelledException, InvalidInputException, DuplicateNameException { - Iterator recoveredClassIterator = recoveredClasses.iterator(); - - while (recoveredClassIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = recoveredClassIterator.next(); - List indeterminateList = recoveredClass.getIndeterminateList(); Iterator indeterminateIterator = indeterminateList.iterator(); @@ -6946,8 +6648,8 @@ public class RecoveredClassHelper { continue; } - List
operatorDeleteCallingAddresses = getAddressesOfListedFunctionsInMap( - operatorDeletes, functionCallMap); + List
operatorDeleteCallingAddresses = + getAddressesOfListedFunctionsInMap(operatorDeletes, functionCallMap); // only process vfunctions with at least one call to operator delete if (operatorDeleteCallingAddresses.size() == 0) { @@ -6965,9 +6667,8 @@ public class RecoveredClassHelper { firstVftableReference = vftableReferences.get(0); } - List possibleCalledDestructors = - getPossibleCalledDestructors(functionCallMap, - operatorDeleteCallingAddresses, firstVftableReference); + List possibleCalledDestructors = getPossibleCalledDestructors( + functionCallMap, operatorDeleteCallingAddresses, firstVftableReference); // process deleting destructors if type 1, 2 or 3 boolean isDeletingDestructor = @@ -6978,23 +6679,20 @@ public class RecoveredClassHelper { continue; } - // process deleting destructors type 4 and 5 // if function has only two calls and one is a vetted possible destructor (ie on // list called after first vftable reference and before operator delete) and the // other is a call to operator delete, then it is one of these two types if (!allFunctionsThatRefVftables.contains(vfunction) && operatorDeleteCallingAddresses.size() == 1 && - functionCallMap.keySet().size() == 2 && - possibleCalledDestructors.size() == 1) { + functionCallMap.keySet().size() == 2 && possibleCalledDestructors.size() == 1) { recoveredClass.addDeletingDestructor(vfunction); Function destructor = possibleCalledDestructors.get(0); // if the called destructor isn't on the possible constructor/destructor // list then it is a vbase destructor - if (firstVftableReference == null && - !allPossibleCDs.contains(destructor)) { + if (firstVftableReference == null && !allPossibleCDs.contains(destructor)) { recoveredClass.setVBaseDestructor(destructor); continue; @@ -7012,7 +6710,6 @@ public class RecoveredClassHelper { } - /** * Method to find the operator delete and operator new functions in the current program * either by name or by common virtual function calls @@ -7032,9 +6729,8 @@ public class RecoveredClassHelper { allPossibleConstructorDestructors = getAllPossibleConstructorDestructors(vftables); - operatorDeletesSet = - findOperatorDeletesUsingCalledCommonFunction(allPossibleConstructorDestructors, - twoCallCommonFunctions, vftables); + operatorDeletesSet = findOperatorDeletesUsingCalledCommonFunction( + allPossibleConstructorDestructors, twoCallCommonFunctions, vftables); } operatorDeletes = new ArrayList(operatorDeletesSet); @@ -7052,9 +6748,8 @@ public class RecoveredClassHelper { if (allPossibleConstructorDestructors == null) { allPossibleConstructorDestructors = getAllPossibleConstructorDestructors(vftables); } - operatorNewsSet = - findOperatorNewsUsingCalledCommonFunction(allPossibleConstructorDestructors, - twoCallCommonFunctions, vftables); + operatorNewsSet = findOperatorNewsUsingCalledCommonFunction( + allPossibleConstructorDestructors, twoCallCommonFunctions, vftables); } operatorNews = new ArrayList(operatorNewsSet); @@ -7072,7 +6767,6 @@ public class RecoveredClassHelper { return new ArrayList
(vftableToClassMap.keySet()); } - private List getPossibleCalledDestructors( Map addressToFunctionCallMap, List
operatorDeleteCallingAddresses, Address firstVftableReference) @@ -7111,7 +6805,7 @@ public class RecoveredClassHelper { calledFunction = calledFunction.getThunkedFunction(true); } possibleCalledDestructorSet.add(calledFunction); - + } } List possibleCalledDestructors = @@ -7119,10 +6813,8 @@ public class RecoveredClassHelper { return possibleCalledDestructors; } - private void processPossibleDestructors(Set allPossibleConstructorDestructors, - List possibleDestructors, - Function calledFromFunction, List
vftables) + List possibleDestructors, Function calledFromFunction, List
vftables) throws InvalidInputException, DuplicateNameException, CancelledException { if (possibleDestructors.isEmpty()) { @@ -7148,7 +6840,6 @@ public class RecoveredClassHelper { } } - /** * Method to return list of reference addresses for any of the given functions that are * contained in the given map @@ -7412,11 +7103,8 @@ public class RecoveredClassHelper { public void findRealVBaseFunctions(List recoveredClasses) throws CancelledException, InvalidInputException, DuplicateNameException { - Iterator recoveredClassIterator = recoveredClasses.iterator(); - - while (recoveredClassIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = recoveredClassIterator.next(); Function vBaseDestructor = recoveredClass.getVBaseDestructor(); if (vBaseDestructor == null) { continue; @@ -7554,12 +7242,9 @@ public class RecoveredClassHelper { Function possiblePureCall = null; - Iterator recoveredClassIterator = recoveredClasses.iterator(); - - while (recoveredClassIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = recoveredClassIterator.next(); if (recoveredClass.hasChildClass()) { Function sameFunction = null; List deletingDestructors = recoveredClass.getDeletingDestructors(); @@ -7567,10 +7252,8 @@ public class RecoveredClassHelper { if (virtualFunctions.size() < 3) { continue; } - Iterator vfunctionIterator = virtualFunctions.iterator(); - while (vfunctionIterator.hasNext()) { + for (Function vfunction : virtualFunctions) { monitor.checkCancelled(); - Function vfunction = vfunctionIterator.next(); // skip the deleting destructors if (deletingDestructors.contains(vfunction)) { continue; @@ -7625,10 +7308,8 @@ public class RecoveredClassHelper { List listOfUniqueFunctions = new ArrayList(); - Iterator listIterator = list.iterator(); - while (listIterator.hasNext()) { + for (Function function : list) { monitor.checkCancelled(); - Function function = listIterator.next(); if (!listOfUniqueFunctions.contains(function)) { listOfUniqueFunctions.add(function); } @@ -7646,10 +7327,8 @@ public class RecoveredClassHelper { List
listOfUniqueAddresses = new ArrayList
(); - Iterator
listIterator = list.iterator(); - while (listIterator.hasNext()) { + for (Address address : list) { monitor.checkCancelled(); - Address address = listIterator.next(); if (!listOfUniqueAddresses.contains(address)) { listOfUniqueAddresses.add(address); } @@ -7665,8 +7344,7 @@ public class RecoveredClassHelper { * @throws CancelledException if cancelled */ protected void trimConstructorDestructorLists(List recoveredClasses, - List
vftables) - throws CancelledException { + List
vftables) throws CancelledException { if (recoveredClasses.isEmpty()) { return; @@ -7703,7 +7381,6 @@ public class RecoveredClassHelper { } - /** * Method to apply the function signature of the given function, if different, to the corresponding * function definition and call the method to update related structure fields and functions @@ -8222,7 +7899,7 @@ public class RecoveredClassHelper { if (vfunctionStructureNamespace == null) { continue; } - + Data vftableData = getVftableStructureFromListing(vfunctionStructureNamespace, vftableStructure); @@ -8420,8 +8097,7 @@ public class RecoveredClassHelper { // TODO: update with regex to exclude very unlikely \/ case path = path.replace("/", "::"); - List namespaceByPath = - NamespaceUtils.getNamespaceByPath(program, null, path); + List namespaceByPath = NamespaceUtils.getNamespaceByPath(program, null, path); // ignore namespaces contained within libraries for (Namespace namespace : namespaceByPath) { diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompInterface.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompInterface.java index 33ff0fa92a..10ca35da40 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompInterface.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompInterface.java @@ -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(); diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerUtils.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerUtils.java index 11d586c87b..e9416ac6f5 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerUtils.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerUtils.java @@ -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. diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/util/FillOutStructureCmd.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/util/FillOutStructureCmd.java new file mode 100644 index 0000000000..e5e30c6ae6 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/util/FillOutStructureCmd.java @@ -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 { + + 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; + } + +} diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FillOutStructureCmd.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/util/FillOutStructureHelper.java similarity index 60% rename from Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FillOutStructureCmd.java rename to Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/util/FillOutStructureHelper.java index a90c5b3f45..99d31cb07d 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FillOutStructureCmd.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/util/FillOutStructureHelper.java @@ -13,18 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ghidra.app.plugin.core.decompile.actions; +package ghidra.app.decompiler.util; import java.util.*; import java.util.Map.Entry; -import docking.options.OptionsService; import ghidra.app.cmd.label.RenameLabelCmd; import ghidra.app.decompiler.*; -import ghidra.framework.cmd.BackgroundCommand; -import ghidra.framework.model.DomainObject; -import ghidra.framework.options.ToolOptions; -import ghidra.framework.plugintool.PluginTool; +import ghidra.app.decompiler.component.DecompilerUtils; +import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSet; import ghidra.program.model.data.*; @@ -32,9 +29,9 @@ import ghidra.program.model.lang.PrototypeModel; import ghidra.program.model.listing.*; import ghidra.program.model.pcode.*; import ghidra.program.model.symbol.*; -import ghidra.program.util.*; import ghidra.util.Msg; -import ghidra.util.exception.*; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.exception.InvalidInputException; import ghidra.util.task.TaskMonitor; /** @@ -44,11 +41,7 @@ import ghidra.util.task.TaskMonitor; * to the structure, even if the structure must grow. * */ -public class FillOutStructureCmd extends BackgroundCommand { - - // NOTE: (see GP-4408) This Command implementation should be refactored to break-out the - // Utility aspects which are contained within and used publicly without invoking the applyTo - // method. In addition, the Command should not be constructed with a Program instance. +public class FillOutStructureHelper { /** * Varnode with data-flow traceable to original pointer @@ -66,18 +59,15 @@ public class FillOutStructureCmd extends BackgroundCommand { private static final String DEFAULT_BASENAME = "astruct"; private static final String DEFAULT_CATEGORY = "/auto_structs"; - private int currentCallDepth = 0; // Current call depth (from root function) - private int maxCallDepth = 1; + private Program currentProgram; + private TaskMonitor monitor; + private DecompileOptions decompileOptions; + private static final int maxCallDepth = 1; + + private int currentCallDepth; // Current call depth (from root function) private NoisyStructureBuilder componentMap = new NoisyStructureBuilder(); private HashMap addressToCallInputMap = new HashMap<>(); - - private Program currentProgram; - private ProgramLocation currentLocation; - private Function rootFunction; - private TaskMonitor monitor; - private PluginTool tool; - private List storePcodeOps = new ArrayList<>(); private List loadPcodeOps = new ArrayList<>(); @@ -85,92 +75,15 @@ public class FillOutStructureCmd extends BackgroundCommand { * Constructor. * * @param program the current program - * @param location the current program location - * @param tool the current plugin tool + * @param decompileOptions decompiler options + * (see {@link DecompilerUtils#getDecompileOptions(ServiceProvider, Program)}) + * @param monitor task monitor */ - public FillOutStructureCmd(Program program, ProgramLocation location, PluginTool tool) { - super("Fill Out Structure", true, false, true); - this.tool = tool; + public FillOutStructureHelper(Program program, DecompileOptions decompileOptions, + TaskMonitor monitor) { this.currentProgram = program; - this.currentLocation = Objects.requireNonNull(location); - } - - @Override - public boolean applyTo(DomainObject obj, TaskMonitor taskMonitor) { - this.monitor = taskMonitor; - - rootFunction = - currentProgram.getFunctionManager().getFunctionContaining(currentLocation.getAddress()); - if (rootFunction == null) { - return false; - } - - int transaction = currentProgram.startTransaction("Fill Out Structure Variable"); - try { - HighVariable var = null; - - if (!(currentLocation instanceof DecompilerLocation)) { - // if we don't have one, make one, and map variable to a varnode - Address storageAddr = computeStorageAddress(currentLocation, rootFunction); - var = computeHighVariable(storageAddr, rootFunction); - } - else { - - // get the Varnode under the cursor - DecompilerLocation dloc = (DecompilerLocation) currentLocation; - ClangToken token = dloc.getToken(); - if (token == null) { - 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) { - return false; - } - } - } - - if (var == null || var.getSymbol() == null || var.getOffset() >= 0) { - return false; - } - - boolean isThisParam = - CreateStructureVariableAction.testForAutoParameterThis(var, rootFunction); - Structure structDT = - CreateStructureVariableAction.getStructureForExtending(var.getDataType()); - if (structDT != null) { - componentMap.populateOriginalStructure(structDT); - } - - fillOutStructureDef(var); - pushIntoCalls(); - - structDT = createStructure(structDT, var, rootFunction, isThisParam); - populateStructure(structDT); - - DataType pointerDT = new PointerDataType(structDT); - - // Delay adding to the manager until full structure is accumulated - pointerDT = currentProgram.getDataTypeManager() - .addDataType(pointerDT, DataTypeConflictHandler.DEFAULT_HANDLER); - commitVariable(var, pointerDT, isThisParam); - } - catch (Exception e) { - Msg.showError(this, tool.getToolFrame(), "Auto Create Structure Failed", - "Failed to create Structure variable", e); - } - finally { - currentProgram.endTransaction(transaction, true); - } - - return true; + this.decompileOptions = decompileOptions; + this.monitor = monitor; } /** @@ -179,31 +92,82 @@ public class FillOutStructureCmd extends BackgroundCommand { * or any existing data-types. A new structure is always created. * @param var a parameter, local variable, or global variable used in the given function * @param function the function to process + * @param createNewStructure if true a new structure with a unique name will always be generated, + * if false and variable corresponds to a structure pointer the existing structure will be + * updated instead. + * @param createClassIfNeeded if true and variable corresponds to a this pointer without + * an assigned Ghidra Class (i.e., {@code void * this}), the function will be assigned to a + * new unique Ghidra Class namespace with a new identically named structure returned. If false, + * a new uniquely structure will be created. * @return a filled-in structure or null if one could not be created */ - public Structure processStructure(HighVariable var, Function function) { + public Structure processStructure(HighVariable var, Function function, + boolean createNewStructure, boolean createClassIfNeeded) { if (var == null || var.getSymbol() == null || var.getOffset() >= 0) { return null; } - Structure structDT; + init(); - try { - fillOutStructureDef(var); - pushIntoCalls(); - structDT = createStructure(null, var, function, false); - populateStructure(structDT); + Structure structDT = null; + + if (!createNewStructure) { + structDT = getStructureForExtending(var.getDataType()); + if (structDT != null) { + componentMap.populateOriginalStructure(structDT); + } } - catch (Exception e) { + + fillOutStructureDef(var); + pushIntoCalls(); + + long size = componentMap.getSize(); + if (size == 0) { return null; } + if (size < 0 || size > Integer.MAX_VALUE) { + Msg.error(this, "Computed structure length out-of-range: " + size); + return null; + } + + if (structDT == null) { + if (createClassIfNeeded && DecompilerUtils.testForAutoParameterThis(var, function)) { + structDT = createUniqueClassNamespaceAndStructure(var, (int) size, function); + } + else { + structDT = createUniqueStructure((int) size); + } + } + else { + expandStructureSizeIfNeeded(structDT, (int) size); + } + + populateStructure(structDT); return structDT; } + private void expandStructureSizeIfNeeded(Structure struct, int size) { + // TODO: How should an existing packed structure be handled? Growing and offset-based + // placement does not apply + int len = struct.isZeroLength() ? 0 : struct.getLength(); + if (size > len) { + struct.growStructure(size - len); + } + } + + private void init() { + currentCallDepth = 0; // Current call depth (from root function) + componentMap = new NoisyStructureBuilder(); + addressToCallInputMap = new HashMap<>(); + storePcodeOps = new ArrayList<>(); + loadPcodeOps = new ArrayList<>(); + } + /** - * Retrieve the component map that was generated when structure was created using decomiler info + * Retrieve the component map that was generated when structure was created using decomiler info. + * Results are not valid until {@link #processStructure(HighVariable, Function, boolean)} is invoked. * @return componentMap */ public NoisyStructureBuilder getComponentMap() { @@ -212,7 +176,8 @@ public class FillOutStructureCmd extends BackgroundCommand { /** * Retrieve the offset/pcodeOp pairs that are used to store data into the variable - * the FillInStructureCmd was trying to create a structure on. + * used to fill-out structure. + * Results are not valid until {@link #processStructure(HighVariable, Function, boolean)} is invoked. * @return the pcodeOps doing the storing to the associated variable */ public List getStorePcodeOps() { @@ -221,7 +186,8 @@ public class FillOutStructureCmd extends BackgroundCommand { /** * Retrieve the offset/pcodeOp pairs that are used to load data from the variable - * the FillInStructureCmd was trying to create a structure on. + * used to fill-out structure. + * Results are not valid until {@link #processStructure(HighVariable, Function, boolean)} is invoked. * @return the pcodeOps doing the loading from the associated variable */ public List getLoadPcodeOps() { @@ -295,59 +261,13 @@ public class FillOutStructureCmd extends BackgroundCommand { } } - /** - * 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 location is the location being queried - * @param function is the function owning the location - * @return the corresponding storage address or null - */ - private Address computeStorageAddress(ProgramLocation location, 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; - } - /** * Decompile a function and return the resulting HighVariable associated with a storage address * @param storageAddress the storage address of the variable * @param function is the function - * @return the corresponding HighVariable + * @return the corresponding HighVariable or null */ - private HighVariable computeHighVariable(Address storageAddress, Function function) { + public HighVariable computeHighVariable(Address storageAddress, Function function) { if (storageAddress == null) { return null; } @@ -360,7 +280,12 @@ public class FillOutStructureCmd extends BackgroundCommand { return null; } - DecompileResults results = decompileFunction(function, decomplib); + DecompileResults results = decomplib.decompileFunction(function, + decomplib.getOptions().getDefaultTimeout(), monitor); + if (monitor.isCancelled()) { + return null; + } + HighFunction highFunc = results.getHighFunction(); // no decompile... @@ -407,57 +332,13 @@ public class FillOutStructureCmd extends BackgroundCommand { */ private DecompInterface setUpDecompiler() { DecompInterface decomplib = new DecompInterface(); - - DecompileOptions options; - options = new DecompileOptions(); - OptionsService service = tool.getService(OptionsService.class); - if (service != null) { - ToolOptions opt = service.getOptions("Decompiler"); - options.grabFromToolAndProgram(null, opt, currentProgram); - } - decomplib.setOptions(options); - + decomplib.setOptions(decompileOptions); decomplib.toggleCCode(true); decomplib.toggleSyntaxTree(true); decomplib.setSimplificationStyle("decompile"); - return decomplib; } - public DecompileResults decompileFunction(Function f, DecompInterface decomplib) { - DecompileResults decompRes; - - decompRes = - decomplib.decompileFunction(f, decomplib.getOptions().getDefaultTimeout(), monitor); - - return decompRes; - } - - /** - * Recover the structure associated with the given pointer variable, or if there is no structure, - * create it. Resize the structure to be at least as large as the maxOffset seen so far. - * @param structDT is the structure data-type to fill in, or null if a new Structure should be created - * @param var is the given pointer variable - * @param f is the function - * @param isThisParam is true if the variable is a 'this' pointer - * @return the Structure object - */ - private Structure createStructure(Structure structDT, HighVariable var, Function f, - boolean isThisParam) { - - if (structDT == null) { - structDT = createNewStruct(var, (int) componentMap.getSize(), f, isThisParam); - } - else { - // FIXME: How should an existing packed structure be handled? Growing and offset-based placement does not apply - int len = structDT.isZeroLength() ? 0 : structDT.getLength(); - if (componentMap.getSize() > len) { - structDT.growStructure((int) componentMap.getSize() - len); - } - } - return structDT; - } - /** * Populate the given structure with any new discovered components in the * offsetToDataTypeMap. @@ -497,70 +378,90 @@ public class FillOutStructureCmd extends BackgroundCommand { } /** - * Create a new structure of a given size. If the associated variable is a 'this' pointer, - * make sure there is a the structure is associated with the class namespace. - * @param var is the associated variable + * Create a new structure of a given size and unique generated name within the DEFAULT_CATEGORY. + * * @param size is the desired structure size - * @param f is the function owning the variable - * @param isThisParam is true if the variable is a 'this' variable * @return the new Structure */ - private Structure createNewStruct(HighVariable var, int size, Function f, boolean isThisParam) { - if (isThisParam) { - Namespace rootNamespace = currentProgram.getGlobalNamespace(); - Namespace newNamespace = createUniqueClassName(rootNamespace); - String name = f.getName(); - Symbol symbol = f.getSymbol(); - RenameLabelCmd command = - new RenameLabelCmd(symbol, name, newNamespace, SourceType.USER_DEFINED); - if (!command.applyTo(currentProgram)) { - return null; - } - Structure structDT = VariableUtilities.findOrCreateClassStruct(f); - if (structDT == null) { - return null; - } -// FIXME: How should an existing packed structure be handled? Growing and offset-based placement does not apply - int len = structDT.isZeroLength() ? 0 : structDT.getLength(); - if (len < size) { - structDT.growStructure(size - len); - } - return structDT; - } - String structName = createUniqueStructName(var, DEFAULT_CATEGORY, DEFAULT_BASENAME); - - StructureDataType dt = new StructureDataType(new CategoryPath(DEFAULT_CATEGORY), structName, - size, f.getProgram().getDataTypeManager()); + private Structure createUniqueStructure(int size) { + ProgramBasedDataTypeManager dtm = currentProgram.getDataTypeManager(); + String structName = dtm.getUniqueName(new CategoryPath(DEFAULT_CATEGORY), DEFAULT_BASENAME); + StructureDataType dt = + new StructureDataType(new CategoryPath(DEFAULT_CATEGORY), structName, size, dtm); return dt; } - private Namespace createUniqueClassName(Namespace rootNamespace) { + /** + * Create new unique Ghidra Class namespace and corresponding structure. + * @param var {@code "this"} pointer variable + * @param size structure size + * @param f Ghidra Class member function + * @return new Ghidra Class structure or null on error + */ + private Structure createUniqueClassNamespaceAndStructure(HighVariable var, int size, + Function f) { + Namespace newNamespace = createUniqueClassName(); + if (newNamespace == null) { + return null; + } + + // Move function into new Ghidra Class namespace + RenameLabelCmd command = + new RenameLabelCmd(f.getSymbol(), f.getName(), newNamespace, SourceType.USER_DEFINED); + if (!command.applyTo(currentProgram)) { + return null; + } + + // Allocate new Ghidra Class structure + Structure structDT = VariableUtilities.findOrCreateClassStruct(f); + if (structDT == null) { + return null; + } + + expandStructureSizeIfNeeded(structDT, size); + + return structDT; + } + + private boolean programContainsNamedStructure(String structName) { + ProgramBasedDataTypeManager dtm = currentProgram.getDataTypeManager(); + List list = new ArrayList<>(); + dtm.findDataTypes(structName, list, true, monitor); + for (DataType dt : list) { + if (dt instanceof Structure) { + return true; + } + } + return false; + } + + /** + * Generate a unique Ghidra Class which does not have an existing structure + * @return new unique Ghidra Class namespace or null on error + */ + private Namespace createUniqueClassName() { + Namespace rootNamespace = currentProgram.getGlobalNamespace(); SymbolTable symbolTable = currentProgram.getSymbolTable(); String newClassBase = "AutoClass"; - String newClassName = ""; - for (int i = 1; i < 1000; ++i) { - newClassName = newClassBase + Integer.toString(i); - if (symbolTable.getSymbols(newClassName, rootNamespace).isEmpty()) { + String newClassName; + int index = 1; + while (true) { + // cycle until we find unused class/structure name + newClassName = newClassBase + Integer.toString(index++); + if (symbolTable.getNamespace(newClassName, rootNamespace) == null && + !programContainsNamedStructure(newClassName)) { break; } } // Create the class - GhidraClass newClass = null; try { - newClass = - symbolTable.createClass(rootNamespace, newClassName, SourceType.USER_DEFINED); + return symbolTable.createClass(rootNamespace, newClassName, SourceType.USER_DEFINED); } - catch (DuplicateNameException e) { + catch (DuplicateNameException | InvalidInputException e) { + // unexpected unless possible race condition Msg.error(this, "Error creating class '" + newClassName + "'", e); } - catch (InvalidInputException e) { - Msg.error(this, "Error creating class '" + newClassName + "'", e); - } - return newClass; - } - - private String createUniqueStructName(HighVariable var, String category, String base) { - return currentProgram.getDataTypeManager().getUniqueName(new CategoryPath(category), base); + return null; } private boolean sanityCheck(long offset, long existingSize) { @@ -577,38 +478,6 @@ public class FillOutStructureCmd extends BackgroundCommand { return true; } - /** - * 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; - } - - /** - * 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; - } - /** * Look for Varnode references that are equal to the given variable plus a * constant offset and store them in the componentMap. The search is performed @@ -692,7 +561,7 @@ public class FillOutStructureCmd extends BackgroundCommand { componentMap.setMinimumSize(currentRef.offset); break; case PcodeOp.LOAD: - outDt = getDataTypeTraceForward(output); + outDt = DecompilerUtils.getDataTypeTraceForward(output); componentMap.addDataType(currentRef.offset, outDt); if (outDt != null) { @@ -706,7 +575,7 @@ public class FillOutStructureCmd extends BackgroundCommand { if (pcodeOp.getSlot(currentRef.varnode) != 1) { break; // store must be into the target structure } - outDt = getDataTypeTraceBackward(inputs[2]); + outDt = DecompilerUtils.getDataTypeTraceBackward(inputs[2]); componentMap.addDataType(currentRef.offset, outDt); if (outDt != null) { @@ -735,12 +604,12 @@ public class FillOutStructureCmd extends BackgroundCommand { } } else { - outDt = getDataTypeTraceBackward(currentRef.varnode); + outDt = DecompilerUtils.getDataTypeTraceBackward(currentRef.varnode); componentMap.addReference(currentRef.offset, outDt); } break; case PcodeOp.CALLIND: - outDt = getDataTypeTraceBackward(currentRef.varnode); + outDt = DecompilerUtils.getDataTypeTraceBackward(currentRef.varnode); componentMap.addReference(currentRef.offset, outDt); break; } @@ -775,6 +644,34 @@ public class FillOutStructureCmd extends BackgroundCommand { doneList.add(output); } + /** + * 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; + } + /** * Class to create pair between an offset and its related PcodeOp */ diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/CreateStructureVariableAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/CreateStructureVariableAction.java index d5b0346ccc..076576171c 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/CreateStructureVariableAction.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/CreateStructureVariableAction.java @@ -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); } } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/DecompilerStructureVariableAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/DecompilerStructureVariableAction.java index 8652072f80..b7aa780f65 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/DecompilerStructureVariableAction.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/DecompilerStructureVariableAction.java @@ -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) { diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/util/exporter/CppExporter.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/util/exporter/CppExporter.java index 0b9a4aad53..dcbaaea29f 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/util/exporter/CppExporter.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/util/exporter/CppExporter.java @@ -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); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java index 653ce0a5b4..d089dc76bf 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java @@ -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 { 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 { 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; diff --git a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ApplyDiffCommand.java b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ApplyDiffCommand.java index d8bb402ec3..3f586e766f 100644 --- a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ApplyDiffCommand.java +++ b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ApplyDiffCommand.java @@ -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 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 {