Skip to content
Snippets Groups Projects
SMPInstr.cpp 368 KiB
Newer Older
			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
		case SMP_REVERSE_SHIFT_U: // Shift right operand by bit count in left operand
		case SMP_SHUFFLE: // Shuffle bytes, words, etc. within destination operation per source mask
		case SMP_COMPARE_EQ_AND_SET: // Compare for equality 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_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_INTERLEAVE: // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC
		case SMP_CONCATENATE:     // extended-precision concatenation; NUMERIC
			transfer = true;
			break;

		default:
			SMP_msg("ERROR: Unknown operator in %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
			break;
	} // end switch on operator

	return transfer;
} // end of SMPInstr::DoesOperatorTransferSign()

// Initial inferences (if any) about FG info of operand based solely on the RTL operator type above it in RTL.
bool SMPInstr::InitFGInfoFromOperator(SMPoperator CurrOp, struct FineGrainedInfo &InitFG) {
	bool changed = false;

	switch (CurrOp) {
		case SMP_NULL_OPERATOR:
			break;

		case SMP_CALL:  // CALL instruction
			InitFG.SignMiscInfo |= FG_MASK_UNSIGNED; // target address is unsigned 32-bit
			InitFG.SizeInfo |= (MD_NORMAL_BITWIDTH_MASK | FG_MASK_CODEPOINTER);
			break;

		case SMP_INPUT:  // input from port
		case SMP_OUTPUT: // output to port
		case SMP_ADDRESS_OF: // take effective address
		case SMP_U_COMPARE: // unsigned compare (AND-based)
		case SMP_S_COMPARE: // signed compare (subtraction-based)
			// NOTE: The AND-based and subtraction-based comparisons are used
			//  on lots of operands of all types, and the conditional jump that
			//  follows determines signedness, not the operator.
			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:
			InitFG.SignMiscInfo |= FG_MASK_UNSIGNED;
			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_LESS_THAN: // boolean test operators
		case SMP_GREATER_THAN:
		case SMP_LESS_EQUAL:
		case SMP_GREATER_EQUAL:
			// Special case: If signed multiply operator, it might sometimes
			//  be used for unsigned operands when upper bits of the result
			//  are discarded, because there is no difference in the result bits
			//  between unsigned and signed multiplcation when only the lower
			//  N bits are retained and the upper N bits are discarded.
			if ((SMP_S_MULTIPLY == CurrOp) && (!(this->MDIsSignedArithmetic()))) {
				break;
			}
			InitFG.SignMiscInfo |= FG_MASK_SIGNED;
			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
			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
			InitFG.SignMiscInfo |= FG_MASK_SIGNED;
			InitFG.SizeInfo |= FG_MASK_FLOAT_MMX;
			break;

		case SMP_REVERSE_SHIFT_U: // Shift right operand by bit count in left operand
		case SMP_SHUFFLE: // Shuffle bytes, words, etc. within destination operation per source mask
		case SMP_COMPARE_EQ_AND_SET: // Compare for equality 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_PACK_S:  // Pack operands into extended-precision register, signed saturation for loss of precision
			InitFG.SignMiscInfo |= FG_MASK_SIGNED;
			InitFG.SizeInfo |= (FG_MASK_FLOAT_MMX | FG_MASK_BITWIDTH_128);
			changed = true;
			break;

		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
			InitFG.SignMiscInfo |= FG_MASK_UNSIGNED;
			InitFG.SizeInfo |= (FG_MASK_FLOAT_MMX | FG_MASK_BITWIDTH_128);
			changed = true;
			break;

		case SMP_INTERLEAVE: // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC
		case SMP_CONCATENATE:     // extended-precision concatenation; NUMERIC
			InitFG.SignMiscInfo |= FG_MASK_SIGNED;
			InitFG.SizeInfo |= (FG_MASK_FLOAT_MMX | FG_MASK_BITWIDTH_128);
			SMP_msg("ERROR: Unknown operator in %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
			break;
	} // end switch on operator

} // end of SMPInstr::InitFGInfoFromOperator()

// Helper to take USE operand, find its SSANum, and return its UseHashValue.
int SMPInstr::GetUseOpHashAndSSA(op_t UseOp, int &SSANum) {
	op_t SearchOp = UseOp;
	SearchOp.reg = MDCanonicalizeSubReg(UseOp.reg);
	set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(SearchOp);
	assert(UseIter != this->GetLastUse());
	SSANum = UseIter->GetSSANum();
	int UseHashValue = HashGlobalNameAndSSA(SearchOp, SSANum);
	return UseHashValue;
} // end of SMPInstr::GetUseOpHashAndSSA()

// Helper to take DEF operand, find its SSANum, and return its DefHashValue.
int SMPInstr::GetDefOpHashAndSSA(op_t DefOp, int &SSANum) {
	op_t SearchOp = DefOp;
	SearchOp.reg = MDCanonicalizeSubReg(DefOp.reg);
	set<DefOrUse, LessDefUse>::iterator DefIter = this->FindDef(SearchOp);
	assert(DefIter != this->GetLastDef());
	SSANum = DefIter->GetSSANum();
	int DefHashValue = HashGlobalNameAndSSA(SearchOp, SSANum);
	return DefHashValue;
} // end of SMPInstr::GetDefOpHashAndSSA()

// helper for InferOperatorFGInfo() to update DEF maps, return true if changed maps
bool SMPInstr::UpdateDefOpFGInfo(op_t DefOp, struct FineGrainedInfo NewFG) {
	bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
	set<DefOrUse, LessDefUse>::iterator DefIter;
	int SSANum;
	int DefHashValue;
	op_t SearchOp;
	bool LocalName;
	struct FineGrainedInfo OldFG, UnionFG;

	// If operator is inherently signed, then we will have 
	//  a sign bit set in NewFG from InitFGInfoFromOperator().
	DefHashValue = this->GetDefOpHashAndSSA(DefOp, SSANum);
	LocalName = this->BasicBlock->IsLocalName(DefOp);
	if (LocalName) {
		// Get old FG info from block level.
		OldFG = this->BasicBlock->GetDefFGInfo(DefHashValue);
	}
	else { // global name
		// Get old FG info from function level.
		OldFG = this->BasicBlock->GetFunc()->GetDefFGInfo(DefHashValue);
	}
	UnionFG.SignMiscInfo = OldFG.SignMiscInfo | NewFG.SignMiscInfo;
	UnionFG.SizeInfo = OldFG.SizeInfo | NewFG.SizeInfo;
	if ((OldFG.SignMiscInfo != UnionFG.SignMiscInfo) || (OldFG.SizeInfo != UnionFG.SizeInfo)) {
		// The signs they are a-changin'.
		MapsChanged = true;
		if (LocalName)
			this->BasicBlock->UpdateDefFGInfo(DefHashValue, UnionFG);
			this->BasicBlock->GetFunc()->UpdateDefFGInfo(DefHashValue, UnionFG);
	}
	return MapsChanged;
} // end of SMPInstr::UpdateDefOpFGInfo()

// helper for InferOperatorFGInfo() to update USE maps, return true if changed maps
bool SMPInstr::UpdateUseOpFGInfo(op_t UseOp, struct FineGrainedInfo NewFG) {
	bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
	int SSANum;
	int UseHashValue;
	bool LocalName;
	struct FineGrainedInfo OldFG, UnionFG;

	// If operator is inherently signed, then we will have 
	//  a sign bit set in NewFG from InitFGInfoFromOperator().
	UseHashValue = this->GetUseOpHashAndSSA(UseOp, SSANum);
	LocalName = this->BasicBlock->IsLocalName(UseOp);
	if (LocalName) {
		// Get old FG info from block level.
		OldFG = this->BasicBlock->GetUseFGInfo(UseHashValue);
	}
	else { // global name
		// Get old FG info from function level.
		OldFG = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue);
	}
	UnionFG.SignMiscInfo = OldFG.SignMiscInfo | NewFG.SignMiscInfo;
	UnionFG.SizeInfo = OldFG.SizeInfo | NewFG.SizeInfo;
	if ((OldFG.SignMiscInfo != UnionFG.SignMiscInfo) || (OldFG.SizeInfo != UnionFG.SizeInfo)) {
		// The signs they are a-changin'.
		MapsChanged = true;
		if (LocalName)
			this->BasicBlock->UpdateUseFGInfo(UseHashValue, UnionFG);
			this->BasicBlock->GetFunc()->UpdateUseFGInfo(UseHashValue, UnionFG);
	}
	return MapsChanged;
} // end of SMPInstr::UpdateUseOpFGInfo()

// Helper to fetch DEF signedness info for UseOp that has none.
unsigned short SMPInstr::GetDefSignInfoFromUseOp(op_t UseOp) {
	int SSANum, UseHashValue;
	bool LocalName;

	UseHashValue = this->GetUseOpHashAndSSA(UseOp, SSANum);
	LocalName = this->BasicBlock->IsLocalName(UseOp);
	if (LocalName) {
		// Get old sign info from block level.
		return this->BasicBlock->GetDefSignMiscInfo(UseHashValue);
	}
	else { // global name
		// Get old sign info from function level.
		return this->BasicBlock->GetFunc()->GetDefSignMiscInfo(UseHashValue);
	}
} // end of SMPInstr::GetDefSignInfoFromUseOp()
// infer FG info, + width on FirstIter; pass out FG info for op subtree, return true if change made to any FG info map.
bool SMPInstr::InferOperatorFGInfo(SMPRegTransfer *CurrRT, bool FirstIter, struct FineGrainedInfo &OpFG) {
	bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
	bool NewChange = false;  // Bit changes from InitFGInfoFromOperator() ?
	SMPoperator CurrOp = CurrRT->GetOperator();
	struct FineGrainedInfo LeftFG, OldLeftFG;
	struct FineGrainedInfo RightFG, OldRightFG;
	op_t LeftOp, RightOp;
	unsigned short WidthMask, SignMask;
	bool CurrOpTransfersSign = this->DoesOperatorTransferSign(CurrOp);
	bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer();
	bool success;
	int DefHashValue, UseHashValue, SSANum;

	// Recurse to the right first, so we can do a depth-first accumulation of FG info.
	RightFG.SignMiscInfo = 0;
	RightFG.SizeInfo = 0;
	if (CurrRT->HasRightSubTree()) {
		if (FirstIter) { // Get width as well as signedness
			NewChange = this->InitFGInfoFromOperator(CurrOp, RightFG);
		} // end if (FirstIter)
		MapsChanged |= this->InferOperatorFGInfo(CurrRT->GetRightTree(), FirstIter, RightFG);
	}
	else {
		RightOp = CurrRT->GetRightOperand();
		if (RightOp.type == o_imm) {
			// If immediate operand is a data address or code address, we can infer that it is unsigned.
			uval_t ImmVal = RightOp.value;
			if (IsImmedGlobalAddress((ea_t) ImmVal)) {
				// Data address (type GLOBALPTR)
				RightFG.SignMiscInfo |= FG_MASK_UNSIGNED;
			}
			else if (this->MDIsInterruptCall() || IsImmedCodeAddress((ea_t) ImmVal)) {
				// Code address (type GLOBALPTR)
				RightFG.SignMiscInfo |= FG_MASK_UNSIGNED;
			}
		}
		else if ((RightOp.type == o_reg) && !RightOp.is_reg(MD_INSTRUCTION_POINTER_REG)) {
			if (FirstIter) { // Get width as well as signedness
				NewChange = this->InitFGInfoFromOperator(CurrOp, RightFG);
				WidthMask = ComputeOperandBitWidthMask(RightOp, 0);
				RightFG.SizeInfo |= WidthMask;
			} // end if (FirstIter)
#define SMP_AGGRESSIVE_SIGN_TRANSFER 1
#if SMP_AGGRESSIVE_SIGN_TRANSFER
			else {
				// On all iterations other than 1st, see if USE has FG info.
				UseHashValue = this->GetUseOpHashAndSSA(RightOp, SSANum);
				if (this->BasicBlock->IsLocalName(RightOp)) {
					// Get FG info from block.
					RightFG = this->BasicBlock->GetUseFGInfo(UseHashValue);
				}
				else {
					// Get FG info from function level.
					RightFG = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue);
				}
			}
#endif
			// Propagate signedness on all iterations.
			// If operator is inherently signed, then we will have 
			//  a sign bit set in RightFG from InitFGInfoFromOperator().
			if ((RightFG.SignMiscInfo == 0) && CurrOpTransfersSign) {
				// We have a USE with no sign info. See if we
				//  can get sign info from the DEF of this USE so we can
				//  transfer it up the RTL tree. 
				RightFG.SignMiscInfo = 
					(FG_MASK_SIGNEDNESS_BITS & (this->GetDefSignInfoFromUseOp(RightOp)));
			}
			if ((RightFG.SignMiscInfo != 0) || (RightFG.SizeInfo != 0))
				MapsChanged |= this->UpdateUseOpFGInfo(RightOp, RightFG);
		} // end if (RightOP is o_reg)
		else if (MDIsStackAccessOpnd(RightOp, UseFP)) {
			// We used to assume that all FG info transfers from stack locations to
			//  the target registers of stack loads happened in SMPInstr::MDSetWidthSignInfo(),
			//  in an early pass that needed no iteration. The FG info was loaded from the
			//  StackFGInfo that was computed in SMPFunction::FindOutgoingArgsSize() based solely
			//  on whether the load was sign-extended or zero-extended. Of course, many stack
			//  locations have neither kind of signed/unsigned load. So, if we see a store to
			//  a stack location with no signedness, we transfer the signedness of the RightFG
			//  to the stack location FGInfo in the code below that processes the LeftOp.
			//  As a result, we now have a need to examine regular loads from the stack to
			//  see if there is signedness info for the stack location.
			success = this->BasicBlock->GetFunc()->MDGetFGStackLocInfo(this->address, RightOp, RightFG);
			if (success) {
				SignMask = (RightFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
				RightFG.SizeInfo = 0; // only want to transfer signedness
			}
		}
	} // end if (right subtree) else right operand

	LeftFG.SignMiscInfo = 0;
	LeftFG.SizeInfo = 0;
	LeftOp = CurrRT->GetLeftOperand();
	bool OpIsDEF = (SMP_ASSIGN == CurrOp);
	// Skip control-flow assignments to the instruction pointer register.
	if ((LeftOp.type == o_reg) && !LeftOp.is_reg(MD_INSTRUCTION_POINTER_REG)) {
		if (FirstIter) { // Get width as well as signedness
			NewChange = this->InitFGInfoFromOperator(CurrOp, LeftFG);
			// Special case: For sign-extended and zero-extended loads,
			//  we don't know whether the DEF will always be USEd as
			//  the smaller or larger size. For example, we could
			//  zero-extend a 16-bit stack location into a 32-bit register
			//  just because the compiler always loads unsigned shorts
			//  that way, but we might never use it as a 32-bit value.
			//  So there is no truncation if we store only 16 bits later.
			//  By setting the target of an extended load to zero width,
			//  we signal that we want the maximum USE width to determine
			//  whether the store is truncated (see EmitIntegerErrorAnnotations).
			WidthMask = ComputeOperandBitWidthMask(LeftOp, 0);
			if (OpIsDEF) {
				if (this->MDIsSignedLoad(SignMask)) {
					WidthMask = 0;
				}
				// DEF inherits sign from right hand side.
				LeftFG.SignMiscInfo |= RightFG.SignMiscInfo; 
			else if ((LeftFG.SignMiscInfo == 0) && CurrOpTransfersSign) {
				// We have a USE, not a DEF, with no sign info. See if we
				//  can get sign info from the DEF of this USE so we can
				//  transfer it up the RTL tree. 
				LeftFG.SignMiscInfo = 
					(FG_MASK_SIGNEDNESS_BITS & (this->GetDefSignInfoFromUseOp(LeftOp)));
			LeftFG.SizeInfo |= WidthMask;
			if ((LeftFG.SignMiscInfo != 0) || (LeftFG.SizeInfo != 0)) {
				// Either NewChanged or CurrOpTransfersSign is true or we set WidthMask above.
				//  See if we would change the FG map entry.
				if (OpIsDEF) { // Need DEF map info
					MapsChanged |= this->UpdateDefOpFGInfo(LeftOp, LeftFG);
				}
				else { // need USE map info
					MapsChanged |= this->UpdateUseOpFGInfo(LeftOp, LeftFG);
				}
			} // end if non-zero LeftFG info
		} // end if (FirstIter)
#if SMP_AGGRESSIVE_SIGN_TRANSFER
		else {
			// On all iterations other than 1st, see if LeftOp has FG info.
			if (!OpIsDEF) { // LeftOp is a USE
				UseHashValue = this->GetUseOpHashAndSSA(LeftOp, SSANum);
				if (this->BasicBlock->IsLocalName(LeftOp)) {
					// Get FG info from block.
					LeftFG = this->BasicBlock->GetUseFGInfo(UseHashValue);
				}
				else {
					// Get FG info from function level.
					LeftFG = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue);
				}
			}
			else { // LeftOp is a DEF
				DefHashValue = this->GetDefOpHashAndSSA(LeftOp, SSANum);
				if (this->BasicBlock->IsLocalName(LeftOp)) {
					// Get FG info from block.
					LeftFG = this->BasicBlock->GetDefFGInfo(DefHashValue);
				}
				else {
					// Get FG info from function level.
					LeftFG = this->BasicBlock->GetFunc()->GetDefFGInfo(DefHashValue);
				}
				// See if RightFG has sign info to transfer to LeftFG.
				SignMask = (RightFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
				if ((SignMask != 0) && (SignMask != (LeftFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS))) {
					// SignMask from RightFG has bits that will change LeftFG.SignMiscInfo.
					LeftFG.SignMiscInfo |= SignMask;
					MapsChanged |= this->UpdateDefOpFGInfo(LeftOp, LeftFG);
				}
			}
		}
#endif
	} // end of register case for LeftOp
	else if (OpIsDEF && MDIsStackAccessOpnd(LeftOp, UseFP) 
		&& (!this->BasicBlock->GetFunc()->IsInOutgoingArgsRegion(LeftOp))) {
		// For stores into the stack, if the operand being stored has signedness
		//  and the stack location has no signedness, then we have a case where
		//  none of the loads from the stack location were signed, so it is
		//  safe to infer signedness of the stack location based on what is being
		//  stored into it, as no store signedness will conflict with load signedness.
		success = this->BasicBlock->GetFunc()->MDGetFGStackLocInfo(this->address, LeftOp, LeftFG);
		assert(success);
		if (0 == (LeftFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS)) {
			// No previous signedness info for the stack location.
			//  Get signedness info from RightFG.
			SignMask = (RightFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
			if ((0 != SignMask) && (FG_MASK_INCONSISTENT_SIGN != SignMask)) {
				// Operand being stored has signedness.
				//  Transfer the signedness to the stack location.
				struct FineGrainedInfo TempFG;
				TempFG.SignMiscInfo = SignMask;
				TempFG.SizeInfo = 0; // just update signedness
				success = this->BasicBlock->GetFunc()->MDUpdateFGStackLocInfo(this->address, LeftOp, TempFG);
				MapsChanged |= success;
			}
		}
	}

	// Prepare to return FG info for operator. First, OR the left and right FG infos.
	if (NewChange || MapsChanged || CurrOpTransfersSign) {
		OpFG.SignMiscInfo |= LeftFG.SignMiscInfo;
		OpFG.SizeInfo |= LeftFG.SizeInfo;
		OpFG.SignMiscInfo |= RightFG.SignMiscInfo;
		OpFG.SizeInfo |= RightFG.SizeInfo;
	}
	// An operator could override the width or signedness info of its operands.
	if (CurrOp == SMP_ADDRESS_OF) {
		// Result is 32-bit data pointer.
		OpFG.SizeInfo &= (~FG_MASK_BITWIDTH_FIELDS); // clear all width bits
		OpFG.SizeInfo |= (FG_MASK_BITWIDTH_32 | FG_MASK_DATAPOINTER);
		OpFG.SignMiscInfo &= (~FG_MASK_SIGNED);
		OpFG.SignMiscInfo |= FG_MASK_UNSIGNED;
	}

} // end of SMPInstr::InferOperatorFGInfo()


// infer width on first pass, signedness on all passes
bool SMPInstr::InferFGInfo(unsigned short IterCount) {
	bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
	struct FineGrainedInfo OpFG;
	SMPitype DFType = this->GetDataFlowType();

	assert(0 < IterCount); // start IterCount at 1, not 0.


	if (DFType != DEFAULT) {
		// We have a control flow instruction, e.g. call, return, branch, jump
		//  No data operands unless these instructions are indirect through a register,
		//  and the indirect operand is a memory operand in that case, e.g. [eax].
		return MapsChanged;
	}

	for (size_t index = 0; index < this->RTL.GetCount(); ++index) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(index);
		if (SMP_NULL_OPERATOR == CurrRT->GetOperator()) // nothing to infer
			continue;
		OpFG.SignMiscInfo = 0;
		OpFG.SizeInfo = 0;

		MapsChanged |= this->InferOperatorFGInfo(CurrRT, (1 == IterCount), OpFG);
		if (SMP_CALL == CurrRT->GetOperator()) // no LeftOp DEF
			continue;
	} // end for all RTs in the RTL

} // end of SMPInstr::InferFGInfo()

// Get the meet of the metadata types of all non-flags DEFs.
SMPMetadataType SMPInstr::GetDefMetadataType(void) {
	SMPMetadataType MeetType = DEF_METADATA_UNANALYZED;
	set<DefOrUse, LessDefUse>::iterator CurrDef;

	for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
		SMPMetadataType CurrType;
		op_t DefOp = CurrDef->GetOp();
		if (DefOp.is_reg(X86_FLAGS_REG))
			continue; // flags are always unused metadata; irrelevant
		CurrType = CurrDef->GetMetadataStatus();
		if (MeetType == CurrType)
			continue; // no meet operation to perform
		// Any time we find USED metadata, that overrides all other types.
		if (CurrType == DEF_METADATA_USED)
			return CurrType;
		if (MeetType == DEF_METADATA_UNANALYZED)
			MeetType = CurrType;
		else if (MeetType < DEF_METADATA_REDUNDANT) {
			// Conflict between types of different DEFs. It could be that
			//  a multiply or divide instruction DEFs EAX and EDX, and one
			//  of them is used in a store and the other is unused. In that
			//  case, the final MeetType is USED and we can return. Or, if
			//  one type is UNUSED and the other is REDUNDANT, we can set
			//  the final type to the REDUNDANT type and return. The USED case
			//  is handled above, so we must have the UNUSED vs. REDUNDANT case.
			assert(CurrType >= DEF_METADATA_REDUNDANT);
			MeetType = CurrType;
		}
		else { // MeetType REDUNDANT, not equal to CurrType.
			if (CurrType >= DEF_METADATA_REDUNDANT) {
				// One type is profile derived, both are REDUNDANT.
				MeetType = DEF_METADATA_PROF_REDUNDANT;
			}
			else {
				assert(DEF_METADATA_UNUSED == CurrType);
				// leave MeetType as REDUNDANT
			}
		}
	} // end for all DEFs

	return MeetType;
} // end of SMPInstr::GetDefMetadataType()

// Handle x86 opcode SIB byte annotations.
void SMPInstr::MDAnnotateSIBStackConstants(FILE *AnnotFile, op_t Opnd, ea_t offset, bool UseFP) {
	int BaseReg;
	int IndexReg;
	ea_t displacement;
	ushort ScaleFactor;
	char *disasm = DisAsmText.GetDisAsm(this->GetAddr());

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

	if (BaseReg == R_sp) { // ESP cannot be IndexReg
		// ESP-relative constant offset
				"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
				this->SMPcmd.ea, this->SMPcmd.size, offset, disasm);
	else if (UseFP && ((IndexReg == R_bp) || (BaseReg == R_bp))) {
		// EBP-relative constant offset
				"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
				this->SMPcmd.ea, this->SMPcmd.size, offset, disasm);
	}

	return;
} // end of MDAnnotateSIBStackConstants

// Emit annotations for constants used as ptr offsets from EBP or
//  ESP into the stack frame. Only pay attention to EBP-relative
//  offsets if EBP is being used as a frame pointer (UseFP == true).
void SMPInstr::AnnotateStackConstants(bool UseFP, FILE *AnnotFile) {
	op_t Opnd;
	ea_t offset;
	int BaseReg;
	int IndexReg;
	ushort ScaleFactor;
	char *disasm = DisAsmText.GetDisAsm(this->GetAddr());
#if 0
	if (this->address == 0x80925f4) {
		this->PrintOperands();
	}
#endif
	for (int i = 0; i < UA_MAXOP; ++i) {
		Opnd = this->SMPcmd.Operands[i];
		if ((Opnd.type == o_displ) || (Opnd.type == o_phrase))
			MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, offset);

		if (Opnd.type == o_displ) {
			if (Opnd.hasSIB) {
				MDAnnotateSIBStackConstants(AnnotFile, Opnd, offset, UseFP);
			}
			else { // no SIB
				if (BaseReg == R_sp) {
					// ESP-relative constant offset
							"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
							this->SMPcmd.ea, this->SMPcmd.size, offset, disasm);
				}
				else if (UseFP && (BaseReg == R_bp)) {
					// EBP-relative constant offset
							"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
							this->SMPcmd.ea, this->SMPcmd.size, offset, disasm);
				}
			} // end if (Opnd.hasSIB) ... else ...
		} // end if (Opnd.type == o_displ) 
		else if (Opnd.type == o_phrase) {
			offset = 0; // mmStrata thinks [esp] is [esp+0]
			if (Opnd.hasSIB) {
				MDAnnotateSIBStackConstants(AnnotFile, Opnd, offset, UseFP);
			}
			else { // Something like [ecx]; is it [esp] or [ebp] ?
				if (BaseReg == R_sp) {
					// ESP-relative constant offset
							"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
							this->SMPcmd.ea, this->SMPcmd.size, offset, disasm);
				}
				else if (UseFP && (BaseReg == R_bp)) {
					// EBP-relative constant offset
							"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
							this->SMPcmd.ea, this->SMPcmd.size, offset, disasm);
				}
			} // end if (Opnd.hasSIB) ... else ...
		} // end else if (Opnd.type == o_phrase)
	} // end for all operands

	// If we move a stack pointer or frame pointer into another register, we
	//  need to annotate the implicit zero offset, e.g. mov edi,esp == mov edi,esp+0
	//  and edi is becoming a stack pointer that mmStrata needs to track.
	if (this->MDIsStackPointerCopy(UseFP)) {
		// Two possibilities: a move of the stack pointer, or an "lea"
		//  opcode, e.g. lea eax,[eap+8] ==> eax:=esp+8. In the move
		//  instruction (e.g. mov eax,esp), we have the implicit zero
		//  offset from the stack pointer register, but in the lea case,
		//  we might have zero or some other offset (lea eax,[esp] has
		//  the implicit zero).
		int ESPoffset = 0;
		if (NN_lea == this->SMPcmd.itype) {
			ESPoffset = this->MDGetImmedUse();
		}
		// NOTE: Looks like this next line should be "else" because an lea instruction
		//  looks like it has a memory operand, hence it has already been handled above.
		//  We are getting duplicate annotations for lea instructions.
			if (UseFP && this->GetFirstUse()->GetOp().is_reg(R_bp)) {
				SMP_fprintf(AnnotFile,	"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
						this->SMPcmd.ea, this->SMPcmd.size, ESPoffset, disasm);
				SMP_fprintf(AnnotFile,	"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
						this->SMPcmd.ea, this->SMPcmd.size, ESPoffset, disasm);
		}
	}

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

// Emit all annotations for the instruction in the absence of RTL type inference.
void SMPInstr::EmitAnnotations(bool UseFP, bool AllocSeen, bool NeedsFrame, FILE *AnnotFile, FILE *InfoAnnotFile) {
	ea_t addr = this->address;
	flags_t InstrFlags = getFlags(addr);
	bool MemDest = this->HasDestMemoryOperand();
	bool MemSrc = this->HasSourceMemoryOperand();
	bool SecondSrcOperandImmNum = this->IsSecondSrcOperandNumeric(InstrFlags); 	// assumes 2nd source is Imm or not-numeric?!
	bool NoWarnFlag = false; // NOWARN annotation emitted?
	char *disasm = DisAsmText.GetDisAsm(this->GetAddr());
clc5q's avatar
clc5q committed

#if SMP_CHILDACCESS_ALL_CODE
	bool OrphanCode = (NULL == this->BasicBlock);
	ProfilerInformation *ProfInfo = NULL;
clc5q's avatar
clc5q committed
	if (!OrphanCode)
		ProfInfo = this->BasicBlock->GetFunc()->GetProg()->GetProfInfo();
#endif

	++OptCount[OptType]; // keep count for debugging info

	// Emit informational annotations for memory operands.
	if (MemSrc) {
		op_t MemSrcOp = this->MDGetMemUseOp();
		size_t SrcBitWidth = 8 * GetOpDataSize(MemSrcOp);
		SMP_fprintf(InfoAnnotFile, "%10x %6d INSTR MEMSRC %d", addr, this->SMPcmd.size, SrcBitWidth);
		AnnotPrintOperand(MemSrcOp, InfoAnnotFile);
		SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm);
	}
	if (MemDest) {
		op_t MemDestOp = this->MDGetMemDefOp();
		size_t DestBitWidth = 8 * GetOpDataSize(MemDestOp);
		SMP_fprintf(InfoAnnotFile, "%10x %6d INSTR MEMDEF %d", addr, this->SMPcmd.size, DestBitWidth);
		AnnotPrintOperand(MemDestOp, InfoAnnotFile);
		SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm);
	// If the instruction is a CALL (or INDIR_CALL that has been resolved to
	//  a single target address), then we need to see if the call is to a 
	//  function that has been forbidden by a security policy. If so, we
	//  need to output a security alert.
	// In the near future, we will output SPRI instrumentation to prevent
	//  the system/library call from executing.
	if ((BADADDR != this->CallTarget) && (!this->IsCallUsedAsJump())) {
		// We have a resolved call target address, either via direct or indirect call.
		string FuncName = this->GetTrimmedCalledFunctionName();
		ZST_SysCallType FuncCallType = GetCallTypeFromFuncName(FuncName);
		ZST_Policy FuncCallPolicy = GetPolicyFromCallType(FuncCallType);
		if (ZST_DISALLOW == FuncCallPolicy) {
			if ((NULL != this->GetBlock()) && (NULL != this->GetBlock()->GetFunc())) {
				SMP_fprintf(ZST_AlarmFile, "ALARM: Call to %s will be disallowed at %x in %s\n", 
					FuncName.c_str(), this->address, this->GetBlock()->GetFunc()->GetFuncName());
			}
			else {
				SMP_fprintf(ZST_AlarmFile, "ALARM: Call to %s will be disallowed at %x\n", FuncName.c_str(), this->address);
			SMP_fprintf(ZST_AlarmFile, "ALARM REASON: Call policy is DISALLOW for all calls of type %s\n", CallTypeNames[FuncCallType]);
			SMP_fprintf(InfoAnnotFile, "%10x %6d INSTR SECURITYCALL Disallow 1 1 %s \n", addr, this->SMPcmd.size, disasm);
#if SMP_DEBUG_MEM
	if (MemDest || MemSrc) {
		this->PrintOperands();
	}
#endif

	// Emit appropriate optimization annotations.
	bool SDTInstrumentation = false;
	switch (OptType) {
		case 0:  // SDT will have to handle these
		{
#if SMP_DEBUG_TYPE0
			SMP_msg("OptType 0: %x  %s\n", addr, disasm);
#endif
			// mmStrata wants to suppress warnings on the PUSH
			//  instructions that precede the LocalVarsAllocInstr
			//  (i.e. the PUSHes of callee-saved regs).
			if ((!AllocSeen || !NeedsFrame) && this->MDIsPushInstr()) {
				SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL NoWarn %s \n",
			}
			else {
				SDTInstrumentation = true;
			}
			break;
		}

		case 1:  // nothing for SDT to do
		{	SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
					addr, -1, OptExplanation[OptType], disasm);
			++AnnotationCount[OptType];
			break;
		}

		case 4:  // INC, DEC, etc.: no SDT work unless MemDest
		{	if (MemDest || MemSrc) {
				SDTInstrumentation = true;
				break;  // treat as category 0
	 		}
			SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL Always1stSrc %s \n",
					addr, -1, disasm);
			++AnnotationCount[OptType];
			break;
		}

		case 5: // ADD, etc.: If numeric 2nd src operand, no SDT work.
		{	if (MemDest || MemSrc) {
				SDTInstrumentation = true;
				break;  // treat as category 0
			}
			if (SecondSrcOperandImmNum 
				&& !this->MDIsFrameAllocInstr()
#if SPECIAL_CASE_CARRY_BORROW
				&& (this->SMPcmd.itype != NN_adc)
				&& (this->SMPcmd.itype != NN_sbb)
#endif
				) { // treat as category 1
				SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
						addr, -1, OptExplanation[OptType], disasm);
				++AnnotationCount[OptType];
			}
			break;
		}

		case 6: // Only OS code should include these; problem for SDT
		{	if (MemDest) {
				SDTInstrumentation = true;
				break;  // treat as category 0
			}
			SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL AlwaysPTR %s \n",
					addr, -OptType, disasm);
			++AnnotationCount[OptType];
			break;
		}

		case 8: // Implicitly writes to EDX:EAX, always numeric.
		{	SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL n EDX EAX ZZ %s %s \n",
					addr, -2, OptExplanation[OptType], disasm);
			++AnnotationCount[OptType];
			SDTInstrumentation = true;
			break;
		}

		case 9:  // Either writes to FP reg (cat. 1) or memory (cat. 0)
		{	if (MemDest) {
				// MemDest seems to happen too much.
				SMP_msg("Floating point MemDest: %s \n", disasm);
#endif
				SDTInstrumentation = true;
				break; // treat as category 0
			}
			SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
					addr, -1, OptExplanation[OptType], disasm);
			++AnnotationCount[OptType];
			break;
		}

		case 10: // Implicitly writes to EDX:EAX and ECX, always numeric.
		{	SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL n EDX EAX ECX ZZ %s %s \n",
					addr, -2, OptExplanation[OptType], disasm);
			++AnnotationCount[OptType];
			SDTInstrumentation = true;
			break;
		}

		default: // 2,3,7: Optimization possibilities depend on operands
		{ 
#if SMP_DEBUG2
			if (OptType ==  3) {  // MOV instr class
				if (MemDest) {
				}
				else if (!SecondSrcOperandNum) {
					SMP_msg("MOV: not 2nd op numeric: %s\n", disasm);
						this->PrintOperands();
				}
			}
#endif
			SDTInstrumentation = true;
			if (MemDest) {
#if SMP_DEBUG_XOR
				if (OptType == 2)
					SMP_msg("MemDest on OptType 2: %s\n", disasm);
#endif
				break;  // treat as category 0
			}
			if ((OptType == 2) || (OptType == 7) || SecondSrcOperandImmNum) {
				SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s %s %s \n",
						addr, -2, this->DestString(OptType), 
						OptExplanation[OptType], disasm);
				++AnnotationCount[OptType];
			}
			break;
		}
	} // end switch (OptType)
jdh8d's avatar
jdh8d committed

	// always emit stack constant annotations, in case strata is 
	// instrumenting all instructions, or trying to verify speculative annotations. 
	this->AnnotateStackConstants(UseFP, AnnotFile);
	
	// If mmStrata is going to have to deal with the
	//  instruction, then we can annotate EBP and ESP
	//  relative constant offsets. If we have emitted
	//  an annotation of type -1, there is no point
	//  in telling mmStrata about these constants.
clc5q's avatar
clc5q committed
	// Likewise, we can tell mmStrata if a MemDest is an
	//  non-directly-accessed child object.
		if (strlen(this->DeadRegsString) > 0) {
			// Optimize by informing mmStrata of dead registers. It can avoid saving
			//  and restoring dead state. This is particularly important for EFLAGS,
			//  as restoring the flags is a pipeline serializing instruction.
			SMP_fprintf(AnnotFile, "%10x %6d INSTR DEADREGS %s ZZ %s \n",
				addr, this->SMPcmd.size, this->DeadRegsString, disasm);
		}
clc5q's avatar
clc5q committed
#if SMP_CHILDACCESS_ALL_CODE
		int ChildOffset, ChildSize;
		if (MemDest && !OrphanCode
			&& ProfInfo->GetMemoryAccessInfo()->ComputeNonDirectAccessRegion(addr,
			ChildOffset, ChildSize)) {
			SMP_fprintf(AnnotFile, "%10x %6d INSTR CHILDACCESS %d %d ZZ %s \n",
clc5q's avatar
clc5q committed
				addr, this->SMPcmd.size, ChildOffset, ChildSize, disasm);
		}
#endif
	}
	return;
} // end of SMPInstr::EmitAnnotations()
/**
 * Emits Safe Returns
 * Mark the type of  the annotation as "-4". Currently  the SDT is ignoring this
 * annotation. 
 */ 
void SMPInstr::EmitSafeReturn(FILE *AnnotFile)
{
	char *disasm = DisAsmText.GetDisAsm(this->GetAddr());
	SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL SafeReturn %s\n",
		this->address, -4, disasm);
// Emit all annotations for the instruction using RTL type inference.
void SMPInstr::EmitTypeAnnotations(bool UseFP, bool AllocSeen, bool NeedsFrame, FILE *AnnotFile, FILE *InfoAnnotFile) {
	ea_t addr = this->address;
	flags_t InstrFlags = getFlags(addr);
	int TypeGroup = SMPTypeCategory[this->SMPcmd.itype];
	bool NumericDEFs = this->AllDefsNumeric();  // all DEFs are NUMERIC or CODEPTR
	bool ProfiledDEFs = this->AnyDefsProfiled();  // Some DEFs come from the profiler
	bool UnusedMetadata = this->AllDefMetadataUnused();
	bool MemDest = this->HasDestMemoryOperand();
	bool MemSrc = this->HasSourceMemoryOperand();
	bool SecondSrcOperandImmNum = this->IsSecondSrcOperandNumeric(InstrFlags); // assumes 2nd source is imm or not-numeric??
	bool NoWarnFlag = false; // NOWARN annotation emitted?
	bool CarryBorrow = ((this->SMPcmd.itype == NN_adc) 
		|| (this->SMPcmd.itype == NN_sbb));
	// Do we have the special case in which a non-NUMERIC comes into
	//  an add with carry or subtract with borrow and the result
	//  has been inferred to be NUMERIC?
	bool TypeChange = CarryBorrow && (!IsNumeric(this->AddSubUseType))
				&& NumericDEFs;
	SMPMetadataType DefMetadataType = this->GetDefMetadataType();
clc5q's avatar
clc5q committed
	ProfilerInformation *ProfInfo;
	ProfInfo = this->BasicBlock->GetFunc()->GetProg()->GetProfInfo();
	char *disasm = DisAsmText.GetDisAsm(this->GetAddr());

	++OptCount[this->OptType]; // keep count for debugging info

	if (this->IsNop())
		TypeGroup = 1; // no-op idioms need their category reset

	// Emit appropriate optimization annotations.
	bool SDTInstrumentation = false;
	// Emit informational annotations for memory operands.
	if (MemSrc) {
		op_t MemSrcOp = this->MDGetMemUseOp();
		size_t SrcBitWidth = 8 * GetOpDataSize(MemSrcOp);
		SMP_fprintf(InfoAnnotFile, "%10x %6zu INSTR MEMSRC %zu", addr, this->SMPcmd.size, SrcBitWidth);
		AnnotPrintOperand(MemSrcOp, InfoAnnotFile);
		SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm);
	}
	if (MemDest) {
		op_t MemDestOp = this->MDGetMemDefOp();
		size_t DestBitWidth = 8 * GetOpDataSize(MemDestOp);
		SMP_fprintf(InfoAnnotFile, "%10x %6zu INSTR MEMDEF %zu", addr, this->SMPcmd.size, DestBitWidth);
		AnnotPrintOperand(MemDestOp, InfoAnnotFile);
		SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm);
	// If the instruction is a CALL (or INDIR_CALL that has been resolved to
	//  a single target address), then we need to see if the call is to a 
	//  function that has been forbidden by a security policy. If so, we
	//  need to output a security alert.
	// In the near future, we will output SPRI instrumentation to prevent
	//  the system/library call from executing.
	if ((BADADDR != this->CallTarget) && (!this->IsCallUsedAsJump())) {
		// We have a resolved call target address, either via direct or indirect call.
		string FuncName = this->GetTrimmedCalledFunctionName();
		ZST_SysCallType FuncCallType = GetCallTypeFromFuncName(FuncName);
		ZST_Policy FuncCallPolicy = GetPolicyFromCallType(FuncCallType);
		if (ZST_DISALLOW == FuncCallPolicy) {
			SMP_fprintf(ZST_AlarmFile, "ALARM: Call to %s will be disallowed at %x in %s\n", 
				FuncName.c_str(), this->address, this->GetBlock()->GetFunc()->GetFuncName());
			SMP_fprintf(ZST_AlarmFile, "ALARM REASON: Call policy is DISALLOW for all calls of type %s\n", CallTypeNames[FuncCallType]);
			SMP_fprintf(InfoAnnotFile, "%10x %6d INSTR SECURITYCALL Disallow 1 1 %s \n", addr, this->SMPcmd.size, disasm);
	// If the DEF metadata is all unused, mmStrata can skip the instruction.
	//  We omit this for groups 1 and 14, so that the metadata analysis
	//  does not get statistical credit for instructions that were already
	//  getting -1 annotations without analysis.
	// We also cannot skip NN_adc and NN_sbb instructions that change the
	//  type of the incoming register.
	if ((1 != TypeGroup) && (14 != TypeGroup) && (!this->MDIsInterruptCall())
		&& !TypeChange) {
		if (UnusedMetadata) {
			SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL MetadataUnused %s \n",
						addr, -1, disasm);
			++AnnotationCount[this->OptType];
			return;
		}
		else if (DEF_METADATA_REDUNDANT == DefMetadataType) {
			SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL MetadataRedundant %s \n",