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:
James 2019-05-17 14:52:44 -04:00
parent 01c43efb2c
commit df983e7bba
9 changed files with 1085 additions and 115 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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