Skip to content
Snippets Groups Projects
SMPInstr.cpp 207 KiB
Newer Older
				}
				if (CurrRT->HasRightSubTree()) {
					// Must need to iterate through the right tree again, as the operator
					//  has been typed.
					if (UNINIT == RightType) {
						CurrRT->GetRightTree()->SetOperatorType(CurrRT->GetOperatorType(), this);
						updated = true;
					}
					updated |= this->InferOperatorType(CurrRT->GetRightTree());
clc5q's avatar
clc5q committed
					break;
				}
				else { // right operand; propagate operator type if needed
clc5q's avatar
clc5q committed
					if (UNINIT == RightType) {
						CurrUse = this->SetUseType(RightOp, CurrRT->GetOperatorType());
						updated = true;
						assert(CurrUse != this->GetLastUse());
clc5q's avatar
clc5q committed
						break;
		case SMP_SUBTRACT:
			// Extract the current types of right and left operands and the operator.
			OperType = CurrRT->GetOperatorType();
			LeftOp = CurrRT->GetLeftOperand();
			LeftUse = this->Uses.FindRef(LeftOp);
			assert(LeftUse != this->GetLastUse()); // found it
			LeftType = LeftUse->GetType();
			if (CurrRT->HasRightSubTree()) {
				RightType = CurrRT->GetRightTree()->GetOperatorType();
			}
			else {
				RightOp = CurrRT->GetRightOperand();
				if (o_void == RightOp.type) {
					msg("ERROR: void operand in %s\n", this->GetDisasm());
					return false;
				}
				else {
					RightUse = this->Uses.FindRef(RightOp);
					if (RightUse == this->GetLastUse()) {
						msg("WARNING: Adding missing USE of ");
						PrintOperand(RightOp);
						msg(" in %s\n", this->GetDisasm());
						this->Uses.SetRef(RightOp);
						updated = true;
						break;
					}
					else {
						RightType = RightUse->GetType();
					}
				}
			}
			// If left operand is NUMERIC, operator is NUMERIC.
			LeftNumeric = IsEqType(NUMERIC, LeftType);
			RightNumeric = IsEqType(NUMERIC, RightType);
			LeftPointer = IsDataPtr(LeftType);
			RightPointer = IsDataPtr(RightType);
			if (LeftNumeric) {
				// Subtracting anything from a NUMERIC leaves it NUMERIC.
				if (UNINIT == OperType) {
					CurrRT->SetOperatorType(NUMERIC, this);
					updated = true;
				}
				else if (NUMERIC != OperType) {
					msg("ERROR: SMP_SUBTRACT from NUMERIC should be NUMERIC operator.");
					msg(" Operator type is %d in: %s\n", OperType, this->GetDisasm());
				}
				if (!RightNumeric) {
					// Right operand is being used as a NUMERIC, so propagate NUMERIC to it.
					if (CurrRT->HasRightSubTree()) {
						CurrRT->GetRightTree()->SetOperatorType(NUMERIC, this);
					}
					else {
						RightUse = this->SetUseType(RightOp, NUMERIC);
					}
					updated = true;
				}
			} // end if LeftNumeric
			else if (LeftPointer) {
				if (UNINIT == OperType) {
					// If we subtract another pointer type, we produce PTROFFSET.
					if (RightPointer) {
						CurrRT->SetOperatorType(PTROFFSET, this);
						updated = true;
					}
					else if (RightType == PTROFFSET) {
						// We assume B - (B - A) == A    **!!**
						CurrRT->SetOperatorType(POINTER, this);
						msg("WARNING: PTR - PTROFFSET produces PTR in %s\n", this->GetDisasm());
						updated = true;
					}
					else if (RightNumeric) {
						// pointer minus NUMERIC keeps same pointer type
						CurrRT->SetOperatorType(LeftType, this);
						updated = true;
					}
				}
				else { // we have an operator type for the SMP_SUBTRACT
					if (CurrRT->HasRightSubTree()) {
						// Must need to iterate through the right tree again, as the operator
						//  has been typed.
						if (UNINIT == RightType) {
							if (OperatorPointer) {
								// PTR := PTR - ?? ==> ?? is NUMERIC
								CurrRT->GetRightTree()->SetOperatorType(NUMERIC, this);
								updated = true;
							}
							else if (OperType == PTROFFSET) {
								CurrRT->GetRightTree()->SetOperatorType(LeftType, this);
								updated = true;
							}
						}
						updated |= this->InferOperatorType(CurrRT->GetRightTree());
						break;
					}
					else { // right operand; propagate operator type if needed
						if (UNINIT == RightType) {
							if (OperatorPointer) {
								// PTR := PTR - ?? ==> ?? is NUMERIC
								RightUse = this->SetUseType(RightOp, NUMERIC);
								updated = true;
								assert(RightUse != this->GetLastUse());
							}
							else if (OperType == PTROFFSET) {
								// PTROFFSET := PTR - ?? ==> ?? is PTR
								RightUse = this->SetUseType(RightOp, LeftType);
								updated = true;
							}
							break;
						}
					}
				} // end if OperType is UNINIT ... else ...
			} // end if LeftNumeric ... else if LeftPointer ...
			else if (UNINIT == LeftType) {
				if (UNINIT != OperType) {
					LeftUse = this->SetUseType(LeftOp, OperType);
					assert(LeftUse != this->GetLastUse());
					updated = true;
				}
			}
			break;

		case SMP_ASSIGN:
clc5q's avatar
clc5q committed
			// Extract the current types of right and left operands and SMP_ASSIGN operator.
			OperType = CurrRT->GetOperatorType();
			DefOp = CurrRT->GetLeftOperand();
			CurrDef = this->Defs.FindRef(DefOp);
			assert(CurrDef != this->GetLastDef()); // found it
clc5q's avatar
clc5q committed
			LeftType = CurrDef->GetType();
			if (CurrRT->HasRightSubTree()) {
				RightType = CurrRT->GetRightTree()->GetOperatorType();
			}
			else {
				UseOp = CurrRT->GetRightOperand();
				if (o_void == UseOp.type) {
					msg("ERROR: void operand for SMP_ASSIGN in %s\n", this->GetDisasm());
					return false;
				}
				else {
					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;
clc5q's avatar
clc5q committed
						break;
clc5q's avatar
clc5q committed
						RightType = CurrUse->GetType();
clc5q's avatar
clc5q committed
			}
			// We keep it simple by only trying to propagate one step at a time, from
			//  the right operand or tree up to the SMP_ASSIGN operator, then from
			//  the operator to the left (DEF) operand, or from left up to operator
			//  and down the right, depending on where the existing types are.
			if (DebugFlag) {
				msg("%x LeftType: %d OperatorType: %d RightType: %d\n", this->address, LeftType,
					OperType, RightType);
			}
clc5q's avatar
clc5q committed
			if ((UNINIT == RightType) && (UNINIT == LeftType)) {
				// We will only try to solve the right hand side on this iteration.
				if (CurrRT->HasRightSubTree()) {
					updated |= this->InferOperatorType(CurrRT->GetRightTree());
clc5q's avatar
clc5q committed
				break;
			}
clc5q's avatar
clc5q committed
				// UNINIT SMP_ASSIGN operator, but either LeftType or RightType is not UNINIT.
				if (UNINIT != RightType) {
					// We have to special case conditional moves. Only if both operands
					//  (the source and the prior value of the potential destination,
					//  which was added to the USE set by BuildMoveRTL()) agree in type
					//  can we propagate their common type to the operator and ultimately
					//  to the DEF.
					if ((!this->MDIsConditionalMoveInstr()) || this->Uses.TypesAgreeNoFlags()) {
						CurrRT->SetOperatorType(RightType, this);
					CurrRT->SetOperatorType(LeftType, this);
clc5q's avatar
clc5q committed
				break;
			}
			else if (UNINIT == LeftType) {
				// SMP_ASSIGN operator has type, so propagate it.
				LeftType = OperType;
				CurrDef = this->SetDefType(DefOp, OperType);
clc5q's avatar
clc5q committed
				updated = true;
				// Propagate the new DEF type unless it is an indirect memory access.
				//  Future: Propagate until re-DEF of addressing register terminates
				//  the propagation. **!!**
				if (!MDIsIndirectMemoryOpnd(DefOp, this->BasicBlock->GetFunc()->UsesFramePointer())) {
					// Be conservative and only propagate register DEFs and SAFE stack locs.
					//  We can improve this in the future. **!!**
					if ((o_reg == DefOp.type) 
						|| (FUNC_SAFE == this->BasicBlock->GetFunc()->GetReturnAddressStatus())) {
						if (this->BasicBlock->IsLocalName(DefOp)) {
							(void) this->BasicBlock->PropagateLocalDefType(DefOp, LeftType,
						}
						else { // global name
							this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
							(void) this->BasicBlock->PropagateGlobalDefType(DefOp, LeftType,
								SSANum);
						}
					}
clc5q's avatar
clc5q committed
				}
				break;
			}
			else if (UNINIT == RightType) {
				// SMP_ASSIGN operator has type, so propagate it.
				if (CurrRT->HasRightSubTree()) {
					CurrRT->GetRightTree()->SetOperatorType(OperType, this);
clc5q's avatar
clc5q committed
					updated |= this->InferOperatorType(CurrRT->GetRightTree());
				}
				else {
					// For conditional moves, propagate to the pseudo-USE of the
					//  destination register as well as the source operand.
					if (this->MDIsConditionalMoveInstr()) {
						CurrUse = this->FindUse(DefOp);
						assert(CurrUse != this->GetLastUse());
						if (UNINIT == CurrUse->GetType())
							CurrUse = this->SetUseType(DefOp, OperType);
						else if (OperType != CurrUse->GetType()) {
							msg("WARNING: Avoiding lattice oscillation from type %d to %d at %x for: ",
								CurrUse->GetType(), OperType, this->address);
							PrintOperand(CurrUse->GetOp());
							msg("\n");
						}
					}
					CurrUse = this->SetUseType(UseOp, OperType);
					updated = true;
			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;
	int IndexReg;
	ea_t displacement;
	ushort ScaleFactor;

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

	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))) {
		// 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;
	ea_t offset;
	int BaseReg;
	int IndexReg;
	ushort ScaleFactor;

#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) || (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
					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) {
			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
					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 %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
	 		}
			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) {
				// 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()
/**
 * Emits Safe Returns
 * Mark the type of  the annotation as "-4". Currently  the SDT is ignoring this
 * annotation. 
 */ 
void SMPInstr::EmitSafeReturn(FILE *AnnotFile)
{
	qfprintf(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, 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 UnusedMetadata = this->AllDefMetadataUnused();
	bool MemDest = this->HasDestMemoryOperand();
	bool MemSrc = this->HasSourceMemoryOperand();
	bool SecondSrcOperandNum = this->IsSecondSrcOperandNumeric(InstrFlags);
	ea_t funcStartAddr=this->GetBlock()->GetFunc()->GetStartAddr();

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

	// Emit appropriate optimization annotations.
	bool SDTInstrumentation = false;

	// 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.
	if (UnusedMetadata && (1 != TypeGroup) && (14 != TypeGroup)) {
		qfprintf(AnnotFile, "%10x %6d INSTR LOCAL MetadataUnused %s \n",
						addr, -1, disasm);
		++AnnotationCount[this->OptType];
		return;
	}

	switch (TypeGroup) {  
		case 0:  // SDT will have to handle these
		case 11: // PUSH/POP  **!!** What if we push/pop NUMERIC type? Optimize?
			// 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
		case 14:
			if (MemDest) {
				msg("ERROR: MemDest in Type Category 1 or 14: %x %s\n", addr, disasm);
				SDTInstrumentation = true;
				break;
			}
			qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
					addr, -1, OptExplanation[this->OptType], disasm);
			++AnnotationCount[this->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[this->OptType];
		case 5: // ADD, etc.: If numeric 2nd src operand, no SDT work.
				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[this->OptType], disasm);
				++AnnotationCount[this->OptType];
			else if (IsEqType(NUMERIC, this->AddSubSourceType)
				&& !this->MDIsFrameAllocInstr()
				&& (this->SMPcmd.itype != NN_adc)
				&& (this->SMPcmd.itype != NN_sbb)) {
				qfprintf(AnnotFile, "%10x %6d INSTR LOCAL 2ndSrcNumeric %s \n",
						addr, -1, disasm);
				++AnnotationCount[this->OptType];
			else if (NumericDEFs) {
				qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s NumericDEFs %s \n",
						addr, -2, this->DestString(this->OptType), disasm);
				++AnnotationCount[this->OptType];
			}
			else {
				SDTInstrumentation = true;
			}
			break;

		case 6: // Only OS code should include these; problem for SDT
				SDTInstrumentation = true;
				break;  // treat as category 0
			}
			qfprintf(AnnotFile, "%10x %6d INSTR LOCAL AlwaysPTR %s \n",
					addr, -OptType, disasm);
			++AnnotationCount[this->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[this->OptType], disasm);
			++AnnotationCount[this->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(this->OptType), disasm);
					++AnnotationCount[this->OptType];
				}
#endif
			}
			else {
				qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
						addr, -1, OptExplanation[this->OptType], disasm);
				++AnnotationCount[this->OptType];
		case 10: // AND, OR, etc.: If all DEFs have been inferred to be
				 //  NUMERIC, then output optimizing annotation.
			SDTInstrumentation = true;
			if (MemDest) { // **!!** optimize with numeric annotation in future
				break;  // treat as category 0
			}
			else if (NumericDEFs) { // NUMERIC result because of NUMERIC sources
				qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s NumericDEFs %s \n",
						addr, -2, this->DestString(this->OptType), disasm);
				++AnnotationCount[this->OptType];
			}
			break;

		case 12: // Exchange, exchange and add, conditional exchange: All NUMERIC
				 //  sources ==> NUMERIC DEFs, so nothing for mmStrata to do.
			if (MemDest) { // **!!** optimize with numeric annotation in future
				SDTInstrumentation = true;
				break;  // treat as category 0
			}
			else if (NumericDEFs) { // NUMERIC result because of NUMERIC sources
				qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n", addr,
						-1, OptExplanation[TypeGroup], disasm);
				++AnnotationCount[this->OptType];
			}
			else 
				SDTInstrumentation = true;
			break;

		case 15: // Floating point, NUMERIC, possible memory destination.
				 //  If not memory destination, fpreg dest, so nothing for mmStrata to do.
			if (MemDest) { // **!!** optimize with numeric annotation in future
				SDTInstrumentation = true;
				break;  // treat as category 0
			}
			else { // NUMERIC floating register result; these regs are always NUMERIC
				qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n", addr,
						-1, OptExplanation[TypeGroup], disasm);
				++AnnotationCount[this->OptType];
			}
			break;

		default: // 2,3,7: Optimization possibilities depend on operands 
			SDTInstrumentation = true;
			if (MemDest) {
				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(this->OptType), 
						OptExplanation[this->OptType], disasm);
				++AnnotationCount[this->OptType];
			}
			else if (NumericDEFs) { // NUMERIC move instruction
				qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s NumericDEFs %s \n",
						addr, -2, this->DestString(this->OptType), disasm);
				++AnnotationCount[this->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()

clc5q's avatar
clc5q committed
// Go through the PUSH RTL and get the operand pushed.
op_t SMPInstr::GetPushedOpnd(void) {
	op_t VoidOp;
	VoidOp.type = o_void;

	if (NN_push == this->SMPcmd.itype) {
		for (size_t OpNum = 0; OpNum < UA_MAXOP; ++OpNum) {
			op_t TempOp = this->SMPcmd.Operands[OpNum];
			if (this->features & UseMacros[OpNum]) { // USE
				return TempOp;
			}
		}
		msg("ERROR: Could not find PUSH operand at %x %s\n", this->address,
			this->GetDisasm());
		return VoidOp;
	}
	else {
		return VoidOp;
	}
} // end of SMPInstr::GetPushedOpnd()

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

	// Handle special cases first
	if (SMP_UNARY_FLOATING_ARITHMETIC == UnaryOp) {
		// Use of the floating register stack top is implicit
		DestFound = true;
		TempRT = new SMPRegTransfer;
		TempRT->SetLeftOperand(FPRegOp);
		TempRT->SetOperator(SMP_ASSIGN);
		SMPRegTransfer *RightRT = new SMPRegTransfer;
		RightRT->SetLeftOperand(FPRegOp);
		RightRT->SetOperator(UnaryOp);
		RightRT->SetRightOperand(VoidOp);
		TempRT->SetRightTree(RightRT);
		this->RTL.push_back(TempRT);
	}
	else if ((NN_clc == this->SMPcmd.itype) || (NN_cld == this->SMPcmd.itype)
		|| (NN_cmc == this->SMPcmd.itype) || (NN_stc == this->SMPcmd.itype)
		|| (NN_std == this->SMPcmd.itype)) {
		// Flags register is implicit destination.
		DestFound = true;
		TempRT = new SMPRegTransfer;
		TempRT->SetLeftOperand(FlagsOp);
		TempRT->SetOperator(SMP_ASSIGN);
		SMPRegTransfer *RightRT = new SMPRegTransfer;
		if (NN_cmc == this->SMPcmd.itype) { // complement carry flag USEs old carry flag
			RightRT->SetLeftOperand(FlagsOp);
			RightRT->SetOperator(SMP_BITWISE_NOT);
		}
		else {
			RightRT->SetLeftOperand(VoidOp);
			RightRT->SetOperator(UnaryOp);
		}
		RightRT->SetRightOperand(VoidOp);
		TempRT->SetRightTree(RightRT);
		this->RTL.push_back(TempRT);
	}

	for (OpNum = 0; !DestFound && (OpNum < UA_MAXOP); ++OpNum) {
		op_t TempOp = this->SMPcmd.Operands[OpNum];
		if (this->features & DefMacros[OpNum]) { // DEF
			if (MDKnownOperandType(TempOp)) {
				DestFound = true;
				TempRT = new SMPRegTransfer;
				TempRT->SetLeftOperand(TempOp);
				TempRT->SetOperator(SMP_ASSIGN);
				SMPRegTransfer *RightRT = new SMPRegTransfer;
				RightRT->SetLeftOperand(TempOp);
				RightRT->SetOperator(UnaryOp);
				RightRT->SetRightOperand(VoidOp);
				TempRT->SetRightTree(RightRT);
				this->RTL.push_back(TempRT);
			}
		}
	} // end for (OpNum = 0; ...)

#if SMP_DEBUG_BUILD_RTL
	if (!DestFound) {
		msg("ERROR: Could not find unary operand at %x for %s\n", this->GetAddr(), this->GetDisasm());
	}
#endif
	return DestFound;
} // end of SMPInstr::BuildUnaryRTL()

// Build the RTL for an instruction with a binary arithmetic opcode
bool SMPInstr::BuildBinaryRTL(SMPoperator BinaryOp) {
	size_t OpNum;
	bool DestFound = false;
	bool SourceFound = false;
	bool MemSrc = this->HasSourceMemoryOperand();
	bool MemDest = this->HasDestMemoryOperand();
	SMPRegTransfer *TempRT = NULL;
	SMPRegTransfer *RightRT = new SMPRegTransfer;

	op_t VoidOp;
	VoidOp.type = o_void;

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

	// Handle special cases first
	if (SMP_BINARY_FLOATING_ARITHMETIC == BinaryOp) {
		// Use of the floating register stack top is implicit
		DestFound = true;
		TempRT = new SMPRegTransfer;
		TempRT->SetLeftOperand(FPRegOp);
		TempRT->SetOperator(SMP_ASSIGN);
		RightRT->SetLeftOperand(FPRegOp);
		RightRT->SetOperator(BinaryOp);
		RightRT->SetRightOperand(VoidOp);
		TempRT->SetRightTree(RightRT);
	}

	for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < UA_MAXOP); ++OpNum) {
		op_t TempOp = this->SMPcmd.Operands[OpNum];
		if (this->features & DefMacros[OpNum]) { // DEF
			if (!DestFound && MDKnownOperandType(TempOp)) {
				// See comments just below for floating point sources. FP stores
				//  are analogous to FP loads.
				if (!MemDest || ((TempOp.type >= o_mem) && (TempOp.type <= o_displ))) {
					DestFound = true;
					TempRT = new SMPRegTransfer;
					TempRT->SetLeftOperand(TempOp);
					TempRT->SetOperator(SMP_ASSIGN);
clc5q's avatar
clc5q committed
					if (this->RegClearIdiom) {
						op_t ImmOp;
						ImmOp.type = o_imm;
						ImmOp.value = 0;
						TempRT->SetRightOperand(ImmOp);
						SourceFound = true; // cause loop exit
					}
					else {
						RightRT->SetLeftOperand(TempOp);
						RightRT->SetOperator(BinaryOp);
						TempRT->SetRightTree(RightRT);
					}
				}
				else {
					;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
					msg("WARNING: Skipping DEF operand: ");
					PrintOperand(TempOp);
					msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm());
#endif
				}
			}
			else if (DestFound && (SMP_BINARY_FLOATING_ARITHMETIC != BinaryOp)) {
				;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				msg("ERROR: Found two DEF operands: ");
				PrintOperand(TempOp);
				msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm());
#endif
			if (!SourceFound && MDKnownOperandType(TempOp)) {
				// If this is a floating point instruction with the fpregs listed as
				//  a USE and a memory operand also listed as a USE, then we want to
				//  ignore the irrelevant USE of the fpreg stack.
				// Note that MemDest AND MemSrc means something like add mem,reg is being
				//  processed, where the memory operand is both DEF and USE.
				if (!MemSrc || MemDest || ((TempOp.type >= o_mem) && (TempOp.type <= o_displ))) {
					SourceFound = true;
					RightRT->SetRightOperand(TempOp);
				}
			if (!(this->features & UseMacros[OpNum])) {
				;
#if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE
				msg("WARNING: Operand neither DEF nor USE: ");
				PrintOperand(TempOp);
				msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm());
#endif
			}
		} // end if DEF ... else ...
	} // end for (OpNum = 0; ...)

	if (!DestFound || !SourceFound) {
		assert(NULL != RightRT);
		if (DestFound && (NULL != TempRT))
#if SMP_DEBUG_BUILD_RTL
		if (!DestFound) {
			msg("ERROR: Could not find binary DEF operand at %x for %s\n", this->GetAddr(),
				this->GetDisasm());
		}
		else {
			msg("ERROR: Could not find binary operand at %x for %s\n", this->GetAddr(),
				this->GetDisasm());
			this->PrintOperands();
		}
#endif
	}
	else {
		this->RTL.push_back(TempRT);
	}
	return (DestFound && SourceFound);
} // end of SMPInstr::BuildBinaryRTL()

// Build the RTL for a load-effective-address instruction.
bool SMPInstr::BuildLeaRTL(void) {
	size_t OpNum;
	bool DestFound = false;
	bool SourceFound = false;
	bool MemSrc = this->HasSourceMemoryOperand();
	op_t DefOp;
	SMPRegTransfer *AssignRT = NULL;
	int BaseReg;
	int IndexReg;
	ushort ScaleFactor;
	ea_t offset;
	bool ScaledIndexReg;

	for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < UA_MAXOP); ++OpNum) {
		op_t TempOp = this->SMPcmd.Operands[OpNum];
		if (this->features & DefMacros[OpNum]) { // DEF
			DefOp = TempOp;
			DestFound = true;
			assert(o_reg == DefOp.type);
		}
		else { // USE
			if (!SourceFound && MDKnownOperandType(TempOp)) {
				if ((TempOp.type >= o_mem) && (TempOp.type <= o_displ)) {
					SourceFound = true;
					MDExtractAddressFields(TempOp, BaseReg, IndexReg, ScaleFactor, offset);