diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionStackAnalysisCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionStackAnalysisCmd.java index 5a9d32933a..61dd3cfdee 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionStackAnalysisCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionStackAnalysisCmd.java @@ -4,9 +4,9 @@ * 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. @@ -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 { + + 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 { * 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 { * 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 { 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 { 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 diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java index 337b84252d..1bb46f308b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java @@ -4,9 +4,9 @@ * 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. @@ -43,46 +43,59 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand { 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 { } - private static final int MAX_PARAM_FILLIN_COUNT = 10; - private int addMissingParameters(Variable stackVar, int nextCopyParamIndex, Parameter[] oldParamList, List newParamList, PrototypeModel callingConvention, boolean hasStackParams) { @@ -516,37 +527,6 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand { ++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 { (growsNegative && offset >= paramOffset) || (!growsNegative && offset <= paramOffset); // Check exclusion options - if (!doLocals && !isParam) { + if (!createLocalStackVars && !isParam) { return; } - if (!doParams && isParam) { + if (!createStackParams && isParam) { return; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackVariableAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackVariableAnalyzer.java index f5e46fb4c8..980ac20eaa 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackVariableAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackVariableAnalyzer.java @@ -4,9 +4,9 @@ * 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. @@ -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 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); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledDataType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledDataType.java index d6f907aa0e..0cc409fc72 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledDataType.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledDataType.java @@ -95,8 +95,8 @@ public class DemangledDataType extends DemangledType { private static final String UNSIGNED_LONG = "unsigned long"; public final static String[] PRIMITIVES = - { VOID, BOOL, CHAR, WCHAR_T, WCHAR16, WCHAR32, CHAR8_T, SHORT, INT, INT0_T, LONG, - LONG_LONG, FLOAT, FLOAT2, DOUBLE, INT128, FLOAT128, LONG_DOUBLE, }; + { VOID, BOOL, CHAR, WCHAR_T, WCHAR16, WCHAR32, CHAR8_T, SHORT, INT, INT0_T, LONG, LONG_LONG, + FLOAT, FLOAT2, DOUBLE, INT128, FLOAT128, LONG_DOUBLE, }; private int arrayDimensions = 0; private boolean isClass; @@ -200,10 +200,10 @@ public class DemangledDataType extends DemangledType { else if (dt == null) { // I don't know what this is - // If it isn't pointed to, or isn't a referent, then assume typedef. + // If it isn't pointed to, or isn't a referent, then assume undefined typedef. if (!(isReference() || isPointer())) { // Unknown type dt = new TypedefDataType(getDemanglerCategoryPath(getNamespace()), name, - new DWordDataType()); + DataType.DEFAULT); } else { // try creating empty structures for unknown types instead. diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/ClassicSampleX86ProgramBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/test/ClassicSampleX86ProgramBuilder.java index cc0a392c9c..4ff6903bea 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/test/ClassicSampleX86ProgramBuilder.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/ClassicSampleX86ProgramBuilder.java @@ -4,9 +4,9 @@ * 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. @@ -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(); } @@ -472,11 +476,11 @@ public class ClassicSampleX86ProgramBuilder extends ProgramBuilder { startTransaction(); StringDataType string = new StringDataType(); - DataType pointer = new Pointer32DataType(string); - Parameter p0 = new ParameterImpl("destStr", pointer, getProgram()); - Parameter p3 = new ParameterImpl("parm_3", DataType.DEFAULT, getProgram()); - Parameter p4 = new ParameterImpl("parm_4", DataType.DEFAULT, getProgram()); - createEmptyFunction("sscanf", "0x0100415a", 78, new Undefined1DataType(), p0, p3, p4); + DataType stringPtr = new Pointer32DataType(string); + Parameter p0 = new ParameterImpl("destStr", stringPtr, getProgram()); + Parameter p3 = new ParameterImpl("parm_3", Pointer32DataType.dataType, getProgram()); + Parameter p4 = new ParameterImpl("parm_4", Pointer32DataType.dataType, getProgram()); + createEmptyFunction("sscanf", "0x0100415a", 78, IntegerDataType.dataType, p0, p3, p4); ReferenceManager referenceManager = getProgram().getReferenceManager(); referenceManager.addStackReference(addr("0x0100416c"), 0, 0x4, RefType.READ, diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/TestEnv.java b/Ghidra/Features/Base/src/main/java/ghidra/test/TestEnv.java index 24262fb15e..d1e780aa57 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/test/TestEnv.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/TestEnv.java @@ -834,7 +834,7 @@ public class TestEnv { AbstractGuiTest.runSwing(() -> { tool = launchDefaultTool(); ProgramManager pm = tool.getService(ProgramManager.class); - pm.openProgram(program.getDomainFile()); + pm.openProgram(program); }); if (tool == null) { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/clipboard/CopyPasteFunctionInfoTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/clipboard/CopyPasteFunctionInfoTest.java index 71afa91362..71624f029a 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/clipboard/CopyPasteFunctionInfoTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/clipboard/CopyPasteFunctionInfoTest.java @@ -4,9 +4,9 @@ * 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. @@ -45,6 +45,7 @@ import ghidra.framework.plugintool.PluginTool; import ghidra.program.database.ProgramBuilder; import ghidra.program.model.address.Address; import ghidra.program.model.data.DataType; +import ghidra.program.model.data.Undefined4DataType; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.SourceType; import ghidra.program.model.symbol.Symbol; @@ -73,7 +74,7 @@ public class CopyPasteFunctionInfoTest extends AbstractGhidraHeadedIntegrationTe ToyProgramBuilder builder = new ToyProgramBuilder(name, true, ProgramBuilder._TOY); builder.createMemory("test1", "0x01001000", 0x8000); builder.createEntryPoint("0x1006420", "entry"); - DataType dt = DataType.DEFAULT; + DataType dt = Undefined4DataType.dataType; Parameter p = new ParameterImpl(null, dt, builder.getProgram()); builder.createEmptyFunction("ghidra", "0x1004600", 1, dt, p, p, p, p, p, p, p, p, p, p, p, p, p); @@ -87,7 +88,7 @@ public class CopyPasteFunctionInfoTest extends AbstractGhidraHeadedIntegrationTe builder.createEntryPoint("0x1006420", "entry"); builder.createFunction("0x1004700"); builder.createComment("0x1006420", "FUNCTION", CodeUnit.PLATE_COMMENT); - DataType dt = DataType.DEFAULT; + DataType dt = Undefined4DataType.dataType; Parameter p = new ParameterImpl(null, dt, builder.getProgram()); builder.createEmptyFunction("BOB", "0x1004260", 1, dt, p, p, p, p, p, p, p, p, p, p, p, p, p); @@ -481,8 +482,7 @@ public class CopyPasteFunctionInfoTest extends AbstractGhidraHeadedIntegrationTe private void resetOptions() { List names = fieldOptions2.getOptionNames(); - for (int i = 0; i < names.size(); i++) { - String name = names.get(i); + for (String name : names) { if (!name.startsWith("Format Code")) { continue; } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/AbstractEditorTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/AbstractEditorTest.java index 4296fa4dcd..f9ca443082 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/AbstractEditorTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/AbstractEditorTest.java @@ -358,7 +358,9 @@ public abstract class AbstractEditorTest extends AbstractGhidraHeadedIntegration } protected DataTypeComponent getComponent(int index) { - return runSwing(() -> model.getComponent(index)); + return runSwing(() -> + model.getComponent(index)); + } protected int getOffset(int index) { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/function/Function1Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/function/Function1Test.java index aeb77f0f54..0b944b870f 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/function/Function1Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/function/Function1Test.java @@ -39,6 +39,7 @@ import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.data.DataPlugin; import ghidra.app.plugin.core.disassembler.DisassemblerPlugin; import ghidra.app.plugin.core.highlight.SetHighlightPlugin; +import ghidra.app.plugin.core.instructionsearch.model.InstructionSearchData.UpdateType; import ghidra.app.plugin.core.navigation.*; import ghidra.app.services.ProgramManager; import ghidra.app.util.AddEditDialog; @@ -52,6 +53,7 @@ import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressFactory; import ghidra.program.model.data.*; import ghidra.program.model.listing.*; +import ghidra.program.model.listing.Function.FunctionUpdateType; import ghidra.program.model.symbol.*; import ghidra.program.util.ProgramSelection; import ghidra.test.*; @@ -1286,9 +1288,19 @@ public class Function1Test extends AbstractGhidraHeadedIntegrationTest { env.showTool(); loadProgram("notepad"); Function f = createFunctionAtEntry(); + // Test requires a size-constrained register variable edit + program.withTransaction("Update Signature", + () -> f.updateFunction(null, null, FunctionUpdateType.CUSTOM_STORAGE, true, + SourceType.ANALYSIS, new ParameterImpl("test", Undefined4DataType.dataType, + program.getRegister("EBX"), program))); 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); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesPlugin3Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesPlugin3Test.java index e41b5c1af1..12f0f09cda 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesPlugin3Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesPlugin3Test.java @@ -106,7 +106,7 @@ public class LocationReferencesPlugin3Test extends AbstractLocationReferencesTes // 0100415a - sscanf Address address = addr(0x0100415a); - int parameterColumn = 28; // param 0's name + int parameterColumn = 24; // param 0's name goTo(address, "Function Signature", parameterColumn); search(); @@ -142,7 +142,7 @@ public class LocationReferencesPlugin3Test extends AbstractLocationReferencesTes // 0100415a - sscanf Address address = addr(0x0100415a); - int parameterColumn = 11; + int parameterColumn = 7; goTo(address, "Function Signature", parameterColumn); search(); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/searchtext/ListingDisplaySearcherTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/searchtext/ListingDisplaySearcherTest.java index 876e3e58af..a08d26cf54 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/searchtext/ListingDisplaySearcherTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/searchtext/ListingDisplaySearcherTest.java @@ -4,9 +4,9 @@ * 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. @@ -142,7 +142,7 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT // example // dword ptr param, EAX - String searchText = "param"; + String searchText = "local_"; SearchOptions options = new SearchOptions(searchText, false, true, false); searcher = new ListingDisplaySearcher(tool, program, startLoc, null, options, TaskMonitor.DUMMY); @@ -163,7 +163,7 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT // example // dword ptr param, EAX - String searchText = "param"; + String searchText = "local_"; SearchOptions options = new SearchOptions(searchText, false, false, false); searcher = @@ -187,17 +187,21 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT // example // dword ptr param, EAX - SearchOptions options = new SearchOptions("param", false, false, false, false, true, true, + SearchOptions options = new SearchOptions("local_", false, false, false, false, true, true, false, false, false, true, false, false); searcher = new ListingDisplaySearcher(tool, program, startLoc, null, options, TaskMonitor.DUMMY); //set up list of answers ArrayList
startList = new ArrayList<>(); - startList.add(addr(0x0100416c)); - startList.add(addr(0x01004186)); - startList.add(addr(0x01004189)); - startList.add(addr(0x0100419c)); + startList.add(addr(0x01004162)); + startList.add(addr(0x01004169)); + startList.add(addr(0x0100416f)); + startList.add(addr(0x01004178)); + startList.add(addr(0x0100417c)); + startList.add(addr(0x01004180)); + startList.add(addr(0x01004196)); + startList.add(addr(0x010041a1)); //check that the text is found there in the correct field checkTextFound(startList, OperandFieldLocation.class); @@ -268,11 +272,9 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT int transactionID = program.startTransaction("test"); try { DataType dt = program.getDataTypeManager() - .addDataType(struct, - DataTypeConflictHandler.DEFAULT_HANDLER); + .addDataType(struct, DataTypeConflictHandler.DEFAULT_HANDLER); floatDt = program.getDataTypeManager() - .addDataType(new FloatDataType(), - DataTypeConflictHandler.DEFAULT_HANDLER); + .addDataType(new FloatDataType(), DataTypeConflictHandler.DEFAULT_HANDLER); listing.createData(addr(0x0100689b), dt); listing.createData(addr(0x0100688c), floatDt); listing.createData(addr(0x01006890), floatDt); @@ -347,11 +349,9 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT int transactionID = program.startTransaction("test"); try { DataType dt = program.getDataTypeManager() - .addDataType(struct, - DataTypeConflictHandler.DEFAULT_HANDLER); + .addDataType(struct, DataTypeConflictHandler.DEFAULT_HANDLER); floatDt = program.getDataTypeManager() - .addDataType(new FloatDataType(), - DataTypeConflictHandler.DEFAULT_HANDLER); + .addDataType(new FloatDataType(), DataTypeConflictHandler.DEFAULT_HANDLER); listing.createData(addr(0x0100689b), dt); listing.createData(addr(0x0100688c), floatDt); listing.createData(addr(0x01006890), floatDt); @@ -437,11 +437,9 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT int transactionID = program.startTransaction("test"); try { DataType dt = program.getDataTypeManager() - .addDataType(struct, - DataTypeConflictHandler.DEFAULT_HANDLER); + .addDataType(struct, DataTypeConflictHandler.DEFAULT_HANDLER); floatDt = program.getDataTypeManager() - .addDataType(new FloatDataType(), - DataTypeConflictHandler.DEFAULT_HANDLER); + .addDataType(new FloatDataType(), DataTypeConflictHandler.DEFAULT_HANDLER); listing.createData(addr(0x0100689b), dt); listing.createData(addr(0x0100688c), floatDt); listing.createData(addr(0x01006890), floatDt); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/function/editor/FunctionEditorModelTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/function/editor/FunctionEditorModelTest.java index 18541d0844..bd295ad46e 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/function/editor/FunctionEditorModelTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/function/editor/FunctionEditorModelTest.java @@ -4,9 +4,9 @@ * 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. @@ -492,9 +492,10 @@ public class FunctionEditorModelTest extends AbstractGuiTest { public void testAutoStorageFix() { model.addParameter(); ParamInfo paramInfo = model.getParameters().get(0);// param_0@Stack[0x4]:4 + model.setParameterFormalDataType(paramInfo, IntegerDataType.dataType); model.setUseCustomizeStorage(true); Varnode v = paramInfo.getStorage().getFirstVarnode(); - assertEquals(1, v.getSize()); + assertEquals(4, v.getSize()); assertEquals(4, v.getOffset()); model.setParameterFormalDataType(paramInfo, new Undefined8DataType()); assertTrue(model.isValid()); @@ -507,9 +508,9 @@ public class FunctionEditorModelTest extends AbstractGuiTest { public void testAutoStorageFixReg() throws Exception { model.addParameter(); ParamInfo paramInfo = model.getParameters().get(0); + model.setParameterFormalDataType(paramInfo, new Undefined2DataType()); model.setUseCustomizeStorage(true); - model.setParameterFormalDataType(paramInfo, new Undefined2DataType()); assertTrue(model.getStatusText(), model.isValid()); Varnode v = paramInfo.getStorage().getFirstVarnode(); assertEquals(2, v.getSize()); @@ -1046,7 +1047,7 @@ public class FunctionEditorModelTest extends AbstractGuiTest { param = model.getParameters().get(3); assertEquals("param_2", param.getName()); assertTrue(DefaultDataType.dataType.isEquivalent(param.getDataType())); - assertEquals("Stack[0xc]:1", param.getStorage().toString()); + assertEquals("", param.getStorage().toString()); model.setParameterFormalDataType(param, struct); @@ -1156,7 +1157,7 @@ public class FunctionEditorModelTest extends AbstractGuiTest { param = model.getParameters().get(3); assertEquals("param_2", param.getName()); assertTrue(DefaultDataType.dataType.isEquivalent(param.getDataType())); - assertEquals("R9B:1", param.getStorage().toString()); + assertEquals("", param.getStorage().toString()); model.setParameterFormalDataType(param, struct); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/program/util/ConstantPropogationReferenceTest.java b/Ghidra/Features/Base/src/test/java/ghidra/program/util/ConstantPropogationReferenceTest.java index e551d72f42..6015ab4681 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/program/util/ConstantPropogationReferenceTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/program/util/ConstantPropogationReferenceTest.java @@ -24,19 +24,17 @@ import org.junit.Test; import generic.test.AbstractGenericTest; import ghidra.app.plugin.core.analysis.ConstantPropagationAnalyzer; import ghidra.app.plugin.core.analysis.ConstantPropagationContextEvaluator; -import ghidra.framework.store.LockException; import ghidra.program.database.ProgramBuilder; -import ghidra.program.model.address.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressSet; import ghidra.program.model.lang.Register; import ghidra.program.model.lang.RegisterValue; import ghidra.program.model.listing.*; import ghidra.program.model.mem.MemoryBlock; -import ghidra.program.model.mem.MemoryConflictException; import ghidra.program.model.pcode.Varnode; import ghidra.program.model.symbol.Reference; import ghidra.program.model.symbol.ReferenceIterator; import ghidra.program.util.SymbolicPropogator.Value; -import ghidra.util.exception.CancelledException; import ghidra.util.exception.NotFoundException; import ghidra.util.task.TaskMonitor; @@ -57,12 +55,12 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest { public ConstantPropogationReferenceTest() { super(); } - + @Test - public void testOperandRef_MIPS6432() throws Exception { - + public void testOperandRef_MIPS6432() throws Exception { + builder = new ProgramBuilder("MIPS_6432", "MIPS:BE:64:64-32addr"); - + // lui v0, 0x80a8 // addiu v0, v0, -0xdf0 // sw v0, -0x46e8(gp) @@ -75,7 +73,7 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest { program = builder.getProgram(); program.startTransaction("Test"); - + Address codeStart = addr("0x80a7f214"); Listing listing = program.getListing(); assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart)); @@ -93,18 +91,19 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest { assertOperandReferenceTo(1, instr, addr("0x8fffb918")); } - + @Test public void testBadAddressOffsetTracking() throws Exception { builder = new ProgramBuilder("thunk", ProgramBuilder._MIPS); - builder.setBytes("0x1000", "3c 1c 00 14 27 9c b3 34 03 99 e0 21 27 bd ff e0" + - "af bc 00 10 3c 07 12 34 24 e7 45 67 ac a7 00 10" + - "3c 06 0a 0b 24 c6 0c 0d ae 06 00 10 8e 11 00 10" + - "8c b1 00 10 8f b1 00 10 8e 51 00 10 ae 53 00 10" + - "8e 51 00 10 36 92 00 00 8e 51 00 10 8e 92 00 10" + - "3c 11 00 53 8e 51 00 10 03 e0 00 08 27 bd 00 20"); + builder.setBytes("0x1000", + "3c 1c 00 14 27 9c b3 34 03 99 e0 21 27 bd ff e0" + + "af bc 00 10 3c 07 12 34 24 e7 45 67 ac a7 00 10" + + "3c 06 0a 0b 24 c6 0c 0d ae 06 00 10 8e 11 00 10" + + "8c b1 00 10 8f b1 00 10 8e 51 00 10 ae 53 00 10" + + "8e 51 00 10 36 92 00 00 8e 51 00 10 8e 92 00 10" + + "3c 11 00 53 8e 51 00 10 03 e0 00 08 27 bd 00 20"); //00001000 lui gp,0x14 //00001004 addiu gp,gp,-0x4ccc @@ -123,29 +122,29 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest { //00001038 lw s1,0x10(s2) //0000103c sw s3,0x10(s2) //00001040 lw s1,0x10(s2) - //00001044 ori s2,s4,0x0 - //00001048 lw s1,0x10(s2) + //00001044 ori s2,s4,0x0 + //00001048 lw s1,0x10(s2) //0000104c lw s2,0x10(s4) //00001050 lui s1=>DAT_00530000,0x53 //00001054 lw s1,0x10(s2) //00001058 jr ra //0000105c _addiu sp,sp,0x20 - + builder.disassemble("0x1000", 88, false); - + builder.createFunction("0x1000"); - + analyzer = new ConstantPropagationAnalyzer(); - + program = builder.getProgram(); program.startTransaction("Test"); - + Address codeStart = addr("0x1000"); Listing listing = program.getListing(); assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart)); - + setRegister(addr("0x1000"), "gp", 0x11200000); - + // follow all flows building up context // use context to fill out addresses on certain instructions ContextEvaluator eval = new ConstantPropagationContextEvaluator(TaskMonitor.DUMMY, true) { @@ -165,116 +164,122 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest { String loc = instr.getMinAddress().toString(); Varnode registerVarnode; - switch(loc) { - case "00001010": - // gp should be 0x14 + t9 offset space - registerVarnode = regValue(context,"gp"); - assertTrue("symbolic value", context.isSymbol(registerVarnode)); - assertEquals("(t9, 0x13b334, 4)", registerVarnode.toString()); - // S3 should be S3 at entry - registerVarnode = regValue(context,"s3"); - assertTrue("register s3", context.isRegister(registerVarnode)); - assertEquals("s3", context.getRegister(registerVarnode).getName()); - break; - case "0000102c": - // s1 restored from space 0x10(s0) space - registerVarnode = regValue(context,"s1"); - assertTrue("constant value", registerVarnode.isConstant()); - assertEquals("(const, 0xa0b0c0d, 4)", registerVarnode.toString()); - break; - case "00001030": - // s1 restored from space 0x10(a1) space - registerVarnode = regValue(context,"s1"); - assertTrue("symbolic value", registerVarnode.isConstant()); - assertEquals("(const, 0x12344567, 4)", registerVarnode.toString()); - break; - case "00001034": - // s1 restored from space 0x10(sp) space - registerVarnode = regValue(context,"s1"); - assertTrue("symbolic value", context.isSymbol(registerVarnode)); - assertEquals("(t9, 0x13b334, 4)", registerVarnode.toString()); - break; - case "00001038": - // s1 restored from space 0x10(s2) space - registerVarnode = regValue(context,"s1"); - //assertTrue("Still s1", registerVarnode.isRegister()); - boolean isBad = false; - try { - context.getConstant(registerVarnode, null); - } catch (NotFoundException e) { - isBad = true; - } - assertTrue("Can get constant value", isBad); - break; - case "00001040": - // s1 restored from space 0x10(s2) space - stored a3 - registerVarnode = regValue(context,"s1"); - assertTrue("register s3", registerVarnode.isRegister()); - assertEquals("s3", context.getRegister(registerVarnode).getName()); - - Address lastSetLocation = context.getLastSetLocation(context.getRegisterVarnode(context.getRegister("s2")), null); - assertEquals("s2 last set", null, lastSetLocation); - break; - case "00001048": - // s1 restored from space 0x10(s2) after s2 has been set again - // it should no longer be s3 that was stored in another s2 relative space - registerVarnode = regValue(context,"s1"); - //assertTrue("Still s1", registerVarnode.isRegister()); - isBad = false; - try { - context.getConstant(registerVarnode, null); - } catch (NotFoundException e) { - isBad = true; - } - assertTrue("Can get constant value", isBad); - break; - case "0000104c": - // s1 restored from space 0x10(s2) after s2 has been set again - // it should no longer be s3 that was stored in another s2 relative space - registerVarnode = regValue(context,"s2"); - //assertTrue("Still s2", registerVarnode.isRegister()); - isBad = false; - try { - context.getConstant(registerVarnode, null); - } catch (NotFoundException e) { - isBad = true; - } - assertTrue("Can get constant value", isBad); - lastSetLocation = context.getLastSetLocation(context.getRegisterVarnode(context.getRegister("s2")), null); - assertEquals("s2 last set", 0x104fL, lastSetLocation.getOffset()); - break; - case "00001054": - // s1 restored from space 0x10(s2) after s2 has been set again - // it should no longer be s3 that was stored in another s2 relative space - registerVarnode = regValue(context,"s1"); - //assertTrue("Still s1", registerVarnode.isRegister()); - //assertEquals(context.getRegister(registerVarnode).getName(),"s1"); - isBad = false; - try { - context.getConstant(registerVarnode, null); - } catch (NotFoundException e) { - isBad = true; - } - assertTrue("Can get constant value", isBad); - break; + switch (loc) { + case "00001010": + // gp should be 0x14 + t9 offset space + registerVarnode = regValue(context, "gp"); + assertTrue("symbolic value", context.isSymbol(registerVarnode)); + assertEquals("(t9, 0x13b334, 4)", registerVarnode.toString()); + // S3 should be S3 at entry + registerVarnode = regValue(context, "s3"); + assertTrue("register s3", context.isRegister(registerVarnode)); + assertEquals("s3", context.getRegister(registerVarnode).getName()); + break; + case "0000102c": + // s1 restored from space 0x10(s0) space + registerVarnode = regValue(context, "s1"); + assertTrue("constant value", registerVarnode.isConstant()); + assertEquals("(const, 0xa0b0c0d, 4)", registerVarnode.toString()); + break; + case "00001030": + // s1 restored from space 0x10(a1) space + registerVarnode = regValue(context, "s1"); + assertTrue("symbolic value", registerVarnode.isConstant()); + assertEquals("(const, 0x12344567, 4)", registerVarnode.toString()); + break; + case "00001034": + // s1 restored from space 0x10(sp) space + registerVarnode = regValue(context, "s1"); + assertTrue("symbolic value", context.isSymbol(registerVarnode)); + assertEquals("(t9, 0x13b334, 4)", registerVarnode.toString()); + break; + case "00001038": + // s1 restored from space 0x10(s2) space + registerVarnode = regValue(context, "s1"); + //assertTrue("Still s1", registerVarnode.isRegister()); + boolean isBad = false; + try { + context.getConstant(registerVarnode, null); + } + catch (NotFoundException e) { + isBad = true; + } + assertTrue("Can get constant value", isBad); + break; + case "00001040": + // s1 restored from space 0x10(s2) space - stored a3 + registerVarnode = regValue(context, "s1"); + assertTrue("register s3", registerVarnode.isRegister()); + assertEquals("s3", context.getRegister(registerVarnode).getName()); + + Address lastSetLocation = context.getLastSetLocation( + context.getRegisterVarnode(context.getRegister("s2")), null); + assertEquals("s2 last set", null, lastSetLocation); + break; + case "00001048": + // s1 restored from space 0x10(s2) after s2 has been set again + // it should no longer be s3 that was stored in another s2 relative space + registerVarnode = regValue(context, "s1"); + //assertTrue("Still s1", registerVarnode.isRegister()); + isBad = false; + try { + context.getConstant(registerVarnode, null); + } + catch (NotFoundException e) { + isBad = true; + } + assertTrue("Can get constant value", isBad); + break; + case "0000104c": + // s1 restored from space 0x10(s2) after s2 has been set again + // it should no longer be s3 that was stored in another s2 relative space + registerVarnode = regValue(context, "s2"); + //assertTrue("Still s2", registerVarnode.isRegister()); + isBad = false; + try { + context.getConstant(registerVarnode, null); + } + catch (NotFoundException e) { + isBad = true; + } + assertTrue("Can get constant value", isBad); + lastSetLocation = context.getLastSetLocation( + context.getRegisterVarnode(context.getRegister("s2")), null); + assertEquals("s2 last set", 0x104fL, lastSetLocation.getOffset()); + break; + case "00001054": + // s1 restored from space 0x10(s2) after s2 has been set again + // it should no longer be s3 that was stored in another s2 relative space + registerVarnode = regValue(context, "s1"); + //assertTrue("Still s1", registerVarnode.isRegister()); + //assertEquals(context.getRegister(registerVarnode).getName(),"s1"); + isBad = false; + try { + context.getConstant(registerVarnode, null); + } + catch (NotFoundException e) { + isBad = true; + } + assertTrue("Can get constant value", isBad); + break; } return super.evaluateContext(context, instr); } }; - + setRegister(addr("0x1000"), "s1", 0); SymbolicPropogator symEval = new SymbolicPropogator(program); Function func = program.getFunctionManager().getFunctionAt(builder.addr(0x1000)); - + symEval.flowConstants(codeStart, func.getBody(), eval, true, TaskMonitor.DUMMY); - + Value registerValue = symEval.getRegisterValue(addr("0x1010"), null); } - + @Test - public void testCorrectOperandConstantParam_X86_64() throws Exception { - + public void testCorrectOperandConstantParam_X86_64() throws Exception { + builder = new ProgramBuilder("thunk", ProgramBuilder._X64, "gcc", this); // PUSH RBP @@ -287,9 +292,8 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest { builder.setBytes("0x00040000", "55 48 89 e5 bf 00 01 04 00 b8 00 00 00 00 66 67 e8 2a 00 c9 c3"); - - builder.setBytes("0x00040100", - "53 54 52 49 4e 47 20 25 73 20 25 73 0a 00 00"); + + builder.setBytes("0x00040100", "53 54 52 49 4e 47 20 25 73 20 25 73 0a 00 00"); builder.disassemble("0x00040000", 21); @@ -297,7 +301,7 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest { program = builder.getProgram(); program.startTransaction("Test"); - + Address codeStart = addr("0x00040000"); Listing listing = program.getListing(); assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart)); @@ -309,10 +313,10 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest { assertNoOperandReference(0, instr); assertOperandReferenceTo(1, instr, addr("0x00040100")); } - + @Test - public void testOverlayReferences_AARCH64() throws Exception { - + public void testOverlayReferences_AARCH64() throws Exception { + builder = new ProgramBuilder("thunk", ProgramBuilder._AARCH64); // Copy and use PasteCopiedListingsBytesScript @@ -345,152 +349,152 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest { // 0040e91c 00 00 00 00 ddw 0h String ovBlockName = "textov"; - - MemoryBlock textBlock = builder.createOverlayMemory(ovBlockName,"0x400000",0x10000); + + MemoryBlock textBlock = builder.createOverlayMemory(ovBlockName, "0x400000", 0x10000); builder.setBytes(textBlock.getStart().toString(), "fd 7b bf a9 fd 03 00 91 60 00 00 d0 01 00 24 91 60 00 00 d0 00 40 24 91 e2 03 01 aa e1 15 80 52 05 00 00 94 21 00 80 d2 40 00 80 d2 02 00 00 94 c0 03 5f d6 c0 03 5f d6"); - - builder.setBytes(ovBlockName+":"+"0x0040e900", - "53 74 72 69 6e 67 50 61 72 61 6d 31 00 00 00 00 53 74 72 69 6e 67 50 61 72 61 6d 32 00 00 00 00"); - builder.disassemble(textBlock.getStart().toString(), 16*4); + builder.setBytes(ovBlockName + ":" + "0x0040e900", + "53 74 72 69 6e 67 50 61 72 61 6d 31 00 00 00 00 53 74 72 69 6e 67 50 61 72 61 6d 32 00 00 00 00"); + + builder.disassemble(textBlock.getStart().toString(), 16 * 4); analyzer = new ConstantPropagationAnalyzer(); program = builder.getProgram(); program.startTransaction("Test"); - Address codeStart = addr(ovBlockName+":"+"0x00400000"); + Address codeStart = addr(ovBlockName + ":" + "0x00400000"); Listing listing = program.getListing(); assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart)); - AddressSet addressSet = new AddressSet(codeStart, codeStart.add(16*4)); + AddressSet addressSet = new AddressSet(codeStart, codeStart.add(16 * 4)); analyze(addressSet); Instruction instr; - instr = listing.getInstructionAt(addr(ovBlockName+":"+"0x00400000").add(20)); + instr = listing.getInstructionAt(addr(ovBlockName + ":" + "0x00400000").add(20)); assertNoOperandReference(1, instr); - assertOperandReferenceTo(0, instr, addr(ovBlockName+":"+"0x0040e910")); - - instr = listing.getInstructionAt(addr(ovBlockName+":"+"0x00400000").add(24)); + assertOperandReferenceTo(0, instr, addr(ovBlockName + ":" + "0x0040e910")); + + instr = listing.getInstructionAt(addr(ovBlockName + ":" + "0x00400000").add(24)); assertNoOperandReference(1, instr); - assertOperandReferenceTo(0, instr, addr(ovBlockName+":"+"0x0040e900")); + assertOperandReferenceTo(0, instr, addr(ovBlockName + ":" + "0x0040e900")); } - + @Test - public void testOverlayReferencesToBase_AARCH64() throws Exception { - + public void testOverlayReferencesToBase_AARCH64() throws Exception { + builder = new ProgramBuilder("thunk", ProgramBuilder._AARCH64); - + String ovBlockName = "textov"; - + // Same as above test - - MemoryBlock textBlock = builder.createOverlayMemory(ovBlockName,"0x400000",0x1000); + + MemoryBlock textBlock = builder.createOverlayMemory(ovBlockName, "0x400000", 0x1000); builder.setBytes(textBlock.getStart().toString(), "fd 7b bf a9 fd 03 00 91 60 00 00 d0 01 00 24 91 60 00 00 d0 00 40 24 91 e2 03 01 aa e1 15 80 52 05 00 00 94 21 00 80 d2 40 00 80 d2 02 00 00 94 c0 03 5f d6 c0 03 5f d6"); - - builder.setBytes("0x0040e900", - "53 74 72 69 6e 67 50 61 72 61 6d 31 00 00 00 00 53 74 72 69 6e 67 50 61 72 61 6d 32 00 00 00 00"); - builder.disassemble(textBlock.getStart().toString(), 16*4); + builder.setBytes("0x0040e900", + "53 74 72 69 6e 67 50 61 72 61 6d 31 00 00 00 00 53 74 72 69 6e 67 50 61 72 61 6d 32 00 00 00 00"); + + builder.disassemble(textBlock.getStart().toString(), 16 * 4); analyzer = new ConstantPropagationAnalyzer(); program = builder.getProgram(); program.startTransaction("Test"); - Address codeStart = addr(ovBlockName+":"+"0x00400000"); + Address codeStart = addr(ovBlockName + ":" + "0x00400000"); Listing listing = program.getListing(); assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart)); - AddressSet addressSet = new AddressSet(codeStart, codeStart.add(16*4)); + AddressSet addressSet = new AddressSet(codeStart, codeStart.add(16 * 4)); analyze(addressSet); Instruction instr; - instr = listing.getInstructionAt(addr(ovBlockName+":"+"0x00400000").add(20)); + instr = listing.getInstructionAt(addr(ovBlockName + ":" + "0x00400000").add(20)); assertNoOperandReference(1, instr); assertOperandReferenceTo(0, instr, addr("0x0040e910")); - - instr = listing.getInstructionAt(addr(ovBlockName+":"+"0x00400000").add(24)); + + instr = listing.getInstructionAt(addr(ovBlockName + ":" + "0x00400000").add(24)); assertNoOperandReference(1, instr); assertOperandReferenceTo(0, instr, addr("0x0040e900")); - } + } - @Test - public void testOverlayReferencesToSplit_AARCH64() throws Exception { - + public void testOverlayReferencesToSplit_AARCH64() throws Exception { + builder = new ProgramBuilder("thunk", ProgramBuilder._AARCH64); String ovBlockName = "textov"; - + // Same as above test - - MemoryBlock textBlock = builder.createOverlayMemory(ovBlockName,"0x400000",0x1000); + + MemoryBlock textBlock = builder.createOverlayMemory(ovBlockName, "0x400000", 0x1000); builder.setBytes(textBlock.getStart().toString(), "fd 7b bf a9 fd 03 00 91 60 00 00 d0 01 00 24 91 60 00 00 d0 00 40 24 91 e2 03 01 aa e1 15 80 52 05 00 00 94 21 00 80 d2 40 00 80 d2 02 00 00 94 c0 03 5f d6 c0 03 5f d6"); - - + builder.withTransaction(() -> { try { - MemoryBlock dataBlock = builder.getProgram().getMemory().createInitializedBlock(ovBlockName, textBlock.getStart().getAddressSpace().getAddressInThisSpaceOnly(0x0040e900), 0x100L, (byte) 0, TaskMonitor.DUMMY, - false); - + MemoryBlock dataBlock = builder.getProgram() + .getMemory() + .createInitializedBlock(ovBlockName, + textBlock.getStart() + .getAddressSpace() + .getAddressInThisSpaceOnly(0x0040e900), + 0x100L, (byte) 0, TaskMonitor.DUMMY, false); + builder.setBytes(dataBlock.getStart().toString(), - "53 74 72 69 6e 67 50 61 72 61 6d 31 00 00 00 00 53 74 72 69 6e 67 50 61 72 61 6d 32 00 00 00 00"); + "53 74 72 69 6e 67 50 61 72 61 6d 31 00 00 00 00 53 74 72 69 6e 67 50 61 72 61 6d 32 00 00 00 00"); } catch (Exception e) { e.printStackTrace(); } }); - - builder.disassemble(textBlock.getStart().toString(), 16*4); + + builder.disassemble(textBlock.getStart().toString(), 16 * 4); analyzer = new ConstantPropagationAnalyzer(); program = builder.getProgram(); program.startTransaction("Test"); - Address codeStart = addr(ovBlockName+":"+"0x00400000"); + Address codeStart = addr(ovBlockName + ":" + "0x00400000"); Listing listing = program.getListing(); assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart)); - AddressSet addressSet = new AddressSet(codeStart, codeStart.add(16*4)); + AddressSet addressSet = new AddressSet(codeStart, codeStart.add(16 * 4)); analyze(addressSet); Instruction instr; - instr = listing.getInstructionAt(addr(ovBlockName+":"+"0x00400000").add(20)); + instr = listing.getInstructionAt(addr(ovBlockName + ":" + "0x00400000").add(20)); assertNoOperandReference(1, instr); - assertOperandReferenceTo(0, instr, addr(ovBlockName+":"+"0x0040e910")); - - instr = listing.getInstructionAt(addr(ovBlockName+":"+"0x00400000").add(24)); - assertNoOperandReference(1, instr); - assertOperandReferenceTo(0, instr, addr(ovBlockName+":"+"0x0040e900")); - } + assertOperandReferenceTo(0, instr, addr(ovBlockName + ":" + "0x0040e910")); + + instr = listing.getInstructionAt(addr(ovBlockName + ":" + "0x00400000").add(24)); + assertNoOperandReference(1, instr); + assertOperandReferenceTo(0, instr, addr(ovBlockName + ":" + "0x0040e900")); + } - - @Test - public void testPIC_Call_X86_64() throws Exception { - + public void testPIC_Call_X86_64() throws Exception { + builder = new ProgramBuilder("PICCode", ProgramBuilder._X64, "gcc", this); - // entry - // 48 83 ec 28 SUB RSP,0x28 + // entry + // 48 83 ec 28 SUB RSP,0x28 // e8 00 00 00 00 CALL LAB_140020119 // LAB_140020119 - // 8f c3 POP RBX - // 48 8d 43 e0 LEA RAX,[RBX + -0x20] + // 8f c3 POP RBX + // 48 8d 43 e0 LEA RAX,[RBX + -0x20] // ff d0 CALL RAX - // 48 83 c4 28 ADD RSP,0x28 - // c3 RET + // 48 83 c4 28 ADD RSP,0x28 + // c3 RET builder.setBytes("0x140020110", - "48 83 ec 28 e8 00 00 00 00 8f c3 48 8d 43 e0 ff d0 48 83 c4 28 c3"); - - builder.setBytes("0x1400200f9", - "15 02 2f 00 00 89 05 e8 b9 00 00 48 83 c4 38"); + "48 83 ec 28 e8 00 00 00 00 8f c3 48 8d 43 e0 ff d0 48 83 c4 28 c3"); + + builder.setBytes("0x1400200f9", "15 02 2f 00 00 89 05 e8 b9 00 00 48 83 c4 38"); builder.disassemble("0x140020110", 21); @@ -498,7 +502,7 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest { program = builder.getProgram(); program.startTransaction("Test"); - + Address codeStart = addr("140020110"); Listing listing = program.getListing(); assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart)); diff --git a/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/gnu/GnuDemanglerTest.java b/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/gnu/GnuDemanglerTest.java index 86b77b3416..d879f51270 100644 --- a/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/gnu/GnuDemanglerTest.java +++ b/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/gnu/GnuDemanglerTest.java @@ -26,6 +26,7 @@ import generic.test.AbstractGenericTest; import ghidra.app.util.demangler.*; import ghidra.program.database.ProgramDB; import ghidra.program.model.address.Address; +import ghidra.program.model.data.DataType; import ghidra.program.model.data.TerminatedStringDataType; import ghidra.program.model.listing.CodeUnit; import ghidra.program.model.listing.Data; @@ -132,6 +133,60 @@ public class GnuDemanglerTest extends AbstractGenericTest { fullSignature); } + @Test + public void testUseStandardReplacements2() throws Exception { + + // + // Mangled: _ZN7Greeter5greetENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE + // + // Demangled: undefined Greeter::greet(std::__cxx11::basic_string,std::allocator>) + // + // Replaced: undefined Greeter::greet(std::string) + // + String mangled = "_ZN7Greeter5greetENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"; + + GnuDemangler demangler = new GnuDemangler(); + demangler.canDemangle(program);// this perform initialization + + GnuDemanglerOptions options = new GnuDemanglerOptions(); + options.setUseStandardReplacements(true); + DemangledFunction dobj = (DemangledFunction) demangler.demangle(mangled, options); + assertNotNull(dobj); + + String signature = dobj.getSignature(); + assertEquals("undefined Greeter::greet(std::string)", signature); + + DemangledParameter demangledParameter = dobj.getParameters().get(0); + DemangledDataType type = demangledParameter.getType(); + DataType dt = type.getDataType(program.getDataTypeManager()); + assertTrue(dt.isNotYetDefined()); + //@formatter:off + assertEquals("/Demangler/std/string\n" + + "pack(disabled)\n" + + "Structure string {\n" + + "}\n" + + "Length: 0 Alignment: 1\n", dt.toString()); + //@formatter:on + + // + // Now disable demangled string replacement + // + options.setUseStandardReplacements(false); + dobj = (DemangledFunction) demangler.demangle(mangled, options); + assertNotNull(dobj); + + String fullSignature = dobj.getSignature(); + assertEquals( + "undefined Greeter::greet(std::__cxx11::basic_string,std::allocator>)", + fullSignature); + + demangledParameter = dobj.getParameters().get(0); + type = demangledParameter.getType(); + dt = type.getDataType(program.getDataTypeManager()); + assertEquals("typedef basic_string undefined", dt.toString()); + + } + @Test public void testDemangleOnlyKnownPatterns_True() throws Exception { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java index 45953238f4..21bbe7ff53 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java @@ -2470,16 +2470,6 @@ public class FunctionDB extends DatabaseObject implements Function { return thunkedFunction.getSignatureSource(); } - // Force DEFAULT source if any param has unassigned storage - if (!getReturn().isValid()) { - return SourceType.DEFAULT; - } - for (Parameter param : getParameters()) { - if (!param.isValid()) { - return SourceType.DEFAULT; - } - } - return getStoredSignatureSource(); } finally { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandard.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandard.java index f03b5b74ad..7a4bcadd14 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandard.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandard.java @@ -4,9 +4,9 @@ * 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. @@ -23,8 +23,7 @@ import java.util.ArrayList; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSpace; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.DataTypeManager; +import ghidra.program.model.data.*; import ghidra.program.model.lang.protorules.*; import ghidra.program.model.listing.Program; import ghidra.program.model.listing.VariableStorage; @@ -85,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) { @@ -133,6 +133,12 @@ public class ParamListStandard implements ParamList { if (dt.isZeroLength()) { return AssignAction.NO_ASSIGNMENT; } + if (dt == DataType.DEFAULT) { + return AssignAction.NO_ASSIGNMENT; + } + if (dt instanceof TypeDef td && td.getBaseDataType() == DataType.DEFAULT) { + return AssignAction.NO_ASSIGNMENT; + } for (ModelRule modelRule : modelRules) { int responseCode = modelRule.assignAddress(dt, proto, pos, dtManager, status, res); if (responseCode != AssignAction.FAIL) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java index 804105b28f..8cfda0e33a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java @@ -4,9 +4,9 @@ * 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. @@ -239,6 +239,10 @@ public class PrototypeModel { * i.e. {@link AutoParameterType#RETURN_STORAGE_PTR}, this routine will not pass back * the storage location of the pointer, but will typically pass * back the location of the normal return register which holds a copy of the pointer. + *
+ * Note: storage will not be assigned to the {@link DataType#DEFAULT default undefined} datatype + * or zero-length datatype. + * * @param dataType first parameter dataType or null for an undefined type. * @param program is the Program * @return return location or {@link VariableStorage#UNASSIGNED_STORAGE} if @@ -259,10 +263,22 @@ public class PrototypeModel { * Get the preferred parameter location for a new parameter which will appended * to the end of an existing set of params. If existing parameters use custom * storage, this method should not be used. + *
+ * Note: storage will not be assigned to the {@link DataType#DEFAULT default undefined} datatype, + * zero-length datatype, or any subsequent parameter following such a parameter. + *
+ * Warning: The use of this method with a null {@code params} argument, or incorrect + * datatypes, is highly discouraged since it will produce inaccurate results. + * It is recommended that a complete function signature be used in + * conjunction with the {@link #getStorageLocations(Program, DataType[], boolean)} + * method. Parameter storage allocation may be affected by the return datatype + * specified (e.g., hidden return storage parameter). + * * @param params existing set parameters to which the next parameter will - * be appended. (may be null) + * be appended (may be null). Element-0 corresponds to the return datatype. * @param dataType dataType associated with next parameter location or null - * for a default undefined type. + * for a default undefined type. If null the speculative first parameter storage + * is returned. * @param program is the Program * @return next parameter location or {@link VariableStorage#UNASSIGNED_STORAGE} if * unable to determine suitable location @@ -276,9 +292,24 @@ public class PrototypeModel { * Get the preferred parameter location for a specified index, * which will be added/inserted within the set of existing function params. * If existing parameters use custom storage, this method should not be used. - * @param argIndex is the index + *
+ * Note: storage will not be assigned to the {@link DataType#DEFAULT default undefined} datatype, + * zero-length datatype, or any subsequent parameter following such a parameter. + *
+ * Warning: The use of this method with a null {@code params} argument, or incorrect + * datatypes, is highly discouraged since it will produce inaccurate results. + * It is recommended that a complete function signature be used in + * conjunction with the {@link #getStorageLocations(Program, DataType[], boolean)} + * method. Parameter storage allocation may be affected by the return datatype + * specified (e.g., hidden return storage parameter). + * + * @param argIndex is the index (0: return storage, 1..n: parameter storage) * @param params existing set parameters to which the parameter specified by - * argIndex will be added/inserted be appended (may be null). + * argIndex will be added/inserted be appended. Element-0 corresponds to the return + * datatype. Parameter elements prior to the argIndex are required for an accurate + * storage determination to be made. Any preceeding parameters not specified will be assumed + * as a 1-byte integer type which could cause an erroneous storage result to be returned. + * A null params list will cause all preceeding params to be assumed in a similar fashion. * @param dataType dataType associated with next parameter location or null * for a default undefined type. * @param program is the Program @@ -302,7 +333,7 @@ public class PrototypeModel { arr[i + 1] = params[i].getDataType(); // Copy in current types if we have them } else { - arr[i + 1] = DataType.DEFAULT; // Otherwise assume default (integer) type + arr[i + 1] = Undefined1DataType.dataType; // Otherwise assume 1-byte (integer) type } } arr[argIndex + 1] = dataType; @@ -353,6 +384,10 @@ public class PrototypeModel { * input parameters, if needed. In this case, the dataTypes array should not include explicit entries for * these parameters. If addAutoParams is false, the dataTypes array is assumed to already contain explicit * entries for any of these parameters. + *
+ * Note: storage will not be assigned to the {@link DataType#DEFAULT default undefined} datatype + * or zero-length datatypes or any subsequent parameter following such a parameter. + * * @param program is the Program * @param dataTypes return/parameter datatypes (first element is always the return datatype, * i.e., minimum array length is 1) diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/LocalSymbolMap.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/LocalSymbolMap.java index c4179411f2..9209d212d1 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/LocalSymbolMap.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/LocalSymbolMap.java @@ -4,9 +4,9 @@ * 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. @@ -210,11 +210,12 @@ public class LocalSymbolMap { pcaddr = pcaddr.subtractWrap(1); List paramList = new ArrayList<>(); + boolean internalInvalid = false; for (int i = 0; i < p.length; ++i) { Parameter var = p[i]; if (!var.isValid()) { - // TODO: exclude parameters which don't have valid storage ?? - continue; + internalInvalid = true; + break; } DataType dt = var.getDataType(); String name = var.getName(); @@ -243,6 +244,12 @@ public class LocalSymbolMap { paramSymbol.setNameLock(namelock); paramSymbol.setTypeLock(lock); } + if (internalInvalid) { + // Can only send down a partial prototype. Let decompiler try to recover the whole. + for (HighSymbol paramSymbol : paramList) { + paramSymbol.setTypeLock(false); + } + } paramSymbols = new HighSymbol[paramList.size()]; paramList.toArray(paramSymbols); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java index 02cb399d35..93e7ee86e8 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java @@ -1153,10 +1153,7 @@ public class PcodeDataTypeManager { private void generateCoreTypes() { voidDt = new VoidDataType(progDataTypes); coreBuiltin = new HashMap(); - TypeMap type = new TypeMap(DataType.DEFAULT, "undefined", "unknown", false, false, - DEFAULT_DECOMPILER_ID); - coreBuiltin.put(type.id, type); - type = new TypeMap(displayLanguage, VoidDataType.dataType, "void", false, false, + TypeMap type = new TypeMap(displayLanguage, VoidDataType.dataType, "void", false, false, builtInDataTypes); coreBuiltin.put(type.id, type); diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/plugin/compare/CompareFunctionsDecompilerViewTest.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/plugin/compare/CompareFunctionsDecompilerViewTest.java index ad7ea9c94d..a921a17038 100644 --- a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/plugin/compare/CompareFunctionsDecompilerViewTest.java +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/plugin/compare/CompareFunctionsDecompilerViewTest.java @@ -4,9 +4,9 @@ * 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. @@ -55,7 +55,6 @@ public class CompareFunctionsDecompilerViewTest extends AbstractGhidraHeadedInte FunctionManager functionManager = program1.getFunctionManager(); fun1 = functionManager.getFunctionAt(addr(0x01002cf5)); fun2 = functionManager.getFunctionAt(addr(0x0100415a)); - } private Address addr(long offset) { @@ -69,6 +68,8 @@ public class CompareFunctionsDecompilerViewTest extends AbstractGhidraHeadedInte @Test public void testDecompDifView() throws Exception { + assertFalse(program1.isClosed()); + Set functions = Set.of(fun1, fun2); compareFunctions(functions); @@ -76,13 +77,12 @@ public class CompareFunctionsDecompilerViewTest extends AbstractGhidraHeadedInte waitForComponentProvider(FunctionComparisonProvider.class); checkFunctions(provider, LEFT, fun1, fun1, fun2); - DecompilerCodeComparisonPanel panel = - (DecompilerCodeComparisonPanel) provider - .getCodeComparisonPanelByName(DecompilerCodeComparisonPanel.NAME); + DecompilerCodeComparisonPanel panel = (DecompilerCodeComparisonPanel) provider + .getCodeComparisonPanelByName(DecompilerCodeComparisonPanel.NAME); waitForDecompiler(panel); assertHasLines(panel.getLeftPanel(), 28); - assertHasLines(panel.getRightPanel(), 23); + assertHasLines(panel.getRightPanel(), 22); } private void checkFunctions(FunctionComparisonProvider provider, Side side, @@ -113,8 +113,7 @@ public class CompareFunctionsDecompilerViewTest extends AbstractGhidraHeadedInte } private Program buildTestProgram() throws Exception { - ClassicSampleX86ProgramBuilder builder = - new ClassicSampleX86ProgramBuilder("Test", false); + ClassicSampleX86ProgramBuilder builder = new ClassicSampleX86ProgramBuilder("Test", false); return builder.getProgram(); }