GP-4408 Refactor of FillOutStructureCmd. Added FillOutStructureHelper and additional DecompilerUtils methods.

This commit is contained in:
ghidra1
2024-04-03 09:53:53 -04:00
parent 434c3f315d
commit 624a3c4e9e
25 changed files with 1281 additions and 1810 deletions
@@ -108,7 +108,7 @@ public class AutoAnalysisManager {
//private Integer currentTaskPriority = null;
//private Stack<Integer> taskPriorityStack = new Stack<Integer>();
private PriorityQueue<BackgroundCommand> queue = new PriorityQueue<>();
private PriorityQueue<BackgroundCommand<Program>> queue = new PriorityQueue<>();
private Map<String, Long> timedTasks = new HashMap<>();
// used for testing and performance monitoring; accessed via reflection
private Map<String, Long> cumulativeTasks = new HashMap<>();
@@ -231,7 +231,7 @@ public class AutoAnalysisManager {
Options options = program.getOptions(Program.ANALYSIS_PROPERTIES);
analyzer.optionsChanged(options.getOptions(analyzer.getName()), getProgram());
BackgroundCommand cmd = new OneShotAnalysisCommand(analyzer, set, log);
OneShotAnalysisCommand cmd = new OneShotAnalysisCommand(analyzer, set, log);
schedule(cmd, analyzer.getPriority().priority());
}
@@ -643,13 +643,13 @@ public class AutoAnalysisManager {
private class AnalysisTaskWrapper {
private final BackgroundCommand task;
private final BackgroundCommand<Program> task;
Integer taskPriority;
private long timeAccumulator;
private long startTime;
AnalysisTaskWrapper(BackgroundCommand task, int taskPriority) {
AnalysisTaskWrapper(BackgroundCommand<Program> task, int taskPriority) {
this.task = task;
this.taskPriority = taskPriority;
}
@@ -845,7 +845,7 @@ public class AutoAnalysisManager {
*/
public synchronized void cancelQueuedTasks() {
while (!queue.isEmpty()) {
BackgroundCommand cmd = queue.getFirst();
BackgroundCommand<Program> cmd = queue.getFirst();
if (cmd instanceof AnalysisWorkerCommand) {
AnalysisWorkerCommand workerCmd = (AnalysisWorkerCommand) cmd;
if (!workerCmd.canCancel()) {
@@ -857,7 +857,7 @@ public class AutoAnalysisManager {
}
}
synchronized boolean schedule(BackgroundCommand cmd, int priority) {
synchronized boolean schedule(BackgroundCommand<Program> cmd, int priority) {
if (cmd == null) {
throw new IllegalArgumentException("Can't schedule a null command");
@@ -1583,7 +1583,8 @@ public class AutoAnalysisManager {
* In a Headed environment a modal task dialog will be used to block user input if the
* worker was scheduled with analyzeChanges==false
*/
private class AnalysisWorkerCommand extends BackgroundCommand implements CancelledListener {
private class AnalysisWorkerCommand extends BackgroundCommand<Program>
implements CancelledListener {
private AnalysisWorker worker;
private Object workerContext;
@@ -1651,7 +1652,7 @@ public class AutoAnalysisManager {
}
@Override
public boolean applyTo(DomainObject obj, TaskMonitor analysisMonitor) {
public boolean applyTo(Program p, TaskMonitor analysisMonitor) {
synchronized (this) {
workerMonitor.removeCancelledListener(this);
@@ -1660,7 +1661,7 @@ public class AutoAnalysisManager {
return false;
}
assert (obj == program);
assert (p == program);
if (analysisMonitor != workerMonitor) {
if (!workerMonitor.isCancelEnabled()) {
@@ -148,11 +148,11 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
return currentProgram != null;
}
};
findTableAction.setHelpLocation(
new HelpLocation(HelpTopics.SEARCH, findTableAction.getName()));
findTableAction.setMenuBarData(new MenuData(
new String[] { ToolConstants.MENU_SEARCH, "For Address Tables" }, null, "search for",
-1, "AddressTables"));
findTableAction
.setHelpLocation(new HelpLocation(HelpTopics.SEARCH, findTableAction.getName()));
findTableAction.setMenuBarData(
new MenuData(new String[] { ToolConstants.MENU_SEARCH, "For Address Tables" }, null,
"search for", -1, "AddressTables"));
findTableAction.setDescription(getPluginDescription().getDescription());
findTableAction.addToWindowWhen(NavigatableActionContext.class);
tool.addAction(findTableAction);
@@ -168,15 +168,15 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
int minimumTableSize = addressTableDialog.getMinTableSize();
if (minimumTableSize < 2) {
addressTableDialog.setDialogText(
"Please enter a valid minimum search length. Must be >= 2");
addressTableDialog
.setDialogText("Please enter a valid minimum search length. Must be >= 2");
return;
}
int alignment = addressTableDialog.getAlignment();
if (alignment <= 0 || alignment > 8) {
addressTableDialog.setDialogText(
"Please enter a valid alignment value. Must be > 0 and <= 8");
addressTableDialog
.setDialogText("Please enter a valid alignment value. Must be > 0 and <= 8");
return;
}
@@ -217,8 +217,8 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
selectedAddresses[i] = model.getAddress(selectedRows[i]);
}
CompoundBackgroundCommand backCmd =
new CompoundBackgroundCommand("Disassemble Address Tables", false, true);
CompoundBackgroundCommand<Program> backCmd =
new CompoundBackgroundCommand<>("Disassemble Address Tables", false, true);
offsetLen = addressTableDialog.getOffset();
// loop over selected table addresses
@@ -237,7 +237,7 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
tool.executeBackgroundCommand(backCmd, currentProgram);
}
private void createDisassemblyCommandsForAddress(CompoundBackgroundCommand backCmd,
private void createDisassemblyCommandsForAddress(CompoundBackgroundCommand<Program> backCmd,
Address currentAddress) {
Listing listing = currentProgram.getListing();
@@ -261,8 +261,8 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
// need to create a context for each one. Also disassembleCmd will align the address to disassemble
DisassembleCommand disassembleCmd = new DisassembleCommand(addr, null, true);
RegisterValue rval = PseudoDisassembler.getTargetContextRegisterValueForDisassembly(
currentProgram, addr);
RegisterValue rval = PseudoDisassembler
.getTargetContextRegisterValueForDisassembly(currentProgram, addr);
disassembleCmd.setInitialContext(rval);
backCmd.add(disassembleCmd);
}
@@ -29,7 +29,6 @@ import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.util.bean.SetEquateDialog;
import ghidra.app.util.bean.SetEquateDialog.SelectionType;
import ghidra.app.util.datatype.ApplyEnumDialog;
import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.cmd.CompoundBackgroundCommand;
import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.PluginStatus;
@@ -182,7 +181,7 @@ public class EquatePlugin extends Plugin {
iter = listing.getCodeUnits(context.getProgram().getMemory(), true);
}
BackgroundCommand cmd = new CreateEquateCmd(scalar, iter, dialog.getEquateName(),
CreateEquateCmd cmd = new CreateEquateCmd(scalar, iter, dialog.getEquateName(),
dialog.getOverwriteExisting(), context);
tool.executeBackgroundCommand(cmd, context.getProgram());
@@ -297,8 +296,8 @@ public class EquatePlugin extends Plugin {
// Set up a background task that we'll populate with all the rename tasks we need
// to perform.
CompoundBackgroundCommand bckCmd =
new CompoundBackgroundCommand("Rename Equates in Selection", false, true);
CompoundBackgroundCommand<Program> bckCmd =
new CompoundBackgroundCommand<>("Rename Equates in Selection", false, true);
// Now loop over all the code units and search for matching scalars...
while (iter.hasNext()) {
@@ -312,7 +311,7 @@ public class EquatePlugin extends Plugin {
}
private void renameEquateForCodeUnit(ListingActionContext context, Enum enoom, Equate equate,
String newName, String oldName, CompoundBackgroundCommand bgCmd, CodeUnit cu) {
String newName, String oldName, CompoundBackgroundCommand<Program> bgCmd, CodeUnit cu) {
if (cu instanceof Instruction) {
@@ -348,8 +347,8 @@ public class EquatePlugin extends Plugin {
CodeUnitIterator iter) {
// Create a background task to process all the remove tasks.
CompoundBackgroundCommand bckCmd =
new CompoundBackgroundCommand("Remove Equates in Selection", false, true);
CompoundBackgroundCommand<Program> bckCmd =
new CompoundBackgroundCommand<>("Remove Equates in Selection", false, true);
// Now iterate over all code units in the iterator.
while (iter.hasNext()) {
@@ -362,7 +361,7 @@ public class EquatePlugin extends Plugin {
}
private void removeEquateForCodeUnit(ListingActionContext context, Equate equate,
CompoundBackgroundCommand bckCmd, CodeUnit cu) {
CompoundBackgroundCommand<Program> bckCmd, CodeUnit cu) {
// A code unit can be either an instruction or data; we need to handle each
// separately.
if (cu instanceof Instruction) {
@@ -46,8 +46,8 @@ public class ApplyClassFunctionDefinitionUpdatesScript extends GhidraScript {
return;
}
RecoveredClassHelper classHelper = new RecoveredClassHelper(currentProgram, currentLocation,
state.getTool(), this, false, false, false, monitor);
RecoveredClassHelper classHelper = new RecoveredClassHelper(currentProgram, state.getTool(),
this, false, false, false, monitor);
DataTypeManagerService dtms = state.getTool().getService(DataTypeManagerService.class);
List<DataType> selectedDatatypes = dtms.getSelectedDatatypes();
@@ -46,20 +46,20 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
return;
}
RecoveredClassHelper classHelper = new RecoveredClassHelper(currentProgram, currentLocation,
state.getTool(), this, false, false, false, monitor);
if(currentAddress == null) {
RecoveredClassHelper classHelper = new RecoveredClassHelper(currentProgram, state.getTool(),
this, false, false, false, monitor);
if (currentAddress == null) {
println("Cursor must be in a class function.");
return;
}
Function function = getFunctionContaining(currentAddress);
if(function == null) {
if (function == null) {
println("Cursor must be in a class function.");
return;
}
if(function.isThunk()) {
if (function.isThunk()) {
println("User should not edit thunks as they are auto-updated from thunked function. " +
"Please undo changes to thunk then edit thunked function and rerun script");
return;
@@ -69,14 +69,13 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
println("Function definitions are not affected by purecall changes.");
return;
}
Namespace classNamespace = classHelper.getClassNamespace(currentAddress);
if (classNamespace == null) {
println("Cursor must be in a class function.");
return;
}
// get a vftable that points to this function - doesn't matter which since it will
// be used to get the underlying function definition which will then be used to update
// all related function signatures
@@ -84,9 +83,8 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
// get all vftables that point to given function
if (vftablesContainingFunction.isEmpty()) {
println(
"Function is not a virtual function so has no function definition or related " +
"function signatures to update");
println("Function is not a virtual function so has no function definition or related " +
"function signatures to update");
return;
}
@@ -107,7 +105,7 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
break;
}
}
if (vftableWithAppliedStructure == null) {
println(
"The vftable(s) containing this function do not have a valid vftable structure " +
@@ -159,5 +157,4 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
}
}
@@ -33,15 +33,33 @@
//@category Data Types
//@keybinding F6
import ghidra.app.plugin.core.decompile.actions.FillOutStructureCmd;
import org.apache.commons.lang3.StringUtils;
import ghidra.app.decompiler.DecompileOptions;
import ghidra.app.decompiler.component.DecompilerUtils;
import ghidra.app.decompiler.util.FillOutStructureCmd;
import ghidra.app.script.GhidraScript;
public class CreateStructure extends GhidraScript {
@Override
public void run() {
FillOutStructureCmd fillCmd =
new FillOutStructureCmd(currentProgram, currentLocation, state.getTool());
fillCmd.applyTo(currentProgram, this.monitor);
if (currentProgram == null || currentLocation == null) {
popup("Requires open program and location");
return;
}
DecompileOptions decompileOptions =
DecompilerUtils.getDecompileOptions(state.getTool(), currentProgram);
FillOutStructureCmd cmd = new FillOutStructureCmd(currentLocation, decompileOptions);
if (!cmd.applyTo(currentProgram, this.monitor)) {
String detail = "";
String msg = cmd.getStatusMsg();
if (!StringUtils.isBlank(msg)) {
detail = ": " + msg;
}
popup("Failed to fill-out structure" + detail);
}
}
}
@@ -190,10 +190,9 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
hasDebugSymbols = isPDBLoadedInProgram();
nameVfunctions = !hasDebugSymbols;
recoverClassesFromRTTI =
new RTTIWindowsClassRecoverer(currentProgram, currentLocation, state.getTool(),
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
nameVfunctions, hasDebugSymbols, monitor);
recoverClassesFromRTTI = new RTTIWindowsClassRecoverer(currentProgram, state.getTool(),
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
nameVfunctions, hasDebugSymbols, monitor);
}
else if (isPE() && isGcc()) {
@@ -213,10 +212,9 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
}
//run fixup old elf relocations script
runScript("FixElfExternalOffsetDataRelocationScript.java");
recoverClassesFromRTTI =
new RTTIGccClassRecoverer(currentProgram, currentLocation, state.getTool(), this,
BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
nameVfunctions, hasDebugSymbols, monitor);
recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, state.getTool(),
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
nameVfunctions, hasDebugSymbols, monitor);
}
else if (isGcc()) {
@@ -245,10 +243,9 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
return;
}
nameVfunctions = !hasDebugSymbols;
recoverClassesFromRTTI =
new RTTIGccClassRecoverer(currentProgram, currentLocation, state.getTool(), this,
BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
nameVfunctions, hasDebugSymbols, monitor);
recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, state.getTool(),
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
nameVfunctions, hasDebugSymbols, monitor);
}
else {
println("This script will not work on this program type");
@@ -25,10 +25,9 @@
import java.util.Iterator;
import docking.options.OptionsService;
import ghidra.app.decompiler.*;
import ghidra.app.decompiler.component.DecompilerUtils;
import ghidra.app.script.GhidraScript;
import ghidra.framework.options.ToolOptions;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.HighFunction;
@@ -38,214 +37,215 @@ import ghidra.program.model.symbol.Symbol;
public class ShowCCallsScript extends GhidraScript {
private Address lastAddr = null;
private Address lastAddr = null;
@Override
public void run() throws Exception {
@Override
public void run() throws Exception {
if (currentLocation == null) {
println("No Location.");
return;
}
Listing listing = currentProgram.getListing();
Function func = listing.getFunctionContaining(currentAddress);
if (func == null) {
println("No Function at address " + currentAddress);
return;
}
DecompInterface decomplib = setUpDecompiler(currentProgram);
try {
if (!decomplib.openProgram(currentProgram)) {
println("Decompile Error: " + decomplib.getLastMessage());
return;
}
// call decompiler for all refs to current function
Symbol sym = this.getSymbolAt(func.getEntryPoint());
Reference refs[] = sym.getReferences(null);
for (int i = 0; i < refs.length; i++) {
if (monitor.isCancelled()) {
break;
}
// get function containing.
Address refAddr = refs[i].getFromAddress();
Function refFunc = currentProgram.getFunctionManager()
.getFunctionContaining(refAddr);
if (refFunc == null) {
continue;
}
// decompile function
// look for call to this function
// display call
analyzeFunction(decomplib, currentProgram, refFunc, refAddr);
}
}
finally {
decomplib.dispose();
}
lastAddr = null;
}
private DecompInterface setUpDecompiler(Program program) {
DecompInterface decomplib = new DecompInterface();
DecompileOptions options;
options = new DecompileOptions();
OptionsService service = state.getTool().getService(OptionsService.class);
if (service != null) {
ToolOptions opt = service.getOptions("Decompiler");
options.grabFromToolAndProgram(null,opt,program);
if (currentLocation == null) {
println("No Location.");
return;
}
decomplib.setOptions(options);
Listing listing = currentProgram.getListing();
Function func = listing.getFunctionContaining(currentAddress);
if (func == null) {
println("No Function at address " + currentAddress);
return;
}
DecompInterface decomplib = setUpDecompiler(currentProgram);
try {
if (!decomplib.openProgram(currentProgram)) {
println("Decompile Error: " + decomplib.getLastMessage());
return;
}
// call decompiler for all refs to current function
Symbol sym = this.getSymbolAt(func.getEntryPoint());
Reference refs[] = sym.getReferences(null);
for (Reference ref : refs) {
if (monitor.isCancelled()) {
break;
}
// get function containing.
Address refAddr = ref.getFromAddress();
Function refFunc =
currentProgram.getFunctionManager().getFunctionContaining(refAddr);
if (refFunc == null) {
continue;
}
// decompile function
// look for call to this function
// display call
analyzeFunction(decomplib, currentProgram, refFunc, refAddr);
}
}
finally {
decomplib.dispose();
}
lastAddr = null;
}
/**
* Method to setup the decompiler interface for the given program
* @param program the given program
* @return the decompiler interface
*/
private DecompInterface setUpDecompiler(Program program) {
DecompileOptions options = DecompilerUtils.getDecompileOptions(state.getTool(), program);
DecompInterface decomplib = new DecompInterface();
decomplib.setOptions(options);
decomplib.toggleCCode(true);
decomplib.toggleSyntaxTree(true);
decomplib.setSimplificationStyle("decompile");
return decomplib;
}
/**
* Analyze a functions references
*/
public void analyzeFunction(DecompInterface decomplib, Program prog, Function f, Address refAddr) {
/**
* Analyze a functions references
*/
public void analyzeFunction(DecompInterface decomplib, Program prog, Function f,
Address refAddr) {
if (f == null) {
return;
}
if (f == null) {
return;
}
// don't decompile the function again if it was the same as the last one
//
if (!f.getEntryPoint().equals(lastAddr))
decompileFunction(f, decomplib);
lastAddr = f.getEntryPoint();
// don't decompile the function again if it was the same as the last one
//
if (!f.getEntryPoint().equals(lastAddr))
decompileFunction(f, decomplib);
lastAddr = f.getEntryPoint();
Instruction instr = prog.getListing().getInstructionAt(refAddr);
if (instr == null) {
return;
}
Instruction instr = prog.getListing().getInstructionAt(refAddr);
if (instr == null) {
return;
}
println(printCall(f, refAddr));
}
println(printCall(f, refAddr));
}
HighFunction hfunction = null;
ClangTokenGroup docroot = null;
HighFunction hfunction = null;
public boolean decompileFunction(Function f, DecompInterface decomplib) {
// decomplib.setSimplificationStyle("normalize", null);
// HighFunction hfunction = decomplib.decompileFunction(f);
ClangTokenGroup docroot = null;
DecompileResults decompRes =
decomplib.decompileFunction(f, decomplib.getOptions().getDefaultTimeout(), monitor);
//String statusMsg = decomplib.getDecompileMessage();
public boolean decompileFunction(Function f, DecompInterface decomplib) {
// decomplib.setSimplificationStyle("normalize", null);
// HighFunction hfunction = decomplib.decompileFunction(f);
hfunction = decompRes.getHighFunction();
docroot = decompRes.getCCodeMarkup();
DecompileResults decompRes = decomplib.decompileFunction(f, decomplib.getOptions().getDefaultTimeout(), monitor);
//String statusMsg = decomplib.getDecompileMessage();
if (hfunction == null)
return false;
hfunction = decompRes.getHighFunction();
docroot = decompRes.getCCodeMarkup();
return true;
}
if (hfunction == null)
return false;
/**
* get the pcode ops that refer to an address
*/
public Iterator<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();
/**
* 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;
}
printCall(refAddr, docroot, buff, false, false);
public String printCall(Function f, Address refAddr) {
StringBuffer buff = new StringBuffer();
return buff.toString();
}
printCall(refAddr, docroot, buff, false, false);
private boolean printCall(Address refAddr, ClangNode node, StringBuffer buff, boolean didStart,
boolean isCall) {
if (node == null) {
return false;
}
return buff.toString();
}
Address min = node.getMinAddress();
Address max = node.getMaxAddress();
if (min == null)
return false;
private boolean printCall(Address refAddr, ClangNode node, StringBuffer buff, boolean didStart, boolean isCall) {
if (node == null) {
return false;
}
Address min = node.getMinAddress();
Address max = node.getMaxAddress();
if (min == null)
return false;
if (refAddr.getPhysicalAddress().equals(max) && node instanceof ClangStatement) {
ClangStatement stmt = (ClangStatement) node;
// Don't check for an actual call. The call could be buried more deeply. As long as the original call reference site
// is the max address, then display the results.
// So this block assumes that the last address contained in the call will be the
// address you are looking for.
// - This could lead to strange behavior if the call reference is placed on some address
// that is not the final call point used by the decompiler.
// - Also if there is a delay slot, then the last address for the call reference point
// might not be the last address for the block of PCode.
//if (stmt.getPcodeOp().getOpcode() == PcodeOp.CALL) {
if (!didStart) {
Address nodeAddr = node.getMaxAddress();
// Decompiler only knows base space.
// If reference came from an overlay space, convert address back
if (refAddr.getAddressSpace().isOverlaySpace()) {
nodeAddr = refAddr.getAddressSpace().getOverlayAddress(nodeAddr);
}
buff.append(" " + nodeAddr + " : ");
}
if (refAddr.getPhysicalAddress().equals(max) && node instanceof ClangStatement) {
ClangStatement stmt = (ClangStatement) node;
// Don't check for an actual call. The call could be buried more deeply. As long as the original call reference site
// is the max address, then display the results.
// So this block assumes that the last address contained in the call will be the
// address you are looking for.
// - This could lead to strange behavior if the call reference is placed on some address
// that is not the final call point used by the decompiler.
// - Also if there is a delay slot, then the last address for the call reference point
// might not be the last address for the block of PCode.
//if (stmt.getPcodeOp().getOpcode() == PcodeOp.CALL) {
if (!didStart) {
Address nodeAddr = node.getMaxAddress();
// Decompiler only knows base space.
// If reference came from an overlay space, convert address back
if (refAddr.getAddressSpace().isOverlaySpace()) {
nodeAddr = refAddr.getAddressSpace().getOverlayAddress(nodeAddr);
}
buff.append(" " + nodeAddr + " : ");
}
buff.append(" " + toString(stmt));
return true;
//}
}
for (int j = 0; j < node.numChildren(); j++) {
isCall = node instanceof ClangStatement;
didStart |= printCall(refAddr, node.Child(j), buff, didStart, isCall);
}
return didStart;
}
buff.append(" " + toString(stmt));
return true;
//}
}
for (int j = 0; j < node.numChildren(); j++) {
isCall = node instanceof ClangStatement;
didStart |= printCall(refAddr, node.Child(j), buff, didStart, isCall);
}
return didStart;
}
public String toString(ClangStatement node) {
StringBuffer buffer = new StringBuffer();
int open=-1;
for (int j = 0; j < node.numChildren(); j++) {
ClangNode subNode = node.Child(j);
if (subNode instanceof ClangSyntaxToken) {
ClangSyntaxToken syntaxNode = (ClangSyntaxToken) subNode;
if (syntaxNode.getOpen() != -1) {
if (node.Child(j+2) instanceof ClangTypeToken) {
open = syntaxNode.getOpen();
continue;
}
}
if (syntaxNode.getClose() == open && open != -1) {
open = -1;
continue;
}
}
if (open != -1) {
continue;
}
buffer.append(subNode.toString());
}
return buffer.toString();
StringBuffer buffer = new StringBuffer();
int open = -1;
for (int j = 0; j < node.numChildren(); j++) {
ClangNode subNode = node.Child(j);
if (subNode instanceof ClangSyntaxToken) {
ClangSyntaxToken syntaxNode = (ClangSyntaxToken) subNode;
if (syntaxNode.getOpen() != -1) {
if (node.Child(j + 2) instanceof ClangTypeToken) {
open = syntaxNode.getOpen();
continue;
}
}
if (syntaxNode.getClose() == open && open != -1) {
open = -1;
continue;
}
}
if (open != -1) {
continue;
}
buffer.append(subNode.toString());
}
return buffer.toString();
}
}
@@ -254,8 +254,7 @@ public class ShowConstantUse extends GhidraScript {
ConstUseLocation entry = (ConstUseLocation) rowObject;
Function func = entry.getProgram()
.getFunctionManager()
.getFunctionContaining(
entry.getAddress());
.getFunctionContaining(entry.getAddress());
if (func == null) {
return "";
}
@@ -762,9 +761,7 @@ public class ShowConstantUse extends GhidraScript {
if (defUseList == null || defUseList.size() <= 0) {
return value;
}
Iterator<PcodeOp> iterator = defUseList.iterator();
while (iterator.hasNext()) {
PcodeOp pcodeOp = iterator.next();
for (PcodeOp pcodeOp : defUseList) {
int opcode = pcodeOp.getOpcode();
switch (opcode) {
case PcodeOp.INT_AND:
@@ -970,8 +967,7 @@ public class ShowConstantUse extends GhidraScript {
}
private void followThroughGlobal(HashMap<Address, Long> constUse, ArrayList<PcodeOp> defUseList,
HighVariable hvar,
ArrayList<FunctionParamUse> funcList,
HighVariable hvar, ArrayList<FunctionParamUse> funcList,
HashSet<SequenceNumber> doneSet) {
Address loc = hvar.getRepresentative().getAddress();
PcodeOp def = hvar.getRepresentative().getDef();
@@ -1013,6 +1009,7 @@ public class ShowConstantUse extends GhidraScript {
private Address lastDecompiledFuncAddr = null;
private DecompInterface setUpDecompiler(Program program) {
DecompInterface decompInterface = new DecompInterface();
// call it to get results
@@ -1021,13 +1018,8 @@ public class ShowConstantUse extends GhidraScript {
return null;
}
DecompileOptions options;
options = new DecompileOptions();
OptionsService service = state.getTool().getService(OptionsService.class);
if (service != null) {
ToolOptions opt = service.getOptions("Decompiler");
options.grabFromToolAndProgram(null, opt, program);
}
DecompileOptions options = DecompilerUtils.getDecompileOptions(state.getTool(), program);
decompInterface.setOptions(options);
decompInterface.toggleCCode(true);
@@ -27,10 +27,11 @@
//
//@category Analysis
import java.util.*;
import ghidra.app.decompiler.*;
import ghidra.app.decompiler.component.DecompilerUtils;
import ghidra.app.script.GhidraScript;
import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.PrototypeModel;
@@ -39,10 +40,6 @@ import ghidra.program.model.pcode.*;
import ghidra.program.model.symbol.*;
import ghidra.util.exception.*;
import java.util.*;
import docking.options.OptionsService;
public class StringParameterPropagator extends GhidraScript {
// TODO!! Error handling needs a lot of work !!
@@ -195,9 +192,10 @@ public class StringParameterPropagator extends GhidraScript {
int maxParams = funcInfo.getMaxParamsSeen();
boolean couldBeVararg = !funcInfo.numParamsAgree();
if (!funcInfo.numParamsAgree()) {
currentProgram.getBookmarkManager().setBookmark(calledFunc.getEntryPoint(),
BookmarkType.NOTE, this.getClass().getName(),
"Number of parameters disagree min: " + minParams + " max: " + maxParams);
currentProgram.getBookmarkManager()
.setBookmark(calledFunc.getEntryPoint(), BookmarkType.NOTE,
this.getClass().getName(), "Number of parameters disagree min: " +
minParams + " max: " + maxParams);
println("WARNING : Number of params disagree for " + calledFunc.getName() +
" @ " + entry);
@@ -317,9 +315,8 @@ public class StringParameterPropagator extends GhidraScript {
ReferenceIterator dataRefIter = rData.getReferenceIteratorTo();
while (dataRefIter.hasNext()) {
Reference dataRef = dataRefIter.next();
func =
currentProgram.getFunctionManager().getFunctionContaining(
dataRef.getFromAddress());
func = currentProgram.getFunctionManager()
.getFunctionContaining(dataRef.getFromAddress());
if (func == null) {
continue;
}
@@ -337,9 +334,8 @@ public class StringParameterPropagator extends GhidraScript {
private void collectDataRefenceLocations(HashSet<Address> dataItemLocationSet,
HashSet<Address> referringFuncLocationSet) {
int count = 0;
ReferenceIterator iter =
currentProgram.getReferenceManager().getReferenceIterator(
currentProgram.getMinAddress());
ReferenceIterator iter = currentProgram.getReferenceManager()
.getReferenceIterator(currentProgram.getMinAddress());
while (iter.hasNext() && !monitor.isCancelled()) {
Reference ref = iter.next();
@@ -412,7 +408,8 @@ public class StringParameterPropagator extends GhidraScript {
if (convention == null) {
convention = currentProgram.getCompilerSpec().getDefaultCallingConvention();
}
if (initialConvention != null && !convention.getName().equals(initialConvention.getName())) {
if (initialConvention != null &&
!convention.getName().equals(initialConvention.getName())) {
return true;
}
@@ -452,8 +449,9 @@ public class StringParameterPropagator extends GhidraScript {
if (param == null) {
return false;
}
currentProgram.getBookmarkManager().setBookmark(func.getEntryPoint(), BookmarkType.NOTE,
this.getClass().getName(), "Created " + dt.getName() + " parameter");
currentProgram.getBookmarkManager()
.setBookmark(func.getEntryPoint(), BookmarkType.NOTE, this.getClass().getName(),
"Created " + dt.getName() + " parameter");
return false;
}
@@ -497,9 +495,8 @@ public class StringParameterPropagator extends GhidraScript {
if (i < f.getParameterCount()) {
continue;
}
VariableStorage storage =
convention.getArgLocation(i - 1, f.getParameters(), DataType.DEFAULT,
currentProgram);
VariableStorage storage = convention.getArgLocation(i - 1, f.getParameters(),
DataType.DEFAULT, currentProgram);
if (storage.isUnassignedStorage()) {
break;
}
@@ -576,7 +573,8 @@ public class StringParameterPropagator extends GhidraScript {
}
long mask =
0xffffffffffffffffL >>> ((8 - entry.getAddressSpace().getPointerSize()) * 8);
0xffffffffffffffffL >>> ((8 - entry.getAddressSpace().getPointerSize()) *
8);
Address possibleAddr = entry.getNewAddress(mask & value);
if (stringLocationSet.contains(possibleAddr)) {
markStringParam(constUse, possibleAddr, calledFuncAddr, i - 1,
@@ -609,18 +607,11 @@ public class StringParameterPropagator extends GhidraScript {
private Address lastDecompiledFuncAddr = null;
private DecompInterface setUpDecompiler(Program program) {
DecompileOptions options = DecompilerUtils.getDecompileOptions(state.getTool(), program);
DecompInterface decompInterface = new DecompInterface();
DecompileOptions options;
options = new DecompileOptions();
PluginTool tool = state.getTool();
if (tool != null) {
OptionsService service = tool.getService(OptionsService.class);
if (service != null) {
ToolOptions opt = service.getOptions("Decompiler");
options.grabFromToolAndProgram(null, opt, program);
}
}
decompInterface.setOptions(options);
decompInterface.toggleCCode(true);
@@ -637,9 +628,8 @@ public class StringParameterPropagator extends GhidraScript {
return true;
try {
DecompileResults decompRes =
decompInterface.decompileFunction(f,
decompInterface.getOptions().getDefaultTimeout(), monitor);
DecompileResults decompRes = decompInterface.decompileFunction(f,
decompInterface.getOptions().getDefaultTimeout(), monitor);
hfunction = decompRes.getHighFunction();
}
@@ -31,11 +31,9 @@ import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import docking.options.OptionsService;
import ghidra.app.decompiler.*;
import ghidra.app.decompiler.component.DecompilerUtils;
import ghidra.app.script.GhidraScript;
import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.*;
@@ -55,7 +53,7 @@ public class WindowsResourceReference extends GhidraScript {
ArrayList<ArrayList<PcodeOp>> defUseLists = new ArrayList<>();
protected AddressSetPropertyMap alreadyDoneAddressSetPropertyMap;
// set of functions that decompilation failed on
protected AddressSet badDecompFunctions = new AddressSet();
@@ -369,7 +367,7 @@ public class WindowsResourceReference extends GhidraScript {
if (f == null) {
return;
}
// check if decompilation of this function failed previously
if (badDecompFunctions.contains(f.getEntryPoint())) {
return;
@@ -462,13 +460,10 @@ public class WindowsResourceReference extends GhidraScript {
private void addResourceReferences(HashMap<Address, Long> constLocs, String resourceName,
boolean printScriptMsgs, boolean createBookmarks) throws CancelledException {
Set<Address> keys;
Iterator<Address> locIter;
keys = constLocs.keySet();
locIter = keys.iterator();
while (locIter.hasNext()) {
for (Address loc : keys) {
monitor.checkCancelled();
Address loc = locIter.next();
Instruction instr = currentProgram.getListing().getInstructionAt(loc);
long rsrcID = constLocs.get(loc);
Address rsrcAddr = findResource(resourceName + "_" + Long.toHexString(rsrcID), 0);
@@ -488,9 +483,9 @@ public class WindowsResourceReference extends GhidraScript {
instr.addMnemonicReference(rsrcAddr, RefType.DATA, SourceType.ANALYSIS);
if (createBookmarks) {
currentProgram.getBookmarkManager().setBookmark(instr.getMinAddress(),
BookmarkType.ANALYSIS, "WindowsResourceReference",
"Added Resource Reference");
currentProgram.getBookmarkManager()
.setBookmark(instr.getMinAddress(), BookmarkType.ANALYSIS,
"WindowsResourceReference", "Added Resource Reference");
}
if (printScriptMsgs) {
println(" " + instr.getMinAddress().toString() + " : Found " + rsrcName +
@@ -513,15 +508,13 @@ public class WindowsResourceReference extends GhidraScript {
private void addResourceTableReferences(HashMap<Address, Long> constLocs, String tableName,
boolean printScriptMsgs, boolean createBookmarks) throws CancelledException {
Set<Address> keys;
Iterator<Address> locIter;
//Get the set of address locations which call the resource function
keys = constLocs.keySet();
locIter = keys.iterator();
//Iterate though the set of address locations
while (locIter.hasNext()) {
for (Address loc : keys) {
monitor.checkCancelled();
Address loc = locIter.next();
Instruction instr = currentProgram.getListing().getInstructionAt(loc);
Long rsrcID = constLocs.get(loc);
Address rsrcAddr = null;
@@ -532,9 +525,9 @@ public class WindowsResourceReference extends GhidraScript {
if (rsrcAddr != null) {
instr.addMnemonicReference(rsrcAddr, RefType.DATA, SourceType.ANALYSIS);
if (createBookmarks) {
currentProgram.getBookmarkManager().setBookmark(instr.getMinAddress(),
BookmarkType.ANALYSIS, "WindowsResourceReference",
"Added Resource Table Reference");
currentProgram.getBookmarkManager()
.setBookmark(instr.getMinAddress(), BookmarkType.ANALYSIS,
"WindowsResourceReference", "Added Resource Table Reference");
}
if (printScriptMsgs) {
println(" " + instr.getMinAddress().toString() + " : Found " +
@@ -622,9 +615,7 @@ public class WindowsResourceReference extends GhidraScript {
if (defUseList == null || defUseList.size() <= 0) {
return value;
}
Iterator<PcodeOp> iterator = defUseList.iterator();
while (iterator.hasNext()) {
PcodeOp pcodeOp = iterator.next();
for (PcodeOp pcodeOp : defUseList) {
int opcode = pcodeOp.getOpcode();
switch (opcode) {
case PcodeOp.INT_AND:
@@ -763,18 +754,11 @@ public class WindowsResourceReference extends GhidraScript {
private Address lastDecompiledFuncAddr = null;
private DecompInterface setUpDecompiler(Program program) {
DecompileOptions options = DecompilerUtils.getDecompileOptions(state.getTool(), program);
DecompInterface decompiler = new DecompInterface();
DecompileOptions options;
options = new DecompileOptions();
PluginTool tool = state.getTool();
if (tool != null) {
OptionsService service = tool.getService(OptionsService.class);
if (service != null) {
ToolOptions opt = service.getOptions("Decompiler");
options.grabFromToolAndProgram(null, opt, program);
}
}
decompiler.setOptions(options);
decompiler.toggleCCode(true);
@@ -15,71 +15,55 @@
*/
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS.
package classrecovery;
import docking.options.OptionsService;
import ghidra.app.decompiler.DecompInterface;
import ghidra.app.decompiler.DecompileOptions;
import ghidra.app.decompiler.DecompileResults;
import ghidra.app.decompiler.*;
import ghidra.app.decompiler.component.DecompilerUtils;
import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.ParameterDefinition;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
import ghidra.program.model.pcode.FunctionPrototype;
import ghidra.program.model.pcode.HighFunction;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.pcode.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class DecompilerScriptUtils {
private Program program;
private PluginTool tool;
private ServiceProvider serviceProvider;
private TaskMonitor monitor;
private DecompInterface decompInterface;
DecompilerScriptUtils(Program program, PluginTool tool, TaskMonitor monitor) {
DecompilerScriptUtils(Program program, ServiceProvider serviceProvider, TaskMonitor monitor) {
this.program = program;
this.monitor = monitor;
this.tool = tool;
this.serviceProvider = serviceProvider;
decompInterface = setupDecompilerInterface();
}
/**
* Method to setup the decompiler interface for the given program
* @return the interface to the decompiler
* @return the interface to the decompiler or null if failed to open program
*/
public DecompInterface setupDecompilerInterface() {
decompInterface = new DecompInterface();
DecompileOptions options;
options = new DecompileOptions();
if (tool == null) {
options.grabFromProgram(program);
}
else {
OptionsService service = tool.getService(OptionsService.class);
if (service != null) {
ToolOptions opt = service.getOptions("Decompiler");
options.grabFromToolAndProgram(null, opt, program);
}
else {
options.grabFromProgram(program);
}
}
DecompileOptions options = DecompilerUtils.getDecompileOptions(serviceProvider, program);
decompInterface.setOptions(options);
decompInterface.toggleCCode(true);
decompInterface.toggleSyntaxTree(true);
decompInterface.setSimplificationStyle("decompile");
if (!decompInterface.openProgram(program)) {
decompInterface.dispose();
return null;
}
return decompInterface;
@@ -90,7 +74,6 @@ public class DecompilerScriptUtils {
return decompInterface;
}
/**
* Method to decompile the given function and return the function's HighFunction
* @param function the given function
@@ -126,7 +109,6 @@ public class DecompilerScriptUtils {
return decompRes.getHighFunction().getFunctionPrototype().getReturnType();
}
/**
* Method to retrieve the function signature string from the decompiler function prototype. NOTE:
* if there is a this param, it will not be included.
@@ -153,7 +135,6 @@ public class DecompilerScriptUtils {
return null;
}
HighFunction highFunction = decompRes.getHighFunction();
FunctionPrototype functionPrototype = highFunction.getFunctionPrototype();
@@ -16,17 +16,17 @@
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS.
package classrecovery;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.NamespaceUtils;
import ghidra.framework.options.Options;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.program.flatapi.FlatProgramAPI;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.SymbolType;
import ghidra.program.util.ProgramLocation;
import ghidra.util.Msg;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
@@ -36,32 +36,21 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
boolean programHasRTTIApplied = false;
String ghidraVersion;
Program program;
TaskMonitor monitor;
boolean hasDebugSymbols;
RTTIClassRecoverer(Program program, ServiceProvider serviceProvider, FlatProgramAPI api,
boolean createBookmarks, boolean useShortTemplates, boolean nameVfunctions,
boolean hasDebugSymbols, TaskMonitor monitor) throws Exception {
RTTIClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
boolean nameVfunctions, boolean hasDebugSymbols, TaskMonitor monitor) throws Exception {
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
super(program, serviceProvider, api, createBookmarks, useShortTemplates, nameVfunctions,
monitor);
this.program = program;
this.monitor = monitor;
this.location = location;
this.tool = tool;
this.api = api;
this.createBookmarks = createBookmarks;
this.useShortTemplates = useShortTemplates;
this.nameVfunctions = nameVfunctions;
this.hasDebugSymbols = hasDebugSymbols;
ghidraVersion = getVersionOfGhidra();
}
public DecompilerScriptUtils getDecompilerUtils() {
return decompilerUtils;
}
@@ -100,21 +89,15 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
return options.getString("Created With Ghidra Version", null);
}
public void fixUpProgram() throws CancelledException, Exception {
return;
}
public List<RecoveredClass> createRecoveredClasses() throws Exception {
return new ArrayList<RecoveredClass>();
}
/**
* Method to promote the namespace is a class namespace.
* @param namespace the namespace for the vftable
@@ -123,18 +106,16 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
*/
public Namespace promoteToClassNamespace(Namespace namespace) throws InvalidInputException {
Namespace newClass = NamespaceUtils.convertNamespaceToClass(namespace);
Namespace newClass = NamespaceUtils.convertNamespaceToClass(namespace);
SymbolType symbolType = newClass.getSymbol().getSymbolType();
if (symbolType == SymbolType.CLASS) {
return newClass;
}
Msg.debug(this,
"Could not promote " + namespace.getName() + " to a class namespace");
return null;
SymbolType symbolType = newClass.getSymbol().getSymbolType();
if (symbolType == SymbolType.CLASS) {
return newClass;
}
Msg.debug(this, "Could not promote " + namespace.getName() + " to a class namespace");
return null;
}
/**
* Method to iterate over all the RecoveredClass objects and see if there is an existing class structure data type already
* if so, add it to the RecoveredClass object
@@ -144,10 +125,8 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
public void retrieveExistingClassStructures(List<RecoveredClass> recoveredClasses)
throws CancelledException {
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
while (recoveredClassIterator.hasNext()) {
for (RecoveredClass recoveredClass : recoveredClasses) {
monitor.checkCancelled();
RecoveredClass recoveredClass = recoveredClassIterator.next();
// if class is non-virtual have to search for an existing class datatype
@@ -156,16 +135,16 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
if (possibleExistingClassStructures.length == 0) {
continue;
}
for (int i = 0; i < possibleExistingClassStructures.length; i++) {
for (DataType possibleExistingClassStructure : possibleExistingClassStructures) {
monitor.checkCancelled();
if (!(possibleExistingClassStructures[i] instanceof Structure)) {
if (!(possibleExistingClassStructure instanceof Structure)) {
continue;
}
if (possibleExistingClassStructures[i].isNotYetDefined()) {
if (possibleExistingClassStructure.isNotYetDefined()) {
continue;
}
Structure existingClassStructure = (Structure) possibleExistingClassStructures[i];
Structure existingClassStructure = (Structure) possibleExistingClassStructure;
recoveredClass.addExistingClassStructure(existingClassStructure);
break;
@@ -174,10 +153,8 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
//Iterate over constructor/destructor functions
List<Function> constructorOrDestructorFunctions =
recoveredClass.getConstructorOrDestructorFunctions();
Iterator<Function> constDestIterator = constructorOrDestructorFunctions.iterator();
while (constDestIterator.hasNext()) {
for (Function constDestFunction : constructorOrDestructorFunctions) {
monitor.checkCancelled();
Function constDestFunction = constDestIterator.next();
Namespace parentNamespace = constDestFunction.getParentNamespace();
if (!parentNamespace.equals(recoveredClass.getClassNamespace())) {
continue;
@@ -220,8 +197,6 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
}
}
/**
* Method to get class data information from destructors if a class has no constructors
* @param recoveredClasses list of classes
@@ -234,11 +209,8 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
throws CancelledException, DuplicateNameException, InvalidInputException,
CircularDependencyException {
Iterator<RecoveredClass> classIterator = recoveredClasses.iterator();
while (classIterator.hasNext()) {
for (RecoveredClass recoveredClass : recoveredClasses) {
monitor.checkCancelled();
RecoveredClass recoveredClass = classIterator.next();
// we can only figure out structure info for functions with vftable since that is
// what we use to determine which variable is being used to store the class structure
if (!recoveredClass.hasVftable()) {
@@ -257,11 +229,8 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
memberFunctionsToProcess.addAll(recoveredClass.getIndeterminateList());
memberFunctionsToProcess.addAll(recoveredClass.getInlinedConstructorList());
Iterator<Function> memberFunctionIterator = memberFunctionsToProcess.iterator();
while (memberFunctionIterator.hasNext()) {
for (Function memberFunction : memberFunctionsToProcess) {
monitor.checkCancelled();
Function memberFunction = memberFunctionIterator.next();
if (getVftableReferences(memberFunction) == null) {
continue;
}
@@ -278,9 +247,4 @@ public class RTTIClassRecoverer extends RecoveredClassHelper {
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -776,22 +776,18 @@ public class DecompInterface {
public synchronized DecompileResults decompileFunction(Function func, int timeoutSecs,
TaskMonitor monitor) {
dtmanage.clearTemporaryIds();
decompileMessage = "";
if (monitor != null && monitor.isCancelled()) {
return null;
if (program == null || (monitor != null && monitor.isCancelled())) {
return new DecompileResults(func, pcodelanguage, compilerSpec, dtmanage,
decompileMessage, null, DecompileProcess.DisposeState.DISPOSED_ON_CANCEL);
}
if (monitor != null) {
monitor.addCancelledListener(monitorListener);
}
dtmanage.clearTemporaryIds();
if (program == null) {
return new DecompileResults(func, pcodelanguage, null, dtmanage, decompileMessage, null,
DecompileProcess.DisposeState.DISPOSED_ON_CANCEL);
}
Decoder decoder = null;
try {
Address funcEntry = func.getEntryPoint();
@@ -17,18 +17,78 @@ package ghidra.app.decompiler.component;
import java.util.*;
import docking.options.OptionsService;
import docking.widgets.fieldpanel.field.Field;
import docking.widgets.fieldpanel.support.*;
import ghidra.app.decompiler.*;
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
import ghidra.program.model.data.MetaDataType;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.*;
public class DecompilerUtils {
/**
* Gaither decompiler options from tool and program. If tool is null or does not provide
* a {@link OptionsService} provider only options stored within the program will be consumed.
* @param serviceProvider plugin tool or service provider providing access to {@link OptionsService}
* @param program program
* @return decompiler options
*/
public static DecompileOptions getDecompileOptions(ServiceProvider serviceProvider,
Program program) {
DecompileOptions options;
options = new DecompileOptions();
OptionsService service = null;
if (serviceProvider != null) {
service = serviceProvider.getService(OptionsService.class);
}
if (service != null) {
ToolOptions opt = service.getOptions("Decompiler");
options.grabFromToolAndProgram(null, opt, program);
}
else {
options.grabFromProgram(program);
}
return options;
}
/**
* Get the data-type associated with a Varnode. If the Varnode is input to a CAST p-code
* op, take the most specific data-type between what it was cast from and cast to.
* @param vn is the Varnode to get the data-type for
* @return the data-type
*/
public static DataType getDataTypeTraceForward(Varnode vn) {
DataType res = vn.getHigh().getDataType();
PcodeOp op = vn.getLoneDescend();
if (op != null && op.getOpcode() == PcodeOp.CAST) {
Varnode otherVn = op.getOutput();
res = MetaDataType.getMostSpecificDataType(res, otherVn.getHigh().getDataType());
}
return res;
}
/**
* Get the data-type associated with a Varnode. If the Varnode is produce by a CAST p-code
* op, take the most specific data-type between what it was cast from and cast to.
* @param vn is the Varnode to get the data-type for
* @return the data-type
*/
public static DataType getDataTypeTraceBackward(Varnode vn) {
DataType res = vn.getHigh().getDataType();
PcodeOp op = vn.getDef();
if (op != null && op.getOpcode() == PcodeOp.CAST) {
Varnode otherVn = op.getInput(0);
res = MetaDataType.getMostSpecificDataType(res, otherVn.getHigh().getDataType());
}
return res;
}
/**
* If the token refers to an individual Varnode, return it. Otherwise return null
*
@@ -214,6 +274,25 @@ public class DecompilerUtils {
return pcodeops;
}
/**
* Test specified variable to see if it corresponds to the auto {@code this} parameter
* of the specified {@link Function}
* @param var decompiler {@link HighVariable variable}
* @param function decompiled function
* @return true if {@code var} corresponds to existing auto {@code this} parameter, else false
*/
public static boolean testForAutoParameterThis(HighVariable var, Function function) {
if (var instanceof HighParam) {
int slot = ((HighParam) var).getSlot();
Parameter parameter = function.getParameter(slot);
if ((parameter != null) &&
(parameter.getAutoParameterType() == AutoParameterType.THIS)) {
return true;
}
}
return false;
}
/**
* Returns the function represented by the given token. This will be either the
* decompiled function or a function referenced within the decompiled function.
@@ -0,0 +1,182 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.decompiler.util;
import java.util.Objects;
import ghidra.app.decompiler.*;
import ghidra.app.decompiler.component.DecompilerUtils;
import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
import ghidra.program.model.pcode.*;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.util.*;
import ghidra.util.Msg;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
/**
* Automatically creates a structure definition based on the references found by the decompiler.
*
* If the parameter is already a structure pointer, any new references found will be added
* to the structure, even if the structure must grow.
*
*/
public class FillOutStructureCmd extends BackgroundCommand<Program> {
private DecompileOptions decompileOptions;
private ProgramLocation location;
/**
* Constructor.
*
* @param location the current program location. Supported location types include:
* {@link DecompilerLocation}, {@link VariableLocation} or
* {@link FunctionParameterFieldLocation}.
* @param decompileOptions decompiler options.
* (see {@link DecompilerUtils#getDecompileOptions(ServiceProvider, Program)})
*/
public FillOutStructureCmd(ProgramLocation location, DecompileOptions decompileOptions) {
super("Fill Out Structure", true, false, true);
this.decompileOptions = Objects.requireNonNull(decompileOptions);
this.location = Objects.requireNonNull(location);
}
@Override
public boolean applyTo(Program program, TaskMonitor monitor) {
if (program != location.getProgram()) {
throw new AssertionError("program does not match location");
}
try {
Function function =
program.getFunctionManager().getFunctionContaining(location.getAddress());
if (function == null) {
setStatusMsg("Function not found at " + location.getAddress());
return false;
}
FillOutStructureHelper fillStructureHelper =
new FillOutStructureHelper(program, decompileOptions, monitor);
HighVariable var = null;
if (!(location instanceof DecompilerLocation dloc)) {
// if we don't have one, make one, and map variable to a varnode
Address storageAddr = computeStorageAddress(function);
var = fillStructureHelper.computeHighVariable(storageAddr, function);
}
else {
// get the Varnode under the cursor
ClangToken token = dloc.getToken();
if (token == null) {
setStatusMsg("Unable to identify variable from decompiler token");
return false;
}
var = token.getHighVariable();
Varnode exactSpot = token.getVarnode();
if ((var != null) && (exactSpot != null)) {
HighFunction hfunc = var.getHighFunction();
try { // Adjust HighVariable based on exact varnode selected, if there are merged groups
var = hfunc.splitOutMergeGroup(var, exactSpot);
}
catch (PcodeException ex) {
setStatusMsg("Unable to isolate variable from merged group");
return false;
}
}
}
Structure structDT = fillStructureHelper.processStructure(var, function, false, true);
if (structDT == null) {
setStatusMsg("Failed to fill-out structure");
return false;
}
DataType pointerDT = new PointerDataType(structDT);
// Delay adding to the manager until full structure is accumulated
pointerDT = program.getDataTypeManager()
.addDataType(pointerDT, DataTypeConflictHandler.DEFAULT_HANDLER);
boolean isThisParam = DecompilerUtils.testForAutoParameterThis(var, function);
if (!isThisParam) {
commitVariable(var, pointerDT, isThisParam);
}
return true;
}
catch (Exception e) {
Msg.showError(this, null, "Auto Create Structure Failed",
"Failed to create Structure variable", e);
}
return false;
}
/**
* Retype the HighVariable to a given data-type to the database
* @param var is the decompiler variable to retype
* @param newDt is the data-type
* @param isThisParam is true if the variable is a 'this' pointer
*/
private void commitVariable(HighVariable var, DataType newDt, boolean isThisParam) {
if (!isThisParam) {
try {
HighFunctionDBUtil.updateDBVariable(var.getSymbol(), null, newDt,
SourceType.USER_DEFINED);
}
catch (DuplicateNameException e) {
throw new AssertException("Unexpected exception", e);
}
catch (InvalidInputException e) {
Msg.error(this,
"Failed to re-type variable " + var.getName() + ": " + e.getMessage());
}
}
}
/**
* Compute the storage address associated with a particular Location
* @param function is the function owning the location
* @return the corresponding storage address or null
*/
private Address computeStorageAddress(Function function) {
Address storageAddress = null;
// make sure what we are over can be mapped to decompiler
// param, local, etc...
if (location instanceof VariableLocation) {
VariableLocation varLoc = (VariableLocation) location;
storageAddress = varLoc.getVariable().getVariableStorage().getMinAddress();
}
else if (location instanceof FunctionParameterFieldLocation) {
FunctionParameterFieldLocation funcPFL = (FunctionParameterFieldLocation) location;
storageAddress = funcPFL.getParameter().getVariableStorage().getMinAddress();
}
return storageAddress;
}
}
@@ -21,14 +21,16 @@ import java.awt.event.KeyEvent;
import docking.ActionContext;
import docking.action.*;
import ghidra.app.context.ListingActionContext;
import ghidra.app.decompiler.DecompileOptions;
import ghidra.app.decompiler.component.DecompilerController;
import ghidra.app.decompiler.component.DecompilerUtils;
import ghidra.app.decompiler.util.FillOutStructureCmd;
import ghidra.app.decompiler.util.FillOutStructureHelper;
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
import ghidra.app.util.HelpTopics;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.HighParam;
import ghidra.program.model.pcode.HighVariable;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
import ghidra.util.HelpLocation;
import ghidra.util.Msg;
@@ -47,46 +49,6 @@ public abstract class CreateStructureVariableAction extends DockingAction {
setKeyBindingData(new KeyBindingData(KeyEvent.VK_OPEN_BRACKET, InputEvent.SHIFT_DOWN_MASK));
}
static boolean testForAutoParameterThis(HighVariable var, Function f) {
if (var instanceof HighParam) {
int slot = ((HighParam) var).getSlot();
Parameter parameter = f.getParameter(slot);
if ((parameter != null) &&
(parameter.getAutoParameterType() == AutoParameterType.THIS)) {
return true;
}
}
return false;
}
/**
* Check if a variable has a data-type that is suitable for being extended.
* If so return the structure data-type, otherwise return null.
* Modulo typedefs, the data-type of the variable must be exactly a
* "pointer to a structure". Not a "structure" itself, or a
* "pointer to a pointer to ... a structure".
* @param dt is the data-type of the variable to test
* @return the extendable structure data-type or null
*/
public static Structure getStructureForExtending(DataType dt) {
if (dt instanceof TypeDef) {
dt = ((TypeDef) dt).getBaseDataType();
}
if (dt instanceof Pointer) {
dt = ((Pointer) dt).getDataType();
}
else {
return null;
}
if (dt instanceof TypeDef) {
dt = ((TypeDef) dt).getBaseDataType();
}
if (dt instanceof Structure) {
return (Structure) dt;
}
return null;
}
@Override
public abstract boolean isEnabledForContext(ActionContext context);
@@ -98,7 +60,7 @@ public abstract class CreateStructureVariableAction extends DockingAction {
*/
protected void adjustCreateStructureMenuText(DataType dt, boolean isThisParam) {
dt = getStructureForExtending(dt);
dt = FillOutStructureHelper.getStructureForExtending(dt);
String menuString = "Auto Create Structure";
if (dt != null) {
if (isThisParam) {
@@ -145,7 +107,8 @@ public abstract class CreateStructureVariableAction extends DockingAction {
return;
}
FillOutStructureCmd task = new FillOutStructureCmd(program, location, tool);
task.applyTo(program);
DecompileOptions decompileOptions = DecompilerUtils.getDecompileOptions(tool, program);
FillOutStructureCmd cmd = new FillOutStructureCmd(location, decompileOptions);
tool.executeBackgroundCommand(cmd, program);
}
}
@@ -17,8 +17,7 @@ package ghidra.app.plugin.core.decompile.actions;
import docking.ActionContext;
import ghidra.app.decompiler.ClangToken;
import ghidra.app.decompiler.component.DecompilerController;
import ghidra.app.decompiler.component.DecompilerPanel;
import ghidra.app.decompiler.component.*;
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.data.DataType;
@@ -62,7 +61,7 @@ public class DecompilerStructureVariableAction extends CreateStructureVariableAc
HighVariable var = tokenAtCursor.getHighVariable();
if (var != null && !(var instanceof HighConstant)) {
dt = var.getDataType();
isThisParam = testForAutoParameterThis(var, function);
isThisParam = DecompilerUtils.testForAutoParameterThis(var, function);
}
if (dt == null || dt.getLength() > maxPointerSize) {
@@ -20,18 +20,16 @@ import java.util.*;
import org.apache.commons.lang3.StringUtils;
import docking.options.OptionsService;
import generic.cache.CachingPool;
import generic.cache.CountingBasicFactory;
import generic.concurrent.QCallback;
import ghidra.GhidraOptions;
import ghidra.app.decompiler.*;
import ghidra.app.decompiler.DecompileOptions.CommentStyleEnum;
import ghidra.app.decompiler.component.DecompilerUtils;
import ghidra.app.decompiler.parallel.ChunkingParallelDecompiler;
import ghidra.app.decompiler.parallel.ParallelDecompiler;
import ghidra.app.util.*;
import ghidra.framework.model.DomainObject;
import ghidra.framework.options.ToolOptions;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.*;
@@ -245,20 +243,8 @@ public class CppExporter extends Exporter {
private void configureOptions(Program program) {
if (!userSuppliedOptions) {
options = new DecompileOptions();
if (provider != null) {
OptionsService service = provider.getService(OptionsService.class);
if (service != null) {
ToolOptions fieldOptions =
service.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
ToolOptions opt = service.getOptions("Decompiler");
options.grabFromToolAndProgram(fieldOptions, opt, program);
}
}
else {
options.grabFromProgram(program); // Let headless pull program specific options
}
options = DecompilerUtils.getDecompileOptions(provider, program);
if (isUseCppStyleComments) {
options.setCommentStyle(CommentStyleEnum.CPPStyle);
@@ -27,7 +27,6 @@ import ghidra.app.util.pdb.pdbapplicator.DefaultPdbApplicator;
import ghidra.app.util.pdb.pdbapplicator.PdbApplicatorOptions;
import ghidra.framework.*;
import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject;
import ghidra.framework.options.OptionType;
import ghidra.framework.options.Options;
import ghidra.program.model.address.AddressSetView;
@@ -192,9 +191,8 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
* @throws CancelledException upon user cancellation
*/
public static boolean doAnalysis(Program program, File pdbFile,
PdbReaderOptions pdbReaderOptions,
PdbApplicatorOptions pdbApplicatorOptions, MessageLog log, TaskMonitor monitor)
throws CancelledException {
PdbReaderOptions pdbReaderOptions, PdbApplicatorOptions pdbApplicatorOptions,
MessageLog log, TaskMonitor monitor) throws CancelledException {
PdbLog.message(
"================================================================================");
PdbLog.message(new Date(System.currentTimeMillis()).toString() + "\n");
@@ -236,8 +234,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
AnalysisPriority.DATA_TYPE_PROPOGATION.after().after().after().priority());
// Following is intended to be the last PDB analysis background command
aam.schedule(
new PdbReportingBackgroundCommand(),
aam.schedule(new PdbReportingBackgroundCommand(),
AnalysisPriority.DATA_TYPE_PROPOGATION.after().after().after().after().priority());
}
@@ -340,7 +337,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
* local variables and other things that might make sense to process in the first phase
* (for now, they will be in the second phase).
*/
private static class ProcessPdbFunctionInternalsCommand extends BackgroundCommand {
private static class ProcessPdbFunctionInternalsCommand extends BackgroundCommand<Program> {
File pdbFile;
private PdbReaderOptions pdbReaderOptions;
@@ -357,14 +354,13 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
}
@Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
Program program = (Program) obj;
public boolean applyTo(Program program, TaskMonitor monitor) {
try (AbstractPdb pdb = PdbParser.parse(pdbFile, pdbReaderOptions, monitor)) {
monitor.setMessage("PDB: Parsing " + pdbFile + "...");
pdb.deserialize();
DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdb, program,
program.getDataTypeManager(), program.getImageBase(), pdbApplicatorOptions,
log);
DefaultPdbApplicator applicator =
new DefaultPdbApplicator(pdb, program, program.getDataTypeManager(),
program.getImageBase(), pdbApplicatorOptions, log);
applicator.applyFunctionInternalsAnalysis();
return true;
}
@@ -382,15 +378,14 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
/**
* A background command that performs final PDB analysis reporting.
*/
private static class PdbReportingBackgroundCommand extends BackgroundCommand {
private static class PdbReportingBackgroundCommand extends BackgroundCommand<Program> {
public PdbReportingBackgroundCommand() {
super("PDB Universal Reporting", false, false, false);
}
@Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
Program program = (Program) obj;
public boolean applyTo(Program program, TaskMonitor monitor) {
try {
DefaultPdbApplicator.applyAnalysisReporting(program);
return true;
@@ -16,11 +16,15 @@
*/
package ghidra.app.plugin.core.diff;
import java.lang.reflect.InvocationTargetException;
import javax.swing.SwingUtilities;
import docking.widgets.dialogs.ReadTextDialog;
import ghidra.app.events.ProgramSelectionPluginEvent;
import ghidra.app.plugin.core.analysis.AnalysisWorker;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
@@ -28,17 +32,11 @@ import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import java.lang.reflect.InvocationTargetException;
import javax.swing.SwingUtilities;
import docking.widgets.dialogs.ReadTextDialog;
/**
* Command to apply diffs to current program.
*
*/
class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
class ApplyDiffCommand extends BackgroundCommand<Program> implements AnalysisWorker {
private AddressSetView p1AddressSet;
private DiffController diffControl;
@@ -47,9 +45,6 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
private boolean applied;
private ProgramDiffPlugin plugin;
/**
* Constructor.
*/
ApplyDiffCommand(ProgramDiffPlugin plugin, AddressSetView program1AddressSet,
DiffController diffControl) {
super("Apply Differences", false, true, true);
@@ -59,8 +54,8 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
}
@Override
public boolean analysisWorkerCallback(Program program, Object workerContext, TaskMonitor monitor)
throws Exception, CancelledException {
public boolean analysisWorkerCallback(Program program, Object workerContext,
TaskMonitor monitor) throws Exception, CancelledException {
// Diff apply done with analysis disabled
return diffControl.apply(p1AddressSet, monitor);
}
@@ -70,11 +65,8 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
return getName();
}
/**
* @see ghidra.framework.cmd.BackgroundCommand#applyTo(ghidra.framework.model.DomainObject, ghidra.util.task.TaskMonitor)
*/
@Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
public boolean applyTo(Program program, TaskMonitor monitor) {
monitor.setMessage("ApplyDiffTask starting...");
applied = false;
final ProgramLocation origLocation = plugin.getProgramLocation();
@@ -90,9 +82,8 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
AutoAnalysisManager.getAnalysisManager(plugin.getFirstProgram());
boolean merged = autoAnalysisManager.scheduleWorker(this, null, false, monitor);
if (merged) {
statusMsg =
"Apply differences has finished."
+ " If your expected change didn't occur, check your Diff Apply Settings.";
statusMsg = "Apply differences has finished." +
" If your expected change didn't occur, check your Diff Apply Settings.";
title = "Program Diff: Apply differences has finished.";
applied = true;
}
@@ -114,15 +105,14 @@ class ApplyDiffCommand extends BackgroundCommand implements AnalysisWorker {
}
}
Msg.showError(this, plugin.getListingPanel(), "Error Applying Diff",
"An error occurred while applying differences.\n"
+ "Only some of the differences may have been applied.",
"An error occurred while applying differences.\n" +
"Only some of the differences may have been applied.",
(t != null) ? t : e);
applyMsg = message + diffControl.getApplyMessage();
}
catch (CancelledException e) {
statusMsg =
"User cancelled \"Apply Differences\". "
+ "Differences were only partially applied.";
statusMsg = "User cancelled \"Apply Differences\". " +
"Differences were only partially applied.";
applyMsg = diffControl.getApplyMessage();
}
finally {