Newer
Older
/*
* 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 "interfaces/STARSTypes.h"
#include "interfaces/SMPDBInterface.h"
clc5q
committed
#include "base/SMPDataFlowAnalysis.h"
#include "base/SMPInstr.h"
#include "base/SMPBasicBlock.h"
#include "base/ProfilerInformation.h"
class SMPProgram; // forward declaration so we can declare a pointer to an SMPProgram
clc5q
committed
// 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 STARS_ISA_Bytewidth
clc5q
committed
// 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 (-STARS_ISA_Bytewidth)
clc5q
committed
// 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
#define SMP_ANALYZE_STACK_POINTER 1
clc5q
committed
// 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
struct LocalVar {
long offset;
std::size_t size;
// Comparison function for sorting.
bool LocalVarCompare(const LocalVar &LV1, const LocalVar &LV2);
// 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
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,
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
};
enum ControlFlowType {
FALL_THROUGH = 0,
JUMP_IF_THEN = 1, // branch around body within then-clause, no else-clause
JUMP_BEFORE_ELSE = 2,
JUMP_BEFORE_ELSIF = 3,
LOOP_BACK = 4,
LOOP_EXIT = 5
};
// 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
// 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
clc5q
committed
inline SMPProgram *GetProg(void) const { return Program; };
inline const char *GetFuncName(void) const { SMP_get_func_name(GetFirstFuncAddr(), StaticFuncName, MAXSMPSTR-1); return StaticFuncName; };
inline ea_t GetFirstFuncAddr(void) const { return FirstEA; };
uint16_t GetJumpToFollowNodeCounter(ea_t InstAddr) const;
inline long GetTypedDefs(void) const { return TypedDefs; };
inline long GetUntypedDefs(void) const { return UntypedDefs; };
clc5q
committed
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; };
clc5q
committed
inline sval_t GetNetStackPtrDelta(void) const { return NetStackDelta; };
inline sval_t GetPreAllocationStackPtrDelta(void) const { return PreAllocStackDelta; };
inline sval_t GetFramePtrStackDelta(void) const { return FramePointerStackDelta; };
clc5q
committed
inline sval_t GetMaxDirectStackAccessDelta(void) const { return MaxDirectStackAccessDelta; };
clc5q
committed
inline ea_t GetFirstFrameAllocInstAddr(void) const { return LocalVarsAllocInstr; };
inline STARS_asize_t GetLocalVarsSize(void) const { return LocalVarsSize; };
inline std::set<STARSOpndTypePtr, LessOp>::iterator GetFirstGlobalName(void) { return GlobalNames.begin(); };
inline std::set<STARSOpndTypePtr, LessOp>::iterator GetLastGlobalName(void) { return GlobalNames.end(); };
inline std::size_t NumGlobalNames(void) { return GlobalNames.size(); };
inline std::set<STARSOpndTypePtr, LessOp>::iterator FindGlobalName(STARSOpndTypePtr SearchOp) { return GlobalNames.find(SearchOp); };
inline std::list<SMPInstr *>::iterator GetFirstInstIter(void) { return Instrs.begin(); };
std::set<STARSOpndTypePtr, LessOp>::iterator GetFirstLiveIn(void); // LiveInSet.begin()
std::set<STARSOpndTypePtr, LessOp>::iterator GetLastLiveIn(void); // LiveInSet.end()
std::set<STARSOpndTypePtr, LessOp>::iterator GetFirstLiveOut(void); // LiveOutSet.begin()
std::set<STARSOpndTypePtr, LessOp>::iterator GetLastLiveOut(void); // LiveOutSet.end()
std::set<STARSOpndTypePtr, LessOp>::iterator GetFirstVarKill(void); // KillSet.begin()
std::set<STARSOpndTypePtr, LessOp>::iterator 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 ea_t GetStartAddr(void) const { return FuncInfo->get_startEA(); };
inline const std::vector<ea_t> GetCallTargets(void) const { return AllCallTargets; };
inline std::size_t GetNumCallTargets(void) const { return AllCallTargets.size(); };
inline 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(ea_t InstAddr, STARSOpndTypePtr TempOp, struct FineGrainedInfo &FGEntry);
// Return fine grained stack entry for stack op TempOp from instruction at InstAddr
ea_t GetGlobalDefAddr(STARSOpndTypePtr DefOp, int SSANum); // retrieve from GlobalDefAddrBySSA or return BADADDR
int GetBlockNumForPhiDef(STARSOpndTypePtr DefOp, int SSANum);
SMPBasicBlock *GetBlockFromInstAddr(ea_t InstAddr); // retrieve from InstBlockMap or assert
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 std::list<SMPBasicBlock *>::iterator GetLastBlock(void) { return Blocks.end(); };
SMPInstr *GetInstFromAddr(ea_t InstAddr);
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(ea_t InstAddr, STARSOpndTypePtr RTLop); // Return RTLop if not stack opnd; return normalized RTLop otherwise.
inline int GetReturnRegType(uint16 RegNum) const { return ((RegNum < ReturnRegTypes.size()) ? (int) ReturnRegTypes[RegNum] : 0); };
inline struct FineGrainedInfo GetReturnRegFGInfo(uint16 RegNum) const { return ReturnRegFGInfo.at(RegNum); };
inline std::size_t GetReturnRegFGInfoSize(void) const { return ReturnRegFGInfo.size(); };
SMPOperandType GetIncomingRegType(uint16 RegNum); // Get reg type from all call sites.
inline std::map<ea_t, STARSOpndTypePtr>::iterator FindLeaOperand(ea_t addr) { return LeaInstOpMap.find(addr); };
inline std::map<ea_t, STARSOpndTypePtr>::iterator GetLastLeaOperand(void) { return LeaInstOpMap.end(); };
inline std::map<int, struct STARS_SCCP_Const_Struct>::iterator FindConstValue(int DefHashValue) { return ConstantDefs.find(DefHashValue); };
inline std::map<int, struct STARS_SCCP_Const_Struct>::iterator GetLastConstValueIter(void) { return ConstantDefs.end(); };
inline int GetLoopType(std::size_t LoopNumber) const { return LoopTypesByLoopNum.at(LoopNumber); };
int GetLoopNumFromTestBlockNum(int BlockNum) const;
std::set<SMPPhiFunction, LessPhi>::iterator GetPhiIterForPhiDef(std::size_t BlockNumber, STARSOpndTypePtr DefOp, int SSANum);
// Given block # and PhiDef op_t and SSANum, return the Phi iterator or assert.
clc5q
committed
// 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);
clc5q
committed
unsigned short GetStackDefSignMiscInfo(ea_t InstAddr);
unsigned short GetUseSignMiscInfo(int UseHashValue);
clc5q
committed
unsigned short GetStackUseSignMiscInfo(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(ea_t InstAddr);
clc5q
committed
void ResetJumpToFollowNodeCounter(ea_t InstAddr); // Set counter to zero, or insert zero counter if none found
void IncrementJumpToFollowNodeCounter(ea_t InstAddr); // Increment counter, or insert count of 1 if none found
clc5q
committed
inline void IncTypedPhiDefs(void) { ++TypedPhiDefs; return; };
inline void IncUntypedPhiDefs(void) { ++UntypedPhiDefs; return; };
inline void DecTypedPhiDefs(void) { --TypedPhiDefs; return; };
inline void DecUntypedPhiDefs(void) { --UntypedPhiDefs; return; };
inline void SetReturnAddressStatus(FuncType funcType) {
ReturnAddrStatus = funcType;
}
inline void SetFuncProcessed(bool Status) { FuncProcessed = Status; return; };
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 SetHasHashingCode(bool Hashes) { HasHashingCode = Hashes; };
clc5q
committed
void AddCallSource(ea_t addr); // Add a caller to the list of all callers of this function.
bool AddDirectCallTarget(ea_t addr); // Add a direct call target; return true if new target, false if target already added
bool RemoveDirectCallTarget(ea_t TargetAddr); // Remove TargetAddr from DirectCallTargets and AllCallTargets.
bool RemoveIndirectCallTarget(ea_t TargetAddr); // Remove TargetAddr from IndirectCallTargets and AllCallTargets.
void AddLeaOperand(ea_t addr, STARSOpndTypePtr LeaOperand); // add map entry to LeaInstOpMap
void AddNormalizedStackOperand(STARSOpndTypePtr OldOp, ea_t InstAddr, STARSOpndTypePtr NormalizedOp); // add to map for RTL lookup later
clc5q
committed
void UpdateMaxDirectStackAccessOffset(sval_t NewOffset); // Update MaxDirectStackAccessDelta
void SetControlFlowType(ea_t InstAddr, ControlFlowType JumpTypeCode); // insert into ControlFlowMap
std::map<int, struct STARS_SCCP_Const_Struct>::iterator InsertGlobalConstValue(int DefHashValue, struct STARS_SCCP_Const_Struct NewConstEntry);
// Insert SCCP value for global name; change if already found.
clc5q
committed
clc5q
committed
// 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);
clc5q
committed
void UpdateStackDefSignMiscInfo(ea_t InstAddr, unsigned short NewInfo);
void UpdateUseSignMiscInfo(int UseHashValue, unsigned short NewInfo);
clc5q
committed
void UpdateStackUseSignMiscInfo(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(ea_t InstAddr, STARSOpndTypePtr TempOp, struct FineGrainedInfo NewFG);
// Return true if we update fine grained stack entry for stack op TempOp from instruction at InstAddr
inline bool IsFuncProcessed(void) const { return FuncProcessed; };
inline bool IsFuncEmpty(void) const { return (0 >= BlockCount); };
clc5q
committed
inline bool StackPtrAnalysisSucceeded(void) const { return AnalyzedSP; };
inline bool HasSTARSStackPtrAnalysisCompleted(void) const { return STARSStackPtrAnalysisPerformed; };
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 IsDirectlyRecursive(void) const { return DirectlyRecursive; };
inline bool HasSharedChunks(void) const { return GetFuncInfo()->HasSharedChunks(); };
// inline bool HasSharedChunks(void) const { return SharedChunks; };
inline void SetSharedChunks(bool v) { GetFuncInfo()->SetSharedChunks(v); };
// inline void SetSharedChunks(bool v) { SharedChunks=v; };
inline bool HasGoodRTLs(void) const { return BuiltRTLs; };
inline bool HasGoodSSAForm(void) const { return HasGoodSSA; };
inline bool HasReducibleControlFlow(void) const { return HasReducibleCFG; };
inline bool HasPushAfterFrameAlloc(void) const { return PushAfterLocalVarAlloc; };
inline bool IsAddrInFunc(ea_t addr) { return ((addr >= FuncInfo->get_startEA()) && (addr <= FuncInfo->get_endEA())); }
inline bool IsLibFunc(void) const { return LibFunc; };
inline bool IsLeaf(void) const { return (!IndirectCalls && DirectCallTargets.empty()); };
clc5q
committed
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
clc5q
committed
inline bool OutArgsRegionComputed(void) const { return OutgoingArgsComputed; };
bool IsInOutgoingArgsRegion(STARSOpndTypePtr DestOp); // Does DestOp fall within outgoing args area?
bool IsInIncomingArgsRegion(SMPInstr *SourceInst, STARSOpndTypePtr SourceOp) const; // Does SourceOp from SourceInst fall within incoming args area?
inline bool IsGlobalName(STARSOpndTypePtr RefOp) const { return (GlobalNames.end() != GlobalNames.find(RefOp)); };
inline bool UsesFramePointer(void) const { return UseFP; };
inline bool FuncHasHashingCode(void) const { return HasHashingCode; };
clc5q
committed
inline bool HasGoodFGStackTable(void) const { return (!(FineGrainedStackTable.empty())); };
inline bool IsLiveIn(STARSOpndTypePtr CurrOp) const {
clc5q
committed
return (Blocks.front()->IsLiveIn(CurrOp));
clc5q
committed
}
inline bool IsLiveOut(STARSOpndTypePtr CurrOp) const {
clc5q
committed
return (LiveOutSet.end() != LiveOutSet.find(CurrOp));
}
inline bool IsVarKill(STARSOpndTypePtr CurrOp) const {
clc5q
committed
return (KillSet.end() != KillSet.find(CurrOp));
}
inline bool IsJumpFollowBlock(ea_t InstAddr) const { return (JumpFollowNodesSet.find(InstAddr) != JumpFollowNodesSet.end()); }
bool IsInStackPtrCopySet(STARSOpndTypePtr CurrOp);
inline bool DoesStackFrameExtendPastStackTop(void) const { return StackFrameExtendsPastStackTop; };
inline bool IsRegPreserved(std::size_t RegNum) const { return (PreservedRegsBitmap[RegNum] != 0); };
clc5q
committed
// Printing methods
void Dump(void); // debug dump
clc5q
committed
void ResetProcessedBlocks(void); // Set Processed flag to false in all blocks
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.
void RemoveBlock(SMPBasicBlock *CurrBlock, std::list<SMPBasicBlock *>::iterator &BlockIter); // Remove a basic block and its instructions.
void RemoveCallingBlocks(void) const; // Func is empty, so add all blocks that call it to Program->BlocksPendingRemoval.
clc5q
committed
void ComputeGlobalSets(void); // compute LiveOut, Kill sets for function
void AnalyzeFunc(void); // Analyze all instructions in function
void AdvancedAnalysis(void); // Analyses that depend on whole program info but not SSA.
std::size_t UnprocessedCalleesCount(void); // Count of callees that have FuncProcessed == false
sval_t GetStackAdjustmentForCallee(ea_t CallAddr); // Get stack pointer adjustment in basic block, after CallAddr
sval_t GetStackDeltaForCallee(ea_t CallTargetAddr); // Get stack pointer delta for callee function, which starts at CallTargetAddr
sval_t ComputeGlobalStackAdjustment(void); // Find consistent or smallest stack adjustment after all calls to this function, program-wide
void ComputeTempReachingDefs(STARSOpndTypePtr TempOp, ea_t UseAddr); // Compute the TempReachingDefs set that reaches UseAddr for TempOp
void ComputeTempStackDeltaReachesList(STARSOpndTypePtr TempOp); // Compute the TempStackDeltaReachesList for TempOp for all DefAddrs in TempReachingDefs
bool FindReachingStackDelta(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 EmitAnnotations(FILE *AnnotFile, FILE *InfoAnnotFile);
void EmitFuncSPARKAda(void); // Emit SPARK Ada translation of function
void LiveVariableAnalysis(bool Recomputing); // Perform Live Variable Analysis across all blocks
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); // Does basic block HeadBlockNum dominate basic block TailBlockNum?
bool IsBlockInAnyLoop(int BlockNum); // Is block (with block # BlockNum) inside any loop?
bool IsBlockInLoop(int BlockNum, std::size_t LoopNum); // Is block (with block # BlockNum) inside loop # LoopNum?
void BuildLoopList(int BlockNum, std::list<std::size_t> &LoopList); // build list of loop numbers that BlockNum is part of.
void AliasAnalysis(void); // Find memory writes with possible aliases
void InferTypes(bool FirstIter); // Determine NUMERIC, POINTER, etc. for all operands
clc5q
committed
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(STARSOpndTypePtr DefOp, int SSANum, SMPBasicBlock *DefBlock, bool CallInst, 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(STARSOpndTypePtr UseOp, SMPMetadataType Status, int SSANum, 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 EvaluateAllPhiConstants(int BlockNum, 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(STARSOpndTypePtr DefOp, int DefSSANum, std::size_t DefAddr, int &IdiomCode); // Do we not care if DEF underflowed, due to how it is used?
bool HasIntErrorCallSink(STARSOpndTypePtr DefOp, int DefSSANum, std::size_t DefAddr, std::string &SinkString, bool &FoundAnyCall); // DEF is passed to known system/lib call
bool WritesAboveLocalFrame(STARSOpndTypePtr DestOp, bool OpNormalized, ea_t InstAddr); // Is DestOp direct stack access to caller's frame?
bool AccessAboveLocalFrame(STARSOpndTypePtr StackOp, bool OpNormalized, ea_t InstAddr, bool WriteAccess); // Is StackOp direct stack access to caller's frame?
bool IsDefUsedInMemWrite(STARSOpndTypePtr DefOp, int DefSSANum, ea_t DefAddr); // Is Defop+DefSSANum at DefAddr used as address reg or as source operand in memory 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
clc5q
committed
SMPProgram* Program; // pointer to the program I'm part of
clc5q
committed
ea_t FirstEA; // address of first instruction in the function
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 DirectlyRecursive; // Calls itself
// 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 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 AnalyzedSP; // Were stack pointer change points successfully analyzed?
clc5q
committed
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 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 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 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.
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()
clc5q
committed
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 (4 for most machines)
std::size_t OutgoingArgsSize; // portion of LocalVarsSize that is really outgoing args space
ea_t LocalVarsAllocInstr; // address of instr that allocates stack frame
ea_t LocalVarsDeallocInstr; // address of epilogue instr that deallocs frame
adiff_t AllocPointDelta; // IDA sp_delta AFTER stack frame allocation instruction
sval_t MinStackDelta; // smallest (negative) value that stack pointer reaches, relative
// to the value it has at the entry point of the function
sval_t MaxStackDelta; // highest (positive) value that stack pointer reaches, relative
// to the value it has at the entry point of the function
sval_t MinStackAccessOffset; // Normalized or unnormalized, min stack byte offset in any DEF or USE
sval_t MaxStackAccessLimit; // Normalized or unnormalized, 1 greater than max stack byte offset in any DEF or USE
clc5q
committed
sval_t NetStackDelta; // Net change to stack pointer after function returns; +4 for most functions,
// because they pop off the return address while returning.
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.
sval_t FramePointerStackDelta; // Stack delta when framepointer := stackpointer was encountered; zero if UseFP is false.
sval_t GlobalStackAdjustment; // Stack adjustment seen program-wide after calls to this function; zero or positive.
clc5q
committed
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)
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
std::list<SMPInstr *> Instrs;
std::list<SMPBasicBlock *> Blocks;
std::set<ea_t> DirectCallTargets; // addresses called directly
std::set<ea_t> IndirectCallTargets; // addresses called by indirect calls
std::vector<ea_t> AllCallTargets; // union of direct and indirect
std::set<ea_t> AllCallSources; // functions that call this one
std::set<ea_t> AllCallSites; // instructions that call this function
std::set<ea_t> JumpFollowNodesSet; // addresses that are jumped to when exiting if-then-elsif-else structures
std::map<ea_t, SMPBasicBlock *> InstBlockMap;
std::vector<SMPBasicBlock *> RPOBlocks;
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
std::set<STARSOpndTypePtr, LessOp> 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> StackFrameMap; // memory map of every byte on stack frame
std::vector<struct FineGrainedInfo> FineGrainedStackTable; // built using opcode analysis, not IDA stack info
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<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> DFSMarkers; // vector indexed by block number, -1 => unvisited, 0 => visited but not all descendants visited, 1 => completed
std::map<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, 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<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<ea_t, struct FineGrainedInfo> StackDefFGInfo; // map stack FG info to instruction address of stack def; UNUSED
std::map<ea_t, struct FineGrainedInfo> StackUseFGInfo; // map stack FG info to instruction address of stack use; UNUSED
std::map<ea_t, STARSOpndTypePtr> LeaInstOpMap; // map original Lea instruction pseudo-memory operand to instruction address.
std::map<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.
clc5q
committed
// Two sets used in live variable analysis. LiveIn and UpExposed can be obtained from Blocks.front().
std::set<STARSOpndTypePtr, LessOp> KillSet; // registers killed in this function
std::set<STARSOpndTypePtr, LessOp> LiveOutSet; // Live-Out registers in this function
// Tracking stack pointer and frame pointer saves, copies, and restores
std::set<std::pair<STARSOpndTypePtr, std::pair<ea_t, sval_t> >, LessStackDeltaCopy> StackPtrCopySet; // triple: operand holding copy, InstAddr where copy is made, stack delta for copy
std::list<std::pair<ea_t, sval_t> > TempStackDeltaReachesList; // Used for temporary lookups of particular op_t in StackPtrCopySet.
std::set<ea_t, LessAddr> TempReachingDefs; // Temporary list of InstAddrs with defs of one op_t that reach a particular InstAddr.
std::map<std::pair<STARSOpndTypePtr, ea_t>, STARSOpndTypePtr, LessDefinition> NormalizedStackOpsMap; // normalized stack operands, indexed by instruction address (for lookup from RTLs).
std::map<std::pair<STARSOpndTypePtr, ea_t>, std::map<std::pair<STARSOpndTypePtr, ea_t>, 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
clc5q
committed
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.
clc5q
committed
void EraseInstRange(ea_t FirstAddr, ea_t LastAddr);
void SetLinks(void); // Link basic blocks and map instructions to blocks
bool FindDistantCodeFragment(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, ea_t InstAddr, sval_t StackDelta); // return true if inserted, false if present already (update delta in that case)
clc5q
committed
void FindPreservedRegs(void); // Determined which regs are not killed by func or its callees; set bits in PreservedRegsBitmap
clc5q
committed
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.
ea_t FindAllocPoint(STARS_asize_t); // Deal with difficult to find stack frame allocations
bool MDFixFrameInfo(void); // Redefine stack regions for our needs
bool MDFixUseFP(void); // Fix IDA errors affecting UseFP
void BuildLocalVarTable(void); // Determine local variable boundaries on the stack
void SemiNaiveLocalVarID(void); // Semi-naive algorithm for local var boundaries ID
void UpdateMinMaxStackOffsets(SMPInstr *CurrInst, STARSOpndTypePtr TempOp); // Update MinStackAccessOffset and MaxStackAccessLimit if TempOp is stack access
bool AuditLocalVarTable(void); // Check and correct IDA Pro listing of local frame members.
void FindOutgoingArgsSize(void); // Find portion of local frame that is outgoing args
inline void SetStackFrameExtendsPastStackTop(void) { StackFrameExtendsPastStackTop = true; };
bool IndexedWritesAboveLocalFrame(STARSOpndTypePtr DestOp); // Is DestOp direct stack write to caller's frame?
bool MDGetStackOffsetAndSize(SMPInstr *Instr, STARSOpndTypePtr TempOp, sval_t BaseValue, 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 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 DetectLoops(void); // Detect which blocks are in which loops and populate FuncLoopsByBlock data structure.
bool DoesBlockExitLoop(std::size_t LoopNumber, SMPBasicBlock *LoopBlock); // return true if block can exit the loop.
void FreeSSAMemory(void); // After SSA #s are in DEFs and USEs, free SSA data structures.
bool FindPossibleChainAlias(SMPInstr *CurrInst, 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, STARSOpndTypePtr DefOp);
// recursive helper for global DefOp with DU-chain that traverses CFG
clc5q
committed
void FindCounterVariables(void); // Mark NUMERIC (and propagate) any DEF that starts at small immed. value and gets only small inc/dec operations.
bool CounterVarHelper(STARSOpndTypePtr DefOp, int DefSSANum, int BlockNum, bool LocalName, std::list<std::pair<int, 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.
bool MDFindReturnTypes(void); // Fill ReturnRegTypes[]
clc5q
committed
void MDFindIncomingTypes(void); // Fill IncomingRegTypes[]
clc5q
committed
bool IsCallerReturnAddressReadOrWritten(void); // Can the return address of any caller be read or written directly from this function?
friend class STARS_IDA_Function_t;
}; // end class SMPFunction
#endif