mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge remote-tracking branch 'origin/GT-3448_emteere_LargeDisPerf'
This commit is contained in:
commit
c828b13a7a
3 changed files with 603 additions and 158 deletions
|
@ -22,10 +22,10 @@ import ghidra.program.disassemble.*;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.lang.Register;
|
import ghidra.program.model.lang.Register;
|
||||||
import ghidra.program.model.lang.RegisterValue;
|
import ghidra.program.model.lang.RegisterValue;
|
||||||
import ghidra.program.model.listing.Data;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.listing.Program;
|
|
||||||
import ghidra.program.model.mem.Memory;
|
import ghidra.program.model.mem.Memory;
|
||||||
import ghidra.program.model.mem.MemoryBlock;
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -165,13 +165,18 @@ public class DisassembleCommand extends BackgroundCommand {
|
||||||
int instructionAlignment) {
|
int instructionAlignment) {
|
||||||
|
|
||||||
exectuableSet = Disassembler.isRestrictToExecuteMemory(program)
|
exectuableSet = Disassembler.isRestrictToExecuteMemory(program)
|
||||||
? exectuableSet = getExecutableSet(program) : null;
|
? exectuableSet = getExecutableSet(program)
|
||||||
|
: null;
|
||||||
|
|
||||||
this.alignment = instructionAlignment;
|
this.alignment = instructionAlignment;
|
||||||
disassemblyPerformed = false;
|
disassemblyPerformed = false;
|
||||||
unalignedStart = false;
|
unalignedStart = false;
|
||||||
nonExecutableStart = false;
|
nonExecutableStart = false;
|
||||||
|
|
||||||
|
disassembledAddrs = new AddressSet();
|
||||||
|
|
||||||
|
Listing listing = program.getListing();
|
||||||
|
|
||||||
Disassembler disassembler =
|
Disassembler disassembler =
|
||||||
Disassembler.getDisassembler(program, monitor, new MyListener(monitor));
|
Disassembler.getDisassembler(program, monitor, new MyListener(monitor));
|
||||||
disassembler.setSeedContext(seedContext);
|
disassembler.setSeedContext(seedContext);
|
||||||
|
@ -199,37 +204,136 @@ public class DisassembleCommand extends BackgroundCommand {
|
||||||
if (startNumAddr > 1) {
|
if (startNumAddr > 1) {
|
||||||
monitor.initialize(startNumAddr);
|
monitor.initialize(startNumAddr);
|
||||||
}
|
}
|
||||||
|
long doneNumAddr = 0;
|
||||||
|
|
||||||
AddressSet allLocalDisAddrs = new AddressSet();
|
AddressSet seedSet = new AddressSet();
|
||||||
|
|
||||||
while (!set.isEmpty() && !monitor.isCancelled()) {
|
// For each range in the address set to disassemble
|
||||||
AddressSet seedSet = getNextSeedSet(program, set, monitor);
|
// small ranges get added to the seedSet
|
||||||
if (seedSet.isEmpty()) {
|
// If a large range is found, then disassemble the seedSet so far, and
|
||||||
|
// process the big range by disassembling flow through the range
|
||||||
|
// causing the analyzer to kick off between disassembly flows
|
||||||
|
AddressRangeIterator addressRanges = startSet.getAddressRanges();
|
||||||
|
for (AddressRange addressRange : addressRanges) {
|
||||||
|
if (monitor.isCancelled()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// bigger address set
|
||||||
|
AddressSet subRangeSet = new AddressSet(addressRange);
|
||||||
|
|
||||||
|
if (startNumAddr > 1) {
|
||||||
|
// report on done - number left in this subRange
|
||||||
|
monitor.setProgress(doneNumAddr);
|
||||||
|
}
|
||||||
|
doneNumAddr += subRangeSet.getNumAddresses(); // addresses are only done when disassembled
|
||||||
|
|
||||||
|
while (!subRangeSet.isEmpty() && !monitor.isCancelled()) {
|
||||||
|
Address nextAddr = subRangeSet.getMinAddress();
|
||||||
|
|
||||||
|
// Check if location is already on disassembly list
|
||||||
|
if (disassembledAddrs.contains(nextAddr)) {
|
||||||
|
AddressRange doneRange = disassembledAddrs.getRangeContaining(nextAddr);
|
||||||
|
subRangeSet.delete(doneRange);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startNumAddr > 1) {
|
subRangeSet.delete(nextAddr, nextAddr);
|
||||||
monitor.setProgress(set.getNumAddresses() - startNumAddr);
|
|
||||||
|
// detect disassembly started in non-executable initialized block
|
||||||
|
if (exectuableSet != null && !exectuableSet.contains(nextAddr) &&
|
||||||
|
!program.getMemory().getLoadedAndInitializedAddressSet().contains(nextAddr)) {
|
||||||
|
nonExecutableStart = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only try disassembly on 2 byte boundaries
|
||||||
|
if ((nextAddr.getOffset() % alignment) != 0) {
|
||||||
|
// Align to the instruction alignment
|
||||||
|
// don't error on align problem here anymore
|
||||||
|
// unalignedStart = true;
|
||||||
|
nextAddr = nextAddr.subtract(nextAddr.getOffset() % alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if range is small, just add it to the seedSet
|
||||||
|
long addrsLeft = subRangeSet.getNumAddresses();
|
||||||
|
if (addrsLeft <= 4) {
|
||||||
|
seedSet.add(nextAddr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// location to disassemble is not undefined
|
||||||
|
Data data = listing.getUndefinedDataAt(nextAddr);
|
||||||
|
if (data == null) {
|
||||||
|
// set the subRangeSet to undefined data in the subRangeSet
|
||||||
|
try {
|
||||||
|
AddressSetView undefRanges;
|
||||||
|
undefRanges =
|
||||||
|
program.getListing().getUndefinedRanges(subRangeSet, true, monitor);
|
||||||
|
subRangeSet = new AddressSet(undefRanges);
|
||||||
|
}
|
||||||
|
catch (CancelledException e) {
|
||||||
|
// will get handled below
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// process the big range by disassembling flow through the range
|
||||||
|
// causing the analyzer to kick off between disassembly flows
|
||||||
|
// disassemble the seedSet first
|
||||||
|
doDisassemblySeeds(disassembler, seedSet, mgr);
|
||||||
|
seedSet = new AddressSet();
|
||||||
|
|
||||||
|
// do the current start of the subRangeSet
|
||||||
AddressSet localDisAddrs =
|
AddressSet localDisAddrs =
|
||||||
disassembler.disassemble(seedSet, restrictedSet, initialContextValue, followFlow);
|
doDisassemblySeeds(disassembler, new AddressSet(nextAddr), mgr);
|
||||||
|
|
||||||
allLocalDisAddrs.add(localDisAddrs);
|
// if anything disassembled, analyze the result set
|
||||||
|
analyzeIfNeeded(mgr, subRangeSet, localDisAddrs, monitor);
|
||||||
|
subRangeSet.delete(localDisAddrs);
|
||||||
|
|
||||||
if (localDisAddrs != null && !localDisAddrs.isEmpty()) {
|
if (startNumAddr > 1) {
|
||||||
disassemblyPerformed = true;
|
monitor.setMaximum(startNumAddr);
|
||||||
analizeIfNeeded(mgr, set, localDisAddrs, monitor);
|
// report on done - number left in this subRange, in case large range
|
||||||
|
monitor.setProgress(doneNumAddr - subRangeSet.getNumAddresses());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set = set.subtract(localDisAddrs);
|
// If there are any small seedSet ranges left, disassemble them
|
||||||
|
// Don't kick off analysis, that will be done later
|
||||||
|
if (!seedSet.isEmpty()) {
|
||||||
|
doDisassemblySeeds(disassembler, seedSet, mgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
disassembledAddrs = allLocalDisAddrs;
|
|
||||||
|
|
||||||
return disassemblyPerformed || (!nonExecutableStart & !unalignedStart);
|
return disassemblyPerformed || (!nonExecutableStart & !unalignedStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do disassembly of a seedSet of address locations
|
||||||
|
*
|
||||||
|
* @param disassembler disassembler to use
|
||||||
|
* @param seedSet set of addresses to be disassembled
|
||||||
|
* @param mgr
|
||||||
|
*
|
||||||
|
* @return addresses actually disassembled
|
||||||
|
*/
|
||||||
|
protected AddressSet doDisassemblySeeds(Disassembler disassembler, AddressSet seedSet,
|
||||||
|
AutoAnalysisManager mgr) {
|
||||||
|
AddressSet newDisassembledAddrs =
|
||||||
|
disassembler.disassemble(seedSet, restrictedSet, initialContextValue, followFlow);
|
||||||
|
|
||||||
|
if (!newDisassembledAddrs.isEmpty()) {
|
||||||
|
disassemblyPerformed = true;
|
||||||
|
disassembledAddrs.add(newDisassembledAddrs);
|
||||||
|
|
||||||
|
// notify analysis manager of new code
|
||||||
|
if (mgr != null) {
|
||||||
|
mgr.codeDefined(newDisassembledAddrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newDisassembledAddrs;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if intermediate analysis is required to reduce the risk of disassembling
|
* Determine if intermediate analysis is required to reduce the risk of disassembling
|
||||||
* data regions when performing static disassembly over a contiguous range if
|
* data regions when performing static disassembly over a contiguous range if
|
||||||
|
@ -242,14 +346,15 @@ public class DisassembleCommand extends BackgroundCommand {
|
||||||
* @param startSet disassembly seed points (prior to removing disassembledSet)
|
* @param startSet disassembly seed points (prior to removing disassembledSet)
|
||||||
* @param disassembledSet last set of disassembled addresses using startSet min-address as seed point
|
* @param disassembledSet last set of disassembled addresses using startSet min-address as seed point
|
||||||
*/
|
*/
|
||||||
private static void analizeIfNeeded(AutoAnalysisManager mgr, AddressSetView startSet,
|
private static void analyzeIfNeeded(AutoAnalysisManager mgr, AddressSetView startSet,
|
||||||
AddressSetView disassembledSet, TaskMonitor monitor) {
|
AddressSetView disassembledSet, TaskMonitor monitor) {
|
||||||
if (mgr == null || monitor.isCancelled()) {
|
if (disassembledSet == null || disassembledSet.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// notify analysis manager of new code
|
if (mgr == null || monitor.isCancelled()) {
|
||||||
mgr.codeDefined(disassembledSet);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
AddressRange firstRange = disassembledSet.getFirstRange();
|
AddressRange firstRange = disassembledSet.getFirstRange();
|
||||||
Address rangeEnd = firstRange.getMaxAddress();
|
Address rangeEnd = firstRange.getMaxAddress();
|
||||||
|
@ -259,77 +364,6 @@ public class DisassembleCommand extends BackgroundCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AddressSet getNextSeedSet(Program program, AddressSet set, TaskMonitor monitor) {
|
|
||||||
AddressSet seedSet = new AddressSet();
|
|
||||||
|
|
||||||
boolean bigRangeFound = false;
|
|
||||||
|
|
||||||
while (!monitor.isCancelled() && !set.isEmpty() && !bigRangeFound) {
|
|
||||||
Address firstaddr = set.getMinAddress();
|
|
||||||
|
|
||||||
// if the range is only 4 byte, assume these are seed disassembly points
|
|
||||||
// and don't cause analysis to happen until the end
|
|
||||||
// unless a range of addresses is found.
|
|
||||||
|
|
||||||
AddressRange addressRange = set.iterator().next();
|
|
||||||
if (addressRange.getLength() > 4) {
|
|
||||||
bigRangeFound = true;
|
|
||||||
}
|
|
||||||
set.deleteRange(firstaddr, firstaddr);
|
|
||||||
|
|
||||||
if (!program.getListing().isUndefined(firstaddr, firstaddr)) {
|
|
||||||
Address end = firstaddr;
|
|
||||||
|
|
||||||
// if nothing left, don't try to find the next undefined location
|
|
||||||
if (set.isEmpty()) {
|
|
||||||
return seedSet;
|
|
||||||
}
|
|
||||||
// if the address right after this one isn't in the set, just jump to the
|
|
||||||
// start of the next range in the set. start has already been deleted.
|
|
||||||
Address nextAddr = firstaddr.next();
|
|
||||||
if (nextAddr == null || !set.contains(nextAddr)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the next undefined after this, but restrict it to this set
|
|
||||||
Data next = program.getListing().getFirstUndefinedData(set, monitor);
|
|
||||||
|
|
||||||
if (next != null) {
|
|
||||||
end = next.getMinAddress();
|
|
||||||
set.deleteRange(firstaddr, end);
|
|
||||||
firstaddr = end;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
set.clear(); // no more undefined here
|
|
||||||
return seedSet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// detect case where disassembly was started in non-executable initialized block
|
|
||||||
if (exectuableSet != null && !exectuableSet.contains(firstaddr) &&
|
|
||||||
!program.getMemory().getLoadedAndInitializedAddressSet().contains(firstaddr)) {
|
|
||||||
nonExecutableStart = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// only try disassembly on 2 byte boundaries
|
|
||||||
if ((firstaddr.getOffset() % alignment) != 0) {
|
|
||||||
// Align to the instruction alignment
|
|
||||||
// don't error on align problem here anymore
|
|
||||||
// unalignedStart = true;
|
|
||||||
firstaddr = firstaddr.subtract(firstaddr.getOffset() % alignment);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there is already stuff there, don't put any context
|
|
||||||
if (!program.getListing().isUndefined(firstaddr, firstaddr)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
seedSet.add(firstaddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return seedSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an address set of all instructions that were disassembled.
|
* Returns an address set of all instructions that were disassembled.
|
||||||
* @return an address set of all instructions that were disassembled
|
* @return an address set of all instructions that were disassembled
|
||||||
|
|
|
@ -25,7 +25,6 @@ import ghidra.app.util.RepeatInstructionByteTracker;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.program.database.register.AddressRangeObjectMap;
|
import ghidra.program.database.register.AddressRangeObjectMap;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.data.DefaultDataType;
|
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.lang.InstructionError.InstructionErrorType;
|
import ghidra.program.model.lang.InstructionError.InstructionErrorType;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
|
@ -127,6 +126,7 @@ public class Disassembler implements DisassemblerConflictHandler {
|
||||||
* @param program the program to be disassembled.
|
* @param program the program to be disassembled.
|
||||||
* @param monitor progress monitor
|
* @param monitor progress monitor
|
||||||
* @param listener object to notify of disassembly messages.
|
* @param listener object to notify of disassembly messages.
|
||||||
|
* @return a disassembler ready to disassemble
|
||||||
*/
|
*/
|
||||||
public static Disassembler getDisassembler(Program program, TaskMonitor monitor,
|
public static Disassembler getDisassembler(Program program, TaskMonitor monitor,
|
||||||
DisassemblerMessageListener listener) {
|
DisassemblerMessageListener listener) {
|
||||||
|
@ -157,6 +157,7 @@ public class Disassembler implements DisassemblerConflictHandler {
|
||||||
* @param addrFactory address factory
|
* @param addrFactory address factory
|
||||||
* @param monitor progress monitor
|
* @param monitor progress monitor
|
||||||
* @param listener object to notify of disassembly messages.
|
* @param listener object to notify of disassembly messages.
|
||||||
|
* @return a disassembler ready to disassemble
|
||||||
*/
|
*/
|
||||||
public static Disassembler getDisassembler(Language language, AddressFactory addrFactory,
|
public static Disassembler getDisassembler(Language language, AddressFactory addrFactory,
|
||||||
TaskMonitor monitor, DisassemblerMessageListener listener) {
|
TaskMonitor monitor, DisassemblerMessageListener listener) {
|
||||||
|
@ -186,6 +187,7 @@ public class Disassembler implements DisassemblerConflictHandler {
|
||||||
* @param restrictToExecuteMemory if true disassembly will only be permitted with executable memory blocks
|
* @param restrictToExecuteMemory if true disassembly will only be permitted with executable memory blocks
|
||||||
* @param monitor progress monitor
|
* @param monitor progress monitor
|
||||||
* @param listener object to notify of disassembly messages.
|
* @param listener object to notify of disassembly messages.
|
||||||
|
* @return a disassembler ready to disassemble
|
||||||
*/
|
*/
|
||||||
public static Disassembler getDisassembler(Program program, boolean markBadInstructions,
|
public static Disassembler getDisassembler(Program program, boolean markBadInstructions,
|
||||||
boolean markUnimplementedPcode, boolean restrictToExecuteMemory, TaskMonitor monitor,
|
boolean markUnimplementedPcode, boolean restrictToExecuteMemory, TaskMonitor monitor,
|
||||||
|
@ -297,7 +299,7 @@ public class Disassembler implements DisassemblerConflictHandler {
|
||||||
* Set seed context which will be used to establish initial context at starting points
|
* Set seed context which will be used to establish initial context at starting points
|
||||||
* which are not arrived at via a natural disassembly flow. A null value will disable
|
* which are not arrived at via a natural disassembly flow. A null value will disable
|
||||||
* use of any previously set seed context
|
* use of any previously set seed context
|
||||||
* @param seedContext
|
* @param seedContext initial context for disassembly
|
||||||
*/
|
*/
|
||||||
public void setSeedContext(DisassemblerContextImpl seedContext) {
|
public void setSeedContext(DisassemblerContextImpl seedContext) {
|
||||||
if (seedContext != null && seedContext.getBaseContextRegister() != baseContextRegister) {
|
if (seedContext != null && seedContext.getBaseContextRegister() != baseContextRegister) {
|
||||||
|
@ -341,7 +343,7 @@ public class Disassembler implements DisassemblerConflictHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param program
|
* @param program the program to check
|
||||||
* @return true if program MARK_BAD_INSTRUCTION_PROPERTY has been enabled
|
* @return true if program MARK_BAD_INSTRUCTION_PROPERTY has been enabled
|
||||||
*/
|
*/
|
||||||
public static boolean isMarkBadDisassemblyOptionEnabled(Program program) {
|
public static boolean isMarkBadDisassemblyOptionEnabled(Program program) {
|
||||||
|
@ -350,7 +352,7 @@ public class Disassembler implements DisassemblerConflictHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param program
|
* @param program the program to check
|
||||||
* @return true if program MARK_UNIMPL_PCODE_PROPERTY has been enabled
|
* @return true if program MARK_UNIMPL_PCODE_PROPERTY has been enabled
|
||||||
*/
|
*/
|
||||||
public static boolean isMarkUnimplementedPcodeOptionEnabled(Program program) {
|
public static boolean isMarkUnimplementedPcodeOptionEnabled(Program program) {
|
||||||
|
@ -359,7 +361,7 @@ public class Disassembler implements DisassemblerConflictHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param program
|
* @param program the program to check
|
||||||
* @return true if program RESTRICT_DISASSEMBLY_TO_EXECUTE_MEMORY_PROPERTY has been enabled
|
* @return true if program RESTRICT_DISASSEMBLY_TO_EXECUTE_MEMORY_PROPERTY has been enabled
|
||||||
*/
|
*/
|
||||||
public static boolean isRestrictToExecuteMemory(Program program) {
|
public static boolean isRestrictToExecuteMemory(Program program) {
|
||||||
|
@ -436,44 +438,56 @@ public class Disassembler implements DisassemblerConflictHandler {
|
||||||
|
|
||||||
disassembledAddrs = new AddressSet();
|
disassembledAddrs = new AddressSet();
|
||||||
|
|
||||||
AddressSet todo = new AddressSet(startSet);
|
|
||||||
|
|
||||||
int alignment = language.getInstructionAlignment();
|
int alignment = language.getInstructionAlignment();
|
||||||
while (!todo.isEmpty() && !monitor.isCancelled()) {
|
|
||||||
Address addr = todo.getMinAddress();
|
AddressRangeIterator addressRanges = startSet.getAddressRanges();
|
||||||
// must be aligned
|
for (AddressRange addressRange : addressRanges) {
|
||||||
if (addr.getOffset() % alignment != 0) {
|
if (monitor.isCancelled()) {
|
||||||
todo.deleteRange(addr, addr);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Data data = listing.getUndefinedDataAt(addr);
|
|
||||||
if (data == null) {
|
|
||||||
Address endAddr = addr;
|
|
||||||
CodeUnitIterator it = listing.getCodeUnits(todo, true);
|
|
||||||
while (it.hasNext() && !monitor.isCancelled()) {
|
|
||||||
CodeUnit cu = it.next();
|
|
||||||
if (cu instanceof Data &&
|
|
||||||
((Data) cu).getDataType() instanceof DefaultDataType) {
|
|
||||||
data = (Data) cu;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
endAddr = cu.getMaxAddress();
|
|
||||||
|
if (disassembledAddrs.contains(addressRange.getMinAddress(),
|
||||||
|
addressRange.getMaxAddress())) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AddressSet todoSubset = new AddressSet(addressRange);
|
||||||
|
|
||||||
|
while (!todoSubset.isEmpty() && !monitor.isCancelled()) {
|
||||||
|
Address nextAddr = todoSubset.getMinAddress();
|
||||||
|
|
||||||
|
// Check if location is already on disassembly list
|
||||||
|
if (disassembledAddrs.contains(nextAddr)) {
|
||||||
|
AddressRange doneRange = disassembledAddrs.getRangeContaining(nextAddr);
|
||||||
|
todoSubset.delete(doneRange);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
todoSubset.delete(nextAddr, nextAddr);
|
||||||
|
|
||||||
|
// must be aligned
|
||||||
|
if (nextAddr.getOffset() % alignment != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data data = listing.getUndefinedDataAt(nextAddr);
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
todo.clear();
|
AddressSetView undefinedRanges = null;
|
||||||
|
try {
|
||||||
|
undefinedRanges =
|
||||||
|
program.getListing().getUndefinedRanges(todoSubset, true, monitor);
|
||||||
|
todoSubset = new AddressSet(undefinedRanges);
|
||||||
}
|
}
|
||||||
else {
|
catch (CancelledException e) {
|
||||||
todo.deleteRange(addr, endAddr);
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
AddressSet currentSet =
|
AddressSet currentSet =
|
||||||
disassemble(addr, restrictedSet, initialContextValue, doFollowFlow);
|
disassemble(nextAddr, restrictedSet, initialContextValue, doFollowFlow);
|
||||||
if (currentSet.isEmpty()) {
|
|
||||||
todo.deleteRange(addr, addr);
|
if (!currentSet.isEmpty()) { // nothing disassembled
|
||||||
}
|
todoSubset.delete(currentSet);
|
||||||
else {
|
|
||||||
todo.delete(currentSet);
|
|
||||||
disassembledAddrs.add(currentSet);
|
disassembledAddrs.add(currentSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -481,6 +495,7 @@ public class Disassembler implements DisassemblerConflictHandler {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return disassembledAddrs;
|
return disassembledAddrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -905,8 +920,9 @@ public class Disassembler implements DisassemblerConflictHandler {
|
||||||
|
|
||||||
disassemblerContext.flowToAddress(addr);
|
disassemblerContext.flowToAddress(addr);
|
||||||
|
|
||||||
MemBuffer instrMemBuffer = new WrappedMemBuffer(blockMemBuffer,
|
// TODO: An overall better caching of bytes for this block could be done instead
|
||||||
(int) addr.subtract(blockMemBuffer.getAddress()));
|
// the previous buffering done here was not doing any buffering
|
||||||
|
MemBuffer instrMemBuffer = new DumbMemBufferImpl(blockMemBuffer.getMemory(), addr);
|
||||||
|
|
||||||
adjustPreParseContext(instrMemBuffer);
|
adjustPreParseContext(instrMemBuffer);
|
||||||
|
|
||||||
|
@ -1100,7 +1116,7 @@ public class Disassembler implements DisassemblerConflictHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adjust disassembler context prior to disassembly of a new instruction.
|
* Adjust disassembler context prior to disassembly of a new instruction.
|
||||||
* @param instrMemBuffer
|
* @param instrMemBuffer buffer for bytes from memory
|
||||||
* @throws UnknownInstructionException if instruction is invalid
|
* @throws UnknownInstructionException if instruction is invalid
|
||||||
*/
|
*/
|
||||||
protected void adjustPreParseContext(MemBuffer instrMemBuffer)
|
protected void adjustPreParseContext(MemBuffer instrMemBuffer)
|
||||||
|
@ -1134,16 +1150,16 @@ public class Disassembler implements DisassemblerConflictHandler {
|
||||||
* Process a new instruction which has just been parsed. This method is responsible for
|
* Process a new instruction which has just been parsed. This method is responsible for
|
||||||
* adding the instruction to the current block as well as any delay-slotted instructions.
|
* adding the instruction to the current block as well as any delay-slotted instructions.
|
||||||
* This method may be overridden and the instruction re-parsed if necessary.
|
* This method may be overridden and the instruction re-parsed if necessary.
|
||||||
* @param inst
|
* @param inst instruction to process
|
||||||
* @param blockMemBuffer
|
* @param blockMemBuffer buffer to get bytes
|
||||||
* @param block
|
* @param block current block of instructions
|
||||||
* @param instructionSet
|
* @param instructionSet address set of current instructions in block
|
||||||
* @return instruction fallthrough address or null if no fallthrough
|
* @return instruction fallthrough address or null if no fallthrough
|
||||||
* @throws InsufficientBytesException if a memory error occurs during instruction processing
|
* @throws InsufficientBytesException if a memory error occurs during instruction processing
|
||||||
* @throws UnknownInstructionException if an error occurs during a modified re-parse of
|
* @throws UnknownInstructionException if an error occurs during a modified re-parse of
|
||||||
* the instruction.
|
* the instruction.
|
||||||
* @throws AddressOverflowException
|
* @throws AddressOverflowException if address goes out of address space
|
||||||
* @throws NestedDelaySlotException
|
* @throws NestedDelaySlotException if delay slot found in a delay slot
|
||||||
*/
|
*/
|
||||||
protected Address processInstruction(PseudoInstruction inst, MemBuffer blockMemBuffer,
|
protected Address processInstruction(PseudoInstruction inst, MemBuffer blockMemBuffer,
|
||||||
InstructionBlock block, InstructionSet instructionSet)
|
InstructionBlock block, InstructionSet instructionSet)
|
||||||
|
@ -1341,8 +1357,9 @@ public class Disassembler implements DisassemblerConflictHandler {
|
||||||
PcodeInjectLibrary pcodeInjectLibrary = program.getCompilerSpec().getPcodeInjectLibrary();
|
PcodeInjectLibrary pcodeInjectLibrary = program.getCompilerSpec().getPcodeInjectLibrary();
|
||||||
InjectPayload callFixup = pcodeInjectLibrary.getPayload(InjectPayload.CALLFIXUP_TYPE,
|
InjectPayload callFixup = pcodeInjectLibrary.getPayload(InjectPayload.CALLFIXUP_TYPE,
|
||||||
callFixupStr, program, null);
|
callFixupStr, program, null);
|
||||||
if (callFixup == null)
|
if (callFixup == null) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
return !callFixup.isFallThru();
|
return !callFixup.isFallThru();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1415,10 +1432,10 @@ public class Disassembler implements DisassemblerConflictHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark all instructions with unimplemented pcode over the specified address set
|
* Mark all instructions with unimplemented pcode over the specified address set
|
||||||
* @param program
|
* @param program to mark unimplemented in
|
||||||
* @param addressSet restricted address set or null for entire program
|
* @param addressSet restricted address set or null for entire program
|
||||||
* @param monitor
|
* @param monitor allow canceling
|
||||||
* @throws CancelledException
|
* @throws CancelledException if monitor canceled
|
||||||
*/
|
*/
|
||||||
public static void markUnimplementedPcode(Program program, AddressSetView addressSet,
|
public static void markUnimplementedPcode(Program program, AddressSetView addressSet,
|
||||||
TaskMonitor monitor) throws CancelledException {
|
TaskMonitor monitor) throws CancelledException {
|
||||||
|
@ -1437,10 +1454,10 @@ public class Disassembler implements DisassemblerConflictHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear all bookmarks which indicate unimplemented pcode within the specified address set.
|
* Clear all bookmarks which indicate unimplemented pcode within the specified address set.
|
||||||
* @param program
|
* @param program program to clear bookmarks
|
||||||
* @param addressSet restricted address set or null for entire program
|
* @param addressSet restricted address set or null for entire program
|
||||||
* @param monitor
|
* @param monitor allow canceling
|
||||||
* @throws CancelledException
|
* @throws CancelledException if monitor canceled
|
||||||
*/
|
*/
|
||||||
public static void clearUnimplementedPcodeWarnings(Program program, AddressSetView addressSet,
|
public static void clearUnimplementedPcodeWarnings(Program program, AddressSetView addressSet,
|
||||||
TaskMonitor monitor) throws CancelledException {
|
TaskMonitor monitor) throws CancelledException {
|
||||||
|
@ -1492,10 +1509,10 @@ public class Disassembler implements DisassemblerConflictHandler {
|
||||||
* for minting a new instruction. If value is not null, the temporary context is expanded
|
* for minting a new instruction. If value is not null, the temporary context is expanded
|
||||||
* to include the context-register value. The temporary context should be cleared after in-memory
|
* to include the context-register value. The temporary context should be cleared after in-memory
|
||||||
* instructions (i.e., InstructionSet) have been written to the program.
|
* instructions (i.e., InstructionSet) have been written to the program.
|
||||||
* @param value
|
* @param value to add to instruction context if different
|
||||||
* @param instrAddr
|
* @param instrAddr address of instruction that should have context
|
||||||
* @param instrLength
|
* @param instrLength length of instruction to set context
|
||||||
* @return
|
* @return instruction context with possible added value
|
||||||
*/
|
*/
|
||||||
ProcessorContext getInstructionContext(RegisterValue value, Address instrAddr,
|
ProcessorContext getInstructionContext(RegisterValue value, Address instrAddr,
|
||||||
int instrLength) {
|
int instrLength) {
|
||||||
|
|
|
@ -0,0 +1,394 @@
|
||||||
|
/* ###
|
||||||
|
* 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.disassemble;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.*;
|
||||||
|
|
||||||
|
import ghidra.app.cmd.disassemble.DisassembleCommand;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.address.AddressSet;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
|
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||||
|
import ghidra.test.ToyProgramBuilder;
|
||||||
|
import ghidra.util.task.TaskMonitorAdapter;
|
||||||
|
|
||||||
|
public class DisassemblerLargeSetTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||||
|
|
||||||
|
private static final int MEMORY_SIZE = 1024 * 128;
|
||||||
|
|
||||||
|
private static final int CASESIZE = 12;
|
||||||
|
|
||||||
|
private static final long NUMCASES = MEMORY_SIZE / CASESIZE;
|
||||||
|
|
||||||
|
private static byte disBlock[] = { (byte) 0xf5, 0x0c, 0x03, 0x04, (byte) 0xf4, 0x00,
|
||||||
|
(byte) 0xdf, 0x34, (byte) 0xf4, 0x00, (byte) 0xf4, 0x00 };
|
||||||
|
|
||||||
|
private ToyProgramBuilder programBuilder;// Instructions are 2-byte aligned
|
||||||
|
private Program program;
|
||||||
|
private Disassembler disassembler;
|
||||||
|
|
||||||
|
private int txId;
|
||||||
|
|
||||||
|
private long startTime = 0;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
programBuilder = new ToyProgramBuilder("Test", true, true, null);
|
||||||
|
program = programBuilder.getProgram();
|
||||||
|
txId = program.startTransaction("Add Memory");// leave open until tearDown
|
||||||
|
programBuilder.createMemory(".text", "0", MEMORY_SIZE).setExecute(true);// initialized
|
||||||
|
|
||||||
|
// Fill memory
|
||||||
|
MemoryBlock block = programBuilder.getProgram().getMemory().getBlock(addr(0x0));
|
||||||
|
long numCases = MEMORY_SIZE / CASESIZE;
|
||||||
|
for (long i = 0; i < numCases; i++) {
|
||||||
|
block.putBytes(addr(i * CASESIZE), disBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
disassembler = new Disassembler(program, TaskMonitorAdapter.DUMMY_MONITOR, null);
|
||||||
|
|
||||||
|
startTime = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
if (program != null) {
|
||||||
|
program.endTransaction(txId, true);
|
||||||
|
}
|
||||||
|
if (programBuilder != null) {
|
||||||
|
programBuilder.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
long endTime = System.currentTimeMillis();
|
||||||
|
System.out.println("Time: " + ((double) endTime - (double) startTime) / 1000.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Address addr(long offset) {
|
||||||
|
return programBuilder.getAddress(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyBookmarks(int cnt) {
|
||||||
|
assertEquals("unexpected bookmarks exist", cnt,
|
||||||
|
program.getBookmarkManager().getBookmarkCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLargeDisjointPointsNoPredisassembledPoints() throws Exception {
|
||||||
|
|
||||||
|
// disassemble the threaded flow
|
||||||
|
AddressSet disassemble1 = disassembler.disassemble(addr(0x0), null, true);
|
||||||
|
|
||||||
|
AddressSet disLocs = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs.add(addr(i * CASESIZE));
|
||||||
|
}
|
||||||
|
assertTrue(disassemble1.contains(disLocs));
|
||||||
|
|
||||||
|
AddressSet disLocs2 = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs2.add(addr(i * CASESIZE + 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressSet disassemble2 = disassembler.disassemble(disLocs2, null, true);
|
||||||
|
|
||||||
|
assertTrue(disassemble2.contains(disLocs2));
|
||||||
|
|
||||||
|
verifyBookmarks(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLargeDisjointPointsWithAlreadyDiassembledPoints() throws Exception {
|
||||||
|
// disassemble the threaded flow
|
||||||
|
AddressSet disassemble1 = disassembler.disassemble(addr(0x0), null, true);
|
||||||
|
|
||||||
|
AddressSet disLocs = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs.add(addr(i * CASESIZE));
|
||||||
|
}
|
||||||
|
assertTrue(disassemble1.contains(disLocs));
|
||||||
|
|
||||||
|
AddressSet disLocs2 = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs2.add(addr(i * CASESIZE));
|
||||||
|
disLocs2.add(addr(i * CASESIZE + 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressSet disassemble2 = disassembler.disassemble(disLocs2, null, true);
|
||||||
|
|
||||||
|
assertTrue(disassemble2.contains(disLocs2.subtract(disLocs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLargeDisjointRange() throws Exception {
|
||||||
|
// disassemble the threaded flow
|
||||||
|
AddressSet disassemble1 = disassembler.disassemble(addr(0x0), null, true);
|
||||||
|
|
||||||
|
AddressSet disLocs = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs.add(addr(i * CASESIZE));
|
||||||
|
}
|
||||||
|
assertTrue(disassemble1.contains(disLocs));
|
||||||
|
|
||||||
|
AddressSet disLocs2 = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs2.add(addr(i * CASESIZE));
|
||||||
|
disLocs2.add(addr(i * CASESIZE + 6), addr(i * CASESIZE + 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressSet disassemble2 = disassembler.disassemble(disLocs2, null, true);
|
||||||
|
|
||||||
|
assertTrue(disassemble2.contains(disLocs2.subtract(disLocs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLargeDisjointRangePartialOverlap() throws Exception {
|
||||||
|
// disassemble the threaded flow
|
||||||
|
AddressSet disassemble1 = disassembler.disassemble(addr(0x0), null, true);
|
||||||
|
|
||||||
|
AddressSet disLocs = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs.add(addr(i * CASESIZE));
|
||||||
|
}
|
||||||
|
assertTrue(disassemble1.contains(disLocs));
|
||||||
|
|
||||||
|
AddressSet disLocs2 = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs2.add(addr(i * CASESIZE));
|
||||||
|
disLocs2.add(addr(i * CASESIZE + 6), addr(i * CASESIZE + 11));
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressSet disassemble2 = disassembler.disassemble(disLocs2, null, true);
|
||||||
|
|
||||||
|
assertTrue(disassemble2.contains(disLocs2.subtract(disLocs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLargeDisjointRangeFullOverlap() throws Exception {
|
||||||
|
// disassemble the threaded flow
|
||||||
|
AddressSet disassemble1 = disassembler.disassemble(addr(0x0), null, true);
|
||||||
|
|
||||||
|
AddressSet disLocs = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs.add(addr(i * CASESIZE), addr(i * CASESIZE + 3));
|
||||||
|
}
|
||||||
|
assertTrue(disassemble1.contains(disLocs));
|
||||||
|
|
||||||
|
AddressSet disLocs2 = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs2.add(addr(i * CASESIZE), addr(i * CASESIZE + 3));
|
||||||
|
disLocs2.add(addr(i * CASESIZE + 6), addr(i * CASESIZE + 11));
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressSet disassemble2 = disassembler.disassemble(disLocs2, null, true);
|
||||||
|
|
||||||
|
assertTrue(disassemble2.contains(disLocs2.subtract(disLocs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleRange() throws Exception {
|
||||||
|
AddressSet disLocs2 = new AddressSet(addr(0x0), addr(CASESIZE * (NUMCASES)));
|
||||||
|
|
||||||
|
AddressSet disassemble2 = disassembler.disassemble(disLocs2, null, true);
|
||||||
|
|
||||||
|
assertTrue(disassemble2.contains(disLocs2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleRangeDisjoint() throws Exception {
|
||||||
|
// disassemble the threaded flow
|
||||||
|
AddressSet disassemble1 = disassembler.disassemble(addr(0x0), null, true);
|
||||||
|
|
||||||
|
AddressSet disLocs2 = new AddressSet(addr(0x0), addr(CASESIZE * (NUMCASES)));
|
||||||
|
|
||||||
|
AddressSet disassemble2 = disassembler.disassemble(disLocs2, null, true);
|
||||||
|
|
||||||
|
AddressSet disLocs = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs.add(addr(i * CASESIZE));
|
||||||
|
}
|
||||||
|
assertTrue(!disassemble2.contains(disLocs));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLargeDisjointPointsNoPredisassembledPointsCmd() throws Exception {
|
||||||
|
|
||||||
|
// disassemble the threaded flow
|
||||||
|
//AddressSet disassemble1 = disassembler.disassemble(addr(0x0), null, true);
|
||||||
|
DisassembleCommand disassembleCommand = new DisassembleCommand(addr(0x0), null, true);
|
||||||
|
disassembleCommand.applyTo(program);
|
||||||
|
|
||||||
|
AddressSet disLocs = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs.add(addr(i * CASESIZE));
|
||||||
|
}
|
||||||
|
assertTrue(disassembleCommand.getDisassembledAddressSet().contains(disLocs));
|
||||||
|
|
||||||
|
AddressSet disLocs2 = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs2.add(addr(i * CASESIZE + 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
//AddressSet disassemble2 = disassembler.disassemble(disLocs2, null, true);
|
||||||
|
disassembleCommand = new DisassembleCommand(disLocs2, null, true);
|
||||||
|
disassembleCommand.applyTo(program);
|
||||||
|
|
||||||
|
assertTrue(disassembleCommand.getDisassembledAddressSet().contains(disLocs2));
|
||||||
|
|
||||||
|
verifyBookmarks(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLargeDisjointPointsWithAlreadyDiassembledPointsCmd() throws Exception {
|
||||||
|
// disassemble the threaded flow
|
||||||
|
//AddressSet disassemble1 = disassembler.disassemble(addr(0x0), null, true);
|
||||||
|
DisassembleCommand disassembleCommand = new DisassembleCommand(addr(0x0), null, true);
|
||||||
|
disassembleCommand.applyTo(program);
|
||||||
|
|
||||||
|
AddressSet disLocs = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs.add(addr(i * CASESIZE));
|
||||||
|
}
|
||||||
|
assertTrue(disassembleCommand.getDisassembledAddressSet().contains(disLocs));
|
||||||
|
|
||||||
|
AddressSet disLocs2 = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs2.add(addr(i * CASESIZE));
|
||||||
|
disLocs2.add(addr(i * CASESIZE + 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
//AddressSet disassemble2 = disassembler.disassemble(disLocs2, null, true);
|
||||||
|
disassembleCommand = new DisassembleCommand(disLocs2, null, true);
|
||||||
|
disassembleCommand.applyTo(program);
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
disassembleCommand.getDisassembledAddressSet().contains(disLocs2.subtract(disLocs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLargeDisjointRangeCmd() throws Exception {
|
||||||
|
// disassemble the threaded flow
|
||||||
|
// AddressSet disassemble1 = disassembler.disassemble(addr(0x0), null, true);
|
||||||
|
DisassembleCommand disassembleCommand = new DisassembleCommand(addr(0x0), null, true);
|
||||||
|
disassembleCommand.applyTo(program);
|
||||||
|
|
||||||
|
AddressSet disLocs = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs.add(addr(i * CASESIZE));
|
||||||
|
}
|
||||||
|
assertTrue(disassembleCommand.getDisassembledAddressSet().contains(disLocs));
|
||||||
|
|
||||||
|
AddressSet disLocs2 = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs2.add(addr(i * CASESIZE));
|
||||||
|
disLocs2.add(addr(i * CASESIZE + 6), addr(i * CASESIZE + 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
//AddressSet disassemble2 = disassembler.disassemble(disLocs2, null, true);
|
||||||
|
disassembleCommand = new DisassembleCommand(disLocs2, null, true);
|
||||||
|
disassembleCommand.applyTo(program);
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
disassembleCommand.getDisassembledAddressSet().contains(disLocs2.subtract(disLocs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLargeDisjointRangePartialOverlapCmd() throws Exception {
|
||||||
|
// disassemble the threaded flow
|
||||||
|
//AddressSet disassemble1 = disassembler.disassemble(addr(0x0), null, true);
|
||||||
|
DisassembleCommand disassembleCommand = new DisassembleCommand(addr(0x0), null, true);
|
||||||
|
disassembleCommand.applyTo(program);
|
||||||
|
|
||||||
|
AddressSet disLocs = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs.add(addr(i * CASESIZE));
|
||||||
|
}
|
||||||
|
assertTrue(disassembleCommand.getDisassembledAddressSet().contains(disLocs));
|
||||||
|
|
||||||
|
AddressSet disLocs2 = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs2.add(addr(i * CASESIZE));
|
||||||
|
disLocs2.add(addr(i * CASESIZE + 6), addr(i * CASESIZE + 11));
|
||||||
|
}
|
||||||
|
|
||||||
|
//AddressSet disassemble2 = disassembler.disassemble(disLocs2, null, true);
|
||||||
|
disassembleCommand = new DisassembleCommand(disLocs2, null, true);
|
||||||
|
disassembleCommand.applyTo(program);
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
disassembleCommand.getDisassembledAddressSet().contains(disLocs2.subtract(disLocs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLargeDisjointRangeFullOverlapCmd() throws Exception {
|
||||||
|
// disassemble the threaded flow
|
||||||
|
//AddressSet disassemble1 = disassembler.disassemble(addr(0x0), null, true);
|
||||||
|
DisassembleCommand disassembleCommand = new DisassembleCommand(addr(0x0), null, true);
|
||||||
|
disassembleCommand.applyTo(program);
|
||||||
|
|
||||||
|
AddressSet disLocs = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs.add(addr(i * CASESIZE), addr(i * CASESIZE + 3));
|
||||||
|
}
|
||||||
|
assertTrue(disassembleCommand.getDisassembledAddressSet().contains(disLocs));
|
||||||
|
|
||||||
|
AddressSet disLocs2 = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs2.add(addr(i * CASESIZE), addr(i * CASESIZE + 3));
|
||||||
|
disLocs2.add(addr(i * CASESIZE + 6), addr(i * CASESIZE + 11));
|
||||||
|
}
|
||||||
|
|
||||||
|
//AddressSet disassemble2 = disassembler.disassemble(disLocs2, null, true);
|
||||||
|
disassembleCommand = new DisassembleCommand(disLocs2, null, true);
|
||||||
|
disassembleCommand.applyTo(program);
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
disassembleCommand.getDisassembledAddressSet().contains(disLocs2.subtract(disLocs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleRangeCmd() throws Exception {
|
||||||
|
AddressSet disLocs2 = new AddressSet(addr(0x0), addr(CASESIZE * (NUMCASES)));
|
||||||
|
|
||||||
|
//AddressSet disassemble2 = disassembler.disassemble(disLocs2, null, true);
|
||||||
|
DisassembleCommand disassembleCommand = new DisassembleCommand(disLocs2, null, true);
|
||||||
|
disassembleCommand.applyTo(program);
|
||||||
|
|
||||||
|
assertTrue(disassembleCommand.getDisassembledAddressSet().contains(disLocs2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleRangeDisjointCmd() throws Exception {
|
||||||
|
// disassemble the threaded flow
|
||||||
|
//AddressSet disassemble1 = disassembler.disassemble(addr(0x0), null, true);
|
||||||
|
DisassembleCommand disassembleCommand = new DisassembleCommand(addr(0x0), null, true);
|
||||||
|
disassembleCommand.applyTo(program);
|
||||||
|
|
||||||
|
AddressSet disLocs2 = new AddressSet(addr(0x0), addr(CASESIZE * (NUMCASES)));
|
||||||
|
|
||||||
|
//AddressSet disassemble2 = disassembler.disassemble(disLocs2, null, true);
|
||||||
|
disassembleCommand = new DisassembleCommand(disLocs2, null, true);
|
||||||
|
disassembleCommand.applyTo(program);
|
||||||
|
|
||||||
|
AddressSet disLocs = new AddressSet();
|
||||||
|
for (long i = 0; i < NUMCASES; i++) {
|
||||||
|
disLocs.add(addr(i * CASESIZE));
|
||||||
|
}
|
||||||
|
assertTrue(!disassembleCommand.getDisassembledAddressSet().contains(disLocs));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue