GP-3256 Added support for Instruction length-override

This commit is contained in:
ghidra1 2023-08-28 09:17:44 -04:00
parent a820a36e94
commit aefb7f2aed
67 changed files with 1895 additions and 574 deletions

View file

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

View file

@ -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);

View file

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

View file

@ -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

View file

@ -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

View file

@ -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();

View file

@ -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();

View file

@ -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) {

View file

@ -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.

View file

@ -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());

View file

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

View file

@ -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]);
}

View file

@ -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.

View file

@ -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();

View file

@ -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();

View file

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

View file

@ -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();

View file

@ -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,

View file

@ -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();
}

View file

@ -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)

View file

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

View file

@ -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

View file

@ -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.

View file

@ -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');
}