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 Integer currentTaskPriority = null;
|
||||||
//private Stack<Integer> taskPriorityStack = new Stack<Integer>();
|
//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<>();
|
private Map<String, Long> timedTasks = new HashMap<>();
|
||||||
// used for testing and performance monitoring; accessed via reflection
|
// used for testing and performance monitoring; accessed via reflection
|
||||||
private Map<String, Long> cumulativeTasks = new HashMap<>();
|
private Map<String, Long> cumulativeTasks = new HashMap<>();
|
||||||
|
@ -231,7 +231,7 @@ public class AutoAnalysisManager {
|
||||||
Options options = program.getOptions(Program.ANALYSIS_PROPERTIES);
|
Options options = program.getOptions(Program.ANALYSIS_PROPERTIES);
|
||||||
analyzer.optionsChanged(options.getOptions(analyzer.getName()), getProgram());
|
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());
|
schedule(cmd, analyzer.getPriority().priority());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -643,13 +643,13 @@ public class AutoAnalysisManager {
|
||||||
|
|
||||||
private class AnalysisTaskWrapper {
|
private class AnalysisTaskWrapper {
|
||||||
|
|
||||||
private final BackgroundCommand task;
|
private final BackgroundCommand<Program> task;
|
||||||
Integer taskPriority;
|
Integer taskPriority;
|
||||||
|
|
||||||
private long timeAccumulator;
|
private long timeAccumulator;
|
||||||
private long startTime;
|
private long startTime;
|
||||||
|
|
||||||
AnalysisTaskWrapper(BackgroundCommand task, int taskPriority) {
|
AnalysisTaskWrapper(BackgroundCommand<Program> task, int taskPriority) {
|
||||||
this.task = task;
|
this.task = task;
|
||||||
this.taskPriority = taskPriority;
|
this.taskPriority = taskPriority;
|
||||||
}
|
}
|
||||||
|
@ -845,7 +845,7 @@ public class AutoAnalysisManager {
|
||||||
*/
|
*/
|
||||||
public synchronized void cancelQueuedTasks() {
|
public synchronized void cancelQueuedTasks() {
|
||||||
while (!queue.isEmpty()) {
|
while (!queue.isEmpty()) {
|
||||||
BackgroundCommand cmd = queue.getFirst();
|
BackgroundCommand<Program> cmd = queue.getFirst();
|
||||||
if (cmd instanceof AnalysisWorkerCommand) {
|
if (cmd instanceof AnalysisWorkerCommand) {
|
||||||
AnalysisWorkerCommand workerCmd = (AnalysisWorkerCommand) cmd;
|
AnalysisWorkerCommand workerCmd = (AnalysisWorkerCommand) cmd;
|
||||||
if (!workerCmd.canCancel()) {
|
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) {
|
if (cmd == null) {
|
||||||
throw new IllegalArgumentException("Can't schedule a null command");
|
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
|
* In a Headed environment a modal task dialog will be used to block user input if the
|
||||||
* worker was scheduled with analyzeChanges==false
|
* 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 AnalysisWorker worker;
|
||||||
private Object workerContext;
|
private Object workerContext;
|
||||||
|
@ -1651,7 +1652,7 @@ public class AutoAnalysisManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applyTo(DomainObject obj, TaskMonitor analysisMonitor) {
|
public boolean applyTo(Program p, TaskMonitor analysisMonitor) {
|
||||||
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
workerMonitor.removeCancelledListener(this);
|
workerMonitor.removeCancelledListener(this);
|
||||||
|
@ -1660,7 +1661,7 @@ public class AutoAnalysisManager {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert (obj == program);
|
assert (p == program);
|
||||||
|
|
||||||
if (analysisMonitor != workerMonitor) {
|
if (analysisMonitor != workerMonitor) {
|
||||||
if (!workerMonitor.isCancelEnabled()) {
|
if (!workerMonitor.isCancelEnabled()) {
|
||||||
|
|
|
@ -148,11 +148,11 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
|
||||||
return currentProgram != null;
|
return currentProgram != null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
findTableAction.setHelpLocation(
|
findTableAction
|
||||||
new HelpLocation(HelpTopics.SEARCH, findTableAction.getName()));
|
.setHelpLocation(new HelpLocation(HelpTopics.SEARCH, findTableAction.getName()));
|
||||||
findTableAction.setMenuBarData(new MenuData(
|
findTableAction.setMenuBarData(
|
||||||
new String[] { ToolConstants.MENU_SEARCH, "For Address Tables" }, null, "search for",
|
new MenuData(new String[] { ToolConstants.MENU_SEARCH, "For Address Tables" }, null,
|
||||||
-1, "AddressTables"));
|
"search for", -1, "AddressTables"));
|
||||||
findTableAction.setDescription(getPluginDescription().getDescription());
|
findTableAction.setDescription(getPluginDescription().getDescription());
|
||||||
findTableAction.addToWindowWhen(NavigatableActionContext.class);
|
findTableAction.addToWindowWhen(NavigatableActionContext.class);
|
||||||
tool.addAction(findTableAction);
|
tool.addAction(findTableAction);
|
||||||
|
@ -168,15 +168,15 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
|
||||||
|
|
||||||
int minimumTableSize = addressTableDialog.getMinTableSize();
|
int minimumTableSize = addressTableDialog.getMinTableSize();
|
||||||
if (minimumTableSize < 2) {
|
if (minimumTableSize < 2) {
|
||||||
addressTableDialog.setDialogText(
|
addressTableDialog
|
||||||
"Please enter a valid minimum search length. Must be >= 2");
|
.setDialogText("Please enter a valid minimum search length. Must be >= 2");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int alignment = addressTableDialog.getAlignment();
|
int alignment = addressTableDialog.getAlignment();
|
||||||
if (alignment <= 0 || alignment > 8) {
|
if (alignment <= 0 || alignment > 8) {
|
||||||
addressTableDialog.setDialogText(
|
addressTableDialog
|
||||||
"Please enter a valid alignment value. Must be > 0 and <= 8");
|
.setDialogText("Please enter a valid alignment value. Must be > 0 and <= 8");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,8 +217,8 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
|
||||||
selectedAddresses[i] = model.getAddress(selectedRows[i]);
|
selectedAddresses[i] = model.getAddress(selectedRows[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompoundBackgroundCommand backCmd =
|
CompoundBackgroundCommand<Program> backCmd =
|
||||||
new CompoundBackgroundCommand("Disassemble Address Tables", false, true);
|
new CompoundBackgroundCommand<>("Disassemble Address Tables", false, true);
|
||||||
offsetLen = addressTableDialog.getOffset();
|
offsetLen = addressTableDialog.getOffset();
|
||||||
|
|
||||||
// loop over selected table addresses
|
// loop over selected table addresses
|
||||||
|
@ -237,7 +237,7 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
|
||||||
tool.executeBackgroundCommand(backCmd, currentProgram);
|
tool.executeBackgroundCommand(backCmd, currentProgram);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createDisassemblyCommandsForAddress(CompoundBackgroundCommand backCmd,
|
private void createDisassemblyCommandsForAddress(CompoundBackgroundCommand<Program> backCmd,
|
||||||
Address currentAddress) {
|
Address currentAddress) {
|
||||||
|
|
||||||
Listing listing = currentProgram.getListing();
|
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
|
// need to create a context for each one. Also disassembleCmd will align the address to disassemble
|
||||||
DisassembleCommand disassembleCmd = new DisassembleCommand(addr, null, true);
|
DisassembleCommand disassembleCmd = new DisassembleCommand(addr, null, true);
|
||||||
RegisterValue rval = PseudoDisassembler.getTargetContextRegisterValueForDisassembly(
|
RegisterValue rval = PseudoDisassembler
|
||||||
currentProgram, addr);
|
.getTargetContextRegisterValueForDisassembly(currentProgram, addr);
|
||||||
disassembleCmd.setInitialContext(rval);
|
disassembleCmd.setInitialContext(rval);
|
||||||
backCmd.add(disassembleCmd);
|
backCmd.add(disassembleCmd);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ import ghidra.app.plugin.PluginCategoryNames;
|
||||||
import ghidra.app.util.bean.SetEquateDialog;
|
import ghidra.app.util.bean.SetEquateDialog;
|
||||||
import ghidra.app.util.bean.SetEquateDialog.SelectionType;
|
import ghidra.app.util.bean.SetEquateDialog.SelectionType;
|
||||||
import ghidra.app.util.datatype.ApplyEnumDialog;
|
import ghidra.app.util.datatype.ApplyEnumDialog;
|
||||||
import ghidra.framework.cmd.BackgroundCommand;
|
|
||||||
import ghidra.framework.cmd.CompoundBackgroundCommand;
|
import ghidra.framework.cmd.CompoundBackgroundCommand;
|
||||||
import ghidra.framework.plugintool.*;
|
import ghidra.framework.plugintool.*;
|
||||||
import ghidra.framework.plugintool.util.PluginStatus;
|
import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
|
@ -182,7 +181,7 @@ public class EquatePlugin extends Plugin {
|
||||||
iter = listing.getCodeUnits(context.getProgram().getMemory(), true);
|
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);
|
dialog.getOverwriteExisting(), context);
|
||||||
tool.executeBackgroundCommand(cmd, context.getProgram());
|
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
|
// Set up a background task that we'll populate with all the rename tasks we need
|
||||||
// to perform.
|
// to perform.
|
||||||
CompoundBackgroundCommand bckCmd =
|
CompoundBackgroundCommand<Program> bckCmd =
|
||||||
new CompoundBackgroundCommand("Rename Equates in Selection", false, true);
|
new CompoundBackgroundCommand<>("Rename Equates in Selection", false, true);
|
||||||
|
|
||||||
// Now loop over all the code units and search for matching scalars...
|
// Now loop over all the code units and search for matching scalars...
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
|
@ -312,7 +311,7 @@ public class EquatePlugin extends Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renameEquateForCodeUnit(ListingActionContext context, Enum enoom, Equate equate,
|
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) {
|
if (cu instanceof Instruction) {
|
||||||
|
|
||||||
|
@ -348,8 +347,8 @@ public class EquatePlugin extends Plugin {
|
||||||
CodeUnitIterator iter) {
|
CodeUnitIterator iter) {
|
||||||
|
|
||||||
// Create a background task to process all the remove tasks.
|
// Create a background task to process all the remove tasks.
|
||||||
CompoundBackgroundCommand bckCmd =
|
CompoundBackgroundCommand<Program> bckCmd =
|
||||||
new CompoundBackgroundCommand("Remove Equates in Selection", false, true);
|
new CompoundBackgroundCommand<>("Remove Equates in Selection", false, true);
|
||||||
|
|
||||||
// Now iterate over all code units in the iterator.
|
// Now iterate over all code units in the iterator.
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
|
@ -362,7 +361,7 @@ public class EquatePlugin extends Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeEquateForCodeUnit(ListingActionContext context, Equate equate,
|
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
|
// A code unit can be either an instruction or data; we need to handle each
|
||||||
// separately.
|
// separately.
|
||||||
if (cu instanceof Instruction) {
|
if (cu instanceof Instruction) {
|
||||||
|
|
|
@ -46,8 +46,8 @@ public class ApplyClassFunctionDefinitionUpdatesScript extends GhidraScript {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RecoveredClassHelper classHelper = new RecoveredClassHelper(currentProgram, currentLocation,
|
RecoveredClassHelper classHelper = new RecoveredClassHelper(currentProgram, state.getTool(),
|
||||||
state.getTool(), this, false, false, false, monitor);
|
this, false, false, false, monitor);
|
||||||
|
|
||||||
DataTypeManagerService dtms = state.getTool().getService(DataTypeManagerService.class);
|
DataTypeManagerService dtms = state.getTool().getService(DataTypeManagerService.class);
|
||||||
List<DataType> selectedDatatypes = dtms.getSelectedDatatypes();
|
List<DataType> selectedDatatypes = dtms.getSelectedDatatypes();
|
||||||
|
|
|
@ -46,20 +46,20 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RecoveredClassHelper classHelper = new RecoveredClassHelper(currentProgram, currentLocation,
|
RecoveredClassHelper classHelper = new RecoveredClassHelper(currentProgram, state.getTool(),
|
||||||
state.getTool(), this, false, false, false, monitor);
|
this, false, false, false, monitor);
|
||||||
|
|
||||||
if(currentAddress == null) {
|
if (currentAddress == null) {
|
||||||
println("Cursor must be in a class function.");
|
println("Cursor must be in a class function.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Function function = getFunctionContaining(currentAddress);
|
Function function = getFunctionContaining(currentAddress);
|
||||||
if(function == null) {
|
if (function == null) {
|
||||||
println("Cursor must be in a class function.");
|
println("Cursor must be in a class function.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(function.isThunk()) {
|
if (function.isThunk()) {
|
||||||
println("User should not edit thunks as they are auto-updated from thunked function. " +
|
println("User should not edit thunks as they are auto-updated from thunked function. " +
|
||||||
"Please undo changes to thunk then edit thunked function and rerun script");
|
"Please undo changes to thunk then edit thunked function and rerun script");
|
||||||
return;
|
return;
|
||||||
|
@ -69,14 +69,13 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
|
||||||
println("Function definitions are not affected by purecall changes.");
|
println("Function definitions are not affected by purecall changes.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Namespace classNamespace = classHelper.getClassNamespace(currentAddress);
|
Namespace classNamespace = classHelper.getClassNamespace(currentAddress);
|
||||||
if (classNamespace == null) {
|
if (classNamespace == null) {
|
||||||
println("Cursor must be in a class function.");
|
println("Cursor must be in a class function.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get a vftable that points to this function - doesn't matter which since it will
|
// get a vftable that points to this function - doesn't matter which since it will
|
||||||
// be used to get the underlying function definition which will then be used to update
|
// be used to get the underlying function definition which will then be used to update
|
||||||
// all related function signatures
|
// all related function signatures
|
||||||
|
@ -84,9 +83,8 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
|
||||||
|
|
||||||
// get all vftables that point to given function
|
// get all vftables that point to given function
|
||||||
if (vftablesContainingFunction.isEmpty()) {
|
if (vftablesContainingFunction.isEmpty()) {
|
||||||
println(
|
println("Function is not a virtual function so has no function definition or related " +
|
||||||
"Function is not a virtual function so has no function definition or related " +
|
"function signatures to update");
|
||||||
"function signatures to update");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +105,7 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vftableWithAppliedStructure == null) {
|
if (vftableWithAppliedStructure == null) {
|
||||||
println(
|
println(
|
||||||
"The vftable(s) containing this function do not have a valid vftable structure " +
|
"The vftable(s) containing this function do not have a valid vftable structure " +
|
||||||
|
@ -159,5 +157,4 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,15 +33,33 @@
|
||||||
//@category Data Types
|
//@category Data Types
|
||||||
//@keybinding F6
|
//@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;
|
import ghidra.app.script.GhidraScript;
|
||||||
|
|
||||||
public class CreateStructure extends GhidraScript {
|
public class CreateStructure extends GhidraScript {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
FillOutStructureCmd fillCmd =
|
|
||||||
new FillOutStructureCmd(currentProgram, currentLocation, state.getTool());
|
if (currentProgram == null || currentLocation == null) {
|
||||||
fillCmd.applyTo(currentProgram, this.monitor);
|
popup("Requires open program and location");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DecompileOptions decompileOptions =
|
||||||
|
DecompilerUtils.getDecompileOptions(state.getTool(), currentProgram);
|
||||||
|
FillOutStructureCmd cmd = new FillOutStructureCmd(currentLocation, decompileOptions);
|
||||||
|
if (!cmd.applyTo(currentProgram, this.monitor)) {
|
||||||
|
String detail = "";
|
||||||
|
String msg = cmd.getStatusMsg();
|
||||||
|
if (!StringUtils.isBlank(msg)) {
|
||||||
|
detail = ": " + msg;
|
||||||
|
}
|
||||||
|
popup("Failed to fill-out structure" + detail);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,10 +190,9 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
||||||
|
|
||||||
hasDebugSymbols = isPDBLoadedInProgram();
|
hasDebugSymbols = isPDBLoadedInProgram();
|
||||||
nameVfunctions = !hasDebugSymbols;
|
nameVfunctions = !hasDebugSymbols;
|
||||||
recoverClassesFromRTTI =
|
recoverClassesFromRTTI = new RTTIWindowsClassRecoverer(currentProgram, state.getTool(),
|
||||||
new RTTIWindowsClassRecoverer(currentProgram, currentLocation, state.getTool(),
|
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
|
||||||
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
|
nameVfunctions, hasDebugSymbols, monitor);
|
||||||
nameVfunctions, hasDebugSymbols, monitor);
|
|
||||||
}
|
}
|
||||||
else if (isPE() && isGcc()) {
|
else if (isPE() && isGcc()) {
|
||||||
|
|
||||||
|
@ -213,10 +212,9 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
||||||
}
|
}
|
||||||
//run fixup old elf relocations script
|
//run fixup old elf relocations script
|
||||||
runScript("FixElfExternalOffsetDataRelocationScript.java");
|
runScript("FixElfExternalOffsetDataRelocationScript.java");
|
||||||
recoverClassesFromRTTI =
|
recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, state.getTool(),
|
||||||
new RTTIGccClassRecoverer(currentProgram, currentLocation, state.getTool(), this,
|
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
|
||||||
BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
|
nameVfunctions, hasDebugSymbols, monitor);
|
||||||
nameVfunctions, hasDebugSymbols, monitor);
|
|
||||||
}
|
}
|
||||||
else if (isGcc()) {
|
else if (isGcc()) {
|
||||||
|
|
||||||
|
@ -245,10 +243,9 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nameVfunctions = !hasDebugSymbols;
|
nameVfunctions = !hasDebugSymbols;
|
||||||
recoverClassesFromRTTI =
|
recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, state.getTool(),
|
||||||
new RTTIGccClassRecoverer(currentProgram, currentLocation, state.getTool(), this,
|
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
|
||||||
BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
|
nameVfunctions, hasDebugSymbols, monitor);
|
||||||
nameVfunctions, hasDebugSymbols, monitor);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
println("This script will not work on this program type");
|
println("This script will not work on this program type");
|
||||||
|
|
|
@ -25,10 +25,9 @@
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import docking.options.OptionsService;
|
|
||||||
import ghidra.app.decompiler.*;
|
import ghidra.app.decompiler.*;
|
||||||
|
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.framework.options.ToolOptions;
|
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.pcode.HighFunction;
|
import ghidra.program.model.pcode.HighFunction;
|
||||||
|
@ -38,214 +37,215 @@ import ghidra.program.model.symbol.Symbol;
|
||||||
|
|
||||||
public class ShowCCallsScript extends GhidraScript {
|
public class ShowCCallsScript extends GhidraScript {
|
||||||
|
|
||||||
private Address lastAddr = null;
|
private Address lastAddr = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
|
|
||||||
if (currentLocation == null) {
|
if (currentLocation == null) {
|
||||||
println("No Location.");
|
println("No Location.");
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
Listing listing = currentProgram.getListing();
|
|
||||||
|
|
||||||
Function func = listing.getFunctionContaining(currentAddress);
|
|
||||||
|
|
||||||
if (func == null) {
|
|
||||||
println("No Function at address " + currentAddress);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DecompInterface decomplib = setUpDecompiler(currentProgram);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!decomplib.openProgram(currentProgram)) {
|
|
||||||
println("Decompile Error: " + decomplib.getLastMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// call decompiler for all refs to current function
|
|
||||||
Symbol sym = this.getSymbolAt(func.getEntryPoint());
|
|
||||||
|
|
||||||
Reference refs[] = sym.getReferences(null);
|
|
||||||
|
|
||||||
for (int i = 0; i < refs.length; i++) {
|
|
||||||
if (monitor.isCancelled()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get function containing.
|
|
||||||
Address refAddr = refs[i].getFromAddress();
|
|
||||||
Function refFunc = currentProgram.getFunctionManager()
|
|
||||||
.getFunctionContaining(refAddr);
|
|
||||||
|
|
||||||
if (refFunc == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// decompile function
|
|
||||||
// look for call to this function
|
|
||||||
// display call
|
|
||||||
analyzeFunction(decomplib, currentProgram, refFunc, refAddr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
decomplib.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
lastAddr = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DecompInterface setUpDecompiler(Program program) {
|
|
||||||
DecompInterface decomplib = new DecompInterface();
|
|
||||||
|
|
||||||
DecompileOptions options;
|
|
||||||
options = new DecompileOptions();
|
|
||||||
OptionsService service = state.getTool().getService(OptionsService.class);
|
|
||||||
if (service != null) {
|
|
||||||
ToolOptions opt = service.getOptions("Decompiler");
|
|
||||||
options.grabFromToolAndProgram(null,opt,program);
|
|
||||||
}
|
}
|
||||||
decomplib.setOptions(options);
|
|
||||||
|
Listing listing = currentProgram.getListing();
|
||||||
|
|
||||||
|
Function func = listing.getFunctionContaining(currentAddress);
|
||||||
|
|
||||||
|
if (func == null) {
|
||||||
|
println("No Function at address " + currentAddress);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DecompInterface decomplib = setUpDecompiler(currentProgram);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!decomplib.openProgram(currentProgram)) {
|
||||||
|
println("Decompile Error: " + decomplib.getLastMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// call decompiler for all refs to current function
|
||||||
|
Symbol sym = this.getSymbolAt(func.getEntryPoint());
|
||||||
|
|
||||||
|
Reference refs[] = sym.getReferences(null);
|
||||||
|
|
||||||
|
for (Reference ref : refs) {
|
||||||
|
if (monitor.isCancelled()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get function containing.
|
||||||
|
Address refAddr = ref.getFromAddress();
|
||||||
|
Function refFunc =
|
||||||
|
currentProgram.getFunctionManager().getFunctionContaining(refAddr);
|
||||||
|
|
||||||
|
if (refFunc == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// decompile function
|
||||||
|
// look for call to this function
|
||||||
|
// display call
|
||||||
|
analyzeFunction(decomplib, currentProgram, refFunc, refAddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
decomplib.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
lastAddr = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to setup the decompiler interface for the given program
|
||||||
|
* @param program the given program
|
||||||
|
* @return the decompiler interface
|
||||||
|
*/
|
||||||
|
private DecompInterface setUpDecompiler(Program program) {
|
||||||
|
|
||||||
|
DecompileOptions options = DecompilerUtils.getDecompileOptions(state.getTool(), program);
|
||||||
|
|
||||||
|
DecompInterface decomplib = new DecompInterface();
|
||||||
|
|
||||||
|
decomplib.setOptions(options);
|
||||||
|
|
||||||
decomplib.toggleCCode(true);
|
decomplib.toggleCCode(true);
|
||||||
decomplib.toggleSyntaxTree(true);
|
decomplib.toggleSyntaxTree(true);
|
||||||
decomplib.setSimplificationStyle("decompile");
|
decomplib.setSimplificationStyle("decompile");
|
||||||
|
|
||||||
return decomplib;
|
return decomplib;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyze a functions references
|
* 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) {
|
if (f == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't decompile the function again if it was the same as the last one
|
// don't decompile the function again if it was the same as the last one
|
||||||
//
|
//
|
||||||
if (!f.getEntryPoint().equals(lastAddr))
|
if (!f.getEntryPoint().equals(lastAddr))
|
||||||
decompileFunction(f, decomplib);
|
decompileFunction(f, decomplib);
|
||||||
lastAddr = f.getEntryPoint();
|
lastAddr = f.getEntryPoint();
|
||||||
|
|
||||||
Instruction instr = prog.getListing().getInstructionAt(refAddr);
|
Instruction instr = prog.getListing().getInstructionAt(refAddr);
|
||||||
if (instr == null) {
|
if (instr == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
println(printCall(f, refAddr));
|
println(printCall(f, refAddr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HighFunction hfunction = null;
|
||||||
|
|
||||||
|
ClangTokenGroup docroot = null;
|
||||||
|
|
||||||
HighFunction hfunction = null;
|
public boolean decompileFunction(Function f, DecompInterface decomplib) {
|
||||||
|
// decomplib.setSimplificationStyle("normalize", null);
|
||||||
|
// HighFunction hfunction = decomplib.decompileFunction(f);
|
||||||
|
|
||||||
ClangTokenGroup docroot = null;
|
DecompileResults decompRes =
|
||||||
|
decomplib.decompileFunction(f, decomplib.getOptions().getDefaultTimeout(), monitor);
|
||||||
|
//String statusMsg = decomplib.getDecompileMessage();
|
||||||
|
|
||||||
public boolean decompileFunction(Function f, DecompInterface decomplib) {
|
hfunction = decompRes.getHighFunction();
|
||||||
// decomplib.setSimplificationStyle("normalize", null);
|
docroot = decompRes.getCCodeMarkup();
|
||||||
// HighFunction hfunction = decomplib.decompileFunction(f);
|
|
||||||
|
|
||||||
DecompileResults decompRes = decomplib.decompileFunction(f, decomplib.getOptions().getDefaultTimeout(), monitor);
|
if (hfunction == null)
|
||||||
//String statusMsg = decomplib.getDecompileMessage();
|
return false;
|
||||||
|
|
||||||
hfunction = decompRes.getHighFunction();
|
return true;
|
||||||
docroot = decompRes.getCCodeMarkup();
|
}
|
||||||
|
|
||||||
if (hfunction == null)
|
/**
|
||||||
return false;
|
* get the pcode ops that refer to an address
|
||||||
|
*/
|
||||||
|
public Iterator<PcodeOpAST> getPcodeOps(Address refAddr) {
|
||||||
|
if (hfunction == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Iterator<PcodeOpAST> piter = hfunction.getPcodeOps(refAddr.getPhysicalAddress());
|
||||||
|
return piter;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
public String printCall(Function f, Address refAddr) {
|
||||||
}
|
StringBuffer buff = new StringBuffer();
|
||||||
|
|
||||||
/**
|
printCall(refAddr, docroot, buff, false, false);
|
||||||
* get the pcode ops that refer to an address
|
|
||||||
*/
|
|
||||||
public Iterator<PcodeOpAST> getPcodeOps(Address refAddr) {
|
|
||||||
if (hfunction == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Iterator<PcodeOpAST> piter = hfunction.getPcodeOps(refAddr.getPhysicalAddress());
|
|
||||||
return piter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String printCall(Function f, Address refAddr) {
|
return buff.toString();
|
||||||
StringBuffer buff = new StringBuffer();
|
}
|
||||||
|
|
||||||
printCall(refAddr, docroot, buff, false, false);
|
private boolean printCall(Address refAddr, ClangNode node, StringBuffer buff, boolean didStart,
|
||||||
|
boolean isCall) {
|
||||||
|
if (node == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return buff.toString();
|
Address min = node.getMinAddress();
|
||||||
}
|
Address max = node.getMaxAddress();
|
||||||
|
if (min == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
private boolean printCall(Address refAddr, ClangNode node, StringBuffer buff, boolean didStart, boolean isCall) {
|
if (refAddr.getPhysicalAddress().equals(max) && node instanceof ClangStatement) {
|
||||||
if (node == null) {
|
ClangStatement stmt = (ClangStatement) node;
|
||||||
return false;
|
// Don't check for an actual call. The call could be buried more deeply. As long as the original call reference site
|
||||||
}
|
// is the max address, then display the results.
|
||||||
|
// So this block assumes that the last address contained in the call will be the
|
||||||
Address min = node.getMinAddress();
|
// address you are looking for.
|
||||||
Address max = node.getMaxAddress();
|
// - This could lead to strange behavior if the call reference is placed on some address
|
||||||
if (min == null)
|
// that is not the final call point used by the decompiler.
|
||||||
return false;
|
// - Also if there is a delay slot, then the last address for the call reference point
|
||||||
|
// might not be the last address for the block of PCode.
|
||||||
|
//if (stmt.getPcodeOp().getOpcode() == PcodeOp.CALL) {
|
||||||
|
if (!didStart) {
|
||||||
|
Address nodeAddr = node.getMaxAddress();
|
||||||
|
// Decompiler only knows base space.
|
||||||
|
// If reference came from an overlay space, convert address back
|
||||||
|
if (refAddr.getAddressSpace().isOverlaySpace()) {
|
||||||
|
nodeAddr = refAddr.getAddressSpace().getOverlayAddress(nodeAddr);
|
||||||
|
}
|
||||||
|
buff.append(" " + nodeAddr + " : ");
|
||||||
|
}
|
||||||
|
|
||||||
if (refAddr.getPhysicalAddress().equals(max) && node instanceof ClangStatement) {
|
buff.append(" " + toString(stmt));
|
||||||
ClangStatement stmt = (ClangStatement) node;
|
return true;
|
||||||
// Don't check for an actual call. The call could be buried more deeply. As long as the original call reference site
|
//}
|
||||||
// is the max address, then display the results.
|
}
|
||||||
// So this block assumes that the last address contained in the call will be the
|
for (int j = 0; j < node.numChildren(); j++) {
|
||||||
// address you are looking for.
|
isCall = node instanceof ClangStatement;
|
||||||
// - This could lead to strange behavior if the call reference is placed on some address
|
didStart |= printCall(refAddr, node.Child(j), buff, didStart, isCall);
|
||||||
// that is not the final call point used by the decompiler.
|
}
|
||||||
// - Also if there is a delay slot, then the last address for the call reference point
|
return didStart;
|
||||||
// might not be the last address for the block of PCode.
|
}
|
||||||
//if (stmt.getPcodeOp().getOpcode() == PcodeOp.CALL) {
|
|
||||||
if (!didStart) {
|
|
||||||
Address nodeAddr = node.getMaxAddress();
|
|
||||||
// Decompiler only knows base space.
|
|
||||||
// If reference came from an overlay space, convert address back
|
|
||||||
if (refAddr.getAddressSpace().isOverlaySpace()) {
|
|
||||||
nodeAddr = refAddr.getAddressSpace().getOverlayAddress(nodeAddr);
|
|
||||||
}
|
|
||||||
buff.append(" " + nodeAddr + " : ");
|
|
||||||
}
|
|
||||||
|
|
||||||
buff.append(" " + toString(stmt));
|
|
||||||
return true;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
for (int j = 0; j < node.numChildren(); j++) {
|
|
||||||
isCall = node instanceof ClangStatement;
|
|
||||||
didStart |= printCall(refAddr, node.Child(j), buff, didStart, isCall);
|
|
||||||
}
|
|
||||||
return didStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString(ClangStatement node) {
|
public String toString(ClangStatement node) {
|
||||||
StringBuffer buffer = new StringBuffer();
|
StringBuffer buffer = new StringBuffer();
|
||||||
int open=-1;
|
int open = -1;
|
||||||
for (int j = 0; j < node.numChildren(); j++) {
|
for (int j = 0; j < node.numChildren(); j++) {
|
||||||
ClangNode subNode = node.Child(j);
|
ClangNode subNode = node.Child(j);
|
||||||
if (subNode instanceof ClangSyntaxToken) {
|
if (subNode instanceof ClangSyntaxToken) {
|
||||||
ClangSyntaxToken syntaxNode = (ClangSyntaxToken) subNode;
|
ClangSyntaxToken syntaxNode = (ClangSyntaxToken) subNode;
|
||||||
if (syntaxNode.getOpen() != -1) {
|
if (syntaxNode.getOpen() != -1) {
|
||||||
if (node.Child(j+2) instanceof ClangTypeToken) {
|
if (node.Child(j + 2) instanceof ClangTypeToken) {
|
||||||
open = syntaxNode.getOpen();
|
open = syntaxNode.getOpen();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (syntaxNode.getClose() == open && open != -1) {
|
if (syntaxNode.getClose() == open && open != -1) {
|
||||||
open = -1;
|
open = -1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (open != -1) {
|
if (open != -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
buffer.append(subNode.toString());
|
buffer.append(subNode.toString());
|
||||||
}
|
}
|
||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -254,8 +254,7 @@ public class ShowConstantUse extends GhidraScript {
|
||||||
ConstUseLocation entry = (ConstUseLocation) rowObject;
|
ConstUseLocation entry = (ConstUseLocation) rowObject;
|
||||||
Function func = entry.getProgram()
|
Function func = entry.getProgram()
|
||||||
.getFunctionManager()
|
.getFunctionManager()
|
||||||
.getFunctionContaining(
|
.getFunctionContaining(entry.getAddress());
|
||||||
entry.getAddress());
|
|
||||||
if (func == null) {
|
if (func == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -762,9 +761,7 @@ public class ShowConstantUse extends GhidraScript {
|
||||||
if (defUseList == null || defUseList.size() <= 0) {
|
if (defUseList == null || defUseList.size() <= 0) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
Iterator<PcodeOp> iterator = defUseList.iterator();
|
for (PcodeOp pcodeOp : defUseList) {
|
||||||
while (iterator.hasNext()) {
|
|
||||||
PcodeOp pcodeOp = iterator.next();
|
|
||||||
int opcode = pcodeOp.getOpcode();
|
int opcode = pcodeOp.getOpcode();
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case PcodeOp.INT_AND:
|
case PcodeOp.INT_AND:
|
||||||
|
@ -970,8 +967,7 @@ public class ShowConstantUse extends GhidraScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void followThroughGlobal(HashMap<Address, Long> constUse, ArrayList<PcodeOp> defUseList,
|
private void followThroughGlobal(HashMap<Address, Long> constUse, ArrayList<PcodeOp> defUseList,
|
||||||
HighVariable hvar,
|
HighVariable hvar, ArrayList<FunctionParamUse> funcList,
|
||||||
ArrayList<FunctionParamUse> funcList,
|
|
||||||
HashSet<SequenceNumber> doneSet) {
|
HashSet<SequenceNumber> doneSet) {
|
||||||
Address loc = hvar.getRepresentative().getAddress();
|
Address loc = hvar.getRepresentative().getAddress();
|
||||||
PcodeOp def = hvar.getRepresentative().getDef();
|
PcodeOp def = hvar.getRepresentative().getDef();
|
||||||
|
@ -1013,6 +1009,7 @@ public class ShowConstantUse extends GhidraScript {
|
||||||
private Address lastDecompiledFuncAddr = null;
|
private Address lastDecompiledFuncAddr = null;
|
||||||
|
|
||||||
private DecompInterface setUpDecompiler(Program program) {
|
private DecompInterface setUpDecompiler(Program program) {
|
||||||
|
|
||||||
DecompInterface decompInterface = new DecompInterface();
|
DecompInterface decompInterface = new DecompInterface();
|
||||||
|
|
||||||
// call it to get results
|
// call it to get results
|
||||||
|
@ -1021,13 +1018,8 @@ public class ShowConstantUse extends GhidraScript {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
DecompileOptions options;
|
DecompileOptions options = DecompilerUtils.getDecompileOptions(state.getTool(), program);
|
||||||
options = new DecompileOptions();
|
|
||||||
OptionsService service = state.getTool().getService(OptionsService.class);
|
|
||||||
if (service != null) {
|
|
||||||
ToolOptions opt = service.getOptions("Decompiler");
|
|
||||||
options.grabFromToolAndProgram(null, opt, program);
|
|
||||||
}
|
|
||||||
decompInterface.setOptions(options);
|
decompInterface.setOptions(options);
|
||||||
|
|
||||||
decompInterface.toggleCCode(true);
|
decompInterface.toggleCCode(true);
|
||||||
|
|
|
@ -27,10 +27,11 @@
|
||||||
//
|
//
|
||||||
//@category Analysis
|
//@category Analysis
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
import ghidra.app.decompiler.*;
|
import ghidra.app.decompiler.*;
|
||||||
|
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||||
import ghidra.app.script.GhidraScript;
|
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.address.Address;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.lang.PrototypeModel;
|
import ghidra.program.model.lang.PrototypeModel;
|
||||||
|
@ -40,10 +41,6 @@ import ghidra.program.model.pcode.HighFunctionDBUtil.ReturnCommitOption;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.util.exception.*;
|
import ghidra.util.exception.*;
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import docking.options.OptionsService;
|
|
||||||
|
|
||||||
public class StringParameterPropagator extends GhidraScript {
|
public class StringParameterPropagator extends GhidraScript {
|
||||||
|
|
||||||
// TODO!! Error handling needs a lot of work !!
|
// TODO!! Error handling needs a lot of work !!
|
||||||
|
@ -612,18 +609,11 @@ public class StringParameterPropagator extends GhidraScript {
|
||||||
private Address lastDecompiledFuncAddr = null;
|
private Address lastDecompiledFuncAddr = null;
|
||||||
|
|
||||||
private DecompInterface setUpDecompiler(Program program) {
|
private DecompInterface setUpDecompiler(Program program) {
|
||||||
|
|
||||||
|
DecompileOptions options = DecompilerUtils.getDecompileOptions(state.getTool(), program);
|
||||||
|
|
||||||
DecompInterface decompInterface = new DecompInterface();
|
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.setOptions(options);
|
||||||
|
|
||||||
decompInterface.toggleCCode(true);
|
decompInterface.toggleCCode(true);
|
||||||
|
|
|
@ -31,11 +31,9 @@ import java.util.*;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import docking.options.OptionsService;
|
|
||||||
import ghidra.app.decompiler.*;
|
import ghidra.app.decompiler.*;
|
||||||
|
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.framework.options.ToolOptions;
|
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.pcode.*;
|
import ghidra.program.model.pcode.*;
|
||||||
|
@ -55,7 +53,7 @@ public class WindowsResourceReference extends GhidraScript {
|
||||||
ArrayList<ArrayList<PcodeOp>> defUseLists = new ArrayList<>();
|
ArrayList<ArrayList<PcodeOp>> defUseLists = new ArrayList<>();
|
||||||
|
|
||||||
protected AddressSetPropertyMap alreadyDoneAddressSetPropertyMap;
|
protected AddressSetPropertyMap alreadyDoneAddressSetPropertyMap;
|
||||||
|
|
||||||
// set of functions that decompilation failed on
|
// set of functions that decompilation failed on
|
||||||
protected AddressSet badDecompFunctions = new AddressSet();
|
protected AddressSet badDecompFunctions = new AddressSet();
|
||||||
|
|
||||||
|
@ -369,7 +367,7 @@ public class WindowsResourceReference extends GhidraScript {
|
||||||
if (f == null) {
|
if (f == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if decompilation of this function failed previously
|
// check if decompilation of this function failed previously
|
||||||
if (badDecompFunctions.contains(f.getEntryPoint())) {
|
if (badDecompFunctions.contains(f.getEntryPoint())) {
|
||||||
return;
|
return;
|
||||||
|
@ -462,13 +460,10 @@ public class WindowsResourceReference extends GhidraScript {
|
||||||
private void addResourceReferences(HashMap<Address, Long> constLocs, String resourceName,
|
private void addResourceReferences(HashMap<Address, Long> constLocs, String resourceName,
|
||||||
boolean printScriptMsgs, boolean createBookmarks) throws CancelledException {
|
boolean printScriptMsgs, boolean createBookmarks) throws CancelledException {
|
||||||
Set<Address> keys;
|
Set<Address> keys;
|
||||||
Iterator<Address> locIter;
|
|
||||||
keys = constLocs.keySet();
|
keys = constLocs.keySet();
|
||||||
locIter = keys.iterator();
|
for (Address loc : keys) {
|
||||||
while (locIter.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
|
|
||||||
Address loc = locIter.next();
|
|
||||||
Instruction instr = currentProgram.getListing().getInstructionAt(loc);
|
Instruction instr = currentProgram.getListing().getInstructionAt(loc);
|
||||||
long rsrcID = constLocs.get(loc);
|
long rsrcID = constLocs.get(loc);
|
||||||
Address rsrcAddr = findResource(resourceName + "_" + Long.toHexString(rsrcID), 0);
|
Address rsrcAddr = findResource(resourceName + "_" + Long.toHexString(rsrcID), 0);
|
||||||
|
@ -488,9 +483,9 @@ public class WindowsResourceReference extends GhidraScript {
|
||||||
|
|
||||||
instr.addMnemonicReference(rsrcAddr, RefType.DATA, SourceType.ANALYSIS);
|
instr.addMnemonicReference(rsrcAddr, RefType.DATA, SourceType.ANALYSIS);
|
||||||
if (createBookmarks) {
|
if (createBookmarks) {
|
||||||
currentProgram.getBookmarkManager().setBookmark(instr.getMinAddress(),
|
currentProgram.getBookmarkManager()
|
||||||
BookmarkType.ANALYSIS, "WindowsResourceReference",
|
.setBookmark(instr.getMinAddress(), BookmarkType.ANALYSIS,
|
||||||
"Added Resource Reference");
|
"WindowsResourceReference", "Added Resource Reference");
|
||||||
}
|
}
|
||||||
if (printScriptMsgs) {
|
if (printScriptMsgs) {
|
||||||
println(" " + instr.getMinAddress().toString() + " : Found " + rsrcName +
|
println(" " + instr.getMinAddress().toString() + " : Found " + rsrcName +
|
||||||
|
@ -513,15 +508,13 @@ public class WindowsResourceReference extends GhidraScript {
|
||||||
private void addResourceTableReferences(HashMap<Address, Long> constLocs, String tableName,
|
private void addResourceTableReferences(HashMap<Address, Long> constLocs, String tableName,
|
||||||
boolean printScriptMsgs, boolean createBookmarks) throws CancelledException {
|
boolean printScriptMsgs, boolean createBookmarks) throws CancelledException {
|
||||||
Set<Address> keys;
|
Set<Address> keys;
|
||||||
Iterator<Address> locIter;
|
|
||||||
//Get the set of address locations which call the resource function
|
//Get the set of address locations which call the resource function
|
||||||
keys = constLocs.keySet();
|
keys = constLocs.keySet();
|
||||||
locIter = keys.iterator();
|
|
||||||
//Iterate though the set of address locations
|
//Iterate though the set of address locations
|
||||||
while (locIter.hasNext()) {
|
for (Address loc : keys) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
|
|
||||||
Address loc = locIter.next();
|
|
||||||
Instruction instr = currentProgram.getListing().getInstructionAt(loc);
|
Instruction instr = currentProgram.getListing().getInstructionAt(loc);
|
||||||
Long rsrcID = constLocs.get(loc);
|
Long rsrcID = constLocs.get(loc);
|
||||||
Address rsrcAddr = null;
|
Address rsrcAddr = null;
|
||||||
|
@ -532,9 +525,9 @@ public class WindowsResourceReference extends GhidraScript {
|
||||||
if (rsrcAddr != null) {
|
if (rsrcAddr != null) {
|
||||||
instr.addMnemonicReference(rsrcAddr, RefType.DATA, SourceType.ANALYSIS);
|
instr.addMnemonicReference(rsrcAddr, RefType.DATA, SourceType.ANALYSIS);
|
||||||
if (createBookmarks) {
|
if (createBookmarks) {
|
||||||
currentProgram.getBookmarkManager().setBookmark(instr.getMinAddress(),
|
currentProgram.getBookmarkManager()
|
||||||
BookmarkType.ANALYSIS, "WindowsResourceReference",
|
.setBookmark(instr.getMinAddress(), BookmarkType.ANALYSIS,
|
||||||
"Added Resource Table Reference");
|
"WindowsResourceReference", "Added Resource Table Reference");
|
||||||
}
|
}
|
||||||
if (printScriptMsgs) {
|
if (printScriptMsgs) {
|
||||||
println(" " + instr.getMinAddress().toString() + " : Found " +
|
println(" " + instr.getMinAddress().toString() + " : Found " +
|
||||||
|
@ -622,9 +615,7 @@ public class WindowsResourceReference extends GhidraScript {
|
||||||
if (defUseList == null || defUseList.size() <= 0) {
|
if (defUseList == null || defUseList.size() <= 0) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
Iterator<PcodeOp> iterator = defUseList.iterator();
|
for (PcodeOp pcodeOp : defUseList) {
|
||||||
while (iterator.hasNext()) {
|
|
||||||
PcodeOp pcodeOp = iterator.next();
|
|
||||||
int opcode = pcodeOp.getOpcode();
|
int opcode = pcodeOp.getOpcode();
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case PcodeOp.INT_AND:
|
case PcodeOp.INT_AND:
|
||||||
|
@ -763,18 +754,11 @@ public class WindowsResourceReference extends GhidraScript {
|
||||||
private Address lastDecompiledFuncAddr = null;
|
private Address lastDecompiledFuncAddr = null;
|
||||||
|
|
||||||
private DecompInterface setUpDecompiler(Program program) {
|
private DecompInterface setUpDecompiler(Program program) {
|
||||||
|
|
||||||
|
DecompileOptions options = DecompilerUtils.getDecompileOptions(state.getTool(), program);
|
||||||
|
|
||||||
DecompInterface decompiler = new DecompInterface();
|
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.setOptions(options);
|
||||||
|
|
||||||
decompiler.toggleCCode(true);
|
decompiler.toggleCCode(true);
|
||||||
|
|
|
@ -15,71 +15,55 @@
|
||||||
*/
|
*/
|
||||||
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS.
|
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS.
|
||||||
package classrecovery;
|
package classrecovery;
|
||||||
|
|
||||||
import docking.options.OptionsService;
|
import docking.options.OptionsService;
|
||||||
import ghidra.app.decompiler.DecompInterface;
|
import ghidra.app.decompiler.*;
|
||||||
import ghidra.app.decompiler.DecompileOptions;
|
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||||
import ghidra.app.decompiler.DecompileResults;
|
|
||||||
import ghidra.framework.options.ToolOptions;
|
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.address.Address;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.data.ParameterDefinition;
|
import ghidra.program.model.data.ParameterDefinition;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.pcode.FunctionPrototype;
|
import ghidra.program.model.pcode.*;
|
||||||
import ghidra.program.model.pcode.HighFunction;
|
|
||||||
import ghidra.program.model.pcode.PcodeOp;
|
|
||||||
import ghidra.program.model.pcode.Varnode;
|
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class DecompilerScriptUtils {
|
public class DecompilerScriptUtils {
|
||||||
|
|
||||||
private Program program;
|
private Program program;
|
||||||
private PluginTool tool;
|
private ServiceProvider serviceProvider;
|
||||||
private TaskMonitor monitor;
|
private TaskMonitor monitor;
|
||||||
|
|
||||||
private DecompInterface decompInterface;
|
private DecompInterface decompInterface;
|
||||||
|
|
||||||
DecompilerScriptUtils(Program program, PluginTool tool, TaskMonitor monitor) {
|
DecompilerScriptUtils(Program program, ServiceProvider serviceProvider, TaskMonitor monitor) {
|
||||||
this.program = program;
|
this.program = program;
|
||||||
this.monitor = monitor;
|
this.monitor = monitor;
|
||||||
this.tool = tool;
|
this.serviceProvider = serviceProvider;
|
||||||
|
|
||||||
decompInterface = setupDecompilerInterface();
|
decompInterface = setupDecompilerInterface();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to setup the decompiler interface for the given program
|
* 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() {
|
public DecompInterface setupDecompilerInterface() {
|
||||||
|
|
||||||
decompInterface = new DecompInterface();
|
decompInterface = new DecompInterface();
|
||||||
|
|
||||||
DecompileOptions options;
|
DecompileOptions options = DecompilerUtils.getDecompileOptions(serviceProvider, program);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decompInterface.setOptions(options);
|
decompInterface.setOptions(options);
|
||||||
|
|
||||||
decompInterface.toggleCCode(true);
|
decompInterface.toggleCCode(true);
|
||||||
decompInterface.toggleSyntaxTree(true);
|
decompInterface.toggleSyntaxTree(true);
|
||||||
decompInterface.setSimplificationStyle("decompile");
|
decompInterface.setSimplificationStyle("decompile");
|
||||||
|
|
||||||
if (!decompInterface.openProgram(program)) {
|
if (!decompInterface.openProgram(program)) {
|
||||||
|
decompInterface.dispose();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return decompInterface;
|
return decompInterface;
|
||||||
|
@ -90,7 +74,6 @@ public class DecompilerScriptUtils {
|
||||||
return decompInterface;
|
return decompInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to decompile the given function and return the function's HighFunction
|
* Method to decompile the given function and return the function's HighFunction
|
||||||
* @param function the given function
|
* @param function the given function
|
||||||
|
@ -126,7 +109,6 @@ public class DecompilerScriptUtils {
|
||||||
return decompRes.getHighFunction().getFunctionPrototype().getReturnType();
|
return decompRes.getHighFunction().getFunctionPrototype().getReturnType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to retrieve the function signature string from the decompiler function prototype. NOTE:
|
* Method to retrieve the function signature string from the decompiler function prototype. NOTE:
|
||||||
* if there is a this param, it will not be included.
|
* if there is a this param, it will not be included.
|
||||||
|
@ -153,7 +135,6 @@ public class DecompilerScriptUtils {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HighFunction highFunction = decompRes.getHighFunction();
|
HighFunction highFunction = decompRes.getHighFunction();
|
||||||
|
|
||||||
FunctionPrototype functionPrototype = highFunction.getFunctionPrototype();
|
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.
|
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS.
|
||||||
package classrecovery;
|
package classrecovery;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.app.util.NamespaceUtils;
|
import ghidra.app.util.NamespaceUtils;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
import ghidra.program.flatapi.FlatProgramAPI;
|
import ghidra.program.flatapi.FlatProgramAPI;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.symbol.Namespace;
|
import ghidra.program.model.symbol.Namespace;
|
||||||
import ghidra.program.model.symbol.SymbolType;
|
import ghidra.program.model.symbol.SymbolType;
|
||||||
import ghidra.program.util.ProgramLocation;
|
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.*;
|
import ghidra.util.exception.*;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
@ -36,32 +36,21 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||||
boolean programHasRTTIApplied = false;
|
boolean programHasRTTIApplied = false;
|
||||||
|
|
||||||
String ghidraVersion;
|
String ghidraVersion;
|
||||||
Program program;
|
|
||||||
TaskMonitor monitor;
|
|
||||||
boolean hasDebugSymbols;
|
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,
|
super(program, serviceProvider, api, createBookmarks, useShortTemplates, nameVfunctions,
|
||||||
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
|
||||||
boolean nameVfunctions, boolean hasDebugSymbols, TaskMonitor monitor) throws Exception {
|
|
||||||
|
|
||||||
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
|
|
||||||
monitor);
|
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;
|
this.hasDebugSymbols = hasDebugSymbols;
|
||||||
|
|
||||||
ghidraVersion = getVersionOfGhidra();
|
ghidraVersion = getVersionOfGhidra();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public DecompilerScriptUtils getDecompilerUtils() {
|
public DecompilerScriptUtils getDecompilerUtils() {
|
||||||
return decompilerUtils;
|
return decompilerUtils;
|
||||||
}
|
}
|
||||||
|
@ -100,21 +89,15 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||||
return options.getString("Created With Ghidra Version", null);
|
return options.getString("Created With Ghidra Version", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void fixUpProgram() throws CancelledException, Exception {
|
public void fixUpProgram() throws CancelledException, Exception {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<RecoveredClass> createRecoveredClasses() throws Exception {
|
public List<RecoveredClass> createRecoveredClasses() throws Exception {
|
||||||
|
|
||||||
return new ArrayList<RecoveredClass>();
|
return new ArrayList<RecoveredClass>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to promote the namespace is a class namespace.
|
* Method to promote the namespace is a class namespace.
|
||||||
* @param namespace the namespace for the vftable
|
* @param namespace the namespace for the vftable
|
||||||
|
@ -123,18 +106,16 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||||
*/
|
*/
|
||||||
public Namespace promoteToClassNamespace(Namespace namespace) throws InvalidInputException {
|
public Namespace promoteToClassNamespace(Namespace namespace) throws InvalidInputException {
|
||||||
|
|
||||||
Namespace newClass = NamespaceUtils.convertNamespaceToClass(namespace);
|
Namespace newClass = NamespaceUtils.convertNamespaceToClass(namespace);
|
||||||
|
|
||||||
SymbolType symbolType = newClass.getSymbol().getSymbolType();
|
SymbolType symbolType = newClass.getSymbol().getSymbolType();
|
||||||
if (symbolType == SymbolType.CLASS) {
|
if (symbolType == SymbolType.CLASS) {
|
||||||
return newClass;
|
return newClass;
|
||||||
}
|
}
|
||||||
Msg.debug(this,
|
Msg.debug(this, "Could not promote " + namespace.getName() + " to a class namespace");
|
||||||
"Could not promote " + namespace.getName() + " to a class namespace");
|
return null;
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to iterate over all the RecoveredClass objects and see if there is an existing class structure data type already
|
* 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
|
* if so, add it to the RecoveredClass object
|
||||||
|
@ -144,10 +125,8 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||||
public void retrieveExistingClassStructures(List<RecoveredClass> recoveredClasses)
|
public void retrieveExistingClassStructures(List<RecoveredClass> recoveredClasses)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
|
||||||
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
|
for (RecoveredClass recoveredClass : recoveredClasses) {
|
||||||
while (recoveredClassIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
RecoveredClass recoveredClass = recoveredClassIterator.next();
|
|
||||||
|
|
||||||
// if class is non-virtual have to search for an existing class datatype
|
// 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) {
|
if (possibleExistingClassStructures.length == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < possibleExistingClassStructures.length; i++) {
|
for (DataType possibleExistingClassStructure : possibleExistingClassStructures) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
if (!(possibleExistingClassStructures[i] instanceof Structure)) {
|
if (!(possibleExistingClassStructure instanceof Structure)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (possibleExistingClassStructures[i].isNotYetDefined()) {
|
if (possibleExistingClassStructure.isNotYetDefined()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Structure existingClassStructure = (Structure) possibleExistingClassStructures[i];
|
Structure existingClassStructure = (Structure) possibleExistingClassStructure;
|
||||||
|
|
||||||
recoveredClass.addExistingClassStructure(existingClassStructure);
|
recoveredClass.addExistingClassStructure(existingClassStructure);
|
||||||
break;
|
break;
|
||||||
|
@ -174,10 +153,8 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||||
//Iterate over constructor/destructor functions
|
//Iterate over constructor/destructor functions
|
||||||
List<Function> constructorOrDestructorFunctions =
|
List<Function> constructorOrDestructorFunctions =
|
||||||
recoveredClass.getConstructorOrDestructorFunctions();
|
recoveredClass.getConstructorOrDestructorFunctions();
|
||||||
Iterator<Function> constDestIterator = constructorOrDestructorFunctions.iterator();
|
for (Function constDestFunction : constructorOrDestructorFunctions) {
|
||||||
while (constDestIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
Function constDestFunction = constDestIterator.next();
|
|
||||||
Namespace parentNamespace = constDestFunction.getParentNamespace();
|
Namespace parentNamespace = constDestFunction.getParentNamespace();
|
||||||
if (!parentNamespace.equals(recoveredClass.getClassNamespace())) {
|
if (!parentNamespace.equals(recoveredClass.getClassNamespace())) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -220,8 +197,6 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to get class data information from destructors if a class has no constructors
|
* Method to get class data information from destructors if a class has no constructors
|
||||||
* @param recoveredClasses list of classes
|
* @param recoveredClasses list of classes
|
||||||
|
@ -234,11 +209,8 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||||
throws CancelledException, DuplicateNameException, InvalidInputException,
|
throws CancelledException, DuplicateNameException, InvalidInputException,
|
||||||
CircularDependencyException {
|
CircularDependencyException {
|
||||||
|
|
||||||
Iterator<RecoveredClass> classIterator = recoveredClasses.iterator();
|
for (RecoveredClass recoveredClass : recoveredClasses) {
|
||||||
while (classIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
RecoveredClass recoveredClass = classIterator.next();
|
|
||||||
|
|
||||||
// we can only figure out structure info for functions with vftable since that is
|
// 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
|
// what we use to determine which variable is being used to store the class structure
|
||||||
if (!recoveredClass.hasVftable()) {
|
if (!recoveredClass.hasVftable()) {
|
||||||
|
@ -257,11 +229,8 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||||
memberFunctionsToProcess.addAll(recoveredClass.getIndeterminateList());
|
memberFunctionsToProcess.addAll(recoveredClass.getIndeterminateList());
|
||||||
memberFunctionsToProcess.addAll(recoveredClass.getInlinedConstructorList());
|
memberFunctionsToProcess.addAll(recoveredClass.getInlinedConstructorList());
|
||||||
|
|
||||||
Iterator<Function> memberFunctionIterator = memberFunctionsToProcess.iterator();
|
for (Function memberFunction : memberFunctionsToProcess) {
|
||||||
while (memberFunctionIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
Function memberFunction = memberFunctionIterator.next();
|
|
||||||
|
|
||||||
if (getVftableReferences(memberFunction) == null) {
|
if (getVftableReferences(memberFunction) == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -278,9 +247,4 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,84 +17,28 @@
|
||||||
package classrecovery;
|
package classrecovery;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
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 ghidra.app.cmd.label.DemanglerCmd;
|
import ghidra.app.cmd.label.DemanglerCmd;
|
||||||
import ghidra.app.plugin.core.analysis.ReferenceAddressPair;
|
import ghidra.app.plugin.core.analysis.ReferenceAddressPair;
|
||||||
import ghidra.app.util.NamespaceUtils;
|
import ghidra.app.util.NamespaceUtils;
|
||||||
import ghidra.app.util.demangler.DemangledObject;
|
import ghidra.app.util.demangler.DemangledObject;
|
||||||
import ghidra.app.util.demangler.DemanglerUtil;
|
import ghidra.app.util.demangler.DemanglerUtil;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
import ghidra.program.flatapi.FlatProgramAPI;
|
import ghidra.program.flatapi.FlatProgramAPI;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.address.AddressIterator;
|
import ghidra.program.model.data.*;
|
||||||
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.data.DataUtilities.ClearDataMode;
|
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.lang.Register;
|
||||||
import ghidra.program.model.listing.Bookmark;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.listing.BookmarkType;
|
import ghidra.program.model.mem.*;
|
||||||
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.scalar.Scalar;
|
import ghidra.program.model.scalar.Scalar;
|
||||||
import ghidra.program.model.symbol.Namespace;
|
import ghidra.program.model.symbol.*;
|
||||||
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.util.CodeUnitInsertionException;
|
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||||
import ghidra.program.util.ProgramLocation;
|
|
||||||
import ghidra.program.util.ProgramMemoryUtil;
|
import ghidra.program.util.ProgramMemoryUtil;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.bytesearch.GenericByteSequencePattern;
|
import ghidra.util.bytesearch.*;
|
||||||
import ghidra.util.bytesearch.GenericMatchAction;
|
import ghidra.util.exception.*;
|
||||||
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.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
@ -151,23 +95,20 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
private Map<RecoveredClass, Map<RecoveredClass, Long>> classToParentOffsetMap =
|
private Map<RecoveredClass, Map<RecoveredClass, Long>> classToParentOffsetMap =
|
||||||
new HashMap<RecoveredClass, Map<RecoveredClass, Long>>();
|
new HashMap<RecoveredClass, Map<RecoveredClass, Long>>();
|
||||||
|
|
||||||
private Map<RecoveredClass, List<Vftable>> classToVftableMap = new HashMap<>();
|
|
||||||
|
|
||||||
boolean isDwarfLoaded;
|
boolean isDwarfLoaded;
|
||||||
boolean replaceClassStructs;
|
boolean replaceClassStructs;
|
||||||
|
|
||||||
FunctionManager functionManager = null;
|
protected final FunctionManager functionManager;
|
||||||
Listing listing;
|
protected final Listing listing;
|
||||||
|
|
||||||
public RTTIGccClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
|
public RTTIGccClassRecoverer(Program program, ServiceProvider serviceProvider,
|
||||||
FlatProgramAPI api,
|
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
||||||
boolean createBookmarks, boolean useShortTemplates, boolean nameVfunctions,
|
boolean nameVfunctions, boolean isDwarfLoaded, TaskMonitor monitor) throws Exception {
|
||||||
boolean isDwarfLoaded,
|
|
||||||
TaskMonitor monitor) throws Exception {
|
|
||||||
|
|
||||||
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
|
super(program, serviceProvider, api, createBookmarks, useShortTemplates, nameVfunctions,
|
||||||
isDwarfLoaded, monitor);
|
isDwarfLoaded, monitor);
|
||||||
|
|
||||||
this.isDwarfLoaded = isDwarfLoaded;
|
this.isDwarfLoaded = isDwarfLoaded;
|
||||||
|
|
||||||
functionManager = program.getFunctionManager();
|
functionManager = program.getFunctionManager();
|
||||||
|
@ -208,8 +149,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
List<ReferenceAddressPair> directReferenceList = new ArrayList<ReferenceAddressPair>();
|
List<ReferenceAddressPair> directReferenceList = new ArrayList<ReferenceAddressPair>();
|
||||||
|
|
||||||
ProgramMemoryUtil.loadDirectReferenceList(program, 1, initializedMem.getMinAddress(),
|
ProgramMemoryUtil.loadDirectReferenceList(program, 1, initializedMem.getMinAddress(),
|
||||||
initializedMem,
|
initializedMem, directReferenceList, monitor);
|
||||||
directReferenceList, monitor);
|
|
||||||
createGlobalDirectRefMap(directReferenceList);
|
createGlobalDirectRefMap(directReferenceList);
|
||||||
|
|
||||||
Msg.debug(this, "Creating Special Typeinfos");
|
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
|
* 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.
|
* order to distinguish which base class the vftable is for.
|
||||||
* @param recoveredClasses the list of RecoveredClass objects
|
|
||||||
* @throws CancelledException if cancelled
|
* @throws CancelledException if cancelled
|
||||||
* @throws InvalidInputException if bad chars trying to label
|
* @throws InvalidInputException if bad chars trying to label
|
||||||
* @throws DuplicateNameException if duplicate name
|
* @throws DuplicateNameException if duplicate name
|
||||||
|
@ -364,8 +303,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private GccTypeinfo findSpecialTypeinfoSymbol(String namespaceName,
|
private GccTypeinfo findSpecialTypeinfoSymbol(String namespaceName,
|
||||||
String mangledNamespaceString)
|
String mangledNamespaceString) throws CancelledException {
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
// try finding with normal symbol name and namespace
|
// try finding with normal symbol name and namespace
|
||||||
Symbol typeinfoSymbol =
|
Symbol typeinfoSymbol =
|
||||||
|
@ -384,9 +322,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
if (typeinfoSymbol == null) {
|
if (typeinfoSymbol == null) {
|
||||||
// then try finding with mangled namespace string in memory
|
// then try finding with mangled namespace string in memory
|
||||||
typeinfoSymbol =
|
typeinfoSymbol = findTypeinfoSymbolUsingMangledNamespaceString(
|
||||||
findTypeinfoSymbolUsingMangledNamespaceString(mangledNamespaceString,
|
mangledNamespaceString, namespaceName);
|
||||||
namespaceName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -397,8 +334,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Symbol findTypeinfoUsingNotInProgramMemoryVtableSymbol(String namespaceName,
|
private Symbol findTypeinfoUsingNotInProgramMemoryVtableSymbol(String namespaceName,
|
||||||
String mangledNamespaceString)
|
String mangledNamespaceString) throws CancelledException {
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
// try finding with normal symbol name and namespace
|
// try finding with normal symbol name and namespace
|
||||||
Symbol vtableSymbol =
|
Symbol vtableSymbol =
|
||||||
|
@ -433,8 +369,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
Symbol typeinfoSymbol;
|
Symbol typeinfoSymbol;
|
||||||
try {
|
try {
|
||||||
typeinfoSymbol = symbolTable.createLabel(vtableAddress, "typeinfo",
|
typeinfoSymbol = symbolTable.createLabel(vtableAddress, "typeinfo",
|
||||||
vtableSymbol.getParentNamespace(),
|
vtableSymbol.getParentNamespace(), SourceType.ANALYSIS);
|
||||||
SourceType.ANALYSIS);
|
|
||||||
// api.setPlateComment(typeinfoAddress, "typeinfo for " + namespace);
|
// api.setPlateComment(typeinfoAddress, "typeinfo for " + namespace);
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
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
|
// TODO: this assumes only one and returns the first found - have never seen
|
||||||
// more than one but should probably check
|
// more than one but should probably check
|
||||||
private Symbol findAndReturnDemangledSymbol(String mangledSymbolName,
|
private Symbol findAndReturnDemangledSymbol(String mangledSymbolName,
|
||||||
String specialClassNamespaceName,
|
String specialClassNamespaceName, String classNamespaceName, String label) {
|
||||||
String classNamespaceName, String label) {
|
|
||||||
|
|
||||||
SymbolIterator symbolIterator = symbolTable.getSymbolIterator(mangledSymbolName, true);
|
SymbolIterator symbolIterator = symbolTable.getSymbolIterator(mangledSymbolName, true);
|
||||||
if (symbolIterator.hasNext()) {
|
if (symbolIterator.hasNext()) {
|
||||||
|
@ -504,9 +438,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Symbol demangledSymbol =
|
Symbol demangledSymbol = symbolTable.createLabel(symbolAddress, label,
|
||||||
symbolTable.createLabel(symbolAddress, label, classNamespace,
|
classNamespace, SourceType.ANALYSIS);
|
||||||
SourceType.ANALYSIS);
|
|
||||||
demangledSymbol.setPrimary();
|
demangledSymbol.setPrimary();
|
||||||
return demangledSymbol;
|
return demangledSymbol;
|
||||||
}
|
}
|
||||||
|
@ -520,8 +453,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
// TODO: can this be used for regular ones too?
|
// TODO: can this be used for regular ones too?
|
||||||
private Symbol findTypeinfoSymbolUsingMangledNamespaceString(String mangledNamespace,
|
private Symbol findTypeinfoSymbolUsingMangledNamespaceString(String mangledNamespace,
|
||||||
String namespaceName)
|
String namespaceName) throws CancelledException {
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
Symbol specialTypeinfoSymbol = findTypeinfoUsingMangledString(mangledNamespace);
|
Symbol specialTypeinfoSymbol = findTypeinfoUsingMangledString(mangledNamespace);
|
||||||
if (specialTypeinfoSymbol == null) {
|
if (specialTypeinfoSymbol == null) {
|
||||||
|
@ -539,9 +471,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
boolean isExternal =
|
boolean isExternal =
|
||||||
typeinfoAddress.isExternalAddress() || inExternalBlock(typeinfoAddress);
|
typeinfoAddress.isExternalAddress() || inExternalBlock(typeinfoAddress);
|
||||||
|
|
||||||
GccTypeinfo gccTypeinfo =
|
GccTypeinfo gccTypeinfo = new GccTypeinfo(typeinfoSymbol.getAddress(),
|
||||||
new GccTypeinfo(typeinfoSymbol.getAddress(), typeinfoSymbol.getParentNamespace(),
|
typeinfoSymbol.getParentNamespace(), isSpecial, !isExternal);
|
||||||
isSpecial, !isExternal);
|
|
||||||
return gccTypeinfo;
|
return gccTypeinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -578,10 +509,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
boolean isGcc;
|
boolean isGcc;
|
||||||
|
|
||||||
boolean isCompilerSpecGcc = program.getCompilerSpec()
|
boolean isCompilerSpecGcc =
|
||||||
.getCompilerSpecID()
|
program.getCompilerSpec().getCompilerSpecID().getIdAsString().equalsIgnoreCase("gcc");
|
||||||
.getIdAsString()
|
|
||||||
.equalsIgnoreCase("gcc");
|
|
||||||
if (isCompilerSpecGcc) {
|
if (isCompilerSpecGcc) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -605,8 +534,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
byte[] maskBytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
|
byte[] maskBytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
|
||||||
|
|
||||||
Address found = program.getMemory()
|
Address found = program.getMemory()
|
||||||
.findBytes(commentBlock.getStart(), commentBlock.getEnd(), gccBytes,
|
.findBytes(commentBlock.getStart(), commentBlock.getEnd(), gccBytes, maskBytes,
|
||||||
maskBytes, true, monitor);
|
true, monitor);
|
||||||
if (found == null) {
|
if (found == null) {
|
||||||
isGcc = false;
|
isGcc = false;
|
||||||
}
|
}
|
||||||
|
@ -726,9 +655,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
// parent isn't a known class - cannot continue processing recoveredClass
|
// parent isn't a known class - cannot continue processing recoveredClass
|
||||||
if (parentClass == null) {
|
if (parentClass == null) {
|
||||||
Msg.error(this,
|
Msg.error(this, "Removing class: " + recoveredClass.getName() +
|
||||||
"Removing class: " + recoveredClass.getName() + " from list to" +
|
" from list to" + " process since parent information is not availalbe.");
|
||||||
" process since parent information is not availalbe.");
|
|
||||||
recoveredClasses.remove(recoveredClass);
|
recoveredClasses.remove(recoveredClass);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
@ -801,9 +729,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
Vtable vtable = processMainVtable(mainVtable, map.get(mainVtable));
|
Vtable vtable = processMainVtable(mainVtable, map.get(mainVtable));
|
||||||
if (vtable == null) {
|
if (vtable == null) {
|
||||||
Msg.debug(this,
|
Msg.debug(this, "MISSING expected vtable for simple class " +
|
||||||
"MISSING expected vtable for simple class " +
|
typeinfo.getNamespace().getName(true));
|
||||||
typeinfo.getNamespace().getName(true));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1051,8 +978,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isPossibleVttStart(Address address, List<Vtable> vtables,
|
private boolean isPossibleVttStart(Address address, List<Vtable> vtables,
|
||||||
List<Address> knownVtts)
|
List<Address> knownVtts) throws CancelledException {
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
// make list of all vtable tops and vftable tops
|
// make list of all vtable tops and vftable tops
|
||||||
List<Address> vtableAndVftableAddrs = getListOfVtableAndVftableTops(vtables);
|
List<Address> vtableAndVftableAddrs = getListOfVtableAndVftableTops(vtables);
|
||||||
|
@ -1164,7 +1090,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
* construction ones to the passed in list
|
* construction ones to the passed in list
|
||||||
*
|
*
|
||||||
* @param typeinfo
|
* @param typeinfo
|
||||||
|
* @param map
|
||||||
* @param constructionVtables
|
* @param constructionVtables
|
||||||
|
* @param numBaseRefs
|
||||||
* @return address of main vtable for this class
|
* @return address of main vtable for this class
|
||||||
* @throws CancelledException
|
* @throws CancelledException
|
||||||
*/
|
*/
|
||||||
|
@ -1468,8 +1396,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Address getMainVtableUsingSymbols(List<Address> vtableAddresses,
|
private Address getMainVtableUsingSymbols(List<Address> vtableAddresses,
|
||||||
List<Address> constructionVtables)
|
List<Address> constructionVtables) throws CancelledException {
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
List<Address> mainVtableCandidates = new ArrayList<Address>();
|
List<Address> mainVtableCandidates = new ArrayList<Address>();
|
||||||
for (Address vtableAddress : vtableAddresses) {
|
for (Address vtableAddress : vtableAddresses) {
|
||||||
|
@ -1662,8 +1589,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
symbolTable.createLabel(vtableAddress, internalString + constructionString + VTABLE_LABEL,
|
symbolTable.createLabel(vtableAddress, internalString + constructionString + VTABLE_LABEL,
|
||||||
classNamespace,
|
classNamespace, SourceType.ANALYSIS);
|
||||||
SourceType.ANALYSIS);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1690,8 +1616,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
symbolTable.createLabel(vtable.getVfunctionTop(),
|
symbolTable.createLabel(vtable.getVfunctionTop(),
|
||||||
internalString + constructionString + VFTABLE_LABEL,
|
internalString + constructionString + VFTABLE_LABEL, classNamespace,
|
||||||
classNamespace, SourceType.ANALYSIS);
|
SourceType.ANALYSIS);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1871,8 +1797,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
Namespace newNamespace;
|
Namespace newNamespace;
|
||||||
try {
|
try {
|
||||||
newNamespace = NamespaceUtils.createNamespaceHierarchy(name,
|
newNamespace = NamespaceUtils.createNamespaceHierarchy(name,
|
||||||
namespaceIn.getParentNamespace(), program,
|
namespaceIn.getParentNamespace(), program, SourceType.ANALYSIS);
|
||||||
SourceType.ANALYSIS);
|
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -1893,8 +1818,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Address, Set<Address>> findTypeinfoReferencesNotInTypeinfoStructsOld(
|
public Map<Address, Set<Address>> findTypeinfoReferencesNotInTypeinfoStructsOld(
|
||||||
List<Address> typeinfoAddresses)
|
List<Address> typeinfoAddresses) throws CancelledException {
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
MemoryBytePatternSearcher searcher = new MemoryBytePatternSearcher("Typeinfo References");
|
MemoryBytePatternSearcher searcher = new MemoryBytePatternSearcher("Typeinfo References");
|
||||||
|
|
||||||
|
@ -1934,7 +1858,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
searchSet.add(addressRange.getMinAddress(), addressRange.getMaxAddress());
|
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 =
|
AddressIterator addrIter =
|
||||||
initializedSet.getAddresses(initializedSet.getMinAddress(), true);
|
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
|
// check direct refs to see if they are in undefined area or not in function
|
||||||
byte[] bytes = ProgramMemoryUtil.getDirectAddressBytes(program, address);
|
byte[] bytes = ProgramMemoryUtil.getDirectAddressBytes(program, address);
|
||||||
|
|
||||||
addByteSearchPatternDirRefs(searcher, directRefMap, address, bytes, monitor);
|
addByteSearchPatternDirRefs(searcher, refMap, address, bytes, monitor);
|
||||||
|
|
||||||
}
|
}
|
||||||
searcher.search(program, searchSet, 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(
|
public Map<Address, Set<Address>> findTypeinfoReferencesNotInTypeinfoStructs(
|
||||||
List<GccTypeinfo> typeinfos)
|
List<GccTypeinfo> typeinfos) throws CancelledException {
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
MemoryBytePatternSearcher searcher = new MemoryBytePatternSearcher("Typeinfo References");
|
MemoryBytePatternSearcher searcher = new MemoryBytePatternSearcher("Typeinfo References");
|
||||||
|
|
||||||
|
@ -2104,8 +2027,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
* @param taskMonitor a cancellable monitor
|
* @param taskMonitor a cancellable monitor
|
||||||
*/
|
*/
|
||||||
private void addByteSearchPattern(MemoryBytePatternSearcher searcher,
|
private void addByteSearchPattern(MemoryBytePatternSearcher searcher,
|
||||||
Map<Address, Set<Address>> typeinfoRefMap,
|
Map<Address, Set<Address>> typeinfoRefMap, Address typeinfoAddress, byte[] bytes,
|
||||||
Address typeinfoAddress, byte[] bytes, TaskMonitor taskMonitor) {
|
TaskMonitor taskMonitor) {
|
||||||
|
|
||||||
// no pattern bytes.
|
// no pattern bytes.
|
||||||
if (bytes == null) {
|
if (bytes == null) {
|
||||||
|
@ -2195,8 +2118,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
* @throws CancelledException if cancelled
|
* @throws CancelledException if cancelled
|
||||||
*/
|
*/
|
||||||
private Vtable processVtable(Address vtableAddress, GccTypeinfoRef typeinfoRef,
|
private Vtable processVtable(Address vtableAddress, GccTypeinfoRef typeinfoRef,
|
||||||
Boolean isConstruction)
|
Boolean isConstruction) throws CancelledException {
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
Vtable vtable = null;
|
Vtable vtable = null;
|
||||||
boolean isSpecial = false;
|
boolean isSpecial = false;
|
||||||
|
@ -2296,9 +2218,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
api.clearListing(vtableAddress);
|
api.clearListing(vtableAddress);
|
||||||
|
|
||||||
SpecialVtable specialVtable =
|
SpecialVtable specialVtable = new SpecialVtable(program, vtableAddress, typeinfoRef,
|
||||||
new SpecialVtable(program, vtableAddress, typeinfoRef, isExternal,
|
isExternal, vtableSymbol.getParentNamespace(), monitor);
|
||||||
vtableSymbol.getParentNamespace(), monitor);
|
|
||||||
return specialVtable;
|
return specialVtable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2421,9 +2342,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
.equals(VMI_CLASS_TYPEINFO_NAMESPACE)) {
|
.equals(VMI_CLASS_TYPEINFO_NAMESPACE)) {
|
||||||
specialTypeinfoNamespaceName = VMI_CLASS_TYPEINFO_NAMESPACE;
|
specialTypeinfoNamespaceName = VMI_CLASS_TYPEINFO_NAMESPACE;
|
||||||
typeinfoToStructuretypeMap.put(typeinfoAddress, VMI_CLASS_TYPE_INFO_STRUCTURE);
|
typeinfoToStructuretypeMap.put(typeinfoAddress, VMI_CLASS_TYPE_INFO_STRUCTURE);
|
||||||
Structure vmiClassTypeinfoStructure =
|
Structure vmiClassTypeinfoStructure = getOrCreateVmiTypeinfoStructure(
|
||||||
getOrCreateVmiTypeinfoStructure(typeinfoAddress,
|
typeinfoAddress, baseClassTypeInfoStructure);
|
||||||
baseClassTypeInfoStructure);
|
|
||||||
if (vmiClassTypeinfoStructure != null) {
|
if (vmiClassTypeinfoStructure != null) {
|
||||||
newStructure =
|
newStructure =
|
||||||
applyTypeinfoStructure(vmiClassTypeinfoStructure, typeinfoAddress);
|
applyTypeinfoStructure(vmiClassTypeinfoStructure, typeinfoAddress);
|
||||||
|
@ -2500,8 +2420,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateTypeinfosWithBases(List<GccTypeinfo> typeinfos,
|
private void updateTypeinfosWithBases(List<GccTypeinfo> typeinfos,
|
||||||
Map<Address, GccTypeinfo> typeinfoMap)
|
Map<Address, GccTypeinfo> typeinfoMap) throws CancelledException {
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
List<GccTypeinfo> invalidTypeinfos = new ArrayList<GccTypeinfo>();
|
List<GccTypeinfo> invalidTypeinfos = new ArrayList<GccTypeinfo>();
|
||||||
for (GccTypeinfo typeinfo : typeinfos) {
|
for (GccTypeinfo typeinfo : typeinfos) {
|
||||||
|
@ -2549,9 +2468,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
// SI_CLASS_TYPE_INFO_STRUCTURE
|
// SI_CLASS_TYPE_INFO_STRUCTURE
|
||||||
if (!isTypeinfoStruct(siTypeinfoStructure)) {
|
if (!isTypeinfoStruct(siTypeinfoStructure)) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(siTypeinfoStructure.getAddressString(false, false) +
|
||||||
siTypeinfoStructure.getAddressString(false, false) +
|
" is not a typeinfo structure");
|
||||||
" is not a typeinfo structure");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Data baseClassPointer = siTypeinfoStructure.getComponent(2);
|
Data baseClassPointer = siTypeinfoStructure.getComponent(2);
|
||||||
|
@ -2604,9 +2522,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
extendedFlatAPI.getReferencedAddress(baseClassStructureAddress, false);
|
extendedFlatAPI.getReferencedAddress(baseClassStructureAddress, false);
|
||||||
|
|
||||||
if (baseTypeinfoAddress == null) {
|
if (baseTypeinfoAddress == null) {
|
||||||
Msg.debug(this,
|
Msg.debug(this, typeinfo.getAddress() +
|
||||||
typeinfo.getAddress() +
|
": invalid typeinfo - cannot get address at baseTypeinfo[" + i + "]");
|
||||||
": invalid typeinfo - cannot get address at baseTypeinfo[" + i + "]");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2674,8 +2591,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
DataType inheritanceFlagDataType = inheritanceFlagComponent.getDataType();
|
DataType inheritanceFlagDataType = inheritanceFlagComponent.getDataType();
|
||||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), flagAddress);
|
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), flagAddress);
|
||||||
Scalar scalar = (Scalar) inheritanceFlagDataType.getValue(buf,
|
Scalar scalar = (Scalar) inheritanceFlagDataType.getValue(buf,
|
||||||
inheritanceFlagDataType.getDefaultSettings(),
|
inheritanceFlagDataType.getDefaultSettings(), inheritanceFlagDataType.getLength());
|
||||||
inheritanceFlagDataType.getLength());
|
|
||||||
long inheritanceFlagValue = scalar.getUnsignedValue();
|
long inheritanceFlagValue = scalar.getUnsignedValue();
|
||||||
return inheritanceFlagValue;
|
return inheritanceFlagValue;
|
||||||
}
|
}
|
||||||
|
@ -2693,8 +2609,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
DataType numBaseClassesDataType = numBaseClassesComponent.getDataType();
|
DataType numBaseClassesDataType = numBaseClassesComponent.getDataType();
|
||||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), numBaseClassesAddress);
|
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), numBaseClassesAddress);
|
||||||
Scalar scalar = (Scalar) numBaseClassesDataType.getValue(buf,
|
Scalar scalar = (Scalar) numBaseClassesDataType.getValue(buf,
|
||||||
numBaseClassesDataType.getDefaultSettings(),
|
numBaseClassesDataType.getDefaultSettings(), numBaseClassesDataType.getLength());
|
||||||
numBaseClassesDataType.getLength());
|
|
||||||
int numBaseClasses = (int) scalar.getUnsignedValue();
|
int numBaseClasses = (int) scalar.getUnsignedValue();
|
||||||
|
|
||||||
return numBaseClasses;
|
return numBaseClasses;
|
||||||
|
@ -2810,9 +2725,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// get or create the vmiClassTypeInfoStruct
|
// get or create the vmiClassTypeInfoStruct
|
||||||
Structure vmiClassTypeinfoStructure =
|
Structure vmiClassTypeinfoStructure = (Structure) dataTypeManager
|
||||||
(Structure) dataTypeManager.getDataType(classDataTypesCategoryPath,
|
.getDataType(classDataTypesCategoryPath, VMI_CLASS_TYPE_INFO_STRUCTURE + numBases);
|
||||||
VMI_CLASS_TYPE_INFO_STRUCTURE + numBases);
|
|
||||||
if (vmiClassTypeinfoStructure == null) {
|
if (vmiClassTypeinfoStructure == null) {
|
||||||
vmiClassTypeinfoStructure =
|
vmiClassTypeinfoStructure =
|
||||||
createVmiClassTypeInfoStructure(baseClassTypeInfoStructure, numBases);
|
createVmiClassTypeInfoStructure(baseClassTypeInfoStructure, numBases);
|
||||||
|
@ -2821,7 +2735,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Symbol createDemangledTypeinfoSymbol(Address typeinfoAddress)
|
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: 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
|
// TODO: 2 - refactor the three places that call this to just call getSymbolAt
|
||||||
|
@ -2919,9 +2833,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
Namespace classNamespace = typeinfoNameSymbol.getParentNamespace();
|
Namespace classNamespace = typeinfoNameSymbol.getParentNamespace();
|
||||||
|
|
||||||
if (classNamespace.isGlobal()) {
|
if (classNamespace.isGlobal()) {
|
||||||
Msg.debug(this,
|
Msg.debug(this, typeinfoAddress.toString() +
|
||||||
typeinfoAddress.toString() +
|
"Could not create a class namespace for demangled namespace string ");
|
||||||
"Could not create a class namespace for demangled namespace string ");
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2987,7 +2900,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
private String getDefinedStringAt(Address address) {
|
private String getDefinedStringAt(Address address) {
|
||||||
|
|
||||||
Listing listing = program.getListing();
|
|
||||||
Data stringData = listing.getDataAt(address);
|
Data stringData = listing.getDataAt(address);
|
||||||
|
|
||||||
if (stringData == null) {
|
if (stringData == null) {
|
||||||
|
@ -3218,15 +3130,11 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assignConstructorsAndDestructorsUsingExistingNameNew(
|
public void assignConstructorsAndDestructorsUsingExistingNameNew(
|
||||||
List<RecoveredClass> recoveredClasses)
|
List<RecoveredClass> recoveredClasses) throws CancelledException, InvalidInputException,
|
||||||
throws CancelledException, InvalidInputException, DuplicateNameException,
|
DuplicateNameException, CircularDependencyException {
|
||||||
CircularDependencyException {
|
|
||||||
|
|
||||||
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
|
for (RecoveredClass recoveredClass : recoveredClasses) {
|
||||||
while (recoveredClassIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
RecoveredClass recoveredClass = recoveredClassIterator.next();
|
|
||||||
|
|
||||||
Namespace classNamespace = recoveredClass.getClassNamespace();
|
Namespace classNamespace = recoveredClass.getClassNamespace();
|
||||||
String name = classNamespace.getName();
|
String name = classNamespace.getName();
|
||||||
SymbolIterator classSymbols = symbolTable.getSymbols(classNamespace);
|
SymbolIterator classSymbols = symbolTable.getSymbols(classNamespace);
|
||||||
|
@ -3353,8 +3261,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeFromIndeterminateLists(List<RecoveredClass> recoveredClasses,
|
private void removeFromIndeterminateLists(List<RecoveredClass> recoveredClasses,
|
||||||
Function function)
|
Function function) throws CancelledException {
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
for (RecoveredClass recoveredClass : recoveredClasses) {
|
for (RecoveredClass recoveredClass : recoveredClasses) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
|
@ -3373,8 +3280,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
if (hasExternalRelocations()) {
|
if (hasExternalRelocations()) {
|
||||||
PointerTypedef classTypeInfoPtr =
|
PointerTypedef classTypeInfoPtr =
|
||||||
new PointerTypedef(null, null, -1, program.getDataTypeManager(),
|
new PointerTypedef(null, null, -1, program.getDataTypeManager(), componentOffset);
|
||||||
componentOffset);
|
|
||||||
classTypeInfoStructure.add(classTypeInfoPtr, "classTypeinfoPtr", null);
|
classTypeInfoStructure.add(classTypeInfoPtr, "classTypeinfoPtr", null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3393,18 +3299,15 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private StructureDataType createSiClassTypeInfoStructure(
|
private StructureDataType createSiClassTypeInfoStructure(
|
||||||
StructureDataType classTypeInfoStructure)
|
StructureDataType classTypeInfoStructure) throws CancelledException {
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
StructureDataType siClassTypeInfoStructure =
|
StructureDataType siClassTypeInfoStructure = new StructureDataType(
|
||||||
new StructureDataType(classDataTypesCategoryPath,
|
classDataTypesCategoryPath, SI_CLASS_TYPE_INFO_STRUCTURE, 0, dataTypeManager);
|
||||||
SI_CLASS_TYPE_INFO_STRUCTURE, 0, dataTypeManager);
|
|
||||||
|
|
||||||
CharDataType characterDT = new CharDataType();
|
CharDataType characterDT = new CharDataType();
|
||||||
|
|
||||||
PointerTypedef classTypeInfoPtr =
|
PointerTypedef classTypeInfoPtr =
|
||||||
new PointerTypedef(null, null, -1, program.getDataTypeManager(),
|
new PointerTypedef(null, null, -1, program.getDataTypeManager(), componentOffset);
|
||||||
componentOffset);
|
|
||||||
siClassTypeInfoStructure.add(classTypeInfoPtr, "classTypeinfoPtr", null);
|
siClassTypeInfoStructure.add(classTypeInfoPtr, "classTypeinfoPtr", null);
|
||||||
|
|
||||||
DataType charPointer = dataTypeManager.getPointer(characterDT);
|
DataType charPointer = dataTypeManager.getPointer(characterDT);
|
||||||
|
@ -3420,12 +3323,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private StructureDataType createBaseClassTypeInfoStructure(
|
private StructureDataType createBaseClassTypeInfoStructure(
|
||||||
StructureDataType classTypeInfoStructure)
|
StructureDataType classTypeInfoStructure) throws InvalidDataTypeException {
|
||||||
throws InvalidDataTypeException {
|
|
||||||
|
|
||||||
StructureDataType baseclassTypeInfoStructure =
|
StructureDataType baseclassTypeInfoStructure = new StructureDataType(
|
||||||
new StructureDataType(classDataTypesCategoryPath,
|
classDataTypesCategoryPath, BASE_CLASS_TYPE_INFO_STRUCTURE, 0, dataTypeManager);
|
||||||
BASE_CLASS_TYPE_INFO_STRUCTURE, 0, dataTypeManager);
|
|
||||||
|
|
||||||
DataType classTypeInfoPointer = dataTypeManager.getPointer(classTypeInfoStructure);
|
DataType classTypeInfoPointer = dataTypeManager.getPointer(classTypeInfoStructure);
|
||||||
|
|
||||||
|
@ -3460,8 +3361,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private StructureDataType createVmiClassTypeInfoStructure(
|
private StructureDataType createVmiClassTypeInfoStructure(
|
||||||
StructureDataType baseClassTypeInfoStructure,
|
StructureDataType baseClassTypeInfoStructure, int numBaseClasses)
|
||||||
int numBaseClasses) throws CancelledException {
|
throws CancelledException {
|
||||||
|
|
||||||
StructureDataType vmiClassTypeInfoStructure =
|
StructureDataType vmiClassTypeInfoStructure =
|
||||||
new StructureDataType(classDataTypesCategoryPath,
|
new StructureDataType(classDataTypesCategoryPath,
|
||||||
|
@ -3471,8 +3372,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
UnsignedIntegerDataType unsignedIntDT = new UnsignedIntegerDataType();
|
UnsignedIntegerDataType unsignedIntDT = new UnsignedIntegerDataType();
|
||||||
|
|
||||||
PointerTypedef classTypeInfoPtr =
|
PointerTypedef classTypeInfoPtr =
|
||||||
new PointerTypedef(null, null, -1, program.getDataTypeManager(),
|
new PointerTypedef(null, null, -1, program.getDataTypeManager(), componentOffset);
|
||||||
componentOffset);
|
|
||||||
vmiClassTypeInfoStructure.add(classTypeInfoPtr, "classTypeinfoPtr", null);
|
vmiClassTypeInfoStructure.add(classTypeInfoPtr, "classTypeinfoPtr", null);
|
||||||
|
|
||||||
DataType charPointer = dataTypeManager.getPointer(characterDT);
|
DataType charPointer = dataTypeManager.getPointer(characterDT);
|
||||||
|
@ -3564,8 +3464,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
* @throws CancelledException if cancelled
|
* @throws CancelledException if cancelled
|
||||||
*/
|
*/
|
||||||
private List<RecoveredClass> addClassParentsAndFlagsForVmiClass(RecoveredClass recoveredClass,
|
private List<RecoveredClass> addClassParentsAndFlagsForVmiClass(RecoveredClass recoveredClass,
|
||||||
GccTypeinfo typeinfo)
|
GccTypeinfo typeinfo) throws CancelledException {
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
long inheritanceFlagValue = typeinfo.getInheritanceFlagValue();
|
long inheritanceFlagValue = typeinfo.getInheritanceFlagValue();
|
||||||
|
|
||||||
|
@ -3646,8 +3545,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Address findSpecialVtable(GccTypeinfo specialTypeinfo,
|
private Address findSpecialVtable(GccTypeinfo specialTypeinfo,
|
||||||
List<GccTypeinfo> specialTypeinfos)
|
List<GccTypeinfo> specialTypeinfos) throws CancelledException {
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
String namespaceName = specialTypeinfo.getNamespace().getName();
|
String namespaceName = specialTypeinfo.getNamespace().getName();
|
||||||
String mangledNamespaceString = specialTypeinfo.getMangledNamespaceString();
|
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
|
// then try finding top of special vtable by finding ref to special typeinfo
|
||||||
if (vtableSymbol == null) {
|
if (vtableSymbol == null) {
|
||||||
Address vtableAddress =
|
Address vtableAddress = findSpecialVtableUsingSpecialTypeinfo(
|
||||||
findSpecialVtableUsingSpecialTypeinfo(specialTypeinfo.getAddress(),
|
specialTypeinfo.getAddress(), specialTypeinfos);
|
||||||
specialTypeinfos);
|
|
||||||
|
|
||||||
if (vtableAddress == null) {
|
if (vtableAddress == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -3673,14 +3570,13 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
vtableSymbol = symbolTable.createLabel(vtableAddress, VTABLE_LABEL,
|
vtableSymbol = symbolTable.createLabel(vtableAddress, VTABLE_LABEL,
|
||||||
specialTypeinfo.getNamespace(),
|
specialTypeinfo.getNamespace(), SourceType.ANALYSIS);
|
||||||
SourceType.ANALYSIS);
|
|
||||||
api.setPlateComment(vtableAddress,
|
api.setPlateComment(vtableAddress,
|
||||||
"vtable for " + specialTypeinfo.getNamespace());
|
"vtable for " + specialTypeinfo.getNamespace());
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
vtableSymbol = null;
|
// ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3729,8 +3625,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
* len between the two
|
* len between the two
|
||||||
*/
|
*/
|
||||||
private Address findSpecialVtableUsingSpecialTypeinfo(Address typeinfoAddress,
|
private Address findSpecialVtableUsingSpecialTypeinfo(Address typeinfoAddress,
|
||||||
List<GccTypeinfo> specialTypeinfos)
|
List<GccTypeinfo> specialTypeinfos) throws CancelledException {
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
List<Address> referencesTo = getAllReferencesTo(typeinfoAddress);
|
List<Address> referencesTo = getAllReferencesTo(typeinfoAddress);
|
||||||
|
|
||||||
|
@ -3805,8 +3700,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
symbolTable.createLabel(findSingleMangledString, mangledNamespaceString,
|
symbolTable.createLabel(findSingleMangledString, mangledNamespaceString,
|
||||||
globalNamespace,
|
globalNamespace, SourceType.ANALYSIS);
|
||||||
SourceType.ANALYSIS);
|
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
|
|
||||||
|
@ -4096,7 +3990,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
baseOffsets.add(baseTypeinfo.getOffset());
|
baseOffsets.add(baseTypeinfo.getOffset());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (baseOffsets.size() != vftableAddresses.size()) {
|
if (baseOffsets.size() != vftableAddresses.size()) {
|
||||||
|
|
||||||
|
@ -4127,13 +4020,12 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
recoveredClass.addVftableToBaseClassMapping(correspondingVftableAddress, baseClass);
|
recoveredClass.addVftableToBaseClassMapping(correspondingVftableAddress, baseClass);
|
||||||
|
|
||||||
//TODO: populate the new Vftable objects
|
//TODO: populate the new Vftable objects
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use information from RTTI Base class Arrays to create class hierarchy lists
|
* Use information from RTTI Base class Arrays to create class hierarchy lists
|
||||||
* and maps
|
* and maps
|
||||||
|
@ -4188,10 +4080,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
RecoveredClass recoveredClass = recoveredClassIterator.next();
|
RecoveredClass recoveredClass = recoveredClassIterator.next();
|
||||||
List<RecoveredClass> parentList = recoveredClass.getParentList();
|
List<RecoveredClass> parentList = recoveredClass.getParentList();
|
||||||
Iterator<RecoveredClass> parentIterator = parentList.iterator();
|
for (RecoveredClass parentClass : parentList) {
|
||||||
while (parentIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
RecoveredClass parentClass = parentIterator.next();
|
|
||||||
recoveredClass.addClassHierarchyMapping(parentClass,
|
recoveredClass.addClassHierarchyMapping(parentClass,
|
||||||
parentClass.getClassHierarchy());
|
parentClass.getClassHierarchy());
|
||||||
}
|
}
|
||||||
|
@ -4224,10 +4114,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
private boolean hasVirtualAncestor(RecoveredClass recoveredClass) throws CancelledException {
|
private boolean hasVirtualAncestor(RecoveredClass recoveredClass) throws CancelledException {
|
||||||
|
|
||||||
List<RecoveredClass> classHierarchy = recoveredClass.getClassHierarchy();
|
List<RecoveredClass> classHierarchy = recoveredClass.getClassHierarchy();
|
||||||
Iterator<RecoveredClass> classIterator = classHierarchy.iterator();
|
for (RecoveredClass ancestor : classHierarchy) {
|
||||||
while (classIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
RecoveredClass ancestor = classIterator.next();
|
|
||||||
if (ancestor.inheritsVirtualAncestor()) {
|
if (ancestor.inheritsVirtualAncestor()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -4287,11 +4175,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
classHierarchyList.add(recoveredClass);
|
classHierarchyList.add(recoveredClass);
|
||||||
|
|
||||||
List<RecoveredClass> parentList = recoveredClass.getParentList();
|
List<RecoveredClass> parentList = recoveredClass.getParentList();
|
||||||
Iterator<RecoveredClass> parentIterator = parentList.iterator();
|
for (RecoveredClass parentClass : parentList) {
|
||||||
while (parentIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
|
|
||||||
RecoveredClass parentClass = parentIterator.next();
|
|
||||||
if (nonInheritedClasses.contains(parentClass)) {
|
if (nonInheritedClasses.contains(parentClass)) {
|
||||||
classHierarchyList.addAll(parentClass.getClassHierarchy());
|
classHierarchyList.addAll(parentClass.getClassHierarchy());
|
||||||
continue;
|
continue;
|
||||||
|
@ -4403,8 +4289,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
disassemble = api.disassemble(address);
|
disassemble = api.disassemble(address);
|
||||||
|
|
||||||
Bookmark bookmark = getBookmarkAt(possibleFunctionPointer, BookmarkType.ERROR,
|
Bookmark bookmark = getBookmarkAt(possibleFunctionPointer, BookmarkType.ERROR,
|
||||||
"Bad Instruction",
|
"Bad Instruction", "conflicting data");
|
||||||
"conflicting data");
|
|
||||||
if (bookmark != null) {
|
if (bookmark != null) {
|
||||||
api.removeBookmark(bookmark);
|
api.removeBookmark(bookmark);
|
||||||
}
|
}
|
||||||
|
@ -4418,8 +4303,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bookmark getBookmarkAt(Address address, String bookmarkType, String category,
|
private Bookmark getBookmarkAt(Address address, String bookmarkType, String category,
|
||||||
String commentContains)
|
String commentContains) throws CancelledException {
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
Bookmark[] bookmarks = program.getBookmarkManager().getBookmarks(address);
|
Bookmark[] bookmarks = program.getBookmarkManager().getBookmarks(address);
|
||||||
|
|
||||||
|
@ -4544,10 +4428,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
for (RecoveredClass parent : parentList) {
|
for (RecoveredClass parent : parentList) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
if (parent.getName().endsWith("_class_type_info")) {
|
if (parent.getName().endsWith("_class_type_info")) {
|
||||||
Msg.debug(this,
|
Msg.debug(this, "Not creating class data type for " +
|
||||||
"Not creating class data type for " +
|
recoveredClass.getClassNamespace().getName(true) +
|
||||||
recoveredClass.getClassNamespace().getName(true) +
|
" because it has a parent that is one of the special typeinfo classes.");
|
||||||
" because it has a parent that is one of the special typeinfo classes.");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4570,8 +4453,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
recoveredClass.getClassNamespace().getName(true));
|
recoveredClass.getClassNamespace().getName(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
updateClassFunctionsNotUsingNewClassStructure(recoveredClass,
|
updateClassFunctionsNotUsingNewClassStructure(recoveredClass, classStructure);
|
||||||
classStructure);
|
|
||||||
// return in this case because if there is no vftable for a class the script cannot
|
// 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
|
// identify any member functions so there is no need to process the rest of this
|
||||||
// method
|
// method
|
||||||
|
@ -4664,8 +4546,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
// simple case the offset for vftablePtr is 0
|
// simple case the offset for vftablePtr is 0
|
||||||
// if can fit or grow structure, add the vftablePtr to it
|
// if can fit or grow structure, add the vftablePtr to it
|
||||||
EditStructureUtils.addDataTypeToStructure(classStructureDataType, 0,
|
EditStructureUtils.addDataTypeToStructure(classStructureDataType, 0,
|
||||||
classVftablePointer,
|
classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor);
|
||||||
CLASS_VTABLE_PTR_FIELD_EXT, monitor);
|
|
||||||
}
|
}
|
||||||
// if single inheritance or multi non-virtual (wouldn't have called this method
|
// 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
|
// if it were virtually inherited) put parent struct and data into class struct
|
||||||
|
@ -4674,18 +4555,16 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
Map<Integer, RecoveredClass> orderToParentMap =
|
Map<Integer, RecoveredClass> orderToParentMap =
|
||||||
classToParentOrderMap.get(recoveredClass);
|
classToParentOrderMap.get(recoveredClass);
|
||||||
if (orderToParentMap == null || orderToParentMap.isEmpty()) {
|
if (orderToParentMap == null || orderToParentMap.isEmpty()) {
|
||||||
Msg.error(this,
|
Msg.error(this, "Vmi class " + recoveredClass.getClassNamespace().getName(true) +
|
||||||
"Vmi class " + recoveredClass.getClassNamespace().getName(true) +
|
" should have a parent in the classToParentOrderMap but doesn't");
|
||||||
" should have a parent in the classToParentOrderMap but doesn't");
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<RecoveredClass, Long> parentToOffsetMap =
|
Map<RecoveredClass, Long> parentToOffsetMap =
|
||||||
classToParentOffsetMap.get(recoveredClass);
|
classToParentOffsetMap.get(recoveredClass);
|
||||||
if (parentToOffsetMap.isEmpty()) {
|
if (parentToOffsetMap.isEmpty()) {
|
||||||
Msg.error(this,
|
Msg.error(this, "Vmi class " + recoveredClass.getClassNamespace().getName(true) +
|
||||||
"Vmi class " + recoveredClass.getClassNamespace().getName(true) +
|
" should have a parent in the classToParentOffsetMap but doesn't");
|
||||||
" should have a parent in the classToParentOffsetMap but doesn't");
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4705,8 +4584,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
if (baseClassStructure == null) {
|
if (baseClassStructure == null) {
|
||||||
Msg.error(this, "Parent structure: " +
|
Msg.error(this, "Parent structure: " +
|
||||||
parent.getClassNamespace().getName(true) +
|
parent.getClassNamespace().getName(true) + " should exist but doesn't.");
|
||||||
" should exist but doesn't.");
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// if it fits at offset or is at the end and class structure can be grown,
|
// 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;
|
int dataLen = UNKNOWN;
|
||||||
if (dataOffset != NONE) {
|
if (dataOffset != NONE) {
|
||||||
dataLen = EditStructureUtils.getNumberOfUndefinedsStartingAtOffset(
|
dataLen = EditStructureUtils.getNumberOfUndefinedsStartingAtOffset(
|
||||||
classStructureDataType, dataOffset,
|
classStructureDataType, dataOffset, monitor);
|
||||||
monitor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dataLen != UNKNOWN && dataLen > 0) {
|
if (dataLen != UNKNOWN && dataLen > 0) {
|
||||||
|
|
||||||
Structure recoveredClassDataStruct =
|
Structure recoveredClassDataStruct = createClassMemberDataStructure(recoveredClass,
|
||||||
createClassMemberDataStructure(recoveredClass, classStructureDataType,
|
classStructureDataType, dataLen, dataOffset);
|
||||||
dataLen, dataOffset);
|
|
||||||
|
|
||||||
if (recoveredClassDataStruct != null) {
|
if (recoveredClassDataStruct != null) {
|
||||||
// if it fits at offset or is at the end and class structure can be grown,
|
// 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
|
// copy the whole baseClass structure to the class Structure at the given offset
|
||||||
EditStructureUtils.addDataTypeToStructure(classStructureDataType, dataOffset,
|
EditStructureUtils.addDataTypeToStructure(classStructureDataType, dataOffset,
|
||||||
recoveredClassDataStruct,
|
recoveredClassDataStruct, "data", monitor);
|
||||||
"data", monitor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,56 +16,26 @@
|
||||||
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS.
|
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS.
|
||||||
package classrecovery;
|
package classrecovery;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
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 ghidra.app.plugin.core.decompile.actions.FillOutStructureCmd;
|
import ghidra.app.decompiler.DecompileOptions;
|
||||||
import ghidra.app.plugin.core.decompile.actions.FillOutStructureCmd.OffsetPcodeOpPair;
|
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;
|
||||||
import ghidra.app.util.opinion.PeLoader.CompilerOpinion.CompilerEnum;
|
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.flatapi.FlatProgramAPI;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.address.AddressOutOfBoundsException;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.address.AddressRange;
|
import ghidra.program.model.listing.*;
|
||||||
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.mem.MemoryAccessException;
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
import ghidra.program.model.mem.MemoryBlock;
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
import ghidra.program.model.pcode.HighFunction;
|
import ghidra.program.model.pcode.HighFunction;
|
||||||
import ghidra.program.model.pcode.HighVariable;
|
import ghidra.program.model.pcode.HighVariable;
|
||||||
import ghidra.program.model.symbol.Namespace;
|
import ghidra.program.model.symbol.*;
|
||||||
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.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.*;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
|
||||||
import ghidra.util.exception.InvalidInputException;
|
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
@ -85,7 +55,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
private static final String RTTI_CLASS_HIERARCHY_DESCRIPTOR_DATA_NAME =
|
private static final String RTTI_CLASS_HIERARCHY_DESCRIPTOR_DATA_NAME =
|
||||||
"RTTIClassHierarchyDescriptor";
|
"RTTIClassHierarchyDescriptor";
|
||||||
private static final String VFTABLE_META_PTR_LABEL = "vftable_meta_ptr";
|
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_STRUCT_NAME = "_vbtable";
|
||||||
private static final String CLASS_VTABLE_PTR_FIELD_EXT = "vftablePtr";
|
private static final String CLASS_VTABLE_PTR_FIELD_EXT = "vftablePtr";
|
||||||
|
@ -102,15 +72,14 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
boolean isPDBLoaded;
|
boolean isPDBLoaded;
|
||||||
|
|
||||||
public RTTIWindowsClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
|
public RTTIWindowsClassRecoverer(Program program, ServiceProvider serviceProvider,
|
||||||
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
||||||
boolean nameVFunctions, boolean isPDBLoaded, TaskMonitor monitor) throws Exception {
|
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);
|
isPDBLoaded, monitor);
|
||||||
|
|
||||||
this.isPDBLoaded = isPDBLoaded;
|
this.isPDBLoaded = isPDBLoaded;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -241,60 +210,60 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Method to determine if the current program has RTTI data applied to it
|
// * 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
|
// * @return true if the current program has RTTI data applied to it
|
||||||
* @throws CancelledException if cancelled
|
// * @throws CancelledException if cancelled
|
||||||
*/
|
// */
|
||||||
private boolean programHasRTTIApplied() throws CancelledException {
|
// private boolean programHasRTTIApplied() throws CancelledException {
|
||||||
|
//
|
||||||
// First check to see if the RTTICompleteObjectLocator data type exists. If not there has
|
// // First check to see if the RTTICompleteObjectLocator data type exists. If not there has
|
||||||
// been no RTTI applied
|
// // been no RTTI applied
|
||||||
DataType completeObjLocatorDataType = dataTypeManager.getDataType(CategoryPath.ROOT,
|
// DataType completeObjLocatorDataType = dataTypeManager.getDataType(CategoryPath.ROOT,
|
||||||
RTTI_BASE_COMPLETE_OBJECT_LOADER_DATA_NAME);
|
// RTTI_BASE_COMPLETE_OBJECT_LOADER_DATA_NAME);
|
||||||
if (completeObjLocatorDataType == null) {
|
// if (completeObjLocatorDataType == null) {
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// Next check that a RTTICompleteObjectLocator has been applied somewhere to make sure that
|
// // 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
|
// // 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
|
// // apply any of the data types
|
||||||
return hasSymbolAndDataType(RTTI_BASE_COMPLETE_OBJECT_LOADER_LABEL,
|
// return hasSymbolAndDataType(RTTI_BASE_COMPLETE_OBJECT_LOADER_LABEL,
|
||||||
completeObjLocatorDataType);
|
// completeObjLocatorDataType);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private void runRTTIAnalyzer() throws Exception {
|
// private void runRTTIAnalyzer() throws Exception {
|
||||||
// Analyzer analyzer = new RttiAnalyzer();
|
//// Analyzer analyzer = new RttiAnalyzer();
|
||||||
// analyzer.added(program, program.getAddressFactory().getAddressSet(), monitor,
|
//// analyzer.added(program, program.getAddressFactory().getAddressSet(), monitor,
|
||||||
// new MessageLog());
|
//// new MessageLog());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* Method to find all the vftables in the program
|
// * Method to find all the vftables in the program
|
||||||
* @return list of all vftable symbols
|
// * @return list of all vftable symbols
|
||||||
* @throws CancelledException when cancelled
|
// * @throws CancelledException when cancelled
|
||||||
*/
|
// */
|
||||||
//TODO: pull into separate methods and check separately above
|
// //TODO: pull into separate methods and check separately above
|
||||||
private boolean hasSymbolAndDataType(String symbolName, DataType datatype)
|
// private boolean hasSymbolAndDataType(String symbolName, DataType datatype)
|
||||||
throws CancelledException {
|
// throws CancelledException {
|
||||||
|
//
|
||||||
String pdbName = "`" + symbolName + "'";
|
// String pdbName = "`" + symbolName + "'";
|
||||||
SymbolIterator symbols =
|
// SymbolIterator symbols =
|
||||||
program.getSymbolTable().getSymbolIterator("*" + symbolName + "*", true);
|
// program.getSymbolTable().getSymbolIterator("*" + symbolName + "*", true);
|
||||||
|
//
|
||||||
while (symbols.hasNext()) {
|
// while (symbols.hasNext()) {
|
||||||
monitor.checkCancelled();
|
// monitor.checkCancelled();
|
||||||
Symbol symbol = symbols.next();
|
// Symbol symbol = symbols.next();
|
||||||
if (symbol.getName().equals(symbolName) || symbol.getName().equals(pdbName)) {
|
// if (symbol.getName().equals(symbolName) || symbol.getName().equals(pdbName)) {
|
||||||
Data dataAt = program.getListing().getDefinedDataAt(symbol.getAddress());
|
// Data dataAt = program.getListing().getDefinedDataAt(symbol.getAddress());
|
||||||
if (dataAt.getDataType().equals(datatype)) {
|
// if (dataAt.getDataType().equals(datatype)) {
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
|
|
||||||
public void fixUpRttiAnalysis() throws CancelledException, Exception {
|
public void fixUpRttiAnalysis() throws CancelledException, Exception {
|
||||||
applyMissingRTTIStructures();
|
applyMissingRTTIStructures();
|
||||||
|
@ -512,10 +481,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
List<Address> classHierarchyDescriptorAddresses = new ArrayList<Address>();
|
List<Address> classHierarchyDescriptorAddresses = new ArrayList<Address>();
|
||||||
|
|
||||||
Iterator<Symbol> baseClassDescriptorIterator = baseClassDescriptors.iterator();
|
for (Symbol symbol : baseClassDescriptors) {
|
||||||
while (baseClassDescriptorIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
Symbol symbol = baseClassDescriptorIterator.next();
|
|
||||||
Address classHierarchyDescriptorAddress = createClassHierarchyDescriptor(
|
Address classHierarchyDescriptorAddress = createClassHierarchyDescriptor(
|
||||||
symbol.getAddress().add(24), symbol.getParentNamespace());
|
symbol.getAddress().add(24), symbol.getParentNamespace());
|
||||||
|
|
||||||
|
@ -526,10 +493,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator<Symbol> completeObjectLocatorIterator = completeObjectLocators.iterator();
|
for (Symbol symbol : completeObjectLocators) {
|
||||||
while (completeObjectLocatorIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
Symbol symbol = completeObjectLocatorIterator.next();
|
|
||||||
Address classHierarchyDescriptorAddress = createClassHierarchyDescriptor(
|
Address classHierarchyDescriptorAddress = createClassHierarchyDescriptor(
|
||||||
symbol.getAddress().add(16), symbol.getParentNamespace());
|
symbol.getAddress().add(16), symbol.getParentNamespace());
|
||||||
if (classHierarchyDescriptorAddress != null &&
|
if (classHierarchyDescriptorAddress != null &&
|
||||||
|
@ -621,13 +586,10 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
List<Address> baseClassArrayAddresses = new ArrayList<Address>();
|
List<Address> baseClassArrayAddresses = new ArrayList<Address>();
|
||||||
|
|
||||||
Iterator<Address> classHierarchyDescriptorIterator = classHierarchyDescriptors.iterator();
|
for (Address classHierarchyDescriptorAddress : classHierarchyDescriptors) {
|
||||||
|
|
||||||
while (classHierarchyDescriptorIterator.hasNext()) {
|
|
||||||
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
|
|
||||||
Address classHierarchyDescriptorAddress = classHierarchyDescriptorIterator.next();
|
|
||||||
Symbol classHierarchyDescriptorSymbol =
|
Symbol classHierarchyDescriptorSymbol =
|
||||||
symbolTable.getPrimarySymbol(classHierarchyDescriptorAddress);
|
symbolTable.getPrimarySymbol(classHierarchyDescriptorAddress);
|
||||||
Namespace classNamespace = classHierarchyDescriptorSymbol.getParentNamespace();
|
Namespace classNamespace = classHierarchyDescriptorSymbol.getParentNamespace();
|
||||||
|
@ -725,11 +687,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
List<Symbol> vftables = new ArrayList<Symbol>();
|
List<Symbol> vftables = new ArrayList<Symbol>();
|
||||||
|
|
||||||
Iterator<Symbol> iterator = completeObjectLocatorSymbols.iterator();
|
for (Symbol completeObjectLocatorSymbol : completeObjectLocatorSymbols) {
|
||||||
while (iterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
Symbol completeObjectLocatorSymbol = iterator.next();
|
|
||||||
|
|
||||||
Address completeObjectLocatorAddress = completeObjectLocatorSymbol.getAddress();
|
Address completeObjectLocatorAddress = completeObjectLocatorSymbol.getAddress();
|
||||||
|
|
||||||
Namespace classNamespace = completeObjectLocatorSymbol.getParentNamespace();
|
Namespace classNamespace = completeObjectLocatorSymbol.getParentNamespace();
|
||||||
|
@ -903,10 +862,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
List<Symbol> classHierarchyDescriptorList = getListOfClassHierarchyDescriptors();
|
List<Symbol> classHierarchyDescriptorList = getListOfClassHierarchyDescriptors();
|
||||||
|
|
||||||
Iterator<Symbol> classHierarchyDescriptorIterator = classHierarchyDescriptorList.iterator();
|
for (Symbol classHierarchyDescriptorSymbol : classHierarchyDescriptorList) {
|
||||||
while (classHierarchyDescriptorIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
Symbol classHierarchyDescriptorSymbol = classHierarchyDescriptorIterator.next();
|
|
||||||
Address classHierarchyDescriptorAddress = classHierarchyDescriptorSymbol.getAddress();
|
Address classHierarchyDescriptorAddress = classHierarchyDescriptorSymbol.getAddress();
|
||||||
|
|
||||||
// Get class name from class vftable is in
|
// Get class name from class vftable is in
|
||||||
|
@ -1000,16 +957,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
PointerDataType pointerDataType = new PointerDataType();
|
PointerDataType pointerDataType = new PointerDataType();
|
||||||
|
|
||||||
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
|
for (RecoveredClass recoveredClass : recoveredClasses) {
|
||||||
while (recoveredClassIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
RecoveredClass recoveredClass = recoveredClassIterator.next();
|
|
||||||
|
|
||||||
List<Address> vftableAddresses = recoveredClass.getVftableAddresses();
|
List<Address> vftableAddresses = recoveredClass.getVftableAddresses();
|
||||||
Iterator<Address> vftableIterator = vftableAddresses.iterator();
|
for (Address vftableAddress : vftableAddresses) {
|
||||||
while (vftableIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
Address vftableAddress = vftableIterator.next();
|
|
||||||
Address ptrToColAddress = vftableAddress.subtract(defaultPointerSize);
|
Address ptrToColAddress = vftableAddress.subtract(defaultPointerSize);
|
||||||
|
|
||||||
Data pointerToCompleteObjLocator = extendedFlatAPI.getDataAt(vftableAddress);
|
Data pointerToCompleteObjLocator = extendedFlatAPI.getDataAt(vftableAddress);
|
||||||
|
@ -1396,12 +1348,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
private void determineParentClassInfoFromBaseClassArray(List<RecoveredClass> recoveredClasses)
|
private void determineParentClassInfoFromBaseClassArray(List<RecoveredClass> recoveredClasses)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
||||||
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
|
for (RecoveredClass recoveredClass : recoveredClasses) {
|
||||||
while (recoveredClassIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
|
|
||||||
RecoveredClass recoveredClass = recoveredClassIterator.next();
|
|
||||||
|
|
||||||
boolean hasVirtualAncestor = false;
|
boolean hasVirtualAncestor = false;
|
||||||
int vbaseOffset = NONE;
|
int vbaseOffset = NONE;
|
||||||
|
|
||||||
|
@ -1531,22 +1480,22 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator<Function> constructorIterator = constructorList.iterator();
|
DecompileOptions decompileOptions =
|
||||||
while (constructorIterator.hasNext()) {
|
DecompilerUtils.getDecompileOptions(serviceProvider, program);
|
||||||
|
FillOutStructureHelper fillStructHelper =
|
||||||
|
new FillOutStructureHelper(program, decompileOptions, monitor);
|
||||||
|
|
||||||
|
for (Function constructor : constructorList) {
|
||||||
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
Function constructor = constructorIterator.next();
|
|
||||||
|
|
||||||
HighFunction highFunction = decompilerUtils.getHighFunction(constructor);
|
HighFunction highFunction = decompilerUtils.getHighFunction(constructor);
|
||||||
|
|
||||||
if (highFunction == null) {
|
if (highFunction == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
FillOutStructureCmd fillCmd = new FillOutStructureCmd(program, location, tool);
|
Address vbtableAddress = getVbtableAddressFromDecompiledFunction(fillStructHelper,
|
||||||
|
highFunction, recoveredClass, constructor, vbtableOffset);
|
||||||
Address vbtableAddress = getVbtableAddressFromDecompiledFunction(fillCmd, highFunction,
|
|
||||||
recoveredClass, constructor, vbtableOffset);
|
|
||||||
|
|
||||||
if (vbtableAddress != null) {
|
if (vbtableAddress != null) {
|
||||||
return vbtableAddress;
|
return vbtableAddress;
|
||||||
|
@ -1561,22 +1510,17 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator<Function> indeterminateIterator = indeterminateList.iterator();
|
for (Function constructor : indeterminateList) {
|
||||||
while (indeterminateIterator.hasNext()) {
|
|
||||||
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
Function constructor = indeterminateIterator.next();
|
|
||||||
|
|
||||||
HighFunction highFunction = decompilerUtils.getHighFunction(constructor);
|
HighFunction highFunction = decompilerUtils.getHighFunction(constructor);
|
||||||
|
|
||||||
if (highFunction == null) {
|
if (highFunction == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
FillOutStructureCmd fillCmd = new FillOutStructureCmd(program, location, tool);
|
Address vbtableAddress = getVbtableAddressFromDecompiledFunction(fillStructHelper,
|
||||||
|
highFunction, recoveredClass, constructor, vbtableOffset);
|
||||||
Address vbtableAddress = getVbtableAddressFromDecompiledFunction(fillCmd, highFunction,
|
|
||||||
recoveredClass, constructor, vbtableOffset);
|
|
||||||
|
|
||||||
if (vbtableAddress != null) {
|
if (vbtableAddress != null) {
|
||||||
return vbtableAddress;
|
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
|
* 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 highFunction the high function for the given function
|
||||||
* @param recoveredClass the given class
|
* @param recoveredClass the given class
|
||||||
* @param function the given function
|
* @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
|
* @return the address of the found vbtable or null if none is found
|
||||||
* @throws CancelledException if cancelled
|
* @throws CancelledException if cancelled
|
||||||
*/
|
*/
|
||||||
private Address getVbtableAddressFromDecompiledFunction(FillOutStructureCmd fillCmd,
|
private Address getVbtableAddressFromDecompiledFunction(FillOutStructureHelper fillStructHelper,
|
||||||
HighFunction highFunction, RecoveredClass recoveredClass, Function function, int offset)
|
HighFunction highFunction, RecoveredClass recoveredClass, Function function, int offset)
|
||||||
throws CancelledException {
|
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();
|
monitor.checkCancelled();
|
||||||
|
|
||||||
fillCmd.processStructure(highVariable, function);
|
fillStructHelper.processStructure(highVariable, function, true, false);
|
||||||
List<OffsetPcodeOpPair> stores = fillCmd.getStorePcodeOps();
|
List<OffsetPcodeOpPair> stores = fillStructHelper.getStorePcodeOps();
|
||||||
stores = removePcodeOpsNotInFunction(function, stores);
|
stores = removePcodeOpsNotInFunction(function, stores);
|
||||||
|
|
||||||
// this method checks the storedPcodeOps to see if one is a vftable address
|
for (OffsetPcodeOpPair offsetPcodeOpPair : stores) {
|
||||||
Iterator<OffsetPcodeOpPair> iterator = stores.iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
OffsetPcodeOpPair offsetPcodeOpPair = iterator.next();
|
|
||||||
int pcodeOffset = offsetPcodeOpPair.getOffset().intValue();
|
int pcodeOffset = offsetPcodeOpPair.getOffset().intValue();
|
||||||
if (pcodeOffset == offset) {
|
if (pcodeOffset == offset) {
|
||||||
|
|
||||||
|
@ -1664,11 +1603,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
private void assignParentClassToVftables(List<RecoveredClass> recoveredClasses)
|
private void assignParentClassToVftables(List<RecoveredClass> recoveredClasses)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
||||||
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
|
for (RecoveredClass recoveredClass : recoveredClasses) {
|
||||||
while (recoveredClassIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
RecoveredClass recoveredClass = recoveredClassIterator.next();
|
|
||||||
|
|
||||||
if (!recoveredClass.hasVftable()) {
|
if (!recoveredClass.hasVftable()) {
|
||||||
continue;
|
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
|
// iterate over the hierarchy list and use it to get the order of the parentsParents and assign
|
||||||
// to correct vftable
|
// to correct vftable
|
||||||
List<RecoveredClass> classHierarchy = recoveredClass.getClassHierarchy();
|
List<RecoveredClass> classHierarchy = recoveredClass.getClassHierarchy();
|
||||||
Iterator<RecoveredClass> classHierarchyIterator = classHierarchy.iterator();
|
for (RecoveredClass ancestor : classHierarchy) {
|
||||||
while (classHierarchyIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
RecoveredClass ancestor = classHierarchyIterator.next();
|
|
||||||
if (grandParents.contains(ancestor)) {
|
if (grandParents.contains(ancestor)) {
|
||||||
Integer index = sortedOrder.get(order);
|
Integer index = sortedOrder.get(order);
|
||||||
Address vftableAddress = orderToVftableMap.get(index);
|
Address vftableAddress = orderToVftableMap.get(index);
|
||||||
|
@ -1817,12 +1751,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
List<RecoveredClass> classHierarchy = recoveredClass.getClassHierarchy();
|
List<RecoveredClass> classHierarchy = recoveredClass.getClassHierarchy();
|
||||||
|
|
||||||
Iterator<RecoveredClass> hierarchyIterator = classHierarchy.iterator();
|
for (RecoveredClass ancestorClass : classHierarchy) {
|
||||||
|
|
||||||
while (hierarchyIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
RecoveredClass ancestorClass = hierarchyIterator.next();
|
|
||||||
|
|
||||||
RecoveredClass firstVirtuallyInheritedAncestorWithVfunctions =
|
RecoveredClass firstVirtuallyInheritedAncestorWithVfunctions =
|
||||||
getVirtuallyInheritedParentWithVfunctions(ancestorClass);
|
getVirtuallyInheritedParentWithVfunctions(ancestorClass);
|
||||||
if (firstVirtuallyInheritedAncestorWithVfunctions != null) {
|
if (firstVirtuallyInheritedAncestorWithVfunctions != null) {
|
||||||
|
@ -1857,11 +1787,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
Map<RecoveredClass, Boolean> parentToBaseTypeMap = recoveredClass.getParentToBaseTypeMap();
|
Map<RecoveredClass, Boolean> parentToBaseTypeMap = recoveredClass.getParentToBaseTypeMap();
|
||||||
|
|
||||||
List<RecoveredClass> parents = new ArrayList<RecoveredClass>(classHierarchyMap.keySet());
|
List<RecoveredClass> parents = new ArrayList<RecoveredClass>(classHierarchyMap.keySet());
|
||||||
Iterator<RecoveredClass> parentIterator = parents.iterator();
|
for (RecoveredClass parent : parents) {
|
||||||
|
|
||||||
while (parentIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
RecoveredClass parent = parentIterator.next();
|
|
||||||
Boolean isVirtuallyInherited = parentToBaseTypeMap.get(parent);
|
Boolean isVirtuallyInherited = parentToBaseTypeMap.get(parent);
|
||||||
|
|
||||||
if (isVirtuallyInherited != null && isVirtuallyInherited && parent.hasVftable()) {
|
if (isVirtuallyInherited != null && isVirtuallyInherited && parent.hasVftable()) {
|
||||||
|
@ -1898,10 +1825,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator<Integer> orderIterator = sortedOrder.iterator();
|
for (Integer order : sortedOrder) {
|
||||||
while (orderIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
Integer order = orderIterator.next();
|
|
||||||
Address vftableAddress = orderToVftableMap.get(order);
|
Address vftableAddress = orderToVftableMap.get(order);
|
||||||
RecoveredClass parentClass = parentOrderMap.get(order);
|
RecoveredClass parentClass = parentOrderMap.get(order);
|
||||||
recoveredClass.addVftableToBaseClassMapping(vftableAddress, parentClass);
|
recoveredClass.addVftableToBaseClassMapping(vftableAddress, parentClass);
|
||||||
|
@ -1970,13 +1895,10 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
return parentOrderMap;
|
return parentOrderMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator<Function> functionIterator = functionList.iterator();
|
for (Function function : functionList) {
|
||||||
while (functionIterator.hasNext()) {
|
|
||||||
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
|
|
||||||
Function function = functionIterator.next();
|
|
||||||
|
|
||||||
parentOrderMap = new HashMap<Integer, RecoveredClass>();
|
parentOrderMap = new HashMap<Integer, RecoveredClass>();
|
||||||
|
|
||||||
Map<Address, RecoveredClass> referenceToParentMap =
|
Map<Address, RecoveredClass> referenceToParentMap =
|
||||||
|
@ -1986,12 +1908,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
new HashMap<Address, RecoveredClass>();
|
new HashMap<Address, RecoveredClass>();
|
||||||
|
|
||||||
List<Address> classReferences = new ArrayList<Address>(referenceToParentMap.keySet());
|
List<Address> classReferences = new ArrayList<Address>(referenceToParentMap.keySet());
|
||||||
Iterator<Address> classReferenceIterator = classReferences.iterator();
|
for (Address classReferenceAddress : classReferences) {
|
||||||
while (classReferenceIterator.hasNext()) {
|
|
||||||
|
|
||||||
monitor.checkCancelled();
|
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
|
// 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);
|
Address possibleVftable = getVftableAddress(classReferenceAddress);
|
||||||
|
|
||||||
|
@ -2029,11 +1948,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
Collections.sort(parentReferences, Collections.reverseOrder());
|
Collections.sort(parentReferences, Collections.reverseOrder());
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate over the ordered parents and add to the order to parent map
|
// iterate over the ordered parents and add the order to the parent map
|
||||||
Iterator<Address> parentRefIterator = parentReferences.iterator();
|
for (Address refAddress : parentReferences) {
|
||||||
while (parentRefIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
Address refAddress = parentRefIterator.next();
|
|
||||||
RecoveredClass parentClass = referenceToParentMap.get(refAddress);
|
RecoveredClass parentClass = referenceToParentMap.get(refAddress);
|
||||||
parentOrderMap.put(order, parentClass);
|
parentOrderMap.put(order, parentClass);
|
||||||
order++;
|
order++;
|
||||||
|
@ -2074,11 +1991,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
List<RecoveredClass> updatedParentClasses = new ArrayList<RecoveredClass>(parentClasses);
|
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
|
// now iterate over the direct parents and map that parent to each ancestor on the ancestor with vfunction list
|
||||||
Iterator<RecoveredClass> parentIterator = parentClasses.iterator();
|
for (RecoveredClass parentClass : parentClasses) {
|
||||||
while (parentIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
|
|
||||||
RecoveredClass parentClass = parentIterator.next();
|
|
||||||
List<RecoveredClass> ancestors =
|
List<RecoveredClass> ancestors =
|
||||||
new ArrayList<RecoveredClass>(parentClass.getClassHierarchy());
|
new ArrayList<RecoveredClass>(parentClass.getClassHierarchy());
|
||||||
ancestors.remove(parentClass);
|
ancestors.remove(parentClass);
|
||||||
|
@ -2088,12 +2003,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator<RecoveredClass> ancestorIterator = ancestors.iterator();
|
for (RecoveredClass ancestor : ancestors) {
|
||||||
while (ancestorIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
|
|
||||||
RecoveredClass ancestor = ancestorIterator.next();
|
|
||||||
|
|
||||||
List<RecoveredClass> decendentList = ancestorToCommonChild.get(ancestor);
|
List<RecoveredClass> decendentList = ancestorToCommonChild.get(ancestor);
|
||||||
if (decendentList == null) {
|
if (decendentList == null) {
|
||||||
List<RecoveredClass> newDecendentList = new ArrayList<RecoveredClass>();
|
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
|
// 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
|
// that has common parents and removing those parents from the list
|
||||||
Iterator<RecoveredClass> ancestorsIterator = keySet.iterator();
|
for (RecoveredClass ancestor : keySet) {
|
||||||
while (ancestorsIterator.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
RecoveredClass ancestor = ancestorsIterator.next();
|
|
||||||
List<RecoveredClass> commonChildList = ancestorToCommonChild.get(ancestor);
|
List<RecoveredClass> commonChildList = ancestorToCommonChild.get(ancestor);
|
||||||
if (commonChildList != null && commonChildList.size() >= 2) {
|
if (commonChildList != null && commonChildList.size() >= 2) {
|
||||||
if (!updatedParentClasses.contains(ancestor)) {
|
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,
|
public synchronized DecompileResults decompileFunction(Function func, int timeoutSecs,
|
||||||
TaskMonitor monitor) {
|
TaskMonitor monitor) {
|
||||||
|
|
||||||
|
dtmanage.clearTemporaryIds();
|
||||||
decompileMessage = "";
|
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) {
|
if (monitor != null) {
|
||||||
monitor.addCancelledListener(monitorListener);
|
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;
|
Decoder decoder = null;
|
||||||
try {
|
try {
|
||||||
Address funcEntry = func.getEntryPoint();
|
Address funcEntry = func.getEntryPoint();
|
||||||
|
|
|
@ -17,18 +17,78 @@ package ghidra.app.decompiler.component;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import docking.options.OptionsService;
|
||||||
import docking.widgets.fieldpanel.field.Field;
|
import docking.widgets.fieldpanel.field.Field;
|
||||||
import docking.widgets.fieldpanel.support.*;
|
import docking.widgets.fieldpanel.support.*;
|
||||||
import ghidra.app.decompiler.*;
|
import ghidra.app.decompiler.*;
|
||||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
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.address.*;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.data.MetaDataType;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.pcode.*;
|
import ghidra.program.model.pcode.*;
|
||||||
|
|
||||||
public class DecompilerUtils {
|
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
|
* If the token refers to an individual Varnode, return it. Otherwise return null
|
||||||
*
|
*
|
||||||
|
@ -214,6 +274,25 @@ public class DecompilerUtils {
|
||||||
return pcodeops;
|
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
|
* Returns the function represented by the given token. This will be either the
|
||||||
* decompiled function or a function referenced within the decompiled function.
|
* 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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.decompile.actions;
|
package ghidra.app.decompiler.util;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import docking.options.OptionsService;
|
|
||||||
import ghidra.app.cmd.label.RenameLabelCmd;
|
import ghidra.app.cmd.label.RenameLabelCmd;
|
||||||
import ghidra.app.decompiler.*;
|
import ghidra.app.decompiler.*;
|
||||||
import ghidra.framework.cmd.BackgroundCommand;
|
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||||
import ghidra.framework.model.DomainObject;
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
import ghidra.framework.options.ToolOptions;
|
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressSet;
|
import ghidra.program.model.address.AddressSet;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
|
@ -32,9 +29,9 @@ import ghidra.program.model.lang.PrototypeModel;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.pcode.*;
|
import ghidra.program.model.pcode.*;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.util.*;
|
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.*;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
import ghidra.util.exception.InvalidInputException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,11 +41,7 @@ import ghidra.util.task.TaskMonitor;
|
||||||
* to the structure, even if the structure must grow.
|
* to the structure, even if the structure must grow.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class FillOutStructureCmd extends BackgroundCommand {
|
public class FillOutStructureHelper {
|
||||||
|
|
||||||
// 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.
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Varnode with data-flow traceable to original pointer
|
* 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_BASENAME = "astruct";
|
||||||
private static final String DEFAULT_CATEGORY = "/auto_structs";
|
private static final String DEFAULT_CATEGORY = "/auto_structs";
|
||||||
|
|
||||||
private int currentCallDepth = 0; // Current call depth (from root function)
|
private Program currentProgram;
|
||||||
private int maxCallDepth = 1;
|
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 NoisyStructureBuilder componentMap = new NoisyStructureBuilder();
|
||||||
private HashMap<Address, Address> addressToCallInputMap = new HashMap<>();
|
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> storePcodeOps = new ArrayList<>();
|
||||||
private List<OffsetPcodeOpPair> loadPcodeOps = new ArrayList<>();
|
private List<OffsetPcodeOpPair> loadPcodeOps = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -85,92 +75,15 @@ public class FillOutStructureCmd extends BackgroundCommand {
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param program the current program
|
* @param program the current program
|
||||||
* @param location the current program location
|
* @param decompileOptions decompiler options
|
||||||
* @param tool the current plugin tool
|
* (see {@link DecompilerUtils#getDecompileOptions(ServiceProvider, Program)})
|
||||||
|
* @param monitor task monitor
|
||||||
*/
|
*/
|
||||||
public FillOutStructureCmd(Program program, ProgramLocation location, PluginTool tool) {
|
public FillOutStructureHelper(Program program, DecompileOptions decompileOptions,
|
||||||
super("Fill Out Structure", true, false, true);
|
TaskMonitor monitor) {
|
||||||
this.tool = tool;
|
|
||||||
this.currentProgram = program;
|
this.currentProgram = program;
|
||||||
this.currentLocation = Objects.requireNonNull(location);
|
this.decompileOptions = decompileOptions;
|
||||||
}
|
this.monitor = monitor;
|
||||||
|
|
||||||
@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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -179,31 +92,82 @@ public class FillOutStructureCmd extends BackgroundCommand {
|
||||||
* or any existing data-types. A new structure is always created.
|
* 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 var a parameter, local variable, or global variable used in the given function
|
||||||
* @param function the function to process
|
* @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
|
* @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) {
|
if (var == null || var.getSymbol() == null || var.getOffset() >= 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Structure structDT;
|
init();
|
||||||
|
|
||||||
try {
|
Structure structDT = null;
|
||||||
fillOutStructureDef(var);
|
|
||||||
pushIntoCalls();
|
if (!createNewStructure) {
|
||||||
structDT = createStructure(null, var, function, false);
|
structDT = getStructureForExtending(var.getDataType());
|
||||||
populateStructure(structDT);
|
if (structDT != null) {
|
||||||
|
componentMap.populateOriginalStructure(structDT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
|
||||||
|
fillOutStructureDef(var);
|
||||||
|
pushIntoCalls();
|
||||||
|
|
||||||
|
long size = componentMap.getSize();
|
||||||
|
if (size == 0) {
|
||||||
return null;
|
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;
|
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
|
* @return componentMap
|
||||||
*/
|
*/
|
||||||
public NoisyStructureBuilder getComponentMap() {
|
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
|
* 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
|
* @return the pcodeOps doing the storing to the associated variable
|
||||||
*/
|
*/
|
||||||
public List<OffsetPcodeOpPair> getStorePcodeOps() {
|
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
|
* 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
|
* @return the pcodeOps doing the loading from the associated variable
|
||||||
*/
|
*/
|
||||||
public List<OffsetPcodeOpPair> getLoadPcodeOps() {
|
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
|
* Decompile a function and return the resulting HighVariable associated with a storage address
|
||||||
* @param storageAddress the storage address of the variable
|
* @param storageAddress the storage address of the variable
|
||||||
* @param function is the function
|
* @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) {
|
if (storageAddress == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -360,7 +280,12 @@ public class FillOutStructureCmd extends BackgroundCommand {
|
||||||
return null;
|
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();
|
HighFunction highFunc = results.getHighFunction();
|
||||||
|
|
||||||
// no decompile...
|
// no decompile...
|
||||||
|
@ -407,57 +332,13 @@ public class FillOutStructureCmd extends BackgroundCommand {
|
||||||
*/
|
*/
|
||||||
private DecompInterface setUpDecompiler() {
|
private DecompInterface setUpDecompiler() {
|
||||||
DecompInterface decomplib = new DecompInterface();
|
DecompInterface decomplib = new DecompInterface();
|
||||||
|
decomplib.setOptions(decompileOptions);
|
||||||
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.toggleCCode(true);
|
decomplib.toggleCCode(true);
|
||||||
decomplib.toggleSyntaxTree(true);
|
decomplib.toggleSyntaxTree(true);
|
||||||
decomplib.setSimplificationStyle("decompile");
|
decomplib.setSimplificationStyle("decompile");
|
||||||
|
|
||||||
return decomplib;
|
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
|
* Populate the given structure with any new discovered components in the
|
||||||
* offsetToDataTypeMap.
|
* 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,
|
* Create a new structure of a given size and unique generated name within the DEFAULT_CATEGORY.
|
||||||
* make sure there is a the structure is associated with the class namespace.
|
*
|
||||||
* @param var is the associated variable
|
|
||||||
* @param size is the desired structure size
|
* @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
|
* @return the new Structure
|
||||||
*/
|
*/
|
||||||
private Structure createNewStruct(HighVariable var, int size, Function f, boolean isThisParam) {
|
private Structure createUniqueStructure(int size) {
|
||||||
if (isThisParam) {
|
ProgramBasedDataTypeManager dtm = currentProgram.getDataTypeManager();
|
||||||
Namespace rootNamespace = currentProgram.getGlobalNamespace();
|
String structName = dtm.getUniqueName(new CategoryPath(DEFAULT_CATEGORY), DEFAULT_BASENAME);
|
||||||
Namespace newNamespace = createUniqueClassName(rootNamespace);
|
StructureDataType dt =
|
||||||
String name = f.getName();
|
new StructureDataType(new CategoryPath(DEFAULT_CATEGORY), structName, size, dtm);
|
||||||
Symbol symbol = f.getSymbol();
|
|
||||||
RenameLabelCmd command =
|
|
||||||
new RenameLabelCmd(symbol, name, newNamespace, SourceType.USER_DEFINED);
|
|
||||||
if (!command.applyTo(currentProgram)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Structure structDT = VariableUtilities.findOrCreateClassStruct(f);
|
|
||||||
if (structDT == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// FIXME: How should an existing packed structure be handled? Growing and offset-based placement does not apply
|
|
||||||
int len = structDT.isZeroLength() ? 0 : structDT.getLength();
|
|
||||||
if (len < size) {
|
|
||||||
structDT.growStructure(size - len);
|
|
||||||
}
|
|
||||||
return structDT;
|
|
||||||
}
|
|
||||||
String structName = createUniqueStructName(var, DEFAULT_CATEGORY, DEFAULT_BASENAME);
|
|
||||||
|
|
||||||
StructureDataType dt = new StructureDataType(new CategoryPath(DEFAULT_CATEGORY), structName,
|
|
||||||
size, f.getProgram().getDataTypeManager());
|
|
||||||
return dt;
|
return dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Namespace createUniqueClassName(Namespace rootNamespace) {
|
/**
|
||||||
|
* Create new unique Ghidra Class namespace and corresponding structure.
|
||||||
|
* @param var {@code "this"} pointer variable
|
||||||
|
* @param size structure size
|
||||||
|
* @param f Ghidra Class member function
|
||||||
|
* @return new Ghidra Class structure or null on error
|
||||||
|
*/
|
||||||
|
private Structure createUniqueClassNamespaceAndStructure(HighVariable var, int size,
|
||||||
|
Function f) {
|
||||||
|
Namespace newNamespace = createUniqueClassName();
|
||||||
|
if (newNamespace == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move function into new Ghidra Class namespace
|
||||||
|
RenameLabelCmd command =
|
||||||
|
new RenameLabelCmd(f.getSymbol(), f.getName(), newNamespace, SourceType.USER_DEFINED);
|
||||||
|
if (!command.applyTo(currentProgram)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate new Ghidra Class structure
|
||||||
|
Structure structDT = VariableUtilities.findOrCreateClassStruct(f);
|
||||||
|
if (structDT == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
expandStructureSizeIfNeeded(structDT, size);
|
||||||
|
|
||||||
|
return structDT;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean programContainsNamedStructure(String structName) {
|
||||||
|
ProgramBasedDataTypeManager dtm = currentProgram.getDataTypeManager();
|
||||||
|
List<DataType> list = new ArrayList<>();
|
||||||
|
dtm.findDataTypes(structName, list, true, monitor);
|
||||||
|
for (DataType dt : list) {
|
||||||
|
if (dt instanceof Structure) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a unique Ghidra Class which does not have an existing structure
|
||||||
|
* @return new unique Ghidra Class namespace or null on error
|
||||||
|
*/
|
||||||
|
private Namespace createUniqueClassName() {
|
||||||
|
Namespace rootNamespace = currentProgram.getGlobalNamespace();
|
||||||
SymbolTable symbolTable = currentProgram.getSymbolTable();
|
SymbolTable symbolTable = currentProgram.getSymbolTable();
|
||||||
String newClassBase = "AutoClass";
|
String newClassBase = "AutoClass";
|
||||||
String newClassName = "";
|
String newClassName;
|
||||||
for (int i = 1; i < 1000; ++i) {
|
int index = 1;
|
||||||
newClassName = newClassBase + Integer.toString(i);
|
while (true) {
|
||||||
if (symbolTable.getSymbols(newClassName, rootNamespace).isEmpty()) {
|
// cycle until we find unused class/structure name
|
||||||
|
newClassName = newClassBase + Integer.toString(index++);
|
||||||
|
if (symbolTable.getNamespace(newClassName, rootNamespace) == null &&
|
||||||
|
!programContainsNamedStructure(newClassName)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Create the class
|
// Create the class
|
||||||
GhidraClass newClass = null;
|
|
||||||
try {
|
try {
|
||||||
newClass =
|
return symbolTable.createClass(rootNamespace, newClassName, SourceType.USER_DEFINED);
|
||||||
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);
|
Msg.error(this, "Error creating class '" + newClassName + "'", e);
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
return null;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean sanityCheck(long offset, long existingSize) {
|
private boolean sanityCheck(long offset, long existingSize) {
|
||||||
|
@ -577,38 +478,6 @@ public class FillOutStructureCmd extends BackgroundCommand {
|
||||||
return true;
|
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
|
* 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
|
* 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);
|
componentMap.setMinimumSize(currentRef.offset);
|
||||||
break;
|
break;
|
||||||
case PcodeOp.LOAD:
|
case PcodeOp.LOAD:
|
||||||
outDt = getDataTypeTraceForward(output);
|
outDt = DecompilerUtils.getDataTypeTraceForward(output);
|
||||||
componentMap.addDataType(currentRef.offset, outDt);
|
componentMap.addDataType(currentRef.offset, outDt);
|
||||||
|
|
||||||
if (outDt != null) {
|
if (outDt != null) {
|
||||||
|
@ -706,7 +575,7 @@ public class FillOutStructureCmd extends BackgroundCommand {
|
||||||
if (pcodeOp.getSlot(currentRef.varnode) != 1) {
|
if (pcodeOp.getSlot(currentRef.varnode) != 1) {
|
||||||
break; // store must be into the target structure
|
break; // store must be into the target structure
|
||||||
}
|
}
|
||||||
outDt = getDataTypeTraceBackward(inputs[2]);
|
outDt = DecompilerUtils.getDataTypeTraceBackward(inputs[2]);
|
||||||
componentMap.addDataType(currentRef.offset, outDt);
|
componentMap.addDataType(currentRef.offset, outDt);
|
||||||
|
|
||||||
if (outDt != null) {
|
if (outDt != null) {
|
||||||
|
@ -735,12 +604,12 @@ public class FillOutStructureCmd extends BackgroundCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
outDt = getDataTypeTraceBackward(currentRef.varnode);
|
outDt = DecompilerUtils.getDataTypeTraceBackward(currentRef.varnode);
|
||||||
componentMap.addReference(currentRef.offset, outDt);
|
componentMap.addReference(currentRef.offset, outDt);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PcodeOp.CALLIND:
|
case PcodeOp.CALLIND:
|
||||||
outDt = getDataTypeTraceBackward(currentRef.varnode);
|
outDt = DecompilerUtils.getDataTypeTraceBackward(currentRef.varnode);
|
||||||
componentMap.addReference(currentRef.offset, outDt);
|
componentMap.addReference(currentRef.offset, outDt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -775,6 +644,34 @@ public class FillOutStructureCmd extends BackgroundCommand {
|
||||||
doneList.add(output);
|
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
|
* 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.ActionContext;
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
import ghidra.app.context.ListingActionContext;
|
import ghidra.app.context.ListingActionContext;
|
||||||
|
import ghidra.app.decompiler.DecompileOptions;
|
||||||
import ghidra.app.decompiler.component.DecompilerController;
|
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.plugin.core.decompile.DecompilerActionContext;
|
||||||
import ghidra.app.util.HelpTopics;
|
import ghidra.app.util.HelpTopics;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.pcode.HighParam;
|
|
||||||
import ghidra.program.model.pcode.HighVariable;
|
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.Msg;
|
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));
|
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
|
@Override
|
||||||
public abstract boolean isEnabledForContext(ActionContext context);
|
public abstract boolean isEnabledForContext(ActionContext context);
|
||||||
|
|
||||||
|
@ -98,7 +60,7 @@ public abstract class CreateStructureVariableAction extends DockingAction {
|
||||||
*/
|
*/
|
||||||
protected void adjustCreateStructureMenuText(DataType dt, boolean isThisParam) {
|
protected void adjustCreateStructureMenuText(DataType dt, boolean isThisParam) {
|
||||||
|
|
||||||
dt = getStructureForExtending(dt);
|
dt = FillOutStructureHelper.getStructureForExtending(dt);
|
||||||
String menuString = "Auto Create Structure";
|
String menuString = "Auto Create Structure";
|
||||||
if (dt != null) {
|
if (dt != null) {
|
||||||
if (isThisParam) {
|
if (isThisParam) {
|
||||||
|
@ -145,7 +107,8 @@ public abstract class CreateStructureVariableAction extends DockingAction {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FillOutStructureCmd task = new FillOutStructureCmd(program, location, tool);
|
DecompileOptions decompileOptions = DecompilerUtils.getDecompileOptions(tool, program);
|
||||||
task.applyTo(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 docking.ActionContext;
|
||||||
import ghidra.app.decompiler.ClangToken;
|
import ghidra.app.decompiler.ClangToken;
|
||||||
import ghidra.app.decompiler.component.DecompilerController;
|
import ghidra.app.decompiler.component.*;
|
||||||
import ghidra.app.decompiler.component.DecompilerPanel;
|
|
||||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
|
@ -62,7 +61,7 @@ public class DecompilerStructureVariableAction extends CreateStructureVariableAc
|
||||||
HighVariable var = tokenAtCursor.getHighVariable();
|
HighVariable var = tokenAtCursor.getHighVariable();
|
||||||
if (var != null && !(var instanceof HighConstant)) {
|
if (var != null && !(var instanceof HighConstant)) {
|
||||||
dt = var.getDataType();
|
dt = var.getDataType();
|
||||||
isThisParam = testForAutoParameterThis(var, function);
|
isThisParam = DecompilerUtils.testForAutoParameterThis(var, function);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dt == null || dt.getLength() > maxPointerSize) {
|
if (dt == null || dt.getLength() > maxPointerSize) {
|
||||||
|
|
|
@ -20,18 +20,16 @@ import java.util.*;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import docking.options.OptionsService;
|
|
||||||
import generic.cache.CachingPool;
|
import generic.cache.CachingPool;
|
||||||
import generic.cache.CountingBasicFactory;
|
import generic.cache.CountingBasicFactory;
|
||||||
import generic.concurrent.QCallback;
|
import generic.concurrent.QCallback;
|
||||||
import ghidra.GhidraOptions;
|
|
||||||
import ghidra.app.decompiler.*;
|
import ghidra.app.decompiler.*;
|
||||||
import ghidra.app.decompiler.DecompileOptions.CommentStyleEnum;
|
import ghidra.app.decompiler.DecompileOptions.CommentStyleEnum;
|
||||||
|
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||||
import ghidra.app.decompiler.parallel.ChunkingParallelDecompiler;
|
import ghidra.app.decompiler.parallel.ChunkingParallelDecompiler;
|
||||||
import ghidra.app.decompiler.parallel.ParallelDecompiler;
|
import ghidra.app.decompiler.parallel.ParallelDecompiler;
|
||||||
import ghidra.app.util.*;
|
import ghidra.app.util.*;
|
||||||
import ghidra.framework.model.DomainObject;
|
import ghidra.framework.model.DomainObject;
|
||||||
import ghidra.framework.options.ToolOptions;
|
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressSetView;
|
import ghidra.program.model.address.AddressSetView;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
|
@ -245,20 +243,8 @@ public class CppExporter extends Exporter {
|
||||||
|
|
||||||
private void configureOptions(Program program) {
|
private void configureOptions(Program program) {
|
||||||
if (!userSuppliedOptions) {
|
if (!userSuppliedOptions) {
|
||||||
options = new DecompileOptions();
|
|
||||||
|
|
||||||
if (provider != null) {
|
options = DecompilerUtils.getDecompileOptions(provider, program);
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isUseCppStyleComments) {
|
if (isUseCppStyleComments) {
|
||||||
options.setCommentStyle(CommentStyleEnum.CPPStyle);
|
options.setCommentStyle(CommentStyleEnum.CPPStyle);
|
||||||
|
|
|
@ -27,7 +27,6 @@ import ghidra.app.util.pdb.pdbapplicator.DefaultPdbApplicator;
|
||||||
import ghidra.app.util.pdb.pdbapplicator.PdbApplicatorOptions;
|
import ghidra.app.util.pdb.pdbapplicator.PdbApplicatorOptions;
|
||||||
import ghidra.framework.*;
|
import ghidra.framework.*;
|
||||||
import ghidra.framework.cmd.BackgroundCommand;
|
import ghidra.framework.cmd.BackgroundCommand;
|
||||||
import ghidra.framework.model.DomainObject;
|
|
||||||
import ghidra.framework.options.OptionType;
|
import ghidra.framework.options.OptionType;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.program.model.address.AddressSetView;
|
import ghidra.program.model.address.AddressSetView;
|
||||||
|
@ -192,9 +191,8 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||||
* @throws CancelledException upon user cancellation
|
* @throws CancelledException upon user cancellation
|
||||||
*/
|
*/
|
||||||
public static boolean doAnalysis(Program program, File pdbFile,
|
public static boolean doAnalysis(Program program, File pdbFile,
|
||||||
PdbReaderOptions pdbReaderOptions,
|
PdbReaderOptions pdbReaderOptions, PdbApplicatorOptions pdbApplicatorOptions,
|
||||||
PdbApplicatorOptions pdbApplicatorOptions, MessageLog log, TaskMonitor monitor)
|
MessageLog log, TaskMonitor monitor) throws CancelledException {
|
||||||
throws CancelledException {
|
|
||||||
PdbLog.message(
|
PdbLog.message(
|
||||||
"================================================================================");
|
"================================================================================");
|
||||||
PdbLog.message(new Date(System.currentTimeMillis()).toString() + "\n");
|
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());
|
AnalysisPriority.DATA_TYPE_PROPOGATION.after().after().after().priority());
|
||||||
|
|
||||||
// Following is intended to be the last PDB analysis background command
|
// Following is intended to be the last PDB analysis background command
|
||||||
aam.schedule(
|
aam.schedule(new PdbReportingBackgroundCommand(),
|
||||||
new PdbReportingBackgroundCommand(),
|
|
||||||
AnalysisPriority.DATA_TYPE_PROPOGATION.after().after().after().after().priority());
|
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
|
* local variables and other things that might make sense to process in the first phase
|
||||||
* (for now, they will be in the second 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;
|
File pdbFile;
|
||||||
private PdbReaderOptions pdbReaderOptions;
|
private PdbReaderOptions pdbReaderOptions;
|
||||||
|
@ -357,14 +354,13 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
|
public boolean applyTo(Program program, TaskMonitor monitor) {
|
||||||
Program program = (Program) obj;
|
|
||||||
try (AbstractPdb pdb = PdbParser.parse(pdbFile, pdbReaderOptions, monitor)) {
|
try (AbstractPdb pdb = PdbParser.parse(pdbFile, pdbReaderOptions, monitor)) {
|
||||||
monitor.setMessage("PDB: Parsing " + pdbFile + "...");
|
monitor.setMessage("PDB: Parsing " + pdbFile + "...");
|
||||||
pdb.deserialize();
|
pdb.deserialize();
|
||||||
DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdb, program,
|
DefaultPdbApplicator applicator =
|
||||||
program.getDataTypeManager(), program.getImageBase(), pdbApplicatorOptions,
|
new DefaultPdbApplicator(pdb, program, program.getDataTypeManager(),
|
||||||
log);
|
program.getImageBase(), pdbApplicatorOptions, log);
|
||||||
applicator.applyFunctionInternalsAnalysis();
|
applicator.applyFunctionInternalsAnalysis();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -382,15 +378,14 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||||
/**
|
/**
|
||||||
* A background command that performs final PDB analysis reporting.
|
* A background command that performs final PDB analysis reporting.
|
||||||
*/
|
*/
|
||||||
private static class PdbReportingBackgroundCommand extends BackgroundCommand {
|
private static class PdbReportingBackgroundCommand extends BackgroundCommand<Program> {
|
||||||
|
|
||||||
public PdbReportingBackgroundCommand() {
|
public PdbReportingBackgroundCommand() {
|
||||||
super("PDB Universal Reporting", false, false, false);
|
super("PDB Universal Reporting", false, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
|
public boolean applyTo(Program program, TaskMonitor monitor) {
|
||||||
Program program = (Program) obj;
|
|
||||||
try {
|
try {
|
||||||
DefaultPdbApplicator.applyAnalysisReporting(program);
|
DefaultPdbApplicator.applyAnalysisReporting(program);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -16,11 +16,15 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.diff;
|
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.events.ProgramSelectionPluginEvent;
|
||||||
import ghidra.app.plugin.core.analysis.AnalysisWorker;
|
import ghidra.app.plugin.core.analysis.AnalysisWorker;
|
||||||
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
|
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
|
||||||
import ghidra.framework.cmd.BackgroundCommand;
|
import ghidra.framework.cmd.BackgroundCommand;
|
||||||
import ghidra.framework.model.DomainObject;
|
|
||||||
import ghidra.program.model.address.AddressSetView;
|
import ghidra.program.model.address.AddressSetView;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
|
@ -28,17 +32,11 @@ import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
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.
|
* Command to apply diffs to current program.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
|
class ApplyDiffCommand extends BackgroundCommand<Program> implements AnalysisWorker {
|
||||||
|
|
||||||
private AddressSetView p1AddressSet;
|
private AddressSetView p1AddressSet;
|
||||||
private DiffController diffControl;
|
private DiffController diffControl;
|
||||||
|
@ -47,9 +45,6 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
|
||||||
private boolean applied;
|
private boolean applied;
|
||||||
private ProgramDiffPlugin plugin;
|
private ProgramDiffPlugin plugin;
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
*/
|
|
||||||
ApplyDiffCommand(ProgramDiffPlugin plugin, AddressSetView program1AddressSet,
|
ApplyDiffCommand(ProgramDiffPlugin plugin, AddressSetView program1AddressSet,
|
||||||
DiffController diffControl) {
|
DiffController diffControl) {
|
||||||
super("Apply Differences", false, true, true);
|
super("Apply Differences", false, true, true);
|
||||||
|
@ -59,8 +54,8 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean analysisWorkerCallback(Program program, Object workerContext, TaskMonitor monitor)
|
public boolean analysisWorkerCallback(Program program, Object workerContext,
|
||||||
throws Exception, CancelledException {
|
TaskMonitor monitor) throws Exception, CancelledException {
|
||||||
// Diff apply done with analysis disabled
|
// Diff apply done with analysis disabled
|
||||||
return diffControl.apply(p1AddressSet, monitor);
|
return diffControl.apply(p1AddressSet, monitor);
|
||||||
}
|
}
|
||||||
|
@ -70,11 +65,8 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
|
||||||
return getName();
|
return getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.framework.cmd.BackgroundCommand#applyTo(ghidra.framework.model.DomainObject, ghidra.util.task.TaskMonitor)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
|
public boolean applyTo(Program program, TaskMonitor monitor) {
|
||||||
monitor.setMessage("ApplyDiffTask starting...");
|
monitor.setMessage("ApplyDiffTask starting...");
|
||||||
applied = false;
|
applied = false;
|
||||||
final ProgramLocation origLocation = plugin.getProgramLocation();
|
final ProgramLocation origLocation = plugin.getProgramLocation();
|
||||||
|
@ -90,9 +82,8 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
|
||||||
AutoAnalysisManager.getAnalysisManager(plugin.getFirstProgram());
|
AutoAnalysisManager.getAnalysisManager(plugin.getFirstProgram());
|
||||||
boolean merged = autoAnalysisManager.scheduleWorker(this, null, false, monitor);
|
boolean merged = autoAnalysisManager.scheduleWorker(this, null, false, monitor);
|
||||||
if (merged) {
|
if (merged) {
|
||||||
statusMsg =
|
statusMsg = "Apply differences has finished." +
|
||||||
"Apply differences has finished."
|
" If your expected change didn't occur, check your Diff Apply Settings.";
|
||||||
+ " If your expected change didn't occur, check your Diff Apply Settings.";
|
|
||||||
title = "Program Diff: Apply differences has finished.";
|
title = "Program Diff: Apply differences has finished.";
|
||||||
applied = true;
|
applied = true;
|
||||||
}
|
}
|
||||||
|
@ -114,15 +105,14 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Msg.showError(this, plugin.getListingPanel(), "Error Applying Diff",
|
Msg.showError(this, plugin.getListingPanel(), "Error Applying Diff",
|
||||||
"An error occurred while applying differences.\n"
|
"An error occurred while applying differences.\n" +
|
||||||
+ "Only some of the differences may have been applied.",
|
"Only some of the differences may have been applied.",
|
||||||
(t != null) ? t : e);
|
(t != null) ? t : e);
|
||||||
applyMsg = message + diffControl.getApplyMessage();
|
applyMsg = message + diffControl.getApplyMessage();
|
||||||
}
|
}
|
||||||
catch (CancelledException e) {
|
catch (CancelledException e) {
|
||||||
statusMsg =
|
statusMsg = "User cancelled \"Apply Differences\". " +
|
||||||
"User cancelled \"Apply Differences\". "
|
"Differences were only partially applied.";
|
||||||
+ "Differences were only partially applied.";
|
|
||||||
applyMsg = diffControl.getApplyMessage();
|
applyMsg = diffControl.getApplyMessage();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue