mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-25 07:18:49 +08:00
Merge branch 'GT-3479_ghidra1_BitfieldMerge' into patch
This commit is contained in:
+666
-239
File diff suppressed because it is too large
Load Diff
+106
-179
File diff suppressed because it is too large
Load Diff
+320
-26
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-4
@@ -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;
|
||||
|
||||
@@ -37,7 +36,7 @@ import ghidra.util.task.TaskMonitorAdapter;
|
||||
public class DataTypeMerge8Test extends AbstractDataTypeMergeTest {
|
||||
|
||||
@Test
|
||||
public void testConflictFixUpForNonFittingStruct() throws Exception {
|
||||
public void testConflictFixUpForNonFittingStruct() throws Exception {
|
||||
|
||||
final CategoryPath miscPath = new CategoryPath("/MISC");
|
||||
final CategoryPath rootPath = new CategoryPath("/");
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
+1
-1
@@ -141,7 +141,7 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getParent() {
|
||||
public Composite getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
|
||||
+47
-14
@@ -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) {
|
||||
|
||||
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();
|
||||
if (offset < 0) {
|
||||
throw new IllegalArgumentException("Offset cannot be negative.");
|
||||
}
|
||||
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);
|
||||
|
||||
|
||||
+2
-3
@@ -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();
|
||||
|
||||
|
||||
+40
-12
@@ -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;
|
||||
|
||||
/**
|
||||
@@ -292,9 +293,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);
|
||||
@@ -519,7 +536,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 {
|
||||
|
||||
@@ -842,6 +859,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);
|
||||
@@ -850,6 +874,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) {
|
||||
@@ -902,15 +933,9 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
||||
int oldLength = structLength;
|
||||
|
||||
components.clear();
|
||||
structLength = 0;
|
||||
numComponents = 0;
|
||||
flexibleArrayComponent = null;
|
||||
if (struct.isNotYetDefined()) {
|
||||
structLength = 0;
|
||||
numComponents = 0;
|
||||
}
|
||||
else {
|
||||
structLength = struct.getLength();
|
||||
numComponents = isInternallyAligned() ? 0 : structLength;
|
||||
}
|
||||
|
||||
setAlignment(struct);
|
||||
|
||||
@@ -945,14 +970,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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user