mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-4886 Fix stack analysis and return storage allocation.
This commit is contained in:
parent
faacb6b6d8
commit
f3eabcfb18
6 changed files with 75 additions and 78 deletions
|
@ -35,12 +35,15 @@ import ghidra.util.task.TaskMonitor;
|
|||
* NOTE: referenced thunk-functions should be created prior to this command
|
||||
*/
|
||||
public class FunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
||||
|
||||
private boolean dontCreateNewVariables = false;
|
||||
|
||||
private final boolean forceProcessing;
|
||||
private final boolean createStackParams;
|
||||
private final boolean createLocalStackVars;
|
||||
|
||||
private AddressSet entryPoints = new AddressSet();
|
||||
private Program program;
|
||||
private boolean forceProcessing = false;
|
||||
private boolean dontCreateNewVariables = false;
|
||||
private boolean doParams = false;
|
||||
private boolean doLocals = false;
|
||||
|
||||
static String DEFAULT_FUNCTION_COMMENT = " FUNCTION";
|
||||
|
||||
|
@ -52,7 +55,7 @@ public class FunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
|||
* has already been defined.
|
||||
*/
|
||||
public FunctionStackAnalysisCmd(AddressSetView entries, boolean forceProcessing) {
|
||||
this(entries, true, true, forceProcessing);
|
||||
this(entries, false, true, forceProcessing);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,7 +66,7 @@ public class FunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
|||
* has already been defined.
|
||||
*/
|
||||
public FunctionStackAnalysisCmd(Address entry, boolean forceProcessing) {
|
||||
this(new AddressSet(entry, entry), true, true, forceProcessing);
|
||||
this(new AddressSet(entry, entry), false, true, forceProcessing);
|
||||
}
|
||||
|
||||
public FunctionStackAnalysisCmd(AddressSetView entries, boolean doParameterAnalysis,
|
||||
|
@ -71,8 +74,8 @@ public class FunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
|||
super("Create Function Stack Variables", true, true, false);
|
||||
entryPoints.add(entries);
|
||||
this.forceProcessing = forceProcessing;
|
||||
doParams = doParameterAnalysis;
|
||||
doLocals = doLocalAnalysis;
|
||||
createStackParams = doParameterAnalysis;
|
||||
createLocalStackVars = doLocalAnalysis;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -354,10 +357,10 @@ public class FunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
|||
Variable var = frame.getVariableContaining(frameLoc);
|
||||
if (var == null) {
|
||||
try {
|
||||
if (!doLocals && frameLoc <= 0) {
|
||||
if (!createLocalStackVars && frameLoc <= 0) {
|
||||
return null;
|
||||
}
|
||||
if (!doParams && frameLoc > 0) {
|
||||
if (!createStackParams && frameLoc > 0) {
|
||||
return null;
|
||||
}
|
||||
// only create variables at locations where a variable doesn't exist
|
||||
|
|
|
@ -43,46 +43,59 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
|||
private static final int MAX_PARAM_OFFSET = 2048; // max size of param reference space
|
||||
private static final int MAX_LOCAL_OFFSET = -(64 * 1024); // max size of local reference space
|
||||
|
||||
private boolean dontCreateNewVariables = false;
|
||||
|
||||
private final boolean forceProcessing;
|
||||
private final boolean createStackParams;
|
||||
private final boolean createLocalStackVars;
|
||||
|
||||
private AddressSet entryPoints = new AddressSet();
|
||||
private Program program;
|
||||
private boolean forceProcessing = false;
|
||||
private boolean dontCreateNewVariables = false;
|
||||
private boolean doParams = false;
|
||||
private boolean doLocals = false;
|
||||
private Register stackReg;
|
||||
private int purge = 0;
|
||||
|
||||
static String DEFAULT_FUNCTION_COMMENT = " FUNCTION";
|
||||
|
||||
/**
|
||||
* Constructs a new command for analyzing the Stack.
|
||||
* Constructs a new command for analyzing the Stack. All stack references will be
|
||||
* marked-up and local stack variables created. Stack parameters are not created
|
||||
* by default to avoid setting an incomplete function signature.
|
||||
* @param entries and address set indicating the entry points of functions that have
|
||||
* stacks to be analyzed.
|
||||
* @param forceProcessing flag to force processing of stack references even if the stack
|
||||
* has already been defined.
|
||||
*/
|
||||
public NewFunctionStackAnalysisCmd(AddressSetView entries, boolean forceProcessing) {
|
||||
this(entries, true, true, forceProcessing);
|
||||
this(entries, false, true, forceProcessing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new command for analyzing the Stack.
|
||||
* Constructs a new command for analyzing the Stack. All stack references will be
|
||||
* marked-up and local stack variables created. Stack parameters are not created
|
||||
* by default to avoid setting an incomplete function signature.
|
||||
* @param entry the entry point of the function that contains the stack to
|
||||
* be analyzed.
|
||||
* @param forceProcessing flag to force processing of stack references even if the stack
|
||||
* has already been defined.
|
||||
*/
|
||||
public NewFunctionStackAnalysisCmd(Address entry, boolean forceProcessing) {
|
||||
this(new AddressSet(entry, entry), true, true, forceProcessing);
|
||||
this(new AddressSet(entry, entry), false, true, forceProcessing);
|
||||
}
|
||||
|
||||
public NewFunctionStackAnalysisCmd(AddressSetView entries, boolean doParameterAnalysis,
|
||||
boolean doLocalAnalysis, boolean forceProcessing) {
|
||||
/**
|
||||
*
|
||||
* @param entries
|
||||
* @param createStackParams
|
||||
* @param createLocalStackVars
|
||||
* @param forceProcessing
|
||||
*/
|
||||
public NewFunctionStackAnalysisCmd(AddressSetView entries, boolean createStackParams,
|
||||
boolean createLocalStackVars, boolean forceProcessing) {
|
||||
super("Create Function Stack Variables", true, true, false);
|
||||
entryPoints.add(entries);
|
||||
this.forceProcessing = forceProcessing;
|
||||
doParams = doParameterAnalysis;
|
||||
doLocals = doLocalAnalysis;
|
||||
this.createStackParams = createStackParams;
|
||||
this.createLocalStackVars = createLocalStackVars;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -479,8 +492,6 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
|||
|
||||
}
|
||||
|
||||
private static final int MAX_PARAM_FILLIN_COUNT = 10;
|
||||
|
||||
private int addMissingParameters(Variable stackVar, int nextCopyParamIndex,
|
||||
Parameter[] oldParamList, List<Variable> newParamList, PrototypeModel callingConvention,
|
||||
boolean hasStackParams) {
|
||||
|
@ -516,37 +527,6 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
|||
++nextCopyParamIndex;
|
||||
}
|
||||
|
||||
// fill-in missing params - don't bother if we already have
|
||||
// too many or no stack param block defined
|
||||
int nextOrdinal = newParamList.size();
|
||||
if ((!hasStackParams) || nextOrdinal >= MAX_PARAM_FILLIN_COUNT) {
|
||||
return nextCopyParamIndex;
|
||||
}
|
||||
|
||||
VariableStorage argLocation;
|
||||
try {
|
||||
Parameter[] params = new Parameter[nextOrdinal];
|
||||
argLocation = callingConvention.getArgLocation(nextOrdinal,
|
||||
newParamList.toArray(params), DataType.DEFAULT, program);
|
||||
while (!argLocation.intersects(stackVar.getVariableStorage()) &&
|
||||
nextOrdinal < MAX_PARAM_FILLIN_COUNT) {
|
||||
// TODO: it feels bad to add a bunch of register variables
|
||||
Parameter p = new ParameterImpl(null, DataType.DEFAULT, argLocation, program);
|
||||
newParamList.add(p);
|
||||
++nextOrdinal;
|
||||
params = new Parameter[nextOrdinal];
|
||||
argLocation = callingConvention.getArgLocation(nextOrdinal,
|
||||
newParamList.toArray(params), DataType.DEFAULT, program);
|
||||
}
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
throw new RuntimeException(e); // unexpected
|
||||
}
|
||||
|
||||
if (!argLocation.isStackStorage()) {
|
||||
return nextCopyParamIndex;
|
||||
}
|
||||
|
||||
return nextCopyParamIndex;
|
||||
}
|
||||
|
||||
|
@ -792,10 +772,10 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
|||
(growsNegative && offset >= paramOffset) || (!growsNegative && offset <= paramOffset);
|
||||
|
||||
// Check exclusion options
|
||||
if (!doLocals && !isParam) {
|
||||
if (!createLocalStackVars && !isParam) {
|
||||
return;
|
||||
}
|
||||
if (!doParams && isParam) {
|
||||
if (!createStackParams && isParam) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,8 +31,8 @@ public class StackVariableAnalyzer extends AbstractAnalyzer {
|
|||
private static final String DESCRIPTION = "Creates stack variables for a function.";
|
||||
|
||||
private boolean doNewStackAnalysis = true;
|
||||
private boolean doLocalAnalysis = true;
|
||||
private boolean doParameterAnalysis = true;
|
||||
private boolean doCreateLocalStackVars = true;
|
||||
private boolean doCreateStackParams = false;
|
||||
|
||||
public StackVariableAnalyzer() {
|
||||
super(NAME, DESCRIPTION, AnalyzerType.FUNCTION_ANALYZER);
|
||||
|
@ -43,13 +43,15 @@ public class StackVariableAnalyzer extends AbstractAnalyzer {
|
|||
|
||||
@Override
|
||||
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) {
|
||||
BackgroundCommand cmd;
|
||||
BackgroundCommand<Program> cmd;
|
||||
|
||||
if (doNewStackAnalysis) {
|
||||
cmd = new NewFunctionStackAnalysisCmd(set, doParameterAnalysis, doLocalAnalysis, false);
|
||||
cmd = new NewFunctionStackAnalysisCmd(set, doCreateStackParams, doCreateLocalStackVars,
|
||||
false);
|
||||
}
|
||||
else {
|
||||
cmd = new FunctionStackAnalysisCmd(set, doParameterAnalysis, doLocalAnalysis, false);
|
||||
cmd = new FunctionStackAnalysisCmd(set, doCreateStackParams, doCreateLocalStackVars,
|
||||
false);
|
||||
}
|
||||
|
||||
cmd.applyTo(program, monitor);
|
||||
|
@ -73,10 +75,10 @@ public class StackVariableAnalyzer extends AbstractAnalyzer {
|
|||
!useOldStackAnalysisByDefault(program), null,
|
||||
"Use General Stack Reference Propogator (This works best on most processors)");
|
||||
|
||||
options.registerOption("Create Local Variables", doLocalAnalysis, null,
|
||||
options.registerOption("Create Local Variables", doCreateLocalStackVars, null,
|
||||
"Create Function Local stack variables and references");
|
||||
|
||||
options.registerOption("Create Param Variables", doParameterAnalysis, null,
|
||||
options.registerOption("Create Param Variables", doCreateStackParams, null,
|
||||
"Create Function Parameter stack variables and references");
|
||||
}
|
||||
|
||||
|
@ -86,9 +88,10 @@ public class StackVariableAnalyzer extends AbstractAnalyzer {
|
|||
options.getBoolean(GhidraLanguagePropertyKeys.USE_NEW_FUNCTION_STACK_ANALYSIS,
|
||||
!useOldStackAnalysisByDefault(program));
|
||||
|
||||
doLocalAnalysis = options.getBoolean("Create Local Variables", doLocalAnalysis);
|
||||
doCreateLocalStackVars =
|
||||
options.getBoolean("Create Local Variables", doCreateLocalStackVars);
|
||||
|
||||
doParameterAnalysis = options.getBoolean("Create Param Variables", doParameterAnalysis);
|
||||
doCreateStackParams = options.getBoolean("Create Param Variables", doCreateStackParams);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -92,9 +92,13 @@ public class ClassicSampleX86ProgramBuilder extends ProgramBuilder {
|
|||
TestUtils.setInstanceField("isEnabled", analysisMgr, Boolean.FALSE);
|
||||
}
|
||||
else {
|
||||
// enable stack analysis
|
||||
// enable full stack analysis with variable/param creation
|
||||
startTransaction();
|
||||
p.getOptions(Program.ANALYSIS_PROPERTIES).setBoolean("Stack", true);
|
||||
p.getOptions(Program.ANALYSIS_PROPERTIES)
|
||||
.setBoolean("Stack.Create Local Variables", true);
|
||||
p.getOptions(Program.ANALYSIS_PROPERTIES)
|
||||
.setBoolean("Stack.Create Param Variables", true);
|
||||
endTransaction();
|
||||
}
|
||||
|
||||
|
|
|
@ -1273,12 +1273,18 @@ public class Function1Test extends AbstractGhidraHeadedIntegrationTest {
|
|||
Function f = createFunctionAtEntry();
|
||||
setCustomParameterStorage(f, true);
|
||||
|
||||
assertTrue(cb.goToField(addr("0x1006420"), "Variable Type", 0, 0));
|
||||
waitForSwing();
|
||||
|
||||
// Set location to param_1 datatype field
|
||||
assertTrue(cb.goToField(addr("0x1006420"), "Variable Type", 1, 0, 0));
|
||||
|
||||
waitForSwing();
|
||||
|
||||
performAction(chooseDataType, cb.getProvider(), false);
|
||||
DataTypeSelectionDialog dialog = waitForDialogComponent(DataTypeSelectionDialog.class);
|
||||
|
||||
setEditorText(dialog, "int[0x8888888]");
|
||||
// FIXME: Dialog does not appear to register type entry until it is dismissed
|
||||
|
||||
// For the test to pass, the status field should show an error message containing
|
||||
// the following text (this is only a part of the status message, but is enough
|
||||
|
|
|
@ -84,6 +84,7 @@ public class ParamListStandard implements ParamList {
|
|||
*/
|
||||
public int assignAddressFallback(StorageClass resource, DataType tp, boolean matchExact,
|
||||
int[] status, ParameterPieces param) {
|
||||
|
||||
for (ParamEntry element : entry) {
|
||||
int grp = element.getGroup();
|
||||
if (status[grp] < 0) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue