/* * SMPFunction.h - <see below>. * * Copyright (c) 2000, 2001, 2010 - University of Virginia * * This file is part of the Memory Error Detection System (MEDS) infrastructure. * This file may be used and modified for non-commercial purposes as long as * all copyright, permission, and nonwarranty notices are preserved. * Redistribution is prohibited without prior written consent from the University * of Virginia. * * Please contact the authors for restrictions applying to commercial use. * * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Author: University of Virginia * e-mail: jwd@virginia.com * URL : http://www.cs.virginia.edu/ * * Additional copyrights 2010, 2011, 2012, 2013, 2014, 2015 by Zephyr Software LLC * e-mail: {clc,jwd}@zephyr-software.com * URL : http://www.zephyr-software.com/ * */ #ifndef SMPFUNCTION_H #define SMPFUNCTION_H 1 // SMPFunction.h // // This header defines the interfaces needed for analyzing functions, performing live variable analysis, // putting code into SSA form, etc. #include <utility> #include <list> #include <vector> #include <map> #include <set> #include <cstddef> #include <stdio.h> class SMPProgram; // forward declaration so we can declare a pointer to an SMPProgram class STARS_IDA_Function_t; class STARS_IRDB_Function_t; #include "interfaces/STARSTypes.h" #include "interfaces/SMPDBInterface.h" #include "base/SMPDataFlowAnalysis.h" #include "base/SMPInstr.h" #include "base/SMPBasicBlock.h" #include "base/ProfilerInformation.h" #define SMP_DEBUG_STACK_GRANULARITY 0 // What is the default change to the stack pointer for a function? // NOTE: When we start handling different calling conventions beyond // the gcc model, we will have to make this a variable that gets // initialized. #define CALLING_CONVENTION_DEFAULT_FUNCTION_STACK_DELTA global_STARS_program->GetSTARS_ISA_Bytewidth() // What is the default stack delta from function entry to stack frame allocation? // This would only be used in resolving phase-ordering problems, and should be // eliminated if possible. #define CALLING_CONVENTION_DEFAULT_PREFRAMEALLOC_STACK_DELTA (-(global_STARS_program->GetSTARS_ISA_Bytewidth())) // What default value should we assign to alloca stack frame allocations? #define STARS_DEFAULT_ALLOCA_SIZE -32 // Use IDA info for switch tables to link indirect jumps to successor blocks? #define SMP_USE_SWITCH_TABLE_INFO 1 // Detect function code fragments that are not shared with another function. #define STARS_FIND_UNSHARED_CHUNKS 1 // Find and fix missing IDA Pro code xrefs. #define STARS_AUDIT_JUMP_XREFS 0 #define STARS_AUDIT_INDIR_JUMP_XREFS 1 // We can decide if conservative analysis of memory writes will cause us to avoid fast returns, // or merely shadow the return address. #define STARS_CONSERVATIVE_FAST_RETURNS 0 // Emit CS: or FS: or GS: etc. segment reg prefix if found in operand #define STARS_SPARK_EMIT_SEGMENT_REGS 0 struct LocalVar { char VarName[MAXSMPVARSTR]; long offset; std::size_t size; }; // Comparison function for sorting. bool LocalVarCompare(const LocalVar &LV1, const LocalVar &LV2); enum StackAccessType { STARS_STACK_UNKNOWN = 0, STARS_STACK_INARG = 1, STARS_STACK_RETURN_ADDRESS = 2, STARS_STACK_CALLEE_SAVED_REG = 3, STARS_STACK_LOCAL_FRAME = 4, STARS_STACK_OUTARG = 5 // could be part of LOCAL_FRAME initially, then changed when we detect usage as OUTARG }; // Entry for each byte address in the stack frame struct StackFrameEntry { struct LocalVar *VarPtr; // LocalVar that includes this offset long offset; // offset relative to incoming stack pointer bool Read; // was this entry ever read by an instruction? bool Written; // was this entry ever written by an instruction? bool AddressTaken; // did this entry have its address taken? bool ESPRelativeAccess; // ever accessed by ESP+const? bool EBPRelativeAccess; // ever accessed by EBP-const? (only if UseFP) bool IndexedAccess; // index reg of unknown value added to the base address StackAccessType EntryType; // inference based on location and accessing instructions }; enum FuncType { FUNC_UNKNOWN = 0, FUNC_SAFE = 1, FUNC_UNSAFE = 2, FUNC_SAFE_IF_CALLEES_ARE_SAFE = 3 }; enum UnsafeFastReturnReason { SAFE_FAST_RETURN = 0, UNSAFE_RETURN_ADDRESS = 1, RETURN_ADDRESS_WRITE = 2, RETURN_ADDRESS_READ = 4, INDIRECTLY_CALLED = 8, NO_CALLERS = 16, TAIL_CALL_TARGET = 32, RAUNSAFE_CALLEES = 64, MAKES_TAIL_CALL = 128, MULTIPLE_ENTRY_POINTS = 256, UNRESOLVED_INDIR_JUMP = 512, EH_FRAME_ENTRY = 1024 }; // For queries about the type of sink that a DEF eventually flows into. enum SinkSearchType { STARS_SINK_NONE = 0, STARS_SINK_MEMWRITE = 1, STARS_SINK_LOOP_CONDITION = 2, STARS_SINK_CALL = 4, STARS_SINK_RETURN = 8 }; // SPARK Ada recursive descent translation stack type; what we are currently translating // is on top. enum SPARKTranslationCFType { SPARK_INITIAL_BLOCK = 0, SPARK_THEN_CLAUSE = 1, SPARK_ELSE_CLAUSE = 2, SPARK_SWITCH = 3, SPARK_LOOP = 4 }; // Loop types for structuring and decompilation #define STARS_LOOP_TYPE_UNKNOWN 0 #define STARS_TOP_TESTING_LOOP 1 #define STARS_BOTTOM_TESTING_LOOP 2 #define STARS_INFINITE_OR_MIDDLE_TESTING_LOOP 3 #define STARS_CONSTANT_ITERATIONS_TOP_TESTING_LOOP 4 // A struct used to describe the comparison used to exit a loop or loop back. // For loops that could not be analyzed, CompareOperator is SMP_NULL_OPERATOR. struct LoopComparison { DefOrUse Operand1; DefOrUse Operand2; STARS_ea_t CompareAddr; // could be address of a decrement inst, for the decrement+COND_BRANCH type of loop SMPoperator CompareOperator; bool ExitsLoop; // comparison could be used to loop back, in which case invert to exit loop. }; // A struct to describe the triple (Multiplier * BasicInductionVar + Addend) that can be // used to define any induction variable. The basic induction variable of a family can // be represented with a Multiplier of one and an Addend of zero. struct InductionVarTriple { DefOrUse InductionVar; DefOrUse Multiplier; DefOrUse Addend; bool SubtractAddend; // Multiplier * BasicInductionVar - Addend }; // Are the operands, SSA numbers, and SubtractAddend fields identical? bool EqualInductionVars(const InductionVarTriple &IV1, const InductionVarTriple &IV2); // Dependent induction variable: At DIVDefAddr, DIV is defined by an operation IVExpr performed upon an earlier IV in the family. struct DependentInductionVar { struct InductionVarTriple IVExpr; DefOrUse DIV; STARS_ea_t DIVDefAddr; STARSExpression *DIVInitExpr; STARSExpression *DIVLimitExpr; }; // An induction variable family is composed of a basic induction variable and // zero or more dependent induction variables, where each dependent induction // variable can be represented as a linear function m*i+a of the basic induction variable i. typedef std::vector<struct DependentInductionVar> STARSDepIndVarVector; typedef STARSDepIndVarVector::iterator STARSDepIndVarIter; struct InductionVarFamily { int BIVIncomingSSANum; // SSA number coming into the loop for BasicInductionVar STARS_ea_t BIVIncomingDefAddr; std::vector<STARS_ea_t> BIVInsideLoopDefAddrs; struct InductionVarTriple BasicInductionVar; STARSDepIndVarVector DependentInductionVars; STARSExpression *BIVInitExpr; STARSExpression *BIVLimitExpr; }; // We can have multiple basic induction vars for one loop, hence multiple families in a list. typedef std::list<struct InductionVarFamily> STARSInductionVarFamilyList; typedef STARSInductionVarFamilyList::iterator STARSInductionVarFamilyIter; // triple: memory write expr, ByteWidth, index into vector of stack pointer copy InstAddrs typedef std::list<std::pair<STARSExprSetIter, std::pair<std::size_t, int> > > STARSMemWriteExprsList; typedef STARSMemWriteExprsList::iterator STARSMemWriteExprListIter; // Debug dump of induction variable. void DumpInductionVar(const struct InductionVarTriple IndVar); // Debug dump of InductionVarFamily. void DumpInductionVarFamily(const struct InductionVarFamily IVFamily); // Determine whether we have an incrementing or decrementing loop based on // the BasicInductionVar. bool IsPositiveIncrementBIV(const struct InductionVarTriple BIV); static char StaticFuncName[MAXSMPSTR]; // Class encapsulating all that the SMP static analyzer cares to know // about a function. class SMPFunction { public: // Constructors and destructors. SMPFunction(STARS_Function_t *Info, SMPProgram *pgm); // Default constructor ~SMPFunction(); // Get methods inline SMPProgram *GetProg(void) const { return Program; }; inline const char *GetFuncName(void) const { SMP_get_func_name(GetFirstFuncAddr(), StaticFuncName, MAXSMPSTR-1); return StaticFuncName; }; STARS_Function_t *GetFuncInfo(void) const; inline STARS_ea_t GetFirstFuncAddr(void) const { return FirstEA; }; uint16_t GetJumpToFollowNodeCounter(STARS_ea_t InstAddr) const; inline long GetTypedDefs(void) const { return TypedDefs; }; inline long GetUntypedDefs(void) const { return UntypedDefs; }; inline long GetTypedPhiDefs(void) const { return TypedPhiDefs; }; inline long GetUntypedPhiDefs(void) const { return UntypedPhiDefs; }; inline long GetSafeBlocks(void) const { return SafeBlocks; }; inline long GetUnsafeBlocks(void) const { return UnsafeBlocks; }; inline std::size_t GetInstCount(void) const { return Instrs.size(); }; inline unsigned short GetIncomingArgCount(void) const { return InArgCount; }; inline STARS_sval_t GetNetStackPtrDelta(void) const { return NetStackDelta; }; inline STARS_sval_t GetPreAllocationStackPtrDelta(void) const { return PreAllocStackDelta; }; inline STARS_sval_t GetFramePtrStackDelta(void) const { return FramePointerStackDelta; }; inline STARS_sval_t GetMaxDirectStackAccessDelta(void) const { return MaxDirectStackAccessDelta; }; inline STARS_ea_t GetFirstFrameAllocInstAddr(void) const { return LocalVarsAllocInstr; }; inline STARS_asize_t GetLocalVarsSize(void) const { return LocalVarsSize; }; inline long GetLocalVarOffsetLimit(void) const { return LocalVarOffsetLimit; }; inline STARSOpndSetIter GetFirstGlobalName(void) { return GlobalNames.begin(); }; inline STARSOpndSetIter GetLastGlobalName(void) { return GlobalNames.end(); }; inline std::size_t NumGlobalNames(void) { return GlobalNames.size(); }; inline STARSOpndSetIter FindGlobalName(const STARSOpndTypePtr &SearchOp) { return GlobalNames.find(SearchOp); }; inline std::list<SMPInstr *>::iterator GetFirstInstIter(void) { return Instrs.begin(); }; inline std::list<SMPInstr *>::iterator GetLastInstIter(void) { return Instrs.end(); }; STARSOpndSetIter GetFirstLiveIn(void); // LiveInSet.begin() STARSOpndSetIter GetLastLiveIn(void); // LiveInSet.end() STARSOpndSetIter GetFirstLiveOut(void); // LiveOutSet.begin() STARSOpndSetIter GetLastLiveOut(void); // LiveOutSet.end() STARSOpndSetIter GetFirstVarKill(void); // KillSet.begin() STARSOpndSetIter GetLastVarKill(void); // KillSet.end() inline FuncType GetReturnAddressStatus(void) const { return ReturnAddrStatus; }; inline unsigned short GetFastReturnStatus(void) const { return FastReturnStatus; }; // exposing the start address of the function. Used in RecurseAndMark inline const STARS_ea_t GetStartAddr(void) const { return FirstEA; }; inline const std::vector<STARS_ea_t> GetCallTargets(void) const { return AllCallTargets; }; inline const std::set<STARS_ea_t> GetReturnTargets(void) const { return ReturnTargets; }; inline std::size_t GetNumCallTargets(void) const { return AllCallTargets.size(); }; inline STARS_ea_t GetCallTargetAddr(std::size_t index) const { return AllCallTargets.at(index); }; bool GetIsSpeculative() { return IsSpeculative; } inline std::size_t GetNumCallers(void) const { return AllCallSources.size(); }; bool MDGetFGStackLocInfo(STARS_ea_t InstAddr, const STARSOpndTypePtr &TempOp, struct FineGrainedInfo &FGEntry); // Return fine grained stack entry for stack op TempOp from instruction at InstAddr STARS_ea_t GetGlobalDefAddrForRegHash(int RegHashValue); // retrieve from GlobalDefAddrBySSA or return BADADDR STARS_ea_t GetGlobalDefAddr(const STARSOpndTypePtr &DefOp, int SSANum); // retrieve from GlobalDefAddrBySSA or return BADADDR std::vector<SMPInstr *>::iterator GetBlockInstIterBySSA(const STARSOpndTypePtr &DefOp, int SSANum); // return iterator within DEF block int GetBlockNumForPhiDef(const STARSOpndTypePtr &DefOp, int SSANum); SMPBasicBlock *GetBlockFromInstAddr(STARS_ea_t InstAddr); // retrieve from InstBlockMap or assert int GetBlockNumFromInstAddr(STARS_ea_t InstAddr); // return -1 if not in InstBlockMap, block # otherwise std::list<SMPBasicBlock *>::iterator GetBlockIter(SMPBasicBlock *FindBlock); // Find FindBlock in Blocks, return iterator. inline SMPBasicBlock *GetBlockByNum(std::size_t BlockIndex) const { return RPOBlocks.at(BlockIndex); }; inline STARSCFGBlock *GetCFGBlockByNum(std::size_t BlockIndex) const { return ShadowCFGBlocks.at(BlockIndex); }; inline std::list<SMPBasicBlock *>::iterator GetLastBlock(void) { return Blocks.end(); }; SMPInstr *GetInstFromAddr(STARS_ea_t InstAddr); STARS_ea_t GetFirstUnprocessedCallee(void); // first addr of first callee in AllCallTargets with Processed == false inline std::size_t GetNumBlocks(void) const { return Blocks.size(); }; STARSOpndTypePtr GetNormalizedOperand(STARS_ea_t InstAddr, const STARSOpndTypePtr &RTLop); // Return RTLop if not stack opnd; return normalized RTLop otherwise. inline int GetReturnRegType(STARS_regnum_t RegNum) const { return ((RegNum < (decltype(RegNum))ReturnRegTypes.size()) ? (int) ReturnRegTypes[RegNum] : 0); }; inline struct FineGrainedInfo GetReturnRegFGInfo(STARS_regnum_t RegNum) const { return ReturnRegFGInfo.at(RegNum); }; inline std::size_t GetReturnRegFGInfoSize(void) const { return ReturnRegFGInfo.size(); }; SMPOperandType GetIncomingRegType(STARS_regnum_t RegNum); // Get reg type from all call sites. bool GetMarkerInstDefType(STARSOpndTypePtr &LiveInOp, SMPOperandType &MarkerDefType); // return true if LiveInOp found in MarkerInst DEFs inline std::map<STARS_ea_t, STARSOpndTypePtr>::iterator FindLeaOperand(STARS_ea_t addr) { return LeaInstOpMap.find(addr); }; inline std::map<STARS_ea_t, STARSOpndTypePtr>::iterator GetLastLeaOperand(void) { return LeaInstOpMap.end(); }; inline STARSSCCPMapIter FindConstValue(int DefHashValue) { return ConstantDefs.find(DefHashValue); }; inline STARSSCCPMapIter GetLastConstValueIter(void) { return ConstantDefs.end(); }; // Fetch SCCP constant iter into block- or func-level constants. True only if const value. bool FindSCCPConstIter(SMPBasicBlock *CurrBlock, int RegHashValue, bool LocalName, STARSSCCPMapIter &ConstIter); inline std::size_t GetNumLoops(void) const { return LoopCount; }; inline int GetLoopType(std::size_t LoopNumber) const { return LoopTypesByLoopNum.at(LoopNumber); }; int GetLoopNumFromTestBlockNum(int BlockNum) const; int GetInnermostLoopNum(int BlockNum) const; // find innermost loop # for BlockNum int GetOutermostLoopNum(int BlockNum) const; // find outermost loop # for BlockNum STARSExprBoundsIter GetFirstLoopMemWriteExprBoundsIter(std::size_t LoopIndex) const { return LoopMemWriteBoundsExprs[LoopIndex].cbegin(); }; STARSExprBoundsIter GetLastLoopMemWriteExprBoundsIter(std::size_t LoopIndex) const { return LoopMemWriteBoundsExprs[LoopIndex].cend(); }; STARSExprBoundsIter GetFirstLoopMemWriteExpandedExprBoundsIter(std::size_t LoopIndex) const { return LoopMemWriteBoundsExprsExpanded[LoopIndex].cbegin(); }; STARSExprBoundsIter GetLastLoopMemWriteExpandedExprBoundsIter(std::size_t LoopIndex) const { return LoopMemWriteBoundsExprsExpanded[LoopIndex].cend(); }; int FindInArgNumFromCopyAddr(STARS_ea_t CopyInstAddr); // return -1 if not found in InArgPointerCopyAddrs, InArg position # otherwise std::set<SMPPhiFunction, LessPhi>::iterator GetPhiIterForPhiDef(std::size_t BlockNumber, const STARSOpndTypePtr &DefOp, int SSANum); // Given block # and PhiDef op_t and SSANum, return the Phi iterator or assert. // Eight methods to get values from the maps of global reg/SSA to FG info. // For local names, see corresponding methods in SMPBasicBlock. unsigned short GetDefSignMiscInfo(int DefHashValue); unsigned short GetStackDefSignMiscInfo(STARS_ea_t InstAddr); unsigned short GetUseSignMiscInfo(int UseHashValue); unsigned short GetStackUseSignMiscInfo(STARS_ea_t InstAddr); unsigned short GetDefWidthTypeInfo(int DefHashValue); unsigned short GetUseWidthTypeInfo(int UseHashValue); struct FineGrainedInfo GetDefFGInfo(int DefHashValue); struct FineGrainedInfo GetUseFGInfo(int UseHashValue); ControlFlowType GetControlFlowType(STARS_ea_t InstAddr) const; std::size_t GetSwitchJumpMapSize(void) const { return SwitchJumpMap.size(); }; std::size_t GetSwitchInfoArraySize(void) const { return SwitchInfoArray.size(); }; inline int GetMaxStackSSANum(void) const { return MaxDirectStackAccessSSANum; }; inline int GetMaxRegSSANum(void) const { return MaxRegSSANum; }; int GetLoopNumFromHeaderBlockNum(const int HeaderBlockNum) const; // return -1 if HeaderBlockNum is not a loop header block # std::size_t FindLoopNumFromHeadBlockNum(int LoopHeaderBlockNum) const; // find loop # corresponding to header block num // inline STARSExpression *GetLoopMemWriteRangeExpr(std::size_t LoopNum) const { return LoopMemWriteRangeExprs[LoopNum]; }; inline std::size_t GetNumInArgsUsedInMemWrites(std::size_t LoopPlusOne) const { return InArgsUsedInMemWriteByteWidths[LoopPlusOne].size(); }; inline std::size_t GetInArgMemWriteWidth(std::size_t LoopPlusOne, std::size_t index) const { return InArgsUsedInMemWriteByteWidths[LoopPlusOne][index].second; }; inline STARSExprSetIter GetInArgExprUsedInMemWrite(std::size_t LoopPlusOne, std::size_t index) const { return InArgsUsedInMemWriteByteWidths[LoopPlusOne][index].first; }; inline std::size_t GetNumInheritedMemWriteExprs(std::size_t LoopIndexPlusOne) const { return MemAddrExprWidthsFromCallees[LoopIndexPlusOne].size(); }; inline std::size_t GetInheritedMemWriteWidth(std::size_t LoopIndexPlusOne, std::size_t ExprIndex) const { return MemAddrExprWidthsFromCallees[LoopIndexPlusOne][ExprIndex].second; }; inline STARSExprSetIter GetInheritedMemWriteExpr(std::size_t LoopIndexPlusOne, std::size_t ExprIndex) const { return MemAddrExprWidthsFromCallees[LoopIndexPlusOne][ExprIndex].first; }; inline std::size_t GetNumStringMemWriteRangeExprs(std::size_t LoopIndexPlusOne) const { return StringMemWriteRangeWidths[LoopIndexPlusOne].size(); }; inline std::size_t GetStringMemWriteRangeWidth(std::size_t LoopIndexPlusOne, std::size_t ExprIndex) const { return StringMemWriteRangeWidths[LoopIndexPlusOne][ExprIndex].first; }; inline STARSExprSetIter GetStringMemWriteRangeExpr(std::size_t LoopIndexPlusOne, std::size_t ExprIndex) const { return StringMemWriteRangeWidths[LoopIndexPlusOne][ExprIndex].second; }; inline std::size_t GetNumCalleeLoopMemExprs(void) const { return LoopMemAddrExprWidthsFromCallees.size(); }; // inline std::size_t GetCalleeLoopMemWriteWidth(std::size_t index) const { return LoopMemAddrExprWidthsFromCallees[index].second; }; // inline STARSExprSetIter GetCalleeLoopExprUsedInMemWrite(std::size_t index) const { return LoopMemAddrExprWidthsFromCallees[index].first; }; STARSInArgMap::const_iterator GetAddressRegToInArgMapping(const STARS_ea_t InstAddr) const { return MemWriteToInArgMap.find(InstAddr); }; STARSInArgMap::const_iterator GetLastAddressRegToInArgMapping(void) const { return MemWriteToInArgMap.cend(); }; const std::bitset<1 + MD_LAST_REG_NO> &GetInputRegs(void) const { return InputRegs; }; const std::bitset<1 + MD_LAST_REG_NO> &GetOutputRegs(void) const { return OutputRegs; }; const std::bitset<1 + MD_LAST_REG_NO> &GetPreservedRegs(void) const { return PreservedRegsBitmap; }; const std::bitset<1 + MD_LAST_REG_NO> &GetCalleePreservedRegs(void) const { return CalleePreservedRegs; }; uint32_t GetTaintInArgPositions(void) const { return TaintInArgPosBits; }; std::string GetFuncSPARKSuffixString(void) const; // produce string "_hexaddress" for first address in func // Set methods void ResetJumpToFollowNodeCounter(STARS_ea_t InstAddr); // Set counter to zero, or insert zero counter if none found void IncrementJumpToFollowNodeCounter(STARS_ea_t InstAddr); // Increment counter, or insert count of 1 if none found inline void IncTypedPhiDefs(void) { ++TypedPhiDefs; }; inline void IncUntypedPhiDefs(void) { ++UntypedPhiDefs; }; inline void DecTypedPhiDefs(void) { --TypedPhiDefs; }; inline void DecUntypedPhiDefs(void) { --UntypedPhiDefs; }; inline void SetIDAReturnAddressOffset(long NewOffset) { IDAReturnAddressOffset = NewOffset; }; inline void SetLocalVarOffsetLimit(long NewLimit) { LocalVarOffsetLimit = NewLimit; }; inline void PushBackLocalVarEntry(struct LocalVar TempLocal) { LocalVarTable.push_back(TempLocal); }; inline void SetSharedChunks(bool v) { GetFuncInfo()->SetSharedChunks(v); }; // inline void SetSharedChunks(bool v) { SharedChunks=v; }; inline void SetReturnAddressStatus(FuncType funcType) { ReturnAddrStatus = funcType; } inline void SetFuncProcessed(bool Status) { FuncProcessed = Status; return; }; inline void SetHasIndirectCalls(void) { IndirectCalls = true; }; inline void SetHasUnresolvedIndirectCalls(void) { UnresolvedIndirectCalls = true; }; inline void SetHasSystemCalls(void) { SystemCalls = true; }; inline void SetAltersSPARKMemory(void) { AltersMemory = true; }; inline void SetFuncSafe(bool Status) { SafeFunc = Status; return; }; inline void SetSpecFuncSafe(bool Status) { SpecSafeFunc = Status; return; }; inline void SetNeedsFrame(bool Status) { NeedsStackReferent = Status; return; }; inline void SetSpecNeedsFrame(bool Status) { SpecNeedsStackReferent = Status; return; }; inline void SetUnsafeForFastReturns(bool Status, UnsafeFastReturnReason Reason) { UnsafeForFastReturns = Status; FastReturnStatus |= (int) Reason; return; }; inline void SetIsSpeculative(bool IsS) { IsSpeculative = IsS; }; inline void SetIsMutuallyRecursive(void) { MutuallyRecursive = true; }; inline void SetIsCalledFromOrphanedCode(void) { CalledFromOrphanCode = true; }; inline void SetIsTailCallChainFromOrphanedCode(void) { TailCallChainFromOrphanCode = true; }; inline void SetCallsNonReturningFunc(void) { CallsNonReturningFunc = true; }; inline void SetCalleeChainCallsNonReturningFunc(void) { CalleeChainCallsNonReturningFunc = true; }; inline void SetHasHashingCode(bool Hashes) { HasHashingCode = Hashes; }; inline void SetHasMallocCall(void) { HasMallocCall = true; }; void AddCallSource(STARS_ea_t addr); // Add a caller to the list of all callers of this function. bool AddDirectCallTarget(STARS_ea_t addr); // Add a direct call target; return true if new target, false if target already added bool AddIndirectCallTarget(STARS_ea_t addr); // Add an indirect call target; return true if new target, false if target already added std::set<STARS_ea_t>::iterator RemoveDirectCallTarget(STARS_ea_t TargetAddr); // Remove TargetAddr from DirectCallTargets and AllCallTargets. bool RemoveIndirectCallTarget(STARS_ea_t TargetAddr); // Remove TargetAddr from IndirectCallTargets and AllCallTargets. inline void AddResolvedBranch(const STARS_ea_t BranchAddr) { (void) ResolvedCondBranches.insert(BranchAddr); } inline void AddMallocCallWithInArg(const CallAddrArgDefAddrPair InsertVal) { (void) MallocCallInArgsMap.insert(InsertVal); } void AddBufferCallWithInArg(const CallAddrArgDefAddrPair InsertVal); inline void SetMaxStackSSANum(int NewMaxSSANum) { MaxDirectStackAccessSSANum = NewMaxSSANum; }; inline void SetMaxRegSSANum(int NewMaxSSANum) { MaxRegSSANum = NewMaxSSANum; }; inline void SetCallerSavedLocalReg(STARS_regnum_t RegNum) { CallerSavedLocalRegsBitmap.set(RegNum); }; void UpdateLocalMaxSSANum(int CurrSSANum) { if (CurrSSANum > MaxLocalSSANum) MaxLocalSSANum = CurrSSANum; }; void AddLeaOperand(STARS_ea_t addr, STARSOpndTypePtr LeaOperand); // add map entry to LeaInstOpMap void AddNormalizedStackOperand(STARSOpndTypePtr OldOp, STARS_ea_t InstAddr, STARSOpndTypePtr NormalizedOp); // add to map for RTL lookup later void UpdateMaxDirectStackAccessOffset(STARS_sval_t NewOffset); // Update MaxDirectStackAccessDelta void MarkTaintInArgReg(std::size_t ArgPos) { TaintInArgPosBits |= (1 << ArgPos); }; void SetControlFlowType(STARS_ea_t InstAddr, ControlFlowType JumpTypeCode); // insert into ControlFlowMap STARSSCCPMapIter InsertGlobalConstValue(int DefHashValue, struct STARS_SCCP_Const_Struct NewConstEntry); // Insert SCCP value for global name; change if already found. // Eight methods to set values into the maps of global reg/stack/SSA to FG info. // For local names, see corresponding methods in SMPBasicBlock. void UpdateDefSignMiscInfo(int DefHashValue, unsigned short NewInfo); void UpdateStackDefSignMiscInfo(STARS_ea_t InstAddr, unsigned short NewInfo); void UpdateUseSignMiscInfo(int UseHashValue, unsigned short NewInfo); void UpdateStackUseSignMiscInfo(STARS_ea_t InstAddr, unsigned short NewInfo); void UpdateDefWidthTypeInfo(int DefHashValue, unsigned short NewInfo); void UpdateUseWidthTypeInfo(int UseHashValue, unsigned short NewInfo); void UpdateDefFGInfo(int DefHashValue, struct FineGrainedInfo NewFG); void UpdateUseFGInfo(int UseHashValue, struct FineGrainedInfo NewFG); void ClearDefSignedness(int DefHashValue); bool MDUpdateFGStackLocInfo(STARS_ea_t InstAddr, const STARSOpndTypePtr &TempOp, struct FineGrainedInfo NewFG); // Return true if we update fine grained stack entry for stack op TempOp from instruction at InstAddr bool AddSwitchTableInfo(STARS_ea_t IndirJumpAddr, struct SwitchTableInfo TableInfo); // push_back new entries on switch data structures // Query methods inline bool IsFuncProcessed(void) const { return FuncProcessed; }; inline bool IsFuncEmpty(void) const { return (0 >= BlockCount); }; inline bool FuncReturnsToCaller(void) const { return FuncInfo->HasReturnPoints(); }; inline bool StackPtrAnalysisSucceeded(void) const { return AnalyzedSP; }; inline bool HasSTARSStackPtrAnalysisCompleted(void) const { return STARSStackPtrAnalysisPerformed; }; inline bool AreReturnTargetsComputed(void) const { return ReturnTargetsComputed; }; inline bool HasExplicitReturnInstruction(void) const { return HasReturnInst; }; inline bool HasIndirectCalls(void) const { return IndirectCalls; }; inline bool HasUnresolvedIndirectCalls(void) const { return UnresolvedIndirectCalls; }; inline bool HasIndirectJumps(void) const { return IndirectJumps; }; inline bool HasUnresolvedIndirectJumps(void) const { return UnresolvedIndirectJumps; }; inline bool HasSystemCalls(void) const { return SystemCalls; }; inline bool IsDirectlyRecursive(void) const { return DirectlyRecursive; }; inline bool IsMutuallyRecursive(void) const { return MutuallyRecursive; }; inline bool HasSharedChunks(void) const { return GetFuncInfo()->HasSharedChunks(); }; // inline bool HasSharedChunks(void) const { return SharedChunks; }; inline bool HasGoodRTLs(void) const { return BuiltRTLs; }; inline bool HasGoodSSAForm(void) const { return HasGoodSSA; }; inline bool HasReducibleControlFlow(void) const { return HasReducibleCFG; }; inline bool HasStructuredControlFlow(void) const { return HasStructuredCFG; }; inline bool HasPushAfterFrameAlloc(void) const { return PushAfterLocalVarAlloc; }; inline bool IsLinkerStub(void) const { return LinkerStub; }; inline bool IsThunkFunction(void) const { return ThunkFunc; }; inline bool IsInstIDInFunc(STARS_ea_t addr) { return this->FuncInfo->IsInstIDInFunc(addr); }; inline bool IsLibFunc(void) const { return LibFunc; }; inline bool IsLeaf(void) const { return (!IndirectCalls && (!IsLinkerStub()) && (DirectCallTargets.empty() || ((1 == DirectCallTargets.size()) && IsDirectlyRecursive()))); }; inline bool IsSafe(void) const { return SafeFunc; }; // safe to follow stack access DEF-USE chains inline bool IsSpecSafe(void) const { return SpecSafeFunc; }; // safe if we can resolve indirect calls at run time in mmStrata inline bool IsSafeCallee(void) const { return SafeCallee; }; inline bool IsSpecSafeCallee(void) const { return SpecSafeCallee; }; inline bool IsUnsafeForFastReturns(void) const { return UnsafeForFastReturns; }; inline bool NeedsStackFrame(void) const { return NeedsStackReferent; }; inline bool SpecNeedsStackFrame(void) const { return SpecNeedsStackReferent; }; inline bool WritesAboveReturnAddress(void) const { return WritesAboveRA; }; // don't use before fixing this member inline bool OutArgsRegionComputed(void) const { return OutgoingArgsComputed; }; bool IsInOutgoingArgsRegion(const STARSOpndTypePtr &DestOp); // Does DestOp fall within outgoing args area? bool IsInIncomingArgsRegion(SMPInstr *SourceInst, const STARSOpndTypePtr &SourceOp) const; // Does SourceOp from SourceInst fall within incoming args area? inline bool IsGlobalName(const STARSOpndTypePtr &RefOp) const { return (GlobalNames.end() != GlobalNames.find(RefOp)); }; inline bool UsesFramePointer(void) const { return UseFP; }; inline bool FuncHasHashingCode(void) const { return HasHashingCode; }; inline bool HasGoodFGStackTable(void) const { return (!(NegativeOffsetFineGrainedStackTable.empty())); }; bool IsLiveIn(const STARSOpndTypePtr &CurrOp) const; inline bool IsLiveOut(const STARSOpndTypePtr &CurrOp) const { return (LiveOutSet.end() != LiveOutSet.find(CurrOp)); } inline bool IsVarKill(const STARSOpndTypePtr &CurrOp) const { return (KillSet.end() != KillSet.find(CurrOp)); } inline bool IsResolvedBranch(const STARS_ea_t BranchAddr) const { return (ResolvedCondBranches.find(BranchAddr) != ResolvedCondBranches.cend()); } bool IsInStackPtrCopySet(const STARSOpndTypePtr &CurrOp); bool IsDefnInStackPtrCopySet(const STARSOpndTypePtr &CurrOp, const STARS_ea_t &DefAddr) const; inline bool DoesStackFrameExtendPastStackTop(void) const { return StackFrameExtendsPastStackTop; }; inline bool IsRegPreserved(std::size_t RegNum) const { return (PreservedRegsBitmap[RegNum] != 0); }; inline bool IsCallerSavedLocalReg(std::size_t RegNum) const { return (CallerSavedLocalRegsBitmap[RegNum] != 0); }; inline bool IsPossibleIndirectCallTarget(void) const { return PossibleIndirectCallTarget; }; inline bool IsCalledFromOrphanedCode(void) const { return CalledFromOrphanCode; }; inline bool IsTailCallChainFromOrphanedCode(void) const { return TailCallChainFromOrphanCode; }; inline bool HasCallToNonReturningFunc(void) const { return CallsNonReturningFunc; }; inline bool HasCalleeChainWithNonReturningFunc(void) const { return CalleeChainCallsNonReturningFunc; }; inline bool HasCallToMalloc(void) const { return HasMallocCall; }; inline bool TranslatingLoopToProc(void) const { return TranslatingSPARKLoop; }; inline bool IsMultiEntry(void) const { return MultipleEntryPoints; }; inline bool DoesLoopWriteMemory(std::size_t LoopIndex) const { return LoopWritesMemory.at(LoopIndex); }; inline bool DoesLoopReadMemory(std::size_t LoopIndex) const { return LoopReadsMemory.at(LoopIndex); }; inline bool DoesLoopUseStackPtrRegs(std::size_t LoopIndex) const { return LoopUsesStackPtrRegs.at(LoopIndex); }; inline bool DoesLoopHavePreconditions(std::size_t LoopIndex) const { return LoopHasPreconditions.at(LoopIndex); }; bool IsLoopInductionVar(std::size_t LoopIndex, STARSOpndTypePtr &CurrOp, SMPInstr *UseInst, STARSInductionVarFamilyIter &ListIter, std::size_t &FamilyIndex); // For CurrOp in LoopIndex, return iterator and position in family if true bool IsLoopInductionVarForAnySSANum(std::size_t LoopIndex, const STARSOpndTypePtr &CurrOp, STARSInductionVarFamilyIter &ListIter, std::size_t &FamilyIndex); // Relax the requirement to match SSA number to IV bool IsLoopNestInductionVar(const STARSOpndTypePtr &CurrOp, SMPInstr *UseInst, STARSInductionVarFamilyIter &ListIter, std::size_t &FamilyIndex, int &LoopIndex); // For CurrOp in loop nest including UseInst, return iterator and position in family if true inline bool AltersSPARKMemory(void) const { return AltersMemory; }; inline bool UsesInArgsForLoopMemWrites(void) const { return HasLoopInArgMemWrites; }; inline bool CalleeUsesInArgsForLoopMemWrites(void) const { return CalleeHasLoopInArgMemWrites; }; inline bool IsCriticalInArg(std::size_t ArgPos) const { return (0 != (TaintInArgPosBits & (1 << ArgPos))); }; inline bool DoesLoopHaveArgs(int LoopNum) const { return LoopMemRangeInArgRegsBitmap[(size_t) LoopNum].any(); }; // Printing methods void Dump(void); // debug dump // Analysis methods void ResetProcessedBlocks(void); // Set Processed flag to false in all blocks void MarkDominatedBlocks(int CurrBlockNum); // Set Processed flag for all blocks below CurrBlockNum in DomTree. void ResetSCCPVisitedBlocks(void); // Set SCCPVisited flag to false in all blocks void RPONumberBlocks(void); // Number basic blocks in reverse post-order and place pointers in RPOBlocks. int GetFallThroughPredBlockNum(int CurrBlockNum); // return block # of block that falls through to CurrBlockNum; SMP_BLOCKNUM_UNINIT if none void RemoveBlock(SMPBasicBlock *CurrBlock, std::list<SMPBasicBlock *>::iterator &BlockIter, bool IBTarget = false); // Remove a basic block and its instructions. void RemoveCallingBlocks(void) const; // Func is empty, so add all blocks that call it to Program->BlocksPendingRemoval. void ComputeGlobalSets(void); // compute LiveOut, Kill sets for function bool ComputeInOutRegs(bool InheritPass, bool &WritesMem, bool &CallChainNonReturning); // compute InputRegs and OutputRegs, only inherit from callees on InheritPass void BuildLoopingStringMemExprs(SMPBasicBlock *CurrBlock, SMPInstr *CurrInst); // Build lower and upper bounds exprs for memory writes in looping string opcode void FindMatchingMemDEFAddrs(STARS_ea_t UseAddr, SMPBasicBlock *CurrBlock, STARSOpndTypePtr &MemUseOp, std::list<STARS_ea_t> &MemDefAddrs, std::set<int> &AddressRegs); // Fill MemDefAddrs with inst addrs that DEF MemUseOp, tracing back from UseAddr. STARS_sval_t GetLoopIncomingStackDelta(std::size_t LoopNum) const; // Find first inst in loop, return its stack delta. void AnalyzeFunc(void); // Analyze all instructions in function void AdvancedAnalysis(void); // Analyses that fix IDA stack frame info, sync RTLs with DEFs and USEs, Live Variable Analysis bool AdvancedAnalysis2(void); // fix call inst DEFs and USEs; return true if changes void AdvancedAnalysis3(void); // Analyses that depend on whole program info but not SSA. std::size_t UnprocessedCalleesCount(void); // Count of callees that have FuncProcessed == false STARS_sval_t GetStackAdjustmentForCallee(STARS_ea_t CallAddr); // Get stack pointer adjustment in basic block, after CallAddr STARS_sval_t GetStackDeltaForCallee(STARS_ea_t CallTargetAddr); // Get stack pointer delta for callee function, which starts at CallTargetAddr STARS_sval_t ComputeGlobalStackAdjustment(void); // Find consistent or smallest stack adjustment after all calls to this function, program-wide void ComputeTempReachingDefs(const STARSOpndTypePtr &TempOp, STARS_ea_t UseAddr); // Compute the TempReachingDefs set that reaches UseAddr for TempOp void ComputeTempStackDeltaReachesList(const STARSOpndTypePtr &TempOp); // Compute the TempStackDeltaReachesList for TempOp for all DefAddrs in TempReachingDefs bool FindReachingStackDelta(STARS_sval_t &StackDelta); // Find maximum stack delta in TempStackDeltaReachesList; return true if one consistent delta is in the list void GatherIncomingArgTypes(void); // Use the SSA marker inst to record incoming arg types in member InArgTypes. void TraceIncomingArgs(void); // Find all copies of incoming args and record in bitsets void AnalyzeBufferUses(void); // Analyze buffer sizes and the use of buffers by vulnerable library funcs. bool ComputeReturnTargets(bool FirstIteration); // Determine inst ID set that func could return to, including tail call issues; return true if set changes void EmitAnnotations(FILE *AnnotFile, FILE *InfoAnnotFile); void PreProcessForSPARKAdaTranslation(void); // Perform look-ahead steps needed before translation to SPARK Ada. bool EmitSPARKLoopMemRangePostCondition(FILE *HeaderFile, FILE *BodyFile, STARS_ea_t LoopAddr, bool PostPrintStarted); // specify mem ranges that loop changes; return true if printed void EmitSPARKStackMemRangePostCondition(FILE *HeaderFile, std::size_t LoopIndex, STARS_ea_t LoopAddr, bool PostPrintStarted); // specify stack mem ranges that loop changes void EmitSPARKAdaForLoopLimit(FILE *BodyFile, STARS_ea_t LoopAddr); // emit loop invariant for basic induction var bound void EmitIncomingLoopRegExprs(FILE *OutputFile, std::size_t LoopNum, bool LoopInvariantSection); // emit LoopRegSourceExprPairs void EmitSPARKLoopBIVLimits(FILE *BodyFile, STARS_ea_t LoopAddr, std::size_t LoopIndex, bool PragmaAssume); // Emit Assumes and Loop_Invariants for loop BIV and mem ranges. void EmitSPARKMemRangeLoopInvariants(FILE *BodyFile, std::size_t LoopIndex, STARS_sval_t IncomingStackDelta, bool LoopInvariant, std::size_t &OutputCount); // Emit only the mem range Loop_Invariant (or pragma Assert) void EmitFuncSPARKAda(void); // Emit SPARK Ada translation of function void SetMarkerInstDefs(void); // Set LiveIn operands as DEFs in SSA marker pseudo-inst at function entry. void LiveVariableAnalysis(bool Recomputing); // Perform Live Variable Analysis across all blocks void RecomputeStackLVA(void); // After normalization, re-do stack ops in LVA sets. void RecomputeSSA(void); // Recompute LVA and SSA and all dependent data structures now that unreachable blocks have been removed. void ComputeSSA(void); // Compute SSA form data structures bool DoesBlockDominateBlock(int HeadBlockNum, int TailBlockNum) const; // Does basic block HeadBlockNum dominate basic block TailBlockNum? bool IsBlockInAnyLoop(int BlockNum) const; // Is block (with block # BlockNum) inside any loop? bool IsBlockInLoop(int BlockNum, std::size_t LoopNum); // Is block (with block # BlockNum) inside loop # LoopNum? bool AreBlocksInSameLoops(const int BlockNum1, const int BlockNum2) const; void BuildLoopList(int BlockNum, std::list<std::size_t> &LoopList); // build list of loop numbers that BlockNum is part of. void BuildLoopBlockList(const size_t LoopNum, std::list<std::size_t> &BlockList); // build list of Block numbers contained in LoopNum. void AnalyzeLoopIterations(void); // analyze how many times each loop iterates STARSExpression *CreateMemoryAddressExpr(const STARSOpndTypePtr &MemDefOp, SMPInstr *WriteInst); // create expression for the memory address computation in MemDefOp void AliasAnalysis(void); // Find memory writes with possible aliases void AliasAnalysis2(void); // Optimized: Find memory writes with possible aliases void InferTypes(bool FirstIter); // Determine NUMERIC, POINTER, etc. for all operands bool InferInterproceduralTypes(void); // Pass types across procedure bounds, return true if types change. void InferFGInfo(void); // determine signedness and width info for all operands SMPOperandType InferGlobalDefType(const STARSOpndTypePtr &DefOp, int SSANum, SMPBasicBlock *DefBlock, bool CallInst, STARS_ea_t DefAddr); // Can DEF type be inferred from all USEs? void ApplyProfilerInformation(ProfilerInformation *pi); void AnalyzeMetadataLiveness(void); // Is metadata live or dead for each inst bool PropagateGlobalMetadata(const STARSOpndTypePtr &UseOp, SMPMetadataType Status, int SSANum, STARS_ea_t UseAddr); void FindRedundantMetadata(void); // Do consecutive DEFs have same type? void SparseConditionalConstantPropagation(void); // perform SCCP to find constant values for DEFs, store in this->ConstantDefs void AuditSCCPForIndirectTargets(void); // emit debug output if SCCP found constant call target for an indir call or jump void EvaluateAllPhiConstants(int BlockNum, const std::vector<STARSBitSet> &ExecutedEdgeBitSet, std::list<std::pair<int, int> > &SSAWorkList); // part of SCCP processing; propagate const DEFs into Phi USEs and Phi DEFs bool IsBenignUnderflowDEF(const STARSOpndTypePtr &DefOp, int DefSSANum, STARS_ea_t DefAddr, int &IdiomCode); // Do we not care if DEF underflowed, due to how it is used? bool HasIntErrorCallSink(const STARSOpndTypePtr &DefOp, int DefSSANum, STARS_ea_t DefAddr, std::string &SinkString, bool &FoundAnyCall); // DEF is passed to known system/lib call bool WritesAboveLocalFrame(const STARSOpndTypePtr &DestOp, bool OpNormalized, STARS_ea_t InstAddr); // Is DestOp direct stack access to caller's frame? bool AccessAboveLocalFrame(const STARSOpndTypePtr &StackOp, bool OpNormalized, STARS_ea_t InstAddr, bool WriteAccess); // Is StackOp direct stack access to caller's frame? StackAccessType GetStackAccessType(const STARSOpndTypePtr &StackOp, bool OpNormalized, STARS_ea_t InstAddr, bool WriteAccess); // Get StackAccessType from stack frame map bool IsAccessToCalleeSavedReg(const STARSOpndTypePtr &StackOp, bool OpNormalized, STARS_ea_t InstAddr, bool WriteAccess); // Is StackOp pointing to a callee-saved reg? bool IsDefUsedInUnsafeMemWrite(STARSOpndTypePtr DefOp, int DefSSANum, STARS_ea_t DefAddr); // Is Defop+DefSSANum at DefAddr used as address reg or as source operand in unsafe memory write? bool IsAddressRegSafe(const STARSOpndTypePtr &UseOp, STARS_ea_t UseAddr, int UseSSANum); // Is UseOp+UseSSANum at UseAddr a safe write? void MarkFunctionSafe(void); // Does analysis to see if the function can be marked safe void FreeUnusedMemory2(void); // After loop 2 in SMPProgram::Analyze(), free memory void FreeUnusedMemory3(void); // After loop 3 in SMPProgram::Analyze(), free memory void FreeUnusedMemory4(void); // After loop 4 (type inference) in SMPProgram::Analyze(), free memory private: // Data SMPProgram* Program; // pointer to the program I'm part of STARS_Function_t *FuncInfo; STARS_ea_t FirstEA; // address of first instruction in the function #if 0 char FuncName[MAXSMPSTR]; #endif int BlockCount; // number of basic blocks in the function std::size_t LoopCount; bool FuncProcessed; // Has function been analyzed in current whole-program analysis? bool UseFP; // Does function use a frame pointer? bool StaticFunc; // Is function declared static? bool LibFunc; // is function a standard library function? bool HasReturnInst; // Does function have a return instruction? (might just have a tail call) bool IndirectCalls; // Does function make indirect calls? bool UnresolvedIndirectCalls; // Calls could not all be linked to targets bool IndirectJumps; // Does function make indirect jumps? bool UnresolvedIndirectJumps; // Jumps could not all be linked to targets bool SystemCalls; // has system calls, e.g. "int 0x80" in Linux bool DirectlyRecursive; // Calls itself bool MutuallyRecursive; // part of program call graph loop, or depends on loop funcs being processed first // bool SharedChunks; // Does function share a tail chunk with other functions? bool UnsharedChunks; // Does function have noncontiguous fragments that are not shared with other funcs? bool MultipleEntryPoints; // Does function have multiple entry points from other functions? bool CalledFromOrphanCode; // function is called from orphaned code, so program CFG is not complete at this function. bool TailCallChainFromOrphanCode; // Part of chain orphancode ... func.. tailcallsfunc2 ... which can return to orphaned code bool CallsNonReturningFunc; // calls exit() or abort(), et al., on some path; could return on other paths bool CalleeChainCallsNonReturningFunc; // somewhere in callee chain we have CallsNonReturningFunc set bool CallsAlloca; // Does function allocate stack space after initial allocation? NOTE:SMPInstr::IsAllocaCall() excludes immediate value alloca calls bool PushAfterLocalVarAlloc; // Does function push onto the stack after allocating local var space? bool LinkerStub; // Is function just a stub to be filled in by the linker, e.g. a PLT stub? bool ThunkFunc; // Function is a thunk to get the code address by returning the return address in a reg bool AnalyzedSP; // Were stack pointer change points successfully analyzed? bool STARSStackPtrAnalysisPerformed; // Have we done our own stack pointer analysis yet? bool StackAdjustmentComputed; // Have we cached a value for the stack adjustment seen after calls to this function throughout the program? bool BuiltRTLs; // Were RTLs built succcessfully for all instructions? bool HasReducibleCFG; // control flow graph is reducible bool HasStructuredCFG; // control flow graph can be transated to a well-structured high-level language, namely SPARK Ada, with no gotos bool HasGoodSSA; // Succeeded in building SSA form bool SafeFunc; // Function needs no bounds checking from mmStrata bool SpecSafeFunc; // Function needs no bounds checking from mmStrata bool SafeCallee; // SafeFunc AND Caller of this func does not need a stack referent bool SpecSafeCallee; // SafeFunc AND Caller of this func does not need a stack referent bool UnsafeForFastReturns; // Strata fast returns mechanism cannot be used for this function bool WritesAboveRA; // Function writes to stack above the return address bool NeedsStackReferent; // mmStrata will need a stack referent to do bounds checking bool SpecNeedsStackReferent; // mmStrata will need a stack referent to do bounds checking bool HasIndirectWrites; // Function has at least one indirect memory write bool HasUnsafeIndirectWrites; // Function has at least one unsafe indirect memory write bool AltersMemory; // Function writes to memory, or its callees write to memory; for SPARK Ada contracts. bool HasLoopInArgMemWrites; // Has loop mem write that traces back to InArg pointer value bool CalleeHasLoopInArgMemWrites; // Callee has loop mem write that traces back to InArg pointer value bool HasMemExprsFromCalleeLoops; // callee has loop mem write exprs, regardless of whether we called the callee from a loop bool PossibleIndirectCallTarget; // function address appears in data, could indicate indirect calls to it bool PossibleTailCallTarget; // function could be called by jump instruction acting as tail call bool ReturnTargetsComputed; // finished computing all return targets (if func can be tail called, depends on other funcs) bool OutgoingArgsComputed; // Were able to compute OutgoingArgsSize bool GoodLocalVarTable; // LocalVarTable was built successfully bool StackFrameExtendsPastStackTop; // Locals are accessed from unallocated space beyond the top of stack. bool IsSpeculative; // Have we started the speculative portion of the analysis for this function. bool HasHashingCode; // Has apparent hashing or crypto code that intentionally overflows. bool HasInArgCodePointer; // Has incoming arg of type CODEPTR bool HasInArgDataPointer; // Has incoming arg of type POINTER or a refinement of POINTER bool HasMallocCall; // calls malloc() bool TranslatingSPARKLoop; // Currently translating a loop into a separate SPARK Ada procedure long TypedDefs; // How many DEFs in instructions were not UNINIT type after InferTypes() long UntypedDefs; // How many DEFs in instructions are UNINIT type after InferTypes() long TypedPhiDefs; long UntypedPhiDefs; long SafeBlocks; // no unsafe memory writes in block; counter long UnsafeBlocks; // possibly unsafe memory write in block; counter std::size_t Size; // Function size in code bytes STARS_asize_t LocalVarsSize; // size of local vars region of stack frame uint16_t CalleeSavedRegsSize; // stack size of callee pushed regs STARS_asize_t IncomingArgsSize; // size of incoming args on stack int RetAddrSize; // size of return address on stack in bytes (4 for 32-bit machines) STARS_sval_t AllocSizeAfterFrameAlloc; // bytes allocated in first block after primary frame alloc, e.g. by alloca std::size_t OutgoingArgsSize; // portion of LocalVarsSize that is really outgoing args space STARS_ea_t LocalVarsAllocInstr; // address of instr that allocates stack frame STARS_ea_t LocalVarsDeallocInstr; // address of epilogue instr that deallocs frame STARS_adiff_t AllocPointDelta; // IDA sp_delta AFTER stack frame allocation instruction STARS_sval_t MinStackDelta; // smallest (negative) value that stack pointer reaches, relative // to the value it has at the entry point of the function STARS_sval_t MaxStackDelta; // highest (positive) value that stack pointer reaches, relative // to the value it has at the entry point of the function STARS_sval_t MinStackAccessOffset; // Normalized or unnormalized, min stack byte offset in any DEF or USE STARS_sval_t MaxStackAccessLimit; // Normalized or unnormalized, 1 greater than max stack byte offset in any DEF or USE STARS_sval_t NetStackDelta; // Net change to stack pointer after function returns; +4 for most functions, // because they pop off the return address while returning. STARS_sval_t PreAllocStackDelta; // Stack delta right before stack frame allocation, to which the stack // delta should be reset when we see an instruction that deallocates the // whole frame. STARS_sval_t FramePointerStackDelta; // Stack delta when framepointer := stackpointer was encountered; zero if UseFP is false. STARS_sval_t GlobalStackAdjustment; // Stack adjustment seen program-wide after calls to this function; zero or positive. STARS_sval_t MaxDirectStackAccessDelta; // Normalized; max offset from incoming stack pointer for direct stack accesses into caller's frame long LocalVarOffsetLimit; // upper bound on stack-relative offsets long IDAReturnAddressOffset; // offset from local frame base of return address in IDA Pro stack frame FuncType ReturnAddrStatus; // Marked true if the return address is safe from being overwritten unsigned short FastReturnStatus; // Whether fast returns can be used for calls to, and returns from, this function, and why not if unsafe. unsigned short InArgCount; // number of incoming arguments used unsigned short MaxInArgIndex; // maximum arg # used (might be greater than InArgCount because some inargs might not be used) uint32_t TaintInArgPosBits; // each set bit indicates InArg position that gets passed as a critical arg to a library call int MaxDirectStackAccessSSANum; // highest SSANum seen on stack locations. int MaxRegSSANum; // highest SSANum seen on registers int MaxLocalSSANum; STARSExpression *DebugExpr; // for gdb printing ease std::list<SMPInstr *> Instrs; std::list<SMPBasicBlock *> Blocks; std::set<STARS_ea_t> DirectCallTargets; // addresses called directly std::set<STARS_ea_t> IndirectCallTargets; // addresses called by indirect calls std::vector<STARS_ea_t> AllCallTargets; // union of direct and indirect std::set<STARS_ea_t> AllCallSources; // functions that call this one std::set<STARS_ea_t> AllCallSites; // instructions that call this function std::set<STARS_ea_t> TailReturnTargets; // tail call return points from this function; subset of ReturnTargets std::set<STARS_ea_t> ReturnTargets; // instructions that this function could return to std::set<STARS_ea_t> JumpTableTargets; // code addresses found in jump tables for this func std::set<STARS_ea_t> ResolvedCondBranches; // conditional branches resolved to always taken or never taken std::set<SMPFunction *> UnresolvedCallers; // temp set to resolve during ComputeReturnTargets() std::map<STARS_ea_t, int> JumpFollowNodesMap; // map COND_BRANCH addresses to their follow nodes when exiting if-then-elsif-else structures std::map<STARS_ea_t, SMPBasicBlock *> InstBlockMap; std::vector<SMPBasicBlock *> RPOBlocks; // blocks in reverse post-order numbering, index == RPO number std::vector<STARSCFGBlock *> ShadowCFGBlocks; // skeleton CFG suitable for node coalescing analyses, index == RPO number std::vector<unsigned short> InArgTypes; // types of incoming arguments, starting with argument zero. std::vector<int> IDom; // Immediate dominators, indexed and valued by block RPO numbers std::vector<std::pair<int, std::list<int> > > DomTree; // Dominator tree, as parent # and list of children STARSOpndSet GlobalNames; // operands used in more than one block; needed in SSA std::vector<std::list<int> > BlocksDefinedIn; // What blocks DEF each GlobalName; index = op # in GlobalNames std::vector<int> SSACounter; // SSA subscript #, indexed by GlobalNames op # std::vector<std::list<int> > SSAStack; // SSA stack of most recent SSA number, indexed by global # std::vector<struct LocalVar> LocalVarTable; // offset-sorted list of local vars / outgoing args std::vector<struct StackFrameEntry> PositiveOffsetStackFrameMap; // memory map of every byte on stack frame, return address and up (inargs, etc.) std::vector<struct StackFrameEntry> NegativeOffsetStackFrameMap; // memory map of every byte on stack frame, below return address (saved reg, locals, etc.) std::vector<struct FineGrainedInfo> PositiveOffsetFineGrainedStackTable; // Inferences based on instruction accesses of stack std::vector<struct FineGrainedInfo> NegativeOffsetFineGrainedStackTable; // Inferences based on instruction accesses of stack std::vector<int> SavedRegLoc; // indexed by reg #; offset from return address of callee-saved reg std::vector<SMPOperandType> ReturnRegTypes; // indexed by reg #; inferred types upon return std::vector<SMPOperandType> IncomingRegTypes; // indexed by reg #; types from call sites of callers of this func std::vector<struct FineGrainedInfo> ReturnRegFGInfo; // indexed by reg #; inferred FG info upon return std::vector<STARSBitSet> FuncLoopsByBlock; // vector indexed by block number, bitset indexed by loop number, set bit means block # is in loop # std::vector<STARSBitSet> FuncBlocksByLoop; // vector indexed by loop number, bitset indexed by block number, set bit means loop includes block # std::vector<STARSBitSet> PositiveOffsetStackBytesWrittenByLoop; // vector indexed by loop number, bitset indexed by byte offset from incoming stack pointer, set bit means memory byte written std::vector<STARSBitSet> NegativeOffsetStackBytesWrittenByLoop; // vector indexed by loop number, bitset indexed by byte offset from minimum stack pointer value, set bit means memory byte written std::vector<int> LoopTypesByLoopNum; // indexed by loop number: top-testing, bottom-testing, middle-testing or infinite std::vector<int> LoopTestBlocksByLoopNum; // indexed by loop number; block number of header block for top-testing or tail block for bottom-testing, -1 for middle-testing std::vector<int> LoopHeadBlockNumbers; // indexed by loop number; block number of header block std::vector<int> LoopFollowNodes; // indexed by loop number; block number of follow block std::vector<bool> LoopHasMultipleExits; std::vector<bool> LoopWritesMemory; // static, indirect or indexed writes std::vector<bool> LoopReadsMemory; // static, indirect or indexed reads std::vector<bool> LoopWritesGlobalStaticMemory; std::vector<bool> LoopReadsGlobalStaticMemory; std::vector<bool> LoopHasCalleeMemWrites; std::vector<bool> LoopUsesStackPtrRegs; std::vector<bool> LoopHasPreconditions; // Loop requires SPARK Ada preconditions std::vector<bool> LoopExecutesWithLimitValue; // Loop executes a final iteration with BIV == LimitValue std::vector<bool> LoopAnalysisProblems; // true if loop had problems with iterations analysis or mem range analysis std::vector<bool> CalleeMemExprProblems; // indexed by LoopNum + 1; error in inheriting memory writing exprs from callees std::vector<bool> SymbolicAnalysisProblems; // indexed by LoopNum + 1; error in symbolic analysis of memory writing exprs std::vector<STARS_sval_t> LoopIncrementValue; // delta for primary BIV on each iteration; could be negative std::vector<STARSInductionVarFamilyList> LoopInductionVars; // indexed by loop number std::vector<struct LoopComparison> LoopComparisonExprs; // indexed by loop number std::vector<STARSExpression *> LoopIterationsInitExprs; // indexed by loop number; primary BIV init for analyzed-iterations loops std::vector<STARSExpression *> LoopIterationsLimitExprs; // indexed by loop number; primary BIV limit for analyzed-iterations loops std::vector<STARSExpression *> LoopIterationsCountExprs; // indexed by loop number; primary BIV count for analyzed-iterations loops std::vector<STARSExprSet> LoopMemWriteRangeExprs; // indexed by loop number; exprs describing memory writing ranges std::vector<STARSExprBoundsSet> LoopMemWriteBoundsExprs; // indexed by loop number; pairs of <lower, upper> bounds exprs std::vector<STARSExprBoundsSet> LoopMemWriteBoundsExprsExpanded; // indexed by loop number; lower/upper exprs expanded to InArg or constant address std::vector<STARSExprSet > StringMemWriteRangeExprs; // indexed by loop number + 1; expr describing string writing range std::vector<std::vector<std::pair<std::size_t, STARSExprSetIter> > > StringMemWriteRangeWidths; // width plus iters to relational range exprs std::vector<STARSExprSet > RelationalLowerBoundExprs; // indexed by loop number + 1; lower bound expr split out from relational expr std::vector<STARSExprSet > RelationalUpperBoundExprs; // indexed by loop number + 1; upper bound expr split out from relational expr std::vector<std::list<std::pair<std::size_t, std::pair<STARSExprSetIter, STARSExprSetIter> > > > RelationalMemWriteWidths; // width plus iters to lower and upper bound exprs std::vector<bool> NonStackFrameLoopMemWrites; // indexed by loop number; corresponding lower bound and/or upper bound expr is not just a local var std::vector<STARSInductionVarFamilyIter> LoopAnalyzedBIVIters; // indexed by loop number; iterator for BIV that was successfully analyzed for mem range & iteration count std::vector<STARSExprSet > MemAddrExprsFromCallees; // non-loop mem addr exprs for this function after substitution of actual arg sources; indexed by LoopNum+1 std::vector<std::vector<std::pair<STARSExprSetIter, std::size_t> > > MemAddrExprWidthsFromCallees; // mem write byte widths for MemAddrExprsFromCallees. indexed by LoopNum + 1 std::vector<std::set<int> > LoopRegHashSets; // indexed by loop #; reg+SSA hashes for regs whose value is copied to another reg that is used for loop mem writes; not used directly as address reg for write STARSExprSet LoopMemAddrRegSourceExprs; // Expanded exprs for regs in LoopRegHashSets std::vector<std::list<std::pair<STARS_regnum_t, STARSExprSetIter> > > LoopRegSourceExprPairs; // map register to incoming-to-loop expr, indexed by loop # std::vector<std::set<STARS_ea_t> > LoopIVUsedAsStringWriteCounter; // loop induction var InsideLoopDefAddrs that are used as RCX counter reg for looping string writes // NOTE: The following two containers are indexed by [LoopNum+1]; if call inst is outside loop, LoopNum == -1 producing index 0. std::vector<STARSExprSet > LoopMemAddrExprsFromCalleeLoops; // callee loop mem addr exprs for this function after substitution of actual arg sources std::vector<std::list<std::pair<STARSExprSetIter, std::size_t> > > LoopMemAddrExprWidthsFromCalleeLoops; // mem write byte widths for LoopMemAddrExprsFromCallees std::vector<std::vector<bool> > NonStackFrameCalleeMemWrites; // corresponding MemAddrExprWidthsFromCallees.first expr is not just a local var; indexed by LoopNum + 1 std::vector<STARSExprSet > LoopMemAddrExprsFromCallees; // mem addr exprs, indexed by loop, after substitution of actual arg sources std::vector<std::vector<std::pair<STARSExprSetIter, std::size_t> > > LoopMemAddrExprWidthsFromCallees; // mem write byte widths for LoopMemAddrExprsFromCallees std::vector<STARSExprSet > StoppedOnIVMemRangeExprs; // indexed by LoopNum+1; STARSExpression::Expand() stopped on hitting an induction variable, needs further analysis std::vector<STARSExprSet > StoppedOnIVNonRangeExprs; // indexed by LoopNum+1; STARSExpression::Expand() stopped on hitting an induction variable, needs further analysis std::vector<std::vector<std::pair<STARSExprSetIter, std::size_t> > > StoppedOnIVMemRangeIterWidths; // widths and iterators pointing to StoppedOnIVMemRangeExprs std::vector<std::vector<std::pair<STARSExprSetIter, std::size_t> > > StoppedOnIVNonRangeIterWidths; // widths and iterators pointing to StoppedOnIVNonRangeExprs // Temporary containers used only in the SPARK output stage for the current loop procedure being output. // They are saved in these containers to be shared across the pre- and post-condition output stages. // The saving is done by AggregateLoopMemExprs(). STARSExprSet TempLowerBoundsExprs; STARSExprSet TempUpperBoundsExprs; STARSExprSet TempNonRangeExprs; std::vector<std::pair<STARSExprSetIter, STARSExprSetIter> > TempRangeExprWidthIters; std::vector<std::pair<std::size_t, STARSExprSetIter> > TempNonRangeExprWidthIters; std::vector<std::bitset<1 + MD_LAST_REG_NO> > LoopMemRangeInArgRegsBitmap; // indexed by loop number; memory writing range expr regs for each loop std::vector<std::map<STARS_regnum_t, STARS_ea_t> > LoopBoundaryInArgRegs; // indexed by loop number; map InArg reg # to DefAddr that is live into the loop if InArg reg is used in mem range exprs std::vector<std::set<STARS_ea_t> > LoopInvariantDEFs; // for each loop #, set of inst IDs in which first non-flags DEF is loop-invariant for its innermost containing loop std::vector<STARSExprSet > InArgsUsedInMemWrites; // InArgs (or global static ops) used for loop-invariant mem writes (perhaps after copying the InArg) std::vector<std::vector<std::pair<STARSExprSetIter, std::size_t> > > InArgsUsedInMemWriteByteWidths; // byte widths for each element of InArgsUsedInMemWrites; indexed by LoopNum+1 std::vector<bool> LoopMemExprsExpandToStackOffsets; // At least one of mem lower or upper bounds or init expr are just stack offsets when Expr->Expand() is done. STARSInArgMap MemWriteToInArgMap; // mem write address reg at STARS_ea_t is copy of InArg found in STARSOpndTypePtr std::vector<int> DFSMarkers; // vector indexed by block number, -1 => unvisited, 0 => visited but not all descendants visited, 1 => completed std::map<STARS_ea_t, uint16_t> JumpToFollowNodeCounterMap; // map addr of follow-block to count of jumps seen to it within if-then-[elsif-else] structure std::map<int, STARS_ea_t> GlobalDefAddrBySSA; // map hash of global name & SSANum to DEF inst addr // If global DEF for that SSA is found in a Phi function, we use block number instead of inst addr // Instruction addresses should never overlap block #s, as block #s start at 0 and top out at a few hundred. // NOTE: We are currently limiting this map to registers, not all global names. std::map<int64_t, STARS_ea_t> GlobalStackDefAddrBySSA; // map hash of normalized stack offset & SSANum to DEF inst addr std::map<int, struct FineGrainedInfo> GlobalDefFGInfoBySSA; // map hash of global name & SSANum to DEF FG info. // NOTE: We are currently limiting this map to registers, not all global names. std::map<int, struct FineGrainedInfo> GlobalUseFGInfoBySSA; // map hash of global name & SSANum to USE FG info. // NOTE: We are currently limiting this map to registers, not all global names. std::map<STARS_ea_t, struct FineGrainedInfo> StackDefFGInfo; // map stack FG info to instruction address of stack def; UNUSED std::map<STARS_ea_t, struct FineGrainedInfo> StackUseFGInfo; // map stack FG info to instruction address of stack use; UNUSED std::map<STARS_ea_t, STARSOpndTypePtr> LeaInstOpMap; // map original Lea instruction pseudo-memory operand to instruction address. std::map<STARS_ea_t, unsigned short> ControlFlowMap; // map InstAddr of each jump or branch to a type suitable for SPARK Ada translation. std::map<int, struct STARS_SCCP_Const_Struct> ConstantDefs; // map hash of global name & SSANum to constant value from SCCP. // NOTE: We are currently limiting this map to registers, not all global names. Flags are tracked separately (e.g. // carry flag, zero flag) only in this SCCP data structure, whereas SSA form, DEFs, USEs and LVA sets have the flags // register tracked in aggregate. // Two sets used in live variable analysis. LiveIn and UpExposed can be obtained from Blocks.front(). STARSOpndSet KillSet; // registers killed in this function STARSOpndSet LiveOutSet; // Live-Out registers in this function // Tracking stack pointer and frame pointer saves, copies, and restores std::set<std::pair<STARSOpndTypePtr, std::pair<STARS_ea_t, STARS_sval_t> >, LessStackDeltaCopy> StackPtrCopySet; // triple: operand holding copy, InstAddr where copy is made, stack delta for copy std::list<std::pair<STARS_ea_t, STARS_sval_t> > TempStackDeltaReachesList; // Used for temporary lookups of particular op_t in StackPtrCopySet. std::set<STARS_ea_t, LessAddr> TempReachingDefs; // Temporary list of InstAddrs with defs of one op_t that reach a particular InstAddr. std::map<STARSDefinition, STARSOpndTypePtr, LessDefinition> NormalizedStackOpsMap; // normalized stack operands, indexed by instruction address (for lookup from RTLs). std::map<STARSDefinition, std::map<STARSDefinition, STARSOpndTypePtr, LessDefinition>::iterator, LessDefinition> InverseNormalizedStackOpsMap; // index: normalized op, // mapped to: iterator into NormalizedStackOpsMap; only for use in functions that call alloca() and need to re-normalize stack ops repeatedly std::bitset<1 + MD_LAST_REG_NO> PreservedRegsBitmap; // Registers that are saved on entry and restored before return from func, or never used, as a bitmap. std::bitset<1 + MD_LAST_REG_NO> CallerSavedLocalRegsBitmap; // Reg numbers that are local names and are caller-saved std::bitset<1 + MD_LAST_REG_NO> MemRangeRegsBitmap; // Reg numbers that are used in defining the memory writing range expr std::bitset<1 + MD_LAST_REG_NO> InputRegs; // Reg numbers that are USEd in non-SSA, non-call, non-return instructions std::bitset<1 + MD_LAST_REG_NO> OutputRegs; // Reg numbers that are DEFed in non-SSA, non-call, non-return instructions std::bitset<1 + MD_LAST_REG_NO> CalleePreservedRegs; // Union of PreservedRegs sets of callees std::vector<std::bitset<1 + MD_LAST_REG_NO> > OutputRegsByLoop; // save results of AnalyzeLoopGlobals() for each loop to emit Loop_Invariants std::vector<std::bitset<1 + MD_LAST_REG_NO> > CalleePreservedRegsByLoop; // callee chain (from each loop) preserved regs since they were last altered std::set<STARS_ea_t> ConstantIndirCalls; // addresses with indir calls that go to a constant address std::list<std::pair<int, std::pair<int, int> > > SPARKLoopWorkList; // Worklist of loops to be translated to procs; pair<LoopIndex, pair<HeaderBlockNum, FollowBlockNum> > std::list<SPARKTranslationCFType> SPARKControlStack; // stack of what CFG structure we are translating. std::map<STARS_ea_t, STARS_ea_t> LoopToGuardMap; // map address of loop to address of guard if we have simple "if cond then ... loop ... endloop .. endif" std::map<STARS_ea_t, STARS_ea_t> GuardToLoopMap; // inverse map of COND_BRANCH addr of guard to loop address for guarded loop std::map<STARS_ea_t, std::size_t> SwitchJumpMap; // map inst ID of indirect jump to switch statement #; switch statements are // numbered starting at zero as they are encountered in a post-order traversal of the graph std::vector<struct SwitchTableInfo> SwitchInfoArray; // same index as the size_t value in SwitchJumpMap std::vector<STARSBitSet> InArgPointerCopies; // indexed by GlobalNameIndex, bitset indexed by SSA #, bit set to 1 => copy of InArg of CODEPTR or POINTER type std::vector<std::set<STARS_ea_t> > InArgPointerCopyAddrs; // Indexed by GlobalNameIndex, addrs where copies of POINTER or CODEPTR InArg are made std::map<unsigned int, std::size_t> GlobalNameIndexMapToInArgIndex; // indexed by GlobalNameIndex, returns InArg position index, zero-based std::map<std::size_t, STARSOpndTypePtr> InArgIndexMapToOperand; // indexed by InArg position ShadowSet AlreadyShadowed; // avoid infinite recursion in FindShadowingPoint() DefOrUseList TempShadowList; // all Refs being analyzed in current FindShadowingPoint() recursion chain std::map<STARS_ea_t, STARS_ea_t> MallocCallInArgsMap; // map addr of malloc(size) call inst to addr of size arg pass std::map<STARS_ea_t, STARSDefinitionSet > BufferCallInArgsMap; // map addr of libfunc(bufferptr) call inst to (op, addr) of arg pass typedef std::map<STARS_ea_t, std::list<std::pair<std::size_t, STARS_uval_t> > > STARSBufferCallArgMap; STARSBufferCallArgMap BufferCallConstBufferArgsMap; // list of (bufptrargpos, bufsize) indexed by CallAddr // Methods void DestroyLoopExprs(void); // release loop-based symbolic memory access expressions void EraseInstRange(STARS_ea_t FirstAddr, STARS_ea_t LastAddr); void SetLinks(void); // Link basic blocks and map instructions to blocks bool FindDistantCodeFragment(STARS_ea_t TargetAddr); // Is TargetAddr the start of a code fragment that belongs to this func, not a separate func? bool AnalyzeStackPointerDeltas(void); // Analyze changes in stack pointer for all instructions; return AnalyzedSP bool UseIDAStackPointerDeltas(void); // Use IDA Pro values instead of doing our own analysis bool AddToStackPtrCopySet(STARSOpndTypePtr CopyOp, STARS_ea_t InstAddr, STARS_sval_t StackDelta); // return true if inserted, false if present already (update delta in that case) void FindPreservedRegs(void); // Determined which regs are not killed by func or its callees; set bits in PreservedRegsBitmap void AuditCallingConvention(void); // Find failure to preserve callee-saved regs void FindAllAllocsAndDeallocs(void); // Find all stack frame allocating and deallocating instructions and stack ptr offsets void FindFramePointerDelta(void); // Compute FramePointerStackDelta void SetStackFrameInfo(void); // Figure out the stack frame regions, and locate the alloc/dealloc frame instructions. bool MDFixFrameInfo(void); // Redefine stack regions for our needs void BuildLocalVarTable(void); // Determine local variable boundaries on the stack void BuildStackAccessTables(void); // Build tables to characterize stack accesses. void UpdateMinMaxStackOffsets(SMPInstr *CurrInst, const STARSOpndTypePtr &TempOp); // Update MinStackAccessOffset and MaxStackAccessLimit if TempOp is stack access inline void SetStackFrameExtendsPastStackTop(void) { StackFrameExtendsPastStackTop = true; }; bool IndexedWritesAboveLocalFrame(const STARSOpndTypePtr &DestOp); // Is DestOp direct stack write to caller's frame? bool MDGetStackOffsetAndSize(SMPInstr *Instr, const STARSOpndTypePtr &TempOp, STARS_sval_t BaseValue, STARS_ea_t &offset, std::size_t &DataSize, bool &FP, bool &Indexed, bool &Signed, bool &Unsigned); // Find any stack memory access in TempOp, return offset, size, // whether the Frame Pointer was used and signedness (if sign-extended or zero-extended). bool FindAlloca(void); // true if found evidence of alloca() allocations void MDFindSavedRegs(void); // Fill in SavedRegLoc[] offsets void DetectMultiEntryFunction(void); // Detect multiple-entry-point func; probably IDA Pro error; not safe for fast returns. void DetectLinkerStubFunction(void); // Determine whether func is a linker stub, e.g. a PLT stub void DetectThunkFunction(void); // Detect function that just puts its return address into a reg and returns. void MDAuditJumpXrefs(void); // Fix missing IDA Pro jump code xrefs void RebuildCallTargets(void); // Rebuild AllCallTargets as the union of the direct and indirect call targets. void EmitStackFrameAnnotations(FILE *AnnotFile, SMPInstr *Instr); void ComputeIDoms(void); // Compute immediate dominators of all blocks into IDom[] int IntersectDoms(int, int) const; // Find Dom intersection (as IDom[] index) for 2 blocks void ComputeDomFrontiers(void); // Compute dominance frontiers for all blocks void ComputeGlobalNames(void); // Compute the GlobalNames set void ComputeBlocksDefinedIn(void); // Compute the BlocksDefinedIn vector void InsertPhiFunctions(void); // Insert SSA phi functions at top of each basic block void BuildDominatorTree(void); // Build the DomTree structure bool TestCFGReducibility(void); // return true if CFG is a reducible graph. bool CFGReducibilityHelper(std::size_t BlockNumber); // recursive depth-first-search helper for TestCFGReducibility() int SSANewNumber(std::size_t GlobNameIndex); // SSA helper: increment and return SSA number void SSARename(int BlockNumber); // SSA main helper: rename throughout block void SSARenumber(void); // Renumber SSA subscripts for all names void AnalyzeSystemCalls(void); // Analyze system calls for memory overwriting safety void DetectUninitializedVars(void); // Find variables that are USEd before they are DEFed void FindLoopHeadsAndTails(SMPBasicBlock *CurrBlock); // Detect loop head and/or tail block for loops and record in data structures bool IsBlockNumLoopHeader(const int BlockNum, std::size_t &LoopNum) const; // Is BlockNum already in this->LoopHeadBlockNumbers? If so, put index in LoopNum void FindLoopBlocksFromTailToHeader(const std::size_t LoopNumber, const int HeadBlockNum, std::list<SMPBasicBlock *>::iterator BlockIter, int &DoubleTailFollowBlockNum); // populate FuncLoopsByBlock and FuncBlocksByLoop data structures for DetectLoops() void DetectLoops(void); // Detect which blocks are in which loops and populate FuncLoopsByBlock and FuncBlocksByLoop data structures. void ClassifyLoop(std::size_t LoopNumber, int HeaderExitFollowNum, int TailExitFollowNum, SMPBasicBlock *CurrBlock, SMPBasicBlock *HeadBlock, bool HeaderBlockExitsLoop, bool TailBlockExitsLoop); // classify LoopNumber loop as top, middle, or bottom testing bool DoesBlockExitLoop(std::size_t LoopNumber, SMPBasicBlock *LoopBlock, int &FollowBlockNum); // return true if block can exit the loop. void DetectLoopInvariantDEFs(void); // Collect a set of loop-invariant DEFs with the inst IDs of the DEFs. void DetectLoopInvariantDEFs2(void); // Collect a set of loop-invariant DEFs with the inst IDs of the DEFs. bool IsUseLoopInvariantDEF(std::size_t LoopIndex, const STARSOpndTypePtr &UseOp, SMPInstr *UseInst); // Track UseOp to its DEF, see if loop-invariant for LoopIndex void DetectLoopInductionVars(void); // Detect basic and dependent loop induction variable families for all loops void FindDependentInductionVar(std::size_t LoopIndex, struct DependentInductionVar &DIV, STARSOpndTypePtr Add1, STARSOpndTypePtr Add2, STARSOpndTypePtr Mult1, STARSOpndTypePtr Mult2, SMPoperator RhsOperator, SMPInstr *DefInst); // pass in results of DefInst::IsDependentInductionVarArithmetic() bool ReplaceLoopRegWithConst(std::size_t LoopIndex, STARSOpndTypePtr &RegOp, SMPInstr *UseInst); // If RegOp USE in UseInst is an SCCP constant, create an immediate operand for it. STARSExpression *CreateLimitExpr(const std::size_t &LoopIndex, const struct InductionVarFamily &IVFamily, const struct LoopComparison &LoopCompExpr); // Create loop limit expr: BIVOpnd relationaloperator Opnd2 STARSExpression *CreateSecondaryBIVLimitExpr(const std::size_t &LoopIndex, const struct InductionVarFamily &IVFamily); // Create loop limit expr: BIVOpnd_InitExpr + (stride * IterationCountExpr) STARSExpression *CreateDIVInitExpr(const std::size_t &LoopIndex, const struct InductionVarFamily &IVFamily, const std::size_t DIVIndex); // Create DIV init expr as linear function of its BIV init expr STARSExpression *CreateDIVLimitExpr(const std::size_t &LoopIndex, const struct InductionVarFamily &IVFamily, const std::size_t DIVIndex); // Create DIV limit expr as linear function of its BIV limit expr STARSExpression *CreateIterationsExpr(std::size_t LoopIndex, const struct InductionVarFamily &IVFamily, bool PositiveIncrement, STARSExpression *InitExpr, STARSExpression *LimitExpr); // Create loop iteration count expr bool CreateSPARKMemoryWriteRangeExpr(std::size_t LoopIndex, bool RecordLoopRegs, std::set<int> &LoopRegHashes, STARSExprSet &MemWriteExprs, STARSMemWriteExprsList &MemWriteExprWidths, std::vector<std::set<STARS_ea_t> > &StackPtrCopiesVector); // Create a Memory range expression set for indirect or indexed memory writes in the loop; return true on success void CombineMemoryExprs(STARSMemWriteExprsList &MemWriteExprWidths, STARSExprSet &MemWriteExprs, std::vector<std::set<STARS_ea_t> > &StackPtrCopies); // Combine items in the expr set that have common regs, e.g. (RDI+1) and (RDI-2), into fewer set entries bool CreateSPARKMemoryReadRangeExprs(std::size_t LoopIndex, bool RecordLoopRegs, std::set<int> &LoopRegHashes, STARSExprSet &MemWriteExprs, STARSMemWriteExprsList &MemWriteExprWidths, std::vector<std::set<STARS_ea_t> > &StackPtrCopiesVector); // Create a Memory range expression set for indirect or indexed memory writes in the loop; return true on success bool ReplaceBIVWithExpr(std::size_t LoopIndex, const struct InductionVarFamily &IVFamily, STARSExpression *CurrExpr, bool InitCase); // Replace occurrences of IVFamily.BIV in CurrExpr with BIV InitExpr or LimitExpr bool ReplaceAllBIVsWithExprs(std::size_t LoopIndex, STARSExpression *CurrExpr, bool InitCase, bool &changed); // Replace all BIVs in CurrExpr with lower or upper limit (depending on InitCase) exprs for BIV bool ReplaceAllDIVsWithExprs(std::size_t LoopIndex, STARSExpression *CurrExpr, bool InitCase, bool &changed); // Replace all DIVs in CurrExpr with lower or upper limit (depending on InitCase) exprs for DIV bool ReplaceAllIVsWithExprs(std::size_t LoopIndex, STARSExpression *CurrExpr, bool InitCase, bool &changed); // wrapper to call ReplaceAllBIVsWithExprs() and ReplaceAllDIVsWithExprs() bool ExpandExprToInArgs(std::size_t LoopIndex, STARSExpression *CurrExpr, bool InitCase, std::set<STARS_ea_t> &StackPtrCopySet); // expand, replace IVs, simplify, until no more can be done void DetectInArgRegsNeededForMemWriteExprs(void); // Fill in LoopMemRangeInArgRegsBitmap and MemRangeRegsBitmap void ExpandLoopRegHashExprs(void); // take LoopRegHashSets and expand into LoopMemAddrRegSourceExprs bool InheritCalleeMemExpr(std::size_t MemExprWidth, STARSExpression *CurrentMemAddrExpr, SMPInstr *CallInst, int LoopNum, const std::list<std::size_t> &LoopList); // return true if expr inherited bool InheritCalleeMemRangeExpr(STARSExpression *CalleeMemRangeExpr, SMPInstr *CallInst, std::size_t MemWriteByteWidth, std::size_t LoopNumPlusOne, const std::list<std::size_t> &LoopList); // return true if expr inherited void SplitAndSaveRelationalExpr(bool PositiveIncrement, std::size_t LoopNumPlusOne, std::size_t MemWidth, STARSExpression *RangeExpr); // Split relational RangeExpr into upper and lower bonds exprs and save them and their width void TraceInArgPointers(void); // helper for TraceIncomingArgs(), focused on CODEPTR and POINTER types void RemoveLocalRefs(STARSDefUseSet &RefSet); // Remove non-global SSA names from RefSet. bool FindShadowingPoint2(const ShadowPoint CriticalOp, const bool TracingMemWrite, ShadowSet &ShadowAddrSet, bool &MemUnsafe, ShadowSet &NewCriticalOps, bool &NonConstSourceFound, std::set<STARS_uval_t> &ConstValues); // Trace CriticalOp via copies back to ShadowOp, return false if no shadowing possible bool AnalyzeMemWriteSafety(void); // Try to find safe indirect memory writes void UpdateLoopFollowBlockNum(int HeaderBlockNum, int FollowBlockNum); int FindFollowBlockNum(SMPBasicBlock *CurrBlock, bool StartAtLastInst = false); // Based on control flow structure of CurrBlock, find Ada follow block num; -1 if no structure besides fall-through bool AnalyzeSwitchStatement(SMPBasicBlock *CurrBlock); // Analyze switch starting at indir jump at end of CurrBlock; return false if not well-structured void FindSwitchIDom(struct SwitchTableInfo &TableInfo); // Mark jumps to default case, find IDom of entire switch statement void BuildShadowCFG(void); // build skeleton CFG, then use in coalescing nodes to analyze expressions void CoalesceShadowBlocks(int LeftBlockNum, int RightBlockNum, bool NegateLeft, SMPoperator TopOper, int NewFTNum, int NewNFTNum); // Make LeftExpr be LeftExpr TopOper RightExpr bool AnalyzeCompoundConditionalStatements(void); // Analyze if-statements with short-circuit operators bool AnalyzeConditionalStatements(void); // Analyze if-then-elses starting at COND_BRANCH at end of all blocks; return false if not well-structured int FindConditionalFollowNode(int HeadBlockNum); // Find candidate block # for if-else follow node for HeadBlockNum; return -1 otherwise int TrackConditionalBranchTerminus(int BranchHeadBlockNum, int CurrBlockNum, STARSBitSet &BlocksSeen, int &BlockAlreadySeenCounter); // Track CurrBlockNum until we reach block that BranchHeadBlockNum doesn't dominate, or dead end. Return block num, possibly SMP_BLOCKNUM_COMMON_RETURN. void FindGuardedLoops(void); // Find guarded loops and fill the GuardToLoopMap and LoopToGuardMap bool IsSPARKLoopInTranslationStack(void) const; // Are we already translating a SPARK_LOOP when we encounter another loop? void UpdateStackBytesWrittenByLoop(STARS_sval_t FinalStackPtrOffset, std::size_t MemWidth, std::size_t LoopNum); // update {Nega, Posi}tiveStackBytesWrittenByLoop[LoopNum] void EmitAnalysisProblemWarnings(FILE *HeaderFile, int LoopIndex); // LoopIndex == -1 indicates main procedure; print warnings if proofs will fail void EmitSPARKSavedArgs(FILE *BodyFile) const; // Save incoming args as locals to preserve their values void EmitSPARKArgs(FILE *BodyFile, FILE *HeaderFile, bool Signature, std::size_t LoopIndex) const; // Emit loop function args, as Signature to HeaderFile or proc call to BodyFile. void EmitSPARKProcPrePostMemConditions(FILE *BodyFile, FILE *HeaderFile, bool PreconditionSection); // Emit mem writing ranges for pre- and post-conditions void EmitSPARKMemRange(FILE *HeaderFile, bool PreconditionSection, bool ProcessingLoop, bool HasArgs, STARSExpression *LowerExpr, STARSExpression *UpperExpr, std::size_t &OutputCount, std::size_t MemWidth); // helper for EmitSPARKProcPrePostMemConditions() void EmitSPARKPrePostMemConditionsFromCalleeNonLoopWrites(FILE *HeaderFile, bool PreconditionSection, size_t LoopIndexPlusOne, std::size_t &OutputCount); // helper for EmitSPARKProcPrePostMemConditions() void EmitSPARKPrePostMemConditionsFromCalleeLoops(FILE *HeaderFile, bool PreconditionSection, std::size_t &OutputCount); // helper for EmitSPARKProcPrePostMemConditions() void AggregateLoopMemExprs(std::size_t LoopIndex); // collect temporary containers of mem exprs for one loop. bool NeedsSPARKPreconditions(bool &HasLoopMemWrites, bool &HasNonLoopInArgMemWrites, bool &HasCalleeMemWrites, bool &HasCalleeLoopMemWrites); // Determine if any mem writes (or callee mem writes) are not just to the stack frame locals. bool LoopRequiresNonStackPreconditions(size_t LoopIndex); // Loop indirect writes require pre-conditions std::string EmitSPARKProcForLoopHeaderBlock(int LoopIndex, int HeaderBlockNum, int FollowBlockNum, FILE *BodyFile, FILE *HeaderFile); // Create SPARK procedure for loop starting at HeaderBlockNum void AnalyzeLoopGlobals(int HeaderBlockNum, int FollowBlockNum, STARS_ea_t LoopAddr, bool &MemoryInput, bool &MemoryOutput, std::bitset<1 + MD_LAST_REG_NO> &InputRegs, std::bitset<1 + MD_LAST_REG_NO> &OutputRegs, std::bitset<1 + MD_LAST_REG_NO> &CalleePreservedRegs); // Analyze reg and mem accesses in loop void EmitSPARKLoopProcGlobals(FILE *BodyFile, FILE *HeaderFile, bool MemoryInput, bool MemoryOutput, const std::bitset<1 + MD_LAST_REG_NO> &InputRegs, const std::bitset<1 + MD_LAST_REG_NO> &OutputRegs, const std::bitset<1 + MD_LAST_REG_NO> &CalleePreservedRegs); // emit Input, Output, In_Out flow annotations void EmitSPARKAdaForBlock(int CurrBlockNum, int FollowBlockNum, FILE *SPARKBodyFile, bool ReadytoEmitSwitchDefault, bool LoopToProc = false); // recursive descent translation to SPARK Ada starting with CurrBlock, stop before Follow Block void EmitSPARKAdaForLoop(int HeaderBlockNum, int FollowBlockNum, FILE *SPARKBodyFile); // recursive descent translation of loop to SPARK Ada starting with header CurrBlock, stop before Follow Block void EmitSPARKAdaForSwitch(int HeaderBlockNum, int FollowBlockNum, FILE *SPARKBodyFile); // recursive descent translation of switch statement starting with INDIR_JUMP block, stop before Follow Block void EmitSPARKAdaForConditional(int HeaderBlockNum, int FollowBlockNum, FILE *SPARKBodyFile); // recursive descent translation of if-else statement starting with COND_BRANCH block, stop before Follow Block void EmitSPARKAdaLoopCall(STARS_ea_t LoopAddr, std::size_t LoopIndex, FILE *SPARKBodyFile); // emit call to loop proc that will be created later starting at LoopAddr void FreeSSAMemory(void); // After SSA #s are in DEFs and USEs, free SSA data structures. bool FindSwitchStatementFollowBlock(struct SwitchTableInfo &TableInfo); // return false if no consistent follow block int FindCaseFollowBlock(int CaseBlockNum, int HeaderBlockNum, std::size_t IncomingEdgeCount) const; // Start at CaseBlockNum, return followblocknum with IncomingEdgeCount std::size_t FindSwitchIndexForDefaultCaseAddr(STARS_ea_t DefaultCaseAddr) const; // Search SwitchInfoArray for DefaultCaseAddr, return index bool FindPossibleChainAlias(SMPInstr *CurrInst, const STARSOpndTypePtr &DefOp, int SSANum); // Does the DefOp DEF_USE chain starting at CurrInst contain an indirect mem write? bool FindChainAliasHelper(std::list<SMPBasicBlock *>::iterator CurrBlock, const STARSOpndTypePtr &DefOp); // recursive helper for global DefOp with DU-chain that traverses CFG void ChainAliasHelper(std::size_t BlockNum); // helper for AliasAnalysis2() void FindCounterVariables(void); // Mark NUMERIC (and propagate) any DEF that starts at small immed. value and gets only small inc/dec operations. bool CounterVarHelper(const STARSOpndTypePtr &DefOp, int DefSSANum, int BlockNum, bool LocalName, std::list<std::pair<int, STARS_ea_t> > &CounterSSANums); // recursive helper for FindCounterVariables() bool ConditionalTypePropagation(void); // Apply SCC algorithm to unresolved Phi DEFs bool PropagateSignedness(void); // Propagate signedness FG info from DEFs to USEs whenever there is no USE sign info. void MarkSpecialNumericErrorCases(void); // Detect and mark special cases before emitting numeric error annotations. void EmitReturnTargetAnnotations(void); // Emit Indirect Branch Target destinations for return instructions in this func. void EmitFuncPtrShadowingAnnotations(FILE *InfoAnnotFile); // Emit annotations for func ptr shadowing defense bool IsAlreadyShadowed(const ShadowPoint &CriticalOp); // Is CriticalOp already represented in AlreadyShadowed set? void EmitShadowingHelper(FILE *InfoAnnotFile, SMPInstr *CurrInst, bool FuncPtr, STARS_ea_t CallAddr); // common code for different cases in shadowing func ptr, critical args void EmitFuncPtrShadowingAnnotations2(FILE *InfoAnnotFile); // Emit annotations for func ptr shadowing defense void EmitArgShadowingAnnotations(FILE *InfoAnnotFile); // Emit annotations for critical argument shadowing defense void EmitStackMemRangeAnnotations(STARSExpression *MemRangeLowerBound, STARSExpression *MemRangeUpperBound, bool PositiveIncrement, const std::set<STARS_ea_t> &StackPtrCopiesSet, std::set<STARS_ea_t> &StaticMemLeaAddrs); bool MDFindReturnTypes(void); // Fill ReturnRegTypes[] void MDFindIncomingTypes(void); // Fill IncomingRegTypes[] bool IsCallerReturnAddressReadOrWritten(void); // Can the return address of any caller be read or written directly from this function? friend class STARS_IDA_Function_t; friend class STARS_IRDB_Function_t; }; // end class SMPFunction #endif