GP-7090 PR and additional test case for split AdressTable from

references and address table sizes
This commit is contained in:
emteere
2026-08-11 15:39:39 -04:00
parent ea5863548e
commit 75a3b5a028

View File

@@ -23,34 +23,40 @@ import org.junit.*;
import generic.test.AbstractGenericTest; import generic.test.AbstractGenericTest;
import ghidra.app.cmd.data.CreateDataCmd; import ghidra.app.cmd.data.CreateDataCmd;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
import ghidra.program.database.ProgramBuilder; import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB; import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet; import ghidra.program.model.address.AddressSet;
import ghidra.program.model.data.ArrayDataType; import ghidra.program.model.data.*;
import ghidra.program.model.data.Undefined1DataType; import ghidra.program.model.listing.*;
import ghidra.program.model.listing.Bookmark;
import ghidra.program.model.listing.BookmarkType;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Listing;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class AddressTableAnalyzerTest extends AbstractGenericTest { public class AddressTableAnalyzerTest extends AbstractGenericTest {
private static final String BaseUndefinedAddrStr = "0x101100";
private ProgramDB program; private ProgramDB program;
private ProgramBuilder builder; private ProgramBuilder builder;
private int pointerSize; private int pointerSize;
private String[] targets; private String[] targets;
private Address[] tableAddrs;
private AddressTableAnalyzer tableAnalyzer = new AddressTableAnalyzer();
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
targets = new String[] { "0x101000", "0x101100", "0x101200", "0x101300" }; targets = new String[] { "0x101000", "0x101100", "0x101200", "0x101300", "0x0", "0x101400", "0x101500", "0x0", "0x101600" };
builder = new ProgramBuilder("AddressTableAnalyzerTest", ProgramBuilder._X64); builder = new ProgramBuilder("AddressTableAnalyzerTest", ProgramBuilder._X64);
builder.createMemory(".text", "0x100000", 0x1000); builder.createMemory(".text", "0x100000", 0x1000);
builder.createMemory(".data", "0x101000", 0x1000); builder.createMemory(".data", "0x101000", 0x1000);
program = builder.getProgram(); program = builder.getProgram();
pointerSize = program.getDefaultPointerSize(); pointerSize = program.getDefaultPointerSize();
tableAddrs = new Address[targets.length];
for (int i = 0; i < tableAddrs.length; i++) {
tableAddrs[i] = builder.addr(BaseUndefinedAddrStr).add(i*pointerSize);
}
} }
@After @After
@@ -59,33 +65,172 @@ public class AddressTableAnalyzerTest extends AbstractGenericTest {
} }
@Test @Test
public void testAnalyzerCreatesTableOverUndefinedData() throws Exception { public void testAnalyzerCreatesTableOverDefaultData() throws Exception {
assertAnalyzerCreatesTableOver(undefinedDataType()); setMinTableSize(1);
setupAndAnalyzeTables(Undefined.getUndefinedDataType(1));
assertBookmarkAt(BaseUndefinedAddrStr);
assertAnalyzerCreatesTableAt(BaseUndefinedAddrStr,4,true);
assertBookmarkAt("0x101128");
assertAnalyzerCreatesTableAt("0x101128",2,true);
assertBookmarkAt("0x101140");
assertAnalyzerCreatesTableAt("0x101140",1,false);
} }
@Test
public void testAnalyzerCreatesTableOverUndefined1Data() throws Exception {
setMinTableSize(1);
setupAndAnalyzeTables(Undefined.getUndefinedDataType(1));
assertBookmarkAt(BaseUndefinedAddrStr);
assertAnalyzerCreatesTableAt(BaseUndefinedAddrStr,4,true);
assertBookmarkAt("0x101128");
assertAnalyzerCreatesTableAt("0x101128",2,true);
assertBookmarkAt("0x101140");
assertAnalyzerCreatesTableAt("0x101140",1,false);
}
@Test
public void testAnalyzerCreatesTableOverUndefined4Data() throws Exception {
setMinTableSize(1);
setupAndAnalyzeTables(Undefined.getUndefinedDataType(4));
assertBookmarkAt(BaseUndefinedAddrStr);
assertAnalyzerCreatesTableAt(BaseUndefinedAddrStr,4,true);
assertBookmarkAt("0x101128");
assertAnalyzerCreatesTableAt("0x101128",2,true);
assertBookmarkAt("0x101140");
assertAnalyzerCreatesTableAt("0x101140",1,false);
}
@Test @Test
public void testAnalyzerCreatesTableOverUndefinedArray() throws Exception { public void testAnalyzerCreatesTableOverUndefinedPointerArray() throws Exception {
assertAnalyzerCreatesTableOver(undefinedArrayDataType(targets.length * pointerSize)); setMinTableSize(1);
setupAndAnalyzeTables(Undefined.getUndefinedDataType(pointerSize));
assertBookmarkAt(BaseUndefinedAddrStr);
assertAnalyzerCreatesTableAt(BaseUndefinedAddrStr,4,true);
assertBookmarkAt("0x101128");
assertAnalyzerCreatesTableAt("0x101128",2,true);
assertBookmarkAt("0x101140");
assertAnalyzerCreatesTableAt("0x101140",1,false);
}
@Test
public void testAnalyzerCreatesTableMinSize2() throws Exception {
setMinTableSize(2);
setupAndAnalyzeTables(Undefined.getUndefinedDataType(1));
assertBookmarkAt(BaseUndefinedAddrStr);
assertAnalyzerCreatesTableAt(BaseUndefinedAddrStr,4,true);
assertNoBookmarkAt("0x101120");
assertNoDataAt("0x101120");
assertBookmarkAt("0x101128");
assertAnalyzerCreatesTableAt("0x101128",2,true);
assertNoBookmarkAt("0x101140");
assertNoDataAt("0x101140");
}
@Test
public void testAnalyzerCreatesTableWithReference() throws Exception {
String InternalTableRefAddrStr = "0x101108";
// reference should split tables
builder.createMemoryReadReference("0x100000", InternalTableRefAddrStr);
setupAndAnalyzeTables(Undefined.getUndefinedDataType(1));
assertBookmarkAt(BaseUndefinedAddrStr);
assertAnalyzerCreatesTableAt(BaseUndefinedAddrStr,1,false);
assertAnalyzerCreatesTableAt(InternalTableRefAddrStr,3,true);
assertBookmarkAt(InternalTableRefAddrStr);
}
@Test
public void testAnalyzerCreatesTableWithReferenceMinSize2() throws Exception {
String InternalTableRefAddrStr = "0x101108";
// reference should split tables
builder.createMemoryReadReference("0x100000", InternalTableRefAddrStr);
setMinTableSize(2);
setupAndAnalyzeTables(null);
assertNoBookmarkAt(BaseUndefinedAddrStr);
assertNoDataAt(BaseUndefinedAddrStr);
assertAnalyzerCreatesTableAt(InternalTableRefAddrStr,3,true);
assertBookmarkAt(InternalTableRefAddrStr);
} }
private void assertAnalyzerCreatesTableOver(ArrayDataType dataType) throws Exception {
Address tableStart = builder.addr("0x101100"); @Test
public void testAnalyzerCreatesTableOverUndefinedArrayDataMinSize() throws Exception {
setMinTableSize(2);
setupAndAnalyzeTables(Undefined.getUndefinedDataType(pointerSize));
assertAnalyzerCreatesTableAt(BaseUndefinedAddrStr,4,true);
assertNoBookmarkAt("0x101120");
assertNoDataAt("0x101120");
assertBookmarkAt("0x101128");
assertAnalyzerCreatesTableAt("0x101128",2,true);
assertNoBookmarkAt("0x101140");
assertNoDataAt("0x101140");
}
@Test
public void testAnalyzerCreatesTableWithReferenceOverUndefinedArrayData() throws Exception {
String InternalTableRefAddrStr = "0x101108";
// reference should split tables
builder.createMemoryReadReference("0x100000", InternalTableRefAddrStr);
setMinTableSize(1);
setupAndAnalyzeTables(Undefined.getUndefinedDataType(pointerSize));
assertBookmarkAt(BaseUndefinedAddrStr);
assertAnalyzerCreatesTableAt(BaseUndefinedAddrStr,1,false);
assertAnalyzerCreatesTableAt(InternalTableRefAddrStr,3,true);
assertBookmarkAt(InternalTableRefAddrStr);
}
private void setupAndAnalyzeTables(DataType elemDataType) throws Exception {
Address tableStart = builder.addr(BaseUndefinedAddrStr);
layOutAddressTable(tableStart); layOutAddressTable(tableStart);
defineUndefinedArray(tableStart, dataType.getLength()); if (elemDataType != null) {
defineUndefinedArray(tableStart, elemDataType, (targets.length*pointerSize) / elemDataType.getLength());
}
runAnalyzer(tableStart); runAnalyzer(tableStart,tableStart.add(targets.length*pointerSize));
}
private void assertAnalyzerCreatesTableAt(String tableStartStr, int size, boolean nothingFollows) throws Exception {
Address tableStart = builder.addr(tableStartStr);
Listing listing = program.getListing(); Listing listing = program.getListing();
for (int i = 0; i < targets.length; i++) { for (int i = 0; i < size; i++) {
Data slot = listing.getDefinedDataAt(tableStart.add(i * pointerSize)); Data slot = listing.getDefinedDataAt(tableStart.add(i * pointerSize));
assertNotNull("missing pointer at table[" + i + "]", slot); assertNotNull("missing pointer at table[" + i + "]", slot);
assertTrue("table[" + i + "] should be a pointer", slot.isPointer()); assertTrue("table[" + i + "] should be a pointer", slot.isPointer());
} }
if (nothingFollows) {
Data slot = listing.getDefinedDataAt(tableStart.add(size * pointerSize));
assertNull("Should not be a pointer defined", slot);
}
}
private void assertNoDataAt(String addrStr) {
Address addr = builder.addr(addrStr);
Data data = program.getListing().getDefinedDataAt(addr);
if (data == null) {
return;
}
assertTrue(Undefined.isUndefined(data.getDataType()));
}
private void assertBookmarkAt(String tableStartStr) {
Address tableStart = builder.addr(tableStartStr);
Bookmark bookmark = program.getBookmarkManager() Bookmark bookmark = program.getBookmarkManager()
.getBookmark(tableStart, BookmarkType.ANALYSIS, "Address Table"); .getBookmark(tableStart, BookmarkType.ANALYSIS, "Address Table");
assertNotNull("bookmark should have been created", bookmark); assertNotNull("bookmark should have been created at " + tableStart, bookmark);
}
private void assertNoBookmarkAt(String tableStartStr) {
Address tableStart = builder.addr(tableStartStr);
Bookmark bookmark = program.getBookmarkManager()
.getBookmark(tableStart, BookmarkType.ANALYSIS, "Address Table");
assertNull("bookmark should NOT have been created at " + tableStart, bookmark);
} }
private void layOutAddressTable(Address tableStart) throws Exception { private void layOutAddressTable(Address tableStart) throws Exception {
@@ -95,28 +240,34 @@ public class AddressTableAnalyzerTest extends AbstractGenericTest {
} }
} }
private ArrayDataType undefinedDataType() { private void defineUndefinedArray(Address at, DataType elementType, int numElements) {
return undefinedArrayDataType(pointerSize);
}
private ArrayDataType undefinedArrayDataType(int byteLength) {
return new ArrayDataType(new Undefined1DataType(), byteLength, 1);
}
private void defineUndefinedArray(Address at, int byteLength) {
builder.withTransaction(() -> { builder.withTransaction(() -> {
new CreateDataCmd(at, undefinedArrayDataType(byteLength)) new CreateDataCmd(at, new ArrayDataType(elementType,numElements))
.applyTo(program); .applyTo(program);
}); });
} }
private void setMinTableSize(int size) {
builder.tx(() -> {
int txId = program.startTransaction("Analyze");
Options analysisOptions = program.getOptions(Program.ANALYSIS_PROPERTIES);
analysisOptions.setInt("Create Address Tables.Minimum Table Size", size);
tableAnalyzer.optionsChanged(analysisOptions.getOptions("Create Address Tables"), program);
program.endTransaction(txId, true);
});
}
private void runAnalyzer(Address inSet) throws CancelledException { private void runAnalyzer(Address start, Address end) {
int tx = program.startTransaction("analyze"); builder.tx(() -> {
try { tableAnalyzer.added(program, new AddressSet(start, end),
new AddressTableAnalyzer().added(program, new AddressSet(inSet, inSet),
TaskMonitor.DUMMY, new MessageLog()); TaskMonitor.DUMMY, new MessageLog());
} finally { // need to let full analysis run, as each table found schedules
program.endTransaction(tx, true); // follow on create table analysis so that effects of found table can be processed,
} // then new tables found
builder.analyze();
});
} }
} }