Skip to content
Snippets Groups Projects
SMPInstr.cpp 166 KiB
Newer Older
	if (DebugFlag) {
		msg("opcode: %d TypeCategory: %d\n", this->SMPcmd.itype, TypeCategory);
	}

	// If we are already finished with all types, return false.
	if (this->TypeInferenceComplete)
		return false;

	// The control flow instructions can be handled simply based on their type
	//  and do not need an RTL walk.
	SMPitype DFAType = this->GetDataFlowType();
	if (DebugFlag) {
		msg("DFAType: %d  CategoryInference: %d\n", DFAType, this->CategoryInference);
	}
	if ((DFAType >= JUMP) && (DFAType <= INDIR_CALL)) {
		// All USEs are either the flags (NUMERIC) or the target address (CODEPTR).
		CurrUse = this->GetFirstUse();
		while (CurrUse != this->GetLastUse()) {
			UseOp = CurrUse->GetOp();
			if (UseOp.is_reg(X86_FLAGS_REG))
				CurrUse = this->SetUseType(UseOp, NUMERIC);
			else
				CurrUse = this->SetUseType(UseOp, CODEPTR);
			++CurrUse;
		}
		this->TypeInferenceComplete = true;
		return true;
	}

	// First, see if we can infer something about DEFs and USEs just from the 
	//  type category of the instruction.
	if (!this->CategoryInference) {
		switch (TypeCategory) {
			case 0: // no inference possible just from type category
			case 1: // no inference possible just from type category
			case 3:  // MOV instructions; inference will come from source to dest in RTL walk.
			case 5:  // binary arithmetic; inference will come in RTL walk.
			case 10:  // binary arithmetic; inference will come in RTL walk.
			case 11:  // push and pop instructions; inference will come in RTL walk.
			case 12:  // exchange instructions; inference will come in RTL walk.
				this->CategoryInference = true;
				break;

			case 2: // Result type is always NUMERIC.
			case 7: // Result type is always NUMERIC.
			case 8: // Result type is always NUMERIC.
			case 9: // Result type is always NUMERIC.
			case 13: // Result type is always NUMERIC.
			case 14: // Result type is always NUMERIC.
			case 15: // Result type is always NUMERIC.
				CurrDef = this->GetFirstDef();
				while (CurrDef != this->GetLastDef()) {
					if (NUMERIC != CurrDef->GetType()) {
						DefOp = CurrDef->GetOp();
						SSANum = CurrDef->GetSSANum();
						CurrDef = this->SetDefType(DefOp, NUMERIC);
						changed = true;
						if (this->BasicBlock->IsLocalName(DefOp)) {
							(void) this->BasicBlock->PropagateLocalDefType(DefOp, NUMERIC,
								this->GetAddr());
						}
						else { // global name
							this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
							(void) this->BasicBlock->PropagateGlobalDefType(DefOp, NUMERIC,
								SSANum);
						}
					}
					++CurrDef;
				}
				CategoryInference = true;
				break;

			case 4: // Unary INC, DEC, etc.: dest=source, so type remains the same
				assert(1 == this->RTL.GetCount());
				assert(this->RTL.GetRT(0)->HasRightSubTree());
				UseOp = this->RTL.GetRT(0)->GetLeftOperand(); // USE == DEF
				CurrUse = this->Uses.FindRef(UseOp);
				assert(CurrUse != this->GetLastUse());
				if (UNINIT != CurrUse->GetType()) {
					// Only one USE, and it has a type assigned, so assign that type
					// to the DEF.
					CurrDef = this->GetFirstDef();
					while (CurrDef != this->GetLastDef()) {
						// Two DEFs: EFLAGS is NUMERIC, dest==source
						DefOp = CurrDef->GetOp();
						SSANum = CurrDef->GetSSANum();
						if (DefOp.is_reg(X86_FLAGS_REG)) {
							CurrDef = this->SetDefType(DefOp, NUMERIC);
							if (this->BasicBlock->IsLocalName(DefOp)) {
								(void) this->BasicBlock->PropagateLocalDefType(DefOp, NUMERIC,
									this->GetAddr());
							}
							else { // global name
								this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
								(void) this->BasicBlock->PropagateGlobalDefType(DefOp, NUMERIC,
									SSANum);
							}
						}
						else {
							CurrDef = this->SetDefType(DefOp, CurrUse->GetType());
							if (this->BasicBlock->IsLocalName(DefOp)) {
								(void) this->BasicBlock->PropagateLocalDefType(DefOp, NUMERIC,
									this->GetAddr());
							}
							else { // global name
								this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
								(void) this->BasicBlock->PropagateGlobalDefType(DefOp, NUMERIC,
									SSANum);
							}
						}
						++CurrDef;
					}
					CategoryInference = true;
					changed = true;
				}
				break;

			case 6: // Result is always POINTER
				DefOp = this->GetFirstDef()->GetOp();
				SSANum = this->GetFirstDef()->GetSSANum();
				CurrDef = this->SetDefType(DefOp, POINTER);
				CategoryInference = true;
				changed = true;
				if (this->BasicBlock->IsLocalName(DefOp)) {
					(void) this->BasicBlock->PropagateLocalDefType(DefOp, NUMERIC,
						this->GetAddr());
				}
				else { // global name
					this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
					(void) this->BasicBlock->PropagateGlobalDefType(DefOp, NUMERIC,
						SSANum);
				}
				break;

			default:
				msg("ERROR: Unknown type category for %s\n", this->GetDisasm());
				CategoryInference = true;
				break;
		} // end switch on TypeCategory
	} // end if (!CategoryInference)

	// Walk the RTL and infer types based on operators and operands.
	if (DebugFlag) {
		msg("RTcount: %d\n", this->RTL.GetCount());
	}
	for (size_t index = 0; index < this->RTL.GetCount(); ++index) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(index);
		if (UNINIT != CurrRT->GetOperatorType()) // all done with this RT  **!!** NO
			continue;
		if (SMP_NULL_OPERATOR == CurrRT->GetOperator()) // nothing to infer
			continue;
		changed |= this->InferOperatorType(CurrRT);
		if (DebugFlag) {
			msg("returned from InferOperatorType\n");
		}
	} // end for all RTs in the RTL
	return changed;
} // end of SMPInstr::InferTypes()

