mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GP-3256 Added support for Instruction length-override
This commit is contained in:
parent
a820a36e94
commit
aefb7f2aed
67 changed files with 1895 additions and 574 deletions
|
@ -182,7 +182,8 @@ public abstract class PcodeEmit {
|
|||
*/
|
||||
void resolveFinalFallthrough() throws IOException {
|
||||
try {
|
||||
if (fallOverride == null || fallOverride.equals(getStartAddress().add(fallOffset))) {
|
||||
if (fallOverride == null) {
|
||||
// handles both length-override and fallthrough override cases
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -505,19 +505,6 @@ abstract class PseudoCodeUnit implements CodeUnit {
|
|||
return program.getListing().getCodeUnitBefore(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given CodeUnit follows directly after this code unit.
|
||||
*
|
||||
* @throws ConcurrentModificationException
|
||||
* if this object is no longer valid.
|
||||
*/
|
||||
@Override
|
||||
public boolean isSuccessor(CodeUnit codeUnit) {
|
||||
Address min = codeUnit.getMinAddress();
|
||||
|
||||
return this.getMaxAddress().isSuccessor(min);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComment(int commentType) {
|
||||
return comments.get(commentType);
|
||||
|
|
|
@ -146,6 +146,18 @@ public class PseudoInstruction extends PseudoCodeUnit implements Instruction, In
|
|||
return b0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getParsedLength() {
|
||||
// length-override is not supported
|
||||
return getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getParsedBytes() throws MemoryAccessException {
|
||||
// length-override is not supported
|
||||
return getBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Register getBaseContextRegister() {
|
||||
return procContext.getBaseContextRegister();
|
||||
|
@ -505,6 +517,16 @@ public class PseudoInstruction extends PseudoCodeUnit implements Instruction, In
|
|||
this.flowOverride = flowOverride != null ? flowOverride : FlowOverride.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLengthOverride(int length) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLengthOverridden() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFallThroughOverridden() {
|
||||
return fallThroughOverride != null;
|
||||
|
|
|
@ -22,7 +22,8 @@ import ghidra.program.database.function.OverlappingFunctionException;
|
|||
import ghidra.program.database.module.TreeManager;
|
||||
import ghidra.program.database.symbol.FunctionSymbol;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
|
@ -107,7 +108,7 @@ class ListingDB implements Listing {
|
|||
|
||||
@Override
|
||||
public Instruction getInstructionContaining(Address addr) {
|
||||
return codeMgr.getInstructionContaining(addr);
|
||||
return codeMgr.getInstructionContaining(addr, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -261,14 +262,15 @@ class ListingDB implements Listing {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PropertyMap getPropertyMap(String propertyName) {
|
||||
public PropertyMap<?> getPropertyMap(String propertyName) {
|
||||
return codeMgr.getPropertyMap(propertyName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instruction createInstruction(Address addr, InstructionPrototype prototype,
|
||||
MemBuffer memBuf, ProcessorContextView context) throws CodeUnitInsertionException {
|
||||
return codeMgr.createCodeUnit(addr, prototype, memBuf, context);
|
||||
MemBuffer memBuf, ProcessorContextView context, int length)
|
||||
throws CodeUnitInsertionException {
|
||||
return codeMgr.createCodeUnit(addr, prototype, memBuf, context, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -278,8 +280,7 @@ class ListingDB implements Listing {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Data createData(Address addr, DataType dataType)
|
||||
throws CodeUnitInsertionException {
|
||||
public Data createData(Address addr, DataType dataType) throws CodeUnitInsertionException {
|
||||
return codeMgr.createCodeUnit(addr, dataType, dataType.getLength());
|
||||
}
|
||||
|
||||
|
@ -292,8 +293,7 @@ class ListingDB implements Listing {
|
|||
@Override
|
||||
public void clearCodeUnits(Address startAddr, Address endAddr, boolean clearContext) {
|
||||
try {
|
||||
codeMgr.clearCodeUnits(startAddr, endAddr, clearContext,
|
||||
TaskMonitor.DUMMY);
|
||||
codeMgr.clearCodeUnits(startAddr, endAddr, clearContext, TaskMonitor.DUMMY);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// can't happen with dummy monitor
|
||||
|
|
|
@ -109,8 +109,10 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
* property map (StringTranslations).
|
||||
* 19-Jan-2023 - version 26 Improved relocation data records to incorporate status and
|
||||
* byte-length when original FileBytes should be used.
|
||||
* 10-Jul-2023 - VERSION 27 Add support for Instruction length override which utilizes
|
||||
* unused flag bits.
|
||||
*/
|
||||
static final int DB_VERSION = 26;
|
||||
static final int DB_VERSION = 27;
|
||||
|
||||
/**
|
||||
* UPGRADE_REQUIRED_BFORE_VERSION should be changed to DB_VERSION anytime the
|
||||
|
|
|
@ -155,11 +155,16 @@ public class CodeManager implements ErrorHandler, ManagerDB {
|
|||
while (addrIter.hasNext()) {
|
||||
monitor.checkCancelled();
|
||||
Address addr = addrIter.next();
|
||||
|
||||
Instruction instr = getInstructionAt(addr);
|
||||
if (instr == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
long offset = oldFallThroughs.getLong(addr);
|
||||
Address toAddr = addr.getNewAddress(offset);
|
||||
refMgr.addMemoryReference(addr, toAddr, RefType.FALL_THROUGH,
|
||||
SourceType.USER_DEFINED, Reference.MNEMONIC);
|
||||
instr.setFallThrough(toAddr);
|
||||
}
|
||||
catch (NoValueException e) {
|
||||
// skip
|
||||
|
@ -531,6 +536,16 @@ public class CodeManager implements ErrorHandler, ManagerDB {
|
|||
if (flowOverride != FlowOverride.NONE) {
|
||||
lastInstruction.setFlowOverride(flowOverride);
|
||||
}
|
||||
|
||||
try {
|
||||
if (protoInstr.isLengthOverridden()) {
|
||||
lastInstruction.setLengthOverride(protoInstr.getLength());
|
||||
}
|
||||
}
|
||||
catch (CodeUnitInsertionException e) {
|
||||
// unexpected - should have been caught previously
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (errorAddr != null && conflictCodeUnit == null &&
|
||||
|
@ -581,21 +596,34 @@ public class CodeManager implements ErrorHandler, ManagerDB {
|
|||
* @param prototype instruction definition object
|
||||
* @param memBuf the MemBuffer to use to get the bytes from memory
|
||||
* @param context object that has the state of all the registers.
|
||||
* @return the new instruction
|
||||
* @exception CodeUnitInsertionException thrown if code unit
|
||||
* overlaps with an existing code unit
|
||||
* @param length instruction byte-length (must be in the range 0..prototype.getLength()).
|
||||
* If smaller than the prototype length it must have a value no greater than 7, otherwise
|
||||
* an error will be thrown. A value of 0 or greater-than-or-equal the prototype length
|
||||
* will be ignored and not impose and override length. The length value must be a multiple
|
||||
* of the {@link Language#getInstructionAlignment() instruction alignment} .
|
||||
* @return the newly created instruction.
|
||||
* @throws CodeUnitInsertionException thrown if the new Instruction would overlap and
|
||||
* existing {@link CodeUnit} or the specified {@code length} is unsupported.
|
||||
* @throws IllegalArgumentException if a negative {@code length} is specified.
|
||||
*/
|
||||
public Instruction createCodeUnit(Address address, InstructionPrototype prototype,
|
||||
MemBuffer memBuf, ProcessorContextView context) throws CodeUnitInsertionException {
|
||||
MemBuffer memBuf, ProcessorContextView context, int length)
|
||||
throws CodeUnitInsertionException {
|
||||
|
||||
lock.acquire();
|
||||
creatingInstruction = true;
|
||||
try {
|
||||
Address endAddr = address.addNoWrap(prototype.getLength() - 1);
|
||||
|
||||
int forcedLengthOverride = InstructionDB.checkLengthOverride(length, prototype);
|
||||
if (length == 0) {
|
||||
length = prototype.getLength();
|
||||
}
|
||||
Address endAddr = address.addNoWrap(length - 1);
|
||||
checkValidAddressRange(address, endAddr);
|
||||
|
||||
InstructionDB inst = addInstruction(address, endAddr, prototype, memBuf, context);
|
||||
if (forcedLengthOverride != 0) {
|
||||
inst.doSetLengthOverride(forcedLengthOverride);
|
||||
}
|
||||
|
||||
// fire event
|
||||
program.setChanged(ChangeManager.DOCR_CODE_ADDED, address, endAddr, null, inst);
|
||||
|
@ -1370,29 +1398,48 @@ public class CodeManager implements ErrorHandler, ManagerDB {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the instruction whose min address is less than or equal to the specified address and
|
||||
* Returns an instruction whose min address is less than or equal to the specified address and
|
||||
* whose max address is greater than or equal to the specified address.
|
||||
* If {@code usePrototypeLength==true}
|
||||
* <pre>{@literal
|
||||
* instruction.minAddress() <= addr <= instruction.maxAddress()
|
||||
* instruction.getMinAddress() <= addr <=
|
||||
* instruction.getMinAddress().add(instruction.getPrototype().getLength() - 1)
|
||||
* }</pre>
|
||||
*
|
||||
* If {@code usePrototypeLength==false}
|
||||
* <pre>{@literal
|
||||
* instruction.getMinAddress() <= addr <= instruction.getMaxAddress()
|
||||
* }</pre>
|
||||
* The use of the prototype length is required when guarding against memory modifications. If
|
||||
* a length-override is present only one of the entangled instructions will be returned and is
|
||||
* intended to simply indicate the presence of a conflict.
|
||||
* @param address the address to be contained
|
||||
* @param usePrototypeLength if actual prototype length should be considered when identifying a
|
||||
* conflict (required when checking for memory modification conflicts), otherwise code unit
|
||||
* length is used. These lengths can vary when a
|
||||
* {@link Instruction#setLengthOverride(int) length-override} is in affect for an instruction.
|
||||
* @return the instruction containing the specified address, or null if a
|
||||
* instruction does not exist
|
||||
*/
|
||||
public Instruction getInstructionContaining(Address address) {
|
||||
public Instruction getInstructionContaining(Address address, boolean usePrototypeLength) {
|
||||
lock.acquire();
|
||||
try {
|
||||
Instruction instr = getInstructionAt(address);
|
||||
|
||||
if (instr != null) {
|
||||
return instr;
|
||||
}
|
||||
|
||||
instr = this.getInstructionBefore(address);
|
||||
|
||||
if (instr != null && instr.contains(address)) {
|
||||
return instr;
|
||||
if (instr != null) {
|
||||
Address endAddr;
|
||||
if (usePrototypeLength && instr.isLengthOverridden()) {
|
||||
endAddr = instr.getMinAddress().add(instr.getParsedLength() - 1);
|
||||
}
|
||||
else {
|
||||
endAddr = instr.getMaxAddress();
|
||||
}
|
||||
if (address.compareTo(endAddr) <= 0) {
|
||||
return instr;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -1639,8 +1686,14 @@ public class CodeManager implements ErrorHandler, ManagerDB {
|
|||
nextInstEndAddr = nextInstAddr;
|
||||
int protoID = nextInstRec.getIntValue(InstDBAdapter.PROTO_ID_COL);
|
||||
InstructionPrototype proto = protoMgr.getPrototype(protoID);
|
||||
int len = proto != null ? proto.getLength()
|
||||
: nextInstAddr.getAddressSpace().getAddressableUnitSize();
|
||||
int len;
|
||||
if (proto != null) {
|
||||
len = InstructionDB.getLength(proto,
|
||||
nextInstRec.getByteValue(InstDBAdapter.FLAGS_COL));
|
||||
}
|
||||
else {
|
||||
len = nextInstAddr.getAddressSpace().getAddressableUnitSize();
|
||||
}
|
||||
if (len > 1) {
|
||||
try {
|
||||
nextInstEndAddr = nextInstAddr.addNoWrap(len - 1);
|
||||
|
@ -1730,7 +1783,7 @@ public class CodeManager implements ErrorHandler, ManagerDB {
|
|||
if (addr != AddressMap.INVALID_ADDRESS_KEY) {
|
||||
lock.acquire();
|
||||
try {
|
||||
Instruction inst = getInstructionContaining(address);
|
||||
Instruction inst = getInstructionContaining(address, false);
|
||||
if (inst != null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -2538,7 +2591,7 @@ public class CodeManager implements ErrorHandler, ManagerDB {
|
|||
return;
|
||||
}
|
||||
boolean fail = false;
|
||||
if (getInstructionContaining(start) != null) {
|
||||
if (getInstructionContaining(start, false) != null) {
|
||||
fail = true;
|
||||
}
|
||||
else {
|
||||
|
@ -2574,7 +2627,7 @@ public class CodeManager implements ErrorHandler, ManagerDB {
|
|||
if (!program.getMemory().contains(start, end)) {
|
||||
return false;
|
||||
}
|
||||
if (getInstructionContaining(start) != null) {
|
||||
if (getInstructionContaining(start, false) != null) {
|
||||
return false;
|
||||
}
|
||||
if (getDefinedDataContaining(start) != null) {
|
||||
|
@ -3168,13 +3221,21 @@ public class CodeManager implements ErrorHandler, ManagerDB {
|
|||
* @param newFallThroughRef new fallthrough reference or null if removed
|
||||
*/
|
||||
public void fallThroughChanged(Address fromAddr, Reference newFallThroughRef) {
|
||||
if (newFallThroughRef != null &&
|
||||
newFallThroughRef.getReferenceType() != RefType.FALL_THROUGH) {
|
||||
throw new IllegalArgumentException("invalid reftype");
|
||||
}
|
||||
lock.acquire();
|
||||
try {
|
||||
InstructionDB instr = getInstructionAt(addrMap.getKey(fromAddr, false));
|
||||
// TODO: Should prevent this if instruction is null or isInDelaySlot
|
||||
if (instr != null) {
|
||||
instr.fallThroughChanged(newFallThroughRef);
|
||||
if (instr == null) {
|
||||
// Do not allow fallthrough ref without instruction
|
||||
if (newFallThroughRef != null) {
|
||||
refManager.delete(newFallThroughRef);
|
||||
}
|
||||
return;
|
||||
}
|
||||
instr.fallThroughChanged(newFallThroughRef);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.commons.lang3.StringUtils;
|
|||
|
||||
import db.DBRecord;
|
||||
import ghidra.program.database.*;
|
||||
import ghidra.program.database.references.ReferenceDBManager;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressOutOfBoundsException;
|
||||
import ghidra.program.model.lang.*;
|
||||
|
@ -48,7 +49,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
|||
protected long addr;
|
||||
protected Address endAddr;
|
||||
protected int length;
|
||||
protected ReferenceManager refMgr;
|
||||
protected ReferenceDBManager refMgr;
|
||||
protected ProgramDB program;
|
||||
|
||||
private DBRecord commentRec;
|
||||
|
@ -407,13 +408,6 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuccessor(CodeUnit codeUnit) {
|
||||
Address min = codeUnit.getMinAddress();
|
||||
|
||||
return this.getMaxAddress().isSuccessor(min);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<String> propertyNames() {
|
||||
PropertyMapManager upm = codeMgr.getPropertyMapManager();
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package ghidra.program.database.code;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import db.DBRecord;
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
|
@ -29,6 +28,7 @@ import ghidra.program.model.mem.MemoryAccessException;
|
|||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.program.util.ChangeManager;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.NoValueException;
|
||||
|
@ -38,16 +38,21 @@ import ghidra.util.exception.NoValueException;
|
|||
*/
|
||||
public class InstructionDB extends CodeUnitDB implements Instruction, InstructionContext {
|
||||
|
||||
private static byte FALLTHROUGH_SET_MASK = (byte) 0x01;
|
||||
private static byte FALLTHROUGH_CLEAR_MASK = (byte) 0xfe;
|
||||
private static final byte FALLTHROUGH_SET_MASK = 0x01;
|
||||
private static final byte FALLTHROUGH_CLEAR_MASK = ~FALLTHROUGH_SET_MASK;
|
||||
|
||||
private static byte FLOWOVERRIDE_MASK = (byte) 0x0e;
|
||||
private static byte FLOWOVERRIDE_CLEAR_MASK = (byte) 0xf1;
|
||||
private static int FLOWOVERRIDE_SHIFT = 1;
|
||||
private static final byte FLOW_OVERRIDE_SET_MASK = 0x0e;
|
||||
private static final byte FLOW_OVERRIDE_CLEAR_MASK = ~FLOW_OVERRIDE_SET_MASK;
|
||||
private static final int FLOW_OVERRIDE_SHIFT = 1;
|
||||
|
||||
private static final byte LENGTH_OVERRIDE_SET_MASK = 0x70;
|
||||
private static final byte LENGTH_OVERRIDE_CLEAR_MASK = ~LENGTH_OVERRIDE_SET_MASK;
|
||||
private static final int LENGTH_OVERRIDE_SHIFT = 4;
|
||||
|
||||
private InstructionPrototype proto;
|
||||
private byte flags;
|
||||
private FlowOverride flowOverride;
|
||||
private int lengthOverride;
|
||||
private final static Address[] EMPTY_ADDR_ARRAY = new Address[0];
|
||||
private volatile boolean clearingFallThroughs = false;
|
||||
|
||||
|
@ -68,7 +73,8 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
|||
this.proto = proto;
|
||||
this.flags = flags;
|
||||
flowOverride =
|
||||
FlowOverride.getFlowOverride((flags & FLOWOVERRIDE_MASK) >> FLOWOVERRIDE_SHIFT);
|
||||
FlowOverride.getFlowOverride((flags & FLOW_OVERRIDE_SET_MASK) >> FLOW_OVERRIDE_SHIFT);
|
||||
refreshLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -83,6 +89,36 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
|||
return proto.hasDelaySlots() ? (length * 2) : length;
|
||||
}
|
||||
|
||||
private void refreshLength() {
|
||||
length = proto.getLength();
|
||||
lengthOverride = (flags & LENGTH_OVERRIDE_SET_MASK) >> LENGTH_OVERRIDE_SHIFT;
|
||||
if (lengthOverride != 0 && lengthOverride < length) {
|
||||
length = lengthOverride;
|
||||
}
|
||||
else {
|
||||
lengthOverride = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the instruction code unit length based upon its prototype and flags
|
||||
* which will be used to check for a length-override condition.
|
||||
* @param proto instruction prototype
|
||||
* @param flags instruction flags
|
||||
* @return instruction code unit length
|
||||
*/
|
||||
static int getLength(InstructionPrototype proto, byte flags) {
|
||||
int length = proto.getLength();
|
||||
int lengthOverride = (flags & LENGTH_OVERRIDE_SET_MASK) >> LENGTH_OVERRIDE_SHIFT;
|
||||
if (lengthOverride != 0 && lengthOverride < length) {
|
||||
length = lengthOverride;
|
||||
}
|
||||
else {
|
||||
lengthOverride = 0;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasBeenDeleted(DBRecord rec) {
|
||||
if (rec == null) {
|
||||
|
@ -106,10 +142,11 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
|||
if (!newProto.equals(proto)) {
|
||||
return true;
|
||||
}
|
||||
length = proto.getLength();
|
||||
|
||||
flags = rec.getByteValue(InstDBAdapter.FLAGS_COL);
|
||||
flowOverride =
|
||||
FlowOverride.getFlowOverride((flags & FLOWOVERRIDE_MASK) >> FLOWOVERRIDE_SHIFT);
|
||||
FlowOverride.getFlowOverride((flags & FLOW_OVERRIDE_SET_MASK) >> FLOW_OVERRIDE_SHIFT);
|
||||
refreshLength();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -142,6 +179,31 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getParsedLength() {
|
||||
return isLengthOverridden() ? proto.getLength() : getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getParsedBytes() throws MemoryAccessException {
|
||||
if (!isLengthOverridden()) {
|
||||
return getBytes();
|
||||
}
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
int len = proto.getLength();
|
||||
byte[] b = new byte[len];
|
||||
if (len != getMemory().getBytes(address, b)) {
|
||||
throw new MemoryAccessException("Failed to read " + len + " bytes at " + address);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getFallFrom() {
|
||||
lock.acquire();
|
||||
|
@ -192,19 +254,22 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
|||
}
|
||||
}
|
||||
|
||||
private Address getFallThroughReference() {
|
||||
for (Reference ref : refMgr.getReferencesFrom(address)) {
|
||||
if (ref.getReferenceType().isFallthrough() && ref.getToAddress().isMemoryAddress()) {
|
||||
return ref.getToAddress();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getFallThrough() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
if (isFallThroughOverridden()) {
|
||||
for (Reference ref : refMgr.getReferencesFrom(address)) {
|
||||
if (ref.getReferenceType().isFallthrough() &&
|
||||
ref.getToAddress().isMemoryAddress()) {
|
||||
return ref.getToAddress();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return getFallThroughReference();
|
||||
}
|
||||
return getDefaultFallThrough();
|
||||
}
|
||||
|
@ -221,7 +286,7 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
|||
return EMPTY_ADDR_ARRAY;
|
||||
}
|
||||
|
||||
ArrayList<Address> list = new ArrayList<>();
|
||||
Set<Address> list = new HashSet<>();
|
||||
for (Reference ref : refs) {
|
||||
if (!ref.getReferenceType().isIndirect()) {
|
||||
list.add(ref.getToAddress());
|
||||
|
@ -232,8 +297,7 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
|||
return EMPTY_ADDR_ARRAY;
|
||||
}
|
||||
|
||||
Address[] addrs = new Address[list.size()];
|
||||
return list.toArray(addrs);
|
||||
return list.toArray(new Address[list.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -537,8 +601,8 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
|||
}
|
||||
FlowType origFlowType = getFlowType();
|
||||
|
||||
flags &= FLOWOVERRIDE_CLEAR_MASK;
|
||||
flags |= (flow.ordinal() << FLOWOVERRIDE_SHIFT);
|
||||
flags &= FLOW_OVERRIDE_CLEAR_MASK;
|
||||
flags |= (flow.ordinal() << FLOW_OVERRIDE_SHIFT);
|
||||
codeMgr.setFlags(addr, flags);
|
||||
flowOverride = flow;
|
||||
|
||||
|
@ -623,19 +687,25 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
|||
|
||||
/**
|
||||
* Clear all existing fall-through references from address.
|
||||
* @param keepFallThroughRef if not null, corresponding fall-through reference will be preserved
|
||||
* @param keepFallThroughAddr if not null, corresponding fall-through reference will be
|
||||
* preserved.
|
||||
*/
|
||||
private void clearFallThroughRefs(Reference keepFallThroughRef) {
|
||||
private void clearFallThroughRefs(Address keepFallThroughAddr) {
|
||||
if (clearingFallThroughs) {
|
||||
return;
|
||||
}
|
||||
refreshIfNeeded();
|
||||
clearingFallThroughs = true;
|
||||
try {
|
||||
boolean fallThroughPreserved = false;
|
||||
for (Reference ref : refMgr.getReferencesFrom(address)) {
|
||||
if (ref.getReferenceType() == RefType.FALL_THROUGH &&
|
||||
!ref.equals(keepFallThroughRef)) {
|
||||
refMgr.delete(ref);
|
||||
if (ref.getReferenceType() == RefType.FALL_THROUGH) {
|
||||
if (!fallThroughPreserved && ref.getToAddress().equals(keepFallThroughAddr)) {
|
||||
fallThroughPreserved = true; // only preserve one
|
||||
}
|
||||
else {
|
||||
refMgr.delete(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -646,9 +716,16 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
|||
|
||||
void fallThroughChanged(Reference fallThroughRef) {
|
||||
if (!clearingFallThroughs) {
|
||||
clearFallThroughRefs(fallThroughRef);
|
||||
setFallthroughOverride(fallThroughRef != null &&
|
||||
fallThroughRef.getReferenceType() == RefType.FALL_THROUGH);
|
||||
Address fallThroughAddr = fallThroughRef != null ? fallThroughRef.getToAddress() : null;
|
||||
clearFallThroughRefs(fallThroughAddr); // ensure there is only one fallthrough ref
|
||||
if (fallThroughAddr == null) { // fallthrough ref removed
|
||||
setFallthroughOverride(false);
|
||||
addLengthOverrideFallthroughRef(); // restore length-override fallthrough if needed
|
||||
}
|
||||
else {
|
||||
// enable fallthrough-override if fallThroughRef does not match length-override fallthrough
|
||||
setFallthroughOverride(!fallThroughAddr.equals(getLengthOverrideFallThrough()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -661,8 +738,9 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
|||
flags &= FALLTHROUGH_CLEAR_MASK;
|
||||
}
|
||||
codeMgr.setFlags(addr, flags);
|
||||
program.setChanged(ChangeManager.DOCR_FALLTHROUGH_CHANGED, address, address, null,
|
||||
null);
|
||||
}
|
||||
program.setChanged(ChangeManager.DOCR_FALLTHROUGH_CHANGED, address, address, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -673,8 +751,10 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
|||
if (!isFallThroughOverridden()) {
|
||||
return;
|
||||
}
|
||||
// clear fall-through override
|
||||
clearFallThroughRefs(null);
|
||||
setFallthroughOverride(false);
|
||||
addLengthOverrideFallthroughRef(); // restore length-override fallthrough if needed
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
@ -693,11 +773,12 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
|||
return;
|
||||
}
|
||||
if (fallThroughAddr == null) {
|
||||
// Fall-through eliminated - no reference added
|
||||
// Fall-through eliminated (i.e., terminal flow) - no reference added
|
||||
clearFallThroughRefs(null);
|
||||
setFallthroughOverride(true);
|
||||
}
|
||||
else {
|
||||
// Adding fallthough ref will trigger override flag on callback
|
||||
refMgr.addMemoryReference(address, fallThroughAddr, RefType.FALL_THROUGH,
|
||||
SourceType.USER_DEFINED, Reference.MNEMONIC);
|
||||
}
|
||||
|
@ -705,7 +786,107 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
|||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLengthOverride(int len) throws CodeUnitInsertionException {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
if (doSetLengthOverride(len)) {
|
||||
program.setChanged(ChangeManager.DOCR_LENGTH_OVERRIDE_CHANGED, address, address,
|
||||
null, null);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check and revise a specified {@code length} to arrive at a suitable length-override value.
|
||||
* @param length instruction byte-length (must be in the range 0..{@code prototype-length}).
|
||||
* If smaller than the prototype length it must have a value no greater than 7, otherwise
|
||||
* an error will be thrown. A value of 0 or greater-than-or-equal the prototype length
|
||||
* will be ignored and not impose and override length. The length value must be a multiple
|
||||
* of the {@link Language#getInstructionAlignment() instruction alignment} .
|
||||
* @param prototype instruction prototype
|
||||
* @return length-override value (0 = disable length-override)
|
||||
* @throws CodeUnitInsertionException thrown if the new Instruction would overlap and
|
||||
* existing {@link CodeUnit} or the specified {@code length} is unsupported.
|
||||
* @throws IllegalArgumentException if a negative {@code length} is specified.
|
||||
*/
|
||||
public static int checkLengthOverride(int length, InstructionPrototype prototype)
|
||||
throws IllegalArgumentException, CodeUnitInsertionException {
|
||||
if (length < 0) {
|
||||
throw new IllegalArgumentException("Negative length not permitted");
|
||||
}
|
||||
int instrProtoLength = prototype.getLength();
|
||||
if (length == 0 || length == instrProtoLength) {
|
||||
return 0;
|
||||
}
|
||||
if (length > instrProtoLength) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int align = prototype.getLanguage().getInstructionAlignment();
|
||||
if (length % align != 0) {
|
||||
throw new CodeUnitInsertionException(
|
||||
"Length(" + length + ") override must be a multiple of " + align + " bytes");
|
||||
}
|
||||
|
||||
if (length > MAX_LENGTH_OVERRIDE) {
|
||||
throw new CodeUnitInsertionException("Unsupported length override: " + length);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
boolean doSetLengthOverride(int len) throws CodeUnitInsertionException {
|
||||
|
||||
int protoLength = proto.getLength();
|
||||
len = checkLengthOverride(len, proto);
|
||||
if (len == lengthOverride) {
|
||||
return false; // no change
|
||||
}
|
||||
|
||||
int instrLength = len != 0 ? len : protoLength;
|
||||
if (instrLength > getLength()) {
|
||||
Address newEndAddr = address.add(instrLength - 1);
|
||||
Address nextCodeUnitAddr = codeMgr.getDefinedAddressAfter(address);
|
||||
if (nextCodeUnitAddr != null && nextCodeUnitAddr.compareTo(newEndAddr) <= 0) {
|
||||
throw new CodeUnitInsertionException("Length override of " + instrLength +
|
||||
" conflicts with code unit at " + nextCodeUnitAddr);
|
||||
}
|
||||
}
|
||||
|
||||
flags &= LENGTH_OVERRIDE_CLEAR_MASK;
|
||||
flags |= (len << LENGTH_OVERRIDE_SHIFT);
|
||||
codeMgr.setFlags(addr, flags);
|
||||
|
||||
endAddr = null;
|
||||
refreshLength();
|
||||
|
||||
addLengthOverrideFallthroughRef();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void addLengthOverrideFallthroughRef() {
|
||||
if (isLengthOverridden() && !isFallThroughOverridden()) {
|
||||
// length-override always uses default fall-through address
|
||||
refMgr.addMemoryReference(address, getDefaultFallThrough(), RefType.FALL_THROUGH,
|
||||
SourceType.USER_DEFINED, Reference.MNEMONIC);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLengthOverridden() {
|
||||
refreshIfNeeded();
|
||||
return lengthOverride != 0;
|
||||
}
|
||||
|
||||
private Address getLengthOverrideFallThrough() {
|
||||
return isLengthOverridden() ? getDefaultFallThrough() : null;
|
||||
}
|
||||
|
||||
private boolean addrsEqual(Address addr1, Address addr2) {
|
||||
|
|
|
@ -18,6 +18,8 @@ package ghidra.program.database.external;
|
|||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import db.*;
|
||||
import ghidra.framework.store.FileSystem;
|
||||
import ghidra.program.database.ManagerDB;
|
||||
|
@ -90,8 +92,8 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
@Override
|
||||
public void setProgram(ProgramDB program) {
|
||||
this.program = program;
|
||||
symbolMgr = (SymbolManager) program.getSymbolTable();
|
||||
functionMgr = (FunctionManagerDB) program.getFunctionManager();
|
||||
symbolMgr = program.getSymbolTable();
|
||||
functionMgr = program.getFunctionManager();
|
||||
scopeMgr = program.getNamespaceManager();
|
||||
}
|
||||
|
||||
|
@ -153,8 +155,8 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
oldAddrMap.decodeAddress(rec.getLongValue(OldExtRefAdapter.FROM_ADDR_COL));
|
||||
int opIndex = rec.getShortValue(OldExtRefAdapter.OP_INDEX_COL);
|
||||
boolean userDefined = rec.getBooleanValue(OldExtRefAdapter.USER_DEFINED_COL);
|
||||
String name = nameMap.get(rec.getLongValue(OldExtRefAdapter.EXT_NAME_ID_COL));
|
||||
if (name == null) {
|
||||
String extLibraryName = nameMap.get(rec.getLongValue(OldExtRefAdapter.EXT_NAME_ID_COL));
|
||||
if (extLibraryName == null) {
|
||||
continue; // should not happen
|
||||
}
|
||||
String label = rec.getString(OldExtRefAdapter.LABEL_COL);
|
||||
|
@ -163,14 +165,11 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
: null;
|
||||
|
||||
try {
|
||||
refMgr.addExternalReference(fromAddr, name, label, addr,
|
||||
refMgr.addExternalReference(fromAddr, extLibraryName, label, addr,
|
||||
userDefined ? SourceType.USER_DEFINED : SourceType.IMPORTED, opIndex,
|
||||
RefType.DATA);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
catch (InvalidInputException | DuplicateNameException e) {
|
||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||
}
|
||||
monitor.setProgress(++cnt);
|
||||
|
@ -283,7 +282,8 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
|
||||
private SourceType checkExternalLabel(String extLabel, Address extAddr, SourceType source)
|
||||
throws InvalidInputException {
|
||||
if (extLabel == null || extLabel.length() == 0) {
|
||||
if (extLabel != null && (StringUtils.isBlank(extLabel) ||
|
||||
SymbolUtilities.isReservedExternalDefaultName(extLabel, addrMap.getAddressFactory()))) {
|
||||
extLabel = null;
|
||||
}
|
||||
if (extLabel == null && extAddr == null) {
|
||||
|
@ -312,8 +312,15 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
throw new InvalidInputException("The namespace must be an external namespace.");
|
||||
}
|
||||
sourceType = checkExternalLabel(extLabel, extAddr, sourceType);
|
||||
if (extAddr != null && !extAddr.isLoadedMemoryAddress()) {
|
||||
throw new InvalidInputException("Invalid memory address");
|
||||
if (extAddr != null) {
|
||||
if (!extAddr.isLoadedMemoryAddress()) {
|
||||
throw new InvalidInputException("Invalid memory address: " + extAddr);
|
||||
}
|
||||
AddressSpace space = extAddr.getAddressSpace();
|
||||
if (!space.equals(program.getAddressFactory().getAddressSpace(space.getName()))) {
|
||||
throw new InvalidInputException(
|
||||
"Memory address not defined for program: " + extAddr);
|
||||
}
|
||||
}
|
||||
lock.acquire();
|
||||
try {
|
||||
|
@ -359,7 +366,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
/**
|
||||
* Get the external location which best matches the specified parameters.
|
||||
* Preference is given to extLabel over extAddr
|
||||
* @param libScope, the library namespace containing this external location.
|
||||
* @param library the library namespace containing this external location.
|
||||
* @param extLabel the name of the external location. Can be null.
|
||||
* @param extAddr the address of function in the external program. Can be null
|
||||
* @return the best matching ExternalLocation or null.
|
||||
|
|
|
@ -2297,7 +2297,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
|
||||
void checkRangeForInstructions(Address start, Address end) throws MemoryAccessException {
|
||||
CodeManager codeManager = program.getCodeManager();
|
||||
Instruction instr = codeManager.getInstructionContaining(start);
|
||||
Instruction instr = codeManager.getInstructionContaining(start, true);
|
||||
if (instr != null) {
|
||||
throw new MemoryAccessException(
|
||||
"Memory change conflicts with instruction at " + instr.getMinAddress());
|
||||
|
|
|
@ -449,6 +449,9 @@ public class ReferenceDBManager implements ReferenceManager, ManagerDB, ErrorHan
|
|||
if (!fromAddr.isMemoryAddress()) {
|
||||
throw new IllegalArgumentException("From address must be memory address");
|
||||
}
|
||||
if (!type.isData()) {
|
||||
throw new IllegalArgumentException("Invalid stack reference type: " + type);
|
||||
}
|
||||
Function function = program.getFunctionManager().getFunctionContaining(fromAddr);
|
||||
if (function == null) {
|
||||
throw new IllegalArgumentException(
|
||||
|
@ -488,6 +491,9 @@ public class ReferenceDBManager implements ReferenceManager, ManagerDB, ErrorHan
|
|||
if (!fromAddr.isMemoryAddress()) {
|
||||
throw new IllegalArgumentException("From address must be memory address");
|
||||
}
|
||||
if (!type.isData()) {
|
||||
throw new IllegalArgumentException("Invalid register reference type: " + type);
|
||||
}
|
||||
removeAllFrom(fromAddr, opIndex);
|
||||
try {
|
||||
return addRef(fromAddr, register.getAddress(), type, sourceType, opIndex, false, false,
|
||||
|
@ -573,9 +579,9 @@ public class ReferenceDBManager implements ReferenceManager, ManagerDB, ErrorHan
|
|||
if (!fromAddr.isMemoryAddress()) {
|
||||
throw new IllegalArgumentException("From address must be memory addresses");
|
||||
}
|
||||
removeAllFrom(fromAddr, opIndex);
|
||||
try {
|
||||
if (symbolMgr.getPrimarySymbol(location.getExternalSpaceAddress()) != null) {
|
||||
removeAllFrom(fromAddr, opIndex);
|
||||
return addRef(fromAddr, location.getExternalSpaceAddress(), type, sourceType,
|
||||
opIndex, false, false, 0);
|
||||
}
|
||||
|
@ -598,24 +604,17 @@ public class ReferenceDBManager implements ReferenceManager, ManagerDB, ErrorHan
|
|||
public Reference addExternalReference(Address fromAddr, String libraryName, String extLabel,
|
||||
Address extAddr, SourceType sourceType, int opIndex, RefType type)
|
||||
throws InvalidInputException, DuplicateNameException {
|
||||
if (libraryName == null || libraryName.length() == 0) {
|
||||
throw new InvalidInputException("A valid library name must be specified.");
|
||||
|
||||
if (!fromAddr.isMemoryAddress()) {
|
||||
throw new IllegalArgumentException("From addresses must be memory addresses");
|
||||
}
|
||||
if (extLabel != null && extLabel.length() == 0) {
|
||||
extLabel = null;
|
||||
}
|
||||
if (extLabel == null && extAddr == null) {
|
||||
throw new InvalidInputException("Either an external label or address is required");
|
||||
}
|
||||
if (!fromAddr.isMemoryAddress() || (extAddr != null && !extAddr.isMemoryAddress())) {
|
||||
throw new IllegalArgumentException(
|
||||
"From and extAddr addresses must be memory addresses");
|
||||
}
|
||||
removeAllFrom(fromAddr, opIndex);
|
||||
try {
|
||||
ExternalManagerDB extMgr = (ExternalManagerDB) program.getExternalManager();
|
||||
ExternalManagerDB extMgr = program.getExternalManager();
|
||||
ExternalLocation extLoc =
|
||||
extMgr.addExtLocation(libraryName, extLabel, extAddr, sourceType);
|
||||
|
||||
removeAllFrom(fromAddr, opIndex);
|
||||
|
||||
Address toAddr = extLoc.getExternalSpaceAddress();
|
||||
|
||||
return addRef(fromAddr, toAddr, type, sourceType, opIndex, false, false, 0);
|
||||
|
@ -630,24 +629,16 @@ public class ReferenceDBManager implements ReferenceManager, ManagerDB, ErrorHan
|
|||
public Reference addExternalReference(Address fromAddr, Namespace extNamespace, String extLabel,
|
||||
Address extAddr, SourceType sourceType, int opIndex, RefType type)
|
||||
throws InvalidInputException, DuplicateNameException {
|
||||
if (extNamespace == null || !extNamespace.isExternal()) {
|
||||
throw new InvalidInputException("The namespace must be an external namespace.");
|
||||
if (!fromAddr.isMemoryAddress()) {
|
||||
throw new IllegalArgumentException("From addresses must be memory addresses");
|
||||
}
|
||||
if (extLabel != null && extLabel.length() == 0) {
|
||||
extLabel = null;
|
||||
}
|
||||
if (extLabel == null && extAddr == null) {
|
||||
throw new InvalidInputException("Either an external label or address is required");
|
||||
}
|
||||
if (!fromAddr.isMemoryAddress() || (extAddr != null && !extAddr.isMemoryAddress())) {
|
||||
throw new IllegalArgumentException(
|
||||
"From and extAddr addresses must be memory addresses");
|
||||
}
|
||||
removeAllFrom(fromAddr, opIndex);
|
||||
try {
|
||||
ExternalManagerDB extMgr = (ExternalManagerDB) program.getExternalManager();
|
||||
ExternalManagerDB extMgr = program.getExternalManager();
|
||||
ExternalLocation extLoc =
|
||||
extMgr.addExtLocation(extNamespace, extLabel, extAddr, sourceType);
|
||||
|
||||
removeAllFrom(fromAddr, opIndex);
|
||||
|
||||
Address toAddr = extLoc.getExternalSpaceAddress();
|
||||
return addRef(fromAddr, toAddr, type, sourceType, opIndex, false, false, 0);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import ghidra.program.model.mem.MemoryAccessException;
|
|||
public class AllBytesHashCalculator implements HashCalculator {
|
||||
@Override
|
||||
public int calcHash(int startHash, Instruction inst) throws MemoryAccessException {
|
||||
byte[] bytes = inst.getBytes();
|
||||
byte[] bytes = inst.getParsedBytes();
|
||||
for(int i=0;i<bytes.length;++i) {
|
||||
startHash = SimpleCRC32.hashOneByte(startHash, bytes[i]);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ package ghidra.program.model.listing;
|
|||
import java.util.ConcurrentModificationException;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.InstructionPrototype;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
|
@ -175,19 +176,18 @@ public interface CodeUnit extends MemBuffer, PropertySet {
|
|||
public void setCommentAsArray(int commentType, String[] comment);
|
||||
|
||||
/**
|
||||
* Return true if the given CodeUnit follows
|
||||
* directly after this code unit.
|
||||
* @param codeUnit the codeUnit being tested to see if it follows this codeUnit.
|
||||
*/
|
||||
public boolean isSuccessor(CodeUnit codeUnit);
|
||||
|
||||
/**
|
||||
* Get length of this code unit.
|
||||
* Get length of this code unit.
|
||||
* NOTE: If an {@link Instruction#isLengthOverridden() instruction length-override} is
|
||||
* set this method will return the reduced length.
|
||||
* @return code unit length
|
||||
*/
|
||||
public int getLength();
|
||||
|
||||
/**
|
||||
* Get the bytes that make up this code unit.
|
||||
* NOTE: If an {@link Instruction#isLengthOverridden() instruction length-override} is
|
||||
* set this method will not return all bytes associated with the
|
||||
* {@link InstructionPrototype instruction prototype}.
|
||||
* @return an array of bytes that are in memory at the codeunits address. The
|
||||
* array length is the same as the codeUnits length
|
||||
* @throws MemoryAccessException if the full number of bytes could not be read.
|
||||
|
|
|
@ -149,11 +149,6 @@ public class DataStub implements Data {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuccessor(CodeUnit codeUnit) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -19,10 +19,12 @@ import java.util.List;
|
|||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.program.model.pcode.PcodeOverride;
|
||||
import ghidra.program.model.symbol.FlowType;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
|
||||
/**
|
||||
* Interface to define an instruction for a processor.
|
||||
|
@ -30,9 +32,10 @@ import ghidra.program.model.symbol.RefType;
|
|||
public interface Instruction extends CodeUnit, ProcessorContext {
|
||||
|
||||
public static final int INVALID_DEPTH_CHANGE = InstructionPrototype.INVALID_DEPTH_CHANGE; // 2^24
|
||||
public static final int MAX_LENGTH_OVERRIDE = 7;
|
||||
|
||||
/**
|
||||
* Get the prototype for this instruction.
|
||||
* @return the prototype for this instruction.
|
||||
*/
|
||||
public InstructionPrototype getPrototype();
|
||||
|
||||
|
@ -46,6 +49,7 @@ public interface Instruction extends CodeUnit, ProcessorContext {
|
|||
/**
|
||||
* Get objects used by this operand (Address, Scalar, Register ...)
|
||||
* @param opIndex index of the operand.
|
||||
* @return objects used by this operand (Address, Scalar, Register ...)
|
||||
*/
|
||||
public Object[] getOpObjects(int opIndex);
|
||||
|
||||
|
@ -108,6 +112,7 @@ public interface Instruction extends CodeUnit, ProcessorContext {
|
|||
/**
|
||||
* Get the operand reference type for the given operand index.
|
||||
* @param index operand index
|
||||
* @return the operand reference type for the given operand index.
|
||||
*/
|
||||
public RefType getOperandRefType(int index);
|
||||
|
||||
|
@ -134,7 +139,7 @@ public interface Instruction extends CodeUnit, ProcessorContext {
|
|||
public Address getFallThrough();
|
||||
|
||||
/**
|
||||
* Get the Address for the instruction that fell through to
|
||||
* @return the Address for the instruction that fell through to
|
||||
* this instruction.
|
||||
* This is useful for handling instructions that are found
|
||||
* in a delay slot.
|
||||
|
@ -159,32 +164,86 @@ public interface Instruction extends CodeUnit, ProcessorContext {
|
|||
public Address[] getDefaultFlows();
|
||||
|
||||
/**
|
||||
* Get the flow type of this instruction (how this
|
||||
* @return the flow type of this instruction (how this
|
||||
* instruction flows to the next instruction).
|
||||
*/
|
||||
public FlowType getFlowType();
|
||||
|
||||
/**
|
||||
* Returns true if this instruction has no execution flow other than fall-through.
|
||||
* @return true if this instruction has no execution flow other than fall-through.
|
||||
*/
|
||||
public boolean isFallthrough();
|
||||
|
||||
/**
|
||||
* Returns true if this instruction has a fall-through flow.
|
||||
* @return true if this instruction has a fall-through flow.
|
||||
*/
|
||||
public boolean hasFallthrough();
|
||||
|
||||
/**
|
||||
* Returns the flow override which may have been set on this instruction.
|
||||
* @return the flow override which may have been set on this instruction.
|
||||
*/
|
||||
public FlowOverride getFlowOverride();
|
||||
|
||||
/**
|
||||
* Set the flow override for this instruction.
|
||||
* @param flowOverride
|
||||
* @param flowOverride flow override setting or {@link FlowOverride#NONE} to clear.
|
||||
*/
|
||||
public void setFlowOverride(FlowOverride flowOverride);
|
||||
|
||||
/**
|
||||
* Set instruction length override. Specified length must be in the range 0..7 where 0 clears
|
||||
* the setting and adopts the default length. The specified length must be less than the actual
|
||||
* number of bytes consumed by the prototype and be a multiple of the language specified
|
||||
* instruction alignment.
|
||||
* <p>
|
||||
* NOTE: Use of the feature with a delay slot instruction is discouraged.
|
||||
* @param length effective instruction code unit length.
|
||||
* @throws CodeUnitInsertionException if expanding instruction length conflicts with another
|
||||
* instruction or length is not a multiple of the language specified instruction alignment.
|
||||
*/
|
||||
public void setLengthOverride(int length) throws CodeUnitInsertionException;
|
||||
|
||||
/**
|
||||
* Determine if an instruction length override has been set.
|
||||
* @return true if length override has been set else false.
|
||||
*/
|
||||
public boolean isLengthOverridden();
|
||||
|
||||
/**
|
||||
* Get the actual number of bytes parsed when forming this instruction. While this method
|
||||
* will generally return the same value as {@link #getLength()}, its value will differ when
|
||||
* {@link #setLengthOverride(int)} has been used. In addition, it is important to note that
|
||||
* {@link #getMaxAddress()} will always reflect a non-overlapping address which reflects
|
||||
* {@link #getLength()}.
|
||||
* This method is equivalent to the following code for a given instruction:
|
||||
* <br>
|
||||
* <pre>
|
||||
* {@link InstructionPrototype} proto = instruction.{@link #getPrototype()};
|
||||
* int length = proto.{@link InstructionPrototype#getLength() getLength()};
|
||||
* </pre>
|
||||
* @return the actual number of bytes parsed when forming this instruction
|
||||
*/
|
||||
public int getParsedLength();
|
||||
|
||||
/**
|
||||
* Get the actual bytes parsed when forming this instruction. While this method
|
||||
* will generally return the same value as {@link #getBytes()}, it will return more bytes when
|
||||
* {@link #setLengthOverride(int)} has been used. In this override situation, the bytes
|
||||
* returned will generally duplicate some of the parsed bytes associated with the next
|
||||
* instruction that this instruction overlaps.
|
||||
* This method is equivalent to the following code for a given instruction:
|
||||
* <br>
|
||||
* <pre>
|
||||
* {@link InstructionPrototype} proto = instruction.{@link #getPrototype()};
|
||||
* {@link Memory} mem = instruction.{@link #getMemory()};
|
||||
* byte[] bytes = mem.getBytes(instruction.{@link #getAddress()}, proto.getLength());
|
||||
* int length = proto.{@link InstructionPrototype#getLength() getLength()};
|
||||
* </pre>
|
||||
* @return the actual number of bytes parsed when forming this instruction
|
||||
* @throws MemoryAccessException if the full number of bytes could not be read
|
||||
*/
|
||||
public byte[] getParsedBytes() throws MemoryAccessException;
|
||||
|
||||
/**
|
||||
* Get an array of PCode operations (micro code) that this instruction
|
||||
* performs. Flow overrides are not factored into pcode.
|
||||
|
@ -223,21 +282,22 @@ public interface Instruction extends CodeUnit, ProcessorContext {
|
|||
* some RISC processors such as SPARC and the PA-RISC. This
|
||||
* returns an integer instead of a boolean in case some other
|
||||
* processor executes more than one instruction from a delay slot.
|
||||
* @return delay slot depth (number of instructions)
|
||||
*/
|
||||
public int getDelaySlotDepth();
|
||||
|
||||
/**
|
||||
* Return true if this instruction was disassembled in a delay slot
|
||||
* @return true if this instruction was disassembled in a delay slot
|
||||
*/
|
||||
public boolean isInDelaySlot();
|
||||
|
||||
/**
|
||||
* Get the instruction following this one in address order.
|
||||
* @return the instruction following this one in address order or null if none found.
|
||||
*/
|
||||
public Instruction getNext();
|
||||
|
||||
/**
|
||||
* Get the instruction before this one in address order.
|
||||
* @return the instruction before this one in address order or null if none found.
|
||||
*/
|
||||
public Instruction getPrevious();
|
||||
|
||||
|
@ -256,7 +316,7 @@ public interface Instruction extends CodeUnit, ProcessorContext {
|
|||
public void clearFallThroughOverride();
|
||||
|
||||
/**
|
||||
* Returns true if this instructions fallthrough has been overriden.
|
||||
* @return true if this instructions fallthrough has been overriden.
|
||||
*/
|
||||
public boolean isFallThroughOverridden();
|
||||
|
||||
|
|
|
@ -28,7 +28,8 @@ import ghidra.util.Msg;
|
|||
|
||||
public class InstructionPcodeOverride implements PcodeOverride {
|
||||
|
||||
protected Instruction instr;
|
||||
protected final Instruction instr;
|
||||
|
||||
private boolean callOverrideApplied = false;
|
||||
private boolean jumpOverrideApplied = false;
|
||||
private boolean callOtherCallOverrideApplied = false;
|
||||
|
@ -64,7 +65,7 @@ public class InstructionPcodeOverride implements PcodeOverride {
|
|||
public Address getFallThroughOverride() {
|
||||
Address defaultFallAddr = instr.getDefaultFallThrough();
|
||||
Address fallAddr = instr.getFallThrough();
|
||||
if (fallAddr != null && !fallAddr.equals(defaultFallAddr)) {
|
||||
if (fallAddr != null && (instr.isLengthOverridden() || !fallAddr.equals(defaultFallAddr))) {
|
||||
return fallAddr;
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -146,21 +146,26 @@ public class InstructionStub implements Instruction {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuccessor(CodeUnit codeUnit) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getParsedLength() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() throws MemoryAccessException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getParsedBytes() throws MemoryAccessException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBytesInCodeUnit(byte[] buffer, int bufferOffset) throws MemoryAccessException {
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -458,6 +463,16 @@ public class InstructionStub implements Instruction {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLengthOverride(int length) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLengthOverridden() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlowOverride(FlowOverride flowOverride) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -602,17 +602,22 @@ public interface Listing {
|
|||
* changes will result in a <code>ContextChangeException</code>
|
||||
*
|
||||
* @param addr the address at which to create an instruction
|
||||
* @param prototype the InstructionPrototype the describes the type of
|
||||
* instruction to create.
|
||||
* @param memBuf buffer that provides the bytes that make up the
|
||||
* instruction.
|
||||
* @param prototype the InstructionPrototype that describes the type of instruction to create.
|
||||
* @param memBuf buffer that provides the bytes that make up the instruction.
|
||||
* @param context the processor context at this location.
|
||||
* @return the newly created instruction.
|
||||
* @exception CodeUnitInsertionException thrown if the new Instruction would
|
||||
* overlap and existing Instruction or defined data.
|
||||
* @param length instruction byte-length (must be in the range 0..prototype.getLength()).
|
||||
* If smaller than the prototype length it must have a value no greater than 7, otherwise
|
||||
* an error will be thrown. A value of 0 or greater-than-or-equal the prototype length
|
||||
* will be ignored and not impose and override length. The length value must be a multiple
|
||||
* of the {@link Language#getInstructionAlignment() instruction alignment} .
|
||||
* @return the newly created instruction.
|
||||
* @throws CodeUnitInsertionException thrown if the new Instruction would overlap and
|
||||
* existing {@link CodeUnit} or the specified {@code length} is unsupported.
|
||||
* @throws IllegalArgumentException if a negative {@code length} is specified.
|
||||
*/
|
||||
public Instruction createInstruction(Address addr, InstructionPrototype prototype,
|
||||
MemBuffer memBuf, ProcessorContextView context) throws CodeUnitInsertionException;
|
||||
MemBuffer memBuf, ProcessorContextView context, int length)
|
||||
throws CodeUnitInsertionException;
|
||||
|
||||
/**
|
||||
* Creates a complete set of instructions. A preliminary pass will be made
|
||||
|
@ -659,8 +664,7 @@ public interface Listing {
|
|||
* @exception CodeUnitInsertionException thrown if the new Instruction would
|
||||
* overlap and existing Instruction or defined data.
|
||||
*/
|
||||
public Data createData(Address addr, DataType dataType)
|
||||
throws CodeUnitInsertionException;
|
||||
public Data createData(Address addr, DataType dataType) throws CodeUnitInsertionException;
|
||||
|
||||
/**
|
||||
* Clears any code units in the given range returning everything to "db"s,
|
||||
|
|
|
@ -282,13 +282,14 @@ public class StubListing implements Listing {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PropertyMap getPropertyMap(String propertyName) {
|
||||
public PropertyMap<?> getPropertyMap(String propertyName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instruction createInstruction(Address addr, InstructionPrototype prototype,
|
||||
MemBuffer memBuf, ProcessorContextView context) throws CodeUnitInsertionException {
|
||||
MemBuffer memBuf, ProcessorContextView context, int forcedLengthOverride)
|
||||
throws CodeUnitInsertionException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.program.model.symbol;
|
|||
import java.util.List;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Library;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
@ -167,92 +168,121 @@ public interface ExternalManager {
|
|||
* Adds a new external library name
|
||||
* @param libraryName the new external library name to add.
|
||||
* @param source the source of this external library
|
||||
* @return library
|
||||
* @throws InvalidInputException
|
||||
* @return library external {@link Library namespace}
|
||||
* @throws InvalidInputException if {@code libraryName} is invalid or null. A library name
|
||||
* with spaces or the empty string are not permitted.
|
||||
* Neither {@code extLabel} nor {@code extAddr} was specified properly.
|
||||
* @throws DuplicateNameException if another non-Library namespace has the same name
|
||||
*/
|
||||
public Library addExternalLibraryName(String libraryName, SourceType source)
|
||||
throws InvalidInputException, DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Get or create an external location associated with an library/file named extName
|
||||
* and the label within that file specified by extLabel
|
||||
* Get or create an external location associated with a library/file named {@code libraryName}
|
||||
* and the location within that file identified by {@code extLabel} and/or its memory address
|
||||
* {@code extAddr}. Either or both {@code extLabel} or {@code extAddr} must be specified.
|
||||
* @param libraryName the external library name
|
||||
* @param extLabel the external label
|
||||
* @param extAddr the external address
|
||||
* @param extLabel the external label or null
|
||||
* @param extAddr the external memory address or null
|
||||
* @param sourceType the source type of this external library's symbol
|
||||
* @return external location
|
||||
* @throws InvalidInputException
|
||||
* @throws InvalidInputException if {@code libraryName} is invalid or null, or an invalid
|
||||
* {@code extlabel} is specified. Names with spaces or the empty string are not permitted.
|
||||
* Neither {@code extLabel} nor {@code extAddr} was specified properly.
|
||||
* @throws DuplicateNameException if another non-Library namespace has the same name
|
||||
* @throws IllegalArgumentException if an invalid {@code extAddr} was specified.
|
||||
*/
|
||||
public ExternalLocation addExtLocation(String libraryName, String extLabel, Address extAddr,
|
||||
SourceType sourceType) throws InvalidInputException, DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Get or create an external location in the indicated parent namespace with the specified name.
|
||||
* Create an external location in the indicated external parent namespace
|
||||
* and identified by {@code extLabel} and/or its memory address
|
||||
* {@code extAddr}. Either or both {@code extLabel} or {@code extAddr} must be specified.
|
||||
* @param extNamespace the external namespace
|
||||
* @param extLabel the external label
|
||||
* @param extAddr the external address
|
||||
* @param extLabel the external label or null
|
||||
* @param extAddr the external memory address or null
|
||||
* @param sourceType the source type of this external library's symbol
|
||||
* @return external location
|
||||
* @throws InvalidInputException
|
||||
* @throws InvalidInputException if an invalid {@code extlabel} is specified.
|
||||
* Names with spaces or the empty string are not permitted.
|
||||
* Neither {@code extLabel} nor {@code extAddr} was specified properly.
|
||||
* @throws IllegalArgumentException if an invalid {@code extAddr} was specified.
|
||||
*/
|
||||
public ExternalLocation addExtLocation(Namespace extNamespace, String extLabel, Address extAddr,
|
||||
SourceType sourceType) throws InvalidInputException;
|
||||
|
||||
/**
|
||||
* Get or create an external location in the indicated parent namespace with the specified name.
|
||||
* Get or create an external location in the indicated external parent namespace
|
||||
* and identified by {@code extLabel} and/or its memory address
|
||||
* {@code extAddr}. Either or both {@code extLabel} or {@code extAddr} must be specified.
|
||||
* @param extNamespace the external namespace
|
||||
* @param extLabel the external label
|
||||
* @param extAddr the external address
|
||||
* @param extLabel the external label or null
|
||||
* @param extAddr the external memory address or null
|
||||
* @param sourceType the source type of this external library's symbol
|
||||
* @param reuseExisting if true, this will return an existing matching external
|
||||
* location instead of creating a new one.
|
||||
* @return external location
|
||||
* @throws InvalidInputException
|
||||
* @throws InvalidInputException if an invalid {@code extlabel} is specified.
|
||||
* Names with spaces or the empty string are not permitted.
|
||||
* Neither {@code extLabel} nor {@code extAddr} was specified properly.
|
||||
* @throws IllegalArgumentException if an invalid {@code extAddr} was specified.
|
||||
*/
|
||||
public ExternalLocation addExtLocation(Namespace extNamespace, String extLabel, Address extAddr,
|
||||
SourceType sourceType, boolean reuseExisting)
|
||||
throws InvalidInputException;
|
||||
|
||||
/**
|
||||
* Get or create an external location associated with an library/file named extName
|
||||
* and the label within that file specified by extLabel
|
||||
* Create an external {@link Function} in the external {@link Library} namespace
|
||||
* {@code libararyName} and identified by {@code extLabel} and/or its memory address
|
||||
* {@code extAddr}. Either or both {@code extLabel} or {@code extAddr} must be specified.
|
||||
* @param libraryName the external library name
|
||||
* @param extLabel the external label
|
||||
* @param extAddr the external address
|
||||
* @param extLabel label within the external program, may be null if extAddr is not null
|
||||
* @param extAddr memory address within the external program, may be null
|
||||
* @param sourceType the source type of this external library's symbol
|
||||
* @return external location
|
||||
* @throws InvalidInputException
|
||||
* @throws InvalidInputException if {@code libraryName} is invalid or null, or an invalid
|
||||
* {@code extlabel} is specified. Names with spaces or the empty string are not permitted.
|
||||
* Neither {@code extLabel} nor {@code extAddr} was specified properly.
|
||||
* @throws DuplicateNameException if another non-Library namespace has the same name
|
||||
* @throws IllegalArgumentException if an invalid {@code extAddr} was specified.
|
||||
*/
|
||||
public ExternalLocation addExtFunction(String libraryName, String extLabel, Address extAddr,
|
||||
SourceType sourceType) throws InvalidInputException, DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Get or create an external function location associated with an library/file named extName
|
||||
* and the label within that file specified by extLabel
|
||||
* Create an external {@link Function} in the indicated external parent namespace
|
||||
* and identified by {@code extLabel} and/or its memory address
|
||||
* {@code extAddr}. Either or both {@code extLabel} or {@code extAddr} must be specified.
|
||||
* @param extNamespace the external namespace
|
||||
* @param extLabel the external label
|
||||
* @param extAddr the external address
|
||||
* @param extLabel the external label or null
|
||||
* @param extAddr the external memory address or null
|
||||
* @param sourceType the source type of this external library's symbol
|
||||
* @return external location
|
||||
* @throws InvalidInputException
|
||||
* @throws InvalidInputException if an invalid {@code extlabel} is specified.
|
||||
* Names with spaces or the empty string are not permitted.
|
||||
* Neither {@code extLabel} nor {@code extAddr} was specified properly.
|
||||
* @throws IllegalArgumentException if an invalid {@code extAddr} was specified.
|
||||
*/
|
||||
public ExternalLocation addExtFunction(Namespace extNamespace, String extLabel, Address extAddr,
|
||||
SourceType sourceType) throws InvalidInputException;
|
||||
|
||||
/**
|
||||
* Get or create an external function location associated with an library/file named extName
|
||||
* and the label within that file specified by extLabel
|
||||
* Get or create an external {@link Function} in the indicated external parent namespace
|
||||
* and identified by {@code extLabel} and/or its memory address
|
||||
* {@code extAddr}. Either or both {@code extLabel} or {@code extAddr} must be specified.
|
||||
* @param extNamespace the external namespace
|
||||
* @param extLabel the external label
|
||||
* @param extLabel the external label or null
|
||||
* @param extAddr the external memory address or null
|
||||
* @param sourceType the source type of this external library's symbol
|
||||
* @param reuseExisting if true, will return any existing matching location instead of
|
||||
* creating a new one. If false, will prefer to create a new one as long as the specified
|
||||
* address is not null and not used in an existing location.
|
||||
* @return external location
|
||||
* @throws InvalidInputException
|
||||
* @throws InvalidInputException if an invalid {@code extlabel} is specified.
|
||||
* Names with spaces or the empty string are not permitted.
|
||||
* Neither {@code extLabel} nor {@code extAddr} was specified properly.
|
||||
* @throws IllegalArgumentException if an invalid {@code extAddr} was specified.
|
||||
*/
|
||||
public ExternalLocation addExtFunction(Namespace extNamespace, String extLabel, Address extAddr,
|
||||
SourceType sourceType, boolean reuseExisting)
|
||||
|
|
|
@ -17,13 +17,24 @@
|
|||
|
||||
package ghidra.program.model.symbol;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.block.CodeBlock;
|
||||
import ghidra.program.model.listing.CodeUnit;
|
||||
import ghidra.program.model.listing.Instruction;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
/**
|
||||
* Class to define reference types.
|
||||
* {@link RefType} defines reference types used to specify the nature of a directional
|
||||
* relationship between a source-location and a destination-location where a "location"
|
||||
* may correspond to a {@link Address}, {@link CodeUnit}, {@link CodeBlock} or other
|
||||
* code related objects. Reference types are generally identified as either
|
||||
* {@link #isData() data} (see {@link DataRefType}) or {@link #isFlow() flow}
|
||||
* (see {@link FlowType}).
|
||||
*/
|
||||
public abstract class RefType {
|
||||
|
||||
//
|
||||
// NOTE:
|
||||
// IMPORTANT:
|
||||
// - When creating a new flow type, be sure to add code to the RefTypeFactory
|
||||
// - Once a RefType value is defined it must be maintained for upgrade use
|
||||
//
|
||||
|
@ -70,86 +81,181 @@ public abstract class RefType {
|
|||
static final byte __UNKNOWNPARAM = 107;
|
||||
|
||||
@Deprecated
|
||||
static final byte __STACK_READ = 110; // Use __READ instead - required for upgrade use
|
||||
static final byte __STACK_READ = 110; // Use __READ instead - retained for upgrade use
|
||||
@Deprecated
|
||||
static final byte __STACK_WRITE = 111; // Use __WRITE instead - required for upgrade use
|
||||
static final byte __STACK_WRITE = 111; // Use __WRITE instead - retained for upgrade use
|
||||
|
||||
static final byte __EXTERNAL_REF = 113;
|
||||
static final byte __UNKNOWNDATA_IND = 114;
|
||||
|
||||
static final byte __DYNAMICDATA = 127;
|
||||
|
||||
/**
|
||||
* {@link #INVALID} corresponds to an unknown {@link FlowType} which encountered an error
|
||||
* when determining the flow-type of the instruction at the from address.
|
||||
*/
|
||||
public static final FlowType INVALID =
|
||||
new FlowType.Builder(__INVALID, "INVALID")
|
||||
.setHasFall()
|
||||
.build();
|
||||
/**
|
||||
* {@link #FLOW} corresponds to a complex or generic {@link FlowType}. This may be used
|
||||
* to describe the flow-type of an instruction or code-block which contains multiple outbound
|
||||
* flows of differing types. This should not be used for a specific flow {@link Reference}.
|
||||
*/
|
||||
public static final FlowType FLOW =
|
||||
new FlowType.Builder(__UNKNOWNFLOW, "FLOW")
|
||||
.setHasFall()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #FALL_THROUGH} corresponds to an instruction fall-through override where modeling
|
||||
* requires a fall-through instruction to convey a branch around other {@link CodeUnit}s.
|
||||
* While this may be freely used to describe the flow-type of a code-block or its relationship
|
||||
* to another code-block, its use with a {@link Reference} is <b>reserved for internal use</b>
|
||||
* to reflect an {@link Instruction} fall-through-override or length-override condition.
|
||||
*/
|
||||
public static final FlowType FALL_THROUGH =
|
||||
new FlowType.Builder(__FALL_THROUGH, "FALL_THROUGH")
|
||||
.setHasFall()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #UNCONDITIONAL_JUMP} corresponds to an unconditional jump/branch {@link FlowType}.
|
||||
* This may be used to describe the flow-type of an instruction or code-block, or
|
||||
* {@link Reference} to another instruction or code-block.
|
||||
*/
|
||||
public static final FlowType UNCONDITIONAL_JUMP =
|
||||
new FlowType.Builder(__UNCONDITIONAL_JUMP, "UNCONDITIONAL_JUMP")
|
||||
.setIsJump()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #CONDITIONAL_JUMP} corresponds to a conditional jump/branch {@link FlowType}.
|
||||
* This may be used to describe the flow-type of an instruction or code-block, or
|
||||
* {@link Reference} to another instruction or code-block.
|
||||
*/
|
||||
public static final FlowType CONDITIONAL_JUMP =
|
||||
new FlowType.Builder(__CONDITIONAL_JUMP, "CONDITIONAL_JUMP")
|
||||
.setHasFall()
|
||||
.setIsJump()
|
||||
.setIsConditional()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #UNCONDITIONAL_CALL} corresponds to an unconditional call {@link FlowType} with fall-through.
|
||||
* This may be used to describe the flow-type of an instruction or code-block, or
|
||||
* call {@link Reference} to another instruction or code-block.
|
||||
*/
|
||||
public static final FlowType UNCONDITIONAL_CALL =
|
||||
new FlowType.Builder(__UNCONDITIONAL_CALL, "UNCONDITIONAL_CALL")
|
||||
.setHasFall()
|
||||
.setIsCall()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #CONDITIONAL_CALL} corresponds to a conditional call {@link FlowType} with fall-through.
|
||||
* This may be used to describe the flow-type of an instruction or code-block, or
|
||||
* call {@link Reference} to another instruction or code-block.
|
||||
*/
|
||||
public static final FlowType CONDITIONAL_CALL =
|
||||
new FlowType.Builder(__CONDITIONAL_CALL, "CONDITIONAL_CALL")
|
||||
.setHasFall()
|
||||
.setIsCall()
|
||||
.setIsConditional()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #TERMINATOR} corresponds to a terminal {@link FlowType} (e.g., return from a
|
||||
* function). This may be used to describe the flow-type of an instruction or code-block
|
||||
* but should generally not be used with a {@link Reference}.
|
||||
*/
|
||||
public static final FlowType TERMINATOR =
|
||||
new FlowType.Builder(__TERMINATOR, "TERMINATOR")
|
||||
.setIsTerminal()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #COMPUTED_JUMP} corresponds to a computed jump/branch {@link FlowType}.
|
||||
* This may be used to describe the flow-type of an instruction or code-block, or
|
||||
* {@link Reference} to another instruction or code-block.
|
||||
*/
|
||||
public static final FlowType COMPUTED_JUMP =
|
||||
new FlowType.Builder(__COMPUTED_JUMP, "COMPUTED_JUMP")
|
||||
.setIsJump()
|
||||
.setIsComputed()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #TERMINATOR} corresponds to a terminal {@link FlowType} (e.g., conditional return
|
||||
* from a function). This may be used to describe the flow-type of an instruction or code-block
|
||||
* but should generally not be used with a {@link Reference}.
|
||||
*/
|
||||
public static final FlowType CONDITIONAL_TERMINATOR =
|
||||
new FlowType.Builder(__CONDITIONAL_TERMINATOR, "CONDITIONAL_TERMINATOR")
|
||||
.setHasFall()
|
||||
.setIsTerminal()
|
||||
.setIsConditional()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #COMPUTED_CALL} corresponds to a computed call {@link FlowType} with fall-through.
|
||||
* This may be used to describe the flow-type of an instruction or code-block, or
|
||||
* call {@link Reference} to another instruction or code-block.
|
||||
*/
|
||||
public static final FlowType COMPUTED_CALL =
|
||||
new FlowType.Builder(__COMPUTED_CALL, "COMPUTED_CALL")
|
||||
.setHasFall()
|
||||
.setIsCall()
|
||||
.setIsComputed()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #CALL_TERMINATOR} corresponds to an unconditional call {@link FlowType}
|
||||
* followed by a terminal without fall-through (e.g., unconditional return from a function).
|
||||
* This may be used to describe the flow-type of an instruction or code-block but
|
||||
* should generally not be used with a {@link Reference}. A corresponding {@link Reference}
|
||||
* should generally specify {@link #__UNCONDITIONAL_CALL}.
|
||||
*/
|
||||
public static final FlowType CALL_TERMINATOR =
|
||||
new FlowType.Builder(__CALL_TERMINATOR, "CALL_TERMINATOR")
|
||||
.setIsCall()
|
||||
.setIsTerminal()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #COMPUTED_CALL_TERMINATOR} corresponds to an unconditional call {@link FlowType}
|
||||
* followed by a terminal without fall-through (e.g., unconditional return from a function).
|
||||
* This may be used to describe the flow-type of an instruction or code-block but
|
||||
* should generally not be used with a {@link Reference}. A corresponding {@link Reference}
|
||||
* should generally specify {@link #COMPUTED_CALL}.
|
||||
*/
|
||||
public static final FlowType COMPUTED_CALL_TERMINATOR =
|
||||
new FlowType.Builder(__COMPUTED_CALL_TERMINATOR, "COMPUTED_CALL_TERMINATOR")
|
||||
.setIsCall()
|
||||
.setIsTerminal()
|
||||
.setIsComputed()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #CONDITIONAL_CALL_TERMINATOR} corresponds to a conditional call {@link FlowType}
|
||||
* followed by a terminal without fall-through (e.g., unconditional return from a function).
|
||||
* This may be used to describe the flow-type of an instruction or code-block but
|
||||
* should generally not be used with a {@link Reference}. A corresponding {@link Reference}
|
||||
* should generally specify {@link #CONDITIONAL_CALL}.
|
||||
*/
|
||||
public static final FlowType CONDITIONAL_CALL_TERMINATOR =
|
||||
new FlowType.Builder(__CONDITIONAL_CALL_TERMINATOR, "CONDITIONAL_CALL_TERMINATOR")
|
||||
.setIsCall()
|
||||
.setIsTerminal()
|
||||
.setIsConditional()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #CONDITIONAL_COMPUTED_CALL} corresponds to a conditional computed call {@link FlowType}
|
||||
* with fall-through. This may be used to describe the flow-type of an instruction or
|
||||
* code-block, or call {@link Reference} to another instruction or code-block.
|
||||
*/
|
||||
public static final FlowType CONDITIONAL_COMPUTED_CALL = new FlowType.Builder(
|
||||
__CONDITIONAL_COMPUTED_CALL, "CONDITIONAL_COMPUTED_CALL")
|
||||
.setHasFall()
|
||||
|
@ -157,6 +263,12 @@ public abstract class RefType {
|
|||
.setIsComputed()
|
||||
.setIsConditional()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #CONDITIONAL_COMPUTED_JUMP} corresponds to a conditional computed jump/branch
|
||||
* {@link FlowType}. This may be used to describe the flow-type of an instruction or
|
||||
* code-block, or {@link Reference} to another instruction or code-block.
|
||||
*/
|
||||
public static final FlowType CONDITIONAL_COMPUTED_JUMP =
|
||||
new FlowType.Builder(__CONDITIONAL_COMPUTED_JUMP, "CONDITIONAL_COMPUTED_JUMP")
|
||||
.setHasFall()
|
||||
|
@ -164,31 +276,89 @@ public abstract class RefType {
|
|||
.setIsComputed()
|
||||
.setIsConditional()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #JUMP_TERMINATOR} corresponds to a conditional jump/branch {@link FlowType}
|
||||
* followed by a terminal without fall-through (e.g., unconditional return from a function).
|
||||
* This may be used to describe the flow-type of an instruction or code-block but
|
||||
* should generally not be used with a {@link Reference}. A corresponding {@link Reference}
|
||||
* should generally specify {@link #CONDITIONAL_JUMP}.
|
||||
*/
|
||||
public static final FlowType JUMP_TERMINATOR =
|
||||
new FlowType.Builder(__JUMP_TERMINATOR, "JUMP_TERMINATOR")
|
||||
.setIsJump()
|
||||
.setIsTerminal()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #INDIRECTION} corresponds to a flow {@link Reference} placed on a pointer data location
|
||||
* that is utilized indirectly by a computed jump/branch or call instruction.
|
||||
*/
|
||||
public static final FlowType INDIRECTION =
|
||||
new FlowType.Builder(__INDIRECTION, "INDIRECTION")
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #__CALL_OVERRIDE_UNCONDITIONAL} is used with a memory {@link Reference} to
|
||||
* override the destination of an instruction {@link PcodeOp#CALL} or {@link PcodeOp#CALLIND}
|
||||
* pcode operation. {@link PcodeOp#CALLIND} operations are changed to {@link PcodeOp#CALL}
|
||||
* operations. The new call target is the "to" address of the {@link Reference}. The override
|
||||
* only takes effect when the {@link Reference} is primary, and only when there is exactly
|
||||
* one {@link #__CALL_OVERRIDE_UNCONDITIONAL} {@link Reference} at the "from" address of
|
||||
* the reference.
|
||||
*/
|
||||
public static final FlowType CALL_OVERRIDE_UNCONDITIONAL =
|
||||
new FlowType.Builder(__CALL_OVERRIDE_UNCONDITIONAL, "CALL_OVERRIDE_UNCONDITIONAL")
|
||||
.setHasFall()
|
||||
.setIsCall()
|
||||
.setIsOverride()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #JUMP_OVERRIDE_UNCONDITIONAL} is used with a memory {@link Reference} to
|
||||
* override the destination of an instruction {@link PcodeOp#BRANCH} or {@link PcodeOp#CBRANCH}
|
||||
* pcode operation. {@link PcodeOp#CBRANCH} operations are changed to {@link PcodeOp#BRANCH}
|
||||
* operations. The new jump target is the "to" address of the {@link Reference}. The override
|
||||
* only takes effect when the {@link Reference} is primary, and only when there is exactly
|
||||
* one {@link #JUMP_OVERRIDE_UNCONDITIONAL} reference at the "from" address of
|
||||
* the reference.
|
||||
*/
|
||||
public static final FlowType JUMP_OVERRIDE_UNCONDITIONAL =
|
||||
new FlowType.Builder(__JUMP_OVERRIDE_UNCONDITIONAL, "JUMP_OVERRIDE_UNCONDITIONAL")
|
||||
.setIsJump()
|
||||
.setIsOverride()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #CALLOTHER_OVERRIDE_CALL} is used to change a {@link PcodeOp#CALLOTHER} pcode operation
|
||||
* to a {@link PcodeOp#CALL} operation. The new call target is the "to" address of the
|
||||
* {@link Reference}. Any inputs to the original {@link PcodeOp#CALLOTHER} are discarded;
|
||||
* the new {@link PcodeOp#CALL} may have inputs assigned to it during decompilation. The
|
||||
* override only takes effect when the {@link Reference} is primary, and only when there is
|
||||
* exactly one {@link #CALLOTHER_OVERRIDE_CALL} reference at the "from" address of the
|
||||
* reference. Only the first {@link PcodeOp#CALLOTHER} operation at the "from" address of the
|
||||
* reference is changed. Applying this override to instances of a {@link PcodeOp#CALLOTHER}
|
||||
* that have an output is not recommended and can adversely affect decompilation
|
||||
* (e.g., the decompiler may throw an exception). Note that this reference override takes
|
||||
* precedence over {@link #CALLOTHER_OVERRIDE_JUMP} references.
|
||||
*/
|
||||
public static final FlowType CALLOTHER_OVERRIDE_CALL =
|
||||
new FlowType.Builder(__CALLOTHER_OVERRIDE_CALL, "CALLOTHER_OVERRIDE_CALL")
|
||||
.setHasFall()
|
||||
.setIsCall()
|
||||
.setIsOverride()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* {@link #CALLOTHER_OVERRIDE_CALL} is used to change a {@link PcodeOp#CALLOTHER} pcode
|
||||
* operation to a {@link PcodeOp#BRANCH} operation. The new jump target is the "to" address
|
||||
* of the {@link Reference}. The override only takes effect when the {@link Reference} is
|
||||
* primary, and only when there is exactly one {@link #CALLOTHER_OVERRIDE_CALL} reference at
|
||||
* the "from" address of the reference. Only the first {@link PcodeOp#CALLOTHER} operation
|
||||
* at the "from" address of the reference is changed. Applying this override to an instance
|
||||
* of a {@link PcodeOp#CALLOTHER} with output is not recommended
|
||||
* (see {@link #CALLOTHER_OVERRIDE_CALL}).
|
||||
*/
|
||||
public static final FlowType CALLOTHER_OVERRIDE_JUMP =
|
||||
new FlowType.Builder(__CALLOTHER_OVERRIDE_JUMP, "CALLOTHER_OVERRIDE_JUMP")
|
||||
.setIsJump()
|
||||
|
@ -196,61 +366,80 @@ public abstract class RefType {
|
|||
.build();
|
||||
|
||||
/**
|
||||
* Reference type is unknown.
|
||||
* {@link #THUNK} type identifies the relationship between a thunk-function and its
|
||||
* corresponding thunked-function which do not rely on a stored {@link Reference}.
|
||||
*/
|
||||
|
||||
public static final RefType THUNK = new DataRefType(__DYNAMICDATA, "THUNK", 0);
|
||||
|
||||
/**
|
||||
* Reference type assigned when data access is unknown.
|
||||
* {@link #DATA} type identifies a generic reference from either an instruction,
|
||||
* when the read/write data access is unknown, or from pointer data when it refers to
|
||||
* data or it's unknown if it refers to code. A pointer that is known to refer to code
|
||||
* should generally have a {@link #INDIRECTION} type if used for by a computed
|
||||
* jump/branch or call.
|
||||
*/
|
||||
public static final RefType DATA = new DataRefType(__UNKNOWNDATA, "DATA", 0);
|
||||
|
||||
/**
|
||||
* Reference type assigned when data (constant or pointer) is passed to a function
|
||||
* {@link #PARAM} type is used to identify data (constant or pointer) that is passed
|
||||
* to a function.
|
||||
*/
|
||||
public static final RefType PARAM = new DataRefType(__UNKNOWNPARAM, "PARAM", 0);
|
||||
|
||||
/**
|
||||
* {@link #DATA_IND} corresponds to a data {@link Reference} placed on a pointer data location
|
||||
* that is utilized indirectly to access a data location.
|
||||
* @deprecated use of this type is discouraged and may be eliminated in a future release.
|
||||
* The type {@link #DATA} should generally be used in place of this type.
|
||||
*/
|
||||
public static final RefType DATA_IND =
|
||||
new DataRefType(__UNKNOWNDATA_IND, "DATA_IND", DataRefType.INDX);
|
||||
|
||||
/**
|
||||
* Reference type assigned when data is being read.
|
||||
* {@link #READ} type identifies an instruction reference to a data location that is directly
|
||||
* read.
|
||||
*/
|
||||
public static final RefType READ = new DataRefType(__READ, "READ", DataRefType.READX);
|
||||
|
||||
/**
|
||||
* Reference type assigned when data is being written.
|
||||
* {@link #WRITE} type identifies an instruction reference to a data location that is directly
|
||||
* written.
|
||||
*/
|
||||
public static final RefType WRITE = new DataRefType(__WRITE, "WRITE", DataRefType.WRITEX);
|
||||
|
||||
/**
|
||||
* Reference type assigned when data is read and written.
|
||||
* {@link #READ_WRITE} type identifies an instruction reference to a data location that is
|
||||
* both directly read and written.
|
||||
*/
|
||||
public static final RefType READ_WRITE =
|
||||
new DataRefType(__READ_WRITE, "READ_WRITE", DataRefType.READX | DataRefType.WRITEX);
|
||||
|
||||
/**
|
||||
* Reference type assigned when data is being read.
|
||||
* {@link #READ_IND} type identifies an instruction reference to a data location that is
|
||||
* indirectly read using a stored pointer or computed value.
|
||||
*/
|
||||
public static final RefType READ_IND =
|
||||
new DataRefType(__READ_IND, "READ_IND", DataRefType.READX | DataRefType.INDX);
|
||||
|
||||
/**
|
||||
* Reference type assigned when data is being written.
|
||||
* {@link #WRITE_IND} type identifies an instruction reference to a data location that is
|
||||
* indirectly written using a stored pointer or computed value.
|
||||
*/
|
||||
public static final RefType WRITE_IND =
|
||||
new DataRefType(__WRITE_IND, "WRITE_IND", DataRefType.WRITEX | DataRefType.INDX);
|
||||
|
||||
/**
|
||||
* Reference type assigned when data is read and written.
|
||||
* {@link #READ_WRITE_IND} type identifies an instruction reference to a data location that is
|
||||
* both indirectly read and written using a stored pointer or computed value.
|
||||
*/
|
||||
public static final RefType READ_WRITE_IND = new DataRefType(__READ_WRITE_IND, "READ_WRITE_IND",
|
||||
DataRefType.READX | DataRefType.WRITEX | DataRefType.INDX);
|
||||
|
||||
/**
|
||||
* Reference type used internally to identify external entry points.
|
||||
* The use of this RefType for references to external library data or functions
|
||||
* {@link #EXTERNAL_REF} type is used internally to identify external entry point locations
|
||||
* using a from address of {@link Address#NO_ADDRESS}.
|
||||
* <p>
|
||||
* NOTE: The use of this type for references to external library data or functions
|
||||
* is deprecated and should not be used for that purpose.
|
||||
*/
|
||||
public static final RefType EXTERNAL_REF = new DataRefType(__EXTERNAL_REF, "EXTERNAL", 0);
|
||||
|
@ -266,6 +455,9 @@ public abstract class RefType {
|
|||
if (this == RefType.THUNK) {
|
||||
return "Thunk";
|
||||
}
|
||||
if (this == RefType.FALL_THROUGH) {
|
||||
return "FallThrough";
|
||||
}
|
||||
|
||||
if (isRead() && isWrite()) {
|
||||
return "RW";
|
||||
|
@ -301,6 +493,37 @@ public abstract class RefType {
|
|||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns name of ref-type
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || !getClass().equals(obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
RefType other = (RefType) obj;
|
||||
return type == other.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
//
|
||||
// Data related methods
|
||||
//
|
||||
|
||||
/**
|
||||
* Returns true if the reference is to data
|
||||
* @return true if the reference is to data
|
||||
|
@ -325,6 +548,18 @@ public abstract class RefType {
|
|||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Flow related methods
|
||||
//
|
||||
|
||||
/**
|
||||
* Returns true if the reference is an instruction flow reference
|
||||
* @return true if the reference is an instruction flow reference
|
||||
*/
|
||||
public boolean isFlow() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the reference is indirect
|
||||
* @return true if the reference is indirect
|
||||
|
@ -336,14 +571,6 @@ public abstract class RefType {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the reference is an instruction flow reference
|
||||
* @return true if the reference is an instruction flow reference
|
||||
*/
|
||||
public boolean isFlow() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this flow type is one that does not cause a break in control flow
|
||||
* @return if this flow type is one that does not cause a break in control flow
|
||||
|
@ -416,30 +643,4 @@ public abstract class RefType {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns name of ref-type
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || !getClass().equals(obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
RefType other = (RefType) obj;
|
||||
return type == other.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.program.model.symbol;
|
|||
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.listing.Library;
|
||||
import ghidra.program.model.listing.Variable;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
@ -69,7 +70,8 @@ public interface ReferenceManager {
|
|||
/**
|
||||
* Adds a memory reference. The first memory reference placed on
|
||||
* an operand will be made primary by default. All non-memory references
|
||||
* will be removed from the specified operand.
|
||||
* will be removed from the specified operand. Certain reference {@link RefType types}
|
||||
* may not be specified (e.g., {@link RefType#FALL_THROUGH}).
|
||||
* @param fromAddr address of the codeunit where the reference occurs
|
||||
* @param toAddr address of the location being referenced.
|
||||
* Memory, stack, and register addresses are all permitted.
|
||||
|
@ -78,6 +80,7 @@ public interface ReferenceManager {
|
|||
* @param opIndex the operand index
|
||||
* display of the operand making this reference
|
||||
* @return new memory reference
|
||||
* @throws IllegalArgumentException if unsupported {@link RefType type} is specified
|
||||
*/
|
||||
public Reference addMemoryReference(Address fromAddr, Address toAddr, RefType type,
|
||||
SourceType source, int opIndex);
|
||||
|
@ -109,10 +112,14 @@ public interface ReferenceManager {
|
|||
* shiftValue parameter. The first memory reference placed on
|
||||
* an operand will be made primary by default. All non-memory references
|
||||
* will be removed from the specified operand.
|
||||
* @param fromAddr address for the "from"
|
||||
* @param toAddr computed as the value of the operand at opIndex shifted
|
||||
* by the number of bits specified by shiftValue
|
||||
* @param shiftValue shifted value
|
||||
*
|
||||
* @param fromAddr source/from memory address
|
||||
* @param toAddr destination/to memory address computed as some
|
||||
* {@link ShiftedReference#getValue() base offset value} shifted left
|
||||
* by the number of bits specified by shiftValue. The least-significant bits of toAddr
|
||||
* offset should be 0's based upon the specified shiftValue since this value is shifted
|
||||
* right to calculate the base offset value.
|
||||
* @param shiftValue number of bits to shift
|
||||
* @param type reference type - how the location is being referenced
|
||||
* @param source the source of this reference
|
||||
* @param opIndex the operand index
|
||||
|
@ -122,19 +129,27 @@ public interface ReferenceManager {
|
|||
RefType type, SourceType source, int opIndex);
|
||||
|
||||
/**
|
||||
* Adds an external reference. If a reference already
|
||||
* exists for the fromAddr and opIndex, the existing reference is replaced
|
||||
* with the new reference.
|
||||
* @param fromAddr from address (source of the reference)
|
||||
* Adds an external reference to an external symbol. If a reference already
|
||||
* exists at {@code fromAddr} and {@code opIndex} the existing reference is replaced
|
||||
* with a new reference. If the external symbol cannot be found, a new {@link Library}
|
||||
* and/or {@link ExternalLocation} symbol will be created which corresponds to the specified
|
||||
* library/file named {@code libraryName}
|
||||
* and the location within that file identified by {@code extLabel} and/or its memory address
|
||||
* {@code extAddr}. Either or both {@code extLabel} or {@code extAddr} must be specified.
|
||||
*
|
||||
* @param fromAddr from memory address (source of the reference)
|
||||
* @param libraryName name of external program
|
||||
* @param extLabel label within the external program, may be null if extAddr is not null
|
||||
* @param extAddr address within the external program, may be null
|
||||
* @param extAddr memory address within the external program, may be null
|
||||
* @param source the source of this reference
|
||||
* @param opIndex operand index
|
||||
* @param type reference type - how the location is being referenced
|
||||
* @return new external space reference
|
||||
* @throws InvalidInputException
|
||||
* @throws DuplicateNameException
|
||||
* @throws InvalidInputException if {@code libraryName} is invalid or null, or an invalid
|
||||
* {@code extlabel} is specified. Names with spaces or the empty string are not permitted.
|
||||
* Neither {@code extLabel} nor {@code extAddr} was specified properly.
|
||||
* @throws DuplicateNameException if another non-Library namespace has the same name
|
||||
* @throws IllegalArgumentException if an invalid {@code extAddr} was specified.
|
||||
*/
|
||||
public Reference addExternalReference(Address fromAddr, String libraryName, String extLabel,
|
||||
Address extAddr, SourceType source, int opIndex, RefType type)
|
||||
|
@ -144,7 +159,8 @@ public interface ReferenceManager {
|
|||
* Adds an external reference. If a reference already
|
||||
* exists for the fromAddr and opIndex, the existing reference is replaced
|
||||
* with the new reference.
|
||||
* @param fromAddr from address (source of the reference)
|
||||
*
|
||||
* @param fromAddr from memory address (source of the reference)
|
||||
* @param extNamespace external namespace containing the named external label.
|
||||
* @param extLabel label within the external program, may be null if extAddr is not null
|
||||
* @param extAddr address within the external program, may be null
|
||||
|
@ -152,8 +168,11 @@ public interface ReferenceManager {
|
|||
* @param opIndex operand index
|
||||
* @param type reference type - how the location is being referenced
|
||||
* @return new external space reference
|
||||
* @throws InvalidInputException
|
||||
* @throws DuplicateNameException
|
||||
* @throws InvalidInputException if an invalid {@code extlabel} is specified.
|
||||
* Names with spaces or the empty string are not permitted.
|
||||
* Neither {@code extLabel} nor {@code extAddr} was specified properly.
|
||||
* @throws DuplicateNameException if another non-Library namespace has the same name
|
||||
* @throws IllegalArgumentException if an invalid {@code extAddr} was specified.
|
||||
*/
|
||||
public Reference addExternalReference(Address fromAddr, Namespace extNamespace, String extLabel,
|
||||
Address extAddr, SourceType source, int opIndex, RefType type)
|
||||
|
@ -163,7 +182,8 @@ public interface ReferenceManager {
|
|||
* Adds an external reference. If a reference already
|
||||
* exists for the fromAddr and opIndex, the existing reference is replaced
|
||||
* with the new reference.
|
||||
* @param fromAddr from address (source of the reference)
|
||||
*
|
||||
* @param fromAddr from memory address (source of the reference)
|
||||
* @param opIndex operand index
|
||||
* @param location external location
|
||||
* @param source the source of this reference
|
||||
|
|
|
@ -661,17 +661,22 @@ public interface ChangeManager {
|
|||
*/
|
||||
public final static int DOCR_FLOWOVERRIDE_CHANGED = 163;
|
||||
|
||||
/**
|
||||
* An instruction length override was changed for an instruction.
|
||||
*/
|
||||
public final static int DOCR_LENGTH_OVERRIDE_CHANGED = 164;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* A custom format for a data type was added.
|
||||
*/
|
||||
public final static int DOCR_CUSTOM_FORMAT_ADDED = 164;
|
||||
public final static int DOCR_CUSTOM_FORMAT_ADDED = 165;
|
||||
|
||||
/**
|
||||
* A custom format for a data type was removed.
|
||||
*/
|
||||
public final static int DOCR_CUSTOM_FORMAT_REMOVED = 165;
|
||||
public final static int DOCR_CUSTOM_FORMAT_REMOVED = 166;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
@ -682,17 +687,17 @@ public interface ChangeManager {
|
|||
/**
|
||||
* An AddressSetPropertyMap was added.
|
||||
*/
|
||||
public final static int DOCR_ADDRESS_SET_PROPERTY_MAP_ADDED = 166;
|
||||
public final static int DOCR_ADDRESS_SET_PROPERTY_MAP_ADDED = 167;
|
||||
|
||||
/**
|
||||
* An AddressSetPropertyMap was removed.
|
||||
*/
|
||||
public final static int DOCR_ADDRESS_SET_PROPERTY_MAP_REMOVED = 167;
|
||||
public final static int DOCR_ADDRESS_SET_PROPERTY_MAP_REMOVED = 168;
|
||||
|
||||
/**
|
||||
* An AddressSetPropertyMap was changed.
|
||||
*/
|
||||
public final static int DOCR_ADDRESS_SET_PROPERTY_MAP_CHANGED = 168;
|
||||
public final static int DOCR_ADDRESS_SET_PROPERTY_MAP_CHANGED = 169;
|
||||
|
||||
/**
|
||||
* An IntAddressSetPropertyMap was added.
|
||||
|
|
|
@ -72,10 +72,16 @@ public class InstructionUtils {
|
|||
textBuf.append(
|
||||
"\nConstructor Line #'s:\n" + getString(debug.getConstructorLineNumbers(), true))
|
||||
.append('\n');
|
||||
textBuf.append("\nByte Length : " + instruction.getLength());
|
||||
int len = instruction.getLength();
|
||||
textBuf.append("\nByte Length : " + len);
|
||||
if (instruction.isLengthOverridden()) {
|
||||
textBuf.append("\n >>> reflects length override, actual length is " +
|
||||
instruction.getParsedLength());
|
||||
}
|
||||
try {
|
||||
byte[] bytes = instruction.getParsedBytes();
|
||||
textBuf.append(
|
||||
"\nInstr Bytes : " + SleighDebugLogger.getFormattedBytes(instruction.getBytes()));
|
||||
"\nInstr Bytes : " + SleighDebugLogger.getFormattedBytes(bytes));
|
||||
textBuf.append("\nMask : " + debug.getFormattedInstructionMask(-1));
|
||||
textBuf.append("\nMasked Bytes: " + debug.getFormattedMaskedValue(-1)).append('\n');
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue