Merge remote-tracking branch 'origin/patch'

Conflicts:
	Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergeManager.java
This commit is contained in:
ghidra1 2020-02-03 15:33:06 -05:00
commit c081a87ede
9 changed files with 1187 additions and 481 deletions

View file

@ -162,8 +162,7 @@ public abstract class CompositeEditorPanel extends JPanel
BitFieldEditorDialog dlg = new BitFieldEditorDialog(model.viewComposite,
provider.dtmService, editingRow, ordinal -> {
model.fireTableDataChanged();
model.compositeInfoChanged();
model.notifyCompositeChanged();
});
Component c = provider.getComponent();
Window w = SwingUtilities.windowForComponent(c);

View file

@ -17,6 +17,8 @@ package ghidra.app.merge.datatypes;
import static org.junit.Assert.*;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Assert;
import org.junit.Test;
@ -36,37 +38,47 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
@Test
public void testCategoryAddRemoveDTAdd() throws Exception {
TypeDef td = new TypedefDataType("BF", IntegerDataType.dataType);
AtomicReference<Structure> structRef = new AtomicReference<>();
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
// Make no changes to Latest.
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test");
Category c = dtm.getCategory(new CategoryPath("/Category1/Category2"));
try {
c.removeCategory("Category5", TaskMonitorAdapter.DUMMY_MONITOR);
Category c5 = c.createCategory("Category5");
Structure dt = new StructureDataType("Test", 0);
dt.add(new ByteDataType());
dt.add(new WordDataType());
dt = (Structure) c5.addDataType(dt, DataTypeConflictHandler.DEFAULT_HANDLER);
dt.add(new QWordDataType());
Structure struct =
new StructureDataType("Test", 0, program.getDataTypeManager());
struct.add(new ByteDataType());
struct.add(new WordDataType());
struct.insertBitFieldAt(3, 2, 6, td, 2, "bf1", null);
struct.insertBitFieldAt(3, 2, 4, td, 2, "bf2", null);
struct.add(new QWordDataType());
struct.setFlexibleArrayComponent(td, "flex", "my flex");
structRef.set(struct);
c.removeCategory("Category5", TaskMonitorAdapter.DUMMY);
Category c5 = c.createCategory("Category5");
c5.addDataType(struct, DataTypeConflictHandler.DEFAULT_HANDLER);
commit = true;
}
catch (InvalidNameException e) {
Assert.fail("got InvalidNameException!");
catch (Exception e) {
e.printStackTrace();
Assert.fail(e.toString());
}
finally {
program.endTransaction(transactionID, commit);
@ -79,7 +91,9 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
Category c = dtm.getCategory(new CategoryPath("/Category1/Category2/Category5"));
assertNotNull(c);
assertNotNull(c.getDataType("Test"));
DataType dt = c.getDataType("Test");
assertNotNull(dt);
assertTrue(structRef.get().isEquivalent(dt));
}
@ -89,9 +103,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
// A category was added to Category5 in the latest;
// in My program, rename Category5 to "My Category5" and add a new data type
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@ -111,9 +123,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
}
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -159,18 +168,17 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
@Test
public void testDataTypeAddedInMy2() throws Exception {
TypeDef td = new TypedefDataType("BF", IntegerDataType.dataType);
AtomicReference<Structure> structRef = new AtomicReference<>();
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
// Make no changes to Latest.
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -179,15 +187,24 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
Category c = dtm.getCategory(new CategoryPath("/Category1/Category2/Category3"));
try {
Structure s = (Structure) c.getDataType("IntStruct");
c.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
s = new StructureDataType(c.getCategoryPath(), "IntStruct", 0);
s.add(new QWordDataType());
c.remove(s, TaskMonitorAdapter.DUMMY);
s = new StructureDataType(c.getCategoryPath(), "IntStruct", 0, dtm);
s.add(new QWordDataType(), "f1", "my f1");
s.add(new FloatDataType());
s.add(new ByteDataType());
s.insertBitFieldAt(16, 2, 6, td, 2, "bf1", "my bf1");
s.insertBitFieldAt(16, 2, 4, td, 2, "bf2", "my bf2");
s.add(new WordDataType());
structRef.set(s);
c.addDataType(s, DataTypeConflictHandler.DEFAULT_HANDLER);
commit = true;
}
catch (Exception e) {
e.printStackTrace();
Assert.fail(e.toString());
}
finally {
program.endTransaction(transactionID, commit);
}
@ -199,30 +216,25 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
Category c = dtm.getCategory(new CategoryPath("/Category1/Category2/Category3"));
DataType dt = c.getDataType("IntStruct");
assertNotNull(dt);
assertTrue(dt instanceof Structure);
Structure s = (Structure) dt;
assertTrue(new QWordDataType().isEquivalent(s.getComponent(0).getDataType()));
assertTrue(new FloatDataType().isEquivalent(s.getComponent(1).getDataType()));
assertTrue(new ByteDataType().isEquivalent(s.getComponent(2).getDataType()));
assertTrue(new WordDataType().isEquivalent(s.getComponent(3).getDataType()));
assertTrue(structRef.get().isEquivalent(dt));
Structure s = (Structure) dt;
assertEquals("my f1", s.getComponent(0).getComment());
DataTypeComponent dtc = s.getComponentAt(17);
assertEquals(7, dtc.getOrdinal());
assertEquals("my bf1", dtc.getComment());
}
@Test
public void testDataTypeAddedInMy3() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
// Make no changes to Latest.
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -231,7 +243,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
Category c = dtm.getCategory(new CategoryPath("/Category1/Category2/Category3"));
try {
Structure s = (Structure) c.getDataType("IntStruct");
c.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
c.remove(s, TaskMonitorAdapter.DUMMY);
s = new StructureDataType(c.getCategoryPath(), "IntStruct", 0);
s.add(new QWordDataType());
s.add(new FloatDataType());
@ -276,9 +288,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
// add a new data type;
// in My program, rename Category5 to "My Category5"
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@ -303,9 +313,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
}
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -346,9 +353,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
// A category was added to Category5 in the latest;
// in My program, rename Category5 to "My Category5" and add a new data type
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@ -372,9 +377,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
}
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -421,17 +423,12 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
public void testDataTypeDeletedInMy() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
// Make no changes to Latest.
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -443,7 +440,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
"IntStruct");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -464,17 +461,12 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
public void testDataTypeAddedDeletedInMy() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
// Make no changes to Latest.
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -487,7 +479,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
try {
DataType dt = dtm.addDataType(s, DataTypeConflictHandler.DEFAULT_HANDLER);
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -508,9 +500,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
public void testDataTypeDeletedChanged() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@ -529,9 +519,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
}
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -543,7 +530,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
"IntStruct");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -564,9 +551,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
public void testDataTypeDeletedChanged2() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@ -585,9 +570,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
}
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -599,7 +581,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
"FloatStruct");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -619,9 +601,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
public void testDataTypeDeletedChanged3() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@ -631,7 +611,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
"IntStruct");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -639,9 +619,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
}
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -672,9 +649,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
public void testDataTypeDeletedInLatest() throws Exception {
mtf.initialize("notepad2", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@ -684,7 +659,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -692,9 +667,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
}
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -731,9 +703,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
public void testDataTypeDeletedInBoth() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@ -745,7 +715,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
"IntStruct");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -753,9 +723,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
}
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -767,7 +734,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
"IntStruct");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -788,17 +755,12 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
public void testDataTypeRenamedInMy() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
// Make no changes to Latest.
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -837,9 +799,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
public void testRenamedBoth() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@ -865,9 +825,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
}
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -905,9 +862,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
public void testRenamedBoth2() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@ -933,9 +888,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
}
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -974,9 +926,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
public void testDeletedInMyRenamedInLatest() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@ -1002,9 +952,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
}
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -1016,7 +963,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
"IntStruct");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -1035,9 +982,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
public void testDeletedInLatestRenamedInMy() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@ -1047,7 +992,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
"IntStruct");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -1055,9 +1000,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
}
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -1093,9 +1035,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
public void testDeletedInLatestChangedInMy() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@ -1110,7 +1050,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
Structure s = (Structure) dt;
s.add(new ByteDataType());
Category parent = dtm.getCategory(new CategoryPath("/Category1/Category2"));
parent.removeCategory("Category3", TaskMonitorAdapter.DUMMY_MONITOR);
parent.removeCategory("Category3", TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -1118,9 +1058,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
}
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -1164,9 +1101,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
public void testDeletedInLatestAddedInMy() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@ -1181,7 +1116,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
Structure s = (Structure) dt;
s.add(new ByteDataType());
Category parent = dtm.getCategory(new CategoryPath("/Category1/Category2"));
parent.removeCategory("Category3", TaskMonitorAdapter.DUMMY_MONITOR);
parent.removeCategory("Category3", TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -1189,9 +1124,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
}
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@ -1233,9 +1165,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
public void testCompositeCommentChanged() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@ -1258,9 +1188,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
}
}
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;

