Newer
Older
7001
7002
7003
7004
7005
7006
7007
7008
7009
7010
7011
7012
7013
7014
7015
7016
7017
7018
7019
7020
7021
7022
7023
7024
7025
7026
7027
7028
7029
7030
7031
7032
7033
7034
7035
7036
7037
7038
7039
map<int, struct FineGrainedInfo>::iterator UseFGIter, DefFGIter;
list<SMPBasicBlock *>::iterator BlockIter;
for (UseFGIter = this->GlobalUseFGInfoBySSA.begin(); UseFGIter != this->GlobalUseFGInfoBySSA.end(); ++UseFGIter) {
struct FineGrainedInfo UseFG = UseFGIter->second;
if (0 == (UseFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS)) {
// No signedness info. Propagate any signedness info from DEF.
int UseHashValue = UseFGIter->first;
unsigned short DefSignMask = this->GetDefSignMiscInfo(UseHashValue);
DefSignMask &= FG_MASK_SIGNEDNESS_BITS;
if (0 != DefSignMask) {
// DEF has signedness info.
UseFGIter->second.SignMiscInfo |= DefSignMask;
changed = true;
}
}
}
// See if we have DEF signedness info for DEFs with no corresponding USE map entries.
for (DefFGIter = this->GlobalDefFGInfoBySSA.begin(); DefFGIter != this->GlobalDefFGInfoBySSA.end(); ++DefFGIter) {
struct FineGrainedInfo DefFG = DefFGIter->second;
unsigned short DefSignMask = (DefFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
if (0 != DefSignMask) {
// Has signedness info. See if USE has no entry.
int DefHashValue = DefFGIter->first;
UseFGIter = this->GlobalUseFGInfoBySSA.find(DefHashValue);
if (UseFGIter == this->GlobalUseFGInfoBySSA.end()) {
this->UpdateUseSignMiscInfo(DefHashValue, DefSignMask);
changed = true;
}
}
}
// Do the same processsing for block-local registers.
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
bool NewChange = (*BlockIter)->PropagateDEFSignedness();
changed = changed || NewChange;
}
#endif
return changed;
} // end of SMPFunction::PropagateSignedness()
// Detect and mark special cases before emitting numeric error annotations.
void SMPFunction::MarkSpecialNumericErrorCases(void) {
list<SMPBasicBlock *>::iterator BlockIter;
list<SMPInstr *>::reverse_iterator InstIter;
SMPBasicBlock *CurrBlock;
SMPInstr *CurrInst;
bool DebugFlag = (0 == strcmp("sub_8063BE0", this->GetFuncName()));
set<int> NonEscapingRegisterHashes; // memoization optimization: set of register/SSA# hashes that do not reach end of block
#if STARS_BUILD_LOOP_BITSET
// Now that we know how many loops we have, we can allocate the loops data structure.
this->FuncLoopsByBlock.resize(this->BlockCount);
for (size_t BlockIndex = 0; BlockIndex < this->BlockCount; ++BlockIndex) {
this->FuncLoopsByBlock.at(BlockIndex).AllocateBits(this->LoopCount);
}
if (this->LoopCount > 0) {
this->DetectLoops();
}
#endif
// Special-case preparatory analyses.
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
CurrBlock->AnalyzePrepForNumericAnnotations();
}
if (this->LoopCount == 0) {
return;
// Loop through blocks and detect tight loops of hashing arithmetic.
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
CurrBlock->AnalyzePrepForNumericAnnotations();
if (CurrBlock->IsLoopTailBlock() && CurrBlock->IsLoopHeaderBlock()) {
// We have a one-block loop to itself. This is the simple case we want
// to start with, as hash functions we have observed are tight loops of arithmetic computations.
// The next question is whether we can find the kind of shift/rotate that is common to hashing, plus
// at least one addition.
bool ShiftFound = false;
bool AddFound = false;
clc5q
committed
set<DefOrUse, LessDefUse>::iterator DefIter;
NonEscapingRegisterHashes.clear();
for (InstIter = CurrBlock->GetRevInstBegin(); InstIter != CurrBlock->GetRevInstEnd(); ++InstIter) {
CurrInst = (*InstIter);
if ((!ShiftFound) && CurrInst->MDIsHashingArithmetic()) {
// If the operand being shifted is never used in any assignment or arithmetic
// except as an address register computation within a memory operand, then the
// shifted value does not reach the top of the loop and get shifts accumulated.
// In that case, we are not dealing with a shift-and-add type of hash function.
clc5q
committed
// So, do not claim success unless the later addition DEF reaches the end
clc5q
committed
DefIter = CurrInst->GetFirstNonFlagsDef();
ea_t DefAddr = CurrInst->GetAddr();
clc5q
committed
DefOp = DefIter->GetOp();
ea_t AdditionAddr = BADADDR;
ShiftFound = CurrBlock->IsDefInvolvedInAddition(DefAddr, DefOp, AdditionAddr);
clc5q
committed
if (ShiftFound) {
SMPInstr *AdditionInst = this->GetInstFromAddr(AdditionAddr);
DefIter = AdditionInst->GetFirstNonFlagsDef();
AddDefOp = DefIter->GetOp();
AddFound = CurrBlock->DoesDefReachBlockEnd(AdditionAddr, AddDefOp, DefIter->GetSSANum(), NonEscapingRegisterHashes);
clc5q
committed
if (AddFound) {
break;
}
else {
// Reset ShiftFound and look for a different shift.
ShiftFound = false;
}
}
}
}
if (ShiftFound && AddFound) {
// We found a tight hashing loop. Mark all the overflowing and underflowing opcodes as benign.
// NOTE: We could do loop-variant analysis to ensure that the shifted and added values are actually
// changing within the loop, but if they are not, they are probably not exploitable overflows anyway,
// and the loop-invariant overflow would happen on every loop iteration based on initial values, which
// is a pattern we have never seen for this kind of code.
list<SMPInstr *>::iterator ForwardInstIter;
for (ForwardInstIter = CurrBlock->GetFirstInstr(); ForwardInstIter != CurrBlock->GetLastInstr(); ++ForwardInstIter) {
CurrInst = (*ForwardInstIter);
if (CurrInst->MDIsOverflowingOpcode() || CurrInst->MDIsUnderflowingOpcode() || CurrInst->MDIsLoadEffectiveAddressInstr()) {
CurrInst->SetHashOperation();
}
}
}
} // end if loop header and loop tail
} // end for all blocks
NonEscapingRegisterHashes.clear();
return;
} // end of SMPFunction::MarkSpecialNumericErrorCases()
// Emit all annotations for the function, including all per-instruction
// annotations.
void SMPFunction::EmitAnnotations(FILE *AnnotFile, FILE *InfoAnnotFile) {
// Emit annotation for the function as a whole.
list<SMPBasicBlock *>::iterator BlockIter;
SMPBasicBlock *CurrBlock;
bool FuncHasProblems = ((!this->AnalyzedSP) || (!this->HasGoodRTLs()) || (this->HasUnresolvedIndirectCalls())
|| (this->HasUnresolvedIndirectJumps()) || (this->HasSharedChunks()));
if (this->StaticFunc) {
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6zu FUNC LOCAL %s ", this->FuncInfo.startEA,
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6zu FUNC GLOBAL %s ", this->FuncInfo.startEA,
switch (this->GetReturnAddressStatus())
{
case FUNC_UNKNOWN:
{
clc5q
committed
SMP_fprintf(AnnotFile, "FUNC_UNKNOWN ");
break;
}
case FUNC_SAFE:
{
clc5q
committed
SMP_fprintf(AnnotFile, "FUNC_SAFE ");
break;
}
case FUNC_UNSAFE:
{
clc5q
committed
SMP_fprintf(AnnotFile, "FUNC_UNSAFE ");
break;
}
default:
assert(0);
}
clc5q
committed
SMP_fprintf(AnnotFile, "USEFP ");
clc5q
committed
SMP_fprintf(AnnotFile, "NOFP ");
}
if (this->FuncInfo.does_return()) {
clc5q
committed
SMP_fprintf(AnnotFile, "RET ");
clc5q
committed
SMP_fprintf(AnnotFile, "NORET ");
clc5q
committed
SMP_fprintf(AnnotFile, "FUNC_LEAF ");
clc5q
committed
SMP_fprintf(AnnotFile,"%10x ", this->FuncInfo.endEA - 1);
clc5q
committed
SMP_fprintf(AnnotFile, "LIBRARY ");
SMP_fprintf(AnnotFile, "\n");
// Emit annotations about how to restore register values
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d FUNC FRAMERESTORE ", this->FuncInfo.startEA, 0);
clc5q
committed
for(int i = R_ax; i <= R_di; i++)
clc5q
committed
SMP_fprintf(AnnotFile, "%d %d %d ", i, this->SavedRegLoc[i], this->ReturnRegTypes[i]);
clc5q
committed
SMP_fprintf(AnnotFile, "ZZ\n");
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d FUNC MMSAFENESS ", this->FuncInfo.startEA, 0);
clc5q
committed
SMP_fprintf(AnnotFile, "UNSAFE\n");
clc5q
committed
SMP_fprintf(AnnotFile, "SPECSAFE\n");
clc5q
committed
SMP_fprintf(AnnotFile, "SAFE\n");
// If function has problems that limited our analyses, emit an information annotation so that
// other tools can be aware of which analyses will be sound.
if (FuncHasProblems) {
clc5q
committed
SMP_fprintf(InfoAnnotFile, "%10x %6zu FUNC PROBLEM %s ", this->FuncInfo.startEA,
if (!this->AnalyzedSP) {
clc5q
committed
SMP_fprintf(InfoAnnotFile, "STACKANALYSIS ");
}
if (this->HasSharedChunks()) {
clc5q
committed
SMP_fprintf(InfoAnnotFile, "CHUNKS ");
}
if (this->HasUnresolvedIndirectJumps()) {
clc5q
committed
SMP_fprintf(InfoAnnotFile, "JUMPUNRESOLVED ");
}
if (this->HasUnresolvedIndirectCalls()) {
clc5q
committed
SMP_fprintf(InfoAnnotFile, "CALLUNRESOLVED ");
}
if (!this->HasGoodRTLs()) {
clc5q
committed
SMP_fprintf(InfoAnnotFile, "BADRTLS ");
clc5q
committed
SMP_fprintf(InfoAnnotFile, "\n");
// Find and mark special cases that will affect the integer error annotations.
this->MarkSpecialNumericErrorCases();
// Loop through all instructions in the function.
// Output optimization annotations for those
// instructions that do not require full computation
// of their memory metadata by the Memory Monitor SDT.
list<size_t> LoopList; // for current block
int CurrBlockNum = SMP_BLOCKNUM_UNINIT;
list<SMPInstr *>::iterator InstIter = Instrs.begin();
#if SMP_USE_SSA_FNOP_MARKER
++InstIter; // skip marker instruction
#endif
bool AllocSeen = false; // Reached LocalVarsAllocInstr yet?
bool DeallocTrigger = false;
for ( ; InstIter != Instrs.end(); ++InstIter) {
SMPInstr *CurrInst = (*InstIter);
ea_t addr = CurrInst->GetAddr();
CurrBlock = CurrInst->GetBlock();
int BlockNum = CurrBlock->GetNumber();
if (BlockNum != CurrBlockNum) {
CurrBlockNum = BlockNum;
if (0 < this->LoopCount) {
LoopList.clear();
this->BuildLoopList(BlockNum, LoopList);
}
}
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d INSTR BELONGTO %x \n", addr, 0, GetStartAddr());
if (this->LocalVarsAllocInstr == addr) {
AllocSeen = true;
clc5q
committed
this->EmitStackFrameAnnotations(AnnotFile, CurrInst);
clc5q
committed
int OptType = CurrInst->GetOptType();
if (5 == OptType) { // ADD or SUB
// Prevent mmStrata from extending the caller's stack frame
// to include the new allocation.
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL SafeFrameAlloc %s \n",
clc5q
committed
addr, -1, CurrInst->GetDisasm());
}
else if (CurrInst->MDIsPushInstr()) {
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL NoWarn %s \n",
clc5q
committed
addr, -3, CurrInst->GetDisasm());
}
clc5q
committed
// mmStrata ignores the DATAREF annotations anyway, so even though
// they are not needed, emit them for use by Strata and other tools
// in other projects besides MEDS.
this->EmitStackFrameAnnotations(AnnotFile, CurrInst);
}
// If this is the instruction which deallocated space
// for local variables, we set a flag to remind us to
// emit an annotation on the next instruction.
// mmStrata wants the instruction AFTER the
// deallocating instruction, so that it processes
// the deallocation after it happens. It inserts
// instrumentation before an instruction, not
// after, so it will insert the deallocating
// instrumentation before the first POP of callee-saved regs,
// if there are any, or before the return, otherwise.
if (addr == this->LocalVarsDeallocInstr) {
DeallocTrigger = true;
}
else if (DeallocTrigger) { // Time for annotation
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d DEALLOC STACK esp - %d %s\n", addr,
this->LocalVarsSize, this->LocalVarsSize, CurrInst->GetDisasm());
DeallocTrigger = false;
}
#ifndef SMP_REDUCED_ANALYSIS
if (this->StackPtrAnalysisSucceeded() && this->HasGoodRTLs() && !this->HasUnresolvedIndirectJumps() && !this->HasSharedChunks()) {
CurrInst->EmitTypeAnnotations(this->UseFP, AllocSeen, this->NeedsStackReferent, AnnotFile, InfoAnnotFile);
CurrInst->EmitIntegerErrorAnnotations(InfoAnnotFile, LoopList);
else
#endif
CurrInst->EmitAnnotations(this->UseFP, AllocSeen, this->NeedsStackReferent, AnnotFile, InfoAnnotFile);
if (CurrInst->MDIsReturnInstr() && this->GetReturnAddressStatus() == FUNC_SAFE)
CurrInst->EmitSafeReturn(AnnotFile);
} // end for all instructions
// Loop through all basic blocks and emit profiling request annotations
// for those blocks that have unsafe memory writes in them.
this->SafeBlocks = 0;
this->UnsafeBlocks = 0;
for (BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
CurrBlock = (*BlockIter);
if (CurrBlock->MaybeAliasedWrite()) {
++(this->UnsafeBlocks);
clc5q
committed
#if SMP_OPTIMIZE_BLOCK_PROFILING
list<SMPInstr *>::iterator CurrInst;
CurrInst = CurrBlock->GetFirstInstr();
ea_t addr = (*CurrInst)->GetAddr();
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d BLOCK PROFILECOUNT %s\n", addr,
(*CurrInst)->GetCmd().size, (*CurrInst)->GetDisasm());
clc5q
committed
#endif
}
else {
++(this->SafeBlocks);
}
}
// Free loop memory.
this->FuncLoopsByBlock.clear();
#if SMP_SHRINK_TO_FIT
vector<STARSBitSet>(this->FuncLoopsByBlock).swap(this->FuncLoopsByBlock);
#endif
return;
} // end of SMPFunction::EmitAnnotations()
// Debug output dump.
void SMPFunction::Dump(void) {
list<SMPBasicBlock *>::iterator CurrBlock;
clc5q
committed
SMP_msg("Debug dump for function: %s\n", this->GetFuncName());
SMP_msg("UseFP: %d LocalVarsAllocInstr: %x\n", this->UseFP,
this->LocalVarsAllocInstr);
for (size_t index = 0; index < this->IDom.size(); ++index) {
clc5q
committed
SMP_msg("IDOM for %zu: %d\n", index, this->IDom.at(index));
for (size_t index = 0; index < this->DomTree.size(); ++index) {
clc5q
committed
SMP_msg("DomTree for %zu: ", index);
list<int>::iterator DomIter;
for (DomIter = this->DomTree.at(index).second.begin();
DomIter != this->DomTree.at(index).second.end();
++DomIter) {
clc5q
committed
SMP_msg("%d ", *DomIter);
clc5q
committed
SMP_msg("\n");
clc5q
committed
SMP_msg("Global names: \n");
set<op_t, LessOp>::iterator NameIter;
for (NameIter = this->GlobalNames.begin(); NameIter != this->GlobalNames.end(); ++NameIter) {
clc5q
committed
SMP_msg("index: %d ", ExtractGlobalIndex(*NameIter));
PrintListOperand(*NameIter);
clc5q
committed
SMP_msg("\n");
clc5q
committed
SMP_msg("Blocks each name is defined in: \n");
for (size_t index = 0; index < this->BlocksDefinedIn.size(); ++index) {
clc5q
committed
SMP_msg("Name index: %zu Blocks: ", index);
list<int>::iterator BlockIter;
for (BlockIter = this->BlocksDefinedIn.at(index).begin();
BlockIter != this->BlocksDefinedIn.at(index).end();
++BlockIter) {
clc5q
committed
SMP_msg("%d ", *BlockIter);
clc5q
committed
SMP_msg("\n");
}
for (CurrBlock = this->Blocks.begin(); CurrBlock != this->Blocks.end(); ++CurrBlock) {
// Dump out the function number and data flow sets before the instructions.
clc5q
committed
SMP_msg("End of debug dump for function: %s\n", this->GetFuncName());
return;
} // end of SMPFunction::Dump()
// Analyzes the function to see if the return address can be marked as safe
void SMPFunction::MarkFunctionSafe() {
clc5q
committed
SMP_msg(" Analyzing function %s and isLeaf = %d \n ", this->GetFuncName(), this->IsLeaf());
bool HasCallTargets = false;
clc5q
committed
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
clc5q
committed
bool HasIndexedStackWrite = false;
bool HasIndirectWrite = false;
bool IsIndirectCallTarget = false; // could be called indirectly
bool IsTailCallTarget = false; // could be called by jump instruction used as tail call
bool HasNoCallers = this->AllCallSources.empty();
clc5q
committed
this->ReturnAddrStatus = FUNC_SAFE;
this->SafeFunc = true;
if (!this->AllCallTargets.empty()) {
HasCallTargets = true;
#if SMP_USE_SWITCH_TABLE_INFO
if (this->UnresolvedIndirectJumps) {
#else
clc5q
committed
SMP_msg("Function %s marked as unsafe due to indirect jumps\n", this->GetFuncName());
#if SMP_DECLARE_INDIRECT_TARGETS_UNSAFE
ea_t FirstAddr = this->FirstEA;
SMP_xref_t xrefs;
for (bool ok = xrefs.SMP_first_to(FirstAddr, XREF_ALL); ok; ok = xrefs.SMP_next_to()) {
ea_t FromAddr = xrefs.GetFrom();
if (FromAddr != 0) {
if (!xrefs.GetIscode()) { // found data xref
IsIndirectCallTarget = true; // addr of func appears in data; assume indirect calls to func
}
else { // found code xref; see if it is a jump used as a tail call
// These tail calls could be a problem for fast returns if they go from unsafe to safe functions.
insn_t TempCmd;
ulong TempFeatures;
bool CmdOK = SMPGetCmd(FromAddr, TempCmd, TempFeatures);
if (!CmdOK) {
// Better be conservative and assume it could be a tail call.
IsTailCallTarget = true;
SMP_msg("ERROR: Could not decode instruction at %x from within MarkFunctionSafe(); assuming tail call\n", FromAddr);
}
else if (TempCmd.itype != MD_CALL_INSTRUCTION) { // not a call instruction; must be jump of some sort
IsTailCallTarget = true;
}
}
}
}
this->PossibleIndirectCallTarget = IsIndirectCallTarget;
this->PossibleTailCallTarget = IsTailCallTarget;
#endif
list<SMPInstr *>::iterator Instructions = Instrs.begin();
SMPInstr *CurrInst;
#if SMP_USE_SSA_FNOP_MARKER
++Instructions; // skip marker instruction
#endif
// While processing the stack pointer writes, the prologue code for
clc5q
committed
// saving the frame register and allocating local variables needs to be
// handled.
bool SaveEBP = false;
bool XferESPtoEBP = false;
for ( ; Instructions != Instrs.end(); ++Instructions) {
CurrInst = (*Instructions);
clc5q
committed
SMP_msg(" Total number of defs for this instruction %d\n", CurrInst->NumDefs());
#endif
if (!SaveEBP) { // still looking for "push ebp"
if (CurrInst->MDIsPushInstr() && CurrInst->GetCmd().Operands[0].is_reg(R_bp)) {
SaveEBP = true;
continue;
}
}
else if (!XferESPtoEBP) { // found "push ebp", looking for "mov ebp,esp"
insn_t CurrCmd = CurrInst->GetCmd();
if ((CurrCmd.itype == NN_mov)
&& (CurrInst->GetFirstDef()->GetOp().is_reg(R_bp))
&& (CurrInst->GetFirstUse()->GetOp().is_reg(R_sp))) {
XferESPtoEBP = true;
continue;
}
}
ea_t address = CurrInst->GetAddr();
if (address == this->LocalVarsAllocInstr ||
address == this->LocalVarsDeallocInstr)
continue;
if (CurrInst->MDIsStackPointerCopy(this->UseFP)) {
clc5q
committed
HasStackPointerCopy = true;
if (CurrInst->MDIsLoadEffectiveAddressInstr()) {
// If an lea instruction loads an address above
// the stack frame, we must assume that writes
// above the stack frame could occur.
op_t TempOp = CurrInst->GetLeaMemUseOp();
if (this->WritesAboveLocalFrame(TempOp, CurrInst->AreDefsNormalized()))
WritesAboveLocalFrameIndirect = true;
}
clc5q
committed
SMP_msg(" Function %s marked as unsafe due to stack pointer copy \n ", this->GetFuncName());
SMP_msg("%s %x \n", CurrInst->GetDisasm(), CurrInst->GetAddr());
if (CurrInst->MDIsPushInstr()) {
// not exactly sure how to handle this instruction
// for the moment if its a push on a esp or usefp & ebp
// mark as unsafe
if (CurrInst->GetCmd().Operands[0].is_reg(R_sp) ||
(this->UseFP && CurrInst->GetCmd().Operands[0].is_reg(R_bp))) {
clc5q
committed
HasStackPointerPush = true;
clc5q
committed
SMP_msg(" Function %s marked as unsafe due to push on ebp or esp outside of function header \n", this->GetFuncName());
SMP_msg("%s %x\n", CurrInst->GetDisasm(), CurrInst->GetAddr());
#endif
}
continue;
}
if (CurrInst->MDIsPopInstr() || CurrInst->MDIsReturnInstr()) {
// ignore pops and returns for the moment
continue;
}
set<DefOrUse, LessDefUse>::iterator setIterator;
for (setIterator = CurrInst->GetFirstDef(); setIterator != CurrInst->GetLastDef(); ++setIterator) {
op_t Operand = setIterator->GetOp();
clc5q
committed
int BaseReg;
int IndexReg;
ushort ScaleFactor;
ea_t offset;
// now o_mem can have sib byte as well, as
clc5q
committed
// reported by IDA. Check if the base reg is R_none
// and index reg is R_none. If they are, then this is
clc5q
committed
// a direct global write and can be marked safe.
clc5q
committed
MDExtractAddressFields(Operand, BaseReg, IndexReg, ScaleFactor, offset);
clc5q
committed
// go onto next def
continue;
HasIndirectGlobalWrite = true;
}
clc5q
committed
MDExtractAddressFields(Operand, BaseReg, IndexReg, ScaleFactor, offset);
bool FramePointerRelative = (this->UseFP && (BaseReg == R_bp));
bool StackPointerRelative = (BaseReg == R_sp);
if (StackPointerRelative || FramePointerRelative) {
clc5q
committed
if (IndexReg == R_none) {
bool tempWritesAboveLocalFrame = this->WritesAboveLocalFrame(Operand, CurrInst->AreDefsNormalized());
clc5q
committed
SMP_msg(" Function %s marked as unsafe due to direct write above loc "
"variables offset=%x loc=%x\n ", this->GetFuncName(),
offset, this->LocalVarsSize);
clc5q
committed
SMP_msg("Write above local frame in %s : offset: %d ",
clc5q
committed
SMP_msg("LocalVarsSize: %d OutgoingArgsSize: %d frsize: %d frregs: %d",
this->LocalVarsSize, this->OutgoingArgsSize,
this->FuncInfo.frsize, this->FuncInfo.frregs);
Instructions->Dump();
}
#endif
bool tempWritesAboveLocalFrameIndirect = this->IndexedWritesAboveLocalFrame(Operand);
/* separate indirect writes to this frame from indirect writes to another frame */
WritesAboveLocalFrameIndirect = true;
clc5q
committed
SMP_msg(" Function %s marked as unsafe due to indexed stack write above "
"loc variable offset\n", this->GetFuncName());
clc5q
committed
SMP_msg("%s %x\n", CurrInst->GetDisasm(), CurrInst->GetAddr());
clc5q
committed
SMP_msg(" Function %s marked as unsafe due to indexed stack write\n",
clc5q
committed
SMP_msg("%s %x\n", CurrInst->GetDisasm(), CurrInst->GetAddr());
/* check whether there is profiler information for this indirect reference */
clc5q
committed
HasIndirectWrite = true;
}
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
clc5q
committed
MDExtractAddressFields(Operand, BaseReg, IndexReg, ScaleFactor, offset);
// check the base reg
// if index reg is used mark as unsafe
if ((BaseReg == R_sp || (this->UseFP && BaseReg == R_bp))) {
if (IndexReg == R_none) {
/* addressing mode is *esp or *ebp */
clc5q
committed
continue;
}
else {
HasIndexedStackWrite = true;
#if SMP_DEBUG_FUNC
clc5q
committed
SMP_msg(" Function %s marked as unsafe due to indexed stack write\n", this->GetFuncName());
SMP_msg("%s %x\n", CurrInst->GetDisasm(), CurrInst->GetAddr());
clc5q
committed
#endif
}
/* check whether there is profiler information for this indirect reference */
clc5q
committed
HasIndirectWrite = true;
// else not memory, and we don't care.
} // end for all DEFs in current instruction
} // end for all instructions
clc5q
committed
// For mmStrata bounds checking of the stack frame, we don't care
// about indirect writes unless they are to the stack.
bool SpecUnsafe = (HasStackPointerCopy || HasStackPointerPush
|| HasIndexedStackWrite || this->SharedChunks
|| this->UnresolvedIndirectJumps);
bool Unsafe = SpecUnsafe || this->UnresolvedIndirectCalls;
this->SafeFunc = (!Unsafe);
this->SpecSafeFunc = (!SpecUnsafe);
this->WritesAboveRA = WritesAboveLocalFrameIndirect;
this->SafeCallee = (!Unsafe) && (!WritesAboveLocalFrameIndirect) && this->AnalyzedSP;
this->SpecSafeCallee = (!SpecUnsafe) && (!WritesAboveLocalFrameIndirect) && this->AnalyzedSP;
this->SpecNeedsStackReferent = SpecUnsafe;
this->HasIndirectWrites = (HasIndexedStackWrite || HasIndirectWrite
|| WritesAboveLocalFrameIndirect || HasIndirectGlobalWrite);
bool UnsafeReturnAddr = (Unsafe || WritesAboveLocalFrame || WritesAboveLocalFrameIndirect || HasIndirectGlobalWrite
|| HasIndirectWrite || (!this->AnalyzedSP));
#if SMP_DECLARE_INDIRECT_TARGETS_UNSAFE
if (!UnsafeReturnAddr && this->PossibleIndirectCallTarget) {
SMP_msg("INFO: Function at %x becoming UNSAFE because it is indirect call target.\n", this->FirstEA);
UnsafeReturnAddr = true;
}
else if (!UnsafeReturnAddr && this->PossibleTailCallTarget) {
SMP_msg("INFO: Function at %x becoming UNSAFE because it is tail call target.\n", this->FirstEA);
UnsafeReturnAddr = true;
}
else if (!UnsafeReturnAddr && HasNoCallers) {
SMP_msg("INFO: Function at %x becoming UNSAFE because it has no callers.\n", this->FirstEA);
UnsafeReturnAddr = true;
}
#endif
if (UnsafeReturnAddr) {
this->SetReturnAddressStatus(FUNC_UNSAFE);
clc5q
committed
SMP_msg("UNSAFE function %s ", this->GetFuncName());
SMP_msg("StackPtrCopy: %d StackPtrPush: %d IndirectGlobal: %d ",
clc5q
committed
HasStackPointerCopy, HasStackPointerPush, HasIndirectGlobalWrite);
clc5q
committed
SMP_msg("WritesAboveFrame: %d IndirectStack: %d IndirectWrite: %d ",
clc5q
committed
WritesAboveLocalFrame, HasIndexedStackWrite, HasIndirectWrite);
SMP_msg("AnalyzedSP: %d UnresolvedCalls: %d UnresolvedJumps: %d SharedChunks: %d IsLeaf: %d",
this->AnalyzedSP, this->UnresolvedIndirectCalls, this->UnresolvedIndirectJumps,
this->SharedChunks, this->IsLeaf());
SMP_msg("IndirCallTarget: %d TailCallTarget: %d HasNoCallers: %d\n", this->PossibleIndirectCallTarget,
this->PossibleTailCallTarget, HasNoCallers);
clc5q
committed
}
else if (HasCallTargets) {
this->SetReturnAddressStatus(FUNC_UNKNOWN);
clc5q
committed
}
if (this->GetReturnAddressStatus() == FUNC_SAFE)
clc5q
committed
SMP_msg("Function %s is SAFE\n", GetFuncName());
else if (this->GetReturnAddressStatus() == FUNC_SAFE)
clc5q
committed
SMP_msg("Function %s is UNSAFE\n", GetFuncName());
else if (this->GetReturnAddressStatus() == FUNC_SAFE)
clc5q
committed
SMP_msg("Function %s is UNKNOWN\n", GetFuncName());
clc5q
committed
SMP_msg("Function %s is mmSAFE\n", GetFuncName());
clc5q
committed
SMP_msg("Function %s is mmUNSAFE\n", GetFuncName());
clc5q
committed
SMP_msg("Function %s is Speculatively mmSAFE\n", GetFuncName());
clc5q
committed
SMP_msg("Function %s is Speculatively mmUNSAFE\n", GetFuncName());
clc5q
committed
return;
} // end of SMPFunction::MarkFunctionSafe()