Skip to content
Snippets Groups Projects
SMPInstr.cpp 538 KiB
Newer Older
jdh8d's avatar
jdh8d committed
/*
 * SMPInstr.cpp - <see below>.
 *
 * Copyright (c) 2000, 2001, 2010 - University of Virginia 
 *
 * This file is part of the Memory Error Detection System (MEDS) infrastructure.
 * This file may be used and modified for non-commercial purposes as long as 
 * all copyright, permission, and nonwarranty notices are preserved.  
 * Redistribution is prohibited without prior written consent from the University 
 * of Virginia.
 *
 * Please contact the authors for restrictions applying to commercial use.
 *
 * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Author: University of Virginia
 * e-mail: jwd@virginia.com
 * URL   : http://www.cs.virginia.edu/
 *
 * Additional copyrights 2010, 2011 by Zephyr Software LLC
 * e-mail: {clc,jwd}@zephyr-software.com
 * URL   : http://www.zephyr-software.com/
 *
jdh8d's avatar
jdh8d committed
 */

//
// SMPInstr.cpp
//
// This module performs the instruction level analyses needed for the
//   SMP project (Software Memory Protection).
//

#include <cstring>

#include <pro.h>
#include <assert.h>
#include <ida.hpp>
#include <idp.hpp>
#include <auto.hpp>
#include <bytes.hpp>
#include <funcs.hpp>
#include <intel.hpp>
#include <loader.hpp>
#include <lines.hpp>
#include <name.hpp>

#include "SMPStaticAnalyzer.h"
#include "SMPDataFlowAnalysis.h"
#include "SMPInstr.h"
#include "SMPProgram.h"
clc5q's avatar
clc5q committed
#include "ProfilerInformation.h"

// Set to 1 for debugging output
#define SMP_DEBUG 1
#define SMP_DEBUG2 0   // verbose
#define SMP_DEBUG_XOR 0
#define SMP_DEBUG_BUILD_RTL  1   // should be left on, serious errors!
#define SMP_VERBOSE_DEBUG_BUILD_RTL  0
#define SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE 0
#define SMP_VERBOSE_DEBUG_INFER_TYPES 0
#define SMP_VERBOSE_DUMP 0
clc5q's avatar
clc5q committed
#define SMP_VERBOSE_FIND_POINTERS 0
#define STARS_DUMP_FG_INFO 1  // show signedness of DEFs and USEs in dump
#define SMP_CALL_TRASHES_REGS 1  // Add DEFs of caller-saved regs to CALL instructions
#define SMP_BASEREG_POINTER_TYPE 1  // Initialize Base Register USEs to type POINTER?
#define SMP_OPTIMIZE_ADD_TO_NUMERIC 0 // optimizing annotation type -5
#define SMP_IDENTIFY_POINTER_ADDRESS_REG 0 // optimizing annotation POINTER
clc5q's avatar
clc5q committed
#define SMP_CHILDACCESS_ALL_CODE 0 // CHILDACCESS annotations for all funcs, or just analyzed funcs?
#define SPECIAL_CASE_CARRY_BORROW 0 // Treat sbb/adc different from sub/add annotations?
#define SMP_BUILD_SPECIAL_ADC_SBB_RTL 0 // Explicit RTL subtree for carry flag?
#define SMP_AGGRESSIVE_TYPE_INFERENCE 1  // Shorten iterations by quick propagation in InferOperatorType()
#define SMP_ANNOTATE_ALL_MEMORY_OPERANDS 0 // Info annotation for all memory read and write operands?
#define SMP_AGGRESSIVE_SIGN_TRANSFER 1  // More transfer of signedness across instructions
#define STARS_NO_SHIFT_SIGNEDNESS_IN_SCALEFACTOR 1  // unsigned left shift for scale factors is really unknownsign multiply
// Make the CF_CHG1 .. CF_CHG6 and CF_USE1..CF_USE6 macros more usable
//  by allowing us to pick them up with an array index.
static ulong DefMacros[UA_MAXOP] = {CF_CHG1, CF_CHG2, CF_CHG3, CF_CHG4, CF_CHG5, CF_CHG6};
static ulong UseMacros[UA_MAXOP] = {CF_USE1, CF_USE2, CF_USE3, CF_USE4, CF_USE5, CF_USE6};

// Text to be printed in each optimizing annotation explaining why
//  the annotation was emitted.
static const char *OptExplanation[LAST_TYPE_CATEGORY + 1] =
	{ "NoOpt", "NoMetaUpdate", "AlwaysNUM", "NUMVia2ndSrcIMMEDNUM",
	  "Always1stSrc", "1stSrcVia2ndSrcIMMEDNUM", "AlwaysPtr",
	  "AlwaysNUM", "AlwaysNUM", "NUMViaFPRegDest", "NumericSources",
	  "StackMemoryTracking", "NumericSources", "NumericMemDest",
	  "NeverMemDest", "SafeIfNoIndexing"
static const char *OperatorText[LAST_SMP_OPERATOR + 1] = 
{ 	"SMP_NULL_OPERATOR", "SMP_CALL", "SMP_INPUT", "SMP_OUTPUT", "SMP_ADDRESS_OF",
	"SMP_U_LEFT_SHIFT", "SMP_S_LEFT_SHIFT", "SMP_U_RIGHT_SHIFT", "SMP_S_RIGHT_SHIFT",
	"SMP_ROTATE_LEFT", "SMP_ROTATE_LEFT_CARRY", "SMP_ROTATE_RIGHT", "SMP_ROTATE_RIGHT_CARRY",
	"SMP_DECREMENT", "SMP_INCREMENT",
	"SMP_ADD", "SMP_ADD_CARRY", "SMP_SUBTRACT", "SMP_SUBTRACT_BORROW", "SMP_U_MULTIPLY",
	"SMP_S_MULTIPLY", "SMP_U_DIVIDE", "SMP_S_DIVIDE", "SMP_U_REMAINDER",
	"SMP_SIGN_EXTEND", "SMP_ZERO_EXTEND", "SMP_ASSIGN", "SMP_BITWISE_AND",
	"SMP_BITWISE_OR", "SMP_BITWISE_NOT", "SMP_BITWISE_XOR", "SMP_BITWISE_AND_NOT", "SMP_NEGATE", 
	"SMP_S_COMPARE", "SMP_U_COMPARE", "SMP_GENERAL_COMPARE", "SMP_LESS_THAN", "SMP_GREATER_THAN",
	"SMP_LESS_EQUAL", "SMP_GREATER_EQUAL", "SMP_EQUAL", "SMP_NOT_EQUAL",
	"SMP_LOGICAL_AND", "SMP_LOGICAL_OR", "SMP_UNARY_NUMERIC_OPERATION",
	"SMP_BINARY_NUMERIC_OPERATION", "SMP_SYSTEM_OPERATION",
	"SMP_UNARY_FLOATING_ARITHMETIC", "SMP_BINARY_FLOATING_ARITHMETIC",
	"SMP_REVERSE_SHIFT_U", "SMP_SHUFFLE", "SMP_COMPARE_EQ_AND_SET",
	"SMP_COMPARE_NE_AND_SET", "SMP_COMPARE_GT_AND_SET", 
	"SMP_COMPARE_GE_AND_SET", "SMP_COMPARE_LT_AND_SET", "SMP_COMPARE_LE_AND_SET",
	"SMP_PACK_SIGNED", "SMP_PACK_UNSIGNED",
	"SMP_AVERAGE_UNSIGNED", "SMP_MULTIPLY_AND_ADD", "SMP_SUM_OF_DIFFS",
	"SMP_MAX_S", "SMP_MAX_U", "SMP_MIN_S", "SMP_MIN_U", "SMP_ABS_VALUE",
	"SMP_CONVERT_INT_TO_FP", "SMP_CONVERT_FP_TO_INT", "SMP_CREATE_MASK",
	"SMP_INTERLEAVE", "SMP_CONCATENATE", "SMP_EXTRACT_ZERO_EXTEND", 
	"SMP_ENCRYPTION_OPERATION", "SMP_SIGNAL"
// Does the CurrOperator definitely indicate a signed or unsigned operation?
bool OperatorHasSignedness(SMPoperator CurrOperator) {
	bool DetectedSignedness;

	switch (CurrOperator) {
		case SMP_NULL_OPERATOR:
			DetectedSignedness = false;
			break;

		case SMP_CALL:  // CALL instruction
			DetectedSignedness = true;
			break;

		case SMP_INPUT:  // input from port
		case SMP_OUTPUT: // output to port
		case SMP_ADDRESS_OF: // take effective address
		case SMP_GENERAL_COMPARE:
			DetectedSignedness = false;
			break;

		case SMP_U_LEFT_SHIFT: // unsigned left shift
		case SMP_U_RIGHT_SHIFT: // unsigned right shift
		case SMP_ROTATE_LEFT:
		case SMP_ROTATE_LEFT_CARRY: // rotate left through carry
		case SMP_ROTATE_RIGHT:
		case SMP_ROTATE_RIGHT_CARRY: // rotate right through carry
		case SMP_U_MULTIPLY:
		case SMP_U_DIVIDE:
		case SMP_U_REMAINDER:
		case SMP_ZERO_EXTEND:
		case SMP_BITWISE_NOT: // unary operator
		case SMP_BITWISE_XOR:
		case SMP_BITWISE_AND_NOT:
		case SMP_U_COMPARE: // unsigned compare (AND-based)
			DetectedSignedness = true;
			break;

		case SMP_S_LEFT_SHIFT: // signed left shift
		case SMP_S_RIGHT_SHIFT: // signed right shift
		case SMP_S_MULTIPLY:
		case SMP_S_DIVIDE:
		case SMP_SIGN_EXTEND:
		case SMP_NEGATE:    // unary negation
		case SMP_S_COMPARE: // signed compare (subtraction-based)
		case SMP_LESS_THAN: // boolean test operators
		case SMP_GREATER_THAN:
		case SMP_LESS_EQUAL:
		case SMP_GREATER_EQUAL:
			DetectedSignedness = true;
			break;

		case SMP_DECREMENT:
		case SMP_INCREMENT:
		case SMP_ADD:
		case SMP_ADD_CARRY:   // add with carry
		case SMP_SUBTRACT:
		case SMP_SUBTRACT_BORROW:  // subtract with borrow
		case SMP_ASSIGN:
		case SMP_BITWISE_AND:
		case SMP_BITWISE_OR:
		case SMP_EQUAL:
		case SMP_NOT_EQUAL:
		case SMP_LOGICAL_AND:
		case SMP_LOGICAL_OR:
		case SMP_UNARY_NUMERIC_OPERATION:  // miscellaneous; produces NUMERIC result
		case SMP_BINARY_NUMERIC_OPERATION:  // miscellaneous; produces NUMERIC result
		case SMP_SYSTEM_OPERATION:   // for instructions such as CPUID, RDTSC, etc.; NUMERIC
		case SMP_SHUFFLE: // Shuffle bytes, words, etc. within destination operation per source mask
		case SMP_SIGNAL: // signal or raise exception
			DetectedSignedness = false;
			break;

		case SMP_UNARY_FLOATING_ARITHMETIC:  // all the same to our type system; all NUMERIC
		case SMP_BINARY_FLOATING_ARITHMETIC:  // all the same to our type system; all NUMERIC
			DetectedSignedness = true;
			break;

		case SMP_REVERSE_SHIFT_U: // Shift right operand by bit count in left operand
		case SMP_COMPARE_EQ_AND_SET: // Compare for equality and set fields to all 1's or all 0's
		case SMP_COMPARE_NE_AND_SET: // Compare for inequality and set fields to all 1's or all 0's
		case SMP_COMPARE_GT_AND_SET: // Compare for greater-than and set fields to all 1's or all 0's
		case SMP_COMPARE_GE_AND_SET: // Compare for greater-than-or-equal and set fields to all 1's or all 0's
		case SMP_COMPARE_LT_AND_SET: // Compare for less-than and set fields to all 1's or all 0's
		case SMP_COMPARE_LE_AND_SET: // Compare for less-than-or-equal and set fields to all 1's or all 0's
		case SMP_PACK_S:  // Pack operands into extended-precision register, signed saturation for loss of precision
		case SMP_PACK_U:  // Pack operands into extended-precision register, unsigned saturation for loss of precision
		case SMP_AVERAGE_U: // Average of unsigned operands
		case SMP_MULTIPLY_AND_ADD: // multiply and add (or multiply and accumulate)
		case SMP_SUM_OF_DIFFS: // sum over two vectors of absolute values of differences of their elements
		case SMP_MAX_S: // dest := signed_max(dest, src)
		case SMP_MAX_U: // dest := unsigned_max(dest, src)
		case SMP_MIN_S: // dest := signed_min(dest, src)
		case SMP_MIN_U: // dest := unsigned_min(dest, src)
		case SMP_ABSOLUTE_VALUE: // take absolute value
		case SMP_CONVERT_INT_TO_FP: // convert integer to floating point
		case SMP_CONVERT_FP_TO_INT: // convert floating point to integer
		case SMP_INTERLEAVE: // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC
		case SMP_CONCATENATE:     // extended-precision concatenation; NUMERIC
			DetectedSignedness = true;
			break;

		default:
			DetectedSignedness = false;
			SMP_msg("ERROR: Unknown operator in OperatorHasSignedness: %d\n", CurrOperator);
			break;
	} // end switch on operator

	return DetectedSignedness;
} // end of OperatorHasSignedness()
// *****************************************************************
// Class SMPGuard
// *****************************************************************
// Constructor
SMPGuard::SMPGuard(void) {
	this->LeftOperand.type = o_void;
	this->RightOperand.type = o_void;
	this->GuardOp = SMP_NULL_OPERATOR;
// Debug print
	PrintOperand(this->LeftOperand);
	SMP_msg(" %s ", OperatorText[this->GuardOp]);
	PrintOperand(this->RightOperand);
	return;
} // end of SMPGuard::Dump()

// *****************************************************************
// Class SMPRegTransfer
// *****************************************************************
SMPRegTransfer::SMPRegTransfer(void) {
	this->LeftOperand.type = o_void;
	this->RightOperand.type = o_void;
	this->RTop.oper = SMP_NULL_OPERATOR;
	this->RTop.type = UNINIT;
#if SMP_TRACK_NONSPEC_OPER_TYPE
	this->RTop.NonSpeculativeType = UNINIT;
#endif
clc5q's avatar
clc5q committed
	this->booleans1 = 0;
	this->RightRT = NULL;
	this->ParentInst = NULL;
	return;
}

// Destructor
SMPRegTransfer::~SMPRegTransfer() {
#if 0
#endif
	if (NULL != this->RightRT)
		delete this->RightRT;
	if (NULL != this->Guard)
		delete this->Guard;
	return;
}

// Get the left operand, and normalize it if it is a stack operand.
op_t SMPRegTransfer::GetLeftOperand(void) const {
	op_t TempOp = this->LeftOperand;
	// AreDefsNormalized and AreUsesNormalized should always agree, but we
	//  use Defs for left operands and Uses for right operands, which is not
	//  strictly true, but there is no difference in results.
	if (this->ParentInst->AreDefsNormalized()) {
		ea_t InstAddr = this->ParentInst->GetAddr();
		TempOp = this->ParentInst->GetBlock()->GetFunc()->GetNormalizedOperand(InstAddr, TempOp);
	}
	return TempOp;
} // end of SMPRegTransfer::GetLeftOperand()

// Get the right operand, and normalize it if it is a stack operand.
op_t SMPRegTransfer::GetRightOperand(void) const {
	op_t TempOp = this->RightOperand;
	if (this->ParentInst->AreDefsNormalized()) {
		ea_t InstAddr = this->ParentInst->GetAddr();
		TempOp = this->ParentInst->GetBlock()->GetFunc()->GetNormalizedOperand(InstAddr, TempOp);
	}
	return TempOp;
} // end of SMPRegTransfer::GetRightOperand()

// Does RTL subtract a non-immediate value from the stack pointer?
bool SMPRegTransfer::IsAllocaRTL(void) {
	bool AllocaFound = false;
	// Search for the pattern: stack_pointer := stack_pointer minus non-immediate
	if ((SMP_ASSIGN == this->GetOperator()) && (this->HasRightSubTree())) {
		op_t DefOp = this->GetLeftOperand();
		if (DefOp.is_reg(MD_STACK_POINTER_REG)) {
			// We have the code pattern stack_pointer := ...
			SMPRegTransfer *RightRT = this->GetRightTree();
			SMPoperator RightOperator = RightRT->GetOperator();
			op_t RightDefOp = RightRT->GetLeftOperand();
			if ((RightDefOp.is_reg(MD_STACK_POINTER_REG)) && (SMP_SUBTRACT == RightOperator)) {
				// We have the code pattern stack_pointer := stack_pointer minus ...
				if (RightRT->HasRightSubTree()) {
					AllocaFound = true; // not an immediate rightop, whatever it is
				}
				else {
					op_t RightUseOp = RightRT->GetRightOperand();
					if (o_imm != RightUseOp.type) {
						AllocaFound = true;
					}
				}
			}
		}
	}
	return AllocaFound;
} // end of SMPRegTransfer::IsAllocaRTL()

// Compute operand-dependent change in stack pointer value.
sval_t SMPRegTransfer::ComputeStackPointerAlteration(bool IsLeaveInstr, sval_t IncomingDelta, sval_t FramePtrDelta) {
	sval_t delta = 0;

	// Search for the pattern: stack_pointer := ...
	if (SMP_ASSIGN == this->GetOperator()) {
		op_t DefOp = this->GetLeftOperand();
		if (DefOp.is_reg(MD_STACK_POINTER_REG)) {
			// We have the code pattern stack_pointer := ...
			// We expect to find an overall RT structure of:
			//   stack_pointer := stack_pointer binaryoperator constant
			//  If the binaryoperator is addition or subtraction, then
			//   we use the constant to determine our return value.
			//  If the binaryoperator is a bitwise AND, then we return
			//   a special code. Delta is unknown but can probably be treated
			//   as zero, assuming that no stack-pointer-relative accesses to
			//   the stack region above the current stack pointer occur later.
			//  If we have a non-constant operand, we return an error code
			//   to indicate that we cannot compute the delta.
			//  If we don't have a binary operator, we return an error code,
			//   unless we find a stack frame deallocation:  esp := ebp
			if (!this->HasRightSubTree()) {
				op_t UseOp = this->GetRightOperand();
				if (UseOp.is_reg(MD_FRAME_POINTER_REG)) { // !!!!****!!!! Should validate that frame pointer reg is used as frame pointer
					// Found esp := ebp (deallocation of stack frame)
					delta = FramePtrDelta - IncomingDelta;
					assert(delta >= 0); // e.g. -4 - -12 => +8 for an 8-byte frame
					// !!!!****!!!!**** Need to look up deltas for registers that
					//  were used to hold a copy of the stack pointer.
					// For now, just consider it an error.
					delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
				}
			}
			else {
				SMPRegTransfer *RightRT = this->GetRightTree();
				SMPoperator RightOperator = RightRT->GetOperator();
				op_t RightDefOp = RightRT->GetLeftOperand();
				if (IsLeaveInstr) {
					// Found the RT esp := ebp + 4 that adjusts the stack pointer
					//  for an x86 LEAVE instruction. esp := ebp is equivalent
					//  to esp := <esp when frame ptr was set up>, so delta becomes
					//  <esp delta when frame ptr was set up> - IncomingDelta + 4.
					assert(SMP_ADD == RightOperator);
					assert(!RightRT->HasRightSubTree());
					assert(RightDefOp.is_reg(X86_FRAME_POINTER_REG));
					// Not the right code pattern; unknown effect on stack pointer.
					delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
				}
				else if (!RightDefOp.is_reg(MD_STACK_POINTER_REG)) {
					// We have stack_pointer := something1 operator something2
					//  where something1 is not the stack_pointer. It might be
					//  the frame pointer, e.g. SP := FP-12. We can compute this
					//  stack delta because we know the delta when the FP was set up.
					op_t RightUseOp = RightRT->GetRightOperand();
					if (RightDefOp.is_reg(MD_FRAME_POINTER_REG) && (o_imm == RightUseOp.type)) {
						// We have SP := FP operator immediate
						delta = FramePtrDelta - IncomingDelta; // partial computation: SP := BP
						assert(delta >= 0); // e.g. -4 - -12 => +8 for an 8-byte frame
						if (SMP_ADD == RightOperator) {
							delta += RightUseOp.value;
						}
						else if (SMP_SUBTRACT == RightOperator) {
							delta -= RightUseOp.value;
						}
						else {
							// Not the right code pattern; unknown effect on stack pointer.
							delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
						}
					}
					else {
						// !!!!****!!!!**** Need to look up deltas for registers that
						//  were used to hold a copy of the stack pointer.
						// For now, just consider it an error.
						delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
					}
				}
				else {
					// We have stack_pointer := stack_pointer operator ...
					op_t RightUseOp = RightRT->GetRightOperand();
					// Check the operator
					if (SMP_BITWISE_AND == RightOperator) {
						delta = (sval_t) SMP_STACK_POINTER_BITWISE_AND_CODE;
					}
					else {
						if (o_imm != RightUseOp.type) {
							// Don't know how to deal with adding non-constant to stack pointer
							delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
						}
						else if (SMP_ADD == RightOperator) {
							delta = (sval_t) RightUseOp.value;
						}
						else if (SMP_SUBTRACT == RightOperator) {
							delta = (0 - ((sval_t) RightUseOp.value));
						}
						else {
							delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
						}
					}
				}
			}
		}
	}
	return delta;
} // end of SMPRegTransfer::ComputeStackPointerAlteration()

// Debug print
	if (NULL != this->Guard)
		this->Guard->Dump();
	// Left operand
	if (o_void != this->LeftOperand.type)
		PrintOperand(this->LeftOperand);
	// Then the operator
	SMP_msg(" %s ", OperatorText[this->GetOperator()]);
	// then the right operand or subtree
	if (this->HasRightSubTree())
		this->GetRightTree()->Dump();
	else if (o_void != this->RightOperand.type)
		PrintOperand(this->RightOperand);
	return;
}

// *****************************************************************
// Class SMPRTL
// *****************************************************************

// Constructor
SMPRTL::SMPRTL() {
	this->ExtraKills.clear();
	this->RTCount = 0;
	return;
}

// Destructor
SMPRTL::~SMPRTL() {
	for (size_t index = 0; index < this->RTCount; ++index) {
		delete (this->RTvector[index]);
	}
	this->ExtraKills.clear();
	return;
}

// Get methods
SMPRegTransfer *SMPRTL::GetRT(size_t index) const {
	if (index > this->RTCount)
		return NULL;
	else
		return this->RTvector[index];
}

// Set methods
void SMPRTL::push_back(SMPRegTransfer *NewEffect) {
	assert(SMP_RT_LIMIT > this->RTCount);
	this->RTvector[this->RTCount] = NewEffect;
	++(this->RTCount);
	return;
}

// Printing methods
	size_t index;
	if (0 < this->RTCount) {
		for (index = 0; index < this->RTCount; ++index) {
			this->RTvector[index]->Dump();
		}
		for (index = 0; index < this->ExtraKills.size(); ++index) {
			PrintOperand(this->ExtraKills.at(index));
		}
	}
	return;
} // end of SMPRTL::Dump()

// Accumulate stack pointer alteration total across all RTs.
sval_t SMPRTL::TotalStackPointerAlteration(bool IsLeaveInstr, sval_t IncomingDelta, sval_t FramePtrDelta) {
	sval_t TotalDelta = 0;
	sval_t IncrementalDelta;

	for (size_t index = 0; index < this->RTCount; ++index) {
		IncrementalDelta = this->RTvector[index]->ComputeStackPointerAlteration(IsLeaveInstr, IncomingDelta, FramePtrDelta);
		if ((SMP_STACK_DELTA_ERROR_CODE == IncrementalDelta) 
			|| (SMP_STACK_POINTER_BITWISE_AND_CODE == IncrementalDelta)) {
			TotalDelta = IncrementalDelta;  // pass code back
			break; // exit loop and return coded value
		}
		else {
			TotalDelta += IncrementalDelta;
		}
	}

	return TotalDelta;
} // end of SMPRTL::TotalStackPointerAlteration()
// *****************************************************************
// Class SMPInstr
// *****************************************************************

// Constructor for instruction.
SMPInstr::SMPInstr(ea_t addr) {
	this->SMPcmd.size = 0;
	this->address = addr;
	this->ResetJumpTarget();
	this->ResetBlockTerm();
	this->ResetTailCall();
	this->ResetCondTailCall();
	this->ResetCallUsedAsJump();
	this->ResetDirectRecursiveCall();
	this->ResetInterrupt();
#else
	this->booleans1 = 0;
#endif
#if 0
	this->ResetNop();
	this->ResetRegClearIdiom();
	this->ResetDefsFlags();
	this->ResetUsesFlags();
	this->ResetFarBranchComputed();
	this->ResetBranchesToFarChunk();
	this->ResetIndirectMemWrite();
	this->ResetIndirectMemRead();
#else
	this->booleans2 = 0;
#endif
#if 0
	this->ResetLoadFromStack();
	this->ResetMultiplicationBitsDiscarded();
	this->ResetTypeInferenceComplete();
	this->ResetCategoryInferenceComplete();
	this->ResetDEFsTyped();
	this->ResetUSEsTyped();
#else
	this->booleans3 = 0;
#endif
	this->FarBranchTarget = BADADDR;
	this->AddSubSourceType = UNINIT;
	this->AddSubUseType = UNINIT;
	this->AddSubUseOp = InitOp;
	this->DEFMemOp = InitOp;
	this->USEMemOp = InitOp;
	this->MoveSource = InitOp;
	this->BasicBlock = NULL;
	this->type = DEFAULT;
	this->OptType = 0;
	this->Defs.clear();
	this->Uses.clear();
SMPInstr::~SMPInstr() {
	this->Defs.clear();
	this->Uses.clear();
char *SMPInstr::GetDisasm(void) const {
	return DisAsmText.GetDisAsm(this->GetAddr());
}

// Is the instruction the type that terminates a basic block?
bool SMPInstr::IsBasicBlockTerminator() const {
	return ((type == JUMP) || (type == COND_BRANCH)
			|| (type == INDIR_JUMP) || (type == RETURN));
}

// Get non-flags DEF, usually for arithmetic opcode.
set<DefOrUse, LessDefUse>::iterator SMPInstr::GetFirstNonFlagsDef(void) {
	set<DefOrUse, LessDefUse>::iterator DefIter;
	op_t DefOp;

	for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
		DefOp = DefIter->GetOp();
		if (!((o_reg == DefOp.type) && DefOp.is_reg(MD_FLAGS_REG)))
			break; // found a non-flags-reg DEF.
	}
	return DefIter;
}


// Is the destination operand a memory reference?
bool SMPInstr::HasDestMemoryOperand(void) {
	return (o_void != this->DEFMemOp.type);
} // end of SMPInstr::HasDestMemoryOperand()

// Is a source operand a memory reference?
bool SMPInstr::HasSourceMemoryOperand(void) {
	return (o_void != this->USEMemOp.type);
} // end of SMPInstr::HasSourceMemoryOperand()

// Get the first memory operand in the DEF list.
op_t SMPInstr::MDGetMemDefOp(void) const {
	return this->DEFMemOp; // cached value
} // end of SMPInstr::MDGetMemDefOp()

// Get the first memory operand in the USE list.
op_t SMPInstr::MDGetMemUseOp(void) const {
	return this->USEMemOp; // cached value
} // end of SMPInstr::MDGetMemUseOp()

// return original Lea instruction [pseudo-]memory operand.
op_t SMPInstr::GetLeaMemUseOp(void) {
	if (this->BasicBlock == NULL) {
		return InitOp;
	}
	else {
		map<ea_t, op_t>::iterator MapIter = this->GetBlock()->GetFunc()->FindLeaOperand(this->GetAddr());
		return MapIter->second;
	}
}

// return BADADDR if not jump, target addr otherwise.
ea_t SMPInstr::GetJumpTarget(void) const {
	ea_t TargetAddr = BADADDR;
	if (this->HasGoodRTL()) {
		// We want to find an RTL of the form: inst_ptr_reg := code_addr
		SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
		op_t DefOp = CurrRT->GetLeftOperand();
		if (DefOp.is_reg(MD_INSTRUCTION_POINTER_REG)) {
			if ((SMP_ASSIGN == CurrRT->GetOperator()) && (!CurrRT->HasRightSubTree())) {
				op_t UseOp = CurrRT->GetRightOperand();
				if ((o_near == UseOp.type) || (o_far == UseOp.type)) { // address
					TargetAddr = UseOp.addr;
				}
			}
		}
	}
	return TargetAddr;
} // end SMPInstr::GetJumpTarget()

// Does any USE have type NEGATEDPTR?
bool SMPInstr::HasNegatedPtrUSE(void) {
	bool UseFound = false;
	set<DefOrUse, LessDefUse>::iterator UseIter;
	SMPOperandType UseType;

	for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
		UseType = UseIter->GetType();
		if (IsEqType(UseType, NEGATEDPTR)) {
			UseFound = true;
			break;
		}
	}

	return UseFound;
} // end of SMPInstr::HasNegatedPtrUSE()

// Detect indirect memory DEFs or USEs
void SMPInstr::AnalyzeIndirectRefs(bool UseFP) {
	op_t DefMemOp = this->MDGetMemDefOp();
	op_t UseMemOp = this->MDGetMemUseOp();

	if (o_void != DefMemOp.type) {
		// Found a memory DEF. Is it indirect?
		if (MDIsIndirectMemoryOpnd(DefMemOp, UseFP)) {
			this->SetIndirectMemWrite();
		}
	}

	if (o_void != UseMemOp.type) {
		// Found a memory USE. Is it indirect?
		if (MDIsIndirectMemoryOpnd(UseMemOp, UseFP)) {
			this->SetIndirectMemRead();
		}
	}

	return;
} // end of SMPInstr::AnalyzeIndirectRefs()

set<DefOrUse, LessDefUse>::iterator SMPInstr::GetPointerAddressReg(op_t MemOp) {
	int BaseReg;
	int IndexReg;
	ushort ScaleFactor;
	ea_t displacement;
	set<DefOrUse, LessDefUse>::iterator PtrIter;

	if ((NULL == this->BasicBlock) || (NULL == this->BasicBlock->GetFunc())) {
		SMP_msg("ERROR: NULL member pointers in SMPInstr::GetPointerAddressReg() at %x \n",
			this->address);
		return this->GetLastUse();
	}
	bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer();

	MDExtractAddressFields(MemOp, BaseReg, IndexReg, ScaleFactor,
		displacement);

	if ((R_none != BaseReg) && (!MDIsStackPtrReg(BaseReg, UseFP))) {
		op_t BaseOp = InitOp;
		BaseOp.type = o_reg;
		BaseOp.reg = (ushort) BaseReg;
		PtrIter = this->FindUse(BaseOp);
		assert(PtrIter != this->GetLastUse());
		if (IsDataPtr(PtrIter->GetType())) {
			return PtrIter;
		}
	}
	if ((R_none != IndexReg) && (!MDIsStackPtrReg(IndexReg, UseFP))) {
		op_t IndexOp = InitOp;
		IndexOp.type = o_reg;
		IndexOp.reg = (ushort) IndexReg;
		PtrIter = this->FindUse(IndexOp);
		assert(PtrIter != this->GetLastUse());
		if (IsDataPtr(PtrIter->GetType())) {
			return PtrIter;
		}
	}
	PtrIter = this->GetLastUse();
	return PtrIter;
} // end of SMPInstr::GetPointerAddressReg()

// Does the instruction whose flags are in F have a numeric type
//   as the second source operand?
// NOTE: We can only analyze immediate values now. When data flow analyses are implemented,
//   we will be able to analyze many non-immediate operands.
#define IMMEDNUM_LOWER -8191
#define IMMEDNUM_UPPER 8191
bool SMPInstr::IsSecondSrcOperandNumeric(flags_t F) const {
	bool SecondOpImm = (this->SMPcmd.Operands[1].type == o_imm);
		TempImm = this->SMPcmd.Operands[1].value;
	return (SecondOpImm && IsImmedNumeric(TempImm));
} // end of SMPInstr::IsSecondSrcOperandNumeric()

// Determine the type of the USE-only operand for add and subtract
//  instructions. If it is NUMERIC or PROF_NUMERIC, an optimizing
//  annotation will result.
// As a byproduct, find the type of the USE/DEF operand as well.
void SMPInstr::SetAddSubSourceType(void) {
	// Walk the RTL and find the operands we care about.
	// The RTL should look like: opnd1 := (opnd1 op opnd2), where op is
	//  and add or subtract operator. Within the parentheses, the type
	//  of opnd1 is our AddSubUseType and opnd1 is our AddSubUseOp, while
	//  the type of opnd2 is our AddSubSourceType.
	if (this->RTL.GetCount() < 1)
		return;  // no RTL, no leave types as UNINIT.

	assert(this->RTL.GetRT(0)->HasRightSubTree());
	SMPRegTransfer *RightTree = this->RTL.GetRT(0)->GetRightTree();
	op_t LeftOp, RightOp;
	LeftOp = RightTree->GetLeftOperand();    // Use (also DEF) operand
	if ((NN_adc != this->SMPcmd.itype) && (NN_sbb != this->SMPcmd.itype)) {
		assert(!(RightTree->HasRightSubTree()));
		RightOp = RightTree->GetRightOperand();  // Src (non-DEF) operand
	else {
		// Add with carry and subtract with borrow have an extra level
		//  to the tree RTL, e.g. for add with carry:
		//  opnd1 := (opnd1 + (opnd2 + carryflag))
		assert(RightTree->HasRightSubTree());
		RightTree = RightTree->GetRightTree();
		RightOp = RightTree->GetLeftOperand();
#else
	assert(!(RightTree->HasRightSubTree()));
	RightOp = RightTree->GetRightOperand();  // Src (non-DEF) operand
#endif

	set<DefOrUse, LessDefUse>::iterator UseIter, SrcIter;

	SrcIter = this->FindUse(RightOp);
	assert(SrcIter != this->GetLastUse());
	this->AddSubSourceType = SrcIter->GetType();
	this->AddSubSourceOp = RightOp;

	UseIter = this->FindUse(LeftOp);
	assert(UseIter != this->GetLastUse());
	this->AddSubUseType = UseIter->GetType();
	this->AddSubUseOp = LeftOp;

	return;
} // end of SMPInstr::SetAddSubSourceType()

// Are all DEFs in the DEF set NUMERIC type?
jdh8d's avatar
jdh8d committed
bool SMPInstr::AllDefsNumeric(void) 
{
	bool AllNumeric = (this->Defs.GetSize() > 0);  // false if no DEFs, true otherwise
	set<DefOrUse, LessDefUse>::iterator CurrDef;
	for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
		// We ignore the stack pointer for pop instructions and consider only
		//  the register DEF of the pop.
		if (this->MDIsPopInstr() && CurrDef->GetOp().is_reg(R_sp))
			continue;
		AllNumeric = (AllNumeric && IsNumeric(CurrDef->GetType()));
	}
	return AllNumeric;
} // end of SMPInstr::AllDefsNumeric()

// Were the types of any DEFs derived from profiler info?
jdh8d's avatar
jdh8d committed
bool SMPInstr::AnyDefsProfiled(void) 
{
	bool profd = false;
	set<DefOrUse, LessDefUse>::iterator CurrDef;
	for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
jdh8d's avatar
jdh8d committed
		profd = (profd || IsProfDerived(CurrDef->GetType()));
	}
	return profd;
} 

// Do all DEFs have DEF_METADATA_UNUSED status?
bool SMPInstr::AllDefMetadataUnused(void) {
	bool AllUnused = (this->Defs.GetSize() > 0);  // false if no DEFs, true otherwise
	set<DefOrUse, LessDefUse>::iterator CurrDef;
	for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
		AllUnused = (AllUnused 
			&& (DEF_METADATA_UNUSED == CurrDef->GetMetadataStatus()));
	}
	return AllUnused;
} // end of SMPInstr::AllDefMetadataUnused()

// DEBUG print operands for Inst.
void SMPInstr::PrintOperands(void) const {
	op_t Opnd;
	for (int i = 0; i < UA_MAXOP; ++i) {
		Opnd = SMPcmd.Operands[i];
		PrintOneOperand(Opnd, this->features, i);
	}
	return;
} // end of SMPInstr::PrintOperands()

// Complete DEBUG printing.
void SMPInstr::Dump(void) {
	SMP_msg("%x %d SMPitype: %d %s\n", this->address, this->SMPcmd.size, (int) this->type, 
		DisAsmText.GetDisAsm(this->GetAddr()));
#if STARS_DUMP_FG_INFO
	SMP_msg("USEs: ");
	if (NULL == this->GetBlock()) { // during early improvement of disasm
		this->Uses.Dump();
		SMP_msg("DEFs: ");
		this->Defs.Dump();
	}
	else {
		set<DefOrUse, LessDefUse>::iterator UseIter, DefIter;
		op_t UseOp, DefOp;
		int UseHashValue, DefHashValue, UseSSANum, DefSSANum;
		unsigned short SignMiscInfo, SignMask;
		bool LocalName;
		for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
			UseIter->Dump();
			UseOp = UseIter->GetOp();
			if (o_reg == UseOp.type) {
				LocalName = this->GetBlock()->IsLocalName(UseOp);
				UseSSANum = UseIter->GetSSANum();
				UseHashValue = HashGlobalNameAndSSA(UseOp, UseSSANum);
				if (LocalName) {
					SignMiscInfo = this->GetBlock()->GetUseSignMiscInfo(UseHashValue);
				}
				else {
					SignMiscInfo = this->GetBlock()->GetFunc()->GetUseSignMiscInfo(UseHashValue);
				}
				SignMask = SignMiscInfo & FG_MASK_SIGNEDNESS_BITS;
				if (SignMask == FG_MASK_SIGNED) {
					SMP_msg(" Si ");
				}
				else if (SignMask == FG_MASK_UNSIGNED) {
					SMP_msg(" Un ");
				}
				else if (SignMask == FG_MASK_INCONSISTENT_SIGN) {
					SMP_msg(" Xs ");
				}
			}
			SMP_msg("\n");
		}
		SMP_msg("DEFs: ");
		for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
			DefIter->Dump();
			DefOp = DefIter->GetOp();
			if (o_reg == DefOp.type) {
				LocalName = this->GetBlock()->IsLocalName(DefOp);
				DefSSANum = DefIter->GetSSANum();
				DefHashValue = HashGlobalNameAndSSA(DefOp, DefSSANum);
				if (LocalName) {
					SignMiscInfo = this->GetBlock()->GetDefSignMiscInfo(DefHashValue);
				}
				else {
					SignMiscInfo = this->GetBlock()->GetFunc()->GetDefSignMiscInfo(DefHashValue);
				}
				SignMask = SignMiscInfo & FG_MASK_SIGNEDNESS_BITS;
				if (SignMask == FG_MASK_SIGNED) {
					SMP_msg(" Si ");
				}
				else if (SignMask == FG_MASK_UNSIGNED) {
					SMP_msg(" Un ");
				}
				else if (SignMask == FG_MASK_INCONSISTENT_SIGN) {
					SMP_msg(" Xs ");
				}
			}
			SMP_msg("\n");
		}
	}
