GP-4886 Fix stack analysis and return storage allocation.

This commit is contained in:
ghidra1 2024-11-18 19:31:16 -05:00
parent faacb6b6d8
commit f3eabcfb18
6 changed files with 75 additions and 78 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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