Skip to content

Commit ed479dd

Browse files
committed
Merge remote-tracking branch 'origin/GT-3260_emteere_MemoryExecSetCache' into patch
2 parents 9edca9a + 652e689 commit ed479dd

File tree

3 files changed

+124
-29
lines changed

3 files changed

+124
-29
lines changed

Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/MemoryManagerTest.java

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,6 @@ public void testBlockChanges() throws Exception {
296296

297297
block2.setSourceName("Test");
298298
assertEquals("Test", block2.getSourceName());
299-
300299
}
301300

302301
@Test
@@ -398,6 +397,90 @@ public void testGetBlockByName() throws Exception {
398397
transactionID = program.startTransaction("Test");
399398
}
400399

400+
@Test
401+
public void testMemoryMapExecuteSet() throws Exception {
402+
403+
AddressSetView executeSet = mem.getExecuteSet();
404+
assertTrue(executeSet.isEmpty());
405+
MemoryBlock block1 = createBlock("Test1", addr(100), 100);
406+
executeSet = mem.getExecuteSet();
407+
assertTrue(executeSet.isEmpty());
408+
MemoryBlock block2 = createBlock("Test2", addr(300), 100);
409+
executeSet = mem.getExecuteSet();
410+
assertTrue(executeSet.isEmpty());
411+
412+
MemoryBlock block = mem.getBlock("Test1");
413+
executeSet = mem.getExecuteSet();
414+
assertTrue(executeSet.isEmpty());
415+
416+
block.setExecute(false);
417+
executeSet = mem.getExecuteSet();
418+
assertTrue(executeSet.isEmpty());
419+
420+
block.setExecute(true);
421+
executeSet = mem.getExecuteSet();
422+
assertTrue(executeSet.isEmpty() != true);
423+
Address start = block.getStart();
424+
Address end = block.getEnd();
425+
assertTrue(executeSet.contains(start,end));
426+
427+
// non-existent block
428+
block = mem.getBlock("NoExist");
429+
assertNull(block);
430+
431+
program.endTransaction(transactionID, true);
432+
transactionID = program.startTransaction("Test");
433+
434+
// now exists
435+
mem.getBlock("Test1").setName("NoExist");
436+
// Test1 no longer exists
437+
block = mem.getBlock("NoExist");
438+
executeSet = mem.getExecuteSet();
439+
start = block.getStart();
440+
end = block.getEnd();
441+
// should be same block
442+
assertTrue(executeSet.contains(start,end));
443+
block.setExecute(false);
444+
executeSet = mem.getExecuteSet();
445+
assertTrue(executeSet.contains(start,end) == false);
446+
447+
block2.setExecute(true);
448+
Address start2 = block2.getStart();
449+
Address end2 = block2.getEnd();
450+
mem.removeBlock(block2, new TaskMonitorAdapter());
451+
452+
program.endTransaction(transactionID, true);
453+
454+
program.undo();
455+
456+
transactionID = program.startTransaction("Test");
457+
458+
// should be execute set on block2, deleted, then undone
459+
executeSet = mem.getExecuteSet();
460+
assertTrue(executeSet.contains(start2,end2) == false);
461+
462+
// undid set execute block should now be contained
463+
block = mem.getBlock("Test1");
464+
start = block.getStart();
465+
end = block.getEnd();
466+
executeSet = mem.getExecuteSet();
467+
assertTrue(executeSet.contains(start,end));
468+
469+
mem.split(block, addr(150));
470+
block = mem.getBlock("Test1");
471+
executeSet = mem.getExecuteSet();
472+
assertTrue(executeSet.isEmpty() != true);
473+
assertTrue(executeSet.contains(block.getStart(), block.getEnd()));
474+
475+
// remove block that was split, should still be executable memory
476+
start = block.getStart();
477+
end = block.getEnd();
478+
mem.removeBlock(block, new TaskMonitorAdapter());
479+
executeSet = mem.getExecuteSet();
480+
assertTrue(executeSet.isEmpty() != true);
481+
assertTrue(executeSet.contains(start, end) == false);
482+
}
483+
401484
@Test
402485
public void testSave() throws Exception {
403486
MemoryBlock block1 = createBlock("Test1", addr(0), 100);

Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/PseudoDisassembler.java

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,6 @@ public class PseudoDisassembler {
9595

9696
private boolean respectExecuteFlag = false;
9797

98-
private AddressSetView executeSet;
99-
10098
/**
10199
* Create a pseudo disassembler for the given program.
102100
*/
@@ -111,18 +109,6 @@ public PseudoDisassembler(Program program) {
111109

112110
this.programContext = program.getProgramContext();
113111
}
114-
115-
/**
116-
* @return cached addressSet of executable memory blocks
117-
*/
118-
private AddressSetView getExecuteSet() {
119-
if (executeSet != null) {
120-
return executeSet;
121-
}
122-
123-
executeSet = memory.getExecuteSet();
124-
return executeSet;
125-
}
126112

127113
/**
128114
* Set the maximum number of instructions to check
@@ -617,6 +603,7 @@ public boolean checkValidSubroutine(Address entryPoint, PseudoDisassemblerContex
617603
boolean allowExistingInstructions, boolean mustTerminate) {
618604
AddressSet body = new AddressSet();
619605
AddressSet instrStarts = new AddressSet();
606+
AddressSetView execSet = memory.getExecuteSet();
620607

621608
if (hasLowBitCodeModeInAddrValues(program)) {
622609
entryPoint = setTargeContextForDisassembly(procContext, entryPoint);
@@ -801,7 +788,6 @@ else if (flowType.isComputed()) {
801788
}
802789
}
803790
// if respecting execute flag on memory, test to make sure we did flow into non-execute memory
804-
AddressSetView execSet = getExecuteSet();
805791
if (respectExecuteFlag && !execSet.isEmpty() && !execSet.contains(flows[j])) {
806792
if (!flows[j].isExternalAddress()) {
807793
MemoryBlock block = memory.getBlock(flows[j]);
@@ -902,8 +888,8 @@ private boolean checkPseudoBody(Address entry, AddressSet body, AddressSet start
902888
}
903889

904890
// check that body does not wander into non-executable memory
905-
AddressSetView execSet = getExecuteSet();
906-
if (respectExecuteFlag && !execSet.isEmpty() && !body.subtract(execSet).isEmpty()) {
891+
AddressSetView execSet = memory.getExecuteSet();
892+
if (respectExecuteFlag && !execSet.isEmpty() && !execSet.contains(body)) {
907893
return false;
908894
}
909895

@@ -914,8 +900,9 @@ private boolean checkPseudoBody(Address entry, AddressSet body, AddressSet start
914900
return false;
915901
}
916902

903+
boolean canHaveOffcutEntry = hasLowBitCodeModeInAddrValues(program);
917904
AddressSet strictlyBody = body.subtract(starts);
918-
if (hasLowBitCodeModeInAddrValues(program)) {
905+
if (canHaveOffcutEntry) {
919906
strictlyBody.deleteRange(entry, entry.add(1));
920907
}
921908
AddressIterator addrIter =

Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDB.java

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,13 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
5757
private AddressSet addrSet = new AddressSet();
5858
private AddressSet initializedLoadedAddrSet = new AddressSet();
5959
private AddressSet allInitializedAddrSet = new AddressSet();
60+
private AddressSetView executeSet = null;
61+
6062
private MemoryBlock lastBlock;// the last accessed block
6163
private LiveMemoryHandler liveMemory;
62-
64+
6365
// lazy hashmap of block names to blocks, must be reloaded if blocks are removed or added
64-
private HashMap<String,MemoryBlock> nameBlockMap = new HashMap<String, MemoryBlock>();
66+
private HashMap<String, MemoryBlock> nameBlockMap = new HashMap<String, MemoryBlock>();
6567
private final static MemoryBlock NoBlock = new MemoryBlockStub(); // placeholder for no block, not given out
6668

6769
Lock lock;
@@ -187,6 +189,7 @@ private synchronized void initializeBlocks() {
187189
blocks = newBlocks;
188190
addrMap.memoryMapChanged(this);
189191
nameBlockMap = new HashMap<>();
192+
executeSet = null;
190193
}
191194

192195
public void setLanguage(Language newLanguage) {
@@ -248,7 +251,7 @@ public AddressSetView getInitializedAddressSet() {
248251

249252
@Override
250253
public AddressSetView getAllInitializedAddressSet() {
251-
return allInitializedAddrSet;
254+
return new AddressSetViewAdapter(allInitializedAddrSet);
252255
}
253256

254257
/**
@@ -259,7 +262,7 @@ public AddressSetView getLoadedAndInitializedAddressSet() {
259262
if (liveMemory != null) {
260263
return this;//all memory is initialized!
261264
}
262-
return initializedLoadedAddrSet;
265+
return new AddressSetViewAdapter(initializedLoadedAddrSet);
263266
}
264267

265268
void checkMemoryWrite(MemoryBlockDB block, Address start, long length)
@@ -393,9 +396,12 @@ void fireBlockChanged(MemoryBlock block) {
393396
if (program != null) {
394397
program.setChanged(ChangeManager.DOCR_MEMORY_BLOCK_CHANGED, block, null);
395398
}
396-
399+
397400
// name could have changed
398401
nameBlockMap = new HashMap<>();
402+
403+
// don't regenerate now, do lazily later if needed
404+
executeSet = null;
399405
}
400406

401407
void fireBytesChanged(Address addr, int count) {
@@ -1972,15 +1978,34 @@ public int hashCode() {
19721978
*/
19731979
@Override
19741980
public AddressSetView getExecuteSet() {
1975-
AddressSet set = new AddressSet();
1976-
for (MemoryBlock block : blocks) {
1977-
if (block.isExecute()) {
1978-
set.addRange(block.getStart(), block.getEnd());
1979-
}
1981+
AddressSetView set = executeSet;
1982+
1983+
if (set == null) {
1984+
set = computeExecuteSet();
19801985
}
19811986
return set;
19821987
}
19831988

1989+
/**
1990+
* @return executable address set
1991+
*/
1992+
private AddressSetView computeExecuteSet() {
1993+
lock.acquire();
1994+
try {
1995+
AddressSet set = new AddressSet();
1996+
for (MemoryBlock block : blocks) {
1997+
if (block.isExecute()) {
1998+
set.addRange(block.getStart(), block.getEnd());
1999+
}
2000+
}
2001+
executeSet = new AddressSetViewAdapter(set);
2002+
return executeSet;
2003+
}
2004+
finally {
2005+
lock.release();
2006+
}
2007+
}
2008+
19842009
@Override
19852010
public void memoryChanged(Address addr, int size) {
19862011
fireBytesChanged(addr, size);

0 commit comments

Comments
 (0)