GP-3883 added source file manager

This commit is contained in:
James
2023-10-13 14:57:59 +00:00
parent 420dd7ce0c
commit 9aeeaa4397
52 changed files with 8432 additions and 306 deletions
@@ -0,0 +1,108 @@
/* ###
* 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.program.database.sourcemap;
import org.junit.Before;
import generic.test.AbstractGenericTest;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.sourcemap.SourceFileManager;
import ghidra.test.ToyProgramBuilder;
public class AbstractSourceFileTest extends AbstractGenericTest {
protected Program program;
protected ToyProgramBuilder builder;
protected int baseOffset = 0x1001000;
protected Address baseAddress;
protected SourceFile source1;
protected SourceFile source2;
protected SourceFile source3;
protected Instruction ret2_1;
protected Instruction ret2_2;
protected Instruction ret2_3;
protected Instruction nop1_1;
protected Instruction nop1_2;
protected Instruction nop1_3;
protected Instruction ret2_4;
protected Instruction nop1_4;
protected String path1 = "/test1";
protected String path2 = "/test2/test2";
protected String path3 = "/test3/test3/test3";
protected String path4 = "/test4/test4/test4/test4";
protected SourceFileManager sourceManager;
@Before
public void setUp() throws Exception {
builder = new ToyProgramBuilder("testprogram", true, false, this);
int txID = builder.getProgram().startTransaction("create source map test program");
long currentOffset = baseOffset;
try {
builder.createMemory(".text", Integer.toHexString(baseOffset), 64).setExecute(true);
builder.addBytesReturn(currentOffset);
currentOffset += 2;
builder.addBytesNOP(currentOffset++, 1);
builder.addBytesReturn(currentOffset);
currentOffset += 2;
builder.addBytesNOP(currentOffset++, 1);
builder.addBytesReturn(currentOffset);
currentOffset += 2;
builder.addBytesNOP(currentOffset++, 1);
builder.addBytesReturn(currentOffset);
currentOffset += 2;
builder.addBytesNOP(currentOffset++, 1);
builder.disassemble(Integer.toHexString(baseOffset),
(int) (currentOffset - baseOffset));
}
finally {
builder.getProgram().endTransaction(txID, true);
}
program = builder.getProgram();
baseAddress = program.getAddressFactory().getDefaultAddressSpace().getAddress(baseOffset);
InstructionIterator instIter = program.getListing().getInstructions(baseAddress, true);
ret2_1 = instIter.next();
nop1_1 = instIter.next();
ret2_2 = instIter.next();
nop1_2 = instIter.next();
ret2_3 = instIter.next();
nop1_3 = instIter.next();
ret2_4 = instIter.next();
nop1_4 = instIter.next();
sourceManager = program.getSourceFileManager();
source1 = new SourceFile(path1);
source2 = new SourceFile(path2);
source3 = new SourceFile(path3);
//leave path4 as String without a corresponding source file
txID = program.startTransaction("adding source files");
try {
sourceManager.addSourceFile(source1);
sourceManager.addSourceFile(source2);
sourceManager.addSourceFile(source3);
}
finally {
program.endTransaction(txID, true);
}
builder.dispose();
}
protected AddressRange getBody(CodeUnit cu) {
return new AddressRangeImpl(cu.getMinAddress(), cu.getMaxAddress());
}
}
@@ -0,0 +1,131 @@
/* ###
* 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.program.database.sourcemap;
import static org.junit.Assert.*;
import java.util.List;
import org.junit.Test;
import ghidra.framework.store.LockException;
import ghidra.program.model.sourcemap.SourceMapEntry;
public class GetSourceFilesTest extends AbstractSourceFileTest {
@Test
public void testGetAllSourceFiles() throws LockException {
List<SourceFile> sourceFiles = sourceManager.getAllSourceFiles();
assertEquals(3, sourceFiles.size());
assertTrue(sourceFiles.contains(source1));
assertTrue(sourceFiles.contains(source2));
assertTrue(sourceFiles.contains(source3));
int txId = program.startTransaction("deleting source file 2");
try {
sourceManager.removeSourceFile(source2);
}
finally {
program.endTransaction(txId, true);
}
sourceFiles = sourceManager.getAllSourceFiles();
assertEquals(2, sourceFiles.size());
assertTrue(sourceFiles.contains(source1));
assertTrue(sourceFiles.contains(source3));
txId = program.startTransaction("deleting source files");
try {
sourceManager.removeSourceFile(source1);
sourceManager.removeSourceFile(source3);
}
finally {
program.endTransaction(txId, true);
}
assertTrue(sourceManager.getAllSourceFiles().isEmpty());
}
@Test
public void testGetMappedSourceFiles() throws LockException {
List<SourceFile> sourceFiles = sourceManager.getMappedSourceFiles();
assertTrue(sourceFiles.isEmpty());
int txId = program.startTransaction("adding source map info");
try {
sourceManager.addSourceMapEntry(source1, 1, getBody(ret2_1));
}
finally {
program.endTransaction(txId, true);
}
sourceFiles = sourceManager.getMappedSourceFiles();
assertEquals(1, sourceFiles.size());
SourceFile file = sourceFiles.get(0);
assertEquals(source1.getPath(), file.getPath());
txId = program.startTransaction("adding source map info");
try {
sourceManager.addSourceMapEntry(source2, 1, getBody(ret2_2));
}
finally {
program.endTransaction(txId, true);
}
sourceFiles = sourceManager.getMappedSourceFiles();
assertEquals(2, sourceFiles.size());
assertTrue(sourceFiles.contains(source1));
assertTrue(sourceFiles.contains(source2));
txId = program.startTransaction("transferring source map entries");
try {
sourceManager.transferSourceMapEntries(source2, source3);
}
finally {
program.endTransaction(txId, true);
}
sourceFiles = sourceManager.getMappedSourceFiles();
assertEquals(2, sourceFiles.size());
assertTrue(sourceFiles.contains(source1));
assertTrue(sourceFiles.contains(source3));
txId = program.startTransaction("deleting source1");
try {
sourceManager.removeSourceFile(source1);
}
finally {
program.endTransaction(txId, true);
}
sourceFiles = sourceManager.getMappedSourceFiles();
assertEquals(1, sourceFiles.size());
assertTrue(sourceFiles.contains(source3));
txId = program.startTransaction("clearing mapping info for source3");
try {
List<SourceMapEntry> entries = sourceManager.getSourceMapEntries(source3);
for (SourceMapEntry entry : entries) {
assertTrue(sourceManager.removeSourceMapEntry(entry));
}
}
finally {
program.endTransaction(txId, true);
}
sourceFiles = sourceManager.getMappedSourceFiles();
assertTrue(sourceFiles.isEmpty());
}
}
@@ -0,0 +1,222 @@
/* ###
* 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.program.database.sourcemap;
import static org.junit.Assert.*;
import java.util.*;
import org.junit.Test;
import ghidra.framework.store.LockException;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressOverflowException;
import ghidra.program.model.sourcemap.*;
public class SourceMapEntryIteratorTest extends AbstractSourceFileTest {
@Test
public void testInappropriateAddress() {
assertFalse(sourceManager.getSourceMapEntryIterator(null, true).hasNext());
assertFalse(sourceManager.getSourceMapEntryIterator(null, false).hasNext());
assertFalse(sourceManager.getSourceMapEntryIterator(Address.NO_ADDRESS, true).hasNext());
assertFalse(sourceManager.getSourceMapEntryIterator(Address.NO_ADDRESS, false).hasNext());
}
@Test
public void testDummySourceManagerIterators() {
Address address = ret2_1.getAddress();
assertFalse(
SourceFileManager.DUMMY.getSourceMapEntryIterator(address, true).hasNext());
assertFalse(
SourceFileManager.DUMMY.getSourceMapEntryIterator(address, false).hasNext());
}
@Test(expected = NoSuchElementException.class)
public void testNoSuchElementExceptionForward() throws AddressOverflowException, LockException {
SourceMapEntry entry1 = null;
int txId = program.startTransaction("adding source map entry");
try {
entry1 = sourceManager.addSourceMapEntry(source1, 1, ret2_1.getAddress(), 2);
}
finally {
program.endTransaction(txId, true);
}
SourceMapEntryIterator iter =
sourceManager.getSourceMapEntryIterator(ret2_1.getAddress(), true);
assertTrue(iter.hasNext());
assertEquals(entry1, iter.next());
assertFalse(iter.hasNext());
iter.next();
}
@Test(expected = NoSuchElementException.class)
public void testNoSuchElementExceptionBackward()
throws AddressOverflowException, LockException {
SourceMapEntry entry1 = null;
int txId = program.startTransaction("adding source map entry");
try {
entry1 = sourceManager.addSourceMapEntry(source1, 1, ret2_1.getAddress(), 2);
}
finally {
program.endTransaction(txId, true);
}
SourceMapEntryIterator iter =
sourceManager.getSourceMapEntryIterator(ret2_1.getAddress(), false);
assertTrue(iter.hasNext());
assertEquals(entry1, iter.next());
assertFalse(iter.hasNext());
iter.next();
}
@Test
public void testForwardIterator() throws AddressOverflowException, LockException {
int txId = program.startTransaction("adding first source map entry");
SourceMapEntry entry1 = null;
SourceMapEntry entry2 = null;
SourceMapEntry entry3 = null;
SourceMapEntry entry4 = null;
SourceMapEntry entry5 = null;
SourceMapEntryIterator iter =
sourceManager.getSourceMapEntryIterator(ret2_1.getAddress(), true);
for (int i = 0; i < 10; i++) {
assertFalse(iter.hasNext());
}
try {
entry1 = sourceManager.addSourceMapEntry(source1, 1, ret2_1.getAddress(), 2);
entry2 = sourceManager.addSourceMapEntry(source1, 2, ret2_1.getAddress(), 2);
entry3 = sourceManager.addSourceMapEntry(source2, 3, ret2_1.getAddress().add(1), 0);
entry4 = sourceManager.addSourceMapEntry(source3, 4, nop1_1.getAddress(), 1);
entry5 = sourceManager.addSourceMapEntry(source3, 5, nop1_1.getAddress(), 1);
}
finally {
program.endTransaction(txId, true);
}
Set<SourceMapEntry> entries = new HashSet<>();
iter = sourceManager.getSourceMapEntryIterator(ret2_1.getAddress(), true);
for (int i = 0; i < 10; i++) {
assertTrue(iter.hasNext());
}
entries.add(iter.next());
assertTrue(iter.hasNext());
entries.add(iter.next());
assertTrue(entries.contains(entry1));
assertTrue(entries.contains(entry2));
entries.clear();
assertTrue(iter.hasNext());
assertEquals(entry3, iter.next());
assertTrue(iter.hasNext());
entries.add(iter.next());
assertTrue(iter.hasNext());
entries.add(iter.next());
assertTrue(entries.contains(entry4));
assertTrue(entries.contains(entry5));
assertFalse(iter.hasNext());
entries.clear();
iter = sourceManager.getSourceMapEntryIterator(ret2_1.getAddress().add(1), true);
assertTrue(iter.hasNext());
assertEquals(entry3, iter.next());
assertTrue(iter.hasNext());
entries.add(iter.next());
assertTrue(iter.hasNext());
entries.add(iter.next());
assertTrue(entries.contains(entry4));
assertTrue(entries.contains(entry5));
assertFalse(iter.hasNext());
iter = sourceManager.getSourceMapEntryIterator(ret2_2.getAddress(), true);
assertFalse(iter.hasNext());
}
@Test
public void testBackwardIterator() throws AddressOverflowException, LockException {
int txId = program.startTransaction("adding first source map entry");
SourceMapEntry entry1 = null;
SourceMapEntry entry2 = null;
SourceMapEntry entry3 = null;
SourceMapEntry entry4 = null;
SourceMapEntry entry5 = null;
SourceMapEntryIterator iter =
sourceManager.getSourceMapEntryIterator(ret2_1.getAddress(), false);
for (int i = 0; i < 10; i++) {
assertFalse(iter.hasNext());
}
try {
entry1 = sourceManager.addSourceMapEntry(source1, 1, ret2_1.getAddress(), 2);
entry2 = sourceManager.addSourceMapEntry(source1, 2, ret2_1.getAddress(), 2);
entry3 = sourceManager.addSourceMapEntry(source2, 3, ret2_1.getAddress().add(1), 0);
entry4 = sourceManager.addSourceMapEntry(source3, 4, nop1_1.getAddress(), 1);
entry5 = sourceManager.addSourceMapEntry(source3, 5, nop1_1.getAddress(), 1);
}
finally {
program.endTransaction(txId, true);
}
Set<SourceMapEntry> entries = new HashSet<>();
iter = sourceManager.getSourceMapEntryIterator(nop1_1.getAddress(), false);
for (int i = 0; i < 10; i++) {
assertTrue(iter.hasNext());
}
entries.add(iter.next());
assertTrue(iter.hasNext());
entries.add(iter.next());
assertTrue(entries.contains(entry4));
assertTrue(entries.contains(entry5));
entries.clear();
assertTrue(iter.hasNext());
assertEquals(entry3, iter.next());
assertTrue(iter.hasNext());
entries.add(iter.next());
assertTrue(iter.hasNext());
entries.add(iter.next());
assertTrue(entries.contains(entry1));
assertTrue(entries.contains(entry1));
assertFalse(iter.hasNext());
entries.clear();
iter = sourceManager.getSourceMapEntryIterator(ret2_1.getAddress().add(1), false);
assertTrue(iter.hasNext());
assertEquals(entry3, iter.next());
assertTrue(iter.hasNext());
entries.add(iter.next());
assertTrue(iter.hasNext());
entries.add(iter.next());
assertTrue(entries.contains(entry1));
assertTrue(entries.contains(entry2));
assertFalse(iter.hasNext());
}
}