diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ProgramBigListingModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ProgramBigListingModel.java index 52e113749f..3ad0d340de 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ProgramBigListingModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ProgramBigListingModel.java @@ -38,6 +38,7 @@ import ghidra.program.model.listing.*; import ghidra.program.model.symbol.Reference; import ghidra.util.datastruct.LRUMap; import ghidra.util.task.TaskMonitor; +import util.CollectionUtils; public class ProgramBigListingModel implements ListingModel, FormatModelListener, DomainObjectListener, ChangeListener, OptionsChangeListener { @@ -454,21 +455,7 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener if (parent.getAddress().equals(addr)) { return null; } - Data data; - if (parent.getBaseDataType() instanceof Union) { - int index = - openCloseMgr.getOpenDataIndex(parent); - if (index < 0) { - return null; - } - data = parent.getComponent(index); - } - else { - int offset = (int) addr.subtract(parent.getMinAddress()); - List componentsContaining = parent.getComponentsContaining(offset - 1); - data = componentsContaining.isEmpty() ? null - : componentsContaining.get(componentsContaining.size() - 1); - } + Data data = getOpenDataAtAddress(parent, addr); if (data == null) { return addr.previous(); } @@ -487,10 +474,29 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener int index = data.getComponentIndex(); if (index > 0) { - return parent.getComponent(index - 1).getAddress(); + Address previous = parent.getComponent(index - 1).getAddress(); + if (!previous.equals(addr)) { + return previous; + } } return null; } + + private Data getOpenDataAtAddress(Data parent, Address address) { + if (parent.getBaseDataType() instanceof Union) { + int index = openCloseMgr.getOpenDataIndex(parent); + if (index < 0) { + return null; + } + return parent.getComponent(index); + } + int offset = (int) address.subtract(parent.getMinAddress()); + List components = parent.getComponentsContaining(offset - 1); + if (CollectionUtils.isBlank(components)) { + return null; + } + return components.get(components.size() - 1); + } private void addOpenData(List list, Data data, Address addr) { Address dataAddr = data.getMinAddress(); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/editor/EnumEditor1Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/editor/EnumEditor1Test.java index 663e65d5df..2d69f29342 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/editor/EnumEditor1Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/editor/EnumEditor1Test.java @@ -95,10 +95,10 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest { assertEquals("", descField.getText()); assertTrue(descField.isEditable()); - // category should be notepad.xml/Category1 + // category should be TestProgram/Category1 JTextField catField = getTextField(panel, "Category"); assertNotNull(catField); - assertEquals("notepad/Category1", catField.getText()); + assertEquals("TestProgram/Category1", catField.getText()); assertFalse(catField.isEditable()); // size should be "1" diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/viewer/listingpanel/ProgramBigListingModelOpenDataTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/viewer/listingpanel/ProgramBigListingModelOpenDataTest.java new file mode 100644 index 0000000000..9f1c91b03d --- /dev/null +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/viewer/listingpanel/ProgramBigListingModelOpenDataTest.java @@ -0,0 +1,87 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.viewer.listingpanel; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; + +import generic.test.AbstractGenericTest; +import ghidra.app.util.viewer.format.FormatManager; +import ghidra.framework.options.SaveState; +import ghidra.framework.options.ToolOptions; +import ghidra.program.database.ProgramBuilder; +import ghidra.program.database.ProgramDB; +import ghidra.program.database.function.OverlappingFunctionException; +import ghidra.program.model.address.*; +import ghidra.program.model.data.StructureDataType; +import ghidra.program.model.data.UnionDataType; +import ghidra.program.model.listing.Data; +import ghidra.program.model.listing.Function; +import ghidra.program.model.listing.Listing; + +public class ProgramBigListingModelOpenDataTest extends AbstractGenericTest { + + private ProgramDB program; + private ProgramBigListingModel model; + private AddressSpace space; + + @Before + public void setUp() throws Exception { + ProgramBuilder builder = new ProgramBuilder("Test", ProgramBuilder._X86); + program = builder.getProgram(); + space = program.getAddressFactory().getDefaultAddressSpace(); + builder.createMemory("block1", "0", 100); + + FormatManager formatManager = + new FormatManager(new ToolOptions("display"), new ToolOptions("Listing Fields")); + formatManager.readState(new SaveState()); // this will use default format + model = new ProgramBigListingModel(program, formatManager); + + StructureDataType struct1 = new StructureDataType("aaa", 4); + StructureDataType struct2 = new StructureDataType("bbb", 2); + UnionDataType union = new UnionDataType("uuu"); + union.add(struct1); + union.add(struct2); + builder.applyDataType("0", union); + + + } + + + private Address addr(long offset) { + return space.getAddress(offset); + } + + @Test + public void testGetPreviousAddressWithLargerUnionComponentOpen() { + Listing listing = program.getListing(); + Data data = listing.getDataAt(addr(0)); + Data component = data.getComponent(0); + model.openData(component); + assertEquals(addr(2), model.getAddressBefore(addr(3))); + } + @Test + public void testGetPreviousAddressWithSmallerUnionComponentOpen() { + Listing listing = program.getListing(); + Data data = listing.getDataAt(addr(0)); + Data component = data.getComponent(1); + model.openData(component); + assertEquals(addr(2), model.getAddressBefore(addr(3))); + } + +}