// Infer the type of an operator within an RT based on the types of its operands and
//  based on the operator itself. Recurse down the tree if necessary.
// Return true if the operator type of the RT is updated.
bool SMPInstr::InferOperatorType(SMPRegTransfer *CurrRT) {
	bool updated = false;
	bool LeftNumeric, RightNumeric;
	bool LeftPointer, RightPointer;
	set<DefOrUse, LessDefUse>::iterator CurrDef;
	set<DefOrUse, LessDefUse>::iterator CurrUse;
	SMPOperandType LeftType = UNINIT;
	SMPOperandType RightType = UNINIT;
	op_t UseOp, DefOp;
	SMPoperator CurrOp = CurrRT->GetOperator();
	bool DebugFlag = false;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
	DebugFlag |= (0 == strcmp("__libc_csu_fini", this->BasicBlock->GetFunc()->GetFuncName()));
#endif

	// See if we can infer the operator type from the operator itself. If so,
	//  we don't need to recurse down the tree because lower operators no longer
	//  matter to the final DEF.
#if SMP_VERBOSE_DEBUG_BUILD_RTL
	msg("Entered InferOperatorType for CurrOp: %d\n", CurrOp);
#endif
	switch (CurrOp) {
		case SMP_NULL_OPERATOR:
			break;

		case SMP_CALL:  // CALL instruction
			if (UNINIT == CurrRT->GetOperatorType()) {
				CurrRT->SetOperatorType(CODEPTR);
				updated = true;
				UseOp = CurrRT->GetRightOperand();
				CurrUse = this->Uses.FindRef(UseOp);
				assert(CurrUse != this->GetLastUse());
				if (UNINIT == CurrUse->GetType()) {
					CurrUse = this->SetUseType(UseOp, CODEPTR);
				}
				else if (CODEPTR != CurrUse->GetType()) {
					msg("WARNING: call target is type %d, setting to CODEPTR at %x in %s\n",
						CurrUse->GetType(), this->GetAddr(), this->GetDisasm());
					CurrUse = this->SetUseType(UseOp, CODEPTR);
				}
			}
			break;

		case SMP_INPUT:  // input from port
			if (UNINIT == CurrRT->GetOperatorType()) {
				CurrRT->SetOperatorType(UNKNOWN);  // Leave DEF as UNINIT and infer later
				updated = true;
			}
			break;

		case SMP_OUTPUT: // output to port
			break;

		case SMP_ADDRESS_OF: // take effective address
			if (UNINIT == CurrRT->GetOperatorType()) {
				CurrRT->SetOperatorType(POINTER);
				// Left operand is having its address taken, but we cannot infer what its
				//  type is.
				updated = true;
			}
			break;

		case SMP_U_LEFT_SHIFT: // unsigned left shift
		case SMP_S_LEFT_SHIFT: // signed left shift
		case SMP_U_RIGHT_SHIFT: // unsigned right shift
		case SMP_S_RIGHT_SHIFT: // signed 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_ADD_CARRY:   // add with carry
		case SMP_SUBTRACT_BORROW:  // subtract with borrow
		case SMP_U_MULTIPLY:
		case SMP_S_MULTIPLY:
		case SMP_U_DIVIDE:
		case SMP_S_DIVIDE:
		case SMP_U_REMAINDER:
		case SMP_SIGN_EXTEND:
		case SMP_ZERO_EXTEND:
		case SMP_BITWISE_NOT: // unary operator
		case SMP_BITWISE_XOR:
		case SMP_NEGATE:    // unary negation
		case SMP_S_COMPARE: // signed compare (subtraction-based)
		case SMP_U_COMPARE: // unsigned compare (AND-based)
		case SMP_LESS_THAN: // boolean test operators
		case SMP_GREATER_THAN:
		case SMP_LESS_EQUAL:
		case SMP_GREATER_EQUAL:
		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_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
			if (UNINIT == CurrRT->GetOperatorType()) {
				CurrRT->SetOperatorType(NUMERIC);
				updated = true;
			}
			// Left operand should be NUMERIC if it exists.
			UseOp = CurrRT->GetLeftOperand();
			if (UseOp.type != o_void) {
				CurrUse = this->Uses.FindRef(UseOp);
				if (CurrUse == this->GetLastUse()) {
					msg("WARNING: Adding missing USE of ");
					PrintOperand(UseOp);
					msg(" in %s\n", this->GetDisasm());
					this->Uses.SetRef(UseOp, NUMERIC, -1);
					updated = true;
				}
				else if (UNINIT == CurrUse->GetType()) {
					CurrUse = this->SetUseType(UseOp, NUMERIC);
					updated = true;
				}
			}
			// Right operand should be NUMERIC if it exists.
			if (CurrRT->HasRightSubTree()) {
				// Recurse into subtree
				updated |= this->InferOperatorType(CurrRT->GetRightTree());
			}
			else {
				UseOp = CurrRT->GetRightOperand();
				if (UseOp.type != o_void) {
					CurrUse = this->Uses.FindRef(UseOp);
					if (CurrUse == this->GetLastUse()) {
						msg("WARNING: Adding missing USE of ");
						PrintOperand(UseOp);
						msg(" in %s\n", this->GetDisasm());
						this->Uses.SetRef(UseOp, NUMERIC, -1);
						updated = true;
					}
					else if (UNINIT == CurrUse->GetType()) {
						CurrUse = this->SetUseType(UseOp, NUMERIC);
						updated = true;
					}
				}
			}
			break;

		case SMP_INCREMENT:
		case SMP_DECREMENT:
			// The type of the right operand is propagated to the operator, or vice
			//  versa, whichever receives a type first.
			assert(!CurrRT->HasRightSubTree());
			UseOp = CurrRT->GetLeftOperand();
			assert(o_void != UseOp.type);
			CurrUse = this->Uses.FindRef(UseOp);
			if (CurrUse == this->GetLastUse()) {
				msg("WARNING: Adding missing USE of ");
				PrintOperand(UseOp);
				msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm());
				this->Uses.SetRef(UseOp);
				updated = true;
				break;
			}
			if (UNINIT == CurrRT->GetOperatorType()) {
				if (UNINIT != CurrUse->GetType()) {
					// Propagate operand type up to the operator.
					CurrRT->SetOperatorType(CurrUse->GetType());
					updated = true;
				}
			}
			else if (UNINIT == CurrUse->GetType()) {
				// Propagate operator type to operand.
				CurrUse = this->SetUseType(UseOp, CurrRT->GetOperatorType());
				updated = true;
			}
			break;

		case SMP_ADD:
		case SMP_SUBTRACT:
		case SMP_BITWISE_AND:
		case SMP_BITWISE_OR:
			// If both operands are NUMERIC, operator and result are NUMERIC.
			// If one operand is NUMERIC and the other is not UNINIT and not NUMERIC,
			//  then the operator and the result will inherit this second type.
			if (UNINIT == CurrRT->GetOperatorType()) {
				UseOp = CurrRT->GetLeftOperand();
				assert(o_void != UseOp.type);
				CurrUse = this->Uses.FindRef(UseOp);
				if (CurrUse == this->GetLastUse()) {
					msg("WARNING: Adding missing USE of ");
					PrintOperand(UseOp);
					msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm());
					this->Uses.SetRef(UseOp);
					updated = true;
					LeftNumeric = false;
					break;
					LeftType = CurrUse->GetType();
					LeftNumeric = (NUMERIC == LeftType);
#if SMP_VERBOSE_DEBUG_BUILD_RTL
					msg("LeftType: %d LeftNumeric: %d\n", LeftType, LeftNumeric);
#endif
				// Process right operand
				if (CurrRT->HasRightSubTree()) {
					updated |= this->InferOperatorType(CurrRT->GetRightTree());
					RightType = CurrRT->GetRightTree()->GetOperatorType();
					if (UNINIT == RightType) {
						break;
					}
					else {
						RightNumeric = (NUMERIC == RightType);
#if SMP_VERBOSE_DEBUG_BUILD_RTL
						msg("Right subtree RightType: %dRightNumeric: %d\n", RightType, RightNumeric);
#endif
					}
				}
				else {
					UseOp = CurrRT->GetRightOperand();
					CurrUse = this->Uses.FindRef(UseOp);
					if (CurrUse == this->GetLastUse()) {
						msg("WARNING: Adding missing USE of ");
						PrintOperand(UseOp);
						msg(" in %s\n", this->GetDisasm());
						this->Uses.SetRef(UseOp);
						updated = true;
						RightNumeric = false;
						break;
						RightType = CurrUse->GetType();
						RightNumeric = (NUMERIC == RightType);
#if SMP_VERBOSE_DEBUG_BUILD_RTL
						msg("RightType: %d RightNumeric: %d\n", RightType, RightNumeric);
#endif
				} // end if RightSubtree else RightOperand
				// Infer operator type from LeftNumeric and RightNumeric
				LeftPointer = ((LeftType >= POINTER) && (LeftType <= HEAPPTR));
				RightPointer = ((RightType >= POINTER) && (RightType <= HEAPPTR));
				if (LeftNumeric && RightNumeric) {
					CurrRT->SetOperatorType(NUMERIC);
					updated = true;
				}
				else if (LeftNumeric || RightNumeric) {
					if (LeftNumeric && (UNINIT != RightType)) {
						CurrRT->SetOperatorType(RightType);
						updated = true;
					}
					else if (RightNumeric && (UNINIT != LeftType)) {
						CurrRT->SetOperatorType(LeftType);
						updated = true;
					}
				}
				else if (LeftPointer && RightPointer) {
					// Arithmetic on two pointers
					if (SMP_ADD == CurrOp) {
						CurrRT->SetOperatorType(UNKNOWN);
					}
					else if (SMP_SUBTRACT == CurrOp) {
						CurrRT->SetOperatorType(PTROFFSET);
					}
					else { // bitwise AND or OR of two pointers
						msg("WARNING: hash of two pointers in %s\n", this->GetDisasm());
						CurrRT->SetOperatorType(NUMERIC); // hash operation?
					}
					updated = true;
				}
				else if ((LeftPointer && (RightType == PTROFFSET))
					|| (RightPointer && (LeftType == PTROFFSET))) {
					// Arithmetic on PTR and PTROFFSET
					if (SMP_ADD == CurrOp) {
						// We assume (A-B) is being added to B or vice versa **!!**
						CurrRT->SetOperatorType(POINTER);
					}
					else if (SMP_SUBTRACT == CurrOp) {
						// We assume B - (B - A) == A    **!!**
						CurrRT->SetOperatorType(POINTER);
					}
					else { // bitwise AND or OR of pointer and pointer difference
						msg("WARNING: hash of PTROFFSET and POINTER at %x in %s\n",
							this->GetAddr(), this->GetDisasm());
						CurrRT->SetOperatorType(NUMERIC); // hash operation?
					}
					updated = true;
				}
			} // end if UNINIT operator type
			else if (CurrRT->HasRightSubTree()) {
				// Must need to iterate through the right tree again, as the operator
				//  has been typed.
				updated |= this->InferOperatorType(CurrRT->GetRightTree());
			}
			break;

		case SMP_ASSIGN:
			// If right operand has a type, it becomes the type of the SMP_ASSIGN
			//  operator and also of the left operand.
			if ((UNINIT == CurrRT->GetOperatorType()) && !CurrRT->HasRightSubTree()) {
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				msg("SMP_ASSIGN with UNINIT operator and no subtree.\n");
#endif
				// we have a right operand, still have not inferred SMP_ASSIGN type
				UseOp = CurrRT->GetRightOperand();
				if (o_void == UseOp.type) {
					msg("ERROR: void operand for SMP_ASSIGN in %s\n", this->GetDisasm());
					return false;
				}
				else {
#if SMP_VERBOSE_DEBUG_BUILD_RTL
					msg("SMP_ASSIGN with right operand op_t.type: %d\n", UseOp.type);
#endif
					CurrUse = this->Uses.FindRef(UseOp);
					if (CurrUse == this->GetLastUse()) {
						msg("WARNING: Adding missing USE of ");
						PrintOperand(UseOp);
						msg(" in %s\n", this->GetDisasm());
						this->Uses.SetRef(UseOp);
						updated = true;
					}
					else if (UNINIT != CurrUse->GetType()) {
#if SMP_VERBOSE_DEBUG_BUILD_RTL
						msg("SMP_ASSIGN with right operand type %d\n", CurrUse->GetType());
#endif
						// SMP_ASSIGN operator and DEF inherit type of the USE
						CurrRT->SetOperatorType(CurrUse->GetType());
						DefOp = CurrRT->GetLeftOperand();
						CurrDef = this->Defs.FindRef(DefOp);
						assert(CurrDef != this->GetLastDef()); // found it
						if (CurrDef->GetType() != CurrUse->GetType()) {
#if SMP_VERBOSE_DEBUG_BUILD_RTL
							msg("SMP_ASSIGN changing DEF type to USE type.\n");
#endif
							// DEF type is changing.
							CurrDef = this->SetDefType(DefOp, CurrUse->GetType());
#if SMP_VERBOSE_DEBUG_BUILD_RTL
							msg("SMP_ASSIGN changed DEF type to USE type.\n");
#endif
							if (this->BasicBlock->IsLocalName(DefOp)) {
#if SMP_VERBOSE_DEBUG_BUILD_RTL
								msg("SMP_ASSIGN DEF name was local.\n");
#endif
								(void) this->BasicBlock->PropagateLocalDefType(DefOp,
									CurrUse->GetType(),	this->GetAddr());
							}
							else { // global name
#if SMP_VERBOSE_DEBUG_BUILD_RTL
								msg("SMP_ASSIGN DEF name was global.\n");
#endif
								int SSANum = CurrDef->GetSSANum();
#if SMP_VERBOSE_DEBUG_BUILD_RTL
								msg("SMP_ASSIGN DEF SSA: %d\n", SSANum);
#endif
								this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
								(void) this->BasicBlock->PropagateGlobalDefType(DefOp,
									CurrUse->GetType(), SSANum);
							}
						}
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				msg("SMP_ASSIGN with operator type: %d\n", CurrRT->GetOperatorType());
#endif
				if (CurrRT->HasRightSubTree()) { // we have a right subtree
					updated |= this->InferOperatorType(CurrRT->GetRightTree());
					RightType = CurrRT->GetRightTree()->GetOperatorType();
#if SMP_VERBOSE_DEBUG_BUILD_RTL
					msg("Right subtree RightType: %d\n", RightType);
#endif
				else {
					UseOp = CurrRT->GetRightOperand();
					CurrUse = this->Uses.FindRef(UseOp);
					assert(CurrUse != this->GetLastUse());
					RightType = CurrUse->GetType();
#if SMP_VERBOSE_DEBUG_BUILD_RTL
					msg("RightType: %d\n", RightType);
#endif
				}
				if ((UNINIT == CurrRT->GetOperatorType()) && (UNINIT != RightType)) {
					// We are now ready to propagate the type from the right
					CurrRT->SetOperatorType(RightType);
					updated = true;
					// Propagate ASSIGN type to left (DEF) operand.
					DefOp = CurrRT->GetLeftOperand();
					CurrDef = this->Defs.FindRef(DefOp);
					assert(CurrDef != this->GetLastDef());
#if SMP_VERBOSE_DEBUG_BUILD_RTL
					msg("Propagated Right subtree RightType: %d\n", RightType);
#endif
					if ((CurrDef->GetType() != UNINIT) && (CurrDef->GetType() != RightType)) {
						msg("WARNING: changing type of ASSIGN DEF from %d to %d at %x in %s\n",
							CurrDef->GetType(), RightType, this->GetAddr(), this->GetDisasm());
						CurrDef = this->SetDefType(DefOp, RightType);
						if (this->BasicBlock->IsLocalName(DefOp)) {
							(void) this->BasicBlock->PropagateLocalDefType(DefOp,
									RightType, this->GetAddr());
						}
						else { // global name
							int SSANum = CurrDef->GetSSANum();
							this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
							(void) this->BasicBlock->PropagateGlobalDefType(DefOp, RightType,
								SSANum);
						}
				} // end if propagating type from the right operand
			} // end if UNINIT operator and no subtree ... else ...
			break;

		default:
			msg("Unknown operator in %s\n", this->GetDisasm());
			break;
	} // end switch on operator

	return updated;
} // end of SMPInstr::InferOperatorType()

// Handle x86 opcode SIB byte annotations.
void SMPInstr::MDAnnotateSIBStackConstants(FILE *AnnotFile, op_t Opnd, ea_t offset, bool UseFP) {
	int BaseReg = sib_base(Opnd);
	short IndexReg = sib_index(Opnd);
	if (BaseReg == R_none) {
		msg("BaseReg of R_none at %x\n", this->address);
	}
	if (BaseReg == R_sp) { // ESP cannot be IndexReg
		// ESP-relative constant offset
		qfprintf(AnnotFile,
				"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
				this->SMPcmd.ea, this->SMPcmd.size, offset, this->disasm);
	}
	else if (UseFP && ((IndexReg == R_bp) || ((BaseReg == R_bp) && (Opnd.type != o_mem)))) {
		// EBP-relative constant offset
		qfprintf(AnnotFile,
				"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
				this->SMPcmd.ea, this->SMPcmd.size, offset, this->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;
#if 0
	if (this->address == 0x80925f4) {
		msg("PROBLEM INSTRUCTION: \n");
		this->PrintOperands();
	}
#endif
	for (int i = 0; i < UA_MAXOP; ++i) {
		Opnd = SMPcmd.Operands[i];
		if (Opnd.type == o_displ) {
			ea_t offset = Opnd.addr;
			if (Opnd.hasSIB) {
				MDAnnotateSIBStackConstants(AnnotFile, Opnd, offset, UseFP);
			}
			else { // no SIB
				ushort BaseReg = Opnd.reg;
				if (BaseReg == R_sp) {
					// ESP-relative constant offset
					qfprintf(AnnotFile,
							"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
							SMPcmd.ea, SMPcmd.size, offset, disasm);
				}
				else if (UseFP && (BaseReg == R_bp)) {
					// EBP-relative constant offset
					qfprintf(AnnotFile,
							"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
							SMPcmd.ea, SMPcmd.size, offset, disasm);
				}
			} // end if (Opnd.hasSIB) ... else ...
		} // end if (Opnd.type == o_displ) 
		else if (Opnd.type == o_phrase) {
			ea_t offset = 0; // mmStrata thinks [esp] is [esp+0]
			if (Opnd.hasSIB) {
				MDAnnotateSIBStackConstants(AnnotFile, Opnd, offset, UseFP);
			}
			else { // Something like [ecx]
				ushort BaseReg = Opnd.reg;
				if (BaseReg == R_sp) {
					// ESP-relative constant offset
					qfprintf(AnnotFile,
							"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
							SMPcmd.ea, SMPcmd.size, offset, disasm);
				}
				else if (UseFP && (BaseReg == R_bp)) {
					// EBP-relative constant offset
					qfprintf(AnnotFile,
							"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
							SMPcmd.ea, 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)) {
		if (UseFP && this->GetFirstUse()->GetOp().is_reg(R_bp)) {
			qfprintf(AnnotFile,	"%10x %6d PTRIMMEDEBP STACK 0 displ %s\n",
					SMPcmd.ea, SMPcmd.size, disasm);
		}
		else {
			qfprintf(AnnotFile,	"%10x %6d PTRIMMEDESP STACK 0 displ %s\n",
					SMPcmd.ea, SMPcmd.size, 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, FILE *AnnotFile) {
	ea_t addr = this->address;
	flags_t InstrFlags = getFlags(addr);
	bool MemDest = this->HasDestMemoryOperand();
	bool MemSrc = this->HasSourceMemoryOperand();
	bool SecondSrcOperandNum = this->IsSecondSrcOperandNumeric(InstrFlags);

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

#if SMP_DEBUG_MEM
	if (MemDest || MemSrc) {
		msg("OptType: %d %s", OptType, disasm);
		this->PrintOperands();
	}
#endif

	// Emit appropriate optimization annotations.
	bool SDTInstrumentation = false;
	switch (OptType) {
		case 0:  // SDT will have to handle these
		{
#if SMP_DEBUG_TYPE0
			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 && this->MDIsPushInstr()) {
				qfprintf(AnnotFile, "%10x %6d INSTR LOCAL NoWarn %s \n",
						addr, -3, disasm);
			}
			else {
				SDTInstrumentation = true;
			}
			break;
		}

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

		case 4:  // INC, DEC, etc.: no SDT work unless MemDest
		{	if (MemDest || MemSrc) {
				SDTInstrumentation = true;
				break;  // treat as category 0
	 		}
			qfprintf(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 (SecondSrcOperandNum && !this->MDIsFrameAllocInstr()) { // treat as category 1
				qfprintf(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
			}
			qfprintf(AnnotFile, "%10x %6d INSTR LOCAL AlwaysPTR %s \n",
					addr, -OptType, disasm);
			++AnnotationCount[OptType];
			break;
		}

		case 8: // Implicitly writes to EDX:EAX, always numeric.
		{	qfprintf(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) {
#if SMP_DEBUG
				// MemDest seems to happen too much.
				msg("Floating point MemDest: %s \n", disasm);
#endif
				SDTInstrumentation = true;
				break; // treat as category 0
			}
			qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
					addr, -1, OptExplanation[OptType], disasm);
			++AnnotationCount[OptType];
			break;
		}

		default: // 2,3,7: Optimization possibilities depend on operands
		{ 
#if SMP_DEBUG2
			if (OptType ==  3) {  // MOV instr class
				if (MemDest) {
					msg("MemDest on MOV: %s\n", disasm);
				}
				else if (!SecondSrcOperandNum) {
					msg("MOV: not 2nd op numeric: %s\n", disasm);
						this->PrintOperands();
				}
			}
#endif
			SDTInstrumentation = true;
			if (MemDest) {
#if SMP_DEBUG_XOR
				if (OptType == 2)
					msg("MemDest on OptType 2: %s\n", disasm);
#endif
				break;  // treat as category 0
			}
			if ((OptType == 2) || (OptType == 7) || SecondSrcOperandNum) {
				qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s %s %s \n",
						addr, -2, this->DestString(OptType), 
						OptExplanation[OptType], disasm);
				++AnnotationCount[OptType];
			}
			break;
		}
	} // end switch (OptType)
	
	// 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.
	if (SDTInstrumentation) {
		this->AnnotateStackConstants(UseFP, AnnotFile);
		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.
			qfprintf(AnnotFile, "%10x %6d INSTR DEADREGS %s ZZ %s \n",
				addr, this->SMPcmd.size, this->DeadRegsString, disasm);
		}
	}
	return;
} // end of SMPInstr::EmitAnnotations()
// Emit all annotations for the instruction using RTL type inference.
void SMPInstr::EmitTypeAnnotations(bool UseFP, bool AllocSeen, FILE *AnnotFile) {
	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 MemDest = this->HasDestMemoryOperand();
	bool MemSrc = this->HasSourceMemoryOperand();
	bool SecondSrcOperandNum = this->IsSecondSrcOperandNumeric(InstrFlags);

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

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

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

		case 4:  // INC, DEC, etc.: no SDT work unless MemDest
		{	if (MemDest || MemSrc) { // pretty conservative here?
				SDTInstrumentation = true;
				break;  // treat as category 0
	 		}
			qfprintf(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 1
			if (MemDest || MemSrc) {
				SDTInstrumentation = true;
				break;  // treat as category 0
			}
#endif
			if (SecondSrcOperandNum && !this->MDIsFrameAllocInstr()) { // treat as category 1
				qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
						addr, -1, OptExplanation[OptType], disasm);
				++AnnotationCount[OptType];
			}
			else if (NumericDEFs) {
				qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s NumericDEFs %s \n",
						addr, -2, this->DestString(OptType), disasm);
				++AnnotationCount[OptType];
			}
			else {
				SDTInstrumentation = true;
			}
			break;
		}

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

		case 8: // Implicitly writes to EDX:EAX, always numeric.
		{	qfprintf(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) {
				SDTInstrumentation = true;
#if 0
				if (NumericDEFs) {
					qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s NumericDEFs %s \n",
						addr, -2, this->DestString(OptType), disasm);
					++AnnotationCount[OptType];
				}
#endif
			}
			else {
				qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
						addr, -1, OptExplanation[OptType], disasm);
				++AnnotationCount[OptType];
			}
			break;
		}

		default: // 2,3,7: Optimization possibilities depend on operands
		{ 
			SDTInstrumentation = true;
#if 1
			if (MemDest) {
				break;  // treat as category 0
			}
#endif
			if ((OptType == 2) || (OptType == 7) || SecondSrcOperandNum) {
				qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s %s %s \n",
						addr, -2, this->DestString(OptType), 
						OptExplanation[OptType], disasm);
				++AnnotationCount[OptType];
			}
			else if (NumericDEFs) { // NUMERIC move instruction
				qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s NumericDEFs %s \n",
						addr, -2, this->DestString(OptType), disasm);
				++AnnotationCount[OptType];
			}
			break;
		}
	} // end switch (OptType)
	
	// 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.
	if (SDTInstrumentation) {
		this->AnnotateStackConstants(UseFP, AnnotFile);
		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.
			qfprintf(AnnotFile, "%10x %6d INSTR DEADREGS %s ZZ %s \n",
				addr, this->SMPcmd.size, this->DeadRegsString, disasm);
		}
	}
	return;
} // end of SMPInstr::EmitTypeAnnotations()

// Build the RTL for an instruction with a unary opcode
bool SMPInstr::BuildUnaryRTL(SMPoperator UnaryOp) {
	size_t OpNum;
	bool DestFound = false;
	SMPRegTransfer *TempRT = NULL;

	op_t VoidOp;
	VoidOp.type = o_void;

	op_t FPRegOp;
	FPRegOp.type = o_fpreg;  // floating point register stack
	FPRegOp.reg = 0;

	op_t FlagsOp;
	FlagsOp.type = o_reg;
	FlagsOp.reg = X86_FLAGS_REG;