Skip to content
Snippets Groups Projects
SMPFunction.cpp 258 KiB
Newer Older
							//  where the ESP-8 refers to the value of ESP upon entry to the function, not its current value.
							//  This normalization makes each stack location uniquely named (no aliases at different code locations due
							//  to different values of ESP at different code locations).
							CurrBlock->AddVarKill(DefOp);
							CurrBlock->UpdateDownExposedDefs(DefOp, InstAddr);
				}

				if (SavedDeltaHasNewValue) {
					IncomingDelta = SavedDelta; // from restore instruction
				}
				else {
					CurrentDelta = CurrInst->AnalyzeStackPointerDelta(IncomingDelta, this->GetFramePtrStackDelta());
					if (SMP_STACK_POINTER_BITWISE_AND_CODE == CurrentDelta) {
						// For now, we ignore instructions that AND a constant into the stack pointer.
						CurrentDelta = 0;
						SMP_msg("WARNING: Stack pointer bitwise AND ignored at %x\n", CurrInst->GetAddr());
					}
					else if (SMP_STACK_DELTA_ERROR_CODE == CurrentDelta) {
						this->AnalyzedSP = false;
						SMP_msg("ERROR: Stack delta unanalyzeable at %x\n", InstAddr);
						WorkList.clear();
						break;
					}
					SMPitype FlowType = CurrInst->GetDataFlowType();
					// Search for tail calls, defined strictly as having an incoming stack delta of zero and
					//  being jumps to far chunks.
					if ((0 == IncomingDelta) && (CurrInst->IsBranchToFarChunk())) {
						CurrInst->SetTailCall();
						SMP_msg("Found tail call at %x from %s: %s\n", InstAddr, this->GetFuncName(),
								CurrInst->GetDisasm());
					}
					IncomingDelta += CurrentDelta;
					if ((RETURN == FlowType) && (!CurrInst->IsCondTailCall())) {
						// We hope to see a consistent outgoing delta from all RETURN points.
						//  We special-case the conditional jump used as tail call, because it must be followed
						//  by a real return instruction later. If the jump is taken, it acts as a return, but
						//  it has not yet popped the stack.
						if (ReturnSeen) { // This is not the first RETURN seen.
							if (IncomingDelta != this->NetStackDelta) { // Inconsistent
								SMP_msg("ERROR: Inconsistent stack deltas at return instruction at %x\n", CurrInst->GetAddr());
								ConsistentNetDelta = false;
								this->AnalyzedSP = false;
								WorkList.clear();
								break;
							}
						}
						else { // First RETURN statement seen.
							ReturnSeen = true;
							this->NetStackDelta = IncomingDelta;
	#if SMP_AUDIT_STACK_POINTER_DELTAS
							if (0 != IncomingDelta) {
								SMP_msg("WARNING: Stack delta not zero after return instruction at %x\n", CurrInst->GetAddr());
							}
	#endif
				} // end if (SavedDeltaHasNewValue) ... else ...
			} // end for each instruction in WorkList block
			if (!ReprocessingAllocaBlocks) {
				ReachesOutChanged = CurrBlock->ComputeReachesOutSet();
			// Push the successor blocks onto the work list if anything changed
			if (this->AnalyzedSP) { // if we do not have an error already
				CurrBlock->SetOutgoingStackDelta(IncomingDelta); // record incoming delta for all successors
				if (ReachesOutChanged || (!ReprocessingAllocaBlocks)) { // if anything changed (deltas or reaching defs ReachOut set)
					list<SMPBasicBlock *>::iterator SuccIter;
					for (SuccIter = CurrBlock->GetFirstSucc(); SuccIter != CurrBlock->GetLastSucc(); ++SuccIter) {
						pair<SMPBasicBlock *, sval_t> SuccPair (*SuccIter, IncomingDelta);
						WorkList.push_back(SuccPair);
					}
		} // end if block already processed ... else ...
		ReprocessingAllocaBlocks = false; // reset to default before processing next worklist element
	} while (!WorkList.empty());

	this->STARSStackPtrAnalysisPerformed = true;
	if (this->AnalyzedSP && (CALLING_CONVENTION_DEFAULT_FUNCTION_STACK_DELTA != this->NetStackDelta)) {
		SMP_msg("WARNING: Non-default stack ptr delta %d for function: %s\n", this->NetStackDelta, this->GetFuncName());
	}

	if (IDAProSucceeded) {
		if (!this->AnalyzedSP) {
			SMP_msg("ERROR: Stack Ptr Delta Analysis succeeded in IDA, failed in STARS for %x : %s\n", this->FirstEA,
				this->GetFuncName());
		}
	}
	else {
		if (this->AnalyzedSP) {
			SMP_msg("SUCCESS: Stack Ptr Delta Analysis failed in IDA, succeeded in STARS for %x : %s\n", this->FirstEA,
				this->GetFuncName());
		}
	}
	return this->AnalyzedSP;
} // end of SMPFunction::AnalyzeStackPointerDeltas()

// Insert the arguments into the StackPtrCopySet; or, if a matching entry already exists
//  with a StackDelta of greater magnitude than StackDelta, update just the StackDelta.
// Return true if StackDelta was inserted, false if it was used to update an old entry.
bool SMPFunction::AddToStackPtrCopySet(op_t CopyOp, ea_t InstAddr, sval_t StackDelta) {
	bool NewInsertion;
	pair<ea_t, sval_t> InsertStackDefn(InstAddr, StackDelta);
	pair<op_t, pair<ea_t, sval_t> > InsertStackDefnOp(CopyOp, InsertStackDefn);
	set<pair<op_t, pair<ea_t, sval_t> >, LessStackDeltaCopy>::iterator FindIter;
	pair<set<pair<op_t, pair<ea_t, sval_t> >, LessStackDeltaCopy>::iterator, bool> InsertResult;

	FindIter = this->StackPtrCopySet.find(InsertStackDefnOp);
	if (FindIter == this->StackPtrCopySet.end()) {
		// Not already present; insert new triple.
		NewInsertion = true;
		InsertResult = this->StackPtrCopySet.insert(InsertStackDefnOp);
		assert(InsertResult.second);
	}
	else {
		// Already there; see if delta needs to be updated.
		NewInsertion = false;
		pair<op_t, pair<ea_t, sval_t> > OldStackDefnOp(*FindIter);
		// Favor a smaller stack frame for the alloca-calling functions, e.g. favor -24 over -32 as a delta.
		if (StackDelta > OldStackDefnOp.second.second) {
			// Replace the old entry with a new one.
			this->StackPtrCopySet.erase(FindIter);
			InsertResult = this->StackPtrCopySet.insert(InsertStackDefnOp);
			assert(InsertResult.second);
		}
	}

	return NewInsertion;
} // end of SMPFunction::AddToStackPtrCopySet()

void SMPFunction::FindAllAllocsAndDeallocs(void) {
	bool FoundAllocInstr = false;
	bool FoundDeallocInstr = false;
clc5q's avatar
clc5q committed
	bool DebugFlag = false;
#if SMP_DEBUG_FRAMEFIXUP
	DebugFlag |= (0 == strcmp("frame_dummy", this->GetFuncName()));
#endif

	// Now, if LocalVarsSize is not zero, we need to find the instruction
	//  in the function prologue that allocates space on the stack for
	//  local vars. This code could be made more robust in the future
	//  by matching LocalVarsSize to the immediate value in the allocation
	//  instruction. However, IDA Pro is sometimes a little off on this
	//  number. **!!**
	if (0 < this->LocalVarsSize) {
		if (DebugFlag) SMP_msg("Searching for alloc and dealloc\n");
		list<SMPInstr *>::iterator InstIter = this->Instrs.begin();
#if SMP_USE_SSA_FNOP_MARKER
		++InstIter;  // skip marker instruction
		for ( ; InstIter != this->Instrs.end(); ++InstIter) {
			SMPInstr *CurrInst = (*InstIter);
			ea_t addr = CurrInst->GetAddr();

			// Keep the most recent instruction in the DeallocInstr
			//  in case we reach the return without seeing a dealloc.
			if (!FoundDeallocInstr) {
				this->LocalVarsDeallocInstr = addr;
			}

			if (!FoundAllocInstr
				&& CurrInst->MDIsFrameAllocInstr()) {
#if SMP_DEBUG_CONTROLFLOW
				SMP_msg("Returned from MDIsFrameAllocInstr()\n");
				this->LocalVarsAllocInstr = addr;
				FoundAllocInstr = true;
				if (DebugFlag) SMP_msg("Found alloc: %s\n", CurrInst->GetDisasm());
				// As soon as we have found the local vars allocation,
				//  we can try to fix incorrect sets of UseFP by IDA.
				// NOTE: We might want to extend this in the future to
				//  handle functions that have no locals.  **!!**
				bool FixedUseFP = MDFixUseFP();
#if SMP_DEBUG_CONTROLFLOW
#if SMP_DEBUG_FRAMEFIXUP
				if (FixedUseFP) {
					SMP_msg("Fixed UseFP in %s\n", this->GetFuncName());
				}
#endif
			}
			else if (FoundAllocInstr) {
				// We can now start searching for the DeallocInstr.
				if (CurrInst->MDIsFrameDeallocInstr(UseFP, this->LocalVarsSize)) {
					// Keep saving the most recent addr that looks
					//  like the DeallocInstr until we reach the
					//  end of the function. Last one to look like
					//  it is used as the DeallocInstr.
#if SMP_DEBUG_CONTROLFLOW
					SMP_msg("Returned from MDIsFrameDeallocInstr()\n");
					this->LocalVarsDeallocInstr = addr;
					FoundDeallocInstr = true;
				}
					if (DebugFlag) SMP_msg("Not dealloc: %s\n", CurrInst->GetDisasm());
		} // end for (list<SMPInstr *>::iterator InstIter ... )
		if (!FoundAllocInstr) {
			// Could not find the frame allocating instruction.  Bad.
			// See if we can find the point at which the stack allocation reaches
			//  a total of FuncInfo.frsize+frregs, regardless of whether it happened by push
			//  instructions or some other means.
			this->LocalVarsAllocInstr = this->FindAllocPoint(this->FuncInfo.frsize + this->FuncInfo.frregs);
#if SMP_DEBUG_CONTROLFLOW
			SMP_msg("Returned from FindAllocPoint()\n");
#if SMP_DEBUG_FRAMEFIXUP
			if (BADADDR == this->LocalVarsAllocInstr) {
				SMP_msg("ERROR: Could not find stack frame allocation in %s\n",
					this->GetFuncName());
				SMP_msg("LocalVarsSize: %d  SavedRegsSize: %d ArgsSize: %d\n",
					LocalVarsSize, CalleeSavedRegsSize, IncomingArgsSize);
			}
			else {
				SMP_msg("FindAllocPoint found %x for function %s\n",
					this->LocalVarsAllocInstr, this->GetFuncName());
			}
#endif
		}
#if SMP_DEBUG_FRAMEFIXUP
		if (!FoundDeallocInstr) {
			// Could not find the frame deallocating instruction.  Bad.
			// Emit diagnostic and use the last instruction in the
			// function.
			SMP_msg("ERROR: Could not find stack frame deallocation in %s\n",
				this->GetFuncName());
		}
#endif
	}
	// else LocalVarsSize was zero, meaning that we need to search 
	//  for the end of the function prologue code and emit stack frame
	//  annotations from that address (i.e. this method returns that
	//  address). We will approximate this by finding the end of the
	//  sequence of PUSH instructions at the beginning of the function.
	//  The last PUSH instruction should be the last callee-save-reg
	//  instruction. We can make this more robust in the future by
	//  making sure that we do not count a PUSH of anything other than
	//  a register. **!!**
	// NOTE: 2nd prologue instr is usually mov ebp,esp
	// THE ASSUMPTION THAT WE HAVE ONLY PUSH INSTRUCTIONS BEFORE
	// THE ALLOCATING INSTR IS ONLY TRUE WHEN LOCALVARSSIZE == 0;
	else {
		ea_t SaveAddr = this->FuncInfo.startEA;
		list<SMPInstr *>::iterator InstIter = this->Instrs.begin();
#if SMP_USE_SSA_FNOP_MARKER
		++InstIter;  // skip marker instruction
		for ( ;	InstIter != this->Instrs.end(); ++InstIter) {
			SMPInstr *CurrInst = (*InstIter);
			insn_t CurrCmd = CurrInst->GetCmd();
			ea_t addr = CurrInst->GetAddr();
			if (CurrCmd.itype == NN_push)
				SaveAddr = addr;
			else
				break;
		}
		this->LocalVarsAllocInstr = SaveAddr;
		this->LocalVarsDeallocInstr = 0;
	} // end if (LocalVarsSize > 0) ... else ...

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

// Figure out the different regions of the stack frame, and find the
//  instructions that allocate and deallocate the local variables space
//  on the stack frame.
// The stack frame info will be used to emit stack
//  annotations when Analyze() reaches the stack allocation
//  instruction that sets aside space for local vars.
// Set the address of the instruction at which these
//  annotations should be emitted. This should normally
//  be an instruction such as:  sub esp,48
//  However, for a function with no local variables at all,
//  we will need to determine which instruction should be
//  considered to be the final instruction of the function
//  prologue and return its address.
// Likewise, we find the stack deallocating instruction in
//  the function epilogue.
void SMPFunction::SetStackFrameInfo(void) {
clc5q's avatar
clc5q committed
#if 0
	for (list<SMPInstr *>::iterator InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) {
		// We can finally search for stack loads now that UseFP has been fixed by
		//  MDFixUseFP(). Otherwise, we would do this in SMPInstr::Analyze(),
		//  but the UseFP flag is not ready that early.
		(*InstIter)->MDFindLoadFromStack(this->UseFP);

		// Fix up machine dependent quirks in the def and use lists.
		//  This used to be called from within SMPInstr.Analyze(), but info such as UseFP
		//  is not available that early.
		(*InstIter)->MDFixupDefUseLists();
clc5q's avatar
clc5q committed
#endif
#if SMP_COMPUTE_STACK_GRANULARITY
	// Now, find the boundaries between local variables.
	this->BuildLocalVarTable();
#endif

	// Get callee-saved regs info for remediation use.
	if (BADADDR != this->GetFirstFrameAllocInstAddr()) {
	return;
} // end of SMPFunction::SetStackFrameInfo()

// IDA Pro defines the sizes of regions in the stack frame in a way
//  that suits its purposes but not ours. The frsize field of the func_info_t
//  structure measures the distance between the stack pointer and the
//  frame pointer (ESP and EBP in the x86). This region includes some
//  of the callee-saved registers. So, the frregs field only includes
//  the callee-saved registers that are above the frame pointer.
//  x86 standard prologue on gcc/linux:
//    push ebp      ; save old frame pointer
//    mov ebp,esp   ; new frame pointer = current stack pointer
//    push esi      ; callee save reg
//    push edi      ; callee save reg
//    sub esp,34h   ; allocate 52 bytes for local variables
//
//  Notice that EBP acquires its final frame pointer value AFTER the
//  old EBP has been pushed. This means that, of the three callee saved
//  registers, one is above where EBP points and two are below.
//  IDA Pro is concerned with generating readable addressing expressions
//  for items on the stack. None of the callee-saved regs will ever
//  be addressed in the function; they will be dormant until they are popped
//  off the stack in the function epilogue. In order to create readable
//  disassembled code, IDA defines named constant offsets for locals. These
//  offsets are negative values (x86 stack grows downward from EBP toward
//  ESP). When ESP_relative addressing occurs, IDA converts a statement:
//    mov eax,[esp+12]
//  into the statement:
//    mov eax,[esp+3Ch+var_30]
//  Here, 3Ch == 60 decimal is the distance between ESP and EBP, and
//  var_30 is defined to have the value -30h == -48 decimal. So, the
//  "frame size" in IDA Pro is 60 bytes, and a certain local can be
//  addressed in ESP-relative manner as shown, or as [ebp+var_30] for
//  EBP-relative addressing. The interactive IDA user can then edit
//  the name var_30 to something mnemonic, such as "virus_size", and IDA
//  will replace all occurrences with the new name, so that code references
//  automatically become [ebp+virus_size]. As the user proceeds
//  interactively, he eventually produces very understandable code.
// This all makes sense for producing readable assembly text. However,
//  our analyses have a compiler perspective as well as a memory access
//  defense perspective. SMP distinguishes between callee saved regs,
//  which should not be overwritten in the function body, and local
//  variables, which can be written. We view the stack frame in logical
//  pieces: here are the saved regs, here are the locals, here is the
//  return address, etc. We don't care which direction from EBP the
//  callee-saved registers lie; we don't want to lump them in with the
//  local variables. We also don't like the fact that IDA Pro will take
//  the function prologue code shown above and declare frregs=4 and
//  frsize=60, because frsize no longer matches the stack allocation
//  statement sub esp,34h == sub esp,52. We prefer frsize=52 and frregs=12.
// So, the task of this function is to fix these stack sizes in our
//  private data members for the function, while leaving the IDA database
//  alone because IDA needs to maintain its own definitions of these
//  variables.
// Fixing means we will update the data members LocalVarsSize and
//  CalleeSavedRegsSize.
// NOTE: This function is both machine dependent and platform dependent.
//  The prologue and epilogue code generated by gcc-linux is as discussed
//  above, while on Visual Studio and other Windows x86 compilers, the
//  saving of registers other than EBP happens AFTER local stack allocation.
//  A Windows version of the function would expect to see the pushing
//  of ESI and EDI AFTER the sub esp,34h statement.
bool SMPFunction::MDFixFrameInfo(void) {
	int SavedRegsSize = 0;
	int OtherPushesSize = 0;  // besides callee-saved regs
	int NewLocalsSize = 0;
	int OldFrameTotal = this->CalleeSavedRegsSize + this->LocalVarsSize;
	bool Changed = false;
	bool DebugFlag = (0 == strcmp("__libc_csu_init", this->GetFuncName()));

	// Iterate through the first basic block in the function. If we find
	//  a frame allocating Instr in it, then we have local vars. If not,
	//  we don't, and LocalVarsSize should have been zero. Count the callee
	//  register saves leading up to the local allocation. Set data members
	//  according to what we found if the values of the data members would
	//  change.
	SMPBasicBlock *CurrBlock = this->Blocks.front();
	list<SMPInstr *>::iterator CurrIter = CurrBlock->GetFirstInstr();
#if SMP_USE_SSA_FNOP_MARKER
	++CurrIter;  // skip marker instruction
	for ( ; CurrIter != CurrBlock->GetLastInstr(); ++CurrIter) {
		SMPInstr *CurrInstr = (*CurrIter);
		if (CurrInstr->MDIsPushInstr()) {
			// We will make the gcc-linux assumption that a PUSH in
			//  the first basic block, prior to the stack allocating
			//  instruction, is a callee register save. To make this
			//  more robust, we ensure that the register is from
			//  the callee saved group of registers, and that it has
			//  not been defined thus far in the function (else it might
			//  be a push of an outgoing argument to a call that happens
			//  in the first block when there are no locals). **!!!!**
			if (CurrInstr->MDUsesCalleeSavedReg()
				&& !CurrInstr->HasSourceMemoryOperand()) {
				SavedRegsSize += 4; // **!!** should check the size
				if (DebugFlag) SMP_msg("libc_csu_init SavedRegsSize: %d  %s\n", SavedRegsSize,
					CurrInstr->GetDisasm());
			}
			else {
				// Pushes of outgoing args can be scheduled so that
				//  they are mixed with the pushes of callee saved regs.
				OtherPushesSize += 4;
				if (DebugFlag) SMP_msg("libc_csu_init OtherPushesSize: %d  %s\n", OtherPushesSize,
					CurrInstr->GetDisasm());
			}
		}
		else if (CurrInstr->MDIsFrameAllocInstr()) {
			if (DebugFlag) SMP_msg("libc_csu_init allocinstr: %s\n", CurrInstr->GetDisasm());
			SavedRegsSize += OtherPushesSize;
			// Get the size being allocated.
			set<DefOrUse, LessDefUse>::iterator CurrUse;
			for (CurrUse = CurrInstr->GetFirstUse(); CurrUse != CurrInstr->GetLastUse(); ++CurrUse) {
				// Find the immediate operand.
				if (o_imm == CurrUse->GetOp().type) {
					// Get its value into LocalVarsSize.
					long AllocValue = (signed long) CurrUse->GetOp().value;
					// One compiler might have sub esp,24 and another
					//  might have add esp,-24. Take the absolute value.
					if (0 > AllocValue)
						AllocValue = -AllocValue;
					if (AllocValue != (long) this->LocalVarsSize) {
						Changed = true;
#if SMP_DEBUG_FRAMEFIXUP
						if (AllocValue + SavedRegsSize != OldFrameTotal)
							SMP_msg("Total frame size changed: %s\n", this->GetFuncName());
#endif
						this->LocalVarsSize = (asize_t) AllocValue;
						this->CalleeSavedRegsSize = (ushort) SavedRegsSize;
						NewLocalsSize = this->LocalVarsSize;
					}
					else { // Old value was correct; no change.
						NewLocalsSize = this->LocalVarsSize;
						if (SavedRegsSize != this->CalleeSavedRegsSize) {
							this->CalleeSavedRegsSize = (ushort) SavedRegsSize;
							Changed = true;
#if SMP_DEBUG_FRAMEFIXUP
							SMP_msg("Only callee regs size changed: %s\n", this->GetFuncName());
#endif
						}
					}
				} // end if (o_imm == ...)
			} // end for all uses
			break; // After frame allocation instr, we are done
		} // end if (push) .. elsif frame allocating instr
	} // end for all instructions in the first basic block

	// If we did not find an allocating instruction, see if it would keep
	//  the total size the same to set LocalVarsSize to 0 and to set
	//  CalleeSavedRegsSize to SavedRegsSize. If so, do it. If not, we
	//  might be better off to leave the numbers alone.
	if (!Changed && (NewLocalsSize == 0)) {
		if (DebugFlag) SMP_msg("libc_csu_init OldFrameTotal: %d \n", OldFrameTotal);
		if (OldFrameTotal == SavedRegsSize) {
clc5q's avatar
clc5q committed
			this->CalleeSavedRegsSize = (ushort) SavedRegsSize;
			this->LocalVarsSize = 0;
			Changed = true;
		}
#if SMP_DEBUG_FRAMEFIXUP
		else {
			SMP_msg("Could not update frame sizes: %s\n", this->GetFuncName());
		}
#endif
	}

#if SMP_DEBUG_FRAMEFIXUP
	if ((0 < OtherPushesSize) && (0 < NewLocalsSize))
		SMP_msg("Extra pushes found of size %d in %s\n", OtherPushesSize,
			this->GetFuncName());
#if SMP_DEBUG_FRAMEFIXUP
	if (Changed) {
		SMP_msg("Fixed stack frame size info: %s\n", this->GetFuncName());
		SMPBasicBlock *CurrBlock = this->Blocks.front();
		SMP_msg("First basic block:\n");
		for (list<SMPInstr *>::iterator CurrInstr = CurrBlock->GetFirstInstr();
			CurrInstr != CurrBlock->GetLastInstr();
			++CurrInstr) {
			SMP_msg("%s\n", (*CurrInstr)->GetDisasm());
		}
	}
#endif

	return Changed;
} // end of SMPFunction::MDFixFrameInfo()

// Some functions have difficult to find stack allocations. For example, in some
//  version of glibc, strpbrk() zeroes out register ECX and then pushes it more than
//  100 times in order to allocate zero-ed out local vars space for a character translation
//  table. We will use the stack pointer analysis of IDA to find out if there is a point
//  in the first basic block at which the stack pointer reaches the allocation total
//  that IDA is expecting for the local vars region.
// If so, we return the address of the instruction at which ESP reaches its value, else
//  we return BADADDR.
ea_t SMPFunction::FindAllocPoint(asize_t OriginalLocSize) {
	sval_t TargetSize = - ((sval_t) OriginalLocSize);  // negate; stack grows down 

#if SMP_DEBUG_FRAMEFIXUP
	bool DebugFlag = (0 == strcmp("_dl_runtime_resolve", this->GetFuncName()));
		SMP_msg("%s OriginalLocSize: %d\n", this->GetFuncName(), OriginalLocSize);
	if (this->AnalyzedSP) {
		// Limit our analysis to the first basic block in the function.
		list<SMPInstr *>::iterator InstIter = this->Instrs.begin();
#if SMP_USE_SSA_FNOP_MARKER
		++InstIter;  // skip marker instruction
		for ( ; InstIter != this->Instrs.end(); ++InstIter) {
			SMPInstr *CurrInst = (*InstIter);
			ea_t addr = CurrInst->GetAddr();
			// get_spd() returns a cumulative delta of ESP
			sval_t sp_delta = get_spd(this->GetFuncInfo(), addr);
#if SMP_DEBUG_FRAMEFIXUP
				SMP_msg("%s delta: %d at %x\n", this->GetFuncName(), sp_delta, addr);
			if (sp_delta == TargetSize) { // <= instead of == here?  **!!**
				// Previous instruction hit the frame size.
				if (InstIter == this->Instrs.begin()) {
					return BADADDR;  // cannot back up from first instruction
				}
				else {
					ea_t PrevAddr = (*(--InstIter))->GetAddr();
#if SMP_USE_SSA_FNOP_MARKER
					if ((*(this->Instrs.begin()))->GetAddr() == PrevAddr)
						return BADADDR;  // don't return marker instruction
					else
						return PrevAddr;
#else
					return PrevAddr;
#endif
			if (CurrInst->IsLastInBlock()) {
				// It could be that the current instruction will cause the stack pointer
				//  delta to reach the TargetSize. sp_delta is not updated until after the
				//  current instruction, so we need to look ahead one instruction if the
				//  current block falls through. On the other hand, if the current block
				//  ends with a jump or return, we cannot hit TargetSize.
				if (CurrInst->IsBasicBlockTerminator())
				list<SMPInstr *>::iterator NextInstIter = InstIter;
				++NextInstIter;
				if (NextInstIter == this->Instrs.end())
				sp_delta = get_spd(this->GetFuncInfo(), (*NextInstIter)->GetAddr());
				if (sp_delta == TargetSize) {
					// CurrInst will cause stack pointer delta to hit TargetSize.
					return addr;
				}
				else {
					return BADADDR;
				}
			} // end if LastInBlock
		} // end for all instructions
	} // end if (this->AnalyzedSP)
#if SMP_DEBUG_FRAMEFIXUP
	else {
		SMP_msg("AnalyzedSP is false for %s\n", this->GetFuncName());
	}
#endif
	return BADADDR;
} // end of SMPFunction::FindAllocPoint()

// IDA Pro is sometimes confused by a function that uses the frame pointer
//  register for other purposes. For the x86, a function that uses EBP
//  as a frame pointer would begin with: push ebp; mov ebp,esp to save
//  the old value of EBP and give it a new value as a frame pointer. The
//  allocation of local variable space would have to come AFTER the move
//  instruction. A function that begins: push ebp; push esi; sub esp,24
//  is obviously not using EBP as a frame pointer. IDA is apparently
//  confused by the push ebp instruction being the first instruction
//  in the function. We will reset UseFP to false in this case.
// The inverse problem happens with a function that begins with instructions
//  other than push ebp; mov ebp,esp; ... etc. but eventually has those
//  instructions in the first basic block. For example, a C compiler generates
//  for the first block of main():
//    lea ecx,[esp+arg0]
//    and esp, 0xfffffff0
//    push dword ptr [ecx-4]
//    push ebp
//    mov ebp,esp
//    push ecx
//    sub esp,<framesize>
//
//  This function is obviously using EBP as a frame pointer, but IDA Pro marks
//  the function as not using a frame pointer. We will reset UseFP to true in
//  this case.
// NOTE: This logic should work for both Linux and Windows x86 prologues.
bool SMPFunction::MDFixUseFP(void) {
	list<SMPInstr *>::iterator InstIter = this->Instrs.begin();
	ea_t addr = (*InstIter)->GetAddr();

#if SMP_USE_SSA_FNOP_MARKER
	++InstIter;  // skip marker instruction
	SMPInstr *CurrInst = (*InstIter);
	if (!(this->UseFP)) {
		// See if we can detect the instruction "push ebp" followed by the instruction
		//  "mov ebp,esp" in the first basic block. The instructions do not have to be
		//  consecutive. If we find them, we will reset UseFP to true.
		bool FirstBlockProcessed = false;
		bool EBPSaved = false;
		bool ESPintoEBP = false;
		do {
			FirstBlockProcessed = CurrInst->IsLastInBlock();
			if (!EBPSaved) { // still looking for "push ebp"
				if (CurrInst->MDIsPushInstr() && CurrInst->GetCmd().Operands[0].is_reg(R_bp)) {
					EBPSaved = true;
				}
			}
			else if (!ESPintoEBP) { // 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))) {
					ESPintoEBP = true;
					FirstBlockProcessed = true; // exit loop
				}
			}
			++InstIter;
			CurrInst = (*InstIter);
			addr = CurrInst->GetAddr();
			// We must get EBP set to its frame pointer value before we reach the
			//  local frame allocation instruction (i.e. the subtraction of locals space
			//   from the stack pointer).
			FirstBlockProcessed |= (addr >= this->LocalVarsAllocInstr);
		} while (!FirstBlockProcessed);
		// If we found ESPintoEBP, we also found EBPSaved first, and we need to change
		//  this->UseFP to true and return true. Otherwise, return false.
		this->UseFP = ESPintoEBP;
			SMP_msg("INFO: MDFixUseFP reset UseFP to true for %s\n", this->GetFuncName());
		return ESPintoEBP;
	} // end if (!(this->UseFP))

	// At this point, this->UseFP must have been true on entry to this method and we will
	//  check whether it should be reset to false.
	while (addr < this->LocalVarsAllocInstr) {
		set<DefOrUse, LessDefUse>::iterator CurrDef = CurrInst->GetFirstDef();
		while (CurrDef != CurrInst->GetLastDef()) {
			if (CurrDef->GetOp().is_reg(R_bp))
				return false; // EBP got set before locals were allocated
		++InstIter;
		CurrInst = (*InstIter);
		addr = CurrInst->GetAddr();
	}
	// If we found no defs of the frame pointer before the local vars
	//  allocation, then the frame pointer register is not being used
	//  as a frame pointer, just as a general callee-saved register.
	this->UseFP = false;
	SMP_msg("INFO: 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 InstIter;
	func_t *CurrFunc = SMP_get_func(this->GetStartAddr());
	for (InstIter = this->Instrs.begin(); InstIter != this->Instrs.end(); ++InstIter) {
		SMPInstr *CurrInst = (*InstIter);
		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) {
					SMP_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 {
					SMP_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 BlockIter;
	SMPBasicBlock *CurrBlock;
	list<SMPInstr *>::iterator InstIter;
	vector<SMPOperandType> RegTypes;
	for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
		CurrBlock = (*BlockIter);
		if (CurrBlock->HasReturn()) {
			// Get the types of all registers at the RETURN point.
			//  Calculate the meet function over them.
			InstIter = CurrBlock->GetLastInstr();
			--InstIter;
			CurrInst = (*InstIter);
			assert(RETURN == CurrInst->GetDataFlowType());
			set<DefOrUse, LessDefUse>::iterator CurrUse;
			for (CurrUse = CurrInst->GetFirstUse();
				CurrUse != CurrInst->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()

// Limit damage from garbage stack offset values produced by IDA Pro.
#define IDAPRO_KLUDGE_STACK_FRAME_SIZE_LIMIT 5000000

// 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.
	list<SMPInstr *>::iterator InstIter;
	this->LocalVarOffsetLimit = -20000;
#if SMP_DEBUG_STACK_GRANULARITY
	DebugFlag |= (0 == strcmp("qSort3", this->GetFuncName()));
#endif
	func_t *FuncPtr = SMP_get_func(this->FuncInfo.startEA);
		SMP_msg("ERROR in SMPFunction::SemiNaiveLocalVarID; no func ptr\n");
	}
	assert(NULL != FuncPtr);
	struc_t *StackFrame = get_frame(FuncPtr);

	if (NULL == StackFrame) {
		SMP_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'};
			SMP_msg("NULL stack frame member pointer in %s\n", this->GetFuncName());
		get_member_name(Member->id, MemberName, MAXSMPVARSTR - 1);
#if SMP_DEBUG_STACK_GRANULARITY
			SMP_msg("NULL stack frame member in %s\n", this->GetFuncName());
		if (Member->unimem()) {
			// Not a separate variable; name for member of a union.
			// The union itself should have a separate entry, so we skip this.
			SMP_msg("STACK INFO: Skipping union member %s frame member %zu in stack frame for %s\n",
				MemberName, i, this->GetFuncName());
			continue;
		}
		offset = (long) Member->get_soff(); // Would be 0 for union member, so we skipped them above.
			SMP_msg("%s local var %s at offset %ld\n", this->GetFuncName(), MemberName, offset);
		if (offset > IDAPRO_KLUDGE_STACK_FRAME_SIZE_LIMIT) {
			SMP_msg("ERROR: Rejected enormous stack offset %ld for var %s in func %s\n", offset, MemberName, this->GetFuncName());
			continue;
		}
		struct LocalVar TempLocal;
		TempLocal.offset = offset;
		TempLocal.size = Member->eoff - Member->soff; // audit later
		SMP_strncpy(TempLocal.VarName, MemberName, sizeof(TempLocal.VarName) - 1);
		this->LocalVarTable.push_back(TempLocal);
		if ((offset + (long) TempLocal.size) >= this->LocalVarOffsetLimit) {
			this->LocalVarOffsetLimit = (long) (TempLocal.offset + TempLocal.size);
	} // end for all stack frame members
	// If AnalyzedSP is false, that is all we can do.
	if (!this->AnalyzedSP) {
		// No allocations; sometimes happens in library functions.
		this->OutgoingArgsSize = 0;
		this->MinStackDelta = 0;
		this->AllocPointDelta = 0;
		return;
	}

	// Calculate min and max stack point deltas.
	this->MinStackDelta = 20000; // Final value should be negative or zero
	this->MaxStackDelta = -1000; // Final value should be zero.
	InstIter = this->Instrs.begin();
#if SMP_USE_SSA_FNOP_MARKER
	if ((*InstIter)->IsFloatNop())
		++InstIter;  // skip marker instruction
	for ( ; InstIter != this->Instrs.end(); ++InstIter) {
		SMPInstr *CurrInst = (*InstIter);
		ea_t addr = CurrInst->GetAddr();
		sval_t sp_delta = get_spd(this->GetFuncInfo(), addr);
		if (sp_delta < this->MinStackDelta)
			this->MinStackDelta = sp_delta;
		if (sp_delta > this->MaxStackDelta)
			this->MaxStackDelta = 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 NextInstIter = InstIter;
			++NextInstIter;
			sp_delta = get_spd(this->GetFuncInfo(), (*NextInstIter)->GetAddr());
			this->AllocPointDelta = sp_delta;
		}
	}

	// IDA Pro sometimes fails to add stack frame members for all incoming args, etc.
	//  Find and correct these omissions by examining stack accesses in instructions
	//  and extend the LocalVarTable to cover whatever is out of range.
	if (!this->AuditLocalVarTable()) {
		// Catastrophic error must have occurred, probably due to errors in IDA's
		//  stack pointer analysis, despite AnalyzedSP being true.
	if (!(this->LocalVarTable.empty())) {
		this->GoodLocalVarTable = true;
		// Sort the LocalVarTable so that we do not depend on IDA Pro
		//  presenting the stack frame members in order.
		std::sort(this->LocalVarTable.begin(), this->LocalVarTable.end(), LocalVarCompare);
	}

#if SMP_DEBUG_STACK_GRANULARITY
	SMP_msg("Computing %d local var sizes\n", this->LocalVarTable.size());
	// Now we want to audit 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) {
			struct LocalVar TempLocEntry = this->LocalVarTable[VarIndex];
			bool AboveLocalsRegion = (TempLocEntry.offset >= this->LocalVarsSize);
			size_t TempSize = this->LocalVarTable[VarIndex + 1].offset
				- TempLocEntry.offset;
			int DiffSize = ((int) TempSize) - ((int) TempLocEntry.size);
			// We don't have IDA Pro stack frame members for callee saved registers. This
			//  omission can make it seem that there is a gap between the uppermost local
			//  variable and the return address or saved frame pointer. Avoid expanding the
			//  last local variable into the callee saved registers region.
			if (DiffSize > 0) { // We are expanding the size.
				if (!AboveLocalsRegion && ((TempLocEntry.offset + TempLocEntry.size + DiffSize) > this->LocalVarsSize)) {
					// Current local does not start above the locals region, but its new size will
					//  carry it into the locals region.
					if ((TempLocEntry.offset + TempLocEntry.size) > this->LocalVarsSize) {
						// Weird. It already overlapped the callee saved regs region.
						SMP_msg("WARNING: Local var at offset %ld size %zu in %s extends above local vars region.\n",
							TempLocEntry.offset, TempLocEntry.size, this->GetFuncName());
					}
					// Limit DiffSize to avoid overlapping callee saved regs.
					DiffSize = this->LocalVarsSize - (TempLocEntry.offset + TempLocEntry.size);
					if (DiffSize < 0)
						DiffSize = 0; // started out positive, cap it at zero.
				}
			}
			if (DiffSize < 0)
				DiffSize = 0; // should not happen with sorted LocalVarTable unless duplicate entries.
			if (DiffSize != 0) {
#if SMP_DEBUG_STACK_GRANULARITY
				SMP_msg("STACK INFO: Adjusted size for stack frame member at %ld in %s\n",
					TempLocEntry.offset, this->GetFuncName());
#endif
				this->LocalVarTable[VarIndex].size += DiffSize;
			}
#if 0 // Using Member->eoff seems to be working for all members, including the last one.
#if SMP_DEBUG_STACK_GRANULARITY
		SMP_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;
#if 0 // AboveLocalsSize is not a reliable number.
	// 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 - AboveLocalsSize) > (adiff_t) this->FuncInfo.frsize) {
		this->LocalVarTable.clear();
		this->GoodLocalVarTable = false;
		SMP_msg("WARNING: Bad frsize %d for %s OffsetLimit: %d AboveLocalsSize: %d LocalVarsSize: %d ; abandoning SemiNaiveLocalVarID.\n",
			this->FuncInfo.frsize, this->GetFuncName(), this->LocalVarOffsetLimit, AboveLocalsSize, this->LocalVarsSize);
	assert((this->LocalVarOffsetLimit - AboveLocalsSize) <= (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 {
		SMP_msg("FindOutgoingArgsSize not called for %s ", this->GetFuncName());
		SMP_msg("AnalyzedSP: %d CallsAlloca: %d LocalVarsAllocInstr: %x \n",
			this->AnalyzedSP, this->CallsAlloca, this->LocalVarsAllocInstr);
	}
	return;
} // end of SMPFunction::SemiNaiveLocalVarID()

// Check and correct the LocalVarTable derived from IDA Pro stack frame members.
//  Examine each instruction and see if any stack accesses are beyond the LocalVarTable
//  and create new entries in the LocalVarTable if so.
bool SMPFunction::AuditLocalVarTable(void) {
	list<SMPInstr *>::iterator InstIter;
	int SignedOffset;
	// We cannot depend on IDA Pro making Member
	//  entries for everything that is accessed on the stack.
	//  When an incoming arg is accessed but no Member is
	//  created, then LocalVarOffsetLimit will be too small
	//  and we will get ERROR messages. Just loop through the
	//  instructions, find offsets higher than the LocalVarTable
	//  currently holds, and add new entries to LocalVarTable to
	//  handle them.
	// Iterate through all instructions and record stack frame accesses in the StackFrameMap.
	InstIter = this->Instrs.begin();
#if SMP_USE_SSA_FNOP_MARKER
	if ((*InstIter)->IsFloatNop())
		++InstIter;  // skip marker instruction
	for ( ; InstIter != this->Instrs.end(); ++InstIter) {