mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
Merge remote-tracking branch 'origin/GP-4408_ghidra1_FillOutStructureCmdCleanup--SQUASHED'
This commit is contained in:
commit
c89d72bad5
25 changed files with 1262 additions and 1791 deletions
|
@ -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()) {
|
||||
|
|
|
@ -148,11 +148,11 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
|
|||
return currentProgram != null;
|
||||
}
|
||||
};
|
||||
findTableAction.setHelpLocation(
|
||||
new HelpLocation(HelpTopics.SEARCH, findTableAction.getName()));
|
||||
findTableAction.setMenuBarData(new MenuData(
|
||||
new String[] { ToolConstants.MENU_SEARCH, "For Address Tables" }, null, "search for",
|
||||
-1, "AddressTables"));
|
||||
findTableAction
|
||||
.setHelpLocation(new HelpLocation(HelpTopics.SEARCH, findTableAction.getName()));
|
||||
findTableAction.setMenuBarData(
|
||||
new MenuData(new String[] { ToolConstants.MENU_SEARCH, "For Address Tables" }, null,
|
||||
"search for", -1, "AddressTables"));
|
||||
findTableAction.setDescription(getPluginDescription().getDescription());
|
||||
findTableAction.addToWindowWhen(NavigatableActionContext.class);
|
||||
tool.addAction(findTableAction);
|
||||
|
@ -168,15 +168,15 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
|
|||
|
||||
int minimumTableSize = addressTableDialog.getMinTableSize();
|
||||
if (minimumTableSize < 2) {
|
||||
addressTableDialog.setDialogText(
|
||||
"Please enter a valid minimum search length. Must be >= 2");
|
||||
addressTableDialog
|
||||
.setDialogText("Please enter a valid minimum search length. Must be >= 2");
|
||||
return;
|
||||
}
|
||||
|
||||
int alignment = addressTableDialog.getAlignment();
|
||||
if (alignment <= 0 || alignment > 8) {
|
||||
addressTableDialog.setDialogText(
|
||||
"Please enter a valid alignment value. Must be > 0 and <= 8");
|
||||
addressTableDialog
|
||||
.setDialogText("Please enter a valid alignment value. Must be > 0 and <= 8");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -217,8 +217,8 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
|
|||
selectedAddresses[i] = model.getAddress(selectedRows[i]);
|
||||
}
|
||||
|
||||
CompoundBackgroundCommand backCmd =
|
||||
new CompoundBackgroundCommand("Disassemble Address Tables", false, true);
|
||||
CompoundBackgroundCommand<Program> backCmd =
|
||||
new CompoundBackgroundCommand<>("Disassemble Address Tables", false, true);
|
||||
offsetLen = addressTableDialog.getOffset();
|
||||
|
||||
// loop over selected table addresses
|
||||
|
@ -237,7 +237,7 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
|
|||
tool.executeBackgroundCommand(backCmd, currentProgram);
|
||||
}
|
||||
|
||||
private void createDisassemblyCommandsForAddress(CompoundBackgroundCommand backCmd,
|
||||
private void createDisassemblyCommandsForAddress(CompoundBackgroundCommand<Program> backCmd,
|
||||
Address currentAddress) {
|
||||
|
||||
Listing listing = currentProgram.getListing();
|
||||
|
@ -261,8 +261,8 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
|
|||
|
||||
// need to create a context for each one. Also disassembleCmd will align the address to disassemble
|
||||
DisassembleCommand disassembleCmd = new DisassembleCommand(addr, null, true);
|
||||
RegisterValue rval = PseudoDisassembler.getTargetContextRegisterValueForDisassembly(
|
||||
currentProgram, addr);
|
||||
RegisterValue rval = PseudoDisassembler
|
||||
.getTargetContextRegisterValueForDisassembly(currentProgram, addr);
|
||||
disassembleCmd.setInitialContext(rval);
|
||||
backCmd.add(disassembleCmd);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ import ghidra.app.plugin.PluginCategoryNames;
|
|||
import ghidra.app.util.bean.SetEquateDialog;
|
||||
import ghidra.app.util.bean.SetEquateDialog.SelectionType;
|
||||
import ghidra.app.util.datatype.ApplyEnumDialog;
|
||||
import ghidra.framework.cmd.BackgroundCommand;
|
||||
import ghidra.framework.cmd.CompoundBackgroundCommand;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
|
@ -182,7 +181,7 @@ public class EquatePlugin extends Plugin {
|
|||
iter = listing.getCodeUnits(context.getProgram().getMemory(), true);
|
||||
}
|
||||
|
||||
BackgroundCommand cmd = new CreateEquateCmd(scalar, iter, dialog.getEquateName(),
|
||||
CreateEquateCmd cmd = new CreateEquateCmd(scalar, iter, dialog.getEquateName(),
|
||||
dialog.getOverwriteExisting(), context);
|
||||
tool.executeBackgroundCommand(cmd, context.getProgram());
|
||||
|
||||
|
@ -297,8 +296,8 @@ public class EquatePlugin extends Plugin {
|
|||
|
||||
// Set up a background task that we'll populate with all the rename tasks we need
|
||||
// to perform.
|
||||
CompoundBackgroundCommand bckCmd =
|
||||
new CompoundBackgroundCommand("Rename Equates in Selection", false, true);
|
||||
CompoundBackgroundCommand<Program> bckCmd =
|
||||
new CompoundBackgroundCommand<>("Rename Equates in Selection", false, true);
|
||||
|
||||
// Now loop over all the code units and search for matching scalars...
|
||||
while (iter.hasNext()) {
|
||||
|
@ -312,7 +311,7 @@ public class EquatePlugin extends Plugin {
|
|||
}
|
||||
|
||||
private void renameEquateForCodeUnit(ListingActionContext context, Enum enoom, Equate equate,
|
||||
String newName, String oldName, CompoundBackgroundCommand bgCmd, CodeUnit cu) {
|
||||
String newName, String oldName, CompoundBackgroundCommand<Program> bgCmd, CodeUnit cu) {
|
||||
|
||||
if (cu instanceof Instruction) {
|
||||
|
||||
|
@ -348,8 +347,8 @@ public class EquatePlugin extends Plugin {
|
|||
CodeUnitIterator iter) {
|
||||
|
||||
// Create a background task to process all the remove tasks.
|
||||
CompoundBackgroundCommand bckCmd =
|
||||
new CompoundBackgroundCommand("Remove Equates in Selection", false, true);
|
||||
CompoundBackgroundCommand<Program> bckCmd =
|
||||
new CompoundBackgroundCommand<>("Remove Equates in Selection", false, true);
|
||||
|
||||
// Now iterate over all code units in the iterator.
|
||||
while (iter.hasNext()) {
|
||||
|
@ -362,7 +361,7 @@ public class EquatePlugin extends Plugin {
|
|||
}
|
||||
|
||||
private void removeEquateForCodeUnit(ListingActionContext context, Equate equate,
|
||||
CompoundBackgroundCommand bckCmd, CodeUnit cu) {
|
||||
CompoundBackgroundCommand<Program> bckCmd, CodeUnit cu) {
|
||||
// A code unit can be either an instruction or data; we need to handle each
|
||||
// separately.
|
||||
if (cu instanceof Instruction) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
|||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -33,15 +33,33 @@
|
|||
//@category Data Types
|
||||
//@keybinding F6
|
||||
|
||||
import ghidra.app.plugin.core.decompile.actions.FillOutStructureCmd;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.app.decompiler.DecompileOptions;
|
||||
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||
import ghidra.app.decompiler.util.FillOutStructureCmd;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
|
||||
public class CreateStructure extends GhidraScript {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
FillOutStructureCmd fillCmd =
|
||||
new FillOutStructureCmd(currentProgram, currentLocation, state.getTool());
|
||||
fillCmd.applyTo(currentProgram, this.monitor);
|
||||
|
||||
if (currentProgram == null || currentLocation == null) {
|
||||
popup("Requires open program and location");
|
||||
return;
|
||||
}
|
||||
|
||||
DecompileOptions decompileOptions =
|
||||
DecompilerUtils.getDecompileOptions(state.getTool(), currentProgram);
|
||||
FillOutStructureCmd cmd = new FillOutStructureCmd(currentLocation, decompileOptions);
|
||||
if (!cmd.applyTo(currentProgram, this.monitor)) {
|
||||
String detail = "";
|
||||
String msg = cmd.getStatusMsg();
|
||||
if (!StringUtils.isBlank(msg)) {
|
||||
detail = ": " + msg;
|
||||
}
|
||||
popup("Failed to fill-out structure" + detail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -190,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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -254,8 +254,7 @@ public class ShowConstantUse extends GhidraScript {
|
|||
ConstUseLocation entry = (ConstUseLocation) rowObject;
|
||||
Function func = entry.getProgram()
|
||||
.getFunctionManager()
|
||||
.getFunctionContaining(
|
||||
entry.getAddress());
|
||||
.getFunctionContaining(entry.getAddress());
|
||||
if (func == null) {
|
||||
return "";
|
||||
}
|
||||
|
@ -762,9 +761,7 @@ public class ShowConstantUse extends GhidraScript {
|
|||
if (defUseList == null || defUseList.size() <= 0) {
|
||||
return value;
|
||||
}
|
||||
Iterator<PcodeOp> iterator = defUseList.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
PcodeOp pcodeOp = iterator.next();
|
||||
for (PcodeOp pcodeOp : defUseList) {
|
||||
int opcode = pcodeOp.getOpcode();
|
||||
switch (opcode) {
|
||||
case PcodeOp.INT_AND:
|
||||
|
@ -970,8 +967,7 @@ public class ShowConstantUse extends GhidraScript {
|
|||
}
|
||||
|
||||
private void followThroughGlobal(HashMap<Address, Long> constUse, ArrayList<PcodeOp> defUseList,
|
||||
HighVariable hvar,
|
||||
ArrayList<FunctionParamUse> funcList,
|
||||
HighVariable hvar, ArrayList<FunctionParamUse> funcList,
|
||||
HashSet<SequenceNumber> doneSet) {
|
||||
Address loc = hvar.getRepresentative().getAddress();
|
||||
PcodeOp def = hvar.getRepresentative().getDef();
|
||||
|
@ -1013,6 +1009,7 @@ public class ShowConstantUse extends GhidraScript {
|
|||
private Address lastDecompiledFuncAddr = null;
|
||||
|
||||
private DecompInterface setUpDecompiler(Program program) {
|
||||
|
||||
DecompInterface decompInterface = new DecompInterface();
|
||||
|
||||
// call it to get results
|
||||
|
@ -1021,13 +1018,8 @@ public class ShowConstantUse extends GhidraScript {
|
|||
return null;
|
||||
}
|
||||
|
||||
DecompileOptions options;
|
||||
options = new DecompileOptions();
|
||||
OptionsService service = state.getTool().getService(OptionsService.class);
|
||||
if (service != null) {
|
||||
ToolOptions opt = service.getOptions("Decompiler");
|
||||
options.grabFromToolAndProgram(null, opt, program);
|
||||
}
|
||||
DecompileOptions options = DecompilerUtils.getDecompileOptions(state.getTool(), program);
|
||||
|
||||
decompInterface.setOptions(options);
|
||||
|
||||
decompInterface.toggleCCode(true);
|
||||
|
|
|
@ -27,10 +27,11 @@
|
|||
//
|
||||
//@category Analysis
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.decompiler.*;
|
||||
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.PrototypeModel;
|
||||
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -15,71 +15,55 @@
|
|||
*/
|
||||
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS.
|
||||
package classrecovery;
|
||||
|
||||
import docking.options.OptionsService;
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.decompiler.DecompileOptions;
|
||||
import ghidra.app.decompiler.DecompileResults;
|
||||
import ghidra.app.decompiler.*;
|
||||
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.ParameterDefinition;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.pcode.FunctionPrototype;
|
||||
import ghidra.program.model.pcode.HighFunction;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
import ghidra.program.model.pcode.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class DecompilerScriptUtils {
|
||||
|
||||
private Program program;
|
||||
private PluginTool tool;
|
||||
private ServiceProvider serviceProvider;
|
||||
private TaskMonitor monitor;
|
||||
|
||||
private DecompInterface decompInterface;
|
||||
|
||||
DecompilerScriptUtils(Program program, PluginTool tool, TaskMonitor monitor) {
|
||||
DecompilerScriptUtils(Program program, ServiceProvider serviceProvider, TaskMonitor monitor) {
|
||||
this.program = program;
|
||||
this.monitor = monitor;
|
||||
this.tool = tool;
|
||||
this.serviceProvider = serviceProvider;
|
||||
|
||||
decompInterface = setupDecompilerInterface();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to setup the decompiler interface for the given program
|
||||
* @return the interface to the decompiler
|
||||
* @return the interface to the decompiler or null if failed to open program
|
||||
*/
|
||||
public DecompInterface setupDecompilerInterface() {
|
||||
|
||||
decompInterface = new DecompInterface();
|
||||
|
||||
DecompileOptions options;
|
||||
options = new DecompileOptions();
|
||||
|
||||
if (tool == null) {
|
||||
options.grabFromProgram(program);
|
||||
}
|
||||
else {
|
||||
OptionsService service = tool.getService(OptionsService.class);
|
||||
if (service != null) {
|
||||
ToolOptions opt = service.getOptions("Decompiler");
|
||||
options.grabFromToolAndProgram(null, opt, program);
|
||||
}
|
||||
else {
|
||||
options.grabFromProgram(program);
|
||||
}
|
||||
}
|
||||
DecompileOptions options = DecompilerUtils.getDecompileOptions(serviceProvider, program);
|
||||
|
||||
decompInterface.setOptions(options);
|
||||
|
||||
decompInterface.toggleCCode(true);
|
||||
decompInterface.toggleSyntaxTree(true);
|
||||
decompInterface.setSimplificationStyle("decompile");
|
||||
|
||||
if (!decompInterface.openProgram(program)) {
|
||||
decompInterface.dispose();
|
||||
return null;
|
||||
}
|
||||
return decompInterface;
|
||||
|
@ -90,7 +74,6 @@ public class DecompilerScriptUtils {
|
|||
return decompInterface;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method to decompile the given function and return the function's HighFunction
|
||||
* @param function the given function
|
||||
|
@ -126,7 +109,6 @@ public class DecompilerScriptUtils {
|
|||
return decompRes.getHighFunction().getFunctionPrototype().getReturnType();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method to retrieve the function signature string from the decompiler function prototype. NOTE:
|
||||
* if there is a this param, it will not be included.
|
||||
|
@ -153,7 +135,6 @@ public class DecompilerScriptUtils {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
HighFunction highFunction = decompRes.getHighFunction();
|
||||
|
||||
FunctionPrototype functionPrototype = highFunction.getFunctionPrototype();
|
||||
|
|
|
@ -16,17 +16,17 @@
|
|||
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS.
|
||||
package classrecovery;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.NamespaceUtils;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.program.flatapi.FlatProgramAPI;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -36,32 +36,21 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
|||
boolean programHasRTTIApplied = false;
|
||||
|
||||
String ghidraVersion;
|
||||
Program program;
|
||||
TaskMonitor monitor;
|
||||
|
||||
boolean hasDebugSymbols;
|
||||
|
||||
RTTIClassRecoverer(Program program, ServiceProvider serviceProvider, FlatProgramAPI api,
|
||||
boolean createBookmarks, boolean useShortTemplates, boolean nameVfunctions,
|
||||
boolean hasDebugSymbols, TaskMonitor monitor) throws Exception {
|
||||
|
||||
RTTIClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
|
||||
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
||||
boolean nameVfunctions, boolean hasDebugSymbols, TaskMonitor monitor) throws Exception {
|
||||
|
||||
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
|
||||
super(program, serviceProvider, api, createBookmarks, useShortTemplates, nameVfunctions,
|
||||
monitor);
|
||||
|
||||
this.program = program;
|
||||
this.monitor = monitor;
|
||||
this.location = location;
|
||||
this.tool = tool;
|
||||
this.api = api;
|
||||
this.createBookmarks = createBookmarks;
|
||||
this.useShortTemplates = useShortTemplates;
|
||||
this.nameVfunctions = nameVfunctions;
|
||||
this.hasDebugSymbols = hasDebugSymbols;
|
||||
|
||||
ghidraVersion = getVersionOfGhidra();
|
||||
}
|
||||
|
||||
|
||||
public DecompilerScriptUtils getDecompilerUtils() {
|
||||
return decompilerUtils;
|
||||
}
|
||||
|
@ -100,21 +89,15 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
|||
return options.getString("Created With Ghidra Version", null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void fixUpProgram() throws CancelledException, Exception {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
public List<RecoveredClass> createRecoveredClasses() throws Exception {
|
||||
|
||||
return new ArrayList<RecoveredClass>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Method to promote the namespace is a class namespace.
|
||||
* @param namespace the namespace for the vftable
|
||||
|
@ -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 {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -776,22 +776,18 @@ public class DecompInterface {
|
|||
public synchronized DecompileResults decompileFunction(Function func, int timeoutSecs,
|
||||
TaskMonitor monitor) {
|
||||
|
||||
dtmanage.clearTemporaryIds();
|
||||
decompileMessage = "";
|
||||
if (monitor != null && monitor.isCancelled()) {
|
||||
return null;
|
||||
|
||||
if (program == null || (monitor != null && monitor.isCancelled())) {
|
||||
return new DecompileResults(func, pcodelanguage, compilerSpec, dtmanage,
|
||||
decompileMessage, null, DecompileProcess.DisposeState.DISPOSED_ON_CANCEL);
|
||||
}
|
||||
|
||||
if (monitor != null) {
|
||||
monitor.addCancelledListener(monitorListener);
|
||||
}
|
||||
|
||||
dtmanage.clearTemporaryIds();
|
||||
|
||||
if (program == null) {
|
||||
return new DecompileResults(func, pcodelanguage, null, dtmanage, decompileMessage, null,
|
||||
DecompileProcess.DisposeState.DISPOSED_ON_CANCEL);
|
||||
}
|
||||
|
||||
Decoder decoder = null;
|
||||
try {
|
||||
Address funcEntry = func.getEntryPoint();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
*/
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,7 @@ package ghidra.app.plugin.core.decompile.actions;
|
|||
|
||||
import docking.ActionContext;
|
||||
import ghidra.app.decompiler.ClangToken;
|
||||
import ghidra.app.decompiler.component.DecompilerController;
|
||||
import ghidra.app.decompiler.component.DecompilerPanel;
|
||||
import ghidra.app.decompiler.component.*;
|
||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.data.DataType;
|
||||
|
@ -62,7 +61,7 @@ public class DecompilerStructureVariableAction extends CreateStructureVariableAc
|
|||
HighVariable var = tokenAtCursor.getHighVariable();
|
||||
if (var != null && !(var instanceof HighConstant)) {
|
||||
dt = var.getDataType();
|
||||
isThisParam = testForAutoParameterThis(var, function);
|
||||
isThisParam = DecompilerUtils.testForAutoParameterThis(var, function);
|
||||
}
|
||||
|
||||
if (dt == null || dt.getLength() > maxPointerSize) {
|
||||
|
|
|
@ -20,18 +20,16 @@ import java.util.*;
|
|||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.options.OptionsService;
|
||||
import generic.cache.CachingPool;
|
||||
import generic.cache.CountingBasicFactory;
|
||||
import generic.concurrent.QCallback;
|
||||
import ghidra.GhidraOptions;
|
||||
import ghidra.app.decompiler.*;
|
||||
import ghidra.app.decompiler.DecompileOptions.CommentStyleEnum;
|
||||
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||
import ghidra.app.decompiler.parallel.ChunkingParallelDecompiler;
|
||||
import ghidra.app.decompiler.parallel.ParallelDecompiler;
|
||||
import ghidra.app.util.*;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.data.*;
|
||||
|
@ -245,20 +243,8 @@ public class CppExporter extends Exporter {
|
|||
|
||||
private void configureOptions(Program program) {
|
||||
if (!userSuppliedOptions) {
|
||||
options = new DecompileOptions();
|
||||
|
||||
if (provider != null) {
|
||||
OptionsService service = provider.getService(OptionsService.class);
|
||||
if (service != null) {
|
||||
ToolOptions fieldOptions =
|
||||
service.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
|
||||
ToolOptions opt = service.getOptions("Decompiler");
|
||||
options.grabFromToolAndProgram(fieldOptions, opt, program);
|
||||
}
|
||||
}
|
||||
else {
|
||||
options.grabFromProgram(program); // Let headless pull program specific options
|
||||
}
|
||||
options = DecompilerUtils.getDecompileOptions(provider, program);
|
||||
|
||||
if (isUseCppStyleComments) {
|
||||
options.setCommentStyle(CommentStyleEnum.CPPStyle);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue