Skip to content
Snippets Groups Projects
SMPFunction.cpp 311 KiB
Newer Older
			if (CurrPhi != CurrBlock->GetLastPhi()) {
				// Found Phi function for current global name.
				if (IsEqType(CurrPhi->GetDefType(), UNINIT)) {
					// Phi DEF is UNINIT; add Phi to the map.
					pair<int, set<SMPPhiFunction, LessPhi>::iterator> TempPair(CurrPhi->GetDefSSANum(), CurrPhi);
					bool Inserted = false;
					map<int, set<SMPPhiFunction, LessPhi>::iterator>::iterator WhereIns;
					pair<map<int, set<SMPPhiFunction, LessPhi>::iterator>::iterator, bool> Result(WhereIns, Inserted);
					Result = UninitDEFPhis.insert(TempPair);
					assert(Result.second == true);
				}
			}
		} // end for all blocks

		// If any Phi DEF had UNINIT as its type, set up a vector of
		//  iterators to instructions that have UNINIT as the DEF type
		//  for the current global name.
		if (UninitDEFPhis.empty())
			continue;
		list<SMPInstr *>::iterator InstIter;
		for (InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) {
			SMPInstr *CurrInst = (*InstIter);
			set<DefOrUse, LessDefUse>::iterator CurrDef = CurrInst->FindDef(GlobalOp);
			if (CurrDef != CurrInst->GetLastDef()) {
				// Found DEF of current global name.
				if (IsEqType(UNINIT, CurrDef->GetType())) {
					UninitDEFInsts.push_back(CurrInst);
				}
			}
		} // end for all instructions

		// Put all UNINIT Phi DEFs that have at least one USE
		//  that is not UNINIT onto the PhiWorkList.
		map<int, set<SMPPhiFunction, LessPhi>::iterator>::iterator CurrUnPhi;
		for (CurrUnPhi = UninitDEFPhis.begin(); CurrUnPhi != UninitDEFPhis.end(); ++CurrUnPhi) {
			pair<int, set<SMPPhiFunction, LessPhi>::iterator> PhiDefPair(*CurrUnPhi);
			if (PhiDefPair.second->HasTypedUses()) {
				PhiWorkList.push_back(CurrUnPhi);
			}
		}

		// Iterate until both work lists are empty:
		while (!(PhiWorkList.empty() && InstWorkList.empty())) {
			// Process Phi items first.
			while (!PhiWorkList.empty()) {
				// If applying the meet operator over the Phi USE types
				//  would produce a new DEF type, change the DEF type and
				//  propagate it, adding Phi functions and instructions that
				//  received the propagated type to their respective work lists.
				map<int, set<SMPPhiFunction, LessPhi>::iterator>::iterator MapIter;
				MapIter = PhiWorkList.front();
				PhiWorkList.pop_front();  // remove from work list
				pair<int, set<SMPPhiFunction, LessPhi>::iterator> PhiDefPair;
				PhiDefPair.first = MapIter->first;
				PhiDefPair.second = MapIter->second;
				set<SMPPhiFunction, LessPhi>::iterator CurrPhi = PhiDefPair.second;
				SMPOperandType MeetType = CurrPhi->ConditionalMeetType();
				// Here we use a straight equality test, not our macros,
				//  because we consider it a change if the MeetType is
				//  profiler derived and the DEFType is not.
				if (MeetType == CurrPhi->GetDefType())
					continue;
				// At this point, we need to set the DEFType to the MeetType
				//  and propagate the change. We have a map of all the
				//  critical Phi functions for this global name, as well
				//  as a vector of the relevant instructions for this name.
				CurrPhi->SetDefType(MeetType);
				changed = true;
				int DefSSANum = CurrPhi->GetDefSSANum();
				map<int, set<SMPPhiFunction, LessPhi>::iterator>::iterator PhiIter;
				vector<list<SMPInstr>::iterator>::iterator InstIter;
				// Propagate to Phi functions first.
				for (PhiIter = UninitDEFPhis.begin(); PhiIter != UninitDEFPhis.end(); ++PhiIter) {
					if (DefSSANum == PhiIter->first)
						continue;  // Skip the Phi that we just changed
					for (size_t index = 0; index < PhiIter->second->GetPhiListSize(); ++index) {
						if (DefSSANum == PhiIter->second->GetUseSSANum(index)) {
							// Matched SSA # to USE. Propagate new type.
							PhiIter->second->SetRefType(index, MeetType);
							// Add this phi function to the work list.
							PhiWorkList.push_back(PhiIter);
						}
					}
				}
#define SMP_COND_TYPE_PROP_TO_INSTS 0
#if SMP_COND_TYPE_PROP_TO_INSTS
				// Propagate to instructions with uninit DEFs of global name.
				//  The idea is that the instructions that hold up type propagation
				//  are the ones that USE and then DEF the same global name.
				//  For example, "increment EAX" has to know the type of
				//  the USE of EAX in order to set the type of the DEF.
#endif
			} // end while the PhiWorkList is not empty
#if SMP_COND_TYPE_PROP_TO_INSTS
			// The PhiWorkList is empty at this point, so process
			//  instructions on the InstWorkList.
#endif
		} // end while both work lists are not empty

	} // end for all global names
	return changed;
} // end of SMPFunction::ConditionalTypePropagation()
#endif  // end if SMP_SIMPLE_CONDITIONAL_TYPE_PROPAGATION else ...

// Propagate signedness FG info from DEFs to USEs whenever there is no USE sign info.
bool SMPFunction::PropagateSignedness(void) {
	bool changed = false;
#if STARS_AGGRESSIVE_SIGNEDNESS_PROPAGATION
	map<int, struct FineGrainedInfo>::iterator UseFGIter, DefFGIter;
	list<SMPBasicBlock *>::iterator BlockIter;
	for (UseFGIter = this->GlobalUseFGInfoBySSA.begin(); UseFGIter != this->GlobalUseFGInfoBySSA.end(); ++UseFGIter) {
		struct FineGrainedInfo UseFG = UseFGIter->second;
		if (0 == (UseFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS)) {
			// No signedness info. Propagate any signedness info from DEF.
			int UseHashValue = UseFGIter->first;
			unsigned short DefSignMask = this->GetDefSignMiscInfo(UseHashValue);
			DefSignMask &= FG_MASK_SIGNEDNESS_BITS;
			if (0 != DefSignMask) {
				// DEF has signedness info.
				UseFGIter->second.SignMiscInfo |= DefSignMask;
				changed = true;
			}
		}
	}
	// See if we have DEF signedness info for DEFs with no corresponding USE map entries.
	for (DefFGIter = this->GlobalDefFGInfoBySSA.begin(); DefFGIter != this->GlobalDefFGInfoBySSA.end(); ++DefFGIter) {
		struct FineGrainedInfo DefFG = DefFGIter->second;
		unsigned short DefSignMask = (DefFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
		if (0 != DefSignMask) {
			// Has signedness info. See if USE has no entry.
			int DefHashValue = DefFGIter->first;
			UseFGIter = this->GlobalUseFGInfoBySSA.find(DefHashValue);
			if (UseFGIter == this->GlobalUseFGInfoBySSA.end()) {
				this->UpdateUseSignMiscInfo(DefHashValue, DefSignMask);
				changed = true;
			}
		}
	}
	// Do the same processsing for block-local registers.
	for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
		bool NewChange = (*BlockIter)->PropagateDEFSignedness();
		changed = changed || NewChange;
	}
#endif
	return changed;
} // end of SMPFunction::PropagateSignedness()

