Merge remote-tracking branch 'origin/GT-3223_emteere_performanceIssues' into Ghidra_9.1

This commit is contained in:
Ryan Kurtz 2019-10-18 12:40:45 -04:00
commit ea55499623
5 changed files with 160 additions and 32 deletions

View file

@ -15,20 +15,51 @@
*/
package ghidra.program.database.mem;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Iterator;
import org.junit.*;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import ghidra.app.plugin.core.memory.UninitializedBlockCmd;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.*;
import ghidra.program.model.symbol.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressOverflowException;
import ghidra.program.model.address.AddressRange;
import ghidra.program.model.address.AddressRangeImpl;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.data.ArrayDataType;
import ghidra.program.model.data.ByteDataType;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.listing.ProgramFragment;
import ghidra.program.model.listing.ProgramModule;
import ghidra.program.model.mem.LiveMemoryHandler;
import ghidra.program.model.mem.LiveMemoryListener;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.mem.MemoryBlockException;
import ghidra.program.model.mem.MemoryBlockSourceInfo;
import ghidra.program.model.mem.MemoryBlockStub;
import ghidra.program.model.mem.MemoryBlockType;
import ghidra.program.model.mem.MemoryConflictException;
import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.ReferenceManager;
import ghidra.program.model.symbol.SourceType;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.ToyProgramBuilder;
import ghidra.util.task.TaskMonitor;
@ -316,6 +347,57 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
assertEquals(newBlock, block);
}
@Test
public void testGetBlockByName() throws Exception {
MemoryBlock block1 = createBlock("Test1", addr(100), 100);
MemoryBlock block2 = createBlock("Test2", addr(300), 100);
MemoryBlock block = mem.getBlock("Test1");
assertEquals("Test1", block.getName());
assertEquals("get same block", block, block1);
mem.split(block, addr(150));
block = mem.getBlock("Test1");
assertEquals("Test1", block.getName());
assertEquals(50, block.getSize());
// non-existent block
block = mem.getBlock("NoExist");
assertNull(block);
program.endTransaction(transactionID, true);
transactionID = program.startTransaction("Test");
// now exists
mem.getBlock("Test1").setName("NoExist");
// Test1 no longer exists
assertNull("block deleted", mem.getBlock("Test1"));
block = mem.getBlock("NoExist");
assertEquals("NoExist", block.getName());
mem.removeBlock(block, new TaskMonitorAdapter());
block = mem.getBlock("NoExist");
assertNull("block should be deleted", block);
// Test1 still doesn't exist
block = mem.getBlock("Test1");
assertNull("block deleted", block);
block = mem.getBlock("Test2");
assertEquals("Test2", block.getName());
program.endTransaction(transactionID, true);
program.undo();
// Test1 still doesn't exist
block = mem.getBlock("Test1");
assertNotNull("Undo, Test1 exists again", block);
transactionID = program.startTransaction("Test");
}
@Test
public void testSave() throws Exception {
MemoryBlock block1 = createBlock("Test1", addr(0), 100);

View file

@ -19,15 +19,39 @@ import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Iterator;
import ghidra.program.model.address.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressIterator;
import ghidra.program.model.address.AddressOutOfBoundsException;
import ghidra.program.model.address.AddressOverflowException;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.*;
import ghidra.program.model.lang.InstructionPrototype;
import ghidra.program.model.lang.InsufficientBytesException;
import ghidra.program.model.lang.Language;
import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.lang.UnknownContextException;
import ghidra.program.model.lang.UnknownInstructionException;
import ghidra.program.model.listing.ContextChangeException;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Instruction;
import ghidra.program.model.listing.Program;
import ghidra.program.model.listing.ProgramContext;
import ghidra.program.model.mem.ByteMemBufferImpl;
import ghidra.program.model.mem.DumbMemBufferImpl;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.symbol.*;
import ghidra.program.util.ProgramContextImpl;
import ghidra.program.model.symbol.FlowType;
import ghidra.program.model.symbol.RefType;
import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolType;
/**
* PseudoDisassembler.java
@ -71,6 +95,8 @@ public class PseudoDisassembler {
private boolean respectExecuteFlag = false;
private AddressSetView executeSet;
/**
* Create a pseudo disassembler for the given program.
*/
@ -86,16 +112,16 @@ public class PseudoDisassembler {
this.programContext = program.getProgramContext();
}
public PseudoDisassembler(Language lang, Memory mem) {
program = null;
/**
* @return cached addressSet of executable memory blocks
*/
private AddressSetView getExecuteSet() {
if (executeSet != null) {
return executeSet;
}
this.language = lang;
this.memory = mem;
pointerSize = language.getDefaultSpace().getPointerSize();
programContext = new ProgramContextImpl(language.getRegisters());
executeSet = memory.getExecuteSet();
return executeSet;
}
/**
@ -615,8 +641,6 @@ public class PseudoDisassembler {
return false;
}
AddressSetView executeSet = memory.getExecuteSet();
RepeatInstructionByteTracker repeatInstructionByteTracker =
new RepeatInstructionByteTracker(MAX_REPEAT_BYTES_LIMIT, null);
@ -777,8 +801,8 @@ public class PseudoDisassembler {
}
}
// if respecting execute flag on memory, test to make sure we did flow into non-execute memory
if (respectExecuteFlag && !executeSet.isEmpty() &&
!executeSet.contains(flows[j])) {
AddressSetView execSet = getExecuteSet();
if (respectExecuteFlag && !execSet.isEmpty() && !execSet.contains(flows[j])) {
if (!flows[j].isExternalAddress()) {
MemoryBlock block = memory.getBlock(flows[j]);
// flowing into non-executable, but readable memory is bad
@ -878,8 +902,8 @@ public class PseudoDisassembler {
}
// check that body does not wander into non-executable memory
AddressSetView executeSet = program.getMemory().getExecuteSet();
if (respectExecuteFlag && !executeSet.isEmpty() && !body.subtract(executeSet).isEmpty()) {
AddressSetView execSet = getExecuteSet();
if (respectExecuteFlag && !execSet.isEmpty() && !body.subtract(execSet).isEmpty()) {
return false;
}

View file

@ -60,6 +60,10 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
private MemoryBlock lastBlock;// the last accessed block
private LiveMemoryHandler liveMemory;
// lazy hashmap of block names to blocks, must be reloaded if blocks are removed or added
private HashMap<String,MemoryBlock> nameBlockMap = new HashMap<String, MemoryBlock>();
private final static MemoryBlock NoBlock = new MemoryBlockStub(); // placeholder for no block, not given out
Lock lock;
private Set<MemoryBlock> potentialOverlappingBlocks;
@ -182,6 +186,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
lastBlock = null;
blocks = newBlocks;
addrMap.memoryMapChanged(this);
nameBlockMap = new HashMap<>();
}
public void setLanguage(Language newLanguage) {
@ -302,11 +307,25 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
*/
@Override
public synchronized MemoryBlock getBlock(String blockName) {
// find block that might have been cached from previous call
MemoryBlock memoryBlock = nameBlockMap.get(blockName);
if (memoryBlock != null) {
if (memoryBlock == NoBlock) {
// found placeholder, have searched and found nothing before
return null;
}
return memoryBlock;
}
for (MemoryBlock block : blocks) {
if (block.getName().equals(blockName)) {
nameBlockMap.put(blockName, block);
return block;
}
}
// store placeholder there is no memory block with that name
nameBlockMap.put(blockName, NoBlock);
return null;
}
@ -374,6 +393,9 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
if (program != null) {
program.setChanged(ChangeManager.DOCR_MEMORY_BLOCK_CHANGED, block, null);
}
// name could have changed
nameBlockMap = new HashMap<>();
}
void fireBytesChanged(Address addr, int count) {

View file

@ -390,7 +390,7 @@ class BigRefListV0 extends RefList {
if (maxLevel < level) {
maxLevel = level;
}
if (level > currentRefLevel) {
if (level >= currentRefLevel) {
return level;
}
}

View file

@ -342,7 +342,7 @@ class RefListV0 extends RefList {
if (maxLevel < level) {
maxLevel = level;
}
if (level > currentRefLevel) {
if (level >= currentRefLevel) {
return level;
}
}