mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GT-2885 cleaned up and extended call/jump overrides
GT-2885: addressing code review GT-2885 improved auto comments for overriding refs GT-2885 more code review changes James_GT-2885 more code review changes GT-2885: reference cacheing and other code review changes GT-2885 more code review changes, added tests GT-2885 more code review changes
This commit is contained in:
parent
01c43efb2c
commit
df983e7bba
9 changed files with 1085 additions and 115 deletions
|
@ -17,8 +17,9 @@ package ghidra.app.util.viewer.field;
|
|||
|
||||
import java.awt.Color;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.widgets.fieldpanel.field.*;
|
||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
||||
|
@ -32,6 +33,8 @@ import ghidra.framework.options.ToolOptions;
|
|||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressOverflowException;
|
||||
import ghidra.program.model.listing.*;
|
||||
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.util.*;
|
||||
|
@ -154,49 +157,110 @@ public class PostCommentFieldFactory extends FieldFactory {
|
|||
}
|
||||
|
||||
private String[] getAutoPostComment(CodeUnit cu) {
|
||||
if (cu instanceof Instruction) {
|
||||
String fallthroughComment = null;
|
||||
String flowOverrideComment = null;
|
||||
int count = 0;
|
||||
Instruction instr = (Instruction) cu;
|
||||
|
||||
if (instr.isInDelaySlot()) {
|
||||
// ensure that auto-comment come from parent and are only placed after last
|
||||
// delay slot. Switch out inst with the parent instruction
|
||||
int delaySlotPosition = 0;
|
||||
while (instr.isInDelaySlot()) {
|
||||
++delaySlotPosition;
|
||||
instr = instr.getPrevious();
|
||||
}
|
||||
if (instr.getDelaySlotDepth() != delaySlotPosition) {
|
||||
return null; // not the last delay slot
|
||||
if (!(cu instanceof Instruction)) {
|
||||
return null;
|
||||
}
|
||||
Instruction instr = (Instruction) cu;
|
||||
LinkedList<String> comments = new LinkedList<>();
|
||||
|
||||
if (instr.isInDelaySlot()) {
|
||||
// ensure that auto-comment come from parent and are only placed after last
|
||||
// delay slot. Switch out inst with the parent instruction
|
||||
int delaySlotPosition = 0;
|
||||
while (instr.isInDelaySlot()) {
|
||||
++delaySlotPosition;
|
||||
instr = instr.getPrevious();
|
||||
}
|
||||
if (instr.getDelaySlotDepth() != delaySlotPosition) {
|
||||
return null; // not the last delay slot
|
||||
}
|
||||
}
|
||||
|
||||
if (instr.isFallThroughOverridden()) {
|
||||
Address fallThrough = instr.getFallThrough();
|
||||
String fallthroughComment = "-- Fallthrough Override: " +
|
||||
(fallThrough != null ? fallThrough.toString() : "NO-FALLTHROUGH");
|
||||
comments.addFirst(fallthroughComment);
|
||||
}
|
||||
FlowOverride flowOverride = instr.getFlowOverride();
|
||||
if (flowOverride != FlowOverride.NONE) {
|
||||
String flowOverrideComment =
|
||||
"-- Flow Override: " + flowOverride + " (" + instr.getFlowType().getName() + ")";
|
||||
comments.addFirst(flowOverrideComment);
|
||||
}
|
||||
|
||||
InstructionPcodeOverride pCodeOverride = new InstructionPcodeOverride(instr);
|
||||
|
||||
if (pCodeOverride.hasPotentialOverride()) {
|
||||
PcodeOp[] pcodeOps = instr.getPcode();
|
||||
OverrideCommentData overrideData = null;
|
||||
if (pCodeOverride.getPrimaryCallReference() == null) {
|
||||
overrideData = getOverrideCommentData(instr, RefType.CALL_OVERRIDE_UNCONDITIONAL,
|
||||
pcodeOps, pCodeOverride);
|
||||
if (overrideData != null) {
|
||||
String callOverrideComment =
|
||||
"-- Call Destination Override: " + getOverridingCommentDestString(
|
||||
overrideData.getOverridingRef(), instr.getProgram());
|
||||
comments.addFirst(callOverrideComment);
|
||||
}
|
||||
}
|
||||
|
||||
if (instr.isFallThroughOverridden()) {
|
||||
Address fallThrough = instr.getFallThrough();
|
||||
fallthroughComment = "-- Fallthrough Override: " +
|
||||
(fallThrough != null ? fallThrough.toString() : "NO-FALLTHROUGH");
|
||||
++count;
|
||||
overrideData = getOverrideCommentData(instr, RefType.JUMP_OVERRIDE_UNCONDITIONAL,
|
||||
pcodeOps, pCodeOverride);
|
||||
if (overrideData != null) {
|
||||
String jumpOverrideComment =
|
||||
"-- Jump Destination Override: " + getOverridingCommentDestString(
|
||||
overrideData.getOverridingRef(), instr.getProgram());
|
||||
comments.addFirst(jumpOverrideComment);
|
||||
}
|
||||
FlowOverride flowOverride = instr.getFlowOverride();
|
||||
if (flowOverride != FlowOverride.NONE) {
|
||||
flowOverrideComment = "-- Flow Override: " + flowOverride + " (" +
|
||||
instr.getFlowType().getName() + ")";
|
||||
++count;
|
||||
overrideData = getOverrideCommentData(instr, RefType.CALLOTHER_OVERRIDE_CALL, pcodeOps,
|
||||
pCodeOverride);
|
||||
if (overrideData != null) {
|
||||
String callOtherCallOverrideComment =
|
||||
"-- CALLOTHER(" + overrideData.getOverriddenCallOther() + ") Call Override: " +
|
||||
getOverridingCommentDestString(overrideData.getOverridingRef(),
|
||||
instr.getProgram());
|
||||
if (overrideData.hasMultipleCallOthers()) {
|
||||
callOtherCallOverrideComment += "\nWARNING: additional CALLOTHER ops present";
|
||||
}
|
||||
comments.addFirst(callOtherCallOverrideComment);
|
||||
}
|
||||
String[] autoComment = new String[count];
|
||||
if (fallthroughComment != null) {
|
||||
autoComment[--count] = fallthroughComment;
|
||||
else {
|
||||
overrideData =
|
||||
getOverrideCommentData(instr, RefType.CALLOTHER_OVERRIDE_JUMP, pcodeOps,
|
||||
pCodeOverride);
|
||||
if (overrideData != null) {
|
||||
String callOtherJumpOverrideComment =
|
||||
"-- CALLOTHER(" + overrideData.getOverriddenCallOther() +
|
||||
") Jump Override: " + getOverridingCommentDestString(
|
||||
overrideData.getOverridingRef(), instr.getProgram());
|
||||
if (overrideData.hasMultipleCallOthers()) {
|
||||
callOtherJumpOverrideComment +=
|
||||
"\nWARNING: additional CALLOTHER ops present";
|
||||
}
|
||||
comments.addFirst(callOtherJumpOverrideComment);
|
||||
}
|
||||
}
|
||||
if (flowOverrideComment != null) {
|
||||
autoComment[--count] = flowOverrideComment;
|
||||
}
|
||||
return autoComment;
|
||||
}
|
||||
if (comments.size() > 0) {
|
||||
return comments.toArray(new String[0]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getOverridingCommentDestString(Address address, Program program) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String symbol = program.getSymbolTable().getPrimarySymbol(address).getName(true);
|
||||
if (!StringUtils.isEmpty(symbol)) {
|
||||
sb.append(symbol);
|
||||
sb.append(" ");
|
||||
}
|
||||
sb.append("(");
|
||||
sb.append(address.toString());
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.app.util.viewer.field.FieldFactory#getProgramLocation(int, int, ghidra.app.util.viewer.field.ListingField)
|
||||
*/
|
||||
|
@ -412,7 +476,8 @@ public class PostCommentFieldFactory extends FieldFactory {
|
|||
// TODO: convoluted logic since str will not be user comment if useLinesAfterBlock is true
|
||||
int nLinesAutoComment =
|
||||
((comments.length == 0 && !useLinesAfterBlock) || alwaysShowAutomatic)
|
||||
? autoComment.length : 0;
|
||||
? autoComment.length
|
||||
: 0;
|
||||
if (!useLinesAfterBlock && comments.length == 0 && nLinesAutoComment == 0) {
|
||||
return null;
|
||||
}
|
||||
|
@ -497,4 +562,118 @@ public class PostCommentFieldFactory extends FieldFactory {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link InstructionPcodeOverride#getOverridingReference(RefType)}
|
||||
* See {@link ghidra.app.plugin.processors.sleigh.PcodeEmit#checkOverrides}
|
||||
* @param inst instruction
|
||||
* @param type reference type
|
||||
* @return {@link OverrideCommentData} object corresponding to override comment
|
||||
* ({@code null} if no override comment)
|
||||
*/
|
||||
private OverrideCommentData getOverrideCommentData(Instruction inst, RefType type,
|
||||
PcodeOp[] pcodeOps, PcodeOverride pcodeOverride) {
|
||||
//first, check whether the pcode corresponding to inst has an appropriate op
|
||||
Set<Integer> ops = new HashSet<>();
|
||||
if (type.equals(RefType.CALL_OVERRIDE_UNCONDITIONAL)) {
|
||||
ops.add(PcodeOp.CALL);
|
||||
ops.add(PcodeOp.CALLIND);
|
||||
}
|
||||
else if (type.equals(RefType.JUMP_OVERRIDE_UNCONDITIONAL)) {
|
||||
ops.add(PcodeOp.BRANCH);
|
||||
ops.add(PcodeOp.CBRANCH);
|
||||
}
|
||||
else if (type.equals(RefType.CALLOTHER_OVERRIDE_CALL) ||
|
||||
type.equals(RefType.CALLOTHER_OVERRIDE_JUMP)) {
|
||||
ops.add(PcodeOp.CALLOTHER);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean hasAppropriatePcodeOp = false;
|
||||
|
||||
//used to warn user that there are CALLOTHER ops at this instruction that are
|
||||
//not overridden
|
||||
boolean hasMultipleCallOthers = false;
|
||||
//used to report the name of the CALLOTHER op that is overridden
|
||||
String callOtherName = null;
|
||||
for (PcodeOp op : pcodeOps) {
|
||||
if (ops.contains(op.getOpcode())) {
|
||||
hasAppropriatePcodeOp = true;
|
||||
if (op.getOpcode() == PcodeOp.CALLOTHER) {
|
||||
if (callOtherName == null) {
|
||||
callOtherName = inst.getProgram().getLanguage().getUserDefinedOpName(
|
||||
(int) op.getInput(0).getOffset());
|
||||
}
|
||||
else {
|
||||
hasMultipleCallOthers = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasAppropriatePcodeOp) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//now check whether there is an active overriding reference of the appropriate type
|
||||
if (type.equals(RefType.CALL_OVERRIDE_UNCONDITIONAL)) {
|
||||
Address ref = pcodeOverride.getOverridingReference(type);
|
||||
if (ref != null) {
|
||||
return new OverrideCommentData(ref, null, false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (type.equals(RefType.JUMP_OVERRIDE_UNCONDITIONAL)) {
|
||||
Address ref = pcodeOverride.getOverridingReference(type);
|
||||
if (ref != null) {
|
||||
return new OverrideCommentData(ref, null, false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (type.equals(RefType.CALLOTHER_OVERRIDE_CALL)) {
|
||||
Address ref = pcodeOverride.getOverridingReference(type);
|
||||
if (ref != null) {
|
||||
return new OverrideCommentData(ref, callOtherName, hasMultipleCallOthers);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
//must be in the RefType.CALLOTHER_OVERRIDE_JUMP case
|
||||
Address ref = pcodeOverride.getOverridingReference(RefType.CALLOTHER_OVERRIDE_CALL);
|
||||
if (ref != null) {
|
||||
return null; //CALLOTHER_OVERRIDE_CALL overrides have precedence
|
||||
}
|
||||
ref = pcodeOverride.getOverridingReference(RefType.CALLOTHER_OVERRIDE_JUMP);
|
||||
if (ref == null) {
|
||||
return null;
|
||||
}
|
||||
return new OverrideCommentData(ref, callOtherName, hasMultipleCallOthers);
|
||||
|
||||
}
|
||||
|
||||
private class OverrideCommentData {
|
||||
private Address overridingRef;
|
||||
private String overriddenCallOther;
|
||||
private boolean hasMultipleCallOthers;
|
||||
|
||||
OverrideCommentData(Address overridingRef, String overriddenCallOther,
|
||||
boolean multipleCallOthers) {
|
||||
this.overridingRef = overridingRef;
|
||||
this.overriddenCallOther = overriddenCallOther;
|
||||
this.hasMultipleCallOthers = multipleCallOthers;
|
||||
}
|
||||
|
||||
Address getOverridingRef() {
|
||||
return overridingRef;
|
||||
}
|
||||
|
||||
String getOverriddenCallOther() {
|
||||
return overriddenCallOther;
|
||||
}
|
||||
|
||||
boolean hasMultipleCallOthers() {
|
||||
return hasMultipleCallOthers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import ghidra.program.database.ProgramDB;
|
|||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressFactory;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.test.*;
|
||||
|
||||
public class PostCommentFieldFactoryTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
@ -72,6 +73,41 @@ public class PostCommentFieldFactoryTest extends AbstractGhidraHeadedIntegration
|
|||
builder.createReturnInstruction("1001042");
|
||||
builder.disassemble("1001040", 1);
|
||||
|
||||
//create a function for testing jump override comments
|
||||
builder.createEmptyFunction("jump_override", "1003000", 100, null);
|
||||
builder.createConditionalJmpInstruction("1003000", "1003006");
|
||||
builder.createNOPInstruction("1003002", 4);
|
||||
builder.createReturnInstruction("1003006");
|
||||
builder.createReturnInstruction("1003008");
|
||||
|
||||
//create a function for testing indirect call override comments
|
||||
builder.createEmptyFunction("indirect_call_override", "1004000", 100, null);
|
||||
//call [r1]
|
||||
builder.setBytes("1004000", "f6 10");
|
||||
builder.disassemble("1004000", 2);
|
||||
builder.createReturnInstruction("1004002");
|
||||
|
||||
//create function for testing direct call override comments
|
||||
builder.createEmptyFunction("direct_call_override_backward_compatibility", "1005000", 10,
|
||||
null);
|
||||
builder.createEmptyFunction("call_dest_1", "1005020", 10, null);
|
||||
builder.createCallInstruction("1005000", "1005020");
|
||||
builder.createReturnInstruction("1005002");
|
||||
|
||||
//create function for testing that overrides only happen when there is exactly one
|
||||
//primary overriding reference (e.g., if there's a primary overriding ref on
|
||||
//both the mnemonic and an operand then no override
|
||||
builder.createEmptyFunction("only_one_primary_override_ref", "1006000", 10, null);
|
||||
builder.createEmptyFunction("call_dest_2", "1006020", 10, null);
|
||||
builder.createCallInstruction("1006000", "1006020");
|
||||
builder.createReturnInstruction("1006002");
|
||||
|
||||
//create function for testing overrides that don't actually change the destination
|
||||
builder.createEmptyFunction("override_without_dest_change", "1007000", 10, null);
|
||||
builder.createEmptyFunction("call_dest_3", "1007020", 10, null);
|
||||
builder.createCallInstruction("1007000", "1007020");
|
||||
builder.createReturnInstruction("1007002");
|
||||
|
||||
return builder.getProgram();
|
||||
}
|
||||
|
||||
|
@ -230,6 +266,430 @@ public class PostCommentFieldFactoryTest extends AbstractGhidraHeadedIntegration
|
|||
assertEquals(4, tf.getNumRows());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverridingJumpComment() {
|
||||
//test overriding a conditional jump to an unconditional jump
|
||||
//using a RefType.JUMP_OVERRIDE_UNCONDITIONAL reference
|
||||
ReferenceManager refManager = program.getReferenceManager();
|
||||
Reference ref1 = null;
|
||||
int transactionID = program.startTransaction("add_primary_jump_ref");
|
||||
try {
|
||||
ref1 = refManager.addMemoryReference(addr("1003000"), addr("1003006"),
|
||||
RefType.JUMP_OVERRIDE_UNCONDITIONAL, SourceType.ANALYSIS, Reference.MNEMONIC);
|
||||
refManager.setPrimary(ref1, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
|
||||
assertTrue(cb.goToField(addr("1003000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
ListingTextField tf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals("-- Jump Destination Override: LAB_01003006 (01003006)", tf.getText());
|
||||
|
||||
//test that making the reference non-primary removes the post comment
|
||||
ref1 = refManager.getPrimaryReferenceFrom(addr("1003000"), Reference.MNEMONIC);
|
||||
assertTrue(ref1.isPrimary());
|
||||
transactionID = program.startTransaction("set_ref_non_primary");
|
||||
try {
|
||||
refManager.setPrimary(ref1, false);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertFalse(cb.goToField(addr("1003000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
|
||||
//test that adding a second ref of the same type and setting it to primary
|
||||
//yields a new post comment
|
||||
transactionID = program.startTransaction("add_second_jump_ref");
|
||||
Reference ref2 = null;
|
||||
try {
|
||||
ref2 = refManager.addMemoryReference(addr("1003000"), addr("1003008"),
|
||||
RefType.JUMP_OVERRIDE_UNCONDITIONAL, SourceType.ANALYSIS, Reference.MNEMONIC);
|
||||
refManager.setPrimary(ref2, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertTrue(cb.goToField(addr("1003000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
tf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals("-- Jump Destination Override: LAB_01003008 (01003008)", tf.getText());
|
||||
|
||||
//test the swapping which reference is primary changes the post comment
|
||||
transactionID = program.startTransaction("swap_primary");
|
||||
try {
|
||||
refManager.setPrimary(ref2, false);
|
||||
refManager.setPrimary(ref1, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertTrue(cb.goToField(addr("1003000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
tf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals("-- Jump Destination Override: LAB_01003006 (01003006)", tf.getText());
|
||||
|
||||
//test that making all references non-primary removes the post comment
|
||||
transactionID = program.startTransaction("no_primary_refs");
|
||||
try {
|
||||
refManager.setPrimary(ref2, false);
|
||||
refManager.setPrimary(ref1, false);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertFalse(cb.goToField(addr("1003000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
|
||||
//test that the other overriding reference types don't add any post comments
|
||||
transactionID = program.startTransaction("add_overriding_call_ref");
|
||||
try {
|
||||
ref2 = refManager.addMemoryReference(addr("1003000"), addr("1004000"),
|
||||
RefType.CALL_OVERRIDE_UNCONDITIONAL, SourceType.ANALYSIS, Reference.MNEMONIC);
|
||||
refManager.setPrimary(ref2, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertFalse(cb.goToField(addr("1003000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
|
||||
transactionID = program.startTransaction("add_overriding_callother_call_ref");
|
||||
try {
|
||||
ref2 = refManager.addMemoryReference(addr("1003000"), addr("1004000"),
|
||||
RefType.CALLOTHER_OVERRIDE_CALL, SourceType.ANALYSIS, Reference.MNEMONIC);
|
||||
refManager.setPrimary(ref2, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertFalse(cb.goToField(addr("1003000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
|
||||
transactionID = program.startTransaction("add_overriding_callother_jump_ref");
|
||||
try {
|
||||
ref2 = refManager.addMemoryReference(addr("1003000"), addr("1003006"),
|
||||
RefType.CALLOTHER_OVERRIDE_JUMP, SourceType.ANALYSIS, Reference.MNEMONIC);
|
||||
refManager.setPrimary(ref2, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertFalse(cb.goToField(addr("1003000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
|
||||
//last test: test primary refs on mnemonic and operand 1
|
||||
//shouldn't work
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverridingIndirectCallComment() {
|
||||
//test that a primary RefType.CALL_OVERRIDE_UNCONDITIONAL reference on an indirect call
|
||||
//causes a post comment indicating that the call destination has been overridden
|
||||
ReferenceManager refManager = program.getReferenceManager();
|
||||
Reference ref1 = null;
|
||||
int transactionID = program.startTransaction("override indirect call");
|
||||
try {
|
||||
ref1 = refManager.addMemoryReference(addr("1004000"), addr("1003000"),
|
||||
RefType.CALL_OVERRIDE_UNCONDITIONAL, SourceType.ANALYSIS, Reference.MNEMONIC);
|
||||
refManager.setPrimary(ref1, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertTrue(cb.goToField(addr("1004000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
ListingTextField tf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals("-- Call Destination Override: jump_override (01003000)", tf.getText());
|
||||
|
||||
//test that making the reference non-primary remove the post comment
|
||||
ref1 = refManager.getPrimaryReferenceFrom(addr("1004000"), Reference.MNEMONIC);
|
||||
assertTrue(ref1.isPrimary());
|
||||
transactionID = program.startTransaction("set_ref_non_primary");
|
||||
try {
|
||||
refManager.setPrimary(ref1, false);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertFalse(cb.goToField(addr("1004000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
|
||||
//test that adding a second ref of the same type and setting it to primary
|
||||
//yields a new post comment
|
||||
transactionID = program.startTransaction("add_second_ref");
|
||||
Reference ref2 = null;
|
||||
try {
|
||||
ref2 = refManager.addMemoryReference(addr("1004000"), addr("1001000"),
|
||||
RefType.CALL_OVERRIDE_UNCONDITIONAL, SourceType.ANALYSIS, Reference.MNEMONIC);
|
||||
refManager.setPrimary(ref2, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertTrue(cb.goToField(addr("1004000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
tf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals("-- Call Destination Override: FUN_01001000 (01001000)", tf.getText());
|
||||
|
||||
//test the swapping which reference is primary changes the post comment
|
||||
transactionID = program.startTransaction("swap_primary");
|
||||
try {
|
||||
refManager.setPrimary(ref2, false);
|
||||
refManager.setPrimary(ref1, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertTrue(cb.goToField(addr("1004000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
tf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals("-- Call Destination Override: jump_override (01003000)", tf.getText());
|
||||
|
||||
//test that making all references non-primary removes the post comment
|
||||
transactionID = program.startTransaction("no_primary_refs");
|
||||
try {
|
||||
refManager.setPrimary(ref2, false);
|
||||
refManager.setPrimary(ref1, false);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertFalse(cb.goToField(addr("1004000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
|
||||
transactionID = program.startTransaction("add_overriding_jump_ref");
|
||||
try {
|
||||
ref2 = refManager.addMemoryReference(addr("1004000"), addr("1003008"),
|
||||
RefType.JUMP_OVERRIDE_UNCONDITIONAL, SourceType.ANALYSIS, Reference.MNEMONIC);
|
||||
refManager.setPrimary(ref2, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertFalse(cb.goToField(addr("1004000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
|
||||
transactionID = program.startTransaction("add_overriding_callother_call_ref");
|
||||
try {
|
||||
ref2 = refManager.addMemoryReference(addr("1004000"), addr("1003000"),
|
||||
RefType.CALLOTHER_OVERRIDE_CALL, SourceType.ANALYSIS, Reference.MNEMONIC);
|
||||
refManager.setPrimary(ref2, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertFalse(cb.goToField(addr("1004000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
|
||||
transactionID = program.startTransaction("add_overriding_callother_jump_ref");
|
||||
try {
|
||||
ref2 = refManager.addMemoryReference(addr("1004000"), addr("1003006"),
|
||||
RefType.CALLOTHER_OVERRIDE_JUMP, SourceType.ANALYSIS, Reference.MNEMONIC);
|
||||
refManager.setPrimary(ref2, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertFalse(cb.goToField(addr("1004000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverridingDirectCallAndBackwardCompatibility() {
|
||||
assertFalse(cb.goToField(addr("1005000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
ReferenceManager refManager = program.getReferenceManager();
|
||||
Reference defaultRef = refManager.getPrimaryReferenceFrom(addr("1005000"), 0);
|
||||
assertNotNull(defaultRef);
|
||||
Reference callOverride = null;
|
||||
int transactionID = program.startTransaction("add_overriding_callother_jump_ref");
|
||||
try {
|
||||
callOverride = refManager.addMemoryReference(addr("1005000"), addr("1003000"),
|
||||
RefType.CALL_OVERRIDE_UNCONDITIONAL, SourceType.ANALYSIS, Reference.MNEMONIC);
|
||||
refManager.setPrimary(callOverride, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
//there's a primary call-type reference on operand one, so the CALL_OVERRIDE_UNCONDITIONAL
|
||||
//override should *not* be active (this is testing backward compatibility)
|
||||
assertFalse(cb.goToField(addr("1005000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
|
||||
//now make defaultRef non-primary and verify that the postcomment from callOverride
|
||||
//shows up
|
||||
transactionID = program.startTransaction("de-primary default ref");
|
||||
try {
|
||||
refManager.setPrimary(defaultRef, false);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertTrue(cb.goToField(addr("1005000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
ListingTextField tf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals("-- Call Destination Override: jump_override (01003000)", tf.getText());
|
||||
|
||||
transactionID = program.startTransaction("set_ref_non_primary");
|
||||
try {
|
||||
refManager.setPrimary(callOverride, false);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertFalse(cb.goToField(addr("1005000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
|
||||
//test that adding a second ref of the same type and setting it to primary
|
||||
//yields a new post comment
|
||||
transactionID = program.startTransaction("add_second_ref");
|
||||
Reference ref2 = null;
|
||||
try {
|
||||
ref2 = refManager.addMemoryReference(addr("1005000"), addr("1001000"),
|
||||
RefType.CALL_OVERRIDE_UNCONDITIONAL, SourceType.ANALYSIS, Reference.MNEMONIC);
|
||||
refManager.setPrimary(ref2, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertTrue(cb.goToField(addr("1005000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
tf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals("-- Call Destination Override: FUN_01001000 (01001000)", tf.getText());
|
||||
|
||||
//test the swapping which reference is primary changes the post comment
|
||||
transactionID = program.startTransaction("swap_primary");
|
||||
try {
|
||||
refManager.setPrimary(ref2, false);
|
||||
refManager.setPrimary(callOverride, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertTrue(cb.goToField(addr("1005000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
tf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals("-- Call Destination Override: jump_override (01003000)", tf.getText());
|
||||
|
||||
//test that making all references non-primary removes the post comment
|
||||
transactionID = program.startTransaction("no_primary_refs");
|
||||
try {
|
||||
refManager.setPrimary(ref2, false);
|
||||
refManager.setPrimary(callOverride, false);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertFalse(cb.goToField(addr("1005000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
|
||||
//verify that JUMP_OVERRIDE_UNCONDITIONAL references and
|
||||
//CALLOTHER overriding references don't do anything
|
||||
transactionID = program.startTransaction("add_overriding_jump_ref");
|
||||
try {
|
||||
ref2 = refManager.addMemoryReference(addr("1005000"), addr("1003008"),
|
||||
RefType.JUMP_OVERRIDE_UNCONDITIONAL, SourceType.ANALYSIS, Reference.MNEMONIC);
|
||||
refManager.setPrimary(ref2, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertFalse(cb.goToField(addr("1005000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
|
||||
transactionID = program.startTransaction("add_overriding_callother_call_ref");
|
||||
try {
|
||||
ref2 = refManager.addMemoryReference(addr("1005000"), addr("1003000"),
|
||||
RefType.CALLOTHER_OVERRIDE_CALL, SourceType.ANALYSIS, Reference.MNEMONIC);
|
||||
refManager.setPrimary(ref2, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertFalse(cb.goToField(addr("1005000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
|
||||
transactionID = program.startTransaction("add_overriding_callother_jump_ref");
|
||||
try {
|
||||
ref2 = refManager.addMemoryReference(addr("1005000"), addr("1003006"),
|
||||
RefType.CALLOTHER_OVERRIDE_JUMP, SourceType.ANALYSIS, Reference.MNEMONIC);
|
||||
refManager.setPrimary(ref2, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertFalse(cb.goToField(addr("1005000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExactlyOnePrimaryOverridingRef() {
|
||||
assertFalse(cb.goToField(addr("1006000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
ReferenceManager refManager = program.getReferenceManager();
|
||||
Reference defaultRef = refManager.getPrimaryReferenceFrom(addr("1006000"), 0);
|
||||
assertNotNull(defaultRef);
|
||||
Reference callOverrideMnemonic = null;
|
||||
int transactionID =
|
||||
program.startTransaction("turn_off_existing_primary_ref_and_create_override_ref");
|
||||
try {
|
||||
refManager.setPrimary(defaultRef, false);
|
||||
callOverrideMnemonic = refManager.addMemoryReference(addr("1006000"), addr("1003000"),
|
||||
RefType.CALL_OVERRIDE_UNCONDITIONAL, SourceType.ANALYSIS, Reference.MNEMONIC);
|
||||
refManager.setPrimary(callOverrideMnemonic, true);
|
||||
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertTrue(cb.goToField(addr("1006000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
ListingTextField tf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals("-- Call Destination Override: jump_override (01003000)", tf.getText());
|
||||
Reference callOverrideOperand0 = null;
|
||||
transactionID = program.startTransaction("set_operand_ref_primary");
|
||||
try {
|
||||
callOverrideOperand0 = refManager.addMemoryReference(addr("1006000"), addr("1005020"),
|
||||
RefType.CALL_OVERRIDE_UNCONDITIONAL, SourceType.ANALYSIS, 0);
|
||||
refManager.setPrimary(callOverrideOperand0, true);
|
||||
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
//two primary override refs of same type, override should not take effect
|
||||
assertFalse(cb.goToField(addr("1006000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
transactionID = program.startTransaction("set_mnemonic_ref_non_primary");
|
||||
try {
|
||||
refManager.setPrimary(callOverrideMnemonic, false);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
//now there's only one primary overriding ref, so the override comment should be there
|
||||
assertTrue(cb.goToField(addr("1006000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
tf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals("-- Call Destination Override: call_dest_1 (01005020)", tf.getText());
|
||||
transactionID = program.startTransaction("set_operand_ref_non_primary");
|
||||
try {
|
||||
refManager.setPrimary(callOverrideOperand0, false);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
//no primary overriding refs, no override post comment
|
||||
assertFalse(cb.goToField(addr("1006000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverridingWithChangingDestination() {
|
||||
assertFalse(cb.goToField(addr("1007000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
ReferenceManager refManager = program.getReferenceManager();
|
||||
Reference defaultRef = refManager.getPrimaryReferenceFrom(addr("1007000"), 0);
|
||||
assertNotNull(defaultRef);
|
||||
Reference callOverrideMnemonic = null;
|
||||
int transactionID = program.startTransaction("override_without_changing_dest");
|
||||
try {
|
||||
refManager.setPrimary(defaultRef, false);
|
||||
callOverrideMnemonic = refManager.addMemoryReference(addr("1007000"), addr("1007020"),
|
||||
RefType.CALL_OVERRIDE_UNCONDITIONAL, SourceType.ANALYSIS, Reference.MNEMONIC);
|
||||
refManager.setPrimary(callOverrideMnemonic, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertTrue(cb.goToField(addr("1007000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
ListingTextField tf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals("-- Call Destination Override: call_dest_3 (01007020)", tf.getText());
|
||||
transactionID = program.startTransaction("turn_off_override");
|
||||
try {
|
||||
refManager.setPrimary(defaultRef, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
assertFalse(cb.goToField(addr("1007000"), PostCommentFieldFactory.FIELD_NAME, 0, 1));
|
||||
}
|
||||
|
||||
//TODO: test overriding CALLOTHER ops
|
||||
|
||||
private void setCommentInFunction(Function function, String comment) {
|
||||
CodeUnit cu = program.getListing().getCodeUnitAt(function.getEntryPoint());
|
||||
int transactionID = program.startTransaction("test");
|
||||
|
|
|
@ -29,6 +29,7 @@ import ghidra.program.model.listing.FlowOverride;
|
|||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.program.model.pcode.PcodeOverride;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
import ghidra.util.exception.NotYetImplementedException;
|
||||
|
||||
/**
|
||||
|
@ -738,42 +739,119 @@ public abstract class PcodeEmit {
|
|||
return opcode;
|
||||
}
|
||||
|
||||
//If there is an overriding reference on an indirect call, change the indirect
|
||||
//call to a direct call
|
||||
if (opcode == PcodeOp.CALLIND) {
|
||||
Address callRef = override.getOverridingCallReference();
|
||||
//If there is an overriding call reference on an indirect call, change it to
|
||||
//to a direct call, unless a call override has already been applied at this instruction
|
||||
if (opcode == PcodeOp.CALLIND && !override.isCallOverrideRefApplied()) {
|
||||
Address callRef = override.getOverridingReference(RefType.CALL_OVERRIDE_UNCONDITIONAL);
|
||||
if (callRef != null) {
|
||||
VarnodeData dest = in[0];
|
||||
dest.space = callRef.getAddressSpace();
|
||||
dest.offset = callRef.getOffset();
|
||||
dest.size = dest.space.getPointerSize();
|
||||
override.setCallOverrideRefApplied();
|
||||
return PcodeOp.CALL;
|
||||
}
|
||||
}
|
||||
|
||||
// Simple call reference override - use primary call reference as destination
|
||||
//CALLOTHER ops can be overridden with RefType.CALLOTHER_OVERRIDE_CALL
|
||||
//or RefType.CALLOTHER_OVERRIDE_JUMP
|
||||
//Call overrides take precedence over jump overrides
|
||||
//override at most one callother pcode op per native instruction
|
||||
boolean callOtherOverrideApplied = override.isCallOtherCallOverrideRefApplied() ||
|
||||
override.isCallOtherJumpOverrideApplied();
|
||||
if (opcode == PcodeOp.CALLOTHER && !callOtherOverrideApplied) {
|
||||
Address overrideRef = override.getOverridingReference(RefType.CALLOTHER_OVERRIDE_CALL);
|
||||
VarnodeData dest = in[0];
|
||||
if (overrideRef != null) {
|
||||
dest.space = overrideRef.getAddressSpace();
|
||||
dest.offset = overrideRef.getOffset();
|
||||
dest.size = dest.space.getPointerSize();
|
||||
override.setCallOtherCallOverrideRefApplied();
|
||||
return PcodeOp.CALL;
|
||||
}
|
||||
overrideRef = override.getOverridingReference(RefType.CALLOTHER_OVERRIDE_JUMP);
|
||||
if (overrideRef != null) {
|
||||
dest.space = overrideRef.getAddressSpace();
|
||||
dest.offset = overrideRef.getOffset();
|
||||
dest.size = dest.space.getPointerSize();
|
||||
override.setCallOtherJumpOverrideRefApplied();
|
||||
return PcodeOp.BRANCH;
|
||||
}
|
||||
}
|
||||
|
||||
// Simple call reference override - grab destination from appropriate reference
|
||||
// Only perform reference override if destination function does not have a call-fixup
|
||||
if (opcode == PcodeOp.CALL &&
|
||||
if (opcode == PcodeOp.CALL && !override.isCallOverrideRefApplied() &&
|
||||
!override.hasCallFixup(in[0].space.getAddress(in[0].offset))) {
|
||||
// Check for call reference (not supported if call-fixup exists for the instruction)
|
||||
Address callRef = override.getOverridingCallReference();
|
||||
if (callRef != null) {
|
||||
VarnodeData dest = in[0];
|
||||
VarnodeData dest = in[0];
|
||||
//call to override.getPrimaryCallReference kept for backward compatibility with
|
||||
//old call override mechanism
|
||||
//old mechanism has precedence over new
|
||||
Address callRef = override.getPrimaryCallReference();
|
||||
boolean overridingRef = false;
|
||||
if (callRef == null) {
|
||||
callRef = override.getOverridingReference(RefType.CALL_OVERRIDE_UNCONDITIONAL);
|
||||
overridingRef = true;
|
||||
}
|
||||
//every call instruction automatically has a call-type reference to the call target
|
||||
//we don't want these references to count as overrides - only count as an override
|
||||
//via explicitly changing the destination or using a CALL_OVERRIDE_UNCONDITIONAL reference
|
||||
if (callRef != null && (overridingRef || actualOverride(dest, callRef))) {
|
||||
dest.space = callRef.getAddressSpace();
|
||||
dest.offset = callRef.getOffset();
|
||||
dest.size = dest.space.getPointerSize();
|
||||
override.setCallOverrideRefApplied();
|
||||
return PcodeOp.CALL;
|
||||
}
|
||||
}
|
||||
|
||||
// Fall-through override - alter branch to next instruction
|
||||
if (fallOverride != null && (opcode == PcodeOp.CBRANCH || opcode == PcodeOp.BRANCH)) {
|
||||
//don't apply fallthrough overrides into the constant space
|
||||
if (in[0].space.getType() == AddressSpace.TYPE_CONSTANT) {
|
||||
return opcode;
|
||||
}
|
||||
VarnodeData dest = in[0];
|
||||
if (defaultFallAddress.getOffset() == dest.offset) {
|
||||
dest.space = fallOverride.getAddressSpace();
|
||||
dest.offset = fallOverride.getOffset();
|
||||
dest.size = dest.space.getPointerSize();
|
||||
}
|
||||
return opcode;
|
||||
}
|
||||
|
||||
//if there is an overriding jump reference, change a conditional jump to an
|
||||
//unconditional jump with the target given by the reference
|
||||
if ((opcode == PcodeOp.BRANCH || opcode == PcodeOp.CBRANCH) &&
|
||||
!override.isJumpOverrideRefApplied()) {
|
||||
//if the destination varnode is in the const space, it's a pcode-relative branch.
|
||||
//these should not be overridden
|
||||
if (in[0].space.getType() == AddressSpace.TYPE_CONSTANT) {
|
||||
return opcode;
|
||||
}
|
||||
Address overrideRef =
|
||||
override.getOverridingReference(RefType.JUMP_OVERRIDE_UNCONDITIONAL);
|
||||
if (overrideRef != null) {
|
||||
VarnodeData dest = in[0];
|
||||
dest.space = overrideRef.getAddressSpace();
|
||||
dest.offset = overrideRef.getOffset();
|
||||
dest.size = dest.space.getPointerSize();
|
||||
override.setJumpOverrideRefApplied();
|
||||
return PcodeOp.BRANCH;
|
||||
}
|
||||
}
|
||||
return opcode;
|
||||
}
|
||||
|
||||
// Used to check whether the address from a potentially overriding reference
|
||||
// actually changes the call destination
|
||||
private boolean actualOverride(VarnodeData data, Address addr) {
|
||||
if (!data.space.equals(addr.getAddressSpace())) {
|
||||
return true;
|
||||
}
|
||||
if (data.offset != addr.getOffset()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,6 +15,8 @@
|
|||
*/
|
||||
package ghidra.program.model.listing;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.UniqueAddressFactory;
|
||||
import ghidra.program.model.lang.*;
|
||||
|
@ -23,8 +24,6 @@ import ghidra.program.model.pcode.PcodeOp;
|
|||
import ghidra.program.model.symbol.FlowType;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Interface to define an instruction for a processor.
|
||||
*/
|
||||
|
|
|
@ -15,19 +15,49 @@
|
|||
*/
|
||||
package ghidra.program.model.listing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.plugin.processors.sleigh.PcodeEmit;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.InjectPayload;
|
||||
import ghidra.program.model.pcode.PcodeOverride;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
import ghidra.program.model.symbol.Reference;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class InstructionPcodeOverride implements PcodeOverride {
|
||||
|
||||
protected Instruction instr;
|
||||
private boolean callOverrideApplied = false;
|
||||
private boolean jumpOverrideApplied = false;
|
||||
private boolean callOtherCallOverrideApplied = false;
|
||||
private boolean callOtherJumpOverrideApplied = false;
|
||||
private Address primaryCallAddress = null;
|
||||
private List<Reference> primaryOverridingReferences;
|
||||
|
||||
/**
|
||||
* This constructor caches the primary and overriding "from" references of {@code instr}.
|
||||
* This cache is never updated; the assumption is that this object is short-lived
|
||||
* (duration of {@link PcodeEmit})
|
||||
* @param instr the instruction
|
||||
*/
|
||||
public InstructionPcodeOverride(Instruction instr) {
|
||||
this.instr = instr;
|
||||
|
||||
primaryOverridingReferences = new ArrayList<>();
|
||||
for (Reference ref : instr.getReferencesFrom()) {
|
||||
if (!ref.isPrimary()) {
|
||||
continue;
|
||||
}
|
||||
RefType type = ref.getReferenceType();
|
||||
if (type.isOverride()) {
|
||||
primaryOverridingReferences.add(ref);
|
||||
}
|
||||
else if (type.isCall() && primaryCallAddress == null) {
|
||||
primaryCallAddress = ref.getToAddress();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -51,14 +81,27 @@ public class InstructionPcodeOverride implements PcodeOverride {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Address getOverridingCallReference() {
|
||||
for (Reference ref : instr.getReferencesFrom()) {
|
||||
if (ref.getSource().equals(SourceType.USER_DEFINED) && ref.isPrimary() &&
|
||||
ref.getReferenceType().isCall()) {
|
||||
return ref.getToAddress();
|
||||
public Address getOverridingReference(RefType type) {
|
||||
if (!type.isOverride()) {
|
||||
return null;
|
||||
}
|
||||
Address overrideAddress = null;
|
||||
for (Reference ref : primaryOverridingReferences) {
|
||||
if (ref.getReferenceType().equals(type)) {
|
||||
if (overrideAddress == null) {
|
||||
overrideAddress = ref.getToAddress();
|
||||
}
|
||||
else {
|
||||
return null; //only allow one primary reference of each type
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return overrideAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getPrimaryCallReference() {
|
||||
return primaryCallAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,4 +132,52 @@ public class InstructionPcodeOverride implements PcodeOverride {
|
|||
}
|
||||
return fixup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallOverrideRefApplied() {
|
||||
callOverrideApplied = true;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCallOverrideRefApplied() {
|
||||
return callOverrideApplied;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setJumpOverrideRefApplied() {
|
||||
jumpOverrideApplied = true;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJumpOverrideRefApplied() {
|
||||
return jumpOverrideApplied;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallOtherCallOverrideRefApplied() {
|
||||
callOtherCallOverrideApplied = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCallOtherCallOverrideRefApplied() {
|
||||
return callOtherCallOverrideApplied;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallOtherJumpOverrideRefApplied() {
|
||||
callOtherJumpOverrideApplied = true;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCallOtherJumpOverrideApplied() {
|
||||
return callOtherJumpOverrideApplied;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPotentialOverride() {
|
||||
return !primaryOverridingReferences.isEmpty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ package ghidra.program.model.pcode;
|
|||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.InjectPayload;
|
||||
import ghidra.program.model.listing.FlowOverride;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
|
||||
public interface PcodeOverride {
|
||||
|
||||
|
@ -35,11 +35,12 @@ public interface PcodeOverride {
|
|||
FlowOverride getFlowOverride();
|
||||
|
||||
/**
|
||||
* Get the primary call reference address (whose {@link SourceType} must be {@link SourceType#USER_DEFINED})
|
||||
* from the current instruction
|
||||
* Get the primary overriding reference address of {@link RefType} {@code type} from
|
||||
* the current instruction
|
||||
* @param type type of reference
|
||||
* @return call reference address or null
|
||||
*/
|
||||
Address getOverridingCallReference();
|
||||
Address getOverridingReference(RefType type);
|
||||
|
||||
/**
|
||||
* Get the fall-through override address which may have been
|
||||
|
@ -66,4 +67,65 @@ public interface PcodeOverride {
|
|||
*/
|
||||
InjectPayload getCallFixup(Address callDestAddr);
|
||||
|
||||
/**
|
||||
* Register that a call override has been applied at the current instruction.
|
||||
*/
|
||||
void setCallOverrideRefApplied();
|
||||
|
||||
/**
|
||||
* Returns a boolean indicating whether a call override has been applied at the current instruction
|
||||
* @return has call override been applied
|
||||
*/
|
||||
boolean isCallOverrideRefApplied();
|
||||
|
||||
/**
|
||||
* Register that a jump override has been applied at the current instruction
|
||||
*/
|
||||
void setJumpOverrideRefApplied();
|
||||
|
||||
/**
|
||||
* Returns a boolean indicating whether a jump override has been applied at the current instruction
|
||||
* @return has jump override been applied
|
||||
*/
|
||||
boolean isJumpOverrideRefApplied();
|
||||
|
||||
/**
|
||||
* Register that a callother call override has been applied at the current instruction
|
||||
*/
|
||||
void setCallOtherCallOverrideRefApplied();
|
||||
|
||||
/**
|
||||
* Returns a boolean indicating whether a callother call override has been applied at the current
|
||||
* instruction
|
||||
* @return has callother call override been applied
|
||||
*/
|
||||
boolean isCallOtherCallOverrideRefApplied();
|
||||
|
||||
/**
|
||||
* Register that a callother jump override has been applied at the current instruction
|
||||
*/
|
||||
void setCallOtherJumpOverrideRefApplied();
|
||||
|
||||
/**
|
||||
* Returns a boolean indicating whether a callother jump override has been applied at the current
|
||||
* instruction
|
||||
* @return has callother jump override been applied
|
||||
*/
|
||||
boolean isCallOtherJumpOverrideApplied();
|
||||
|
||||
/**
|
||||
* Returns a boolean indicating whether there are any primary overriding references at the current
|
||||
* instruction
|
||||
* @return are there primary overriding references
|
||||
*/
|
||||
boolean hasPotentialOverride();
|
||||
|
||||
/**
|
||||
*
|
||||
* Get the primary call reference address from the current instruction
|
||||
* @return call reference address or null
|
||||
*/
|
||||
@Deprecated
|
||||
Address getPrimaryCallReference();
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -22,22 +21,81 @@ package ghidra.program.model.symbol;
|
|||
*/
|
||||
public final class FlowType extends RefType {
|
||||
|
||||
private final boolean hasFall;
|
||||
private final boolean hasFall;
|
||||
private final boolean isCall;
|
||||
private final boolean isJump;
|
||||
private final boolean isTeminal;
|
||||
private final boolean isTerminal;
|
||||
private final boolean isConditional;
|
||||
private final boolean isComputed;
|
||||
private final boolean isOverride;
|
||||
|
||||
protected FlowType(byte type, String name, boolean hasFall, boolean isCall, boolean isJump, boolean isTeminal, boolean isComputed, boolean isConditional) {
|
||||
super(type, name);
|
||||
this.hasFall = hasFall;
|
||||
this.isCall = isCall;
|
||||
this.isJump = isJump;
|
||||
this.isTeminal = isTeminal;
|
||||
this.isComputed = isComputed;
|
||||
this.isConditional = isConditional;
|
||||
}
|
||||
protected static class Builder {
|
||||
private byte type;
|
||||
private String name;
|
||||
|
||||
private boolean hasFall = false;
|
||||
private boolean isCall = false;
|
||||
private boolean isJump = false;
|
||||
private boolean isTerminal = false;
|
||||
private boolean isComputed = false;
|
||||
private boolean isConditional = false;
|
||||
private boolean isOverride = false;
|
||||
|
||||
protected Builder(byte type, String name) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
protected Builder setHasFall() {
|
||||
this.hasFall = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected Builder setIsCall() {
|
||||
this.isCall = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected Builder setIsJump() {
|
||||
this.isJump = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected Builder setIsTerminal() {
|
||||
this.isTerminal = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected Builder setIsComputed() {
|
||||
this.isComputed = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected Builder setIsConditional() {
|
||||
this.isConditional = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected Builder setIsOverride() {
|
||||
this.isOverride = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected FlowType build() {
|
||||
return new FlowType(this);
|
||||
}
|
||||
}
|
||||
|
||||
private FlowType(Builder builder) {
|
||||
super(builder.type, builder.name);
|
||||
this.hasFall = builder.hasFall;
|
||||
this.isCall = builder.isCall;
|
||||
this.isJump = builder.isJump;
|
||||
this.isTerminal = builder.isTerminal;
|
||||
this.isComputed = builder.isComputed;
|
||||
this.isConditional = builder.isConditional;
|
||||
this.isOverride = builder.isOverride;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFallthrough() {
|
||||
|
@ -71,7 +129,7 @@ public final class FlowType extends RefType {
|
|||
|
||||
@Override
|
||||
public boolean isTerminal() {
|
||||
return isTeminal;
|
||||
return isTerminal;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -79,4 +137,9 @@ public final class FlowType extends RefType {
|
|||
return !isConditional;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverride() {
|
||||
return isOverride;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -53,6 +53,12 @@ public abstract class RefType {
|
|||
static final byte __CONDITIONAL_CALL_TERMINATOR = 14;
|
||||
static final byte __COMPUTED_CALL_TERMINATOR = 15;
|
||||
|
||||
static final byte __CALL_OVERRIDE_UNCONDITIONAL = 16;
|
||||
static final byte __JUMP_OVERRIDE_UNCONDITIONAL = 17;
|
||||
|
||||
static final byte __CALLOTHER_OVERRIDE_CALL = 18;
|
||||
static final byte __CALLOTHER_OVERRIDE_JUMP = 19;
|
||||
|
||||
// DATA REFERENCE TYPES
|
||||
static final byte __UNKNOWNDATA = 100;
|
||||
static final byte __READ = 101;
|
||||
|
@ -72,44 +78,58 @@ public abstract class RefType {
|
|||
static final byte __DYNAMICDATA = 127;
|
||||
|
||||
public static final FlowType INVALID =
|
||||
new FlowType(__INVALID, "INVALID", true, false, false, false, false, false);
|
||||
new FlowType.Builder(__INVALID, "INVALID").setHasFall().build();
|
||||
public static final FlowType FLOW =
|
||||
new FlowType(__UNKNOWNFLOW, "FLOW", true, false, false, false, false, false);
|
||||
new FlowType.Builder(__UNKNOWNFLOW, "FLOW").setHasFall().build();
|
||||
public static final FlowType FALL_THROUGH =
|
||||
new FlowType(__FALL_THROUGH, "FALL_THROUGH", true, false, false, false, false, false);
|
||||
public static final FlowType UNCONDITIONAL_JUMP = new FlowType(__UNCONDITIONAL_JUMP,
|
||||
"UNCONDITIONAL_JUMP", false, false, true, false, false, false);
|
||||
public static final FlowType CONDITIONAL_JUMP =
|
||||
new FlowType(__CONDITIONAL_JUMP, "CONDITIONAL_JUMP", true, false, true, false, false, true);
|
||||
public static final FlowType UNCONDITIONAL_CALL = new FlowType(__UNCONDITIONAL_CALL,
|
||||
"UNCONDITIONAL_CALL", true, true, false, false, false, false);
|
||||
public static final FlowType CONDITIONAL_CALL =
|
||||
new FlowType(__CONDITIONAL_CALL, "CONDITIONAL_CALL", true, true, false, false, false, true);
|
||||
new FlowType.Builder(__FALL_THROUGH, "FALL_THROUGH").setHasFall().build();
|
||||
public static final FlowType UNCONDITIONAL_JUMP =
|
||||
new FlowType.Builder(__UNCONDITIONAL_JUMP, "UNCONDITIONAL_JUMP").setIsJump().build();
|
||||
public static final FlowType CONDITIONAL_JUMP = new FlowType.Builder(__CONDITIONAL_JUMP,
|
||||
"CONDITIONAL_JUMP").setHasFall().setIsJump().setIsConditional().build();
|
||||
public static final FlowType UNCONDITIONAL_CALL = new FlowType.Builder(__UNCONDITIONAL_CALL,
|
||||
"UNCONDITIONAL_CALL").setHasFall().setIsCall().build();
|
||||
public static final FlowType CONDITIONAL_CALL = new FlowType.Builder(__CONDITIONAL_CALL,
|
||||
"CONDITIONAL CALL").setHasFall().setIsCall().setIsConditional().build();
|
||||
public static final FlowType TERMINATOR =
|
||||
new FlowType(__TERMINATOR, "TERMINATOR", false, false, false, true, false, false);
|
||||
new FlowType.Builder(__TERMINATOR, "TERMINATOR").setIsTerminal().build();
|
||||
public static final FlowType COMPUTED_JUMP =
|
||||
new FlowType(__COMPUTED_JUMP, "COMPUTED_JUMP", false, false, true, false, true, false);
|
||||
public static final FlowType CONDITIONAL_TERMINATOR = new FlowType(__CONDITIONAL_TERMINATOR,
|
||||
"CONDITIONAL_TERMINATOR", true, false, false, true, false, true);
|
||||
public static final FlowType COMPUTED_CALL =
|
||||
new FlowType(__COMPUTED_CALL, "COMPUTED_CALL", true, true, false, false, true, false);
|
||||
public static final FlowType CALL_TERMINATOR =
|
||||
new FlowType(__CALL_TERMINATOR, "CALL_TERMINATOR", false, true, false, true, false, false);
|
||||
public static final FlowType COMPUTED_CALL_TERMINATOR = new FlowType(__COMPUTED_CALL_TERMINATOR,
|
||||
"COMPUTED_CALL_TERMINATOR", false, true, false, true, true, false);
|
||||
new FlowType.Builder(__COMPUTED_JUMP, "COMPUTED_JUMP").setIsJump().setIsComputed().build();
|
||||
public static final FlowType CONDITIONAL_TERMINATOR =
|
||||
new FlowType.Builder(__CONDITIONAL_TERMINATOR,
|
||||
"CONDITIONAL_TERMINATOR").setHasFall().setIsTerminal().setIsConditional().build();
|
||||
public static final FlowType COMPUTED_CALL = new FlowType.Builder(__COMPUTED_CALL,
|
||||
"COMPUTED_CALL").setHasFall().setIsCall().setIsComputed().build();
|
||||
public static final FlowType CALL_TERMINATOR = new FlowType.Builder(__CALL_TERMINATOR,
|
||||
"CALL_TERMINATOR").setIsCall().setIsTerminal().build();
|
||||
public static final FlowType COMPUTED_CALL_TERMINATOR =
|
||||
new FlowType.Builder(__COMPUTED_CALL_TERMINATOR,
|
||||
"COMPUTED_CALL_TERMINATOR").setIsCall().setIsTerminal().setIsComputed().build();
|
||||
public static final FlowType CONDITIONAL_CALL_TERMINATOR =
|
||||
new FlowType(__CONDITIONAL_CALL_TERMINATOR, "CONDITIONAL_CALL_TERMINATOR", false, true,
|
||||
false, true, false, true);
|
||||
public static final FlowType CONDITIONAL_COMPUTED_CALL =
|
||||
new FlowType(__CONDITIONAL_COMPUTED_CALL, "CONDITIONAL_COMPUTED_CALL", true, true, false,
|
||||
false, true, true);
|
||||
public static final FlowType CONDITIONAL_COMPUTED_JUMP =
|
||||
new FlowType(__CONDITIONAL_COMPUTED_JUMP, "CONDITIONAL_COMPUTED_JUMP", true, false, true,
|
||||
false, true, true);
|
||||
public static final FlowType JUMP_TERMINATOR =
|
||||
new FlowType(__JUMP_TERMINATOR, "JUMP TERMINATOR", false, false, true, true, false, false);
|
||||
new FlowType.Builder(__CONDITIONAL_CALL_TERMINATOR,
|
||||
"CONDITIONAL_CALL_TERMINATOR").setIsCall().setIsTerminal().setIsConditional().build();
|
||||
public static final FlowType CONDITIONAL_COMPUTED_CALL = new FlowType.Builder(
|
||||
__CONDITIONAL_COMPUTED_CALL,
|
||||
"CONDITIONAL_COMPUTED_CALL").setHasFall().setIsCall().setIsComputed().setIsConditional().build();
|
||||
public static final FlowType CONDITIONAL_COMPUTED_JUMP = new FlowType.Builder(
|
||||
__CONDITIONAL_COMPUTED_JUMP,
|
||||
"CONDITIONAL_COMPUTED_JUMP").setHasFall().setIsJump().setIsComputed().setIsConditional().build();
|
||||
public static final FlowType JUMP_TERMINATOR = new FlowType.Builder(__JUMP_TERMINATOR,
|
||||
"JUMP_TERMINATOR").setIsJump().setIsTerminal().build();
|
||||
public static final FlowType INDIRECTION =
|
||||
new FlowType(__INDIRECTION, "INDIRECTION", false, false, false, false, false, false);
|
||||
new FlowType.Builder(__INDIRECTION, "INDIRECTION").build();
|
||||
public static final FlowType CALL_OVERRIDE_UNCONDITIONAL =
|
||||
new FlowType.Builder(__CALL_OVERRIDE_UNCONDITIONAL,
|
||||
"CALL_OVERRIDE_UNCONDITIONAL").setHasFall().setIsCall().setIsOverride().build();
|
||||
public static final FlowType JUMP_OVERRIDE_UNCONDITIONAL =
|
||||
new FlowType.Builder(__JUMP_OVERRIDE_UNCONDITIONAL,
|
||||
"JUMP_OVERRIDE_UNCONDITIONAL").setIsJump().setIsOverride().build();
|
||||
public static final FlowType CALLOTHER_OVERRIDE_CALL =
|
||||
new FlowType.Builder(__CALLOTHER_OVERRIDE_CALL,
|
||||
"CALLOTHER_OVERRIDE_CALL").setHasFall().setIsCall().setIsOverride().build();
|
||||
public static final FlowType CALLOTHER_OVERRIDE_JUMP =
|
||||
new FlowType.Builder(__CALLOTHER_OVERRIDE_JUMP,
|
||||
"CALLOTHER_OVERRIDE_JUMP").setIsJump().setIsOverride().build();
|
||||
|
||||
/**
|
||||
* Reference type is unknown.
|
||||
|
@ -272,7 +292,7 @@ public abstract class RefType {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns true if the flow is a conditiona call or jump.
|
||||
* Returns true if the flow is a conditional call or jump.
|
||||
*/
|
||||
public boolean isConditional() {
|
||||
return false;
|
||||
|
@ -292,6 +312,14 @@ public abstract class RefType {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true precisely when the reference is an overriding reference
|
||||
*/
|
||||
public boolean isOverride() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
|
|
|
@ -77,6 +77,14 @@ public class RefTypeFactory {
|
|||
REFTYPE_LOOKUP_BY_TYPE_MAP.put(RefType.STACK_READ.getValue(), RefType.STACK_READ);
|
||||
REFTYPE_LOOKUP_BY_TYPE_MAP.put(RefType.STACK_WRITE.getValue(), RefType.STACK_WRITE);
|
||||
REFTYPE_LOOKUP_BY_TYPE_MAP.put(RefType.EXTERNAL_REF.getValue(), RefType.EXTERNAL_REF);
|
||||
REFTYPE_LOOKUP_BY_TYPE_MAP.put(RefType.__CALL_OVERRIDE_UNCONDITIONAL,
|
||||
RefType.CALL_OVERRIDE_UNCONDITIONAL);
|
||||
REFTYPE_LOOKUP_BY_TYPE_MAP.put(RefType.__JUMP_OVERRIDE_UNCONDITIONAL,
|
||||
RefType.JUMP_OVERRIDE_UNCONDITIONAL);
|
||||
REFTYPE_LOOKUP_BY_TYPE_MAP.put(RefType.__CALLOTHER_OVERRIDE_CALL,
|
||||
RefType.CALLOTHER_OVERRIDE_CALL);
|
||||
REFTYPE_LOOKUP_BY_TYPE_MAP.put(RefType.__CALLOTHER_OVERRIDE_JUMP,
|
||||
RefType.CALLOTHER_OVERRIDE_JUMP);
|
||||
}
|
||||
|
||||
private static RefType[] memoryRefTypes = new RefType[] { RefType.INDIRECTION,
|
||||
|
@ -84,7 +92,9 @@ public class RefTypeFactory {
|
|||
RefType.CONDITIONAL_JUMP, RefType.UNCONDITIONAL_CALL, RefType.UNCONDITIONAL_JUMP,
|
||||
RefType.CONDITIONAL_COMPUTED_CALL, RefType.CONDITIONAL_COMPUTED_JUMP, RefType.PARAM,
|
||||
RefType.DATA, RefType.DATA_IND, RefType.READ, RefType.READ_IND, RefType.WRITE,
|
||||
RefType.WRITE_IND, RefType.READ_WRITE, RefType.READ_WRITE_IND };
|
||||
RefType.WRITE_IND, RefType.READ_WRITE, RefType.READ_WRITE_IND,
|
||||
RefType.CALL_OVERRIDE_UNCONDITIONAL, RefType.JUMP_OVERRIDE_UNCONDITIONAL,
|
||||
RefType.CALLOTHER_OVERRIDE_CALL, RefType.CALLOTHER_OVERRIDE_JUMP };
|
||||
|
||||
private static HashSet<RefType> validMemRefTypes = new HashSet<>();
|
||||
static {
|
||||
|
@ -99,13 +109,13 @@ public class RefTypeFactory {
|
|||
private static RefType[] dataRefTypes = new RefType[] { RefType.DATA, RefType.PARAM,
|
||||
RefType.READ, RefType.WRITE, RefType.READ_WRITE, };
|
||||
|
||||
private static RefType[] extRefTypes = new RefType[] {
|
||||
// TODO: RefType.EXTERNAL_REF should be deprecated and RefType.DATA taking its place
|
||||
RefType.COMPUTED_CALL, RefType.COMPUTED_JUMP, RefType.CONDITIONAL_CALL,
|
||||
RefType.CONDITIONAL_JUMP, RefType.UNCONDITIONAL_CALL, RefType.UNCONDITIONAL_JUMP,
|
||||
RefType.CONDITIONAL_COMPUTED_CALL, RefType.CONDITIONAL_COMPUTED_JUMP, RefType.DATA,
|
||||
RefType.DATA_IND, RefType.READ, RefType.READ_IND, RefType.WRITE, RefType.WRITE_IND,
|
||||
RefType.READ_WRITE, RefType.READ_WRITE_IND };
|
||||
private static RefType[] extRefTypes =
|
||||
new RefType[] { RefType.COMPUTED_CALL, RefType.COMPUTED_JUMP, RefType.CONDITIONAL_CALL,
|
||||
RefType.CONDITIONAL_JUMP, RefType.UNCONDITIONAL_CALL, RefType.UNCONDITIONAL_JUMP,
|
||||
RefType.CONDITIONAL_COMPUTED_CALL, RefType.CONDITIONAL_COMPUTED_JUMP, RefType.DATA,
|
||||
RefType.DATA_IND, RefType.READ, RefType.READ_IND, RefType.WRITE, RefType.WRITE_IND,
|
||||
RefType.READ_WRITE, RefType.READ_WRITE_IND, RefType.CALL_OVERRIDE_UNCONDITIONAL,
|
||||
RefType.CALLOTHER_OVERRIDE_CALL, RefType.CALLOTHER_OVERRIDE_JUMP };
|
||||
|
||||
public static RefType[] getMemoryRefTypes() {
|
||||
return memoryRefTypes;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue