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

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

View file

@ -108,7 +108,7 @@ public class AutoAnalysisManager {
//private Integer currentTaskPriority = null; //private 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()) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -13,18 +13,15 @@
* See the License for the specific language governing permissions and * 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
*/ */

View file

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

View file

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

View file

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

View file

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

View file

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