Skip to content
Snippets Groups Projects
SMPFunction.h 85.7 KiB
Newer Older
jdh8d's avatar
jdh8d committed
/*
 * 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/
 *
jdh8d's avatar
jdh8d committed
 */

#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 <list>
#include <vector>
#include <map>
#include <set>

#include <cstddef>
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.
// Emit CS: or FS: or GS: etc. segment reg prefix if found in operand
#define STARS_SPARK_EMIT_SEGMENT_REGS 0   

	char VarName[MAXSMPVARSTR];
// 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,
clc5q's avatar
clc5q committed
	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
clc5q's avatar
clc5q committed
// 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;
	int BIVIncomingSSANum; // SSA number coming into the loop for BasicInductionVar
	STARS_ea_t BIVIncomingDefAddr;
	std::vector<STARS_ea_t> BIVInsideLoopDefAddrs;
	struct InductionVarTriple BasicInductionVar;
	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);
clc5q's avatar
clc5q committed
// 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.
jdh8d's avatar
jdh8d committed
	SMPFunction(STARS_Function_t *Info, SMPProgram *pgm);  // Default constructor
	~SMPFunction();
clc5q's avatar
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; 
	};
jdh8d's avatar
jdh8d committed
	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(); };
clc5q's avatar
clc5q committed
	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; };
jdh8d's avatar
jdh8d committed

	// exposing the start address of the function. Used in RecurseAndMark
	inline const STARS_ea_t GetStartAddr(void) const { return FirstEA; }; 
jdh8d's avatar
jdh8d committed

	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
clc5q's avatar
clc5q committed
	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.
jdh8d's avatar
jdh8d committed
	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; };
clc5q's avatar
clc5q committed
	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; };
clc5q's avatar
clc5q committed
	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; };
clc5q's avatar
clc5q committed
	std::string GetFuncSPARKSuffixString(void) const; // produce string "_hexaddress" for first address in func
	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

	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; };
jdh8d's avatar
jdh8d committed
	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; };
clc5q's avatar
clc5q committed
	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; };
clc5q's avatar
clc5q committed
	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)
clc5q's avatar
clc5q committed
	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?
clc5q's avatar
clc5q committed
	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
clc5q's avatar
clc5q committed
	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
	SMPProgram* Program;		// pointer to the program I'm part of
jdh8d's avatar
jdh8d committed
	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
	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
jdh8d's avatar
jdh8d committed
//	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.
clc5q's avatar
clc5q committed
	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 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 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
clc5q's avatar
clc5q committed
	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
clc5q's avatar
clc5q committed
	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> 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;
clc5q's avatar
clc5q committed
	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
clc5q's avatar
clc5q committed
	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
	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.
clc5q's avatar
clc5q committed
	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
clc5q's avatar
clc5q committed
	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
clc5q's avatar
clc5q committed
	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.
clc5q's avatar
clc5q committed
	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()
clc5q's avatar
clc5q committed
	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