Merge remote-tracking branch 'origin/Ghidra_9.1'

This commit is contained in:
Ryan Kurtz 2019-10-18 12:44:35 -04:00
commit 8e30848804
12 changed files with 450 additions and 62 deletions

View file

@ -5,6 +5,9 @@
<executable_format name="Mac OS X Mach-O">
<functionNamesFile>MachOFunctionsThatDoNotReturn</functionNamesFile>
</executable_format>
<executable_format name="DYLD Cache">
<functionNamesFile>MachOFunctionsThatDoNotReturn</functionNamesFile>
</executable_format>
<executable_format name="Portable Executable (PE)">
<functionNamesFile>PEFunctionsThatDoNotReturn</functionNamesFile>
</executable_format>

View file

@ -275,6 +275,29 @@ public class DyldCacheHeader implements StructConverter {
return localSymbolsInfo;
}
/**
* Gets the {@link DyldCacheSlideInfoCommon}.
*
* @return the {@link DyldCacheSlideInfoCommon}. Common, or particular version
*/
public DyldCacheSlideInfoCommon getSlideInfo() {
return slideInfo;
}
/**
* @return slideInfoOffset
*/
public long getSlideInfoOffset() {
return slideInfoOffset;
}
/**
* @return slideInfoSize
*/
public long getSlideInfoSize() {
return slideInfoSize;
}
/**
* Gets the {@link List} of branch pool address. Requires header to have been parsed.
*

View file

@ -27,7 +27,6 @@ import ghidra.util.exception.DuplicateNameException;
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-625.13/launch-cache/dyld_cache_format.h.auto.html">launch-cache/dyld_cache_format.h</a>
*/
@SuppressWarnings("unused")
public class DyldCacheSlideInfo1 extends DyldCacheSlideInfoCommon {
private int toc_offset;
@ -36,6 +35,26 @@ public class DyldCacheSlideInfo1 extends DyldCacheSlideInfoCommon {
private int entries_count;
private int entries_size;
public int getTocOffset() {
return toc_offset;
}
public int getTocCount() {
return toc_count;
}
public int getEntriesOffset() {
return entries_offset;
}
public int getEntriesCount() {
return entries_count;
}
public int getEntriesSize() {
return entries_size;
}
/**
* Create a new {@link DyldCacheSlideInfo1}.
*

View file

@ -27,7 +27,6 @@ import ghidra.util.exception.DuplicateNameException;
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-625.13/launch-cache/dyld_cache_format.h.auto.html">launch-cache/dyld_cache_format.h</a>
*/
@SuppressWarnings("unused")
public class DyldCacheSlideInfo2 extends DyldCacheSlideInfoCommon {
private int page_size;
@ -37,6 +36,44 @@ public class DyldCacheSlideInfo2 extends DyldCacheSlideInfoCommon {
private int page_extras_count;
private long delta_mask;
private long value_add;
private short page_starts_entries[];
private short page_extras_entries[];
public long getPageSize() {
return ((long)page_size) & 0xffffffff;
}
public long getPageStartsOffset() {
return ((long) page_starts_offset) & 0xffffffff;
}
public long getPageStartsCount() {
return ((long) page_starts_count) & 0xffffffff;
}
public long getPageExtrasOffset() {
return ((long) page_extras_offset) & 0xffffffff;
}
public long getPageExtrasCount() {
return ((long) page_extras_count) & 0xffffffff;
}
public long getDeltaMask() {
return delta_mask;
}
public long getValueAdd() {
return value_add;
}
public short[] getPageStartsEntries() {
return page_starts_entries;
}
public short[] getPageExtrasEntries() {
return page_extras_entries;
}
/**
* Create a new {@link DyldCacheSlideInfo2}.
@ -53,6 +90,8 @@ public class DyldCacheSlideInfo2 extends DyldCacheSlideInfoCommon {
page_extras_count = reader.readNextInt();
delta_mask = reader.readNextLong();
value_add = reader.readNextLong();
page_starts_entries = reader.readNextShortArray(page_starts_count);
page_extras_entries = reader.readNextShortArray(page_extras_count);
}
@Override

View file

@ -27,7 +27,6 @@ import ghidra.util.exception.DuplicateNameException;
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-625.13/launch-cache/dyld_cache_format.h.auto.html">launch-cache/dyld_cache_format.h</a>
*/
@SuppressWarnings("unused")
public class DyldCacheSlideInfo3 extends DyldCacheSlideInfoCommon {
private int page_size;
@ -35,6 +34,22 @@ public class DyldCacheSlideInfo3 extends DyldCacheSlideInfoCommon {
private long auth_value_add;
private short page_starts[];
public int getPageSize() {
return page_size;
}
public int getPageStartsCount() {
return page_starts_count;
}
public long getAuthValueAdd() {
return auth_value_add;
}
public short[] getPageStarts() {
return page_starts;
}
/**
* Create a new {@link DyldCacheSlideInfo3}.
*

View file

@ -20,6 +20,7 @@ import java.util.*;
import ghidra.app.util.MemoryBlockUtils;
import ghidra.app.util.Option;
import ghidra.app.util.OptionUtils;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.macho.dyld.DyldArchitecture;
@ -47,7 +48,13 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
static final String CREATE_DYLIB_SECTIONS_OPTION_NAME = "Create DYLIB section memory blocks";
/** Default value for loader option to create memory blocks for DYLIB sections */
static final boolean CREATE_DYLIB_SECTIONS_OPTION_DEFAULT = true;
static final boolean CREATE_DYLIB_SECTIONS_OPTION_DEFAULT = false;
/** Loader option to add relocation entries for each fixed chain pointer */
static final String ADD_RELOCATION_ENTRIES_OPTION_NAME = "Add relocation entries for fixed chain pointers";
/** Default value for loader option add relocation entries */
static final boolean ADD_RELOCATION_ENTRIES_OPTION_DEFAULT = false;
@Override
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
@ -84,7 +91,8 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
try {
DyldCacheProgramBuilder.buildProgram(program, provider,
MemoryBlockUtils.createFileBytes(program, provider, monitor),
shouldProcessSymbols(options), shouldCreateDylibSections(options), log, monitor);
shouldProcessSymbols(options), shouldCreateDylibSections(options),
shouldAddRelocationEntries(options), log, monitor);
}
catch (CancelledException e) {
return;
@ -105,32 +113,23 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
list.add(
new Option(CREATE_DYLIB_SECTIONS_OPTION_NAME, CREATE_DYLIB_SECTIONS_OPTION_DEFAULT,
Boolean.class, Loader.COMMAND_LINE_ARG_PREFIX + "-createDylibSections"));
list.add(
new Option(ADD_RELOCATION_ENTRIES_OPTION_NAME, ADD_RELOCATION_ENTRIES_OPTION_DEFAULT,
Boolean.class, Loader.COMMAND_LINE_ARG_PREFIX + "-addRelocationEntries"));
}
return list;
}
private boolean shouldProcessSymbols(List<Option> options) {
if (options != null) {
for (Option option : options) {
String optName = option.getName();
if (optName.equals(PROCESS_SYMBOLS_OPTION_NAME)) {
return (Boolean) option.getValue();
}
}
}
return PROCESS_SYMBOLS_OPTION_DEFAULT;
return OptionUtils.getOption(PROCESS_SYMBOLS_OPTION_NAME, options, PROCESS_SYMBOLS_OPTION_DEFAULT);
}
private boolean shouldCreateDylibSections(List<Option> options) {
if (options != null) {
for (Option option : options) {
String optName = option.getName();
if (optName.equals(CREATE_DYLIB_SECTIONS_OPTION_NAME)) {
return (Boolean) option.getValue();
return OptionUtils.getOption(CREATE_DYLIB_SECTIONS_OPTION_NAME, options, CREATE_DYLIB_SECTIONS_OPTION_DEFAULT);
}
}
}
return CREATE_DYLIB_SECTIONS_OPTION_DEFAULT;
private boolean shouldAddRelocationEntries(List<Option> options) {
return OptionUtils.getOption(ADD_RELOCATION_ENTRIES_OPTION_NAME, options, ADD_RELOCATION_ENTRIES_OPTION_DEFAULT);
}
@Override

View file

@ -17,7 +17,10 @@ package ghidra.app.util.opinion;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;
import ghidra.app.util.MemoryBlockUtils;
import ghidra.app.util.bin.BinaryReader;
@ -25,15 +28,28 @@ import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.macho.MachException;
import ghidra.app.util.bin.format.macho.MachHeader;
import ghidra.app.util.bin.format.macho.commands.NList;
import ghidra.app.util.bin.format.macho.dyld.*;
import ghidra.app.util.bin.format.macho.dyld.DyldCacheHeader;
import ghidra.app.util.bin.format.macho.dyld.DyldCacheImageInfo;
import ghidra.app.util.bin.format.macho.dyld.DyldCacheLocalSymbolsInfo;
import ghidra.app.util.bin.format.macho.dyld.DyldCacheMappingInfo;
import ghidra.app.util.bin.format.macho.dyld.DyldCacheSlideInfo2;
import ghidra.app.util.bin.format.macho.dyld.DyldCacheSlideInfoCommon;
import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.importer.MessageLogContinuesFactory;
import ghidra.program.database.mem.FileBytes;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.listing.*;
import ghidra.program.model.data.DataUtilities;
import ghidra.program.model.data.Pointer64DataType;
import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Program;
import ghidra.program.model.listing.ProgramFragment;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.SymbolUtilities;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
@ -41,9 +57,16 @@ import ghidra.util.task.TaskMonitor;
*/
public class DyldCacheProgramBuilder extends MachoProgramBuilder {
private static final int DATA_PAGE_MAP_ENTRY = 1;
private static final int BYTES_PER_CHAIN_OFFSET = 4;
private static final int CHAIN_OFFSET_MASK = 0x3fff;
private static final int DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE = 0x4000;
private static final int DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA = 0x8000;
protected DyldCacheHeader dyldCacheHeader;
private boolean shouldProcessSymbols;
private boolean shouldCreateDylibSections;
private boolean shouldAddRelocationEntries;
/**
* Creates a new {@link DyldCacheProgramBuilder} based on the given information.
@ -54,15 +77,18 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
* @param shouldProcessSymbols True if symbols should be processed; otherwise, false
* @param shouldCreateDylibSections True if memory blocks should be created for DYLIB sections;
* otherwise, false
* @param shouldAddRelocationEntries True to create a relocation entry for each fixed up pointer in pointer chain
* @param log The log
* @param monitor A cancelable task monitor
*/
protected DyldCacheProgramBuilder(Program program, ByteProvider provider, FileBytes fileBytes,
boolean shouldProcessSymbols, boolean shouldCreateDylibSections, MessageLog log,
boolean shouldProcessSymbols, boolean shouldCreateDylibSections,
boolean shouldAddRelocationEntries, MessageLog log,
TaskMonitor monitor) {
super(program, provider, fileBytes, log, monitor);
this.shouldProcessSymbols = shouldProcessSymbols;
this.shouldCreateDylibSections = shouldCreateDylibSections;
this.shouldAddRelocationEntries = shouldAddRelocationEntries;
}
/**
@ -74,15 +100,17 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
* @param shouldProcessSymbols True if symbols should be processed; otherwise, false
* @param shouldCreateDylibSections True if memory blocks should be created for DYLIB sections;
* otherwise, false
* @param addRelocationEntries True to create a relocation entry for each fixed up pointer in pointer chain
* @param log The log
* @param monitor A cancelable task monitor
* @throws Exception if a problem occurs
*/
public static void buildProgram(Program program, ByteProvider provider, FileBytes fileBytes,
boolean shouldProcessSymbols, boolean shouldCreateDylibSections, MessageLog log,
TaskMonitor monitor) throws Exception {
boolean shouldProcessSymbols, boolean shouldCreateDylibSections, boolean addRelocationEntries,
MessageLog log, TaskMonitor monitor) throws Exception {
DyldCacheProgramBuilder dyldCacheProgramBuilder = new DyldCacheProgramBuilder(program,
provider, fileBytes, shouldProcessSymbols, shouldCreateDylibSections, log, monitor);
provider, fileBytes, shouldProcessSymbols, shouldCreateDylibSections,
addRelocationEntries, log, monitor);
dyldCacheProgramBuilder.build();
}
@ -97,9 +125,11 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
setDyldCacheImageBase();
processDyldCacheMemoryBlocks();
fixPageChains();
markupHeaders();
markupBranchIslands();
createSymbols();
processDylibs();
}
@ -212,6 +242,138 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
}
}
/**
* Fixes any chained pointers within each of the data pages.
*
* @throws MemoryAccessException if there was a problem reading/writing memory.
* @throws CancelledException
*/
private void fixPageChains() throws MemoryAccessException, CancelledException {
long fixedAddressCount = 0;
// locate slide Info
DyldCacheSlideInfoCommon slideInfo = dyldCacheHeader.getSlideInfo();
if (slideInfo == null || !(slideInfo instanceof DyldCacheSlideInfo2)) {
log.appendMsg("Can't handle version " +slideInfo.getVersion() + " slide info, only version 2");
return;
}
DyldCacheSlideInfo2 slideInfo2 = (DyldCacheSlideInfo2) slideInfo;
List<DyldCacheMappingInfo> mappingInfos = dyldCacheHeader.getMappingInfos();
DyldCacheMappingInfo dyldCacheMappingInfo = mappingInfos.get(DATA_PAGE_MAP_ENTRY);
long dataPageStart = dyldCacheMappingInfo.getAddress();
long pageSize = slideInfo2.getPageSize();
long pageStartsCount = slideInfo2.getPageStartsCount();
long deltaMask = slideInfo2.getDeltaMask();
long deltaShift = Long.numberOfTrailingZeros(deltaMask);
long valueAdd = slideInfo2.getValueAdd();
short[] pageEntries = slideInfo2.getPageStartsEntries();
short[] extraEntries = slideInfo2.getPageExtrasEntries();
monitor.setMessage("Fixing chained data page pointers...");
monitor.setMaximum(pageStartsCount);
for (int index=0; index < pageStartsCount; index++) {
monitor.checkCanceled();
long page = dataPageStart + (pageSize * index);
monitor.setProgress(index);
int pageEntry = ((int)pageEntries[index]) & 0xffff;
if (pageEntry == DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE) {
continue;
}
if ((pageEntry & DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA) != 0) {
// go into extras and process list of chain entries for the same page
int extraIndex = (pageEntry & CHAIN_OFFSET_MASK);
do {
pageEntry = ((int) extraEntries[extraIndex]) & 0xffff;
long pageOffset = (pageEntry & CHAIN_OFFSET_MASK) * BYTES_PER_CHAIN_OFFSET;
fixedAddressCount += processPointerChain(page, pageOffset, deltaMask, deltaShift, valueAdd);
extraIndex++;
} while ((pageEntry & DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA) == 0);
}
else {
long pageOffset = pageEntry * BYTES_PER_CHAIN_OFFSET;
fixedAddressCount += processPointerChain(page, pageOffset, deltaMask, deltaShift, valueAdd);
}
}
log.appendMsg("Fixed " + fixedAddressCount + " chained pointers. Creating Pointers");
monitor.setMessage("Created " + fixedAddressCount + " chained pointers");
}
/**
* Fixes up any chained pointers, starting at the given address.
*
* @param page within data pages that has pointers to be unchained
* @param nextOff offset within the page that is the chain start
* @param deltaMask delta offset mask for each value
* @param deltaShift shift needed for the deltaMask to extract the next offset
* @param valueAdd value to be added to each chain pointer
*
* @return count of number of addresses fixed
* @throws MemoryAccessException
* @throws CancelledException
*/
private long processPointerChain(long page, long nextOff, long deltaMask, long deltaShift, long valueAdd)
throws MemoryAccessException, CancelledException {
// TODO: should the image base be used to perform the ASLR slide on the pointers.
// currently image is kept at it's initial location with no ASLR.
Address chainStart = memory.getProgram().getLanguage().getDefaultSpace().getAddress(page);
long fixedAddressCount = 0;
byte origBytes[] = new byte[8];
long valueMask = ~deltaMask;
long delta = -1;
while (delta != 0) {
monitor.checkCanceled();
Address chainLoc = chainStart.add(nextOff);
long chainValue = memory.getLong(chainLoc);
delta = (chainValue & deltaMask) >> deltaShift;
chainValue = chainValue & valueMask;
if (chainValue != 0) {
chainValue += valueAdd;
}
if (shouldAddRelocationEntries) {
// Add entry to relocation table for the pointer fixup
memory.getBytes(chainLoc, origBytes);
program.getRelocationTable().add(chainLoc, (int) 1,
new long[] { chainValue }, origBytes, null);
}
memory.setLong(chainLoc, chainValue);
// create a pointer at the fixed up chain pointer location
try {
// don't use data utilities. does too much extra checking work
listing.createData(chainLoc, Pointer64DataType.dataType);
}
catch (CodeUnitInsertionException e) {
// No worries, something presumably more important was there already
}
fixedAddressCount++;
nextOff += (delta * 4);
}
return fixedAddressCount;
}
/**
* Processes the DYLD Cache's DYLIB files. This will mark up the DYLIB files, added them to the
* program tree, and make memory blocks for them.

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;
}
}