diff --git a/SMPFunction.cpp b/SMPFunction.cpp index 2cff5a677226bf987594b9247ec33f28bd86a9fb..d261d7a4e7d4308ed78f76dc8b980dbd59d28680 100644 --- a/SMPFunction.cpp +++ b/SMPFunction.cpp @@ -41,7 +41,8 @@ #define SMP_DEBUG_FRAMEFIXUP 0 #define SMP_DEBUG_DATAFLOW 0 #define SMP_DEBUG_STACK_GRANULARITY 0 -#define SMP_DEBUG_BUILD_RTL 1 // should be left on; serious errors! +#define SMP_DEBUG_FUNC 1 +#define SMP_DEBUG_BUILD_RTL 1 // leave this on; serious errors reported // Compute LVA/SSA or not? Turn it off for NICECAP demo on 31-JAN-2008 #define SMP_COMPUTE_LVA_SSA 1 @@ -80,6 +81,7 @@ SMPFunction::SMPFunction(func_t *Info) { this->LocalVarTable.clear(); this->StackFrameMap.clear(); this->DirectCallTargets.clear(); + this->ReturnAddrStatus = FUNC_UNKNOWN; this->Blocks.clear(); this->Instrs.clear(); this->GlobalNames.clear(); @@ -1301,11 +1303,13 @@ void SMPFunction::Analyze(void) { #if SMP_DEBUG_CONTROLFLOW msg("SMPFunction::Analyze: set stack frame info.\n"); #endif - // Figure out the stack frame and related info. +#ifdef SMP_DEBUG_FUNC + msg(" %s has shared chunks \n", this->GetFuncName()); +#endif + // Figure out the stack frame and related info. this->SetStackFrameInfo(); } - - return; + this->MarkFunctionSafe(); } // end of SMPFunction::Analyze() // Compute SSA form data structures across the function. @@ -2430,6 +2434,26 @@ void SMPFunction::EmitAnnotations(FILE *AnnotFile) { qfprintf(AnnotFile, "%10x %6d FUNC GLOBAL %s ", this->FuncInfo.startEA, this->Size, this->FuncName); } + switch (this->ReturnAddrStatus) + { + case FUNC_UNKNOWN: + { + qfprintf(AnnotFile, "FUNC_UNKNOWN "); + break; + } + case FUNC_SAFE: + { + qfprintf(AnnotFile, "FUNC_SAFE "); + break; + } + case FUNC_UNSAFE: + { + qfprintf(AnnotFile, "FUNC_UNSAFE "); + break; + } + default: + assert(0); + } if (this->UseFP) { qfprintf(AnnotFile, "USEFP "); } @@ -2437,11 +2461,17 @@ void SMPFunction::EmitAnnotations(FILE *AnnotFile) { qfprintf(AnnotFile, "NOFP "); } if (this->FuncInfo.does_return()) { - qfprintf(AnnotFile, "\n"); + qfprintf(AnnotFile, "RET \n"); } else { qfprintf(AnnotFile, "NORET \n"); } +#ifdef SMP_DEBUG_FUNC + if (this->IsLeaf()) + qfprintf(AnnotFile, "FUNC_LEAF "); + // store the return address + qfprintf(AnnotFile,"%10x ", this->FuncInfo.endEA - 1); +#endif // Loop through all instructions in the function. // Output optimization annotations for those @@ -2481,6 +2511,8 @@ void SMPFunction::EmitAnnotations(FILE *AnnotFile) { else { CurrInst->EmitAnnotations(this->UseFP, AllocSeen, AnnotFile); } + if (CurrInst->MDIsReturnInstr() && this->GetReturnAddressStatus() == FUNC_SAFE ) + CurrInst->EmitSafeReturn(AnnotFile); } // end for (ea_t addr = FuncInfo.startEA; ...) return; } // end of SMPFunction::EmitAnnotations() @@ -2527,3 +2559,209 @@ void SMPFunction::Dump(void) { return; } // end of SMPFunction::Dump() + +// Analyzes the function to see if the return address can be marked as safe +void SMPFunction::MarkFunctionSafe() { +#ifdef SMP_DEBUG_FUNC + msg(" Analyzing function name %s and isLeaf=%d ", this->GetFuncName(), this->IsLeaf()); +#endif + + ReturnAddrStatus = FUNC_SAFE; + if (!AnalyzedSP || this->IndirectCalls) { +#ifdef SMP_DEBUG_FUNC + if (!AnalyzedSP) + msg(" Function marked as unsafe %s coz AnalyzedSP = false\n", this->GetFuncName()); + else + msg(" Function marked as unsafe %s coz function has indirect calls\n", this->GetFuncName()); +#endif + + ReturnAddrStatus = FUNC_UNSAFE; + return; + } + + if (!this->DirectCallTargets.empty()) { +#ifdef SMP_DEBUG_FUNC + msg(" Function marked as unknown %s \n", this->GetFuncName()); +#endif + ReturnAddrStatus = FUNC_UNKNOWN; + } + if (this->IndirectJumps) { +#ifdef SMP_DEBUG_FUNC + msg(" Function marked as unsafe due to indirect jumps %s\n", this->GetFuncName()); +#endif + ReturnAddrStatus = FUNC_UNSAFE; + return ; + } + if (this->HasSharedChunks()) { + ReturnAddrStatus = FUNC_UNSAFE; + return; + } + list<SMPInstr>::iterator Instructions; + + // while processing the stack pointer write the prolog containing for + // saving frame register and allcating local variables needs to be + // handled + bool SaveEBP = false; + bool XferESPtoEBP = false; + for (Instructions = Instrs.begin(); Instructions != Instrs.end(); Instructions++) { +#ifdef SMP_DEBUG_FUNC + msg(" Total number of defs for this instruction %d\n", Instructions->NumDefs()); +#endif + if (!SaveEBP) { // still looking for "push ebp" + if (Instructions->MDIsPushInstr() && Instructions->GetCmd().Operands[0].is_reg(R_bp)) { + SaveEBP = true; + continue; + } + } + else if (!XferESPtoEBP) { // found "push ebp", looking for "mov ebp,esp" + insn_t CurrCmd = Instructions->GetCmd(); + if ((CurrCmd.itype == NN_mov) + && (Instructions->GetFirstDef()->GetOp().is_reg(R_bp)) + && (Instructions->GetFirstUse()->GetOp().is_reg(R_sp))) { + XferESPtoEBP = true; + continue; + } + } + ea_t address = Instructions->GetAddr(); + if (address == this->LocalVarsAllocInstr || + address == this->LocalVarsDeallocInstr) + continue; + + if (Instructions->MDIsStackPointerCopy(this->UseFP)) { +#ifdef SMP_DEBUG_FUNC + msg(" Function marked as unsafe %s due to stack pointer copy \n ", this->GetFuncName()); + msg("%s %x \n", (Instructions)->GetDisasm(), (Instructions)->GetAddr()); +#endif + ReturnAddrStatus = FUNC_UNSAFE; + return; + } + if (Instructions->MDIsPushInstr()) { + // not exactly sure how to handle this instruction + // for the moment if its a push on a esp or usefp & ebp + // mark as unsafe + if (Instructions->GetCmd().Operands[0].is_reg(R_sp) || + ( this->UseFP && Instructions->GetCmd().Operands[0].is_reg(R_bp))) { +#ifdef SMP_DEBUG_FUNC + msg(" Function marked as unsafe %s due to push on ebp or esp outside of function header \n", this->GetFuncName()); + msg("%s %x\n", (Instructions)->GetDisasm(), (Instructions)->GetAddr()); +#endif + ReturnAddrStatus = FUNC_UNSAFE; + return; + } + continue; + } + if (Instructions->MDIsPopInstr()) { + // ignore pops for the moment + continue; + } + set<DefOrUse, LessDefUse>::iterator setIterator; + for (setIterator = Instructions->GetFirstDef(); setIterator != Instructions->GetLastDef(); setIterator++) { + op_t Operand = setIterator->GetOp(); + if (Operand.type == o_mem) { + // now o_mem can have sib byte as well, as + // reported by IDA. check if the base reg is bp + // and index reg is sp. If it is, then this is + // probably a global write and can be marked + // safe + if (Operand.hasSIB) { + int BaseReg = sib_base(Operand); + short IndexReg = sib_index(Operand); + if ((BaseReg == R_none || BaseReg == R_bp) && + (IndexReg == R_none || IndexReg == R_sp)) { + // go onto next def + continue; + } + } + else { + // o_mem should never have a base register (field should be zero) + if ((Operand.reg == 0) || (Operand.reg == R_bp)) // ignore + continue; + } + ReturnAddrStatus = FUNC_UNSAFE; + return; + } + if (Operand.type == o_displ) { + if (Operand.hasSIB) { + int BaseReg = sib_base(Operand); + short IndexReg = sib_index(Operand); + if (((BaseReg==R_sp || (this->UseFP && BaseReg == R_bp)))) { + if (IndexReg == R_sp || IndexReg == R_none) { + ea_t offset = Operand.addr; + if (offset > this->LocalVarsSize ) { +#ifdef SMP_DEBUG_FUNC + msg(" Function marked as unsafe %s due to write above loc variables offset=%x loc=%x\n ", this->GetFuncName(), offset, this->LocalVarsSize); + msg("%s %x\n", (Instructions)->GetDisasm(), (Instructions)->GetAddr()); +#endif + ReturnAddrStatus = FUNC_UNSAFE; + return; + } + } + else { +#ifdef SMP_DEBUG_FUNC + msg(" Function marked as unsafe %s due to index write above loc variables \n", this->GetFuncName()); + msg("%s %x\n", (Instructions)->GetDisasm(), (Instructions)->GetAddr()); +#endif + ReturnAddrStatus = FUNC_UNSAFE; + return; + } + } + else { + ReturnAddrStatus = FUNC_UNSAFE; + return; + } + + } + else { + // no index + ushort BaseReg = Operand.reg; + if (BaseReg == R_sp || (UseFP && BaseReg == R_bp)) { + ea_t offset = Operand.addr; + if (offset > this->LocalVarsSize ) { +#ifdef SMP_DEBUG_FUNC + msg(" Function marked as unsafe %s due to write above loc variables in no sib offset=%x loc=%x \n", this->GetFuncName(), offset, this->LocalVarsSize); + msg("%s %x \n", (Instructions)->GetDisasm(), (Instructions)->GetAddr()); +#endif + ReturnAddrStatus = FUNC_UNSAFE; + return; + } + } + else { + ReturnAddrStatus = FUNC_UNSAFE; + return; + } + } + } + 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 + if (Operand.hasSIB) { + // check the base reg + int BaseReg = sib_base(Operand); + short IndexReg = sib_index(Operand); + // if index reg is used mark as unsafe + if ((BaseReg == R_sp || (this->UseFP && BaseReg == R_bp)) + && (IndexReg != R_sp) && (IndexReg != R_none)) { + // index=sp implies there is no index register +#ifdef SMP_DEBUG_FUNC + msg(" Does function with phrase have displ %s %x ", this->GetFuncName(), Operand.addr); +#endif + continue; + } + else { + ReturnAddrStatus = FUNC_UNSAFE; + return ; + } + } + else { + ushort BaseReg = Operand.reg; + if (BaseReg == R_sp || (this->UseFP && BaseReg == R_bp)) + continue; + ReturnAddrStatus = FUNC_UNSAFE; + return; + } + } + } + } +} + diff --git a/SMPFunction.h b/SMPFunction.h index ca4eefed0ae4adcd238cc7f2779489c5794129a5..33a0bf5680070d8f88d6fd2afbf83563524f7760 100644 --- a/SMPFunction.h +++ b/SMPFunction.h @@ -41,6 +41,13 @@ struct StackFrameEntry { bool EBPRelativeAccess; // ever accessed by EBP-const? (only if UseFP) }; +enum FuncType { + FUNC_UNKNOWN = 0, + FUNC_SAFE = 1, + FUNC_UNSAFE = 2 +}; + + // Class encapsulating all that the SMP static analyzer cares to know // about a function. class SMPFunction { @@ -73,6 +80,11 @@ public: void SetLinks(void); // Link basic blocks and map instructions to blocks void LiveVariableAnalysis(void); // Perform Live Variable Analysis across all blocks void ComputeSSA(void); // Compute SSA form data structures + inline FuncType GetReturnAddressStatus(void) const { return ReturnAddrStatus;} + void SetReturnAddressStatus(FuncType funcType) {ReturnAddrStatus = funcType;} + inline const vector<ea_t> GetCallTargets() const { return DirectCallTargets;} + inline const ea_t GetStartAddr() const { return FuncInfo.startEA; } // exposing the start address of the function. Used in RecurseAndMark + void InferTypes(void); // Determine NUMERIC, POINTER, etc. for all operands bool InferGlobalDefType(op_t RefOp, int SSANum); // Can DEF type be inferred from all USEs? private: @@ -115,6 +127,9 @@ private: vector<struct LocalVar> LocalVarTable; // offset-sorted list of local vars / outgoing args adiff_t LocalVarOffsetLimit; // upper bound on stack-relative offsets vector<struct StackFrameEntry> StackFrameMap; // memory map of every byte on stack frame + FuncType ReturnAddrStatus; // Marked true if the return address is safe from being overwritten + void MarkFunctionSafe(); // Does analysis to see if the function can be marked safe + // Methods void SetStackFrameInfo(void); ea_t FindAllocPoint(asize_t); // Deal with difficult to find stack frame allocations diff --git a/SMPInstr.cpp b/SMPInstr.cpp index 99ce1556fd41dbb1728914fa05b0c85b96095181..8670a60f9a7b8c4e4a88175cf5d23c3e1897585b 100644 --- a/SMPInstr.cpp +++ b/SMPInstr.cpp @@ -1898,6 +1898,14 @@ void SMPInstr::EmitAnnotations(bool UseFP, bool AllocSeen, FILE *AnnotFile) { return; } // end of SMPInstr::EmitAnnotations() +/** + * Emits Safe Returns + */ +void SMPInstr::EmitSafeReturn(FILE *AnnotFile) +{ + qfprintf(AnnotFile, "%10x %6d INSTR RET_SAFE %s\n", this->address, this->SMPcmd.size, disasm); +} + // Emit all annotations for the instruction using RTL type inference. void SMPInstr::EmitTypeAnnotations(bool UseFP, bool AllocSeen, FILE *AnnotFile) { ea_t addr = this->address; diff --git a/SMPInstr.h b/SMPInstr.h index 363babbbb5dff67b68ce5c5b704df6e15e8bfd58..5aecccba79ea8fe0a775e3d95b4f74d38ce8f0a6 100644 --- a/SMPInstr.h +++ b/SMPInstr.h @@ -212,8 +212,9 @@ public: void AnnotateStackConstants(bool UseFP, FILE *AnnotFile); void EmitAnnotations(bool UseFP, bool AllocSeen, FILE *AnnotFile); // No RTLs available void EmitTypeAnnotations(bool UseFP, bool AllocSeen, FILE *AnnotFile); // Use RTL types + void EmitSafeReturn(FILE *AnnotFile); // emit annotation to denote that the return belongs to a safe function. private: - // Data + // Data SMPBasicBlock *BasicBlock; // basic block containing this instruction insn_t SMPcmd; // copy of 'cmd' for this instruction ulong features; // Canonical features for SMPcmd diff --git a/SMPProgram.cpp b/SMPProgram.cpp index 6fc39fde92871009d85ca339a81b3fc62202cebe..83acac4325eefa837e9864c4b4ebf044fae99e48 100644 --- a/SMPProgram.cpp +++ b/SMPProgram.cpp @@ -37,6 +37,7 @@ #define SMP_DEBUG_GLOBAL_GRANULARITY 0 #define SMP_DEBUG_OPTIMIZATIONS 1 #define SMP_DEBUG_OPTIMIZATIONS_VERBOSE 1 +#define SMP_DEBUG_FUNC 1 // Compute fine-grained global static data boundaries? #define SMP_COMPUTE_GLOBAL_GRANULARITY 1 @@ -418,11 +419,101 @@ void SMPProgram::EmitAnnotations(FILE *AnnotFile) { map<ea_t, SMPFunction *>::iterator FuncIter; for (FuncIter = this->FuncMap.begin(); FuncIter != this->FuncMap.end(); ++FuncIter) { SMPFunction *TempFunc = FuncIter->second; + if (TempFunc == NULL) continue; + FuncType Type; + if (TempFunc->GetReturnAddressStatus() == FUNC_UNKNOWN) + { + // add func name to set + set<const char*,LtStr>::const_iterator find = FuncNameSet.find(TempFunc->GetFuncName()); + if (find == FuncNameSet.end()) + { + FuncNameSet.insert(TempFunc->GetFuncName()); + RecurseAndMarkRetAdd(TempFunc); + FuncNameSet.erase(TempFunc->GetFuncName()); + } + //remove name + } TempFunc->EmitAnnotations(AnnotFile); } // end for all functions return; } // end of SMPProgram::EmitAnnotations() +/** + * If a function is still marked FUNC_UNKNOWN at the time of emitting + * annotations, this function traverses over the call graph rooted at this + * function and checks if they are marked safe. + */ +FuncType SMPProgram::RecurseAndMarkRetAdd(SMPFunction* FuncAttrib) +{ + if (FuncAttrib->IsLeaf()) + { +#ifdef SMP_DEBUG_FUNC + if (FuncAttrib->GetReturnAddressStatus() == FUNC_UNKNOWN) + msg(" Leaf Function %s found with status unknown", FuncAttrib->GetFuncName()); +#endif + assert(FuncAttrib->GetReturnAddressStatus() != FUNC_UNKNOWN); + return FuncAttrib->GetReturnAddressStatus(); + } + vector<ea_t> CallTargets = FuncAttrib->GetCallTargets(); + for (int i = 0; i < CallTargets.size(); i++) + { + ea_t CallAddr = CallTargets[i]; + SMPFunction* ChildInstance = FuncMap[CallAddr]; + if (!ChildInstance) + { +#ifdef SMP_DEBUG_FUNC + // if a call target doesnt have a SMPFunction instance + // note it down + msg(" Function doesnt have SMPFunction instance at %x \n", CallAddr); +#endif + continue; + } + switch (ChildInstance->GetReturnAddressStatus()) + { + case FUNC_SAFE: + continue; + case FUNC_UNSAFE: + { + FuncAttrib->SetReturnAddressStatus(FUNC_UNSAFE); +#ifdef SMP_DEBUG_FUNC + // if a call target doesnt have a SMPFunction instance + // note it down + msg("Function marked as unsafe %s\n", FuncAttrib->GetFuncName()); +#endif + return FUNC_UNSAFE; + } + case FUNC_UNKNOWN: + { + set<const char*,LtStr>::const_iterator find = FuncNameSet.find(ChildInstance->GetFuncName()); + if (find == FuncNameSet.end()) + { + FuncNameSet.insert(ChildInstance->GetFuncName()); + FuncType Type = RecurseAndMarkRetAdd(ChildInstance); + FuncNameSet.erase(ChildInstance->GetFuncName()); + if (Type == FUNC_UNSAFE) + { + FuncAttrib->SetReturnAddressStatus(FUNC_UNSAFE); +#ifdef SMP_DEBUG_FUNC + // if a call target doesnt have a SMPFunction instance + // note it down + msg("Function marked as unsafe %s\n", FuncAttrib->GetFuncName()); +#endif + return FUNC_UNSAFE; + } + } + } + } + } +#ifdef SMP_DEBUG_FUNC + // if a call target doesnt have a SMPFunction instance + // note it down + msg("Function marked as safe %s\n", FuncAttrib->GetFuncName()); +#endif + + FuncAttrib->SetReturnAddressStatus(FUNC_SAFE); + return FUNC_SAFE; +} + // Debug output dump. void SMPProgram::Dump(void) { // Loop through all functions and call the debug Dump() for each. diff --git a/SMPProgram.h b/SMPProgram.h index 6788cd010b1305cab25418225259ab53e7f68417..3c016274dba28e210db60ca165b17ea47b34d40c 100644 --- a/SMPProgram.h +++ b/SMPProgram.h @@ -58,6 +58,14 @@ struct GlobalVar { set<pair<size_t, bool>, LessOff> FieldOffsets; // bool = accessed through index register by any instruction? }; +class LtStr{ + public: + bool operator() (const char* c1, const char* c2) const { + return strcmp(c1, c2) < 0; + } +}; + + // Class encapsulating all that the SMP static analyzer cares to know // about a whole program. class SMPProgram { @@ -77,10 +85,12 @@ private: // Data map<ea_t, SMPFunction *> FuncMap; // all functions in the program map<ea_t, struct GlobalVar> GlobalVarTable; // all global static variables + set<const char*,LtStr> FuncNameSet; // Methods void InitStaticDataTable(void); // Gather info about global static data locations void ComputeGlobalFieldOffsets(struct GlobalVar &CurrGlobal); + FuncType RecurseAndMarkRetAdd(SMPFunction*); }; // end class SMPProgram #endif