Skip to content
Snippets Groups Projects
SMPFunction.cpp 191 KiB
Newer Older
	msg("MDFixUseFP reset UseFP to false for %s\n", this->GetFuncName());
	return true;
} // end of SMPFunction::MDFixUseFP()

// Find the callee-saved reg offsets (negative offset from return address)
//  for all registers pushed onto the stack before the stack frame allocation
//  instruction.
void SMPFunction::MDFindSavedRegs(void) {
	list<SMPInstr>::iterator CurrInst;
	int RegIndex;
	func_t *CurrFunc = get_func(this->GetStartAddr());
	assert(NULL != CurrFunc);

	for (CurrInst = this->Instrs.begin(); CurrInst != this->Instrs.end(); ++CurrInst) {
		if (CurrInst->GetAddr() > this->LocalVarsAllocInstr)
			break;
		if (!(CurrInst->MDIsPushInstr()))
			continue;

		sval_t CurrOffset = get_spd(CurrFunc, CurrInst->GetAddr());
		if (CurrInst->GetCmd().itype == NN_push) {
			op_t PushedReg = CurrInst->GetPushedOpnd();
			if (o_reg == PushedReg.type) {
				RegIndex = (int) PushedReg.reg;
				if (RegIndex > R_di) {
					msg("WARNING: Skipping save of register %d\n", RegIndex);
					continue;
				}
				if (this->SavedRegLoc.at((size_t) RegIndex) == 0) {
					this->SavedRegLoc[(size_t) RegIndex] = CurrOffset - 4;
				}
				else {
					msg("WARNING: Multiple saves of register %d\n", RegIndex);
				}
			} // end if register push operand
		} // end if PUSH instruction
		else if (NN_pusha == CurrInst->GetCmd().itype) {
			// **!!** Handle pushes of all regs.
			this->SavedRegLoc[(size_t) R_ax] = CurrOffset - 4;
			this->SavedRegLoc[(size_t) R_cx] = CurrOffset - 8;
			this->SavedRegLoc[(size_t) R_dx] = CurrOffset - 12;
			this->SavedRegLoc[(size_t) R_bx] = CurrOffset - 16;
			this->SavedRegLoc[(size_t) R_sp] = CurrOffset - 20;
			this->SavedRegLoc[(size_t) R_bp] = CurrOffset - 24;
			this->SavedRegLoc[(size_t) R_si] = CurrOffset - 28;
			this->SavedRegLoc[(size_t) R_di] = CurrOffset - 32;
			break; // all regs accounted for
		}
		else if (CurrInst->MDIsEnterInstr()) {
			this->SavedRegLoc[(size_t) R_bp] = CurrOffset - 4;
		}
	} // end for all instructions

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

// Compute the ReturnRegTypes[] as the meet over all register types
//  at all return instructions.
void SMPFunction::MDFindReturnTypes(void) {
	list<SMPBasicBlock>::iterator CurrBlock;
	list<list<SMPInstr>::iterator>::iterator InstIter;
	vector<SMPOperandType> RegTypes;

	for (CurrBlock = this->Blocks.begin(); CurrBlock != this->Blocks.end(); ++CurrBlock) {
		if (CurrBlock->HasReturn()) {
			// Get the types of all registers at the RETURN point.
			//  Calculate the meet function over them.
			InstIter = CurrBlock->GetLastInstr();
			--InstIter;
			assert(RETURN == (*InstIter)->GetDataFlowType());
			set<DefOrUse, LessDefUse>::iterator CurrUse;
			for (CurrUse = (*InstIter)->GetFirstUse();
				CurrUse != (*InstIter)->GetLastUse();
				++CurrUse) {

				op_t UseOp = CurrUse->GetOp();
				if ((o_reg != UseOp.type) || (R_di < UseOp.reg))
					continue;
				this->ReturnRegTypes[UseOp.reg]
					= SMPTypeMeet(this->ReturnRegTypes.at(UseOp.reg),
						CurrUse->GetType());
			} // for all USEs in the RETURN instruction
		} // end if current block has a RETURN
	} // end for all blocks
	return;
} // end of SMPFunction::MDFindReturnTypes()

// Determine local variable boundaries in the stack frame.
void SMPFunction::BuildLocalVarTable(void) {
	// Currently we just use the info that IDA Pro has inferred from the direct
	//  addressing of stack locations.
	this->SemiNaiveLocalVarID();
	return;
} // end of SMPFunction::BuildLocalVarTable()

// Use the local variable offset list from IDA's stack frame structure to compute
//  the table of local variable boundaries.
void SMPFunction::SemiNaiveLocalVarID(void) {
	// NOTE: We use IDA Pro's offsets from this->FuncInfo (e.g. frsize) and NOT
	//  our own corrected values in our private data members. The offsets we
	//  read from the stack frame structure returned by get_frame() are consistent
	//  with other IDA Pro values, not with our corrected values.
	bool DebugFlag = false;
#if SMP_DEBUG_STACK_GRANULARITY
	DebugFlag |= (0 == strcmp("qSort3", this->GetFuncName()));
#endif
	func_t *FuncPtr = get_func(this->FuncInfo.startEA);
	if (NULL == FuncPtr) {
		msg("ERROR in SMPFunction::SemiNaiveLocalVarID; no func ptr\n");
	}
	assert(NULL != FuncPtr);
	struc_t *StackFrame = get_frame(FuncPtr);

	if (NULL == StackFrame) {
		msg("WARNING: No stack frame info from get_frame for %s\n", this->GetFuncName());
		return;
	}

	member_t *Member = StackFrame->members;
	for (size_t i = 0; i < StackFrame->memqty; ++i, ++Member) {
		long offset;
		char MemberName[MAXSMPVARSTR] = {'\0'};
		if (NULL == Member) {
			msg("NULL stack frame member pointer in %s\n", this->GetFuncName());
			break;
		}
		get_member_name(Member->id, MemberName, MAXSMPVARSTR - 1);
#if SMP_DEBUG_STACK_GRANULARITY
			msg("NULL stack frame member in %s\n", this->GetFuncName());
 		if (MemberName[0] == ' ') {
#if SMP_DEBUG_STACK_GRANULARITY
			msg("NULL stack frame name at offset %d in %s\n", offset, this->GetFuncName());
			msg("%s local var %s at offset %ld\n", this->GetFuncName(), MemberName, offset);
		}
		if (offset >= (long) this->LocalVarsSize)
#if 1
			continue;  // Skip incoming args
#else
			break;  // Stop after processing locals and outgoing args
#if 0
		// We want the offset from the stack pointer after local frame allocation.
		//  This subtraction would make it relative to the original stack pointer.
		offset -= this->FuncInfo.frsize;
#endif
		struct LocalVar TempLocal;
		TempLocal.offset = offset;
clc5q's avatar
clc5q committed
		TempLocal.size = (size_t) -1; // compute later
		qstrncpy(TempLocal.VarName, MemberName, sizeof(TempLocal.VarName) - 1);
		this->LocalVarTable.push_back(TempLocal);
	} // end for all stack frame members
	if (!(this->LocalVarTable.empty()))
		this->GoodLocalVarTable = true;
#if SMP_DEBUG_STACK_GRANULARITY
	msg("Computing %d local var sizes\n", this->LocalVarTable.size());
	// Now we want to fill in the size field for each local
	if (this->GoodLocalVarTable) {
		size_t VarLimit = this->LocalVarTable.size() - 1;
		assert(this->LocalVarTable.size() > 0);
		for (size_t VarIndex = 0; VarIndex < VarLimit; ++VarIndex) {
			this->LocalVarTable[VarIndex].size = this->LocalVarTable[VarIndex + 1].offset
				- this->LocalVarTable[VarIndex].offset;
		}
#if SMP_DEBUG_STACK_GRANULARITY
		msg("Computing last local var size for frsize %d\n", this->FuncInfo.frsize);
		// Size of last local is total frsize minus savedregs in frame minus offset of last local
		size_t SavedRegsSpace = 0; // portion of frsize that is saved regs, not locals.
		if (this->CalleeSavedRegsSize > this->FuncInfo.frregs) {
			// IDA Pro counts the save of EBP in frregs, but then EBP gets its new
			//  value and callee saved regs other than the old EBP push get counted
			//  in frsize rather than frregs. CalleeSavedRegsSize includes all saved
			//  regs on the stack, both above and below the current EBP offset.
			// NOTE: For windows, this has to be done differently, as callee saved regs
			//  happen at the bottom of the local frame, not the top.
			SavedRegsSpace = this->CalleeSavedRegsSize - this->FuncInfo.frregs;
			SavedRegsSpace = this->FuncInfo.frsize - this->LocalVarsSize;
		this->LocalVarTable.back().size = this->FuncInfo.frsize
			- SavedRegsSpace - this->LocalVarTable.back().offset;

		this->LocalVarOffsetLimit = this->LocalVarTable.back().offset 
			+ (adiff_t) this->LocalVarTable.back().size;
	}

	// IDA Pro can have difficulty with some irregular functions such as are found
	//  in the C startup code. The frsize value might be bogus. Just punt on the
	//  local variable ID if that is the case.
	if (this->LocalVarOffsetLimit > (adiff_t) this->FuncInfo.frsize) {
		this->LocalVarTable.clear();
		this->GoodLocalVarTable = false;
		msg("WARNING: Bad frsize for %s ; abandoning SemiNaiveLocalVarID.\n", this->FuncName);
		return;
	}
	assert(this->LocalVarOffsetLimit <= (adiff_t) this->FuncInfo.frsize);
	// Find out how many of the locals are really outgoing args.
	if (this->AnalyzedSP && !this->CallsAlloca && (BADADDR != this->LocalVarsAllocInstr)) {
		this->FindOutgoingArgsSize();
	}
	else {
		msg("FindOutgoingArgsSize not called for %s ", this->GetFuncName());
		msg("AnalyzedSP: %d CallsAlloca: %d LocalVarsAllocInstr: %x \n",
			this->AnalyzedSP, this->CallsAlloca, this->LocalVarsAllocInstr);
	}
	return;
} // end of SMPFunction::SemiNaiveLocalVarID()

// Determine how many bytes at the bottom of the stack frame (i.e. at bottom of
//  this->LocalVarsSize) are used for outgoing args. This is the case when the cdecl
//  calling convention is used, e.g. gcc/linux allocates local var space + out args space
//  in a single allocation and then writes outarg values directly to ESP+0, ESP+4, etc.
void SMPFunction::FindOutgoingArgsSize(void) {
	// Compute the lowest value reached by the stack pointer.
	list<SMPInstr>::iterator CurrInst;
	this->MinStackDelta = 20000; // Final value should be negative or zero
	unsigned short BitWidthMask;
	bool DebugFlag = false;
#if SMP_DEBUG_STACK_GRANULARITY
	DebugFlag = (0 == strcmp("error_for_asm", this->GetFuncName()));
#endif
	if (DebugFlag) {
		msg("DEBUG: Entered FindOutgoingArgsSize for %s\n", this->GetFuncName());
#if SMP_IDAPRO52_WORKAROUND
		this->OutgoingArgsSize = 16;
		return;
	CurrInst = this->Instrs.begin();
#if SMP_USE_SSA_FNOP_MARKER
	if (CurrInst->IsFloatNop())
		++CurrInst;  // skip marker instruction
	for ( ; CurrInst != this->Instrs.end(); ++CurrInst) {
		ea_t addr = CurrInst->GetAddr();
		sval_t sp_delta = get_spd(this->GetFuncInfo(), addr);
		if (sp_delta < this->MinStackDelta)
			this->MinStackDelta = sp_delta;
		if (addr == this->LocalVarsAllocInstr) {
			// Total stack pointer delta is sp_delta for the next instruction,
			//  because IDA updates the sp delta AFTER each instruction.
			list<SMPInstr>::iterator NextInst = CurrInst;
			++NextInst;
			sp_delta = get_spd(this->GetFuncInfo(), NextInst->GetAddr());
			this->AllocPointDelta = sp_delta;
		}
	}
#if SMP_DEBUG_STACK_GRANULARITY
	msg("AllocPointDelta: %d MinStackDelta: %d\n", this->AllocPointDelta, this->MinStackDelta);
#endif
	if ((0 <= this->MinStackDelta) || (0 <= this->AllocPointDelta)) {
		// No allocations; sometimes happens in library functions.
		this->OutgoingArgsSize = 0;
		this->MinStackDelta = 0;
		this->AllocPointDelta = 0;
		return;
	}
	assert(0 > this->MinStackDelta);

	// Allocate a vector of stack frame entries, one for each byte of the stack frame.
	//  This will be our memory map for analyzing stack usage.
	int limit = 0;
#if 1
	if (this->LocalVarOffsetLimit > 0)
		limit = this->LocalVarOffsetLimit;
#endif
	for (int i = this->MinStackDelta; i < limit; ++i) {
		struct StackFrameEntry TempEntry;
		struct FineGrainedInfo TempFineGrained;
		TempEntry.VarPtr = NULL;
		TempEntry.offset = (long) i;
		TempEntry.Read = false;
		TempEntry.Written = false;
		TempEntry.AddressTaken = false;
		TempEntry.ESPRelativeAccess = false;
		TempEntry.EBPRelativeAccess = false;
		TempEntry.IndexedAccess = false;
		this->StackFrameMap.push_back(TempEntry);
		TempFineGrained.SignMiscInfo = 0;
		TempFineGrained.SizeInfo = 0;
		this->FineGrainedStackTable.push_back(TempFineGrained);
	}

	// Fill in the VarPtr fields for each StackFrameMap entry.
	if (0 <= this->AllocPointDelta) {
		msg("FATAL ERROR: AllocPointDelta = %d in %s\n", this->AllocPointDelta, this->GetFuncName());
	}
	assert(0 > this->AllocPointDelta);
	for (size_t i = 0; i < this->LocalVarTable.size(); ++i) {
		assert(this->LocalVarTable.at(i).offset >= 0);
		// Picture that AllocPointDelta is -200, MinStackDelta is -210, and
		//  the LocalVarTable[i].offset is +8 (i.e. 8 bytes above alloc point).
		//  Then base = 8 + (-200 - -210) = 8 + 10 = 18, the proper offset into
		//  the StackFrameMap.
		size_t base = (size_t) (this->LocalVarTable.at(i).offset
			+ (this->AllocPointDelta - this->MinStackDelta));
		size_t limit = base + this->LocalVarTable.at(i).size;
		if (limit > this->StackFrameMap.size()) {
			msg("ERROR: base = %d limit = %d StackFrameMap size = %d\n", base, limit,
				this->StackFrameMap.size());
		}
		assert(limit <= this->StackFrameMap.size());
		for (size_t MapIndex = base; MapIndex < limit; ++MapIndex) {
			this->StackFrameMap[MapIndex].VarPtr = &(this->LocalVarTable.at(i));
		}
	}

	// Iterate through all instructions and record stack frame accesses in the StackFrameMap.
	CurrInst = this->Instrs.begin();
#if SMP_USE_SSA_FNOP_MARKER
	if (CurrInst->IsFloatNop())
		++CurrInst;  // skip marker instruction
	for ( ; CurrInst != this->Instrs.end(); ++CurrInst) {
		ea_t InstAddr = CurrInst->GetAddr();
		sval_t sp_delta = get_spd(this->GetFuncInfo(), InstAddr);
		if (0 < sp_delta) {
			// Stack underflow; about to assert
			msg("Stack underflow at %x %s sp_delta: %d\n", CurrInst->GetAddr(),
				CurrInst->GetDisasm(), sp_delta);
		}
		assert(0 >= sp_delta);
		ea_t offset;
		size_t DataSize;
		bool UsedFramePointer;
		bool SignedMove;
		bool UnsignedMove;
		if (CurrInst->HasDestMemoryOperand()) {
			set<DefOrUse, LessDefUse>::iterator CurrDef;
			for (CurrDef = CurrInst->GetFirstDef(); CurrDef != CurrInst->GetLastDef(); ++CurrDef) {
				op_t TempOp = CurrDef->GetOp();
				if (TempOp.type != o_phrase && TempOp.type != o_displ)
					continue;
				if (this->MDGetStackOffsetAndSize(CurrInst, TempOp, sp_delta, offset, DataSize, UsedFramePointer,
					IndexedAccess, SignedMove, UnsignedMove)) {
					assert(0 <= offset);
					if (offset >= this->FuncInfo.frsize)
						continue;  // limit processing to outgoing args and locals
					if ((offset + DataSize) > this->StackFrameMap.size()) {
						msg("ERROR: offset = %d DataSize = %d FrameMapSize = %d\n",
							offset, DataSize, this->StackFrameMap.size());
					}
					assert((offset + DataSize) <= this->StackFrameMap.size());
					for (int j = 0; j < (int) DataSize; ++j) {
						this->StackFrameMap[offset + j].Written = true;
						this->StackFrameMap[offset + j].IndexedAccess = IndexedAccess;
							this->StackFrameMap[offset + j].ESPRelativeAccess = true;
							this->StackFrameMap[offset + j].EBPRelativeAccess = true;
					BitWidthMask = ComputeOperandBitWidthMask(TempOp, DataSize);
					this->FineGrainedStackTable.at(offset).SizeInfo |= BitWidthMask;
					this->FineGrainedStackTable.at(offset).SignMiscInfo |= FG_MASK_WRITTEN;
					if (IndexedAccess) {
						this->FineGrainedStackTable.at(offset).SignMiscInfo |= FG_MASK_INDEXED_ACCESS;
					}
					if (!UsedFramePointer) {
						this->FineGrainedStackTable.at(offset).SignMiscInfo |= FG_MASK_SP_RELATIVE;
					}
					else {
						this->FineGrainedStackTable.at(offset).SignMiscInfo |= FG_MASK_FP_RELATIVE;
					}
					// We will process the signedness of stores later, so that loads can take precedence
					//  over stores in determining signedness.
				} // end if MDGetStackOffsetAndSize()
			} // end for all DEFs
		} // end if DestMemoryOperand

		if (CurrInst->HasSourceMemoryOperand()) {
			set<DefOrUse, LessDefUse>::iterator CurrUse;
			for (CurrUse = CurrInst->GetFirstUse(); CurrUse != CurrInst->GetLastUse(); ++CurrUse) {
				op_t TempOp = CurrUse->GetOp();
				if (TempOp.type != o_phrase && TempOp.type != o_displ)
					continue;
				if (this->MDGetStackOffsetAndSize(CurrInst, TempOp, sp_delta, offset, DataSize, UsedFramePointer,
					IndexedAccess, SignedMove, UnsignedMove)) {
					assert(0 <= offset);
					if (offset >= this->FuncInfo.frsize)
						continue;  // limit processing to outgoing args and locals
					if ((offset + DataSize) > this->StackFrameMap.size()) {
						msg("ERROR: offset = %d DataSize = %d FrameMapSize = %d\n",
							offset, DataSize, this->StackFrameMap.size());
					}
					assert((offset + DataSize) <= this->StackFrameMap.size());
					for (int j = 0; j < (int) DataSize; ++j) {
						this->StackFrameMap[offset + j].Read = true;
						this->StackFrameMap[offset + j].IndexedAccess |= IndexedAccess;
						if (!UsedFramePointer)
							this->StackFrameMap[offset + j].ESPRelativeAccess = true;
						else
							this->StackFrameMap[offset + j].EBPRelativeAccess = true;
					}
					BitWidthMask = ComputeOperandBitWidthMask(TempOp, DataSize);
					this->FineGrainedStackTable.at(offset).SizeInfo |= BitWidthMask;
					this->FineGrainedStackTable.at(offset).SignMiscInfo |= FG_MASK_READ;
					if (IndexedAccess) {
						this->FineGrainedStackTable.at(offset).SignMiscInfo |= FG_MASK_INDEXED_ACCESS;
					}
					if (!UsedFramePointer) {
						this->FineGrainedStackTable.at(offset).SignMiscInfo |= FG_MASK_SP_RELATIVE;
					}
					else {
						this->FineGrainedStackTable.at(offset).SignMiscInfo |= FG_MASK_FP_RELATIVE;
					}
					if (SignedMove) {
						this->FineGrainedStackTable.at(offset).SignMiscInfo |= FG_MASK_SIGNED;
					}
					else if (UnsignedMove) {
						this->FineGrainedStackTable.at(offset).SignMiscInfo |= FG_MASK_UNSIGNED;
					}
				} // end if MDGetStackOffsetAndSize()
			} // end for all USEs
		} // end if SourceMemoryOperand
		// NOTE: Detect taking the address of stack locations. **!!**
	} // end for all instructions

	// If function is a leaf function, set OutgoingArgsSize to zero and return.
	if (this->IsLeaf()) {
		this->OutgoingArgsSize = 0;
		return;
	}

	// For non-leaf functions, set the OutgoingArgsSize to the write-only, ESP-relative
	//  region of the bottom of the StackFrameMap.
	bool OutgoingArgsRegionFinished = false;
	bool IndexedOutgoingArgs = false; // Any indexed accesses to outgoing args?
	size_t FramePadSize = 0;
	for (size_t MapIndex = 0; MapIndex < this->StackFrameMap.size(); ++MapIndex) {
		// Some of the bottom of the stack frame might be below the local frame allocation.
		//  These are pushes that happened after allocation, etc. We skip over these
		//  locations and define the outgoing args region to start strictly at the bottom
		//  of the local frame allocation.
		struct StackFrameEntry TempEntry = this->StackFrameMap.at(MapIndex);
		if (DebugFlag) {
			msg("StackFrameMap entry %d: offset: %ld Read: %d Written: %d ESP: %d EBP: %d\n",
				MapIndex, TempEntry.offset, TempEntry.Read, TempEntry.Written,
				TempEntry.ESPRelativeAccess, TempEntry.EBPRelativeAccess);
		}
		if (TempEntry.offset < this->AllocPointDelta)
			continue;
		if (OutgoingArgsRegionFinished) {
			// We are just processing the stack frame padding.
			if (!TempEntry.Read && !TempEntry.Written) {
				// Could be stack frame padding.
				++FramePadSize;
			}
			else {
				break; // No more padding region
			}
		}
		else if (TempEntry.Read || TempEntry.EBPRelativeAccess || !TempEntry.Written
			|| !TempEntry.ESPRelativeAccess) {
			OutgoingArgsRegionFinished = true;
			if (!TempEntry.Read && !TempEntry.Written) {
				// Could be stack frame padding.
				++FramePadSize;
			}
			else {
				break; // No padding region
			}
		}
		else {
			this->OutgoingArgsSize++;
			if (TempEntry.IndexedAccess) {
				IndexedOutgoingArgs = true;
			}
		}
	}

	// If any outgoing arg was accessed using an index register, then we don't know how high
	//  the index register value went. It could potentially consume the so-called padding
	//  region, which might be just the region we did not detect direct accesses to because
	//  the accesses were indirect. To be safe, we expand the outgoing args region to fill
	//  the padding region above it in this indexed access case.
	if (IndexedOutgoingArgs) {
		this->OutgoingArgsSize += FramePadSize;
	// Sometimes we encounter unused stack space above the outgoing args. Lump this space
	//  in with the outgoing args. We detect this by noting when the outgoing args space
	//  has only partially used the space assigned to a local var.
	// NOTE: This is usually just stack padding to maintain stack alignment. It could
	//  also be the case that the lowest local variable is accessed indirectly and we missed
	//  seeing its address taken, in which case it would be unsound to lump it into the
	//  outgoing args region. We might want to create a local var called STACKPAD
	//  to occupy this space.
	if ((0 < this->OutgoingArgsSize) && (this->OutgoingArgsSize < this->FuncInfo.frsize)) {
		long MapIndex = (this->AllocPointDelta - this->MinStackDelta);
		assert(0 <= MapIndex);
		MapIndex += (((long) this->OutgoingArgsSize) - 1);
		struct StackFrameEntry TempEntry = this->StackFrameMap.at((size_t) MapIndex);
		if (NULL == TempEntry.VarPtr) { // Gap in stack frame; IDA 6.0
			msg("Gap in stack frame: %s\n", this->FuncName);
		}
		else if (this->OutgoingArgsSize < (TempEntry.VarPtr->offset + TempEntry.VarPtr->size)) {
			msg("OutGoingArgsSize = %d", this->OutgoingArgsSize);
			this->OutgoingArgsSize = TempEntry.VarPtr->offset + TempEntry.VarPtr->size;
			msg(" adjusted to %d\n", this->OutgoingArgsSize);
	return;
} // end of SMPFunction::FindOutgoingArgsSize()

// If TempOp reads or writes to a stack location, return the offset (relative to the initial
//  stack pointer value) and the size in bytes of the data access. Also return whether the
//  access was frame-pointer-relative, and whether signedness can be inferred due to a load
//  from the stack being zero-extended or sign-extended.
// NOTE: TempOp must be of type o_displ or o_phrase, as no other operand type could be a
//  stack memory access.
// sp_delta is the stack pointer delta of the current instruction, relative to the initial
//  stack pointer value for the function.
// Return true if a stack memory access was found in TempOp, false otherwise.
bool SMPFunction::MDGetStackOffsetAndSize(list<SMPInstr>::iterator Instr, op_t TempOp, sval_t sp_delta, ea_t &offset, size_t &DataSize, bool &FP,
										  bool & Indexed, bool &Signed, bool &Unsigned) {
	assert((o_displ == TempOp.type) || (o_phrase == TempOp.type));
	MDExtractAddressFields(TempOp, BaseReg, IndexReg, ScaleFactor, offset);
	if (TempOp.type == o_phrase) {
		assert(offset == 0);  // implicit zero, as in [esp] ==> [esp+0]

	SignedOffset = (int) offset;  // avoid sign errors during adjustment arithmetic

	if ((BaseReg == R_sp) || (IndexReg == R_sp)) {
		// ESP-relative constant offset
		SignedOffset += sp_delta; // base offsets from entry ESP value
		SignedOffset -= this->MinStackDelta; // convert to StackFrameMap index
		offset = (ea_t) SignedOffset;
		if (0 > SignedOffset) {
			// Consider asserting here.
			msg("ERROR: Negative offset in MDGetStackOffsetAndSize for inst dump: \n");
			Instr->Dump();
		}
		// Get size of data written
		DataSize = GetOpDataSize(TempOp);
		FP = false;
		Indexed = ((BaseReg != R_none) && (IndexReg != R_none)); // two regs used
		unsigned short opcode = Instr->GetCmd().itype;
		Unsigned = (opcode == NN_movzx);
		Signed = (opcode == NN_movsx);
		return true;
	}
	else if (this->UseFP && ((BaseReg == R_bp) || (IndexReg == R_bp))) {
		SignedOffset -= this->FuncInfo.frregs; // base offsets from entry ESP value
		SignedOffset -= this->MinStackDelta; // convert to StackFrameMap index
		offset = (ea_t) SignedOffset;
		if (0 > SignedOffset) {
			// Consider asserting here.
			msg("ERROR: Negative offset in MDGetStackOffsetAndSize for inst dump: \n");
			Instr->Dump();
		}
		DataSize = GetOpDataSize(TempOp);
		FP = true;
		Indexed = ((BaseReg != R_none) && (IndexReg != R_none)); // two regs used
		unsigned short opcode = Instr->GetCmd().itype;
		Unsigned = (opcode == NN_movzx);
		Signed = (opcode == NN_movsx);
		return true;
	}
	else {
		return false;
	}
} // end of SMPFunction::MDGetStackOffsetAndSize()
		
// Return fine grained stack entry for stack op TempOp from instruction at InstAddr
bool SMPFunction::MDGetFGStackLocInfo(ea_t InstAddr, op_t TempOp, struct FineGrainedInfo &FGEntry) {
	int BaseReg;
	int IndexReg;
	ushort ScaleFactor;
	ea_t offset;
	int SignedOffset;

	assert((o_displ == TempOp.type) || (o_phrase == TempOp.type));
	MDExtractAddressFields(TempOp, BaseReg, IndexReg, ScaleFactor, offset);
	sval_t sp_delta = get_spd(this->GetFuncInfo(), InstAddr);

	SignedOffset = (int) offset;

	if (TempOp.type == o_phrase) {
		assert(SignedOffset == 0);  // implicit zero, as in [esp] ==> [esp+0]
	}
	if ((BaseReg == R_sp) || (IndexReg == R_sp)) {
		// ESP-relative constant offset
		SignedOffset += sp_delta; // base offsets from entry ESP value
		SignedOffset -= this->MinStackDelta; // convert to StackFrameMap index
	}
	else if (this->UseFP && ((BaseReg == R_bp) || (IndexReg == R_bp))) {
		SignedOffset -= this->FuncInfo.frregs; // base offsets from entry ESP value
		SignedOffset -= this->MinStackDelta; // convert to StackFrameMap index
	}
	else {
		return false;
	}
	// We did not return false, so we should have a good offset. Use it to
	//  pass back the fine grained stack table entry for that offset.
	if ((0 > SignedOffset) || (SignedOffset >= (int) this->FineGrainedStackTable.size())) {
		if (this->OutgoingArgsComputed) {
			msg("ERROR: FG stack table index out of range in MDGetFGStackLocInfo at %x\n", InstAddr);
		}
		FGEntry.SignMiscInfo = 0;
		FGEntry.SizeInfo = 0;
	}
	else {
		FGEntry = this->FineGrainedStackTable.at((size_t) SignedOffset);
	}
	return true;
} // end of SMPFunction::MDGetFGStackLocInfo()

// Return true if we update fine grained stack entry for stack op TempOp from instruction at InstAddr
bool SMPFunction::MDUpdateFGStackLocInfo(ea_t InstAddr, op_t TempOp, struct FineGrainedInfo NewFG) {
	int BaseReg;
	int IndexReg;
	ushort ScaleFactor;
	ea_t offset;
	int SignedOffset;
	struct FineGrainedInfo OldFG, UnionFG;

	assert((o_displ == TempOp.type) || (o_phrase == TempOp.type));
	MDExtractAddressFields(TempOp, BaseReg, IndexReg, ScaleFactor, offset);
	sval_t sp_delta = get_spd(this->GetFuncInfo(), InstAddr);

	SignedOffset = (int) offset;

	if (TempOp.type == o_phrase) {
		assert(SignedOffset == 0);  // implicit zero, as in [esp] ==> [esp+0]
	}
	if ((BaseReg == R_sp) || (IndexReg == R_sp)) {
		// ESP-relative constant offset
		SignedOffset += sp_delta; // base offsets from entry ESP value
		SignedOffset -= this->MinStackDelta; // convert to StackFrameMap index
	}
	else if (this->UseFP && ((BaseReg == R_bp) || (IndexReg == R_bp))) {
		SignedOffset -= this->FuncInfo.frregs; // base offsets from entry ESP value
		SignedOffset -= this->MinStackDelta; // convert to StackFrameMap index
	}
	else {
		return false;
	}
	// We did not return false, so we should have a good offset. Use it to
	//  retrieve the fine grained stack table entry for that offset.
	if ((0 > SignedOffset) || (SignedOffset >= (int) this->FineGrainedStackTable.size())) {
		if (this->OutgoingArgsComputed) {
			msg("ERROR: FG stack table index out of range in MDGetFGStackLocInfo at %x\n", InstAddr);
		}
		return false;
	}
	else if (this->OutgoingArgsComputed && (((size_t)SignedOffset) < this->OutgoingArgsSize)) {
		// We don't want to update the outgoing args region, as it will not be consistent
		//  over multiple function calls. NOTE: We could fine tune this by seeing if we
		//  call mutliple target functions or not; if only one, then outgoing args region
		//  would be consistent in the absence of varargs targets.
		return false;
	}
	else {
		OldFG = this->FineGrainedStackTable.at((size_t) SignedOffset);
		UnionFG.SignMiscInfo = OldFG.SignMiscInfo | NewFG.SignMiscInfo;
		UnionFG.SizeInfo = OldFG.SizeInfo | NewFG.SizeInfo;
		if ((OldFG.SignMiscInfo != UnionFG.SignMiscInfo) || (OldFG.SizeInfo != UnionFG.SizeInfo)) {
			// The signs they are a-changin'. Or maybe the sizes.
			this->FineGrainedStackTable.at(SignedOffset).SignMiscInfo |= NewFG.SignMiscInfo;
			this->FineGrainedStackTable.at(SignedOffset).SizeInfo |= NewFG.SizeInfo;
		}
	}
	return true;
} // end of SMPFunction::MDUpdateFGStackLocInfo()

// retrieve DEF addr from GlobalDefAddrBySSA or return BADADDR
ea_t SMPFunction::GetGlobalDefAddr(op_t DefOp, int SSANum) {
	map<int, ea_t>::iterator DefAddrMapIter;
	map<int, ea_t>::iterator MapResult;
	ea_t DefAddr = BADADDR; // BADADDR means we did not find it

	int HashedName = HashGlobalNameAndSSA(DefOp, SSANum);
	MapResult = this->GlobalDefAddrBySSA.find(HashedName);
	if (MapResult != this->GlobalDefAddrBySSA.end()) { // Found it.
		DefAddr = (ea_t) MapResult->second;
	}
	return DefAddr;
} // end of SMPFunction::GetGlobalDefAddr()

// Retrieve block iterator for InstAddr from InstBlockMap; assert if failure
list<SMPBasicBlock>::iterator SMPFunction::GetBlockFromInstAddr(ea_t InstAddr) {
	map<ea_t, list<SMPBasicBlock>::iterator>::iterator MapEntry;
	MapEntry = this->InstBlockMap.find(InstAddr);
	assert(MapEntry != this->InstBlockMap.end());
	return MapEntry->second;
}

// Given block # and PhiDef op_t and SSANum, return the Phi iterator or assert.
set<SMPPhiFunction, LessPhi>::iterator SMPFunction::GetPhiIterForPhiDef(size_t BlockNumber, op_t DefOp, int SSANum) {
	list<SMPBasicBlock>::iterator DefBlock = this->RPOBlocks.at(BlockNumber);
	set<SMPPhiFunction, LessPhi>::iterator PhiIter = DefBlock->FindPhi(DefOp);
	assert(PhiIter != DefBlock->GetLastPhi());
	return PhiIter;
}
// Is DestOp within the outgoing args area? Assume it must be an ESP-relative
//  DEF operand in order to be a write to the outgoing args area.
bool SMPFunction::WritesToOutgoingArgs(op_t DestOp) {
	bool OutArgWrite = false;
	int BaseReg, IndexReg;
	ushort ScaleFactor;
	ea_t offset;

	if (this->IsLeaf())
		return false;

	MDExtractAddressFields(DestOp, BaseReg, IndexReg, ScaleFactor, offset);
	if ((BaseReg != R_sp) && (IndexReg != R_sp))
		return false;
	if (((BaseReg == R_sp) && (IndexReg != R_none))
		|| ((IndexReg == R_sp) && (BaseReg != R_none))
		|| (0 < ScaleFactor)) {

		msg("WARNING: WritesToOutgoingArgs called with indexed write.");
		PrintOperand(DestOp);
		return false;
	}

	if (!this->OutgoingArgsComputed) {
		OutArgWrite = true; // be conservative
	}
	else {
		OutArgWrite = (offset < this->OutgoingArgsSize);
	}
	return OutArgWrite;
} // end of SMPFunction::WritesToOutgoingArgs()

// Is DestOp a direct memory access above the local vars frame?
bool SMPFunction::WritesAboveLocalFrame(op_t DestOp) {
	bool InArgWrite = false;
	int BaseReg, IndexReg;
	ushort ScaleFactor;
	ea_t offset;
	long SignedOffset;

	MDExtractAddressFields(DestOp, BaseReg, IndexReg, ScaleFactor, offset);
	SignedOffset = (long) offset;
	bool ESPrelative = (BaseReg == R_sp) || (IndexReg == R_sp);
	bool EBPrelative = this->UseFP && ((BaseReg == R_bp) || (IndexReg == R_bp));
	if (!(ESPrelative || EBPrelative))
		return false;
	if (((IndexReg != R_none) && (BaseReg != R_none))
		|| (0 < ScaleFactor)) {

		msg("WARNING: WritesAboveLocalFrame called with indexed write.");
	InArgWrite = (ESPrelative && (SignedOffset > ((long) this->LocalVarsSize)))
		|| (EBPrelative && (SignedOffset > 0));
}// end of SMPFunction::WritesAboveLocalFrame()

// Is DestOp an indexed write above the local vars frame?
bool SMPFunction::IndexedWritesAboveLocalFrame(op_t DestOp) 
{
	bool InArgWrite = false;
	int BaseReg, IndexReg;
	ushort ScaleFactor;
	ea_t offset;

	MDExtractAddressFields(DestOp, BaseReg, IndexReg, ScaleFactor, offset);
	bool ESPrelative = (BaseReg == R_sp) || (IndexReg == R_sp);
	bool EBPrelative = this->UseFP && ((BaseReg == R_bp) || (IndexReg == R_bp));
	if (!(ESPrelative || EBPrelative))
		return false;

	InArgWrite = (ESPrelative && (offset > this->LocalVarsSize))
		|| (EBPrelative && (offset > 0));

	return InArgWrite;
}	 // end of SMPFunction::IndexedWritesAboveLocalFrame
// Find evidence of calls to alloca(), which appear as stack space allocations (i.e.
//  subtractions from the stack pointer) AFTER the local frame allocation instruction
//  for this function.
// Return true if such an allocation is found and false otherwise.
bool SMPFunction::FindAlloca(void) {
	list<SMPInstr>::iterator CurrInst = this->Instrs.begin();
#if SMP_USE_SSA_FNOP_MARKER
	++CurrInst;  // skip marker instruction
	for ( ; CurrInst != this->Instrs.end(); ++CurrInst) {
		if ((CurrInst->GetAddr() > this->LocalVarsAllocInstr) && CurrInst->MDIsFrameAllocInstr()) {
			return true;
		}
	}
	return false;
} // end of SMPFunction::FindAlloca()

// Emit the annotations describing the regions of the stack frame.
void SMPFunction::EmitStackFrameAnnotations(FILE *AnnotFile, list<SMPInstr>::iterator Instr) {
	ea_t addr = Instr->GetAddr();

#if 0
	if (0 < IncomingArgsSize) {
		qfprintf(AnnotFile, "%10x %6d INARGS STACK esp + %d %s \n",
				addr, IncomingArgsSize,
				(LocalVarsSize + CalleeSavedRegsSize + RetAddrSize),
				Instr->GetDisasm());
		qfprintf(AnnotFile, "%10x %6d MEMORYHOLE STACK esp + %d ReturnAddress \n",
				addr, RetAddrSize, (LocalVarsSize + CalleeSavedRegsSize));
	}
	if (0 < CalleeSavedRegsSize) {
		qfprintf(AnnotFile, "%10x %6d MEMORYHOLE STACK esp + %d CalleeSavedRegs \n",
				addr, CalleeSavedRegsSize, LocalVarsSize);
		unsigned long ParentReferentID = DataReferentID++;
		qfprintf(AnnotFile, "%10x %6d DATAREF STACK %ld esp + %d PARENT LocalFrame LOCALFRAME\n",
				addr, LocalVarsSize, ParentReferentID, 0);
#if SMP_COMPUTE_STACK_GRANULARITY
		if (this->AnalyzedSP && !this->CallsAlloca && (BADADDR != this->LocalVarsAllocInstr)) {
			// We can only fine-grain the stack frame if we were able to analyze the stack
			if (this->OutgoingArgsSize > 0) {
				qfprintf(AnnotFile, "%10x %6d DATAREF STACK %ld esp + %d CHILDOF %ld OFFSET %d OutArgsRegion OUTARGS\n",
					addr, this->OutgoingArgsSize, DataReferentID, 0, ParentReferentID, 0);
				++DataReferentID;
#if SMP_DEBUG_STACK_GRANULARITY
			msg("LocalVarTable of size %d for function %s\n", this->LocalVarTable.size(),
				this->GetFuncName());
			for (size_t i = 0; i < this->LocalVarTable.size(); ++i) {
#if SMP_DEBUG_STACK_GRANULARITY
				msg("Entry %d offset %d size %d name %s\n", i, this->LocalVarTable[i].offset,
					this->LocalVarTable[i].size, this->LocalVarTable[i].VarName);
				// Don't emit annotations for incoming or outgoing args or anything else
				//  above or below the current local frame.
				if ((this->LocalVarTable[i].offset >= (long) this->FuncInfo.frsize)
					|| (this->LocalVarTable[i].offset < (long) this->OutgoingArgsSize))
					continue;
				qfprintf(AnnotFile, "%10x %6d DATAREF STACK %ld esp + %ld CHILDOF %ld OFFSET %ld LOCALVAR %s \n",
					addr, this->LocalVarTable[i].size, DataReferentID,
					this->LocalVarTable[i].offset, ParentReferentID,
					this->LocalVarTable[i].offset, this->LocalVarTable[i].VarName);
				++DataReferentID;
		} // end if (this->AnalyzedSP and not Alloca .... )
	} // end if (0 < LocalVarsSize)
	return;
} // end of SMPFunction::EmitStackFrameAnnotations() 

// Main data flow analysis driver. Goes through the function and
//  fills all objects for instructions, basic blocks, and the function
//  itself.
void SMPFunction::Analyze(void) {
	list<SMPInstr>::iterator FirstInBlock = this->Instrs.end();
	   // For starting a basic block
	list<SMPInstr>::iterator LastInBlock = this->Instrs.end();
	   // Terminating a basic block

#if SMP_DEBUG_CONTROLFLOW
	msg("Entering SMPFunction::Analyze.\n");
#endif

	// Get some basic info from the FuncInfo structure.
	this->Size = this->FuncInfo.endEA - this->FuncInfo.startEA;
	this->UseFP = (0 != (this->FuncInfo.flags & (FUNC_FRAME | FUNC_BOTTOMBP)));
	this->StaticFunc = (0 != (this->FuncInfo.flags & FUNC_STATIC));
	this->LibFunc = (0 != (this->FuncInfo.flags & FUNC_LIB));
	get_func_name(this->FuncInfo.startEA, this->FuncName,
		sizeof(this->FuncName) - 1);
	this->BlockCount = 0;
	this->AnalyzedSP = this->FuncInfo.analyzed_sp();

#if SMP_DEBUG_CONTROLFLOW
	msg("SMPFunction::Analyze: got basic info.\n");
#endif

	// Cycle through all chunks that belong to the function.
	func_tail_iterator_t FuncTail(this->GetFuncInfo());
	size_t ChunkCounter = 0;
	for (bool ChunkOK = FuncTail.main(); ChunkOK; ChunkOK = FuncTail.next()) {
		const area_t &CurrChunk = FuncTail.chunk();
		++ChunkCounter;
		if (1 < ChunkCounter) {
			this->SharedChunks = true;
#if SMP_DEBUG_CHUNKS
			msg("Found tail chunk for %s at %x\n", this->FuncName, CurrChunk.startEA);
#endif
		}
		// Build the instruction and block lists for the function.
		for (ea_t addr = CurrChunk.startEA; addr < CurrChunk.endEA;
			addr = get_item_end(addr)) {
			flags_t InstrFlags = getFlags(addr);
			if (isHead(InstrFlags) && isCode(InstrFlags)) {
				SMPInstr CurrInst = SMPInstr(addr);
				// Fill in the instruction data members.
#if SMP_DEBUG_CONTROLFLOW
				msg("SMPFunction::Analyze: calling CurrInst::Analyze.\n");
#endif
				CurrInst.Analyze();
				if (SMPBinaryDebug) {
					msg("Disasm:  %s \n", CurrInst.GetDisasm());
				}
#if SMP_USE_SSA_FNOP_MARKER
				if (this->Instrs.empty()) {
					// First instruction in function. We want to create a pseudo-instruction
					//  at the top of the function that can hold SSA DEFs for LiveIn names
					//  to the function. We use a floating point no-op as the pseudo-inst.
					//  The code address is one less than the start address of the function.
					SMPInstr MarkerInst = SMPInstr(addr - 1);
					MarkerInst.AnalyzeMarker();
					assert(FirstInBlock == this->Instrs.end());
					this->Instrs.push_back(MarkerInst);
				}
#endif
				if (this->AnalyzedSP) {
					// Audit the IDA SP analysis.
					sval_t sp_delta = get_spd(this->GetFuncInfo(), addr);
					// sp_delta is difference between current value of stack pointer
					//  and value of the stack pointer coming into the function. It
					//  is updated AFTER each instruction. Thus, it should not get back
					//  above zero (e.g. to +4) until after a return instruction.
					if (sp_delta > 0) {
						// Stack pointer has underflowed, according to IDA's analysis,
						//  which is probably incorrect.
						this->AnalyzedSP = false;
						msg("Resetting AnalyzedSP to false for %s\n", this->GetFuncName());
						msg("Underflowing instruction: %s sp_delta: %d\n", CurrInst.GetDisasm(),
							sp_delta);
					}
					else if (sp_delta == 0) {
						// Search for tail calls.
						if (CurrInst.IsBranchToFarChunk()) {
							// After the stack has been restored to the point at which
							//  we are ready to return, we instead find a jump to a
							//  far chunk. This is the classic tail call optimization:
							//  the return statement has been replaced with a jump to
							//  another function, which will return not to this function,
							//  but to the caller of this function.
							CurrInst.SetTailCall();
							msg("Found tail call at %x from %s: %s\n", addr, this->GetFuncName(),
								CurrInst.GetDisasm());
						}
					}
				// Find all functions that call the current function.
				xrefblk_t CurrXrefs;
				if (!FoundAllCallers) {
					for (bool ok = CurrXrefs.first_to(CurrInst.GetAddr(), XREF_ALL);
						ok;
						ok = CurrXrefs.next_to()) {
						if ((CurrXrefs.from != 0) && (CurrXrefs.iscode)) {
							// Make sure it is not a fall-through. Must be a
							//  control-flow instruction of some sort, including
							//  direct or indirect calls or tail calls.
							SMPInstr CallInst(CurrXrefs.from);
							CallInst.Analyze();
							SMPitype CallType = CallInst.GetDataFlowType();
							if ((COND_BRANCH <= CallType) && (RETURN >= CallType)) {
								// Found a caller, with its call address in CurrXrefs.from
								this->AddCallSource(CurrXrefs.from);
							}