mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-26 22:21:52 +00:00
fixed issues related to image base changes for stored address ranges maps. This affects register context and program tree fragments
This commit is contained in:
parent
07a9878b94
commit
0b65bf2f0c
@ -0,0 +1,986 @@
|
||||
/* ###
|
||||
* 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.map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import db.Field;
|
||||
import db.LongField;
|
||||
import db.util.ErrorHandler;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.database.mem.MemoryMapDB;
|
||||
import ghidra.program.database.util.AddressRangeMapDB;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.test.TestEnv;
|
||||
import ghidra.util.Lock;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public abstract class AbstractAddressRangeMapTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
private TestEnv env; // needed to discover languages
|
||||
private ProgramDB program;
|
||||
private AddressMap addrMap;
|
||||
private AddressSpace space;
|
||||
private int txId;
|
||||
|
||||
protected static Field ONE = new LongField(1);
|
||||
protected static Field TWO = new LongField(2);
|
||||
protected AddressRangeMapDB map;
|
||||
protected Address spaceMax;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
env = new TestEnv();
|
||||
|
||||
program = createProgram();
|
||||
MemoryMapDB memory = (MemoryMapDB) program.getMemory();
|
||||
addrMap = (AddressMap) getInstanceField("addrMap", memory);
|
||||
space = program.getAddressFactory().getDefaultAddressSpace();
|
||||
spaceMax = space.getMaxAddress();
|
||||
ErrorHandler errHandler = e -> fail();
|
||||
|
||||
map = new AddressRangeMapDB(program.getDBHandle(), addrMap,
|
||||
new Lock("Test"), "TEST", errHandler, LongField.INSTANCE, true);
|
||||
txId = program.startTransaction("test");
|
||||
}
|
||||
|
||||
protected abstract ProgramDB createProgram() throws IOException;
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
program.endTransaction(txId, false);
|
||||
if (program != null) {
|
||||
program.release(this);
|
||||
}
|
||||
addrMap = null;
|
||||
env.dispose();
|
||||
}
|
||||
|
||||
protected Address addr(long offset) {
|
||||
return space.getAddress(offset);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPaint() {
|
||||
map.paintRange(addr(0x100), addr(0x200), ONE);
|
||||
map.paintRange(addr(0x300), addr(0x400), TWO);
|
||||
|
||||
List<AddressRange> ranges = getMapRanges();
|
||||
assertEquals(2, ranges.size());
|
||||
assertEquals(range(addr(0x100), addr(0x200)), ranges.get(0));
|
||||
assertEquals(range(addr(0x300), addr(0x400)), ranges.get(1));
|
||||
|
||||
checkRange(ranges.get(0), ONE);
|
||||
checkRange(ranges.get(1), TWO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPaintOverlap() {
|
||||
assertNull(map.getValue(addr(0x200)));
|
||||
|
||||
map.paintRange(addr(0x100), addr(0x300), ONE);
|
||||
map.paintRange(addr(0x200), addr(0x400), TWO);
|
||||
|
||||
List<AddressRange> ranges = getMapRanges();
|
||||
assertEquals(2, ranges.size());
|
||||
assertEquals(range(addr(0x100), addr(0x1ff)), ranges.get(0));
|
||||
assertEquals(range(addr(0x200), addr(0x400)), ranges.get(1));
|
||||
|
||||
checkRange(ranges.get(0), ONE, null, TWO);
|
||||
checkRange(ranges.get(1), TWO, ONE, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPaintCoallesceWithLowerExistingRange() {
|
||||
map.paintRange(addr(0x100), addr(0x200), ONE);
|
||||
map.paintRange(addr(0x200), addr(0x300), ONE);
|
||||
|
||||
List<AddressRange> ranges = getMapRanges();
|
||||
assertEquals(1, ranges.size());
|
||||
assertEquals(range(addr(0x100), addr(0x300)), ranges.get(0));
|
||||
|
||||
checkRange(ranges.get(0), ONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPaintCoallesceWithHigherExistingRange() {
|
||||
map.paintRange(addr(0x200), addr(0x300), ONE);
|
||||
map.paintRange(addr(0x100), addr(0x200), ONE);
|
||||
|
||||
List<AddressRange> ranges = getMapRanges();
|
||||
assertEquals(1, ranges.size());
|
||||
assertEquals(range(addr(0x100), addr(0x300)), ranges.get(0));
|
||||
|
||||
checkRange(ranges.get(0), ONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPaintSplitExistingRangeWithNewValue() {
|
||||
map.paintRange(addr(0x100), addr(0x400), ONE);
|
||||
map.paintRange(addr(0x200), addr(0x300), TWO);
|
||||
|
||||
List<AddressRange> ranges = getMapRanges();
|
||||
assertEquals(3, ranges.size());
|
||||
assertEquals(range(addr(0x100), addr(0x1ff)), ranges.get(0));
|
||||
assertEquals(range(addr(0x200), addr(0x300)), ranges.get(1));
|
||||
assertEquals(range(addr(0x301), addr(0x400)), ranges.get(2));
|
||||
|
||||
checkRange(ranges.get(0), ONE, null, TWO);
|
||||
checkRange(ranges.get(1), TWO, ONE, ONE);
|
||||
checkRange(ranges.get(2), ONE, TWO, null);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPaintStartOfExitingRangeWithNewValue() {
|
||||
map.paintRange(addr(0x200), addr(0x400), ONE);
|
||||
map.paintRange(addr(0x100), addr(0x300), TWO);
|
||||
|
||||
List<AddressRange> ranges = getMapRanges();
|
||||
assertEquals(2, ranges.size());
|
||||
assertEquals(range(addr(0x100), addr(0x300)), ranges.get(0));
|
||||
assertEquals(range(addr(0x301), addr(0x400)), ranges.get(1));
|
||||
|
||||
checkRange(ranges.get(0), TWO, null, ONE);
|
||||
checkRange(ranges.get(1), ONE, TWO, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPaintSameValueInsideExistingRange() {
|
||||
map.paintRange(addr(0x100), addr(0x200), ONE);
|
||||
map.paintRange(addr(0x110), addr(0x150), ONE);
|
||||
|
||||
List<AddressRange> ranges = getMapRanges();
|
||||
assertEquals(1, ranges.size());
|
||||
assertEquals(range(addr(0x100), addr(0x200)), ranges.get(0));
|
||||
|
||||
checkRange(ranges.get(0), ONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValueRecordWithStartKeyGreaterThanEndKey() {
|
||||
addrMap.setImageBase(addr(0x100));
|
||||
// address 0 will have a high key, and address 0x200 will have a low key
|
||||
map.paintRange(addr(0), addr(0x200), ONE);
|
||||
|
||||
checkValueNoCache(ONE, addr(0x0));
|
||||
checkValueNoCache(ONE, addr(0x1));
|
||||
checkValueNoCache(ONE, addr(0xff));
|
||||
checkValueNoCache(ONE, addr(0x100));
|
||||
checkValueNoCache(ONE, addr(0x101));
|
||||
checkValueNoCache(ONE, addr(0x1ff));
|
||||
checkValueNoCache(ONE, addr(0x200));
|
||||
checkValueNoCache(null, addr(0x201));
|
||||
checkValueNoCache(null, spaceMax);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValueWithWrappingAddressRecordAndStartKeyGreaterThanEndKey() {
|
||||
addrMap.setImageBase(addr(0x200));
|
||||
// address 0 will have a high key, and address 0x200 will have a low key
|
||||
map.paintRange(addr(0), addr(0x400), ONE);
|
||||
addrMap.setImageBase(addr(0x100));
|
||||
map.invalidate();
|
||||
|
||||
checkValueNoCache(ONE, addr(0x0));
|
||||
checkValueNoCache(ONE, addr(0xff));
|
||||
checkValueNoCache(ONE, addr(0x100));
|
||||
checkValueNoCache(ONE, addr(0x101));
|
||||
checkValueNoCache(ONE, addr(0x1ff));
|
||||
checkValueNoCache(ONE, addr(0x200));
|
||||
checkValueNoCache(ONE, addr(0x201));
|
||||
checkValueNoCache(ONE, addr(0x2ff));
|
||||
checkValueNoCache(ONE, addr(0x300));
|
||||
checkValueNoCache(null, addr(0x301));
|
||||
checkValueNoCache(null, addr(0).subtractWrap(0x101));
|
||||
checkValueNoCache(ONE, addr(0).subtractWrap(0x100));
|
||||
checkValueNoCache(ONE, addr(0).subtractWrap(0x0ff));
|
||||
checkValueNoCache(ONE, spaceMax);
|
||||
}
|
||||
|
||||
protected void checkValueNoCache(Field expectedValue, Address address) {
|
||||
map.invalidate(); // clears cache
|
||||
assertEquals(expectedValue, map.getValue(address));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRecordCount() {
|
||||
assertEquals(0, map.getRecordCount());
|
||||
|
||||
map.paintRange(addr(0x100), addr(0x200), ONE);
|
||||
assertEquals(1, map.getRecordCount());
|
||||
|
||||
map.paintRange(addr(0x300), addr(0x400), ONE);
|
||||
assertEquals(2, map.getRecordCount());
|
||||
|
||||
// paint the gap should result in only 1 record
|
||||
map.paintRange(addr(0x200), addr(0x300), ONE);
|
||||
assertEquals(1, map.getRecordCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveAddressRange() throws CancelledException {
|
||||
map.paintRange(addr(0x100), addr(0x300), ONE);
|
||||
|
||||
map.moveAddressRange(addr(0x200), addr(0x500), 0x200, TaskMonitor.DUMMY);
|
||||
|
||||
List<AddressRange> ranges = getMapRanges();
|
||||
assertEquals(2, ranges.size());
|
||||
assertEquals(range(addr(0x100), addr(0x1ff)), ranges.get(0));
|
||||
assertEquals(range(addr(0x500), addr(0x600)), ranges.get(1));
|
||||
|
||||
checkRange(ranges.get(0), ONE);
|
||||
checkRange(ranges.get(1), ONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsEmpty() {
|
||||
assertTrue(map.isEmpty());
|
||||
|
||||
map.paintRange(addr(0x100), addr(0x900), ONE);
|
||||
assertFalse(map.isEmpty());
|
||||
|
||||
map.clearRange(addr(0), addr(0x1000));
|
||||
assertTrue(map.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPaintFullRangeWithNonZeroImageBase() {
|
||||
Address imageBase = addr(0x50);
|
||||
|
||||
addrMap.setImageBase(imageBase);
|
||||
|
||||
AddressRange range = range(space.getMinAddress(), space.getMaxAddress());
|
||||
map.paintRange(range.getMinAddress(), range.getMaxAddress(), ONE);
|
||||
|
||||
assertEquals(ONE, map.getValue(addr(0)));
|
||||
assertEquals(ONE, map.getValue(addr(0x200)));
|
||||
assertEquals(ONE, map.getValue(space.getMaxAddress()));
|
||||
|
||||
List<AddressRange> ranges = getMapRanges();
|
||||
assertEquals(1, ranges.size());
|
||||
assertEquals(range, ranges.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddressRangeIteratorWithNoTable() {
|
||||
AddressRangeIterator it = map.getAddressRanges();
|
||||
assertFalse(it.hasNext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIteratorWithMultipleRangesIncludeOneThatSpansAddressBoundary() {
|
||||
|
||||
Address imageBase = addr(0x100);
|
||||
|
||||
AddressRange range1 = range(addr(0x0), addr(0x10));
|
||||
AddressRange range2 = range(addr(0x20), addr(0x30));
|
||||
AddressRange range3 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range4 = range(spaceMax.subtract(0x500), spaceMax);
|
||||
|
||||
addrMap.setImageBase(imageBase);
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
map.paintRange(range4.getMinAddress(), range4.getMaxAddress(), ONE);
|
||||
|
||||
checkRange(range1, ONE);
|
||||
checkRange(range2, ONE);
|
||||
checkRange(range3, ONE);
|
||||
checkRange(range4, ONE);
|
||||
|
||||
List<AddressRange> ranges = getMapRanges();
|
||||
assertEquals(4, ranges.size());
|
||||
assertEquals(range1, ranges.get(0));
|
||||
assertEquals(range2, ranges.get(1));
|
||||
assertEquals(range3, ranges.get(2));
|
||||
assertEquals(range4, ranges.get(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddressIteratorWithStartAddressBeforeFirstRange() {
|
||||
AddressRange range2 = range(addr(0x20), addr(0x30));
|
||||
AddressRange range3 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range4 = range(addr(0x500), spaceMax);
|
||||
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
map.paintRange(range4.getMinAddress(), range4.getMaxAddress(), ONE);
|
||||
|
||||
// try iterating starting in first range
|
||||
List<AddressRange> ranges = getMapRanges(addr(0x5));
|
||||
assertEquals(3, ranges.size());
|
||||
assertEquals(range2, ranges.get(0));
|
||||
assertEquals(range3, ranges.get(1));
|
||||
assertEquals(range4, ranges.get(2));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddressIteratorWithStartAddressInFirstRange() {
|
||||
AddressRange range1 = range(addr(0x0), addr(0x10));
|
||||
AddressRange range2 = range(addr(0x20), addr(0x30));
|
||||
AddressRange range3 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range4 = range(addr(0x500), spaceMax);
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
map.paintRange(range4.getMinAddress(), range4.getMaxAddress(), ONE);
|
||||
|
||||
// try iterating starting in first range
|
||||
List<AddressRange> ranges = getMapRanges(addr(0x5));
|
||||
assertEquals(4, ranges.size());
|
||||
assertEquals(range(addr(0x5), range1.getMaxAddress()), ranges.get(0));
|
||||
assertEquals(range2, ranges.get(1));
|
||||
assertEquals(range3, ranges.get(2));
|
||||
assertEquals(range4, ranges.get(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddressIteratorWithStartAddressBetweenFirstAndSecondRange() {
|
||||
AddressRange range1 = range(addr(0x0), addr(0x10));
|
||||
AddressRange range2 = range(addr(0x20), addr(0x30));
|
||||
AddressRange range3 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range4 = range(addr(0x500), spaceMax);
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
map.paintRange(range4.getMinAddress(), range4.getMaxAddress(), ONE);
|
||||
|
||||
// try iterating starting in first range
|
||||
List<AddressRange> ranges = getMapRanges(addr(0x15));
|
||||
assertEquals(3, ranges.size());
|
||||
assertEquals(range2, ranges.get(0));
|
||||
assertEquals(range3, ranges.get(1));
|
||||
assertEquals(range4, ranges.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddressIteratorWithStartAddressInSecondRange() {
|
||||
AddressRange range1 = range(addr(0x0), addr(0x10));
|
||||
AddressRange range2 = range(addr(0x20), addr(0x30));
|
||||
AddressRange range3 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range4 = range(addr(0x500), spaceMax);
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
map.paintRange(range4.getMinAddress(), range4.getMaxAddress(), ONE);
|
||||
|
||||
// try iterating starting in first range
|
||||
List<AddressRange> ranges = getMapRanges(addr(0x25));
|
||||
assertEquals(3, ranges.size());
|
||||
assertEquals(range(addr(0x25), range2.getMaxAddress()), ranges.get(0));
|
||||
assertEquals(range3, ranges.get(1));
|
||||
assertEquals(range4, ranges.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddressIteratorWithStartAddressInLastRange() {
|
||||
AddressRange range1 = range(addr(0x0), addr(0x10));
|
||||
AddressRange range2 = range(addr(0x20), addr(0x30));
|
||||
AddressRange range3 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range4 = range(addr(0x500), addr(0x1000));
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
map.paintRange(range4.getMinAddress(), range4.getMaxAddress(), ONE);
|
||||
|
||||
// try iterating starting in first range
|
||||
List<AddressRange> ranges = getMapRanges(addr(0x600));
|
||||
assertEquals(1, ranges.size());
|
||||
assertEquals(range(addr(0x600), range4.getMaxAddress()), ranges.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddressIteratorWithStartAddressAfterLastRange() {
|
||||
AddressRange range1 = range(addr(0x0), addr(0x10));
|
||||
AddressRange range2 = range(addr(0x20), addr(0x30));
|
||||
AddressRange range3 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range4 = range(addr(0x500), addr(0x600));
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
map.paintRange(range4.getMinAddress(), range4.getMaxAddress(), ONE);
|
||||
|
||||
// try iterating after last range
|
||||
List<AddressRange> ranges = getMapRanges(addr(0x1000));
|
||||
assertEquals(0, ranges.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddressIteratorWithImageBaseStartAddressInFirstRange() {
|
||||
|
||||
Address imageBase = addr(0x100);
|
||||
addrMap.setImageBase(imageBase);
|
||||
|
||||
AddressRange range1 = range(addr(0x0), addr(0x10));
|
||||
AddressRange range2 = range(addr(0x20), addr(0x30));
|
||||
AddressRange range3 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range4 = range(spaceMax.subtract(0x500), spaceMax);
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
map.paintRange(range4.getMinAddress(), range4.getMaxAddress(), ONE);
|
||||
|
||||
// try iterating starting in first range
|
||||
List<AddressRange> ranges = getMapRanges(addr(0x5));
|
||||
assertEquals(4, ranges.size());
|
||||
assertEquals(range(addr(0x5), range1.getMaxAddress()), ranges.get(0));
|
||||
assertEquals(range2, ranges.get(1));
|
||||
assertEquals(range3, ranges.get(2));
|
||||
assertEquals(range4, ranges.get(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddressIteratorWithImageBaseStartAddressBetweenFirstAndSecondRange() {
|
||||
|
||||
Address imageBase = addr(0x100);
|
||||
addrMap.setImageBase(imageBase);
|
||||
|
||||
AddressRange range1 = range(addr(0x0), addr(0x10));
|
||||
AddressRange range2 = range(addr(0x20), addr(0x30));
|
||||
AddressRange range3 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range4 = range(addr(0x500), spaceMax);
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
map.paintRange(range4.getMinAddress(), range4.getMaxAddress(), ONE);
|
||||
|
||||
// try iterating starting in first range
|
||||
List<AddressRange> ranges = getMapRanges(addr(0x15));
|
||||
assertEquals(3, ranges.size());
|
||||
assertEquals(range2, ranges.get(0));
|
||||
assertEquals(range3, ranges.get(1));
|
||||
assertEquals(range4, ranges.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddressIteratorWithImageBaseStartAddressInSecondRange() {
|
||||
|
||||
Address imageBase = addr(0x100);
|
||||
addrMap.setImageBase(imageBase);
|
||||
|
||||
AddressRange range1 = range(addr(0x0), addr(0x10));
|
||||
AddressRange range2 = range(addr(0x20), addr(0x30));
|
||||
AddressRange range3 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range4 = range(addr(0x500), spaceMax);
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
map.paintRange(range4.getMinAddress(), range4.getMaxAddress(), ONE);
|
||||
|
||||
// try iterating starting in first range
|
||||
List<AddressRange> ranges = getMapRanges(addr(0x25));
|
||||
assertEquals(3, ranges.size());
|
||||
assertEquals(range(addr(0x25), range2.getMaxAddress()), ranges.get(0));
|
||||
assertEquals(range3, ranges.get(1));
|
||||
assertEquals(range4, ranges.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddressIteratorWithImageBaseStartAddressInLastRange() {
|
||||
|
||||
Address imageBase = addr(0x100);
|
||||
addrMap.setImageBase(imageBase);
|
||||
|
||||
AddressRange range1 = range(addr(0x0), addr(0x10));
|
||||
AddressRange range2 = range(addr(0x20), addr(0x30));
|
||||
AddressRange range3 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range4 = range(addr(0x500), spaceMax);
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
map.paintRange(range4.getMinAddress(), range4.getMaxAddress(), ONE);
|
||||
|
||||
// try iterating starting in first range
|
||||
List<AddressRange> ranges = getMapRanges(addr(0x600));
|
||||
assertEquals(1, ranges.size());
|
||||
assertEquals(range(addr(0x600), range4.getMaxAddress()), ranges.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAddressIteratorWithStartAndEndBeforeFirstRange() {
|
||||
AddressRange range1 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range2 = range(addr(0x300), addr(0x400));
|
||||
AddressRange range3 = range(addr(0x600), addr(0x700));
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
|
||||
// try iterating starting in first range
|
||||
List<AddressRange> ranges = getMapRanges(addr(0x20), addr(0x50));
|
||||
assertEquals(0, ranges.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAddressIteratorWithStartAndEndBeforeInsideRange() {
|
||||
AddressRange range1 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range2 = range(addr(0x300), addr(0x400));
|
||||
AddressRange range3 = range(addr(0x600), addr(0x700));
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
|
||||
// try iterating starting in first range
|
||||
List<AddressRange> ranges = getMapRanges(addr(0x310), addr(0x390));
|
||||
assertEquals(1, ranges.size());
|
||||
assertEquals(range(addr(0x310), addr(0x390)), ranges.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAddressIteratorWithStartInOneRangeEndInAnother() {
|
||||
AddressRange range1 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range2 = range(addr(0x300), addr(0x400));
|
||||
AddressRange range3 = range(addr(0x600), addr(0x700));
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
|
||||
// try iterating starting in first range
|
||||
List<AddressRange> ranges = getMapRanges(addr(0x310), addr(0x610));
|
||||
assertEquals(2, ranges.size());
|
||||
assertEquals(range(addr(0x310), addr(0x400)), ranges.get(0));
|
||||
assertEquals(range(addr(0x600), addr(0x610)), ranges.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAddressIteratorWithStartAndEndPastLastRange() {
|
||||
AddressRange range1 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range2 = range(addr(0x300), addr(0x400));
|
||||
AddressRange range3 = range(addr(0x600), addr(0x700));
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
|
||||
// try iterating starting in first range
|
||||
List<AddressRange> ranges = getMapRanges(addr(0x800), addr(0x900));
|
||||
assertEquals(0, ranges.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAddressIteratorWithImageBaseStartingAndEndingInSpanningRecord() {
|
||||
Address imageBase = addr(0x150);
|
||||
addrMap.setImageBase(imageBase);
|
||||
|
||||
AddressRange range1 = range(addr(0x0), addr(0x100));
|
||||
AddressRange range2 = range(addr(0x200), addr(0x300));
|
||||
AddressRange range3 = range(addr(0x500), addr(0x600));
|
||||
AddressRange range4 = range(addr(0x800), spaceMax);
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
map.paintRange(range4.getMinAddress(), range4.getMaxAddress(), ONE);
|
||||
|
||||
List<AddressRange> ranges = getMapRanges(addr(0x50), addr(0x1000));
|
||||
assertEquals(4, ranges.size());
|
||||
assertEquals(range(addr(0x50), range1.getMaxAddress()), ranges.get(0));
|
||||
assertEquals(range2, ranges.get(1));
|
||||
assertEquals(range3, ranges.get(2));
|
||||
assertEquals(range(range4.getMinAddress(), addr(0x1000)), ranges.get(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAddressIteratorWithImageBaseWithStartAndEndIncludeAll() {
|
||||
Address imageBase = addr(0x250);
|
||||
addrMap.setImageBase(imageBase);
|
||||
AddressRange range1 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range2 = range(addr(0x300), addr(0x400));
|
||||
AddressRange range3 = range(addr(0x600), addr(0x700));
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
|
||||
// try iterating starting in first range
|
||||
List<AddressRange> ranges = getMapRanges(addr(0x150), addr(0x650));
|
||||
assertEquals(3, ranges.size());
|
||||
assertEquals(range(addr(0x150), range1.getMaxAddress()), ranges.get(0));
|
||||
assertEquals(range2, ranges.get(1));
|
||||
assertEquals(range(range3.getMinAddress(), addr(0x650)), ranges.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAddressIteratorWithImageBaseStartInOneRangeEndInAnother() {
|
||||
AddressRange range1 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range2 = range(addr(0x300), addr(0x400));
|
||||
AddressRange range3 = range(addr(0x600), addr(0x700));
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
|
||||
// try iterating starting in first range
|
||||
List<AddressRange> ranges = getMapRanges(addr(0x310), addr(0x610));
|
||||
assertEquals(2, ranges.size());
|
||||
assertEquals(range(addr(0x310), addr(0x400)), ranges.get(0));
|
||||
assertEquals(range(addr(0x600), addr(0x610)), ranges.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAddressSet() {
|
||||
map.paintRange(addr(0x100), addr(0x200), ONE);
|
||||
map.paintRange(addr(0x300), addr(0x400), TWO);
|
||||
|
||||
AddressSet set = map.getAddressSet();
|
||||
assertEquals(2, set.getNumAddressRanges());
|
||||
assertEquals(range(addr(0x100), addr(0x200)), set.getFirstRange());
|
||||
assertEquals(range(addr(0x300), addr(0x400)), set.getLastRange());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAddressSetWithImageBaseSet() {
|
||||
addrMap.setImageBase(addr(0x100));
|
||||
map.paintRange(addr(0), spaceMax, ONE);
|
||||
AddressSet set = map.getAddressSet();
|
||||
assertEquals(1, set.getNumAddressRanges());
|
||||
assertEquals(range(addr(0), spaceMax), set.getFirstRange());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAddressRangeContaining() {
|
||||
AddressRange range1 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range2 = range(addr(0x300), addr(0x400));
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), TWO);
|
||||
|
||||
assertEquals(range1, map.getAddressRangeContaining(addr(0x100)));
|
||||
assertEquals(range1, map.getAddressRangeContaining(addr(0x150)));
|
||||
assertEquals(range1, map.getAddressRangeContaining(addr(0x200)));
|
||||
assertEquals(range2, map.getAddressRangeContaining(addr(0x300)));
|
||||
assertEquals(range2, map.getAddressRangeContaining(addr(0x350)));
|
||||
assertEquals(range2, map.getAddressRangeContaining(addr(0x400)));
|
||||
|
||||
assertEquals(range(addr(0), addr(0xff)), map.getAddressRangeContaining(addr(0x0)));
|
||||
assertEquals(range(addr(0x201), addr(0x2ff)), map.getAddressRangeContaining(addr(0x250)));
|
||||
assertEquals(range(addr(0x401), spaceMax), map.getAddressRangeContaining(addr(0x900)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRangeContainingWithStartKeyGreaterThanEndKey() {
|
||||
AddressRange range = range(addr(0), addr(0x200));
|
||||
AddressRange noValueRange = range(addr(0x201), spaceMax);
|
||||
addrMap.setImageBase(addr(0x100));
|
||||
// address 0 will have a high key, and address 0x200 will have a low key
|
||||
map.paintRange(range.getMinAddress(), range.getMaxAddress(), ONE);
|
||||
|
||||
assertEquals(range, map.getAddressRangeContaining(addr(0)));
|
||||
assertEquals(range, map.getAddressRangeContaining(addr(0x100)));
|
||||
assertEquals(range, map.getAddressRangeContaining(addr(0x200)));
|
||||
|
||||
assertEquals(noValueRange, map.getAddressRangeContaining(addr(0x201)));
|
||||
assertEquals(noValueRange, map.getAddressRangeContaining(addr(0x500)));
|
||||
assertEquals(noValueRange, map.getAddressRangeContaining(spaceMax));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRangeContainingWithWrappingAddressRecordAndStartKeyGreaterThanEndKey() {
|
||||
addrMap.setImageBase(addr(0x200));
|
||||
// address 0 will have a high key, and address 0x200 will have a low key
|
||||
map.paintRange(addr(0), addr(0x400), ONE);
|
||||
addrMap.setImageBase(addr(0x100));
|
||||
map.invalidate();
|
||||
|
||||
AddressRange rangeLow = range(addr(0), addr(0x300));
|
||||
AddressRange rangeHigh = range(addr(0).subtractWrap(0x100), spaceMax);
|
||||
AddressRange noValueRange = range(addr(0x301), rangeHigh.getMinAddress().subtract(1));
|
||||
|
||||
assertEquals(rangeLow, map.getAddressRangeContaining(addr(0)));
|
||||
assertEquals(rangeLow, map.getAddressRangeContaining(addr(0x100)));
|
||||
assertEquals(rangeLow, map.getAddressRangeContaining(addr(0x200)));
|
||||
assertEquals(rangeLow, map.getAddressRangeContaining(addr(0x300)));
|
||||
|
||||
assertEquals(rangeHigh, map.getAddressRangeContaining(spaceMax));
|
||||
assertEquals(rangeHigh, map.getAddressRangeContaining(rangeHigh.getMinAddress()));
|
||||
|
||||
assertEquals(noValueRange, map.getAddressRangeContaining(addr(0x301)));
|
||||
assertEquals(noValueRange, map.getAddressRangeContaining(addr(0x500)));
|
||||
assertEquals(noValueRange,
|
||||
map.getAddressRangeContaining(rangeHigh.getMinAddress().subtract(1)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAddressRangeContainingWithSpanningAddressBoundary() {
|
||||
map.paintRange(addr(0), addr(0x200), ONE);
|
||||
|
||||
// move the image base to make the above range partially wrap into upper address
|
||||
addrMap.setImageBase(addr(0).subtractWrap(0x100));
|
||||
|
||||
// there is still currently only one record
|
||||
assertEquals(1, map.getRecordCount());
|
||||
|
||||
List<AddressRange> ranges = getMapRanges();
|
||||
assertEquals(range(addr(0), addr(0x100)), ranges.get(0));
|
||||
assertEquals(range(addr(0).subtractWrap(0x100), spaceMax), ranges.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeWithImageBaseMoveToInsideRange() {
|
||||
map.paintRange(addr(0x10), addr(0x20), ONE);
|
||||
|
||||
assertNull(map.getValue(addr(0)));
|
||||
assertEquals(ONE, map.getValue(addr(0x10)));
|
||||
assertEquals(ONE, map.getValue(addr(0x15)));
|
||||
assertEquals(ONE, map.getValue(addr(0x20)));
|
||||
assertNull(map.getValue(addr(0x25)));
|
||||
|
||||
List<AddressRange> ranges = getMapRanges();
|
||||
assertEquals(1, ranges.size());
|
||||
assertEquals(range(addr(0x10), addr(0x20)), ranges.get(0));
|
||||
|
||||
Address imageBase = addr(0x15);
|
||||
addrMap.setImageBase(imageBase);
|
||||
// if the image base changes, the map has to be told so that it can clear its cache.
|
||||
map.invalidate();
|
||||
|
||||
// now range should be from 0x25 to 0x35
|
||||
assertNull(map.getValue(addr(0)));
|
||||
assertNull(map.getValue(addr(0x10)));
|
||||
assertNull(map.getValue(addr(0x15)));
|
||||
assertNull(map.getValue(addr(0x20)));
|
||||
assertEquals(ONE, map.getValue(addr(0x25)));
|
||||
assertEquals(ONE, map.getValue(addr(0x30)));
|
||||
assertEquals(ONE, map.getValue(addr(0x35)));
|
||||
assertNull(map.getValue(addr(0x36)));
|
||||
|
||||
ranges = getMapRanges();
|
||||
assertEquals(1, ranges.size());
|
||||
// image base will cause range to be two pieces, but effectively same set of addresses
|
||||
assertEquals(range(addr(0x25), addr(0x35)), ranges.get(0));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValueRangeSet() {
|
||||
AddressRange range1 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range2 = range(addr(0x300), addr(0x400));
|
||||
AddressRange range3 = range(addr(0x500), addr(0x600));
|
||||
AddressRange range4 = range(addr(0x700), addr(0x800));
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), TWO);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
map.paintRange(range4.getMinAddress(), range4.getMaxAddress(), TWO);
|
||||
|
||||
AddressSet setOne = addressSet(range1, range3);
|
||||
AddressSet setTwo = addressSet(range2, range4);
|
||||
|
||||
assertEquals(setOne, map.getAddressSet(ONE));
|
||||
assertEquals(setTwo, map.getAddressSet(TWO));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValueRangeSetWithNoGaps() {
|
||||
AddressRange range1 = range(addr(0x100), addr(0x500));
|
||||
AddressRange range2 = range(addr(0x200), addr(0x300));
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), TWO);
|
||||
|
||||
AddressSet setOne = addressSet(range1).subtract(addressSet(range2));
|
||||
AddressSet setTwo = addressSet(range2);
|
||||
|
||||
assertEquals(setOne, map.getAddressSet(ONE));
|
||||
assertEquals(setTwo, map.getAddressSet(TWO));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValueRangeSetWithImageBaseAndSpanningRecord() {
|
||||
Address imageBase = addr(0x150);
|
||||
addrMap.setImageBase(imageBase);
|
||||
|
||||
AddressRange range1 = range(addr(0x0), addr(0x100));
|
||||
AddressRange range2 = range(addr(0x300), addr(0x400));
|
||||
AddressRange range3 = range(addr(0x500), spaceMax);
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), TWO);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
|
||||
assertEquals(addressSet(range1, range3), map.getAddressSet(ONE));
|
||||
assertEquals(addressSet(range2), map.getAddressSet(TWO));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValueRangeSetWithValueNotInMap() {
|
||||
AddressRange range1 = range(addr(0x100), addr(0x500));
|
||||
AddressRange range2 = range(addr(0x200), addr(0x300));
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), ONE);
|
||||
|
||||
assertEquals(addressSet(), map.getAddressSet(TWO));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAddressSetForValue() {
|
||||
AddressRange range1 = range(addr(0x100), addr(0x200));
|
||||
AddressRange range2 = range(addr(0x300), addr(0x400));
|
||||
AddressRange range3 = range(addr(0x500), addr(0x600));
|
||||
AddressRange range4 = range(addr(0x700), addr(0x800));
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), TWO);
|
||||
map.paintRange(range3.getMinAddress(), range3.getMaxAddress(), ONE);
|
||||
map.paintRange(range4.getMinAddress(), range4.getMaxAddress(), TWO);
|
||||
|
||||
AddressSet addressSet = map.getAddressSet(ONE);
|
||||
assertEquals(2, addressSet.getNumAddressRanges());
|
||||
assertEquals(range1, addressSet.getFirstRange());
|
||||
assertEquals(range3, addressSet.getLastRange());
|
||||
|
||||
addressSet = map.getAddressSet(TWO);
|
||||
assertEquals(2, addressSet.getNumAddressRanges());
|
||||
assertEquals(range2, addressSet.getFirstRange());
|
||||
assertEquals(range4, addressSet.getLastRange());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPaintAfterImageBaseChangeSplitsWrappingRecord() {
|
||||
AddressRange range1 = range(addr(0x00), addr(0x200));
|
||||
AddressRange range2 = range(addr(0x500), addr(0x600));
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
assertEquals(1, map.getRecordCount());
|
||||
assertEquals(1, getMapRanges().size());
|
||||
assertEquals(range1, getMapRanges().get(0));
|
||||
|
||||
Address imageBase = spaceMax.subtract(0xff);
|
||||
addrMap.setImageBase(imageBase);
|
||||
map.invalidate();
|
||||
|
||||
assertEquals(1, map.getRecordCount());
|
||||
assertEquals(2, getMapRanges().size());
|
||||
assertEquals(range(addr(0), addr(0x100)), getMapRanges().get(0));
|
||||
assertEquals(range(imageBase, spaceMax), getMapRanges().get(1));
|
||||
|
||||
// do another paint and see that the record got split
|
||||
// any paint will do, so do a paint that effectively does nothing
|
||||
map.paintRange(range2.getMinAddress(), range2.getMaxAddress(), null);
|
||||
assertEquals(2, map.getRecordCount());
|
||||
assertEquals(2, getMapRanges().size());
|
||||
assertEquals(range(imageBase, spaceMax), getMapRanges().get(0));
|
||||
assertEquals(range(addr(0), addr(0x100)), getMapRanges().get(1));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeIteratorWithRestrictionsSuchThatStartRangeIsOnlyRange() {
|
||||
AddressRange range1 = range(addr(0x00), addr(0x200));
|
||||
|
||||
map.paintRange(range1.getMinAddress(), range1.getMaxAddress(), ONE);
|
||||
assertEquals(1, map.getRecordCount());
|
||||
assertEquals(1, getMapRanges().size());
|
||||
assertEquals(range1, getMapRanges().get(0));
|
||||
|
||||
Address imageBase = spaceMax.subtract(0xff);
|
||||
addrMap.setImageBase(imageBase);
|
||||
map.invalidate();
|
||||
|
||||
List<AddressRange> ranges = getMapRanges(addr(0), addr(0x500));
|
||||
assertEquals(1, ranges.size());
|
||||
assertEquals(range(addr(0), addr(0x100)), ranges.get(0));
|
||||
|
||||
}
|
||||
|
||||
private AddressRange range(Address start, Address end) {
|
||||
return new AddressRangeImpl(start, end);
|
||||
}
|
||||
|
||||
private List<AddressRange> getMapRanges() {
|
||||
AddressRangeIterator addressRanges = map.getAddressRanges();
|
||||
List<AddressRange> ranges = new ArrayList<AddressRange>();
|
||||
for (AddressRange addressRange : addressRanges) {
|
||||
ranges.add(addressRange);
|
||||
}
|
||||
return ranges;
|
||||
}
|
||||
|
||||
private List<AddressRange> getMapRanges(Address start) {
|
||||
AddressRangeIterator addressRanges = map.getAddressRanges(start);
|
||||
List<AddressRange> ranges = new ArrayList<AddressRange>();
|
||||
for (AddressRange addressRange : addressRanges) {
|
||||
ranges.add(addressRange);
|
||||
}
|
||||
return ranges;
|
||||
}
|
||||
|
||||
private List<AddressRange> getMapRanges(Address start, Address end) {
|
||||
AddressRangeIterator addressRanges = map.getAddressRanges(start, end);
|
||||
List<AddressRange> ranges = new ArrayList<AddressRange>();
|
||||
for (AddressRange addressRange : addressRanges) {
|
||||
ranges.add(addressRange);
|
||||
}
|
||||
return ranges;
|
||||
}
|
||||
|
||||
private void checkRange(AddressRange range, Field value) {
|
||||
checkRange(range, value, null, null);
|
||||
}
|
||||
|
||||
private void checkRange(AddressRange range, Field value, Field valueBeforeRange,
|
||||
Field valueAfterRange) {
|
||||
Address start = range.getMinAddress();
|
||||
Address end = range.getMaxAddress();
|
||||
|
||||
assertEquals("Value at range start " + range, value, map.getValue(start));
|
||||
assertEquals("Value at range end " + range, value, map.getValue(end));
|
||||
|
||||
// if not at zero, check that value doesn't exist just before range;
|
||||
if (start.compareTo(addr(0)) > 0) {
|
||||
assertEquals("Value before range " + range, valueBeforeRange,
|
||||
map.getValue(start.subtract(1)));
|
||||
}
|
||||
|
||||
// if not at end, check that value doesn't exist just past range
|
||||
if (end.compareTo(spaceMax) < 0) {
|
||||
assertEquals("Value after range " + range, valueAfterRange, map.getValue(end.add(1)));
|
||||
}
|
||||
}
|
||||
|
||||
private AddressSet addressSet(AddressRange... ranges) {
|
||||
AddressSet set = new AddressSet();
|
||||
for (AddressRange range : ranges) {
|
||||
set.add(range);
|
||||
}
|
||||
return set;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/* ###
|
||||
* 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.map;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.model.lang.*;
|
||||
|
||||
public class AddressRangeMap32BitTest extends AbstractAddressRangeMapTest {
|
||||
|
||||
protected ProgramDB createProgram() throws IOException {
|
||||
LanguageService service = getLanguageService();
|
||||
Language language = service.getLanguage(new LanguageID("sparc:BE:32:default"));
|
||||
return new ProgramDB("test", language, language.getDefaultCompilerSpec(), this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/* ###
|
||||
* 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.map;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.model.lang.*;
|
||||
|
||||
public class AddressRangeMap64BitTest extends AbstractAddressRangeMapTest {
|
||||
|
||||
protected ProgramDB createProgram() throws IOException {
|
||||
LanguageService service = getLanguageService();
|
||||
Language language = service.getLanguage(new LanguageID("sparc:BE:64:default"));
|
||||
return new ProgramDB("test", language, language.getDefaultCompilerSpec(), this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValue64BitSpecific() {
|
||||
map.paintRange(addr(0), spaceMax, ONE);
|
||||
|
||||
checkValueNoCache(ONE, addr(0x0));
|
||||
checkValueNoCache(ONE, addr(0x0));
|
||||
|
||||
// now check addresses that are in different address bases that don't exist yet
|
||||
// addresses that differ in the upper 32bits are in different address basesI
|
||||
checkValueNoCache(ONE, addr(0xA0000000000000L));
|
||||
checkValueNoCache(ONE, addr(0xB0000000000000L));
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -30,6 +30,7 @@ import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.listing.ProgramContext;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
|
||||
/**
|
||||
@ -78,7 +79,7 @@ public class ProgramContextTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
int id = program.startTransaction("Test");
|
||||
try {
|
||||
|
||||
Address start = getAddress(0);
|
||||
Address start = addr(0);
|
||||
try {
|
||||
mem.createInitializedBlock("first", start, 100, (byte) 0,
|
||||
TaskMonitorAdapter.DUMMY_MONITOR, false);
|
||||
@ -91,7 +92,7 @@ public class ProgramContextTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
boolean didSomething = false;
|
||||
|
||||
Address startAddress = start;
|
||||
Address endAddress = getAddress(0x30);
|
||||
Address endAddress = addr(0x30);
|
||||
|
||||
// stick a value into each one!
|
||||
BigInteger value = BigInteger.valueOf(255);
|
||||
@ -157,8 +158,38 @@ public class ProgramContextTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
}
|
||||
}
|
||||
|
||||
private Address getAddress(long offset) {
|
||||
return space.getAddress(offset);
|
||||
@Test
|
||||
public void testImageBaseChange() throws Exception {
|
||||
int id = program.startTransaction("Test");
|
||||
Address start = addr(0x10);
|
||||
Address end = addr(0x20);
|
||||
|
||||
mem.createInitializedBlock("first", addr(0), 0x100, (byte) 0, TaskMonitor.DUMMY, false);
|
||||
|
||||
ProgramContext programContext = program.getProgramContext();
|
||||
|
||||
Register register = programContext.getRegisters().get(0);
|
||||
BigInteger value = BigInteger.valueOf(0x11);
|
||||
|
||||
programContext.setValue(register, addr(0x10), addr(0x20), value);
|
||||
assertNull(programContext.getValue(register, start.subtract(1), true));
|
||||
assertEquals(value, programContext.getValue(register, start, true));
|
||||
assertEquals(value, programContext.getValue(register, end, true));
|
||||
assertNull(programContext.getValue(register, end.add(1), true));
|
||||
|
||||
long imageOffset = 0x5;
|
||||
Address imageBase = addr(imageOffset);
|
||||
program.setImageBase(imageBase, true);
|
||||
|
||||
assertNull(programContext.getValue(register, start.add(imageOffset - 1), true));
|
||||
assertEquals(value, programContext.getValue(register, start.add(imageOffset), true));
|
||||
assertEquals(value, programContext.getValue(register, end.add(imageOffset), true));
|
||||
assertNull(programContext.getValue(register, end.add(imageOffset + 1), true));
|
||||
|
||||
program.endTransaction(id, false);
|
||||
}
|
||||
|
||||
private Address addr(long offset) {
|
||||
return space.getAddress(offset);
|
||||
}
|
||||
}
|
||||
|
@ -199,7 +199,6 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
||||
private int languageMinorVersion;
|
||||
private LanguageTranslator languageUpgradeTranslator;
|
||||
|
||||
private Address storedImageBase; // current image base maintained by addrMap
|
||||
private boolean imageBaseOverride = false;
|
||||
private boolean recordChanges;
|
||||
|
||||
@ -1204,7 +1203,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
||||
|
||||
private void refreshImageBase() throws IOException {
|
||||
long baseOffset = getStoredBaseImageOffset();
|
||||
storedImageBase = addressFactory.getDefaultAddressSpace().getAddress(baseOffset);
|
||||
Address storedImageBase = addressFactory.getDefaultAddressSpace().getAddress(baseOffset);
|
||||
if (!imageBaseOverride) {
|
||||
Address currentImageBase = getImageBase();
|
||||
if (!currentImageBase.equals(storedImageBase)) {
|
||||
@ -1356,7 +1355,6 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
||||
record.setString(0, Long.toHexString(base.getOffset()));
|
||||
table.putRecord(record);
|
||||
|
||||
storedImageBase = base;
|
||||
imageBaseOverride = false;
|
||||
|
||||
setChanged(ChangeManager.DOCR_IMAGE_BASE_CHANGED, oldBase, base);
|
||||
@ -1857,9 +1855,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
||||
refreshName();
|
||||
overlaySpaceAdapter.updateOverlaySpaces(addressFactory);
|
||||
addrMap.invalidateCache();
|
||||
if (!imageBaseOverride) {
|
||||
refreshImageBase();
|
||||
}
|
||||
refreshImageBase();
|
||||
for (int i = 0; i < NUM_MANAGERS; i++) {
|
||||
managers[i].invalidateCache(all);
|
||||
}
|
||||
|
@ -87,12 +87,19 @@ public interface AddressMap {
|
||||
* never be generated. The returned key ranges will correspond
|
||||
* to those key ranges which have previously been created within
|
||||
* the specified address range and may represent a much smaller subset
|
||||
* of addresses within the specified range.
|
||||
* @param start minimum address of range
|
||||
* of addresses within the specified range.
|
||||
* NOTE: if the create parameter is true, the given range must not extend in the upper 32 bits
|
||||
* by more than 1 segment. For example, range(0x0000000000000000 - 0x0000000100000000)
|
||||
* is acceptable, but the range (0x0000000000000000 - 0x0000000200000000) is not because the
|
||||
* upper 32 bits differ by 2.
|
||||
* @param start the start address of the range
|
||||
* @param end maximum address of range
|
||||
* @param create true if a new keys may be generated, otherwise returned
|
||||
* key-ranges will be limited to those already defined.
|
||||
* key-ranges will be limited to those already defined. And if true, the range will be limited
|
||||
* to a size of 2^32 so that at most it creates two new address bases
|
||||
* @return "sorted" list of KeyRange objects
|
||||
* @throws UnsupportedOperationException if the given range is so large that the upper 32 bit
|
||||
* segments differ by more than 1.
|
||||
*/
|
||||
public List<KeyRange> getKeyRanges(Address start, Address end, boolean create);
|
||||
|
||||
@ -136,7 +143,8 @@ public interface AddressMap {
|
||||
* key-ranges will be limited to those already defined.
|
||||
* @return "sorted" list of KeyRange objects
|
||||
*/
|
||||
public List<KeyRange> getKeyRanges(Address start, Address end, boolean absolute, boolean create);
|
||||
public List<KeyRange> getKeyRanges(Address start, Address end, boolean absolute,
|
||||
boolean create);
|
||||
|
||||
/**
|
||||
* Generates a properly ordered list of database key ranges for a
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package ghidra.program.database.map;
|
||||
|
||||
import static generic.util.UnsignedDataUtils.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
@ -803,15 +805,16 @@ public class AddressMapDB implements AddressMap {
|
||||
/**
|
||||
* Create all memory base segments within the specified range.
|
||||
* NOTE: minAddress and maxAddress must have the same address space!
|
||||
* @param minAddress
|
||||
* @param maxAddress
|
||||
* @param minAddress start address of the range
|
||||
* @param maxAddress last address of the range
|
||||
* @param absolute if the address are absolute and not relative
|
||||
*/
|
||||
private void createBaseSegments(Address minAddress, Address maxAddress) {
|
||||
private void createBaseSegments(Address minAddress, Address maxAddress, boolean absolute) {
|
||||
|
||||
long minBase;
|
||||
long maxBase;
|
||||
|
||||
if (isInDefaultAddressSpace(minAddress)) {
|
||||
if (!absolute && isInDefaultAddressSpace(minAddress)) {
|
||||
minBase = getNormalizedOffset(minAddress) & BASE_MASK;
|
||||
maxBase = getNormalizedOffset(maxAddress) & BASE_MASK;
|
||||
}
|
||||
@ -820,7 +823,15 @@ public class AddressMapDB implements AddressMap {
|
||||
maxBase = maxAddress.getOffset() & BASE_MASK;
|
||||
}
|
||||
|
||||
for (long base = minBase; base <= maxBase; base += (MAX_OFFSET + 1)) {
|
||||
long numBases = (maxBase >>> 32) - (minBase >>> 32);
|
||||
|
||||
if (numBases > 2) {
|
||||
throw new UnsupportedOperationException("Can't create address bases for a range that" +
|
||||
"extends across more than two upper 32 bit segments!");
|
||||
}
|
||||
|
||||
for (long base = minBase; unsignedLessThanOrEqual(base, maxBase); base +=
|
||||
(MAX_OFFSET + 1)) {
|
||||
getBaseAddressIndex(minAddress.getNewAddress(base), false, INDEX_CREATE);
|
||||
}
|
||||
}
|
||||
@ -828,17 +839,19 @@ public class AddressMapDB implements AddressMap {
|
||||
/**
|
||||
* Add simple key ranges where the address range lies within a single base segment for a single space.
|
||||
* NOTE: start and end addresses must have the same address space!
|
||||
* @param keyRangeList
|
||||
* @param start
|
||||
* @param end
|
||||
* @param absolute
|
||||
* @param create
|
||||
* @param keyRangeList the list to store key ranges into
|
||||
* @param start the start address
|
||||
* @param end the end address
|
||||
* @param absolute true if the address are to be encoded as absolute (not relative to the
|
||||
* image base
|
||||
* @param create if true, this method will add new address bases that are required to
|
||||
* store addresses in that database that have that address base
|
||||
*/
|
||||
private void addKeyRanges(List<KeyRange> keyRangeList, Address start, Address end,
|
||||
boolean absolute, boolean create) {
|
||||
if (start.isMemoryAddress()) {
|
||||
if (create) {
|
||||
createBaseSegments(start, end);
|
||||
createBaseSegments(start, end, absolute);
|
||||
}
|
||||
Address normalizedStart = absolute ? start : getShiftedAddr(start);
|
||||
Address normalizedEnd = absolute ? end : getShiftedAddr(end);
|
||||
|
@ -15,12 +15,12 @@
|
||||
*/
|
||||
package ghidra.program.database.register;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Associates objects with address ranges.
|
||||
*/
|
||||
@ -170,7 +170,8 @@ public class AddressRangeObjectMap<T> {
|
||||
T object, AddressValueRange<T> newRange, int pos) {
|
||||
|
||||
AddressValueRange<T> previousRange = ranges.get(pos);
|
||||
if ((start.previous() == null) || (previousRange.getEnd().compareTo(start.previous()) < 0)) {
|
||||
if ((start.previous() == null) ||
|
||||
(previousRange.getEnd().compareTo(start.previous()) < 0)) {
|
||||
return newRange; // no overlap
|
||||
}
|
||||
|
||||
@ -469,6 +470,10 @@ public class AddressRangeObjectMap<T> {
|
||||
}
|
||||
return new AddressRangeImpl(min, max);
|
||||
}
|
||||
|
||||
public void clearCache() {
|
||||
lastRange = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -209,4 +209,9 @@ public class DatabaseRangeMapAdapter implements RangeMapAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
rangeMap.invalidate();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -143,4 +142,9 @@ public class InMemoryRangeMapAdapter implements RangeMapAdapter {
|
||||
}
|
||||
rangeMap = newRangeMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
rangeMap.clearCache();
|
||||
}
|
||||
}
|
||||
|
@ -175,6 +175,7 @@ public class ProgramRegisterContextDB extends AbstractStoredProgramContext imple
|
||||
@Override
|
||||
public void invalidateCache(boolean all) throws IOException {
|
||||
this.invalidateReadCache();
|
||||
invalidateRegisterStores();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -525,4 +526,12 @@ public class ProgramRegisterContextDB extends AbstractStoredProgramContext imple
|
||||
}
|
||||
}
|
||||
|
||||
private void invalidateRegisterStores() {
|
||||
for (RegisterValueStore store : registerValueMap.values()) {
|
||||
store.invalidate();
|
||||
}
|
||||
for (RegisterValueStore store : defaultRegisterValueMap.values()) {
|
||||
store.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,281 @@
|
||||
/* ###
|
||||
* 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.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import db.DBRecord;
|
||||
import db.RecordIterator;
|
||||
import ghidra.program.database.map.AddressKeyRecordIterator;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.util.Lock;
|
||||
|
||||
/**
|
||||
* An iterator over ranges that have a defined values in the AddressRangeMapDB
|
||||
* <P>
|
||||
* NOTE: this iterator is complicated by the fact that there can exist a record that represents
|
||||
* an address range that "wraps around" from the max address to the 0 address, where this record
|
||||
* actually represents two address ranges. This is cause by changing the image base which shifts
|
||||
* all records up or down. That shift can cause a record to have a wrapping range where the start
|
||||
* address is larger than the end address. If such a record exists, it is found during construction
|
||||
* and the lower address range is extracted from the record and is stored as a special "start range"
|
||||
* that should be emitted before any other ranges in that space. The upper range of a wrapping
|
||||
* record will be handled more naturally during the iteration process. When a wrapping record is
|
||||
* encountered during the normal iteration, only the upper range is used and it will be in the
|
||||
* correct address range ordering.
|
||||
*/
|
||||
class AddressRangeMapIterator implements AddressRangeIterator {
|
||||
|
||||
private AddressRangeMapDB rangeMap;
|
||||
private AddressMap addressMap;
|
||||
private Lock lock;
|
||||
private int expectedModCount;
|
||||
|
||||
private DBRecord nextRecord;
|
||||
private RecordIterator recordIterator;
|
||||
|
||||
// this is the range from a wrapping address record that needs to be emitted before any other
|
||||
// ranges in the default space. It is discovered during construction if it exists
|
||||
private AddressRange startRange;
|
||||
|
||||
// these will be null if iterating over all records
|
||||
private Address iteratorStart;
|
||||
private Address iteratorEnd;
|
||||
|
||||
/**
|
||||
* Constructs an AddressRangeIterator over all ranges that have a defined value
|
||||
* @param rangeMap the AddressRangeMapDB to iterate over
|
||||
* @throws IOException if a database I/O exception occurs
|
||||
*/
|
||||
AddressRangeMapIterator(AddressRangeMapDB rangeMap) throws IOException {
|
||||
this.rangeMap = rangeMap;
|
||||
this.lock = rangeMap.getLock();
|
||||
this.addressMap = rangeMap.getAddressMap();
|
||||
this.expectedModCount = rangeMap.getModCount();
|
||||
this.recordIterator = new AddressKeyRecordIterator(rangeMap.getTable(), addressMap);
|
||||
startRange = checkForStartRangeFromWrappingAddressRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an AddressRangeIterator over all ranges greater than the given start address
|
||||
* that have a defined value. If start is in the middle of a defined range, the first
|
||||
* range will be truncated to start with the given start address.
|
||||
* @param rangeMap the AddressRangeMapDB to iterate over
|
||||
* @param start the address where the iterator should start
|
||||
* @throws IOException if a database I/O exception occurs
|
||||
*/
|
||||
AddressRangeMapIterator(AddressRangeMapDB rangeMap, Address start) throws IOException {
|
||||
this(rangeMap, start, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an AddressRangeIterator over all ranges between the given start address and the
|
||||
* given end address that have a defined value. If start is in the middle of a defined range,
|
||||
* the first range returned will truncated to start with the given start address.
|
||||
* If the endAddress is in the middle of a defined range, the last range will be truncated to
|
||||
* end with the given end address
|
||||
* @param rangeMap the AddressRangeMapDB to iterate over
|
||||
* @param start the address where the iterator should start
|
||||
* @param end the address where the iterator should end
|
||||
* @throws IOException if a database I/O exception occurs
|
||||
*/
|
||||
AddressRangeMapIterator(AddressRangeMapDB rangeMap, Address start, Address end)
|
||||
throws IOException {
|
||||
this.rangeMap = rangeMap;
|
||||
this.lock = rangeMap.getLock();
|
||||
this.addressMap = rangeMap.getAddressMap();
|
||||
this.expectedModCount = rangeMap.getModCount();
|
||||
this.iteratorStart = start;
|
||||
this.iteratorEnd = getIteratorEnd(end);
|
||||
|
||||
// adjust start address to start of previous range if it contains this address
|
||||
// so the iterator will include it
|
||||
AddressRange range = rangeMap.getAddressRangeContaining(iteratorStart);
|
||||
this.recordIterator = new AddressKeyRecordIterator(rangeMap.getTable(), addressMap,
|
||||
range.getMinAddress(), iteratorEnd, range.getMinAddress(), true);
|
||||
|
||||
startRange = trimRange(checkForStartRangeFromWrappingAddressRecord());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<AddressRange> iterator() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
lock.acquire();
|
||||
try {
|
||||
if (expectedModCount != rangeMap.getModCount()) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
if (nextRecord != null) {
|
||||
return true;
|
||||
}
|
||||
if (startRange != null) {
|
||||
return true;
|
||||
}
|
||||
if (recordIterator != null) {
|
||||
try {
|
||||
return recordIterator.hasNext();
|
||||
}
|
||||
catch (IOException e) {
|
||||
rangeMap.dbError(e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressRange next() {
|
||||
lock.acquire();
|
||||
try {
|
||||
if (expectedModCount != rangeMap.getModCount()) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
if (nextRecord != null) {
|
||||
DBRecord record = nextRecord;
|
||||
nextRecord = null;
|
||||
return getAddressRange(record);
|
||||
}
|
||||
if (recordIterator == null || !recordIterator.hasNext()) {
|
||||
if (startRange != null) {
|
||||
// there are no more items in the underlying iterator, so if we have a
|
||||
// discovered start range, as described in the class header, then return that
|
||||
AddressRange range = startRange;
|
||||
startRange = null;
|
||||
return range;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return getAddressRange(recordIterator.next());
|
||||
}
|
||||
catch (IOException e) {
|
||||
rangeMap.dbError(e);
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes an address range for the given record. If a wrapping record (a record whose start
|
||||
* address is greater than its end address, so it really represents two ranges) is encountered,
|
||||
* it only returns the high range. The low range is specially found in the constructor and
|
||||
* returned before any other ranges in that same address space are returned.
|
||||
* @param record the record to convert to an address range
|
||||
* @return the address range represented by the given record
|
||||
*/
|
||||
private AddressRange getAddressRange(DBRecord record) {
|
||||
List<AddressRange> ranges = rangeMap.getRangesForRecord(record);
|
||||
if (ranges.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Normally, there is only one range for a record. If it is an address wrapping record
|
||||
// caused by an image base change, then the record will produce two ranges. While iterating
|
||||
// we always want the last (higher) range.
|
||||
AddressRange range = ranges.get(ranges.size() - 1);
|
||||
|
||||
// if there is a "start range" discovered in the constructor and this is the first
|
||||
// range we see in the default space (the space with image base), then we need to return
|
||||
// the start range and save this record for next time.
|
||||
if (startRange != null && hasSameSpace(startRange.getMinAddress(), range.getMinAddress())) {
|
||||
range = startRange;
|
||||
startRange = null;
|
||||
|
||||
// save current record into next record so we process it again next time
|
||||
nextRecord = record;
|
||||
}
|
||||
|
||||
return trimRange(range);
|
||||
}
|
||||
|
||||
private boolean hasSameSpace(Address address1, Address address2) {
|
||||
AddressSpace space1 = address1.getAddressSpace();
|
||||
AddressSpace space2 = address2.getAddressSpace();
|
||||
return space1.equals(space2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a start range that needs to be issued before any other ranges in the default
|
||||
* space.
|
||||
* <P>
|
||||
* Because of a changed image base, it is possible that a single record can represent
|
||||
* multiple ranges, as described in the class header. This is the code that will look for that
|
||||
* case and correct the ordering.
|
||||
*
|
||||
* @return the start range that needs to be issued before any other ranges in this space.
|
||||
* @throws IOException if a database I/O error occurs
|
||||
*/
|
||||
private AddressRange checkForStartRangeFromWrappingAddressRecord()
|
||||
throws IOException {
|
||||
|
||||
DBRecord record = rangeMap.getAddressWrappingRecord();
|
||||
if (record == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<AddressRange> ranges = rangeMap.getRangesForRecord(record);
|
||||
// we want the lower range - the upper range will be handle later during iteration
|
||||
return ranges.get(0);
|
||||
}
|
||||
|
||||
private Address getIteratorEnd(Address end) {
|
||||
if (end != null) {
|
||||
return end; // non-null end was supplied, use that
|
||||
}
|
||||
AddressFactory factory = addressMap.getAddressFactory();
|
||||
AddressSet allAddresses = factory.getAddressSet();
|
||||
return allAddresses.getMaxAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the range is within the iterator's given start and end range. This really only
|
||||
* matters for the first and last range returned by the iterator, but it hard to know when
|
||||
* the given range is the first or last, just just trim all returned ranges.
|
||||
* @param range the range to be trimmed
|
||||
* @return the trimmed address range
|
||||
*/
|
||||
private AddressRange trimRange(AddressRange range) {
|
||||
if (range == null) {
|
||||
return null;
|
||||
}
|
||||
// if no iterator bounds set, no trimming needed
|
||||
if (iteratorStart == null) {
|
||||
return range;
|
||||
}
|
||||
|
||||
if (range.compareTo(iteratorStart) > 0 && range.compareTo(iteratorEnd) < 0) {
|
||||
return range;
|
||||
}
|
||||
|
||||
Address start = Address.max(range.getMinAddress(), iteratorStart);
|
||||
Address end = Address.min(range.getMaxAddress(), iteratorEnd);
|
||||
if (start.compareTo(end) <= 0) {
|
||||
return new AddressRangeImpl(start, end);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -243,4 +243,5 @@ public interface ProgramContext {
|
||||
* @return disassembly context register value
|
||||
*/
|
||||
public RegisterValue getDisassemblyContext(Address address);
|
||||
|
||||
}
|
||||
|
@ -109,4 +109,9 @@ public interface RangeMapAdapter {
|
||||
*/
|
||||
public void checkWritableState();
|
||||
|
||||
/**
|
||||
* Notification that something has changed that may affect internal caching
|
||||
*/
|
||||
public void invalidate();
|
||||
|
||||
}
|
||||
|
@ -15,14 +15,14 @@
|
||||
*/
|
||||
package ghidra.program.util;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.lang.RegisterValue;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This is a generalized class for storing register values over ranges. The values include mask bits
|
||||
* to indicate which bits within the register are being set. The mask is stored along with the
|
||||
@ -324,4 +324,11 @@ public class RegisterValueStore {
|
||||
return rangeMap.getValueRangeContaining(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies that something changed, may need to invalidate any caches
|
||||
*/
|
||||
public void invalidate() {
|
||||
rangeMap.invalidate();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user