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.awt.Color;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import docking.widgets.fieldpanel.field.*;
|
import docking.widgets.fieldpanel.field.*;
|
||||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
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.Address;
|
||||||
import ghidra.program.model.address.AddressOverflowException;
|
import ghidra.program.model.address.AddressOverflowException;
|
||||||
import ghidra.program.model.listing.*;
|
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.FlowType;
|
||||||
import ghidra.program.model.symbol.RefType;
|
import ghidra.program.model.symbol.RefType;
|
||||||
import ghidra.program.util.*;
|
import ghidra.program.util.*;
|
||||||
|
@ -154,49 +157,110 @@ public class PostCommentFieldFactory extends FieldFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] getAutoPostComment(CodeUnit cu) {
|
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()) {
|
if (!(cu instanceof Instruction)) {
|
||||||
// ensure that auto-comment come from parent and are only placed after last
|
return null;
|
||||||
// delay slot. Switch out inst with the parent instruction
|
}
|
||||||
int delaySlotPosition = 0;
|
Instruction instr = (Instruction) cu;
|
||||||
while (instr.isInDelaySlot()) {
|
LinkedList<String> comments = new LinkedList<>();
|
||||||
++delaySlotPosition;
|
|
||||||
instr = instr.getPrevious();
|
if (instr.isInDelaySlot()) {
|
||||||
}
|
// ensure that auto-comment come from parent and are only placed after last
|
||||||
if (instr.getDelaySlotDepth() != delaySlotPosition) {
|
// delay slot. Switch out inst with the parent instruction
|
||||||
return null; // not the last delay slot
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
overrideData = getOverrideCommentData(instr, RefType.JUMP_OVERRIDE_UNCONDITIONAL,
|
||||||
if (instr.isFallThroughOverridden()) {
|
pcodeOps, pCodeOverride);
|
||||||
Address fallThrough = instr.getFallThrough();
|
if (overrideData != null) {
|
||||||
fallthroughComment = "-- Fallthrough Override: " +
|
String jumpOverrideComment =
|
||||||
(fallThrough != null ? fallThrough.toString() : "NO-FALLTHROUGH");
|
"-- Jump Destination Override: " + getOverridingCommentDestString(
|
||||||
++count;
|
overrideData.getOverridingRef(), instr.getProgram());
|
||||||
|
comments.addFirst(jumpOverrideComment);
|
||||||
}
|
}
|
||||||
FlowOverride flowOverride = instr.getFlowOverride();
|
overrideData = getOverrideCommentData(instr, RefType.CALLOTHER_OVERRIDE_CALL, pcodeOps,
|
||||||
if (flowOverride != FlowOverride.NONE) {
|
pCodeOverride);
|
||||||
flowOverrideComment = "-- Flow Override: " + flowOverride + " (" +
|
if (overrideData != null) {
|
||||||
instr.getFlowType().getName() + ")";
|
String callOtherCallOverrideComment =
|
||||||
++count;
|
"-- 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];
|
else {
|
||||||
if (fallthroughComment != null) {
|
overrideData =
|
||||||
autoComment[--count] = fallthroughComment;
|
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;
|
if (comments.size() > 0) {
|
||||||
}
|
return comments.toArray(new String[0]);
|
||||||
return autoComment;
|
|
||||||
}
|
}
|
||||||
return null;
|
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)
|
* @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
|
// TODO: convoluted logic since str will not be user comment if useLinesAfterBlock is true
|
||||||
int nLinesAutoComment =
|
int nLinesAutoComment =
|
||||||
((comments.length == 0 && !useLinesAfterBlock) || alwaysShowAutomatic)
|
((comments.length == 0 && !useLinesAfterBlock) || alwaysShowAutomatic)
|
||||||
? autoComment.length : 0;
|
? autoComment.length
|
||||||
|
: 0;
|
||||||
if (!useLinesAfterBlock && comments.length == 0 && nLinesAutoComment == 0) {
|
if (!useLinesAfterBlock && comments.length == 0 && nLinesAutoComment == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -497,4 +562,118 @@ public class PostCommentFieldFactory extends FieldFactory {
|
||||||
return null;
|
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.Address;
|
||||||
import ghidra.program.model.address.AddressFactory;
|
import ghidra.program.model.address.AddressFactory;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.test.*;
|
import ghidra.test.*;
|
||||||
|
|
||||||
public class PostCommentFieldFactoryTest extends AbstractGhidraHeadedIntegrationTest {
|
public class PostCommentFieldFactoryTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
@ -72,6 +73,41 @@ public class PostCommentFieldFactoryTest extends AbstractGhidraHeadedIntegration
|
||||||
builder.createReturnInstruction("1001042");
|
builder.createReturnInstruction("1001042");
|
||||||
builder.disassemble("1001040", 1);
|
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();
|
return builder.getProgram();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,6 +266,430 @@ public class PostCommentFieldFactoryTest extends AbstractGhidraHeadedIntegration
|
||||||
assertEquals(4, tf.getNumRows());
|
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) {
|
private void setCommentInFunction(Function function, String comment) {
|
||||||
CodeUnit cu = program.getListing().getCodeUnitAt(function.getEntryPoint());
|
CodeUnit cu = program.getListing().getCodeUnitAt(function.getEntryPoint());
|
||||||
int transactionID = program.startTransaction("test");
|
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.mem.MemoryAccessException;
|
||||||
import ghidra.program.model.pcode.PcodeOp;
|
import ghidra.program.model.pcode.PcodeOp;
|
||||||
import ghidra.program.model.pcode.PcodeOverride;
|
import ghidra.program.model.pcode.PcodeOverride;
|
||||||
|
import ghidra.program.model.symbol.RefType;
|
||||||
import ghidra.util.exception.NotYetImplementedException;
|
import ghidra.util.exception.NotYetImplementedException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -738,42 +739,119 @@ public abstract class PcodeEmit {
|
||||||
return opcode;
|
return opcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
//If there is an overriding reference on an indirect call, change the indirect
|
//If there is an overriding call reference on an indirect call, change it to
|
||||||
//call to a direct call
|
//to a direct call, unless a call override has already been applied at this instruction
|
||||||
if (opcode == PcodeOp.CALLIND) {
|
if (opcode == PcodeOp.CALLIND && !override.isCallOverrideRefApplied()) {
|
||||||
Address callRef = override.getOverridingCallReference();
|
Address callRef = override.getOverridingReference(RefType.CALL_OVERRIDE_UNCONDITIONAL);
|
||||||
if (callRef != null) {
|
if (callRef != null) {
|
||||||
VarnodeData dest = in[0];
|
VarnodeData dest = in[0];
|
||||||
dest.space = callRef.getAddressSpace();
|
dest.space = callRef.getAddressSpace();
|
||||||
dest.offset = callRef.getOffset();
|
dest.offset = callRef.getOffset();
|
||||||
dest.size = dest.space.getPointerSize();
|
dest.size = dest.space.getPointerSize();
|
||||||
|
override.setCallOverrideRefApplied();
|
||||||
return PcodeOp.CALL;
|
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
|
// 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))) {
|
!override.hasCallFixup(in[0].space.getAddress(in[0].offset))) {
|
||||||
// Check for call reference (not supported if call-fixup exists for the instruction)
|
VarnodeData dest = in[0];
|
||||||
Address callRef = override.getOverridingCallReference();
|
//call to override.getPrimaryCallReference kept for backward compatibility with
|
||||||
if (callRef != null) {
|
//old call override mechanism
|
||||||
VarnodeData dest = in[0];
|
//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.space = callRef.getAddressSpace();
|
||||||
dest.offset = callRef.getOffset();
|
dest.offset = callRef.getOffset();
|
||||||
dest.size = dest.space.getPointerSize();
|
dest.size = dest.space.getPointerSize();
|
||||||
|
override.setCallOverrideRefApplied();
|
||||||
|
return PcodeOp.CALL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fall-through override - alter branch to next instruction
|
// Fall-through override - alter branch to next instruction
|
||||||
if (fallOverride != null && (opcode == PcodeOp.CBRANCH || opcode == PcodeOp.BRANCH)) {
|
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];
|
VarnodeData dest = in[0];
|
||||||
if (defaultFallAddress.getOffset() == dest.offset) {
|
if (defaultFallAddress.getOffset() == dest.offset) {
|
||||||
dest.space = fallOverride.getAddressSpace();
|
dest.space = fallOverride.getAddressSpace();
|
||||||
dest.offset = fallOverride.getOffset();
|
dest.offset = fallOverride.getOffset();
|
||||||
dest.size = dest.space.getPointerSize();
|
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;
|
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
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.program.model.listing;
|
package ghidra.program.model.listing;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.UniqueAddressFactory;
|
import ghidra.program.model.address.UniqueAddressFactory;
|
||||||
import ghidra.program.model.lang.*;
|
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.FlowType;
|
||||||
import ghidra.program.model.symbol.RefType;
|
import ghidra.program.model.symbol.RefType;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface to define an instruction for a processor.
|
* Interface to define an instruction for a processor.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -15,19 +15,49 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.program.model.listing;
|
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.address.Address;
|
||||||
import ghidra.program.model.lang.InjectPayload;
|
import ghidra.program.model.lang.InjectPayload;
|
||||||
import ghidra.program.model.pcode.PcodeOverride;
|
import ghidra.program.model.pcode.PcodeOverride;
|
||||||
|
import ghidra.program.model.symbol.RefType;
|
||||||
import ghidra.program.model.symbol.Reference;
|
import ghidra.program.model.symbol.Reference;
|
||||||
import ghidra.program.model.symbol.SourceType;
|
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
public class InstructionPcodeOverride implements PcodeOverride {
|
public class InstructionPcodeOverride implements PcodeOverride {
|
||||||
|
|
||||||
protected Instruction instr;
|
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) {
|
public InstructionPcodeOverride(Instruction instr) {
|
||||||
this.instr = 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
|
@Override
|
||||||
|
@ -51,14 +81,27 @@ public class InstructionPcodeOverride implements PcodeOverride {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getOverridingCallReference() {
|
public Address getOverridingReference(RefType type) {
|
||||||
for (Reference ref : instr.getReferencesFrom()) {
|
if (!type.isOverride()) {
|
||||||
if (ref.getSource().equals(SourceType.USER_DEFINED) && ref.isPrimary() &&
|
return null;
|
||||||
ref.getReferenceType().isCall()) {
|
}
|
||||||
return ref.getToAddress();
|
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
|
@Override
|
||||||
|
@ -89,4 +132,52 @@ public class InstructionPcodeOverride implements PcodeOverride {
|
||||||
}
|
}
|
||||||
return fixup;
|
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.address.Address;
|
||||||
import ghidra.program.model.lang.InjectPayload;
|
import ghidra.program.model.lang.InjectPayload;
|
||||||
import ghidra.program.model.listing.FlowOverride;
|
import ghidra.program.model.listing.FlowOverride;
|
||||||
import ghidra.program.model.symbol.SourceType;
|
import ghidra.program.model.symbol.RefType;
|
||||||
|
|
||||||
public interface PcodeOverride {
|
public interface PcodeOverride {
|
||||||
|
|
||||||
|
@ -35,11 +35,12 @@ public interface PcodeOverride {
|
||||||
FlowOverride getFlowOverride();
|
FlowOverride getFlowOverride();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the primary call reference address (whose {@link SourceType} must be {@link SourceType#USER_DEFINED})
|
* Get the primary overriding reference address of {@link RefType} {@code type} from
|
||||||
* from the current instruction
|
* the current instruction
|
||||||
|
* @param type type of reference
|
||||||
* @return call reference address or null
|
* @return call reference address or null
|
||||||
*/
|
*/
|
||||||
Address getOverridingCallReference();
|
Address getOverridingReference(RefType type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the fall-through override address which may have been
|
* Get the fall-through override address which may have been
|
||||||
|
@ -66,4 +67,65 @@ public interface PcodeOverride {
|
||||||
*/
|
*/
|
||||||
InjectPayload getCallFixup(Address callDestAddr);
|
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
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -21,23 +20,82 @@ package ghidra.program.model.symbol;
|
||||||
* flows from one instruction to the next)
|
* flows from one instruction to the next)
|
||||||
*/
|
*/
|
||||||
public final class FlowType extends RefType {
|
public final class FlowType extends RefType {
|
||||||
|
|
||||||
private final boolean hasFall;
|
private final boolean hasFall;
|
||||||
private final boolean isCall;
|
private final boolean isCall;
|
||||||
private final boolean isJump;
|
private final boolean isJump;
|
||||||
private final boolean isTeminal;
|
private final boolean isTerminal;
|
||||||
private final boolean isConditional;
|
private final boolean isConditional;
|
||||||
private final boolean isComputed;
|
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) {
|
protected static class Builder {
|
||||||
super(type, name);
|
private byte type;
|
||||||
this.hasFall = hasFall;
|
private String name;
|
||||||
this.isCall = isCall;
|
|
||||||
this.isJump = isJump;
|
private boolean hasFall = false;
|
||||||
this.isTeminal = isTeminal;
|
private boolean isCall = false;
|
||||||
this.isComputed = isComputed;
|
private boolean isJump = false;
|
||||||
this.isConditional = isConditional;
|
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
|
@Override
|
||||||
public boolean hasFallthrough() {
|
public boolean hasFallthrough() {
|
||||||
|
@ -71,7 +129,7 @@ public final class FlowType extends RefType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTerminal() {
|
public boolean isTerminal() {
|
||||||
return isTeminal;
|
return isTerminal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -79,4 +137,9 @@ public final class FlowType extends RefType {
|
||||||
return !isConditional;
|
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 __CONDITIONAL_CALL_TERMINATOR = 14;
|
||||||
static final byte __COMPUTED_CALL_TERMINATOR = 15;
|
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
|
// DATA REFERENCE TYPES
|
||||||
static final byte __UNKNOWNDATA = 100;
|
static final byte __UNKNOWNDATA = 100;
|
||||||
static final byte __READ = 101;
|
static final byte __READ = 101;
|
||||||
|
@ -72,44 +78,58 @@ public abstract class RefType {
|
||||||
static final byte __DYNAMICDATA = 127;
|
static final byte __DYNAMICDATA = 127;
|
||||||
|
|
||||||
public static final FlowType INVALID =
|
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 =
|
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 =
|
public static final FlowType FALL_THROUGH =
|
||||||
new FlowType(__FALL_THROUGH, "FALL_THROUGH", true, false, false, false, false, false);
|
new FlowType.Builder(__FALL_THROUGH, "FALL_THROUGH").setHasFall().build();
|
||||||
public static final FlowType UNCONDITIONAL_JUMP = new FlowType(__UNCONDITIONAL_JUMP,
|
public static final FlowType UNCONDITIONAL_JUMP =
|
||||||
"UNCONDITIONAL_JUMP", false, false, true, false, false, false);
|
new FlowType.Builder(__UNCONDITIONAL_JUMP, "UNCONDITIONAL_JUMP").setIsJump().build();
|
||||||
public static final FlowType CONDITIONAL_JUMP =
|
public static final FlowType CONDITIONAL_JUMP = new FlowType.Builder(__CONDITIONAL_JUMP,
|
||||||
new FlowType(__CONDITIONAL_JUMP, "CONDITIONAL_JUMP", true, false, true, false, false, true);
|
"CONDITIONAL_JUMP").setHasFall().setIsJump().setIsConditional().build();
|
||||||
public static final FlowType UNCONDITIONAL_CALL = new FlowType(__UNCONDITIONAL_CALL,
|
public static final FlowType UNCONDITIONAL_CALL = new FlowType.Builder(__UNCONDITIONAL_CALL,
|
||||||
"UNCONDITIONAL_CALL", true, true, false, false, false, false);
|
"UNCONDITIONAL_CALL").setHasFall().setIsCall().build();
|
||||||
public static final FlowType CONDITIONAL_CALL =
|
public static final FlowType CONDITIONAL_CALL = new FlowType.Builder(__CONDITIONAL_CALL,
|
||||||
new FlowType(__CONDITIONAL_CALL, "CONDITIONAL_CALL", true, true, false, false, false, true);
|
"CONDITIONAL CALL").setHasFall().setIsCall().setIsConditional().build();
|
||||||
public static final FlowType TERMINATOR =
|
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 =
|
public static final FlowType COMPUTED_JUMP =
|
||||||
new FlowType(__COMPUTED_JUMP, "COMPUTED_JUMP", false, false, true, false, true, false);
|
new FlowType.Builder(__COMPUTED_JUMP, "COMPUTED_JUMP").setIsJump().setIsComputed().build();
|
||||||
public static final FlowType CONDITIONAL_TERMINATOR = new FlowType(__CONDITIONAL_TERMINATOR,
|
public static final FlowType CONDITIONAL_TERMINATOR =
|
||||||
"CONDITIONAL_TERMINATOR", true, false, false, true, false, true);
|
new FlowType.Builder(__CONDITIONAL_TERMINATOR,
|
||||||
public static final FlowType COMPUTED_CALL =
|
"CONDITIONAL_TERMINATOR").setHasFall().setIsTerminal().setIsConditional().build();
|
||||||
new FlowType(__COMPUTED_CALL, "COMPUTED_CALL", true, true, false, false, true, false);
|
public static final FlowType COMPUTED_CALL = new FlowType.Builder(__COMPUTED_CALL,
|
||||||
public static final FlowType CALL_TERMINATOR =
|
"COMPUTED_CALL").setHasFall().setIsCall().setIsComputed().build();
|
||||||
new FlowType(__CALL_TERMINATOR, "CALL_TERMINATOR", false, true, false, true, false, false);
|
public static final FlowType CALL_TERMINATOR = new FlowType.Builder(__CALL_TERMINATOR,
|
||||||
public static final FlowType COMPUTED_CALL_TERMINATOR = new FlowType(__COMPUTED_CALL_TERMINATOR,
|
"CALL_TERMINATOR").setIsCall().setIsTerminal().build();
|
||||||
"COMPUTED_CALL_TERMINATOR", false, true, false, true, true, false);
|
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 =
|
public static final FlowType CONDITIONAL_CALL_TERMINATOR =
|
||||||
new FlowType(__CONDITIONAL_CALL_TERMINATOR, "CONDITIONAL_CALL_TERMINATOR", false, true,
|
new FlowType.Builder(__CONDITIONAL_CALL_TERMINATOR,
|
||||||
false, true, false, true);
|
"CONDITIONAL_CALL_TERMINATOR").setIsCall().setIsTerminal().setIsConditional().build();
|
||||||
public static final FlowType CONDITIONAL_COMPUTED_CALL =
|
public static final FlowType CONDITIONAL_COMPUTED_CALL = new FlowType.Builder(
|
||||||
new FlowType(__CONDITIONAL_COMPUTED_CALL, "CONDITIONAL_COMPUTED_CALL", true, true, false,
|
__CONDITIONAL_COMPUTED_CALL,
|
||||||
false, true, true);
|
"CONDITIONAL_COMPUTED_CALL").setHasFall().setIsCall().setIsComputed().setIsConditional().build();
|
||||||
public static final FlowType CONDITIONAL_COMPUTED_JUMP =
|
public static final FlowType CONDITIONAL_COMPUTED_JUMP = new FlowType.Builder(
|
||||||
new FlowType(__CONDITIONAL_COMPUTED_JUMP, "CONDITIONAL_COMPUTED_JUMP", true, false, true,
|
__CONDITIONAL_COMPUTED_JUMP,
|
||||||
false, true, true);
|
"CONDITIONAL_COMPUTED_JUMP").setHasFall().setIsJump().setIsComputed().setIsConditional().build();
|
||||||
public static final FlowType JUMP_TERMINATOR =
|
public static final FlowType JUMP_TERMINATOR = new FlowType.Builder(__JUMP_TERMINATOR,
|
||||||
new FlowType(__JUMP_TERMINATOR, "JUMP TERMINATOR", false, false, true, true, false, false);
|
"JUMP_TERMINATOR").setIsJump().setIsTerminal().build();
|
||||||
public static final FlowType INDIRECTION =
|
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.
|
* 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() {
|
public boolean isConditional() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -292,6 +312,14 @@ public abstract class RefType {
|
||||||
return false;
|
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)
|
* @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_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.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.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,
|
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_JUMP, RefType.UNCONDITIONAL_CALL, RefType.UNCONDITIONAL_JUMP,
|
||||||
RefType.CONDITIONAL_COMPUTED_CALL, RefType.CONDITIONAL_COMPUTED_JUMP, RefType.PARAM,
|
RefType.CONDITIONAL_COMPUTED_CALL, RefType.CONDITIONAL_COMPUTED_JUMP, RefType.PARAM,
|
||||||
RefType.DATA, RefType.DATA_IND, RefType.READ, RefType.READ_IND, RefType.WRITE,
|
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<>();
|
private static HashSet<RefType> validMemRefTypes = new HashSet<>();
|
||||||
static {
|
static {
|
||||||
|
@ -99,13 +109,13 @@ public class RefTypeFactory {
|
||||||
private static RefType[] dataRefTypes = new RefType[] { RefType.DATA, RefType.PARAM,
|
private static RefType[] dataRefTypes = new RefType[] { RefType.DATA, RefType.PARAM,
|
||||||
RefType.READ, RefType.WRITE, RefType.READ_WRITE, };
|
RefType.READ, RefType.WRITE, RefType.READ_WRITE, };
|
||||||
|
|
||||||
private static RefType[] extRefTypes = new RefType[] {
|
private static RefType[] extRefTypes =
|
||||||
// TODO: RefType.EXTERNAL_REF should be deprecated and RefType.DATA taking its place
|
new RefType[] { RefType.COMPUTED_CALL, RefType.COMPUTED_JUMP, RefType.CONDITIONAL_CALL,
|
||||||
RefType.COMPUTED_CALL, RefType.COMPUTED_JUMP, RefType.CONDITIONAL_CALL,
|
RefType.CONDITIONAL_JUMP, RefType.UNCONDITIONAL_CALL, RefType.UNCONDITIONAL_JUMP,
|
||||||
RefType.CONDITIONAL_JUMP, RefType.UNCONDITIONAL_CALL, RefType.UNCONDITIONAL_JUMP,
|
RefType.CONDITIONAL_COMPUTED_CALL, RefType.CONDITIONAL_COMPUTED_JUMP, RefType.DATA,
|
||||||
RefType.CONDITIONAL_COMPUTED_CALL, RefType.CONDITIONAL_COMPUTED_JUMP, RefType.DATA,
|
RefType.DATA_IND, RefType.READ, RefType.READ_IND, RefType.WRITE, RefType.WRITE_IND,
|
||||||
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.READ_WRITE, RefType.READ_WRITE_IND };
|
RefType.CALLOTHER_OVERRIDE_CALL, RefType.CALLOTHER_OVERRIDE_JUMP };
|
||||||
|
|
||||||
public static RefType[] getMemoryRefTypes() {
|
public static RefType[] getMemoryRefTypes() {
|
||||||
return memoryRefTypes;
|
return memoryRefTypes;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue