mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-22 04:05:39 +00:00
GP-5013 Rework disassembler to address special use cases
This commit is contained in:
parent
d97df93cd5
commit
d5ae0f96e8
@ -680,7 +680,20 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||||||
while ((nextBlock = disassemblerQueue.getNextBlockToBeDisassembled(fallThruAddr,
|
while ((nextBlock = disassemblerQueue.getNextBlockToBeDisassembled(fallThruAddr,
|
||||||
programMemBuffer.getMemory(), monitor)) != null) {
|
programMemBuffer.getMemory(), monitor)) != null) {
|
||||||
|
|
||||||
Address blockAddr = disassemblerQueue.getDisassemblyAddress();
|
Address blockAddr = nextBlock.getStartAddress();
|
||||||
|
Address flowFrom = nextBlock.getFlowFromAddress();
|
||||||
|
|
||||||
|
if (flowFrom != null) {
|
||||||
|
InstructionBlock containingBlock =
|
||||||
|
instructionSet.getInstructionBlockContaining(blockAddr);
|
||||||
|
if (containingBlock != null && containingBlock.getInstructionAt(flowFrom) != null) {
|
||||||
|
// Skip block if start address already handled as a fallthrough.
|
||||||
|
// NOTE: This behavior is relied upon by customized disassemblers which may
|
||||||
|
// create a conjoined InstructionBlock for an unconditional branch which
|
||||||
|
// behaves like a fallthrough flow.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!disassemblerContext.isFlowActive()) {
|
if (!disassemblerContext.isFlowActive()) {
|
||||||
disassemblerContext.flowStart(blockAddr);
|
disassemblerContext.flowStart(blockAddr);
|
||||||
@ -932,6 +945,7 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||||||
while (!monitor.isCancelled() && addr != null) {
|
while (!monitor.isCancelled() && addr != null) {
|
||||||
|
|
||||||
if (restrictedAddressSet != null && !restrictedAddressSet.contains(addr)) {
|
if (restrictedAddressSet != null && !restrictedAddressSet.contains(addr)) {
|
||||||
|
blockTerminated(block);
|
||||||
return; // no fall-through
|
return; // no fall-through
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -941,16 +955,13 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||||||
new WrappedMemBuffer(blockMemBuffer, DISASSEMBLE_MEMORY_CACHE_SIZE,
|
new WrappedMemBuffer(blockMemBuffer, DISASSEMBLE_MEMORY_CACHE_SIZE,
|
||||||
(int) addr.subtract(blockMemBuffer.getAddress()));
|
(int) addr.subtract(blockMemBuffer.getAddress()));
|
||||||
|
|
||||||
adjustPreParseContext(instrMemBuffer);
|
InstructionPrototype prototype = parseInstructionPrototype(instrMemBuffer, block);
|
||||||
|
|
||||||
RegisterValue contextValue = null;
|
RegisterValue contextValue = null;
|
||||||
if (baseContextRegister != null) {
|
if (baseContextRegister != null) {
|
||||||
contextValue = disassemblerContext.getRegisterValue(baseContextRegister);
|
contextValue = disassemblerContext.getRegisterValue(baseContextRegister);
|
||||||
}
|
}
|
||||||
|
|
||||||
InstructionPrototype prototype =
|
|
||||||
language.parse(instrMemBuffer, disassemblerContext, false);
|
|
||||||
|
|
||||||
// if fall-through already exists in another block - check for conflict
|
// if fall-through already exists in another block - check for conflict
|
||||||
// and terminate terminate block
|
// and terminate terminate block
|
||||||
if (!block.isEmpty() && instructionSet != null &&
|
if (!block.isEmpty() && instructionSet != null &&
|
||||||
@ -960,13 +971,14 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||||||
InstructionPrototype existingProto = existingBlockStartInstr.getPrototype();
|
InstructionPrototype existingProto = existingBlockStartInstr.getPrototype();
|
||||||
if (!existingProto.equals(prototype)) {
|
if (!existingProto.equals(prototype)) {
|
||||||
|
|
||||||
PseudoInstruction badInst = getPseudoInstruction(addr, prototype,
|
PseudoInstruction badInst = getPseudoInstruction(instrMemBuffer,
|
||||||
instrMemBuffer, contextValue, block);
|
prototype, contextValue, block);
|
||||||
InstructionError.dumpInstructionDifference(badInst,
|
InstructionError.dumpInstructionDifference(badInst,
|
||||||
existingBlockStartInstr);
|
existingBlockStartInstr);
|
||||||
|
|
||||||
block.setInconsistentPrototypeConflict(addr, flowFrom);
|
block.setInconsistentPrototypeConflict(addr, flowFrom);
|
||||||
}
|
}
|
||||||
|
blockTerminated(block);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// existing block must be an empty conflicted block - just keep going
|
// existing block must be an empty conflicted block - just keep going
|
||||||
@ -990,16 +1002,18 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||||||
disassemblerQueue
|
disassemblerQueue
|
||||||
.queueDelaySlotFallthrough(existingBlockStartInstr);
|
.queueDelaySlotFallthrough(existingBlockStartInstr);
|
||||||
}
|
}
|
||||||
|
blockTerminated(block);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (existingProto.equals(prototype)) {
|
else if (existingProto.equals(prototype)) {
|
||||||
// skip block start silently if it was previously disassembled
|
// skip block start silently if it was previously disassembled
|
||||||
|
blockTerminated(block);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PseudoInstruction badInst = getPseudoInstruction(addr, prototype,
|
PseudoInstruction badInst =
|
||||||
instrMemBuffer, contextValue, block);
|
getPseudoInstruction(instrMemBuffer, prototype, contextValue, block);
|
||||||
InstructionError.dumpInstructionDifference(badInst,
|
InstructionError.dumpInstructionDifference(badInst,
|
||||||
existingBlockStartInstr);
|
existingBlockStartInstr);
|
||||||
|
|
||||||
@ -1008,7 +1022,7 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PseudoInstruction inst =
|
PseudoInstruction inst =
|
||||||
getPseudoInstruction(addr, prototype, instrMemBuffer, contextValue, block);
|
getPseudoInstruction(instrMemBuffer, prototype, contextValue, block);
|
||||||
|
|
||||||
Address maxAddr = inst.getMaxAddress();
|
Address maxAddr = inst.getMaxAddress();
|
||||||
if (instructionSet != null && instructionSet.intersects(addr, maxAddr)) {
|
if (instructionSet != null && instructionSet.intersects(addr, maxAddr)) {
|
||||||
@ -1038,15 +1052,15 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!existingProto.equals(prototype)) {
|
if (!existingProto.equals(prototype)) {
|
||||||
|
PseudoInstruction badInst = getPseudoInstruction(instrMemBuffer,
|
||||||
PseudoInstruction badInst = getPseudoInstruction(addr, prototype,
|
prototype, contextValue, block);
|
||||||
instrMemBuffer, contextValue, block);
|
|
||||||
InstructionError.dumpInstructionDifference(badInst,
|
InstructionError.dumpInstructionDifference(badInst,
|
||||||
existingBlockStartInstr);
|
existingBlockStartInstr);
|
||||||
|
|
||||||
block.setInconsistentPrototypeConflict(addr, flowFrom);
|
block.setInconsistentPrototypeConflict(addr, flowFrom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
blockTerminated(block);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1059,6 +1073,7 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||||||
addr = processInstruction(inst, blockMemBuffer, block, instructionSet);
|
addr = processInstruction(inst, blockMemBuffer, block, instructionSet);
|
||||||
|
|
||||||
if (addr == null || block.hasInstructionError()) {
|
if (addr == null || block.hasInstructionError()) {
|
||||||
|
blockTerminated(block);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (endBlockEarly(inst, addr, limit, block) || endBlockOnCall(inst, addr, block)) {
|
if (endBlockEarly(inst, addr, limit, block) || endBlockOnCall(inst, addr, block)) {
|
||||||
@ -1067,6 +1082,7 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||||||
// are added to facilitate future prioritization of flows
|
// are added to facilitate future prioritization of flows
|
||||||
// block.setFallThrough(addr);
|
// block.setFallThrough(addr);
|
||||||
disassemblerContext.copyToFutureFlowState(addr);
|
disassemblerContext.copyToFutureFlowState(addr);
|
||||||
|
blockTerminated(block);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1076,17 +1092,45 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||||||
catch (AddressOutOfBoundsException | AddressOverflowException e) {
|
catch (AddressOutOfBoundsException | AddressOverflowException e) {
|
||||||
block.setInstructionMemoryError(addr, flowFrom,
|
block.setInstructionMemoryError(addr, flowFrom,
|
||||||
"Instruction does not fit within address space constraint");
|
"Instruction does not fit within address space constraint");
|
||||||
|
blockTerminated(block);
|
||||||
}
|
}
|
||||||
catch (InsufficientBytesException e) {
|
catch (InsufficientBytesException e) {
|
||||||
block.setInstructionMemoryError(addr, flowFrom, e.getMessage());
|
block.setInstructionMemoryError(addr, flowFrom, e.getMessage());
|
||||||
|
blockTerminated(block);
|
||||||
}
|
}
|
||||||
catch (UnknownInstructionException e) {
|
catch (UnknownInstructionException e) {
|
||||||
block.setParseConflict(addr,
|
block.setParseConflict(addr,
|
||||||
disassemblerContext.getRegisterValue(disassemblerContext.getBaseContextRegister()),
|
disassemblerContext.getRegisterValue(disassemblerContext.getBaseContextRegister()),
|
||||||
flowFrom, e.getMessage());
|
flowFrom, e.getMessage());
|
||||||
|
blockTerminated(block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signal that block disassembly has been terminated. An error condition may
|
||||||
|
* have been recorded within the block (see {@link InstructionBlock#hasInstructionError()}
|
||||||
|
* or block terminated early due to a matching instruction within the active instruction
|
||||||
|
* set had already been disassembled.
|
||||||
|
* @param block instruction block
|
||||||
|
*/
|
||||||
|
protected void blockTerminated(InstructionBlock block) {
|
||||||
|
// do nothing - intended for use by extension to cleanup state
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform parse of instruction bytes and context to produce an instruction prototype.
|
||||||
|
* @param instrMemBuffer memory buffer
|
||||||
|
* @param block fallthrough sequence of instructions preceeding current instruction
|
||||||
|
* required to facilitate potential crossbuilds for current instruction.
|
||||||
|
* @return instruction prototype
|
||||||
|
* @throws InsufficientBytesException
|
||||||
|
* @throws UnknownInstructionException
|
||||||
|
*/
|
||||||
|
protected InstructionPrototype parseInstructionPrototype(MemBuffer instrMemBuffer,
|
||||||
|
InstructionBlock block) throws InsufficientBytesException, UnknownInstructionException {
|
||||||
|
return language.parse(instrMemBuffer, disassemblerContext, false);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean endBlockEarly(Instruction inst, Address fallThruAddr, int limit,
|
private boolean endBlockEarly(Instruction inst, Address fallThruAddr, int limit,
|
||||||
InstructionBlock block) {
|
InstructionBlock block) {
|
||||||
if (fallThruAddr == null) {
|
if (fallThruAddr == null) {
|
||||||
@ -1131,34 +1175,51 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private PseudoInstruction getPseudoInstruction(MemBuffer memBuffer,
|
||||||
* Adjust disassembler context prior to disassembly of a new instruction.
|
InstructionPrototype prototype, RegisterValue contextValue, InstructionBlock block)
|
||||||
* @param instrMemBuffer buffer for bytes from memory
|
|
||||||
* @throws UnknownInstructionException if instruction is invalid
|
|
||||||
*/
|
|
||||||
protected void adjustPreParseContext(MemBuffer instrMemBuffer)
|
|
||||||
throws UnknownInstructionException {
|
|
||||||
// nothing to do - method provided for disassembler extensions
|
|
||||||
}
|
|
||||||
|
|
||||||
protected PseudoInstruction getPseudoInstruction(Address addr, InstructionPrototype prototype,
|
|
||||||
MemBuffer memBuffer, RegisterValue contextValue, InstructionBlock block)
|
|
||||||
throws AddressOverflowException {
|
throws AddressOverflowException {
|
||||||
|
|
||||||
|
Address addr = memBuffer.getAddress();
|
||||||
|
ProcessorContext processorContext =
|
||||||
|
getProcessorContext(addr, prototype.getLength(), contextValue);
|
||||||
|
|
||||||
PseudoInstruction instr;
|
PseudoInstruction instr;
|
||||||
if (program != null) {
|
if (program != null) {
|
||||||
instr = new PseudoInstruction(program, addr, prototype, memBuffer,
|
instr = new PseudoInstruction(program, addr, prototype, memBuffer, processorContext);
|
||||||
disassemblerProgramContext.getInstructionContext(contextValue, addr,
|
|
||||||
prototype.getLength()));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
instr = new PseudoInstruction(addrFactory, addr, prototype, memBuffer,
|
instr =
|
||||||
disassemblerProgramContext.getInstructionContext(contextValue, addr,
|
new PseudoInstruction(addrFactory, addr, prototype, memBuffer, processorContext);
|
||||||
prototype.getLength()));
|
|
||||||
}
|
}
|
||||||
instr.setInstructionBlock(block);
|
instr.setInstructionBlock(block);
|
||||||
return instr;
|
return instr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the processor context for the current instruction being disassembled as reflected by
|
||||||
|
* the {@link #disassemblerContext}. This is intended to be used in forming a
|
||||||
|
* {@link PseudoInstruction} or exercising certain methods on an {@link InstructionPrototype}.
|
||||||
|
*
|
||||||
|
* @param addr current instruction address
|
||||||
|
* @param instrLength instruction byte length
|
||||||
|
* @param contextValue instruction context register value
|
||||||
|
* @return processor context
|
||||||
|
*/
|
||||||
|
protected ProcessorContext getProcessorContext(Address addr, int instrLength,
|
||||||
|
RegisterValue contextValue) {
|
||||||
|
return disassemblerProgramContext.getInstructionContext(contextValue, addr, instrLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if {@link InstructionBlock} termination is allowed after the specified instruction
|
||||||
|
* has been added. Based upon the crossbuild requirements / parallel instruction semantics,
|
||||||
|
* this method may return false to force continued fallthrough instruction accumulation within
|
||||||
|
* the current block.
|
||||||
|
*
|
||||||
|
* @param instr last instruction disassembled
|
||||||
|
* @return true if current block with last instruction may be terminated, false if block
|
||||||
|
* must continue fallthrough instruction accumulation.
|
||||||
|
*/
|
||||||
protected boolean isBlockTerminationOK(Instruction instr) {
|
protected boolean isBlockTerminationOK(Instruction instr) {
|
||||||
return parallelHelper == null || parallelHelper.isEndOfParallelInstructionGroup(instr);
|
return parallelHelper == null || parallelHelper.isEndOfParallelInstructionGroup(instr);
|
||||||
}
|
}
|
||||||
@ -1167,6 +1228,7 @@ 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 instruction to process
|
* @param inst instruction to process
|
||||||
* @param blockMemBuffer buffer to get bytes
|
* @param blockMemBuffer buffer to get bytes
|
||||||
* @param block current block of instructions
|
* @param block current block of instructions
|
||||||
@ -1317,7 +1379,7 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PseudoInstruction dsInstr =
|
PseudoInstruction dsInstr =
|
||||||
getPseudoInstruction(addr, prototype, dsInstrMemBuffer, contextValue, block);
|
getPseudoInstruction(dsInstrMemBuffer, prototype, contextValue, block);
|
||||||
|
|
||||||
if (repeatInstructionByteTracker.exceedsRepeatBytePattern(dsInstr)) {
|
if (repeatInstructionByteTracker.exceedsRepeatBytePattern(dsInstr)) {
|
||||||
block.setParseConflict(addr, contextValue, instAddr,
|
block.setParseConflict(addr, contextValue, instAddr,
|
||||||
@ -1389,11 +1451,13 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||||||
RegisterValue contextValue = conflict.getParseContextValue();
|
RegisterValue contextValue = conflict.getParseContextValue();
|
||||||
if (contextValue != null) {
|
if (contextValue != null) {
|
||||||
try {
|
try {
|
||||||
RegisterValue curContextValue = program.getProgramContext().getRegisterValue(contextValue.getRegister(), address);
|
RegisterValue curContextValue = program.getProgramContext()
|
||||||
|
.getRegisterValue(contextValue.getRegister(), address);
|
||||||
|
|
||||||
// only store if different than what is already there, which could be a default value
|
// only store if different than what is already there, which could be a default value
|
||||||
if (!contextValue.equals(curContextValue)) {
|
if (!contextValue.equals(curContextValue)) {
|
||||||
program.getProgramContext().setRegisterValue(address, address, contextValue);
|
program.getProgramContext()
|
||||||
|
.setRegisterValue(address, address, contextValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ContextChangeException e) {
|
catch (ContextChangeException e) {
|
||||||
@ -1554,7 +1618,7 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||||||
* @param instrLength length of instruction to set context
|
* @param instrLength length of instruction to set context
|
||||||
* @return instruction context with possible added value
|
* @return instruction context with possible added value
|
||||||
*/
|
*/
|
||||||
ProcessorContext getInstructionContext(RegisterValue value, Address instrAddr,
|
protected ProcessorContext getInstructionContext(RegisterValue value, Address instrAddr,
|
||||||
int instrLength) {
|
int instrLength) {
|
||||||
|
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
|
Loading…
Reference in New Issue
Block a user