View file

@ -21,11 +21,11 @@ import org.junit.Assert;
import org.junit.Test;
import docking.widgets.OptionDialog;
import ghidra.program.database.ProgramDB;
import ghidra.program.database.ProgramModifierListener;
import ghidra.program.database.*;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
import ghidra.util.task.TaskMonitorAdapter;
/**
@ -47,7 +47,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
try {
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(s, TaskMonitorAdapter.DUMMY);
// 2 components should get removed from CoolUnion
commit = true;
}
@ -119,7 +119,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
try {
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(s, TaskMonitorAdapter.DUMMY);
// 2 components should get removed from CoolUnion
commit = true;
}
@ -191,7 +191,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
try {
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(s, TaskMonitorAdapter.DUMMY);
// 2 components should get removed from CoolUnion
commit = true;
}
@ -296,10 +296,9 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
setErrorsExpected(true);
executeMerge();
DataTypeManager dtm = resultProgram.getDataTypeManager();
executeMerge(true);
waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager();
checkConflictCount(0);
@ -573,7 +572,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
DataType dt =
dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -646,7 +645,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
DataType dt =
dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
// causes Bar to be marked as changed
commit = true;
}
@ -720,7 +719,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
DataType dt =
dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
// causes Bar to be marked as changed
commit = true;
}
@ -796,7 +795,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
Structure ms = (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"),
"MyStruct");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
Structure s1 = new StructureDataType(
new CategoryPath("/Category1/Category2/Category5"), "s1", 0);
s1.add(ms);
@ -884,6 +883,196 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
assertEquals(3, dtcs.length);
}
@Test
public void testConflictUpdate5() throws Exception {
TypeDef td = new TypedefDataType(new CategoryPath("/Category1/Category2"), "BF",
IntegerDataType.dataType);
mtf.initialize("notepad2", new OriginalProgramModifierListener() {
@Override
public void modifyOriginal(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test");
try {
dtm.addDataType(td, null);
}
finally {
program.endTransaction(transactionID, true);
}
}
@Override
public void modifyLatest(ProgramDB program) {
DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test");
DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2"), "BF");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
}
finally {
program.endTransaction(transactionID, true);
}
}
@Override
public void modifyPrivate(ProgramDB program) {
DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test");
Structure s1 = (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"),
"Structure_1");
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
try {
s1.insertBitFieldAt(3, 2, 6, td, 2, "bf1", "my bf1");
s1.insertBitFieldAt(3, 2, 4, td, 2, "bf2", "my bf2");
foo.add(new FloatDataType());
}
catch (Exception e) {
e.printStackTrace();
Assert.fail(e.toString());
}
finally {
program.endTransaction(transactionID, true);
}
}
});
// bitfield silently transitions to int since typedef BF was removed
executeMerge();
DataTypeManager dtm = resultProgram.getDataTypeManager();
Structure s1 =
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1");
assertNotNull(s1);
DataTypeComponent[] dtcs = s1.getComponents();
assertEquals(7, dtcs.length);
assertEquals(4, dtcs[3].getOffset()); // base on original 2-byte length 1st byte remains undefined
assertEquals("bf1", dtcs[3].getFieldName());
assertEquals("my bf1", dtcs[3].getComment());
DataType dt = dtcs[3].getDataType();
assertTrue(dt instanceof BitFieldDataType);
BitFieldDataType bfDt = (BitFieldDataType) dt;
assertTrue(bfDt.getBaseDataType() instanceof IntegerDataType);
assertEquals(2, bfDt.getDeclaredBitSize());
assertEquals(6, bfDt.getBitOffset());
assertEquals(4, dtcs[4].getOffset()); // base on original 2-byte length 1st byte remains undefined
assertEquals("bf2", dtcs[4].getFieldName());
assertEquals("my bf2", dtcs[4].getComment());
dt = dtcs[4].getDataType();
assertTrue(dt instanceof BitFieldDataType);
bfDt = (BitFieldDataType) dt;
assertTrue(bfDt.getBaseDataType() instanceof IntegerDataType);
assertEquals(2, bfDt.getDeclaredBitSize());
assertEquals(4, bfDt.getBitOffset());
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
// Structure_1 should contain MY Foo
assertEquals(foo, dtcs[5].getDataType());
dtcs = foo.getComponents();
assertEquals(5, dtcs.length);
assertTrue(dtcs[4].getDataType().isEquivalent(new FloatDataType()));
checkConflictCount(0);
}
@Test
public void testConflictUpdate6() throws Exception {
TypeDef td = new TypedefDataType(new CategoryPath("/Category1/Category2"), "BF",
IntegerDataType.dataType);
mtf.initialize("notepad2", new ProgramModifierListener() {
@Override
public void modifyLatest(ProgramDB program) {
DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test");
try {
// add new BF not compatible with BitFields
dtm.addDataType(
new StructureDataType(new CategoryPath("/Category1/Category2"), "BF", 0),
null);
}
finally {
program.endTransaction(transactionID, true);
}
}
@Override
public void modifyPrivate(ProgramDB program) {
DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test");
Structure s1 = (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"),
"Structure_1");
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
try {
s1.insertBitFieldAt(3, 2, 6, td, 2, "bf1", "my bf1");
s1.insertBitFieldAt(3, 2, 4, td, 2, "bf2", "my bf2");
foo.add(new FloatDataType());
}
catch (Exception e) {
e.printStackTrace();
Assert.fail(e.toString());
}
finally {
program.endTransaction(transactionID, true);
}
}
});
// bitfield silently transitions to BF.conflict since two different BF types were added
executeMerge();
DataTypeManager dtm = resultProgram.getDataTypeManager();
Structure s1 =
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1");
assertNotNull(s1);
DataTypeComponent[] dtcs = s1.getComponents();
assertEquals(7, dtcs.length);
assertEquals(4, dtcs[3].getOffset()); // base on original 2-byte length 1st byte remains undefined
assertEquals("bf1", dtcs[3].getFieldName());
assertEquals("my bf1", dtcs[3].getComment());
DataType dt = dtcs[3].getDataType();
assertTrue(dt instanceof BitFieldDataType);
BitFieldDataType bfDt = (BitFieldDataType) dt;
DataType bdt = bfDt.getBaseDataType();
assertEquals("/Category1/Category2/BF.conflict", bdt.getPathName());
assertTrue(bdt.isEquivalent(td));
assertEquals(2, bfDt.getDeclaredBitSize());
assertEquals(6, bfDt.getBitOffset());
assertEquals(4, dtcs[4].getOffset()); // base on original 2-byte length 1st byte remains undefined
assertEquals("bf2", dtcs[4].getFieldName());
assertEquals("my bf2", dtcs[4].getComment());
dt = dtcs[4].getDataType();
assertTrue(dt instanceof BitFieldDataType);
bfDt = (BitFieldDataType) dt;
bdt = bfDt.getBaseDataType();
assertEquals("/Category1/Category2/BF.conflict", bdt.getPathName());
assertTrue(bdt.isEquivalent(td));
assertEquals(2, bfDt.getDeclaredBitSize());
assertEquals(4, bfDt.getBitOffset());
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
// Structure_1 should contain MY Foo
assertEquals(foo, dtcs[5].getDataType());
dtcs = foo.getComponents();
assertEquals(5, dtcs.length);
assertTrue(dtcs[4].getDataType().isEquivalent(new FloatDataType()));
checkConflictCount(1);
}
@Test
public void testEditUnions() throws Exception {
@ -896,7 +1085,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
try {
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(s, TaskMonitorAdapter.DUMMY);
// 2 components should get removed from CoolUnion
commit = true;
}
@ -988,7 +1177,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
try {
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(s, TaskMonitorAdapter.DUMMY);
// 2 components should get removed from CoolUnion
commit = true;
}
@ -1070,10 +1259,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
try {
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(s, TaskMonitorAdapter.DUMMY);
DataType dt =
dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -1157,10 +1346,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
try {
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(s, TaskMonitorAdapter.DUMMY);
DataType dt =
dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -1245,10 +1434,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
try {
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(s, TaskMonitorAdapter.DUMMY);
DataType dt =
dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -1332,10 +1521,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
try {
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(s, TaskMonitorAdapter.DUMMY);
DataType dt =
dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -1425,10 +1614,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
try {
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(s, TaskMonitorAdapter.DUMMY);
DataType dt =
dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -1526,10 +1715,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
try {
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(s, TaskMonitorAdapter.DUMMY);
DataType dt =
dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
commit = true;
}
finally {
@ -1624,4 +1813,109 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
checkConflictCount(0);
}
@Test
public void testEditUnions9() throws Exception {
mtf.initialize("notepad", new OriginalProgramModifierListener() {
@Override
public void modifyOriginal(ProgramDB program) throws Exception {
boolean commit = false;
DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test");
try {
Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "XYZ", 1);
enumm.add("one", 1);
enumm.add("two", 2);
enumm.add("three", 3);
dtm.addDataType(
new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnum", enumm),
null);
commit = true;
}
finally {
program.endTransaction(transactionID, commit);
}
}
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test");
try {
DataType enumm = dtm.getDataType(new CategoryPath("/Category1"), "XYZ");
dtm.remove(enumm, TaskMonitor.DUMMY);
Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"),
"CoolUnion");
// NOTE: bit field component byte sizing is currently auto-sized and packed within unions
union.insertBitField(1, IntegerDataType.dataType, 4, "bf1", "latest bf1");
union.insertBitField(2, IntegerDataType.dataType, 2, "bf2", "latest bf2");
commit = true;
}
catch (InvalidDataTypeException e) {
e.printStackTrace();
Assert.fail();
}
finally {
program.endTransaction(transactionID, commit);
}
}
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test");
try {
DataType enumm = dtm.getDataType(new CategoryPath("/Category1"), "XYZ");
assertTrue(enumm instanceof Enum);
Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"),
"CoolUnion");
// NOTE: bit field component byte sizing is currently auto-sized and packed within unions
union.insertBitField(1, enumm, 4, "BF1", "my bf1");
union.insertBitField(2, enumm, 2, "BF2", "my bf2");
commit = true;
}
catch (InvalidDataTypeException e) {
e.printStackTrace();
Assert.fail();
}
finally {
program.endTransaction(transactionID, commit);
}
}
});
executeMerge();
DataTypeManager dtm = resultProgram.getDataTypeManager();
chooseOption(DataTypeMergeManager.OPTION_MY);// MY bitfields w/ enum
waitForCompletion();
// primitive type of byte used in absence of enum
Union union =
(Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
//@formatter:off
assertEquals("/Category1/Category2/CoolUnion\n" +
"Unaligned\n" +
"Union CoolUnion {\n" +
" 0 qword 8 null \"\"\n" +
" 0 byte:4(4) 1 BF1 \"my bf1\"\n" +
" 0 byte:2(6) 1 BF2 \"my bf2\"\n" +
" 0 word 2 null \"\"\n" +
" 0 undefined * * * * * 4 null \"\"\n" +
" 0 DLL_Table 96 null \"\"\n" +
" 0 DLL_Table * 4 null \"\"\n" +
"}\n" +
"Size = 96 Actual Alignment = 1\n", union.toString());
//@formatter:on
}
}

View file

@ -15,8 +15,7 @@
*/
package ghidra.app.merge.datatypes;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import javax.swing.JLabel;
@ -163,7 +162,7 @@ public class DataTypeMerge8Test extends AbstractDataTypeMergeTest {
JLabel label = (JLabel) TestUtils.getInstanceField("label", logPanel);
String statusText = label.getText();
String expectedText =
"Merging Data Types: Not enough undefined bytes to fit /XYZ in structure " +
"Structure Merge: Not enough undefined bytes to fit /XYZ in structure " +
"/MISC/ABC at offset 0x4.\nIt needs 3 more byte(s) to be able to fit.";
assertTrue(statusText.contains(expectedText));
}

View file

@ -141,7 +141,7 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
}
@Override
public DataType getParent() {
public Composite getParent() {
return parent;
}

View file

@ -25,6 +25,7 @@ import ghidra.program.model.data.*;
import ghidra.program.model.data.AlignedStructurePacker.StructurePackResult;
import ghidra.program.model.mem.MemBuffer;
import ghidra.util.Msg;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.InvalidInputException;
/**
@ -640,6 +641,13 @@ class StructureDB extends CompositeDB implements Structure {
}
}
/**
* Create copy of structure for target dtm (source archive information is discarded).
* WARNING! copying unaligned structures which contain bitfields can produce
* invalid results when switching endianess due to the differences in packing order.
* @param dtm target data type manager
* @return cloned structure
*/
@Override
public DataType copy(DataTypeManager dtm) {
StructureDataType struct =
@ -649,6 +657,13 @@ class StructureDB extends CompositeDB implements Structure {
return struct;
}
/**
* Create cloned structure for target dtm preserving source archive information.
* WARNING! cloning unaligned structures which contain bitfields can produce
* invalid results when switching endianess due to the differences in packing order.
* @param dtm target data type manager
* @return cloned structure
*/
@Override
public DataType clone(DataTypeManager dtm) {
StructureDataType struct =
@ -891,12 +906,28 @@ class StructureDB extends CompositeDB implements Structure {
@Override
public DataTypeComponent insertAtOffset(int offset, DataType dataType, int length, String name,
String comment) {
lock.acquire();
try {
checkDeleted();
if (offset < 0) {
throw new IllegalArgumentException("Offset cannot be negative.");
}
if (dataType instanceof BitFieldDataType) {
BitFieldDataType bfDt = (BitFieldDataType) dataType;
if (length <= 0) {
length = dataType.getLength();
}
try {
return insertBitFieldAt(offset, length, bfDt.getBitOffset(), bfDt.getBaseDataType(),
bfDt.getDeclaredBitSize(), name, comment);
}
catch (InvalidDataTypeException e) {
throw new AssertException(e);
}
}
lock.acquire();
try {
checkDeleted();
validateDataType(dataType);
dataType = resolve(dataType);
@ -966,6 +997,10 @@ class StructureDB extends CompositeDB implements Structure {
if (ordinal < 0 || ordinal >= numComponents) {
throw new ArrayIndexOutOfBoundsException(ordinal);
}
if (dataType instanceof BitFieldDataType) {
throw new IllegalArgumentException(
"Components may not be replaced with a bit-field");
}
validateDataType(dataType);
DataTypeComponent origDtc = getComponent(ordinal);
@ -1085,19 +1120,14 @@ class StructureDB extends CompositeDB implements Structure {
componentAdapter.removeRecord(dtc.getKey());
}
components.clear();
numComponents = 0;
structLength = 0;
if (flexibleArrayComponent != null) {
flexibleArrayComponent.getDataType().removeParent(this);
componentAdapter.removeRecord(flexibleArrayComponent.getKey());
flexibleArrayComponent = null;
}
if (struct.isNotYetDefined()) {
numComponents = 0;
structLength = 0;
}
else {
structLength = struct.getLength();
numComponents = isInternallyAligned() ? 0 : structLength;
}
setAlignment(struct, false);
@ -1154,14 +1184,17 @@ class StructureDB extends CompositeDB implements Structure {
private void doReplaceWithUnaligned(Structure struct) throws IOException {
// assumes components is clear and that alignment characteristics have been set.
if (struct.isNotYetDefined()) {
return;
}
// NOTE: unaligned bitfields should remain unchanged when
// transitioning endianess even though it makes little sense.
// Unaligned structures are not intended to be portable!
structLength = struct.getLength();
numComponents = structLength;
DataTypeComponent[] otherComponents = struct.getDefinedComponents();
for (int i = 0; i < otherComponents.length; i++) {
DataTypeComponent dtc = otherComponents[i];
DataType dt = resolve(dtc.getDataType());
checkAncestry(dt);

View file

@ -196,9 +196,8 @@ public interface Structure extends Composite {
public void deleteAtOffset(int offset);
/**
* Remove all components from this structure, effectively setting the
* length to zero.
*
* Remove all components from this structure (including flex-array),
* effectively setting the length to zero.
*/
public void deleteAll();

View file

@ -23,6 +23,7 @@ import ghidra.program.model.data.AlignedStructurePacker.StructurePackResult;
import ghidra.program.model.mem.MemBuffer;
import ghidra.util.Msg;
import ghidra.util.UniversalID;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.InvalidInputException;
/**
@ -297,9 +298,25 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
@Override
public DataTypeComponentImpl insertAtOffset(int offset, DataType dataType, int length,
String componentName, String comment) {
if (offset < 0) {
throw new IllegalArgumentException("Offset cannot be negative.");
}
if (dataType instanceof BitFieldDataType) {
BitFieldDataType bfDt = (BitFieldDataType) dataType;
if (length <= 0) {
length = dataType.getLength();
}
try {
return insertBitFieldAt(offset, length, bfDt.getBitOffset(), bfDt.getBaseDataType(),
bfDt.getDeclaredBitSize(), componentName, comment);
}
catch (InvalidDataTypeException e) {
throw new AssertException(e);
}
}
validateDataType(dataType);
dataType = dataType.clone(dataMgr);
@ -524,7 +541,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
}
@Override
public DataTypeComponent insertBitFieldAt(int byteOffset, int byteWidth, int bitOffset,
public DataTypeComponentImpl insertBitFieldAt(int byteOffset, int byteWidth, int bitOffset,
DataType baseDataType, int bitSize, String componentName, String comment)
throws InvalidDataTypeException {
@ -847,6 +864,13 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
return available;
}
/**
* Create copy of structure for target dtm (source archive information is discarded).
* WARNING! copying unaligned structures which contain bitfields can produce
* invalid results when switching endianess due to the differences in packing order.
* @param dtm target data type manager
* @return cloned structure
*/
@Override
public DataType copy(DataTypeManager dtm) {
StructureDataType struct = new StructureDataType(categoryPath, getName(), getLength(), dtm);
@ -855,6 +879,13 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
return struct;
}
/**
* Create cloned structure for target dtm preserving source archive information.
* WARNING! cloning unaligned structures which contain bitfields can produce
* invalid results when switching endianess due to the differences in packing order.
* @param dtm target data type manager
* @return cloned structure
*/
@Override
public DataType clone(DataTypeManager dtm) {
if (dataMgr == dtm) {
@ -907,15 +938,9 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
int oldLength = structLength;
components.clear();
flexibleArrayComponent = null;
if (struct.isNotYetDefined()) {
structLength = 0;
numComponents = 0;
}
else {
structLength = struct.getLength();
numComponents = isInternallyAligned() ? 0 : structLength;
}
flexibleArrayComponent = null;
setAlignment(struct);
@ -950,14 +975,17 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
private void doReplaceWithUnaligned(Structure struct) {
// assumes components is clear and that alignment characteristics have been set.
if (struct.isNotYetDefined()) {
return;
}
// NOTE: unaligned bitfields should remain unchanged when
// transitioning endianess even though it makes little sense.
// Unaligned structures are not intended to be portable!
structLength = struct.getLength();
numComponents = structLength;
DataTypeComponent[] otherComponents = struct.getDefinedComponents();
for (int i = 0; i < otherComponents.length; i++) {
DataTypeComponent dtc = otherComponents[i];
DataType dt = dtc.getDataType().clone(dataMgr);
checkAncestry(dt);