Merge remote-tracking branch 'origin/GP-4408_ghidra1_FillOutStructureCmdCleanup--SQUASHED'

This commit is contained in:
Ryan Kurtz 2024-04-03 10:12:19 -04:00
commit c89d72bad5
25 changed files with 1262 additions and 1791 deletions

View file

@ -108,7 +108,7 @@ public class AutoAnalysisManager {
//private Integer currentTaskPriority = null;
//private Stack<Integer> taskPriorityStack = new Stack<Integer>();
private PriorityQueue<BackgroundCommand> queue = new PriorityQueue<>();
private PriorityQueue<BackgroundCommand<Program>> queue = new PriorityQueue<>();
private Map<String, Long> timedTasks = new HashMap<>();
// used for testing and performance monitoring; accessed via reflection
private Map<String, Long> cumulativeTasks = new HashMap<>();
@ -231,7 +231,7 @@ public class AutoAnalysisManager {
Options options = program.getOptions(Program.ANALYSIS_PROPERTIES);
analyzer.optionsChanged(options.getOptions(analyzer.getName()), getProgram());
BackgroundCommand cmd = new OneShotAnalysisCommand(analyzer, set, log);
OneShotAnalysisCommand cmd = new OneShotAnalysisCommand(analyzer, set, log);
schedule(cmd, analyzer.getPriority().priority());
}
@ -643,13 +643,13 @@ public class AutoAnalysisManager {
private class AnalysisTaskWrapper {
private final BackgroundCommand task;
private final BackgroundCommand<Program> task;
Integer taskPriority;
private long timeAccumulator;
private long startTime;
AnalysisTaskWrapper(BackgroundCommand task, int taskPriority) {
AnalysisTaskWrapper(BackgroundCommand<Program> task, int taskPriority) {
this.task = task;
this.taskPriority = taskPriority;
}
@ -845,7 +845,7 @@ public class AutoAnalysisManager {
*/
public synchronized void cancelQueuedTasks() {
while (!queue.isEmpty()) {
BackgroundCommand cmd = queue.getFirst();
BackgroundCommand<Program> cmd = queue.getFirst();
if (cmd instanceof AnalysisWorkerCommand) {
AnalysisWorkerCommand workerCmd = (AnalysisWorkerCommand) cmd;
if (!workerCmd.canCancel()) {
@ -857,7 +857,7 @@ public class AutoAnalysisManager {
}
}
synchronized boolean schedule(BackgroundCommand cmd, int priority) {
synchronized boolean schedule(BackgroundCommand<Program> cmd, int priority) {
if (cmd == null) {
throw new IllegalArgumentException("Can't schedule a null command");
@ -1583,7 +1583,8 @@ public class AutoAnalysisManager {
* In a Headed environment a modal task dialog will be used to block user input if the
* worker was scheduled with analyzeChanges==false
*/
private class AnalysisWorkerCommand extends BackgroundCommand implements CancelledListener {
private class AnalysisWorkerCommand extends BackgroundCommand<Program>
implements CancelledListener {
private AnalysisWorker worker;
private Object workerContext;
@ -1651,7 +1652,7 @@ public class AutoAnalysisManager {
}
@Override
public boolean applyTo(DomainObject obj, TaskMonitor analysisMonitor) {
public boolean applyTo(Program p, TaskMonitor analysisMonitor) {
synchronized (this) {
workerMonitor.removeCancelledListener(this);
@ -1660,7 +1661,7 @@ public class AutoAnalysisManager {
return false;
}
assert (obj == program);
assert (p == program);
if (analysisMonitor != workerMonitor) {
if (!workerMonitor.isCancelEnabled()) {

View file

@ -148,11 +148,11 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
return currentProgram != null;
}
};
findTableAction.setHelpLocation(
new HelpLocation(HelpTopics.SEARCH, findTableAction.getName()));
findTableAction.setMenuBarData(new MenuData(
new String[] { ToolConstants.MENU_SEARCH, "For Address Tables" }, null, "search for",
-1, "AddressTables"));
findTableAction
.setHelpLocation(new HelpLocation(HelpTopics.SEARCH, findTableAction.getName()));
findTableAction.setMenuBarData(
new MenuData(new String[] { ToolConstants.MENU_SEARCH, "For Address Tables" }, null,
"search for", -1, "AddressTables"));
findTableAction.setDescription(getPluginDescription().getDescription());
findTableAction.addToWindowWhen(NavigatableActionContext.class);
tool.addAction(findTableAction);
@ -168,15 +168,15 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
int minimumTableSize = addressTableDialog.getMinTableSize();
if (minimumTableSize < 2) {
addressTableDialog.setDialogText(
"Please enter a valid minimum search length. Must be >= 2");
addressTableDialog
.setDialogText("Please enter a valid minimum search length. Must be >= 2");
return;
}
int alignment = addressTableDialog.getAlignment();
if (alignment <= 0 || alignment > 8) {
addressTableDialog.setDialogText(
"Please enter a valid alignment value. Must be > 0 and <= 8");
addressTableDialog
.setDialogText("Please enter a valid alignment value. Must be > 0 and <= 8");
return;
}
@ -217,8 +217,8 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
selectedAddresses[i] = model.getAddress(selectedRows[i]);
}
CompoundBackgroundCommand backCmd =
new CompoundBackgroundCommand("Disassemble Address Tables", false, true);
CompoundBackgroundCommand<Program> backCmd =
new CompoundBackgroundCommand<>("Disassemble Address Tables", false, true);
offsetLen = addressTableDialog.getOffset();
// loop over selected table addresses
@ -237,7 +237,7 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
tool.executeBackgroundCommand(backCmd, currentProgram);
}
private void createDisassemblyCommandsForAddress(CompoundBackgroundCommand backCmd,
private void createDisassemblyCommandsForAddress(CompoundBackgroundCommand<Program> backCmd,
Address currentAddress) {
Listing listing = currentProgram.getListing();
@ -261,8 +261,8 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
// need to create a context for each one. Also disassembleCmd will align the address to disassemble
DisassembleCommand disassembleCmd = new DisassembleCommand(addr, null, true);
RegisterValue rval = PseudoDisassembler.getTargetContextRegisterValueForDisassembly(
currentProgram, addr);
RegisterValue rval = PseudoDisassembler
.getTargetContextRegisterValueForDisassembly(currentProgram, addr);
disassembleCmd.setInitialContext(rval);
backCmd.add(disassembleCmd);
}

View file

@ -29,7 +29,6 @@ import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.util.bean.SetEquateDialog;
import ghidra.app.util.bean.SetEquateDialog.SelectionType;
import ghidra.app.util.datatype.ApplyEnumDialog;
import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.cmd.CompoundBackgroundCommand;
import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.PluginStatus;
@ -182,7 +181,7 @@ public class EquatePlugin extends Plugin {
iter = listing.getCodeUnits(context.getProgram().getMemory(), true);
}
BackgroundCommand cmd = new CreateEquateCmd(scalar, iter, dialog.getEquateName(),
CreateEquateCmd cmd = new CreateEquateCmd(scalar, iter, dialog.getEquateName(),
dialog.getOverwriteExisting(), context);
tool.executeBackgroundCommand(cmd, context.getProgram());
@ -297,8 +296,8 @@ public class EquatePlugin extends Plugin {
// Set up a background task that we'll populate with all the rename tasks we need
// to perform.
CompoundBackgroundCommand bckCmd =
new CompoundBackgroundCommand("Rename Equates in Selection", false, true);
CompoundBackgroundCommand<Program> bckCmd =
new CompoundBackgroundCommand<>("Rename Equates in Selection", false, true);
// Now loop over all the code units and search for matching scalars...
while (iter.hasNext()) {
@ -312,7 +311,7 @@ public class EquatePlugin extends Plugin {
}
private void renameEquateForCodeUnit(ListingActionContext context, Enum enoom, Equate equate,
String newName, String oldName, CompoundBackgroundCommand bgCmd, CodeUnit cu) {
String newName, String oldName, CompoundBackgroundCommand<Program> bgCmd, CodeUnit cu) {
if (cu instanceof Instruction) {
@ -348,8 +347,8 @@ public class EquatePlugin extends Plugin {
CodeUnitIterator iter) {
// Create a background task to process all the remove tasks.
CompoundBackgroundCommand bckCmd =
new CompoundBackgroundCommand("Remove Equates in Selection", false, true);
CompoundBackgroundCommand<Program> bckCmd =
new CompoundBackgroundCommand<>("Remove Equates in Selection", false, true);
// Now iterate over all code units in the iterator.
while (iter.hasNext()) {
@ -362,7 +361,7 @@ public class EquatePlugin extends Plugin {
}
private void removeEquateForCodeUnit(ListingActionContext context, Equate equate,
CompoundBackgroundCommand bckCmd, CodeUnit cu) {
CompoundBackgroundCommand<Program> bckCmd, CodeUnit cu) {
// A code unit can be either an instruction or data; we need to handle each
// separately.
if (cu instanceof Instruction) {

View file

@ -46,8 +46,8 @@ public class ApplyClassFunctionDefinitionUpdatesScript extends GhidraScript {
return;
}
RecoveredClassHelper classHelper = new RecoveredClassHelper(currentProgram, currentLocation,
state.getTool(), this, false, false, false, monitor);
RecoveredClassHelper classHelper = new RecoveredClassHelper(currentProgram, state.getTool(),
this, false, false, false, monitor);
DataTypeManagerService dtms = state.getTool().getService(DataTypeManagerService.class);
List<DataType> selectedDatatypes = dtms.getSelectedDatatypes();

View file

@ -46,8 +46,8 @@ public class ApplyClassFunctionSignatureUpdatesScript 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);
if (currentAddress == null) {
println("Cursor must be in a class function.");
@ -70,7 +70,6 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
return;
}
Namespace classNamespace = classHelper.getClassNamespace(currentAddress);
if (classNamespace == null) {
println("Cursor must be in a class function.");
@ -84,8 +83,7 @@ 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 " +
println("Function is not a virtual function so has no function definition or related " +
"function signatures to update");
return;
}
@ -159,5 +157,4 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
}
}

View file

@ -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);
}
}
}

View file

@ -190,8 +190,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
hasDebugSymbols = isPDBLoadedInProgram();
nameVfunctions = !hasDebugSymbols;
recoverClassesFromRTTI =
new RTTIWindowsClassRecoverer(currentProgram, currentLocation, state.getTool(),
recoverClassesFromRTTI = new RTTIWindowsClassRecoverer(currentProgram, state.getTool(),
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
nameVfunctions, hasDebugSymbols, monitor);
}
@ -213,9 +212,8 @@ 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,
recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, state.getTool(),
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
nameVfunctions, hasDebugSymbols, monitor);
}
else if (isGcc()) {
@ -245,9 +243,8 @@ 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,
recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, state.getTool(),
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
nameVfunctions, hasDebugSymbols, monitor);
}
else {

View file

@ -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;
@ -70,15 +69,15 @@ public class ShowCCallsScript extends GhidraScript {
Reference refs[] = sym.getReferences(null);
for (int i = 0; i < refs.length; i++) {
for (Reference ref : refs) {
if (monitor.isCancelled()) {
break;
}
// get function containing.
Address refAddr = refs[i].getFromAddress();
Function refFunc = currentProgram.getFunctionManager()
.getFunctionContaining(refAddr);
Address refAddr = ref.getFromAddress();
Function refFunc =
currentProgram.getFunctionManager().getFunctionContaining(refAddr);
if (refFunc == null) {
continue;
@ -97,16 +96,17 @@ public class ShowCCallsScript extends GhidraScript {
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();
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);
}
decomplib.setOptions(options);
decomplib.toggleCCode(true);
@ -119,7 +119,8 @@ public class ShowCCallsScript extends GhidraScript {
/**
* Analyze a functions references
*/
public void analyzeFunction(DecompInterface decomplib, Program prog, Function f, Address refAddr) {
public void analyzeFunction(DecompInterface decomplib, Program prog, Function f,
Address refAddr) {
if (f == null) {
return;
@ -139,8 +140,6 @@ public class ShowCCallsScript extends GhidraScript {
println(printCall(f, refAddr));
}
HighFunction hfunction = null;
ClangTokenGroup docroot = null;
@ -149,7 +148,8 @@ public class ShowCCallsScript extends GhidraScript {
// decomplib.setSimplificationStyle("normalize", null);
// HighFunction hfunction = decomplib.decompileFunction(f);
DecompileResults decompRes = decomplib.decompileFunction(f, decomplib.getOptions().getDefaultTimeout(), monitor);
DecompileResults decompRes =
decomplib.decompileFunction(f, decomplib.getOptions().getDefaultTimeout(), monitor);
//String statusMsg = decomplib.getDecompileMessage();
hfunction = decompRes.getHighFunction();
@ -180,7 +180,8 @@ public class ShowCCallsScript extends GhidraScript {
return buff.toString();
}
private boolean printCall(Address refAddr, ClangNode node, StringBuffer buff, boolean didStart, boolean isCall) {
private boolean printCall(Address refAddr, ClangNode node, StringBuffer buff, boolean didStart,
boolean isCall) {
if (node == null) {
return false;
}
@ -248,4 +249,3 @@ public class ShowCCallsScript extends GhidraScript {
return buffer.toString();
}
}

View file

@ -254,8 +254,7 @@ public class ShowConstantUse extends GhidraScript {
ConstUseLocation entry = (ConstUseLocation) rowObject;
Function func = entry.getProgram()
.getFunctionManager()
.getFunctionContaining(
entry.getAddress());
.getFunctionContaining(entry.getAddress());
if (func == null) {
return "";
}
@ -762,9 +761,7 @@ public class ShowConstantUse extends GhidraScript {
if (defUseList == null || defUseList.size() <= 0) {
return value;
}
Iterator<PcodeOp> iterator = defUseList.iterator();
while (iterator.hasNext()) {
PcodeOp pcodeOp = iterator.next();
for (PcodeOp pcodeOp : defUseList) {
int opcode = pcodeOp.getOpcode();
switch (opcode) {
case PcodeOp.INT_AND:
@ -970,8 +967,7 @@ public class ShowConstantUse extends GhidraScript {
}
private void followThroughGlobal(HashMap<Address, Long> constUse, ArrayList<PcodeOp> defUseList,
HighVariable hvar,
ArrayList<FunctionParamUse> funcList,
HighVariable hvar, ArrayList<FunctionParamUse> funcList,
HashSet<SequenceNumber> doneSet) {
Address loc = hvar.getRepresentative().getAddress();
PcodeOp def = hvar.getRepresentative().getDef();
@ -1013,6 +1009,7 @@ public class ShowConstantUse extends GhidraScript {
private Address lastDecompiledFuncAddr = null;
private DecompInterface setUpDecompiler(Program program) {
DecompInterface decompInterface = new DecompInterface();
// call it to get results
@ -1021,13 +1018,8 @@ public class ShowConstantUse extends GhidraScript {
return null;
}
DecompileOptions options;
options = new DecompileOptions();
OptionsService service = state.getTool().getService(OptionsService.class);
if (service != null) {
ToolOptions opt = service.getOptions("Decompiler");
options.grabFromToolAndProgram(null, opt, program);
}
DecompileOptions options = DecompilerUtils.getDecompileOptions(state.getTool(), program);
decompInterface.setOptions(options);
decompInterface.toggleCCode(true);

View file

@ -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;
@ -40,10 +41,6 @@ import ghidra.program.model.pcode.HighFunctionDBUtil.ReturnCommitOption;
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 !!
@ -612,18 +609,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);

View file

@ -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.*;
@ -462,13 +460,10 @@ public class WindowsResourceReference extends GhidraScript {
private void addResourceReferences(HashMap<Address, Long> constLocs, String resourceName,
boolean printScriptMsgs, boolean createBookmarks) throws CancelledException {
Set<Address> keys;
Iterator<Address> locIter;
keys = constLocs.keySet();
locIter = keys.iterator();
while (locIter.hasNext()) {
for (Address loc : keys) {
monitor.checkCancelled();
Address loc = locIter.next();
Instruction instr = currentProgram.getListing().getInstructionAt(loc);
long rsrcID = constLocs.get(loc);
Address rsrcAddr = findResource(resourceName + "_" + Long.toHexString(rsrcID), 0);
@ -488,9 +483,9 @@ public class WindowsResourceReference extends GhidraScript {
instr.addMnemonicReference(rsrcAddr, RefType.DATA, SourceType.ANALYSIS);
if (createBookmarks) {
currentProgram.getBookmarkManager().setBookmark(instr.getMinAddress(),
BookmarkType.ANALYSIS, "WindowsResourceReference",
"Added Resource Reference");
currentProgram.getBookmarkManager()
.setBookmark(instr.getMinAddress(), BookmarkType.ANALYSIS,
"WindowsResourceReference", "Added Resource Reference");
}
if (printScriptMsgs) {
println(" " + instr.getMinAddress().toString() + " : Found " + rsrcName +
@ -513,15 +508,13 @@ public class WindowsResourceReference extends GhidraScript {
private void addResourceTableReferences(HashMap<Address, Long> constLocs, String tableName,
boolean printScriptMsgs, boolean createBookmarks) throws CancelledException {
Set<Address> keys;
Iterator<Address> locIter;
//Get the set of address locations which call the resource function
keys = constLocs.keySet();
locIter = keys.iterator();
//Iterate though the set of address locations
while (locIter.hasNext()) {
for (Address loc : keys) {
monitor.checkCancelled();
Address loc = locIter.next();
Instruction instr = currentProgram.getListing().getInstructionAt(loc);
Long rsrcID = constLocs.get(loc);
Address rsrcAddr = null;
@ -532,9 +525,9 @@ public class WindowsResourceReference extends GhidraScript {
if (rsrcAddr != null) {
instr.addMnemonicReference(rsrcAddr, RefType.DATA, SourceType.ANALYSIS);
if (createBookmarks) {
currentProgram.getBookmarkManager().setBookmark(instr.getMinAddress(),
BookmarkType.ANALYSIS, "WindowsResourceReference",
"Added Resource Table Reference");
currentProgram.getBookmarkManager()
.setBookmark(instr.getMinAddress(), BookmarkType.ANALYSIS,
"WindowsResourceReference", "Added Resource Table Reference");
}
if (printScriptMsgs) {
println(" " + instr.getMinAddress().toString() + " : Found " +
@ -622,9 +615,7 @@ public class WindowsResourceReference extends GhidraScript {
if (defUseList == null || defUseList.size() <= 0) {
return value;
}
Iterator<PcodeOp> iterator = defUseList.iterator();
while (iterator.hasNext()) {
PcodeOp pcodeOp = iterator.next();
for (PcodeOp pcodeOp : defUseList) {
int opcode = pcodeOp.getOpcode();
switch (opcode) {
case PcodeOp.INT_AND:
@ -763,18 +754,11 @@ public class WindowsResourceReference extends GhidraScript {
private Address lastDecompiledFuncAddr = null;
private DecompInterface setUpDecompiler(Program program) {
DecompileOptions options = DecompilerUtils.getDecompileOptions(state.getTool(), program);
DecompInterface decompiler = new DecompInterface();
DecompileOptions options;
options = new DecompileOptions();
PluginTool tool = state.getTool();
if (tool != null) {
OptionsService service = tool.getService(OptionsService.class);
if (service != null) {
ToolOptions opt = service.getOptions("Decompiler");
options.grabFromToolAndProgram(null, opt, program);
}
}
decompiler.setOptions(options);
decompiler.toggleCCode(true);

View file

@ -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();

View file

@ -16,17 +16,17 @@
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS.
package classrecovery;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.NamespaceUtils;
import ghidra.framework.options.Options;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.program.flatapi.FlatProgramAPI;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.SymbolType;
import ghidra.program.util.ProgramLocation;
import ghidra.util.Msg;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
@ -36,32 +36,21 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
boolean programHasRTTIApplied = false;
String ghidraVersion;
Program program;
TaskMonitor monitor;
boolean hasDebugSymbols;
RTTIClassRecoverer(Program program, ServiceProvider serviceProvider, FlatProgramAPI api,
boolean createBookmarks, boolean useShortTemplates, boolean nameVfunctions,
boolean hasDebugSymbols, TaskMonitor monitor) throws Exception {
RTTIClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
boolean nameVfunctions, boolean hasDebugSymbols, TaskMonitor monitor) throws Exception {
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
super(program, serviceProvider, api, createBookmarks, useShortTemplates, nameVfunctions,
monitor);
this.program = program;
this.monitor = monitor;
this.location = location;
this.tool = tool;
this.api = api;
this.createBookmarks = createBookmarks;
this.useShortTemplates = useShortTemplates;
this.nameVfunctions = nameVfunctions;
this.hasDebugSymbols = hasDebugSymbols;
ghidraVersion = getVersionOfGhidra();
}
public DecompilerScriptUtils getDecompilerUtils() {
return decompilerUtils;
}
@ -100,21 +89,15 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
return options.getString("Created With Ghidra Version", null);
}
public void fixUpProgram() throws CancelledException, Exception {
return;
}
public List<RecoveredClass> createRecoveredClasses() throws Exception {
return new ArrayList<RecoveredClass>();
}
/**
* Method to promote the namespace is a class namespace.
* @param namespace the namespace for the vftable
@ -129,12 +112,10 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
if (symbolType == SymbolType.CLASS) {
return newClass;
}
Msg.debug(this,
"Could not promote " + namespace.getName() + " to a class namespace");
Msg.debug(this, "Could not promote " + namespace.getName() + " to a class namespace");
return null;
}
/**
* Method to iterate over all the RecoveredClass objects and see if there is an existing class structure data type already
* if so, add it to the RecoveredClass object
@ -144,10 +125,8 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
public void retrieveExistingClassStructures(List<RecoveredClass> recoveredClasses)
throws CancelledException {
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
while (recoveredClassIterator.hasNext()) {
for (RecoveredClass recoveredClass : recoveredClasses) {
monitor.checkCancelled();
RecoveredClass recoveredClass = recoveredClassIterator.next();
// if class is non-virtual have to search for an existing class datatype
@ -156,16 +135,16 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
if (possibleExistingClassStructures.length == 0) {
continue;
}
for (int i = 0; i < possibleExistingClassStructures.length; i++) {
for (DataType possibleExistingClassStructure : possibleExistingClassStructures) {
monitor.checkCancelled();
if (!(possibleExistingClassStructures[i] instanceof Structure)) {
if (!(possibleExistingClassStructure instanceof Structure)) {
continue;
}
if (possibleExistingClassStructures[i].isNotYetDefined()) {
if (possibleExistingClassStructure.isNotYetDefined()) {
continue;
}
Structure existingClassStructure = (Structure) possibleExistingClassStructures[i];
Structure existingClassStructure = (Structure) possibleExistingClassStructure;
recoveredClass.addExistingClassStructure(existingClassStructure);
break;
@ -174,10 +153,8 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
//Iterate over constructor/destructor functions
List<Function> constructorOrDestructorFunctions =
recoveredClass.getConstructorOrDestructorFunctions();
Iterator<Function> constDestIterator = constructorOrDestructorFunctions.iterator();
while (constDestIterator.hasNext()) {
for (Function constDestFunction : constructorOrDestructorFunctions) {
monitor.checkCancelled();
Function constDestFunction = constDestIterator.next();
Namespace parentNamespace = constDestFunction.getParentNamespace();
if (!parentNamespace.equals(recoveredClass.getClassNamespace())) {
continue;
@ -220,8 +197,6 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
}
}
/**
* Method to get class data information from destructors if a class has no constructors
* @param recoveredClasses list of classes
@ -234,11 +209,8 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
throws CancelledException, DuplicateNameException, InvalidInputException,
CircularDependencyException {
Iterator<RecoveredClass> classIterator = recoveredClasses.iterator();
while (classIterator.hasNext()) {
for (RecoveredClass recoveredClass : recoveredClasses) {
monitor.checkCancelled();
RecoveredClass recoveredClass = classIterator.next();
// we can only figure out structure info for functions with vftable since that is
// what we use to determine which variable is being used to store the class structure
if (!recoveredClass.hasVftable()) {
@ -257,11 +229,8 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
memberFunctionsToProcess.addAll(recoveredClass.getIndeterminateList());
memberFunctionsToProcess.addAll(recoveredClass.getInlinedConstructorList());
Iterator<Function> memberFunctionIterator = memberFunctionsToProcess.iterator();
while (memberFunctionIterator.hasNext()) {
for (Function memberFunction : memberFunctionsToProcess) {
monitor.checkCancelled();
Function memberFunction = memberFunctionIterator.next();
if (getVftableReferences(memberFunction) == null) {
continue;
}
@ -278,9 +247,4 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
}
}
}

View file

@ -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 {
@ -152,22 +96,19 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
private Map<RecoveredClass, Map<RecoveredClass, Long>> classToParentOffsetMap =
new HashMap<RecoveredClass, Map<RecoveredClass, Long>>();
private Map<RecoveredClass, List<Vftable>> 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<ReferenceAddressPair> directReferenceList = new ArrayList<ReferenceAddressPair>();
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,8 +729,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
Vtable vtable = processMainVtable(mainVtable, map.get(mainVtable));
if (vtable == null) {
Msg.debug(this,
"MISSING expected vtable for simple class " +
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<Vtable> vtables,
List<Address> knownVtts)
throws CancelledException {
List<Address> knownVtts) throws CancelledException {
// make list of all vtable tops and vftable tops
List<Address> 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<Address> vtableAddresses,
List<Address> constructionVtables)
throws CancelledException {
List<Address> constructionVtables) throws CancelledException {
List<Address> mainVtableCandidates = new ArrayList<Address>();
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<Address, Set<Address>> findTypeinfoReferencesNotInTypeinfoStructsOld(
List<Address> typeinfoAddresses)
throws CancelledException {
List<Address> 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<Address, Set<Address>> directRefMap = new HashMap<Address, Set<Address>>();
Map<Address, Set<Address>> refMap = new HashMap<Address, Set<Address>>();
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<Address, Set<Address>> findTypeinfoReferencesNotInTypeinfoStructs(
List<GccTypeinfo> typeinfos)
throws CancelledException {
List<GccTypeinfo> 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<Address, Set<Address>> typeinfoRefMap,
Address typeinfoAddress, byte[] bytes, TaskMonitor taskMonitor) {
Map<Address, Set<Address>> 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<GccTypeinfo> typeinfos,
Map<Address, GccTypeinfo> typeinfoMap)
throws CancelledException {
Map<Address, GccTypeinfo> typeinfoMap) throws CancelledException {
List<GccTypeinfo> invalidTypeinfos = new ArrayList<GccTypeinfo>();
for (GccTypeinfo typeinfo : typeinfos) {
@ -2549,8 +2468,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
// SI_CLASS_TYPE_INFO_STRUCTURE
if (!isTypeinfoStruct(siTypeinfoStructure)) {
throw new IllegalArgumentException(
siTypeinfoStructure.getAddressString(false, false) +
throw new IllegalArgumentException(siTypeinfoStructure.getAddressString(false, false) +
" is not a typeinfo structure");
}
@ -2604,8 +2522,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
extendedFlatAPI.getReferencedAddress(baseClassStructureAddress, false);
if (baseTypeinfoAddress == null) {
Msg.debug(this,
typeinfo.getAddress() +
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,8 +2833,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
Namespace classNamespace = typeinfoNameSymbol.getParentNamespace();
if (classNamespace.isGlobal()) {
Msg.debug(this,
typeinfoAddress.toString() +
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<RecoveredClass> recoveredClasses)
throws CancelledException, InvalidInputException, DuplicateNameException,
CircularDependencyException {
List<RecoveredClass> recoveredClasses) throws CancelledException, InvalidInputException,
DuplicateNameException, CircularDependencyException {
Iterator<RecoveredClass> 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<RecoveredClass> 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<RecoveredClass> 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<GccTypeinfo> specialTypeinfos)
throws CancelledException {
List<GccTypeinfo> 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<GccTypeinfo> specialTypeinfos)
throws CancelledException {
List<GccTypeinfo> specialTypeinfos) throws CancelledException {
List<Address> 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) {
@ -4097,7 +3991,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
baseOffsets.add(baseTypeinfo.getOffset());
}
if (baseOffsets.size() != vftableAddresses.size()) {
Msg.debug(this,
@ -4133,7 +4026,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
}
}
/**
* 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<RecoveredClass> parentList = recoveredClass.getParentList();
Iterator<RecoveredClass> 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<RecoveredClass> classHierarchy = recoveredClass.getClassHierarchy();
Iterator<RecoveredClass> 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<RecoveredClass> parentList = recoveredClass.getParentList();
Iterator<RecoveredClass> 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,8 +4428,7 @@ 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 " +
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,8 +4555,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
Map<Integer, RecoveredClass> orderToParentMap =
classToParentOrderMap.get(recoveredClass);
if (orderToParentMap == null || orderToParentMap.isEmpty()) {
Msg.error(this,
"Vmi class " + recoveredClass.getClassNamespace().getName(true) +
Msg.error(this, "Vmi class " + recoveredClass.getClassNamespace().getName(true) +
" should have a parent in the classToParentOrderMap but doesn't");
return null;
}
@ -4683,8 +4563,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
Map<RecoveredClass, Long> parentToOffsetMap =
classToParentOffsetMap.get(recoveredClass);
if (parentToOffsetMap.isEmpty()) {
Msg.error(this,
"Vmi class " + recoveredClass.getClassNamespace().getName(true) +
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);
}
}

View file

@ -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<Address> classHierarchyDescriptorAddresses = new ArrayList<Address>();
Iterator<Symbol> 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<Symbol> 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<Address> baseClassArrayAddresses = new ArrayList<Address>();
Iterator<Address> 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<Symbol> vftables = new ArrayList<Symbol>();
Iterator<Symbol> 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<Symbol> classHierarchyDescriptorList = getListOfClassHierarchyDescriptors();
Iterator<Symbol> 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<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
while (recoveredClassIterator.hasNext()) {
for (RecoveredClass recoveredClass : recoveredClasses) {
monitor.checkCancelled();
RecoveredClass recoveredClass = recoveredClassIterator.next();
List<Address> vftableAddresses = recoveredClass.getVftableAddresses();
Iterator<Address> 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<RecoveredClass> recoveredClasses)
throws Exception {
Iterator<RecoveredClass> 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<Function> 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<Function> 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<HighVariable> highVariableIterator = highVariables.iterator();
for (HighVariable highVariable : highVariables) {
while (highVariableIterator.hasNext()) {
HighVariable highVariable = highVariableIterator.next();
monitor.checkCancelled();
fillCmd.processStructure(highVariable, function);
List<OffsetPcodeOpPair> stores = fillCmd.getStorePcodeOps();
fillStructHelper.processStructure(highVariable, function, true, false);
List<OffsetPcodeOpPair> stores = fillStructHelper.getStorePcodeOps();
stores = removePcodeOpsNotInFunction(function, stores);
// this method checks the storedPcodeOps to see if one is a vftable address
Iterator<OffsetPcodeOpPair> 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<RecoveredClass> recoveredClasses)
throws Exception {
Iterator<RecoveredClass> 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<RecoveredClass> classHierarchy = recoveredClass.getClassHierarchy();
Iterator<RecoveredClass> 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<RecoveredClass> classHierarchy = recoveredClass.getClassHierarchy();
Iterator<RecoveredClass> 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<RecoveredClass, Boolean> parentToBaseTypeMap = recoveredClass.getParentToBaseTypeMap();
List<RecoveredClass> parents = new ArrayList<RecoveredClass>(classHierarchyMap.keySet());
Iterator<RecoveredClass> 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<Integer> 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<Function> functionIterator = functionList.iterator();
while (functionIterator.hasNext()) {
for (Function function : functionList) {
monitor.checkCancelled();
Function function = functionIterator.next();
parentOrderMap = new HashMap<Integer, RecoveredClass>();
Map<Address, RecoveredClass> referenceToParentMap =
@ -1986,12 +1908,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
new HashMap<Address, RecoveredClass>();
List<Address> classReferences = new ArrayList<Address>(referenceToParentMap.keySet());
Iterator<Address> 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<Address> 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<RecoveredClass> updatedParentClasses = new ArrayList<RecoveredClass>(parentClasses);
// now iterate over the direct parents and map that parent to each ancestor on the ancestor with vfunction list
Iterator<RecoveredClass> parentIterator = parentClasses.iterator();
while (parentIterator.hasNext()) {
for (RecoveredClass parentClass : parentClasses) {
monitor.checkCancelled();
RecoveredClass parentClass = parentIterator.next();
List<RecoveredClass> ancestors =
new ArrayList<RecoveredClass>(parentClass.getClassHierarchy());
ancestors.remove(parentClass);
@ -2088,12 +2003,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
continue;
}
Iterator<RecoveredClass> ancestorIterator = ancestors.iterator();
while (ancestorIterator.hasNext()) {
for (RecoveredClass ancestor : ancestors) {
monitor.checkCancelled();
RecoveredClass ancestor = ancestorIterator.next();
List<RecoveredClass> decendentList = ancestorToCommonChild.get(ancestor);
if (decendentList == null) {
List<RecoveredClass> newDecendentList = new ArrayList<RecoveredClass>();
@ -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<RecoveredClass> ancestorsIterator = keySet.iterator();
while (ancestorsIterator.hasNext()) {
for (RecoveredClass ancestor : keySet) {
monitor.checkCancelled();
RecoveredClass ancestor = ancestorsIterator.next();
List<RecoveredClass> commonChildList = ancestorToCommonChild.get(ancestor);
if (commonChildList != null && commonChildList.size() >= 2) {
if (!updatedParentClasses.contains(ancestor)) {

View file

@ -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();

View file

@ -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.

View file

@ -0,0 +1,182 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.decompiler.util;
import java.util.Objects;
import ghidra.app.decompiler.*;
import ghidra.app.decompiler.component.DecompilerUtils;
import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
import ghidra.program.model.pcode.*;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.util.*;
import ghidra.util.Msg;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
/**
* Automatically creates a structure definition based on the references found by the decompiler.
*
* If the parameter is already a structure pointer, any new references found will be added
* to the structure, even if the structure must grow.
*
*/
public class FillOutStructureCmd extends BackgroundCommand<Program> {
private DecompileOptions decompileOptions;
private ProgramLocation location;
/**
* Constructor.
*
* @param location the current program location. Supported location types include:
* {@link DecompilerLocation}, {@link VariableLocation} or
* {@link FunctionParameterFieldLocation}.
* @param decompileOptions decompiler options.
* (see {@link DecompilerUtils#getDecompileOptions(ServiceProvider, Program)})
*/
public FillOutStructureCmd(ProgramLocation location, DecompileOptions decompileOptions) {
super("Fill Out Structure", true, false, true);
this.decompileOptions = Objects.requireNonNull(decompileOptions);
this.location = Objects.requireNonNull(location);
}
@Override
public boolean applyTo(Program program, TaskMonitor monitor) {
if (program != location.getProgram()) {
throw new AssertionError("program does not match location");
}
try {
Function function =
program.getFunctionManager().getFunctionContaining(location.getAddress());
if (function == null) {
setStatusMsg("Function not found at " + location.getAddress());
return false;
}
FillOutStructureHelper fillStructureHelper =
new FillOutStructureHelper(program, decompileOptions, monitor);
HighVariable var = null;
if (!(location instanceof DecompilerLocation dloc)) {
// if we don't have one, make one, and map variable to a varnode
Address storageAddr = computeStorageAddress(function);
var = fillStructureHelper.computeHighVariable(storageAddr, function);
}
else {
// get the Varnode under the cursor
ClangToken token = dloc.getToken();
if (token == null) {
setStatusMsg("Unable to identify variable from decompiler token");
return false;
}
var = token.getHighVariable();
Varnode exactSpot = token.getVarnode();
if ((var != null) && (exactSpot != null)) {
HighFunction hfunc = var.getHighFunction();
try { // Adjust HighVariable based on exact varnode selected, if there are merged groups
var = hfunc.splitOutMergeGroup(var, exactSpot);
}
catch (PcodeException ex) {
setStatusMsg("Unable to isolate variable from merged group");
return false;
}
}
}
Structure structDT = fillStructureHelper.processStructure(var, function, false, true);
if (structDT == null) {
setStatusMsg("Failed to fill-out structure");
return false;
}
DataType pointerDT = new PointerDataType(structDT);
// Delay adding to the manager until full structure is accumulated
pointerDT = program.getDataTypeManager()
.addDataType(pointerDT, DataTypeConflictHandler.DEFAULT_HANDLER);
boolean isThisParam = DecompilerUtils.testForAutoParameterThis(var, function);
if (!isThisParam) {
commitVariable(var, pointerDT, isThisParam);
}
return true;
}
catch (Exception e) {
Msg.showError(this, null, "Auto Create Structure Failed",
"Failed to create Structure variable", e);
}
return false;
}
/**
* Retype the HighVariable to a given data-type to the database
* @param var is the decompiler variable to retype
* @param newDt is the data-type
* @param isThisParam is true if the variable is a 'this' pointer
*/
private void commitVariable(HighVariable var, DataType newDt, boolean isThisParam) {
if (!isThisParam) {
try {
HighFunctionDBUtil.updateDBVariable(var.getSymbol(), null, newDt,
SourceType.USER_DEFINED);
}
catch (DuplicateNameException e) {
throw new AssertException("Unexpected exception", e);
}
catch (InvalidInputException e) {
Msg.error(this,
"Failed to re-type variable " + var.getName() + ": " + e.getMessage());
}
}
}
/**
* Compute the storage address associated with a particular Location
* @param function is the function owning the location
* @return the corresponding storage address or null
*/
private Address computeStorageAddress(Function function) {
Address storageAddress = null;
// make sure what we are over can be mapped to decompiler
// param, local, etc...
if (location instanceof VariableLocation) {
VariableLocation varLoc = (VariableLocation) location;
storageAddress = varLoc.getVariable().getVariableStorage().getMinAddress();
}
else if (location instanceof FunctionParameterFieldLocation) {
FunctionParameterFieldLocation funcPFL = (FunctionParameterFieldLocation) location;
storageAddress = funcPFL.getParameter().getVariableStorage().getMinAddress();
}
return storageAddress;
}
}

View file

@ -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<Address, Address> addressToCallInputMap = new HashMap<>();
private Program currentProgram;
private ProgramLocation currentLocation;
private Function rootFunction;
private TaskMonitor monitor;
private PluginTool tool;
private List<OffsetPcodeOpPair> storePcodeOps = new ArrayList<>();
private List<OffsetPcodeOpPair> 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 <B>this</B> 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();
Structure structDT = null;
if (!createNewStructure) {
structDT = getStructureForExtending(var.getDataType());
if (structDT != null) {
componentMap.populateOriginalStructure(structDT);
}
}
try {
fillOutStructureDef(var);
pushIntoCalls();
structDT = createStructure(null, var, function, false);
populateStructure(structDT);
}
catch (Exception e) {
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<OffsetPcodeOpPair> 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<OffsetPcodeOpPair> 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();
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;
}
/**
* 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(symbol, name, newNamespace, SourceType.USER_DEFINED);
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;
}
// 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);
}
expandStructureSizeIfNeeded(structDT, size);
return structDT;
}
String structName = createUniqueStructName(var, DEFAULT_CATEGORY, DEFAULT_BASENAME);
StructureDataType dt = new StructureDataType(new CategoryPath(DEFAULT_CATEGORY), structName,
size, f.getProgram().getDataTypeManager());
return dt;
private boolean programContainsNamedStructure(String structName) {
ProgramBasedDataTypeManager dtm = currentProgram.getDataTypeManager();
List<DataType> list = new ArrayList<>();
dtm.findDataTypes(structName, list, true, monitor);
for (DataType dt : list) {
if (dt instanceof Structure) {
return true;
}
}
return false;
}
private Namespace createUniqueClassName(Namespace rootNamespace) {
/**
* 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
*/

View file

@ -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);
}
}

View file

@ -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) {

View file

@ -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);

View file

@ -27,7 +27,6 @@ import ghidra.app.util.pdb.pdbapplicator.DefaultPdbApplicator;
import ghidra.app.util.pdb.pdbapplicator.PdbApplicatorOptions;
import ghidra.framework.*;
import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject;
import ghidra.framework.options.OptionType;
import ghidra.framework.options.Options;
import ghidra.program.model.address.AddressSetView;
@ -192,9 +191,8 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
* @throws CancelledException upon user cancellation
*/
public static boolean doAnalysis(Program program, File pdbFile,
PdbReaderOptions pdbReaderOptions,
PdbApplicatorOptions pdbApplicatorOptions, MessageLog log, TaskMonitor monitor)
throws CancelledException {
PdbReaderOptions pdbReaderOptions, PdbApplicatorOptions pdbApplicatorOptions,
MessageLog log, TaskMonitor monitor) throws CancelledException {
PdbLog.message(
"================================================================================");
PdbLog.message(new Date(System.currentTimeMillis()).toString() + "\n");
@ -236,8 +234,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
AnalysisPriority.DATA_TYPE_PROPOGATION.after().after().after().priority());
// Following is intended to be the last PDB analysis background command
aam.schedule(
new PdbReportingBackgroundCommand(),
aam.schedule(new PdbReportingBackgroundCommand(),
AnalysisPriority.DATA_TYPE_PROPOGATION.after().after().after().after().priority());
}
@ -340,7 +337,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
* local variables and other things that might make sense to process in the first phase
* (for now, they will be in the second phase).
*/
private static class ProcessPdbFunctionInternalsCommand extends BackgroundCommand {
private static class ProcessPdbFunctionInternalsCommand extends BackgroundCommand<Program> {
File pdbFile;
private PdbReaderOptions pdbReaderOptions;
@ -357,14 +354,13 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
}
@Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
Program program = (Program) obj;
public boolean applyTo(Program program, TaskMonitor monitor) {
try (AbstractPdb pdb = PdbParser.parse(pdbFile, pdbReaderOptions, monitor)) {
monitor.setMessage("PDB: Parsing " + pdbFile + "...");
pdb.deserialize();
DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdb, program,
program.getDataTypeManager(), program.getImageBase(), pdbApplicatorOptions,
log);
DefaultPdbApplicator applicator =
new DefaultPdbApplicator(pdb, program, program.getDataTypeManager(),
program.getImageBase(), pdbApplicatorOptions, log);
applicator.applyFunctionInternalsAnalysis();
return true;
}
@ -382,15 +378,14 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
/**
* A background command that performs final PDB analysis reporting.
*/
private static class PdbReportingBackgroundCommand extends BackgroundCommand {
private static class PdbReportingBackgroundCommand extends BackgroundCommand<Program> {
public PdbReportingBackgroundCommand() {
super("PDB Universal Reporting", false, false, false);
}
@Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
Program program = (Program) obj;
public boolean applyTo(Program program, TaskMonitor monitor) {
try {
DefaultPdbApplicator.applyAnalysisReporting(program);
return true;

View file

@ -16,11 +16,15 @@
*/
package ghidra.app.plugin.core.diff;
import java.lang.reflect.InvocationTargetException;
import javax.swing.SwingUtilities;
import docking.widgets.dialogs.ReadTextDialog;
import ghidra.app.events.ProgramSelectionPluginEvent;
import ghidra.app.plugin.core.analysis.AnalysisWorker;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
@ -28,17 +32,11 @@ import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import java.lang.reflect.InvocationTargetException;
import javax.swing.SwingUtilities;
import docking.widgets.dialogs.ReadTextDialog;
/**
* Command to apply diffs to current program.
*
*/
class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
class ApplyDiffCommand extends BackgroundCommand<Program> implements AnalysisWorker {
private AddressSetView p1AddressSet;
private DiffController diffControl;
@ -47,9 +45,6 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
private boolean applied;
private ProgramDiffPlugin plugin;
/**
* Constructor.
*/
ApplyDiffCommand(ProgramDiffPlugin plugin, AddressSetView program1AddressSet,
DiffController diffControl) {
super("Apply Differences", false, true, true);
@ -59,8 +54,8 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
}
@Override
public boolean analysisWorkerCallback(Program program, Object workerContext, TaskMonitor monitor)
throws Exception, CancelledException {
public boolean analysisWorkerCallback(Program program, Object workerContext,
TaskMonitor monitor) throws Exception, CancelledException {
// Diff apply done with analysis disabled
return diffControl.apply(p1AddressSet, monitor);
}
@ -70,11 +65,8 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
return getName();
}
/**
* @see ghidra.framework.cmd.BackgroundCommand#applyTo(ghidra.framework.model.DomainObject, ghidra.util.task.TaskMonitor)
*/
@Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
public boolean applyTo(Program program, TaskMonitor monitor) {
monitor.setMessage("ApplyDiffTask starting...");
applied = false;
final ProgramLocation origLocation = plugin.getProgramLocation();
@ -90,9 +82,8 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
AutoAnalysisManager.getAnalysisManager(plugin.getFirstProgram());
boolean merged = autoAnalysisManager.scheduleWorker(this, null, false, monitor);
if (merged) {
statusMsg =
"Apply differences has finished."
+ " If your expected change didn't occur, check your Diff Apply Settings.";
statusMsg = "Apply differences has finished." +
" If your expected change didn't occur, check your Diff Apply Settings.";
title = "Program Diff: Apply differences has finished.";
applied = true;
}
@ -114,15 +105,14 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
}
}
Msg.showError(this, plugin.getListingPanel(), "Error Applying Diff",
"An error occurred while applying differences.\n"
+ "Only some of the differences may have been applied.",
"An error occurred while applying differences.\n" +
"Only some of the differences may have been applied.",
(t != null) ? t : e);
applyMsg = message + diffControl.getApplyMessage();
}
catch (CancelledException e) {
statusMsg =
"User cancelled \"Apply Differences\". "
+ "Differences were only partially applied.";
statusMsg = "User cancelled \"Apply Differences\". " +
"Differences were only partially applied.";
applyMsg = diffControl.getApplyMessage();
}
finally {