// Detect and mark special cases before emitting numeric error annotations.
void SMPFunction::MarkSpecialNumericErrorCases(void) {
	list<SMPBasicBlock *>::iterator BlockIter;
	list<SMPInstr *>::reverse_iterator InstIter;
	SMPBasicBlock *CurrBlock;
	SMPInstr *CurrInst;
	bool DebugFlag = (0 == strcmp("sub_8063BE0", this->GetFuncName()));
	set<int> NonEscapingRegisterHashes; // memoization optimization: set of register/SSA# hashes that do not reach end of block

#if STARS_BUILD_LOOP_BITSET
	// Now that we know how many loops we have, we can allocate the loops data structure.
	this->FuncLoopsByBlock.resize(this->BlockCount);
	for (size_t BlockIndex = 0; BlockIndex < this->BlockCount; ++BlockIndex) {
		this->FuncLoopsByBlock.at(BlockIndex).AllocateBits(this->LoopCount);
	}

	if (this->LoopCount > 0) {
		this->DetectLoops();
	}
	// Special-case preparatory analyses.
	for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
		CurrBlock = (*BlockIter);
		CurrBlock->AnalyzePrepForNumericAnnotations();
	}

	if (this->LoopCount == 0) {
		return;

	// Loop through blocks and detect tight loops of hashing arithmetic.
	for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
		CurrBlock = (*BlockIter);
		if (CurrBlock->IsLoopTailBlock() && CurrBlock->IsLoopHeaderBlock()) {
			// We have a one-block loop to itself. This is the simple case we want
			//  to start with, as hash functions we have observed are tight loops of arithmetic computations.
			//  The next question is whether we can find the kind of shift/rotate that is common to hashing, plus
			//  at least one addition.
			bool ShiftFound = false;
			bool AddFound = false;
clc5q's avatar
clc5q committed
			op_t DefOp = InitOp, AddDefOp = InitOp;
			set<DefOrUse, LessDefUse>::iterator DefIter;
			NonEscapingRegisterHashes.clear();

			for (InstIter = CurrBlock->GetRevInstBegin(); InstIter != CurrBlock->GetRevInstEnd(); ++InstIter) {
				CurrInst = (*InstIter);
				if ((!ShiftFound) && CurrInst->MDIsHashingArithmetic()) {
					// If the operand being shifted is never used in any assignment or arithmetic
					//  except as an address register computation within a memory operand, then the
					//  shifted value does not reach the top of the loop and get shifts accumulated.
					//  In that case, we are not dealing with a shift-and-add type of hash function.
					//  So, do not claim success unless the later addition DEF reaches the end
					DefIter = CurrInst->GetFirstNonFlagsDef();
					ea_t DefAddr = CurrInst->GetAddr();
					DefOp = DefIter->GetOp();
					ea_t AdditionAddr = BADADDR;
clc5q's avatar
clc5q committed
					ShiftFound = CurrBlock->IsDefInvolvedInAddition(DefAddr, DefOp, AdditionAddr);
					if (ShiftFound) {
						SMPInstr *AdditionInst = this->GetInstFromAddr(AdditionAddr);
clc5q's avatar
clc5q committed
						DefIter = AdditionInst->GetFirstNonFlagsDef();
						AddDefOp = DefIter->GetOp();
						AddFound = CurrBlock->DoesDefReachBlockEnd(AdditionAddr, AddDefOp, DefIter->GetSSANum(), NonEscapingRegisterHashes);
						if (AddFound) {
							break;
						}
						else {
							// Reset ShiftFound and look for a different shift.
							ShiftFound = false;
						}
					}
				}
			}
			if (ShiftFound && AddFound) {
				// We found a tight hashing loop. Mark all the overflowing and underflowing opcodes as benign.
				//  NOTE: We could do loop-variant analysis to ensure that the shifted and added values are actually
				//  changing within the loop, but if they are not, they are probably not exploitable overflows anyway,
				//  and the loop-invariant overflow would happen on every loop iteration based on initial values, which
				//  is a pattern we have never seen for this kind of code.
				list<SMPInstr *>::iterator ForwardInstIter;
				for (ForwardInstIter = CurrBlock->GetFirstInstr(); ForwardInstIter != CurrBlock->GetLastInstr(); ++ForwardInstIter) {
					CurrInst = (*ForwardInstIter);
					if (CurrInst->MDIsOverflowingOpcode() || CurrInst->MDIsUnderflowingOpcode() || CurrInst->MDIsLoadEffectiveAddressInstr()) {
						CurrInst->SetHashOperation();
					}
				}
			}
		} // end if loop header and loop tail
	} // end for all blocks

	return;
} // end of SMPFunction::MarkSpecialNumericErrorCases()

// Emit all annotations for the function, including all per-instruction
//  annotations.
void SMPFunction::EmitAnnotations(FILE *AnnotFile, FILE *InfoAnnotFile) {
	// Emit annotation for the function as a whole.
	list<SMPBasicBlock *>::iterator BlockIter;
	SMPBasicBlock *CurrBlock;
	bool FuncHasProblems = ((!this->AnalyzedSP) || (!this->HasGoodRTLs()) || (this->HasUnresolvedIndirectCalls())
		|| (this->HasUnresolvedIndirectJumps()) || (this->HasSharedChunks()));

	if (this->StaticFunc) {
		SMP_fprintf(AnnotFile,	"%10x %6zu FUNC LOCAL  %s ", this->FuncInfo.startEA,
			this->Size, this->GetFuncName());
		SMP_fprintf(AnnotFile,	"%10x %6zu FUNC GLOBAL %s ", this->FuncInfo.startEA,
			this->Size, this->GetFuncName());
	switch (this->GetReturnAddressStatus())
	}
	if (this->FuncInfo.does_return()) {
	if (this->IsLeaf())
	// store the return address
	SMP_fprintf(AnnotFile,"%10x ", this->FuncInfo.endEA - 1);

	if (this->IsLibFunc())
		SMP_fprintf(AnnotFile, "LIBRARY ");
	SMP_fprintf(AnnotFile, "\n");
jdh8d's avatar
jdh8d committed
	// Emit annotations about how to restore register values
	SMP_fprintf(AnnotFile, "%10x %6d FUNC FRAMERESTORE ", this->FuncInfo.startEA, 0);
jdh8d's avatar
jdh8d committed
	{
		SMP_fprintf(AnnotFile, "%d %d %d ", i, this->SavedRegLoc[i], this->ReturnRegTypes[i]);
jdh8d's avatar
jdh8d committed
	}
jdh8d's avatar
jdh8d committed

	SMP_fprintf(AnnotFile, "%10x %6d FUNC MMSAFENESS ", this->FuncInfo.startEA, 0);
clc5q's avatar
clc5q committed
	if (!IsSpecSafe())
clc5q's avatar
clc5q committed
	else if (!IsSafe())
clc5q's avatar
clc5q committed
	else {
		assert(IsSafe());
	// If function has problems that limited our analyses, emit an information annotation so that
	//  other tools can be aware of which analyses will be sound.
	if (FuncHasProblems) {
		SMP_fprintf(InfoAnnotFile,	"%10x %6zu FUNC PROBLEM %s ", this->FuncInfo.startEA,
			this->Size, this->GetFuncName());
		if (!this->AnalyzedSP) {
			SMP_fprintf(InfoAnnotFile, "STACKANALYSIS ");
		}
		if (this->HasSharedChunks()) {
		}
		if (this->HasUnresolvedIndirectJumps()) {
			SMP_fprintf(InfoAnnotFile, "JUMPUNRESOLVED ");
		}
		if (this->HasUnresolvedIndirectCalls()) {
			SMP_fprintf(InfoAnnotFile, "CALLUNRESOLVED ");
		}
		if (!this->HasGoodRTLs()) {
	// Find and mark special cases that will affect the integer error annotations.
	this->MarkSpecialNumericErrorCases();

	// Loop through all instructions in the function.
	// Output optimization annotations for those
	//  instructions that do not require full computation
	//  of their memory metadata by the Memory Monitor SDT.
	list<size_t> LoopList; // for current block
	int CurrBlockNum = SMP_BLOCKNUM_UNINIT;
	list<SMPInstr *>::iterator InstIter = Instrs.begin();
	++InstIter;  // skip marker instruction
	bool AllocSeen = false; // Reached LocalVarsAllocInstr yet?
	bool DeallocTrigger = false;
	for ( ; InstIter != Instrs.end(); ++InstIter) {
		SMPInstr *CurrInst = (*InstIter);
		ea_t addr = CurrInst->GetAddr();
		CurrBlock = CurrInst->GetBlock();
		int BlockNum = CurrBlock->GetNumber();
		if (BlockNum != CurrBlockNum) {
			CurrBlockNum = BlockNum;
			if (0 < this->LoopCount) {
				LoopList.clear();
				this->BuildLoopList(BlockNum, LoopList);
			}
		}
		SMP_fprintf(AnnotFile, "%10x %6d INSTR BELONGTO %x \n", addr, 0, GetStartAddr());
		if (this->LocalVarsAllocInstr == addr) {
			AllocSeen = true;
			if (this->NeedsStackReferent)
				this->EmitStackFrameAnnotations(AnnotFile, CurrInst);
				int OptType = CurrInst->GetOptType(); 
				if (5 == OptType) { // ADD or SUB
					// Prevent mmStrata from extending the caller's stack frame
					//  to include the new allocation.
					SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL SafeFrameAlloc %s \n",
						addr, -1, CurrInst->GetDisasm());
				}
				else if (CurrInst->MDIsPushInstr()) {
					SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL NoWarn %s \n",
				// mmStrata ignores the DATAREF annotations anyway, so even though
				//  they are not needed, emit them for use by Strata and other tools
				//  in other projects besides MEDS.
				this->EmitStackFrameAnnotations(AnnotFile, CurrInst);
		}
		// If this is the instruction which deallocated space
		//  for local variables, we set a flag to remind us to 
		//  emit an annotation on the next instruction.
		// mmStrata wants the instruction AFTER the
		//  deallocating instruction, so that it processes
		//  the deallocation after it happens. It inserts
		//  instrumentation before an instruction, not
		//  after, so it will insert the deallocating
		//  instrumentation before the first POP of callee-saved regs,
		//  if there are any, or before the return, otherwise.
		if (addr == this->LocalVarsDeallocInstr) {
			DeallocTrigger = true;
		}
		else if (DeallocTrigger) { // Time for annotation
			SMP_fprintf(AnnotFile,	"%10x %6d DEALLOC STACK esp - %d %s\n", addr,
				this->LocalVarsSize, this->LocalVarsSize, CurrInst->GetDisasm());
		if (this->StackPtrAnalysisSucceeded() && this->HasGoodRTLs() && !this->HasUnresolvedIndirectJumps() && !this->HasSharedChunks()) {
			CurrInst->EmitTypeAnnotations(this->UseFP, AllocSeen, this->NeedsStackReferent, AnnotFile, InfoAnnotFile);
			CurrInst->EmitIntegerErrorAnnotations(InfoAnnotFile, LoopList);
			CurrInst->EmitAnnotations(this->UseFP, AllocSeen, this->NeedsStackReferent, AnnotFile, InfoAnnotFile);

		if (CurrInst->MDIsReturnInstr() && this->GetReturnAddressStatus() == FUNC_SAFE)
			CurrInst->EmitSafeReturn(AnnotFile);
	}  // end for all instructions

	// Loop through all basic blocks and emit profiling request annotations
	//  for those blocks that have unsafe memory writes in them.
	this->SafeBlocks = 0;
	this->UnsafeBlocks = 0;
	for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
		CurrBlock = (*BlockIter);
		if (CurrBlock->MaybeAliasedWrite()) {
			++(this->UnsafeBlocks);
			list<SMPInstr *>::iterator CurrInst;
			CurrInst = CurrBlock->GetFirstInstr();
			ea_t addr = (*CurrInst)->GetAddr();
			SMP_fprintf(AnnotFile,	"%10x %6d BLOCK PROFILECOUNT %s\n", addr,
				(*CurrInst)->GetCmd().size, (*CurrInst)->GetDisasm());
	LoopList.clear();
	this->FuncLoopsByBlock.clear();
#if SMP_SHRINK_TO_FIT
	vector<STARSBitSet>(this->FuncLoopsByBlock).swap(this->FuncLoopsByBlock);
#endif

	return;
} // end of SMPFunction::EmitAnnotations()

// Debug output dump.
void SMPFunction::Dump(void) {
	list<SMPBasicBlock *>::iterator CurrBlock;
	SMP_msg("Debug dump for function: %s\n", this->GetFuncName());
	SMP_msg("UseFP: %d  LocalVarsAllocInstr: %x\n", this->UseFP,
		this->LocalVarsAllocInstr);
	for (size_t index = 0; index < this->IDom.size(); ++index) {
		SMP_msg("IDOM for %zu: %d\n", index, this->IDom.at(index));
	for (size_t index = 0; index < this->DomTree.size(); ++index) {
		list<int>::iterator DomIter;
		for (DomIter = this->DomTree.at(index).second.begin();
			DomIter != this->DomTree.at(index).second.end();
			++DomIter) {
	set<op_t, LessOp>::iterator NameIter;
	for (NameIter = this->GlobalNames.begin(); NameIter != this->GlobalNames.end(); ++NameIter) {
		SMP_msg("index: %d ", ExtractGlobalIndex(*NameIter));
		PrintListOperand(*NameIter);
	SMP_msg("Blocks each name is defined in: \n");
	for (size_t index = 0; index < this->BlocksDefinedIn.size(); ++index) {
		SMP_msg("Name index: %zu Blocks: ", index);
		list<int>::iterator BlockIter;
		for (BlockIter = this->BlocksDefinedIn.at(index).begin();
			BlockIter != this->BlocksDefinedIn.at(index).end();
			++BlockIter) {
	}
	for (CurrBlock = this->Blocks.begin(); CurrBlock != this->Blocks.end(); ++CurrBlock) {
		// Dump out the function number and data flow sets before the instructions.
		(*CurrBlock)->Dump();
	SMP_msg("End of debug dump for function: %s\n", this->GetFuncName());
	return;
} // end of SMPFunction::Dump()


// Analyzes the function to see if the return address can be marked as safe 
void SMPFunction::MarkFunctionSafe() {
clc5q's avatar
clc5q committed
#if SMP_DEBUG_FUNC
	SMP_msg(" Analyzing function %s and isLeaf = %d \n ", this->GetFuncName(), this->IsLeaf());
	bool HasStackPointerCopy = false;
	bool HasStackPointerPush = false;
	bool HasIndirectGlobalWrite = false;
	bool WritesAboveLocalFrame = false;		// Direct writes above local frame
	bool WritesAboveLocalFrameIndirect = false;	// Indirect writes above local frame
	bool HasIndexedStackWrite = false;
	bool HasIndirectWrite = false;
	bool IsIndirectCallTarget = false; // could be called indirectly
	bool IsTailCallTarget = false; // could be called by jump instruction used as tail call
	bool HasNoCallers = this->AllCallSources.empty();

#if SMP_USE_SWITCH_TABLE_INFO
	if (this->UnresolvedIndirectJumps) {
#else
	if (this->IndirectJumps) {
clc5q's avatar
clc5q committed
#if SMP_DEBUG_FUNC
		SMP_msg("Function %s marked as unsafe due to indirect jumps\n", this->GetFuncName());

#if SMP_DECLARE_INDIRECT_TARGETS_UNSAFE
	ea_t FirstAddr = this->FirstEA;
	SMP_xref_t xrefs;
	for (bool ok = xrefs.SMP_first_to(FirstAddr, XREF_ALL); ok; ok = xrefs.SMP_next_to()) {
		ea_t FromAddr = xrefs.GetFrom();
		if (FromAddr != 0) {
			if (!xrefs.GetIscode()) { // found data xref
				IsIndirectCallTarget = true; // addr of func appears in data; assume indirect calls to func
			}
			else { // found code xref; see if it is a jump used as a tail call
				// These tail calls could be a problem for fast returns if they go from unsafe to safe functions.
				insn_t TempCmd;
				ulong TempFeatures;
				bool CmdOK = SMPGetCmd(FromAddr, TempCmd, TempFeatures);
				if (!CmdOK) {
					// Better be conservative and assume it could be a tail call.
					IsTailCallTarget = true;
					SMP_msg("ERROR: Could not decode instruction at %x from within MarkFunctionSafe(); assuming tail call\n", FromAddr);
				}
				else if (TempCmd.itype != MD_CALL_INSTRUCTION) { // not a call instruction; must be jump of some sort
					IsTailCallTarget = true;
				}
			}
		}
	}
	this->PossibleIndirectCallTarget = IsIndirectCallTarget;
	this->PossibleTailCallTarget = IsTailCallTarget;
	list<SMPInstr *>::iterator Instructions = Instrs.begin();
	SMPInstr *CurrInst;
	++Instructions;  // skip marker instruction
	// While processing the stack pointer writes, the prologue code for
	//  saving the frame register and allocating local variables needs to be
	//  handled.
	bool SaveEBP = false;
	bool XferESPtoEBP = false;
	for ( ; Instructions != Instrs.end(); ++Instructions) {
clc5q's avatar
clc5q committed
#if SMP_VERBOSE_DEBUG_FUNC 
		SMP_msg(" Total number of defs for this instruction %d\n", CurrInst->NumDefs());
#endif
		if (!SaveEBP) { // still looking for "push ebp"
			if (CurrInst->MDIsPushInstr() && CurrInst->GetCmd().Operands[0].is_reg(R_bp)) {
				SaveEBP = true;
				continue;
			}
		}
		else if (!XferESPtoEBP) { // found "push ebp", looking for "mov ebp,esp"
			insn_t CurrCmd = CurrInst->GetCmd();
			if ((CurrCmd.itype == NN_mov)
					&& (CurrInst->GetFirstDef()->GetOp().is_reg(R_bp))
					&& (CurrInst->GetFirstUse()->GetOp().is_reg(R_sp))) {
				XferESPtoEBP = true;
				continue;
			}
		}
		ea_t address = CurrInst->GetAddr();
		if (address == this->LocalVarsAllocInstr ||
		    address == this->LocalVarsDeallocInstr)
			continue;

		if (CurrInst->MDIsStackPointerCopy(this->UseFP)) {
			if (CurrInst->MDIsLoadEffectiveAddressInstr()) {
				// If an lea instruction loads an address above
				//  the stack frame, we must assume that writes
				//  above the stack frame could occur.
				op_t TempOp = CurrInst->GetLeaMemUseOp();
				if (this->WritesAboveLocalFrame(TempOp, CurrInst->AreDefsNormalized()))
clc5q's avatar
clc5q committed
#if SMP_DEBUG_FUNC 
			SMP_msg(" Function %s marked as unsafe due to stack pointer copy \n ", this->GetFuncName());
			SMP_msg("%s %x \n", CurrInst->GetDisasm(), CurrInst->GetAddr());
		if (CurrInst->MDIsPushInstr()) {
			// not exactly sure how to handle this instruction
			// for the moment if its a push on a esp or usefp & ebp
			// mark as unsafe
			if (CurrInst->GetCmd().Operands[0].is_reg(R_sp) || 	 
					(this->UseFP && CurrInst->GetCmd().Operands[0].is_reg(R_bp))) {
clc5q's avatar
clc5q committed
#if SMP_DEBUG_FUNC 
				SMP_msg(" Function %s marked as unsafe due to push on ebp or esp outside of function header \n", this->GetFuncName());	
				SMP_msg("%s %x\n", CurrInst->GetDisasm(), CurrInst->GetAddr());
		if (CurrInst->MDIsPopInstr() || CurrInst->MDIsReturnInstr()) {
			// ignore pops and returns for the moment
			 continue;
		}
		set<DefOrUse, LessDefUse>::iterator setIterator;
		for (setIterator = CurrInst->GetFirstDef(); setIterator != CurrInst->GetLastDef(); ++setIterator) {
			op_t Operand = setIterator->GetOp();
clc5q's avatar
clc5q committed
			if (Operand.type == o_mem) {
				// now o_mem can have sib byte as well, as
				// reported by IDA. Check if the base reg is R_none
				// and index reg is R_none. If they are, then this is
				// a direct global write and can be marked safe.
				MDExtractAddressFields(Operand, BaseReg, IndexReg, ScaleFactor, offset);
clc5q's avatar
clc5q committed
				if ((BaseReg == R_none) && (IndexReg == R_none)) {
clc5q's avatar
clc5q committed
				else {
					HasIndirectGlobalWrite = true;
				}
clc5q's avatar
clc5q committed
			else if (Operand.type == o_displ) {
				MDExtractAddressFields(Operand, BaseReg, IndexReg, ScaleFactor, offset);
				bool FramePointerRelative = (this->UseFP && (BaseReg == R_bp));
				bool StackPointerRelative = (BaseReg == R_sp);
				if (StackPointerRelative || FramePointerRelative) {
						bool tempWritesAboveLocalFrame = this->WritesAboveLocalFrame(Operand, CurrInst->AreDefsNormalized());
clc5q's avatar
clc5q committed
						WritesAboveLocalFrame |= tempWritesAboveLocalFrame;
#if SMP_DEBUG_FUNC 
clc5q's avatar
clc5q committed
						if (tempWritesAboveLocalFrame) {
							SMP_msg(" Function %s marked as unsafe due to direct write above loc "
								"variables offset=%x  loc=%x\n ", this->GetFuncName(), 
								offset, this->LocalVarsSize);	
							SMP_msg("Write above local frame in %s : offset: %d ",
								this->GetFuncName(), offset);
							SMP_msg("LocalVarsSize: %d OutgoingArgsSize: %d frsize: %d frregs: %d",
								this->LocalVarsSize, this->OutgoingArgsSize, 
								this->FuncInfo.frsize, this->FuncInfo.frregs);
							Instructions->Dump();
						}
#endif
clc5q's avatar
clc5q committed
					else {
						bool tempWritesAboveLocalFrameIndirect = this->IndexedWritesAboveLocalFrame(Operand);

						/* separate indirect writes to this frame from indirect writes to another frame */
clc5q's avatar
clc5q committed
						if (tempWritesAboveLocalFrameIndirect) {
							WritesAboveLocalFrameIndirect = true;
clc5q's avatar
clc5q committed
#if SMP_DEBUG_FUNC 
							SMP_msg(" Function %s marked as unsafe due to indexed stack write above "
								"loc variable offset\n", this->GetFuncName());	
							SMP_msg("%s %x\n", CurrInst->GetDisasm(), CurrInst->GetAddr());
clc5q's avatar
clc5q committed
#endif
clc5q's avatar
clc5q committed
						else {
							HasIndexedStackWrite = true;
clc5q's avatar
clc5q committed
#if SMP_DEBUG_FUNC 
							SMP_msg(" Function %s marked as unsafe due to indexed stack write\n", 
								this->GetFuncName());	
							SMP_msg("%s %x\n", CurrInst->GetDisasm(), CurrInst->GetAddr());
clc5q's avatar
clc5q committed
				else {
					/* check whether there is profiler information for this indirect reference */
			else if (Operand.type == o_phrase) {
				// so phrase is of the form [BASE_REG + IND ]
				// if the index register is missing just make sure that
				// the displacement is below stack frame top
				MDExtractAddressFields(Operand, BaseReg, IndexReg, ScaleFactor, offset);
				// check the base reg
				// if index reg is used mark as unsafe 
clc5q's avatar
clc5q committed
				if ((BaseReg == R_sp || (this->UseFP && BaseReg == R_bp))) {
					if (IndexReg == R_none) {
						/* addressing mode is *esp or *ebp */
						continue;
					}
					else {
						HasIndexedStackWrite = true;
#if SMP_DEBUG_FUNC 
						SMP_msg(" Function %s marked as unsafe due to indexed stack write\n", this->GetFuncName());	
						SMP_msg("%s %x\n", CurrInst->GetDisasm(), CurrInst->GetAddr());
clc5q's avatar
clc5q committed
				else {
					/* check whether there is profiler information for this indirect reference */
			// else not memory, and we don't care.
		} // end for all DEFs in current instruction
	} // end for all instructions
	// For mmStrata bounds checking of the stack frame, we don't care
	//  about indirect writes unless they are to the stack.
	bool SpecUnsafe = (HasStackPointerCopy || HasStackPointerPush 
		|| HasIndexedStackWrite || this->SharedChunks
		|| this->UnresolvedIndirectJumps);
	bool Unsafe = SpecUnsafe || this->UnresolvedIndirectCalls;

	this->SafeFunc = (!Unsafe);
	this->SpecSafeFunc = (!SpecUnsafe);

	this->WritesAboveRA = WritesAboveLocalFrameIndirect;
	this->SafeCallee = (!Unsafe) && (!WritesAboveLocalFrameIndirect) && this->AnalyzedSP;
	this->SpecSafeCallee = (!SpecUnsafe) && (!WritesAboveLocalFrameIndirect) && this->AnalyzedSP;
	this->NeedsStackReferent = Unsafe;
	this->SpecNeedsStackReferent = SpecUnsafe;

	this->HasIndirectWrites = (HasIndexedStackWrite || HasIndirectWrite
		|| WritesAboveLocalFrameIndirect || HasIndirectGlobalWrite);

	bool UnsafeReturnAddr = (Unsafe || WritesAboveLocalFrame || WritesAboveLocalFrameIndirect || HasIndirectGlobalWrite 
		|| HasIndirectWrite || (!this->AnalyzedSP));
#if SMP_DECLARE_INDIRECT_TARGETS_UNSAFE
	if (!UnsafeReturnAddr && this->PossibleIndirectCallTarget) {
		SMP_msg("INFO: Function at %x becoming UNSAFE because it is indirect call target.\n", this->FirstEA);
		UnsafeReturnAddr =  true;
	}
	else if (!UnsafeReturnAddr && this->PossibleTailCallTarget) {
		SMP_msg("INFO: Function at %x becoming UNSAFE because it is tail call target.\n", this->FirstEA);
		UnsafeReturnAddr =  true;
	}
	else if (!UnsafeReturnAddr && HasNoCallers) {
		SMP_msg("INFO: Function at %x becoming UNSAFE because it has no callers.\n", this->FirstEA);
		UnsafeReturnAddr =  true;
	}
#endif

	if (UnsafeReturnAddr) {
		this->SetReturnAddressStatus(FUNC_UNSAFE);
#if SMP_DEBUG_FUNC_SAFETY
		SMP_msg("UNSAFE function %s ", this->GetFuncName());
		SMP_msg("StackPtrCopy: %d StackPtrPush: %d IndirectGlobal: %d ",
			HasStackPointerCopy, HasStackPointerPush, HasIndirectGlobalWrite);
		SMP_msg("WritesAboveFrame: %d IndirectStack: %d IndirectWrite: %d ",
			WritesAboveLocalFrame, HasIndexedStackWrite, HasIndirectWrite);
		SMP_msg("AnalyzedSP: %d UnresolvedCalls: %d UnresolvedJumps: %d SharedChunks: %d IsLeaf: %d",
			this->AnalyzedSP, this->UnresolvedIndirectCalls, this->UnresolvedIndirectJumps,
			this->SharedChunks, this->IsLeaf());
		SMP_msg("IndirCallTarget: %d TailCallTarget: %d HasNoCallers: %d\n", this->PossibleIndirectCallTarget,
			this->PossibleTailCallTarget, HasNoCallers);
clc5q's avatar
clc5q committed
#endif
		this->SetReturnAddressStatus(FUNC_UNKNOWN);
	if (this->GetReturnAddressStatus() == FUNC_SAFE)
		SMP_msg("Function %s is SAFE\n", GetFuncName());
	else if (this->GetReturnAddressStatus() == FUNC_SAFE)
		SMP_msg("Function %s is UNSAFE\n", GetFuncName());
	else if (this->GetReturnAddressStatus() == FUNC_SAFE)
		SMP_msg("Function %s is UNKNOWN\n", GetFuncName());
clc5q's avatar
clc5q committed
	if (!Unsafe) 
		SMP_msg("Function %s is mmSAFE\n", GetFuncName());
		SMP_msg("Function %s is mmUNSAFE\n", GetFuncName());
clc5q's avatar
clc5q committed
	if (!SpecUnsafe) 
		SMP_msg("Function %s is Speculatively mmSAFE\n", GetFuncName());
		SMP_msg("Function %s is Speculatively mmUNSAFE\n", GetFuncName());
} // end of SMPFunction::MarkFunctionSafe()