#else
	this->RTL.Dump();
#if SMP_VERBOSE_DUMP
	this->PrintOperands();
#endif
	return;
} // end of SMPInstr::Dump()

// Print out the destination operand list for the instruction, given
//  the OptCategory for the instruction as a hint.
char * SMPInstr::DestString(int OptType) {
	int RegDestCount = 0;
	DestList[0] = 'Z';  // Make sure there are no leftovers from last call
	DestList[1] = 'Z';
	DestList[2] = '\0';
	set<DefOrUse, LessDefUse>::iterator CurrDef;
	for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
		op_t DefOpnd = CurrDef->GetOp();
		if (DefOpnd.is_reg(X86_FLAGS_REG))  // don't print flags as a destination
			continue;
		// We want to ignore the stack pointer DEF for pops and just include
		//  the register DEF for the pop.
		if (DefOpnd.is_reg(R_sp) && this->MDIsPopInstr())
			continue;
		if (o_reg == DefOpnd.type) {
			ushort DestReg = DefOpnd.reg;
			if (0 == RegDestCount) {
				SMP_strncpy(DestList, RegNames[DestReg], 1 + strlen(RegNames[DestReg]));
				SMP_strncat(DestList, " ", MAXSTR);
				SMP_strncat(DestList, RegNames[DestReg], MAXSTR);
			}
			++RegDestCount;
		}
	}
	if (0 >= RegDestCount) {
		SMP_msg("WARNING: No destination registers: %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
	}
	return DestList;
} // end of SMPInstr::DestString()