Skip to content
Snippets Groups Projects
SMPFunction.cpp 205 KiB
Newer Older
				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
			qfprintf(AnnotFile,	"%10x %6d DEALLOC STACK esp - %d %s\n", addr,
				this->LocalVarsSize, this->LocalVarsSize, CurrInst->GetDisasm());
		if (this->HasGoodRTLs() && !this->HasUnresolvedIndirectJumps() && !this->HasSharedChunks()) {
			CurrInst->EmitTypeAnnotations(this->UseFP, AllocSeen, this->NeedsStackReferent, AnnotFile, InfoAnnotFile);
			CurrInst->EmitIntegerErrorAnnotations(InfoAnnotFile);
			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.
	list<SMPBasicBlock>::iterator CurrBlock;
	this->SafeBlocks = 0;
	this->UnsafeBlocks = 0;
	for (CurrBlock = this->Blocks.begin(); CurrBlock != this->Blocks.end(); ++CurrBlock) {
		if (CurrBlock->MaybeAliasedWrite()) {
			++(this->UnsafeBlocks);
			list<list<SMPInstr>::iterator>::iterator CurrInst;
			CurrInst = CurrBlock->GetFirstInstr();
			ea_t addr = (*CurrInst)->GetAddr();
			qfprintf(AnnotFile,	"%10x %6d BLOCK PROFILECOUNT %s\n", addr,
				(*CurrInst)->GetCmd().size, (*CurrInst)->GetDisasm());
	return;
} // end of SMPFunction::EmitAnnotations()

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

#if SMP_USE_SWITCH_TABLE_INFO
	if (this->UnresolvedIndirectJumps) {
#else
	if (this->IndirectJumps) {
clc5q's avatar
clc5q committed
#if SMP_DEBUG_FUNC
		msg("Function %s marked as unsafe due to indirect jumps\n", this->GetFuncName());
	list<SMPInstr>::iterator Instructions = Instrs.begin();
	++Instructions;  // skip marker instruction
	// While processing the stack pointer writes, the prologue code for
	//  saving 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 
		msg(" Total number of defs for this instruction %d\n", Instructions->NumDefs());
#endif
		if (!SaveEBP) { // still looking for "push ebp"
			if (Instructions->MDIsPushInstr() && Instructions->GetCmd().Operands[0].is_reg(R_bp)) {
				SaveEBP = true;
				continue;
			}
		}
		else if (!XferESPtoEBP) { // found "push ebp", looking for "mov ebp,esp"
			insn_t CurrCmd = Instructions->GetCmd();
			if ((CurrCmd.itype == NN_mov)
					&& (Instructions->GetFirstDef()->GetOp().is_reg(R_bp))
					&& (Instructions->GetFirstUse()->GetOp().is_reg(R_sp))) {
				XferESPtoEBP = true;
				continue;
			}
		}
		ea_t address = Instructions->GetAddr();
		if (address == this->LocalVarsAllocInstr ||
		    address == this->LocalVarsDeallocInstr)
			continue;

		if (Instructions->MDIsStackPointerCopy(this->UseFP)) {
			if (NN_lea == Instructions->GetCmd().itype) {
				// If an lea instruction loads an address above
				//  the stack frame, we must assume that writes
				//  above the stack frame could occur.
				if (this->WritesAboveLocalFrame(Instructions->GetCmd().Operands[1]))
					WritesAboveLocalFrameIndirect = true;
			}
clc5q's avatar
clc5q committed
#if SMP_DEBUG_FUNC 
			msg(" Function %s marked as unsafe due to stack pointer copy \n ", this->GetFuncName());
			msg("%s %x \n", (Instructions)->GetDisasm(), (Instructions)->GetAddr());
#endif
		}
		if (Instructions->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 (Instructions->GetCmd().Operands[0].is_reg(R_sp) || 	 
clc5q's avatar
clc5q committed
					(this->UseFP && Instructions->GetCmd().Operands[0].is_reg(R_bp))) {
clc5q's avatar
clc5q committed
#if SMP_DEBUG_FUNC 
				msg(" Function %s marked as unsafe due to push on ebp or esp outside of function header \n", this->GetFuncName());	
				msg("%s %x\n", (Instructions)->GetDisasm(), (Instructions)->GetAddr());
#endif
			}
			continue;
		}
		if (Instructions->MDIsPopInstr() || Instructions->MDIsReturnInstr()) {
			// ignore pops and returns for the moment
			 continue;
		}
		set<DefOrUse, LessDefUse>::iterator setIterator;
clc5q's avatar
clc5q committed
		for (setIterator = Instructions->GetFirstDef(); setIterator != Instructions->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);
clc5q's avatar
clc5q committed
						WritesAboveLocalFrame |= tempWritesAboveLocalFrame;
#if SMP_DEBUG_FUNC 
clc5q's avatar
clc5q committed
						if (tempWritesAboveLocalFrame) {
							msg(" Function %s marked as unsafe due to direct write above loc "
								"variables offset=%x  loc=%x\n ", this->GetFuncName(), 
								offset, this->LocalVarsSize);	
							msg("Write above local frame in %s : offset: %d ",
								this->GetFuncName(), offset);
							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);

						/* seperate 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 
							msg(" Function %s marked as unsafe due to indexed stack write above "
								"loc variable offset\n", this->GetFuncName());	
							msg("%s %x\n", (Instructions)->GetDisasm(), (Instructions)->GetAddr());
clc5q's avatar
clc5q committed
#endif
clc5q's avatar
clc5q committed
						else {
							HasIndexedStackWrite = true;
clc5q's avatar
clc5q committed
#if SMP_DEBUG_FUNC 
							msg(" Function %s marked as unsafe due to indexed stack write\n", 
								this->GetFuncName());	
							msg("%s %x\n", (Instructions)->GetDisasm(), (Instructions)->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 
						msg(" Function %s marked as unsafe due to indexed stack write\n", this->GetFuncName());	
						msg("%s %x\n", (Instructions)->GetDisasm(), (Instructions)->GetAddr());
#endif
					}
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 Unsafe = (HasStackPointerCopy || HasStackPointerPush 
		|| HasIndexedStackWrite || this->SharedChunks
		|| this->UnresolvedIndirectJumps || this->UnresolvedIndirectCalls);

	bool SpecUnsafe = (HasStackPointerCopy || HasStackPointerPush 
		|| HasIndexedStackWrite || this->SharedChunks
		|| this->UnresolvedIndirectJumps);
	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);

	if (Unsafe || WritesAboveLocalFrame || WritesAboveLocalFrameIndirect || HasIndirectGlobalWrite 
		|| HasIndirectWrite || (!this->AnalyzedSP)) {
clc5q's avatar
clc5q committed
#if SMP_DEBUG_FUNC
		msg("UNSAFE function %s ", this->GetFuncName());
		msg("StackPtrCopy: %d StackPtrPush: %d IndirectGlobal: %d ",
			HasStackPointerCopy, HasStackPointerPush, HasIndirectGlobalWrite);
		msg("WritesAboveFrame: %d IndirectStack: %d IndirectWrite: %d ",
			WritesAboveLocalFrame, HasIndexedStackWrite, HasIndirectWrite);
		msg("AnalyzedSP: %d UnresolvedCalls: %d UnresolvedJumps: %d SharedChunks: %d IsLeaf: %d\n",
			this->AnalyzedSP, this->UnresolvedIndirectCalls, this->UnresolvedIndirectJumps,
clc5q's avatar
clc5q committed
#endif
clc5q's avatar
clc5q committed
	if (ReturnAddrStatus == FUNC_SAFE)
		msg("Function %s is SAFE\n", GetFuncName());
clc5q's avatar
clc5q committed
	else if (ReturnAddrStatus == FUNC_SAFE)
		msg("Function %s is UNSAFE\n", GetFuncName());
clc5q's avatar
clc5q committed
	else if (ReturnAddrStatus == FUNC_SAFE)
		msg("Function %s is UNKNOWN\n", GetFuncName());

clc5q's avatar
clc5q committed
	if (!Unsafe) 
		msg("Function %s is mmSAFE\n", GetFuncName());
	else 
		msg("Function %s is mmUNSAFE\n", GetFuncName());

clc5q's avatar
clc5q committed
	if (!SpecUnsafe) 
		msg("Function %s is Speculatively mmSAFE\n", GetFuncName());
	else 
		msg("Function %s is Speculatively mmUNSAFE\n", GetFuncName());

#endif
} // end of SMPFunction::MarkFunctionSafe()