mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge remote-tracking branch 'origin/patch'
This commit is contained in:
commit
05ee2c14b9
5 changed files with 134 additions and 35 deletions
|
@ -84,9 +84,11 @@ public class SymbolTableCommand extends LoadCommand {
|
||||||
nlistList.add(NList.createNList(reader, is32bit));
|
nlistList.add(NList.createNList(reader, is32bit));
|
||||||
}
|
}
|
||||||
// sort the entries by the index in the string table, so don't jump around reading
|
// sort the entries by the index in the string table, so don't jump around reading
|
||||||
List<NList> sortedList = nlistList.stream().sorted(
|
List<NList> sortedList = nlistList
|
||||||
(o1, o2) -> o1.getStringTableIndex() - o2.getStringTableIndex()).collect(
|
.stream()
|
||||||
Collectors.toList());
|
.sorted((o1, o2) -> Integer.valueOf(o1.getStringTableIndex())
|
||||||
|
.compareTo(Integer.valueOf(o2.getStringTableIndex())))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
// initialize the NList strings from string table
|
// initialize the NList strings from string table
|
||||||
long stringTableOffset = stroff;
|
long stringTableOffset = stroff;
|
||||||
|
|
|
@ -159,9 +159,11 @@ public class DyldCacheLocalSymbolsInfo implements StructConverter {
|
||||||
monitor.incrementProgress(1);
|
monitor.incrementProgress(1);
|
||||||
}
|
}
|
||||||
// sort the entries by the index in the string table, so don't jump around reading
|
// sort the entries by the index in the string table, so don't jump around reading
|
||||||
List<NList> sortedList = nlistList.stream().sorted(
|
List<NList> sortedList = nlistList
|
||||||
(o1, o2) -> o1.getStringTableIndex() - o2.getStringTableIndex()).collect(
|
.stream()
|
||||||
Collectors.toList());
|
.sorted((o1, o2) -> Integer.valueOf(o1.getStringTableIndex())
|
||||||
|
.compareTo(Integer.valueOf(o2.getStringTableIndex())))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
// initialize the NList strings from string table
|
// initialize the NList strings from string table
|
||||||
long stringTableOffset = startIndex + stringsOffset;
|
long stringTableOffset = startIndex + stringsOffset;
|
||||||
|
|
|
@ -296,7 +296,6 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
block2.setSourceName("Test");
|
block2.setSourceName("Test");
|
||||||
assertEquals("Test", block2.getSourceName());
|
assertEquals("Test", block2.getSourceName());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -398,6 +397,90 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
transactionID = program.startTransaction("Test");
|
transactionID = program.startTransaction("Test");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMemoryMapExecuteSet() throws Exception {
|
||||||
|
|
||||||
|
AddressSetView executeSet = mem.getExecuteSet();
|
||||||
|
assertTrue(executeSet.isEmpty());
|
||||||
|
MemoryBlock block1 = createBlock("Test1", addr(100), 100);
|
||||||
|
executeSet = mem.getExecuteSet();
|
||||||
|
assertTrue(executeSet.isEmpty());
|
||||||
|
MemoryBlock block2 = createBlock("Test2", addr(300), 100);
|
||||||
|
executeSet = mem.getExecuteSet();
|
||||||
|
assertTrue(executeSet.isEmpty());
|
||||||
|
|
||||||
|
MemoryBlock block = mem.getBlock("Test1");
|
||||||
|
executeSet = mem.getExecuteSet();
|
||||||
|
assertTrue(executeSet.isEmpty());
|
||||||
|
|
||||||
|
block.setExecute(false);
|
||||||
|
executeSet = mem.getExecuteSet();
|
||||||
|
assertTrue(executeSet.isEmpty());
|
||||||
|
|
||||||
|
block.setExecute(true);
|
||||||
|
executeSet = mem.getExecuteSet();
|
||||||
|
assertTrue(executeSet.isEmpty() != true);
|
||||||
|
Address start = block.getStart();
|
||||||
|
Address end = block.getEnd();
|
||||||
|
assertTrue(executeSet.contains(start,end));
|
||||||
|
|
||||||
|
// 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
|
||||||
|
block = mem.getBlock("NoExist");
|
||||||
|
executeSet = mem.getExecuteSet();
|
||||||
|
start = block.getStart();
|
||||||
|
end = block.getEnd();
|
||||||
|
// should be same block
|
||||||
|
assertTrue(executeSet.contains(start,end));
|
||||||
|
block.setExecute(false);
|
||||||
|
executeSet = mem.getExecuteSet();
|
||||||
|
assertTrue(executeSet.contains(start,end) == false);
|
||||||
|
|
||||||
|
block2.setExecute(true);
|
||||||
|
Address start2 = block2.getStart();
|
||||||
|
Address end2 = block2.getEnd();
|
||||||
|
mem.removeBlock(block2, new TaskMonitorAdapter());
|
||||||
|
|
||||||
|
program.endTransaction(transactionID, true);
|
||||||
|
|
||||||
|
program.undo();
|
||||||
|
|
||||||
|
transactionID = program.startTransaction("Test");
|
||||||
|
|
||||||
|
// should be execute set on block2, deleted, then undone
|
||||||
|
executeSet = mem.getExecuteSet();
|
||||||
|
assertTrue(executeSet.contains(start2,end2) == false);
|
||||||
|
|
||||||
|
// undid set execute block should now be contained
|
||||||
|
block = mem.getBlock("Test1");
|
||||||
|
start = block.getStart();
|
||||||
|
end = block.getEnd();
|
||||||
|
executeSet = mem.getExecuteSet();
|
||||||
|
assertTrue(executeSet.contains(start,end));
|
||||||
|
|
||||||
|
mem.split(block, addr(150));
|
||||||
|
block = mem.getBlock("Test1");
|
||||||
|
executeSet = mem.getExecuteSet();
|
||||||
|
assertTrue(executeSet.isEmpty() != true);
|
||||||
|
assertTrue(executeSet.contains(block.getStart(), block.getEnd()));
|
||||||
|
|
||||||
|
// remove block that was split, should still be executable memory
|
||||||
|
start = block.getStart();
|
||||||
|
end = block.getEnd();
|
||||||
|
mem.removeBlock(block, new TaskMonitorAdapter());
|
||||||
|
executeSet = mem.getExecuteSet();
|
||||||
|
assertTrue(executeSet.isEmpty() != true);
|
||||||
|
assertTrue(executeSet.contains(start, end) == false);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSave() throws Exception {
|
public void testSave() throws Exception {
|
||||||
MemoryBlock block1 = createBlock("Test1", addr(0), 100);
|
MemoryBlock block1 = createBlock("Test1", addr(0), 100);
|
||||||
|
|
|
@ -95,8 +95,6 @@ public class PseudoDisassembler {
|
||||||
|
|
||||||
private boolean respectExecuteFlag = false;
|
private boolean respectExecuteFlag = false;
|
||||||
|
|
||||||
private AddressSetView executeSet;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a pseudo disassembler for the given program.
|
* Create a pseudo disassembler for the given program.
|
||||||
*/
|
*/
|
||||||
|
@ -112,18 +110,6 @@ public class PseudoDisassembler {
|
||||||
this.programContext = program.getProgramContext();
|
this.programContext = program.getProgramContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return cached addressSet of executable memory blocks
|
|
||||||
*/
|
|
||||||
private AddressSetView getExecuteSet() {
|
|
||||||
if (executeSet != null) {
|
|
||||||
return executeSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
executeSet = memory.getExecuteSet();
|
|
||||||
return executeSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the maximum number of instructions to check
|
* Set the maximum number of instructions to check
|
||||||
*
|
*
|
||||||
|
@ -617,6 +603,7 @@ public class PseudoDisassembler {
|
||||||
boolean allowExistingInstructions, boolean mustTerminate) {
|
boolean allowExistingInstructions, boolean mustTerminate) {
|
||||||
AddressSet body = new AddressSet();
|
AddressSet body = new AddressSet();
|
||||||
AddressSet instrStarts = new AddressSet();
|
AddressSet instrStarts = new AddressSet();
|
||||||
|
AddressSetView execSet = memory.getExecuteSet();
|
||||||
|
|
||||||
if (hasLowBitCodeModeInAddrValues(program)) {
|
if (hasLowBitCodeModeInAddrValues(program)) {
|
||||||
entryPoint = setTargeContextForDisassembly(procContext, entryPoint);
|
entryPoint = setTargeContextForDisassembly(procContext, entryPoint);
|
||||||
|
@ -801,7 +788,6 @@ public class PseudoDisassembler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if respecting execute flag on memory, test to make sure we did flow into non-execute memory
|
// if respecting execute flag on memory, test to make sure we did flow into non-execute memory
|
||||||
AddressSetView execSet = getExecuteSet();
|
|
||||||
if (respectExecuteFlag && !execSet.isEmpty() && !execSet.contains(flows[j])) {
|
if (respectExecuteFlag && !execSet.isEmpty() && !execSet.contains(flows[j])) {
|
||||||
if (!flows[j].isExternalAddress()) {
|
if (!flows[j].isExternalAddress()) {
|
||||||
MemoryBlock block = memory.getBlock(flows[j]);
|
MemoryBlock block = memory.getBlock(flows[j]);
|
||||||
|
@ -902,8 +888,8 @@ public class PseudoDisassembler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that body does not wander into non-executable memory
|
// check that body does not wander into non-executable memory
|
||||||
AddressSetView execSet = getExecuteSet();
|
AddressSetView execSet = memory.getExecuteSet();
|
||||||
if (respectExecuteFlag && !execSet.isEmpty() && !body.subtract(execSet).isEmpty()) {
|
if (respectExecuteFlag && !execSet.isEmpty() && !execSet.contains(body)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -914,8 +900,9 @@ public class PseudoDisassembler {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean canHaveOffcutEntry = hasLowBitCodeModeInAddrValues(program);
|
||||||
AddressSet strictlyBody = body.subtract(starts);
|
AddressSet strictlyBody = body.subtract(starts);
|
||||||
if (hasLowBitCodeModeInAddrValues(program)) {
|
if (canHaveOffcutEntry) {
|
||||||
strictlyBody.deleteRange(entry, entry.add(1));
|
strictlyBody.deleteRange(entry, entry.add(1));
|
||||||
}
|
}
|
||||||
AddressIterator addrIter =
|
AddressIterator addrIter =
|
||||||
|
|
|
@ -57,6 +57,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||||
private AddressSet addrSet = new AddressSet();
|
private AddressSet addrSet = new AddressSet();
|
||||||
private AddressSet initializedLoadedAddrSet = new AddressSet();
|
private AddressSet initializedLoadedAddrSet = new AddressSet();
|
||||||
private AddressSet allInitializedAddrSet = new AddressSet();
|
private AddressSet allInitializedAddrSet = new AddressSet();
|
||||||
|
private AddressSetView executeSet = null;
|
||||||
|
|
||||||
private MemoryBlock lastBlock;// the last accessed block
|
private MemoryBlock lastBlock;// the last accessed block
|
||||||
private LiveMemoryHandler liveMemory;
|
private LiveMemoryHandler liveMemory;
|
||||||
|
|
||||||
|
@ -187,6 +189,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||||
blocks = newBlocks;
|
blocks = newBlocks;
|
||||||
addrMap.memoryMapChanged(this);
|
addrMap.memoryMapChanged(this);
|
||||||
nameBlockMap = new HashMap<>();
|
nameBlockMap = new HashMap<>();
|
||||||
|
executeSet = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLanguage(Language newLanguage) {
|
public void setLanguage(Language newLanguage) {
|
||||||
|
@ -248,7 +251,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AddressSetView getAllInitializedAddressSet() {
|
public AddressSetView getAllInitializedAddressSet() {
|
||||||
return allInitializedAddrSet;
|
return new AddressSetViewAdapter(allInitializedAddrSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -259,7 +262,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||||
if (liveMemory != null) {
|
if (liveMemory != null) {
|
||||||
return this;//all memory is initialized!
|
return this;//all memory is initialized!
|
||||||
}
|
}
|
||||||
return initializedLoadedAddrSet;
|
return new AddressSetViewAdapter(initializedLoadedAddrSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkMemoryWrite(MemoryBlockDB block, Address start, long length)
|
void checkMemoryWrite(MemoryBlockDB block, Address start, long length)
|
||||||
|
@ -396,6 +399,9 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||||
|
|
||||||
// name could have changed
|
// name could have changed
|
||||||
nameBlockMap = new HashMap<>();
|
nameBlockMap = new HashMap<>();
|
||||||
|
|
||||||
|
// don't regenerate now, do lazily later if needed
|
||||||
|
executeSet = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fireBytesChanged(Address addr, int count) {
|
void fireBytesChanged(Address addr, int count) {
|
||||||
|
@ -1972,13 +1978,32 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public AddressSetView getExecuteSet() {
|
public AddressSetView getExecuteSet() {
|
||||||
|
AddressSetView set = executeSet;
|
||||||
|
|
||||||
|
if (set == null) {
|
||||||
|
set = computeExecuteSet();
|
||||||
|
}
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return executable address set
|
||||||
|
*/
|
||||||
|
private AddressSetView computeExecuteSet() {
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
AddressSet set = new AddressSet();
|
AddressSet set = new AddressSet();
|
||||||
for (MemoryBlock block : blocks) {
|
for (MemoryBlock block : blocks) {
|
||||||
if (block.isExecute()) {
|
if (block.isExecute()) {
|
||||||
set.addRange(block.getStart(), block.getEnd());
|
set.addRange(block.getStart(), block.getEnd());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return set;
|
executeSet = new AddressSetViewAdapter(set);
|
||||||
|
return executeSet;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue