Skip to content
Snippets Groups Projects
SMPDataFlowAnalysis.cpp 200 KiB
Newer Older
	*this = CopyIn;
	return;
}

// Assignment operator for copy constructor use.
DefOrUse &DefOrUse::operator=(const DefOrUse &rhs) {
	this->Operand = rhs.Operand;
	this->OpType = rhs.OpType;
	this->NonSpeculativeOpType = rhs.NonSpeculativeOpType;
	this->SSANumber = rhs.SSANumber;
	this->MetadataStatus = rhs.MetadataStatus;
	this->NoTruncation = rhs.NoTruncation;
// Set the operand type for this DEF or USE - don't forget to take
//  into account the speculative (profiler) status.
void DefOrUse::SetType(SMPOperandType Type, const SMPInstr *Instr) 
{
	SMPOperandType OldType = this->OpType;
	SMPOperandType NewType = Type;
	if (Instr->GetBlock()->GetFunc()->GetIsSpeculative()) {
		NewType = (SMPOperandType)(((int)NewType) | PROF_BASE);
		if (!IsProfDerived(OldType))
			this->NonSpeculativeOpType = OldType;
	this->OpType = NewType;
// Set the indirect memory write flag.
void DefOrUse::SetIndWrite(bool IndMemWrite) {
	this->IndWrite = IndMemWrite;
	return;
}
void DefOrUse::SetNoTruncation(bool NoTruncFlag) {
	this->NoTruncation = NoTruncFlag;
	return;
}

void DefOrUse::SetNoOverflow(bool NoOverflowFlag) {
	this->NoOverflow = NoOverflowFlag;
	return;
}

// Debug printing.
void DefOrUse::Dump(void) const {
	PrintListOperand(this->Operand, this->SSANumber);
	if (IsEqType(this->OpType , NUMERIC))
	else if (IsEqType(this->OpType , CODEPTR))
	else if (IsEqType(this->OpType , POINTER))
	else if (IsEqType(this->OpType , STACKPTR))
	else if (IsEqType(this->OpType , GLOBALPTR))
	else if (IsEqType(this->OpType , HEAPPTR))
	else if (IsEqType(this->OpType , PTROFFSET))
	else if (IsEqType(this->OpType , UNKNOWN))
	if (IsProfDerived(this->OpType))
	// Don't write anything for UNINIT OpType

	// Emit the metadata status.
	if (DEF_METADATA_UNUSED == this->MetadataStatus)
	else if (DEF_METADATA_USED == this->MetadataStatus)
	else if (DEF_METADATA_REDUNDANT == this->MetadataStatus)
	// Is the DEF possibly aliased because of an indirect write in
	//  the DEF-USE chain?
	if (this->IndWrite)
	return;
} // end of DefOrUse::Dump()

// *****************************************************************
// Class DefOrUseSet
// *****************************************************************

// Default constructor.
DefOrUseSet::DefOrUseSet(void) {
// Destructor.
DefOrUseSet::~DefOrUseSet() {
// Find the reference for a given operand type.
set<DefOrUse, LessDefUse>::iterator DefOrUseSet::FindRef(op_t SearchOp) {
	set<DefOrUse, LessDefUse>::iterator CurrRef;
	DefOrUse DummyRef(SearchOp);
	CurrRef = this->Refs.find(DummyRef);
	return CurrRef;
}

// Insert a new DEF or USE; must be new, insert must succeed else we assert.
set<DefOrUse, LessDefUse>::iterator DefOrUseSet::InsertRef(DefOrUse Ref) {
	pair<set<DefOrUse, LessDefUse>::iterator, bool> InsertResult;
	InsertResult = this->Refs.insert(Ref);
	assert(InsertResult.second);
	return InsertResult.first;
}

// Set a Def or Use into the list, along with its type.
void DefOrUseSet::SetRef(op_t Ref, SMPOperandType Type, int SSASub) {
	pair<set<DefOrUse, LessDefUse>::iterator, bool> InsertResult;
	DefOrUse CurrRef(Ref, Type, SSASub);
	InsertResult = this->Refs.insert(CurrRef);
	if ((!(InsertResult.second)) && (o_reg != Ref.type)) {
		SMP_msg("ERROR: Inserted duplicate DEF or USE.\n");
	}
// Change the indirect write status for a reference.
set<DefOrUse, LessDefUse>::iterator DefOrUseSet::SetOp(set<DefOrUse, LessDefUse>::iterator CurrRef, op_t NewOp) {
	// To change a field within a set, we must grab a copy, change the copy,
	//  delete the old set member, and insert the updated copy as a new member.
	assert(CurrRef != this->Refs.end());
	DefOrUse NewCopy = (*CurrRef);
	NewCopy.SetOp(NewOp);
	this->Refs.erase(CurrRef);
	pair<set<DefOrUse, LessDefUse>::iterator, bool> InsertResult;
	InsertResult = this->Refs.insert(NewCopy);
	assert(InsertResult.second);
	return InsertResult.first;
} // end of DefOrUseSet::SetOp()

// Change the SSA subscript for a reference.
set<DefOrUse, LessDefUse>::iterator DefOrUseSet::SetSSANum(op_t CurrOp, int NewSSASub) {
	// To change a field within a set, we must grab a copy, change the copy,
	//  delete the old set member, and insert the updated copy as a new member.
	set<DefOrUse, LessDefUse>::iterator CurrRef = this->FindRef(CurrOp);
	assert(CurrRef != this->Refs.end());
	set<DefOrUse, LessDefUse>::iterator NextRef = CurrRef;
	++NextRef;
	DefOrUse NewCopy = (*CurrRef);
	NewCopy.SetSSANum(NewSSASub);
	this->Refs.erase(CurrRef);
	CurrRef = this->Refs.insert(NextRef, NewCopy);
	return CurrRef;
} // end of DefOrUseSet::SetSSANum()

// Change the operand type for a reference.
set<DefOrUse, LessDefUse>::iterator DefOrUseSet::SetType(op_t CurrOp, SMPOperandType Type, const SMPInstr* Instr) {
	// To change a field within a set, we must grab a copy, change the copy,
	//  delete the old set member, and insert the updated copy as a new member.
	set<DefOrUse, LessDefUse>::iterator CurrRef = this->FindRef(CurrOp);
	assert(CurrRef != this->Refs.end());
#if 1
	if (o_imm == CurrOp.type) {
		if (UNINIT != CurrRef->GetType() && Type != CurrRef->GetType()) {
			SMP_msg("ERROR: Changing type of immediate from %d to %d at %lx: ", CurrRef->GetType(), Type, (unsigned long) Instr->GetAddr());
			SMPInstr InstCopy = (*Instr);
			InstCopy.Dump();
	DefOrUse NewCopy = (*CurrRef);
	this->Refs.erase(CurrRef);
	pair<set<DefOrUse, LessDefUse>::iterator, bool> InsertResult;
	InsertResult = this->Refs.insert(NewCopy);
	assert(InsertResult.second);
	CurrRef = InsertResult.first;
} // end of DefOrUseSet::SetType()

// Change the Metadata type for a reference.
set<DefOrUse, LessDefUse>::iterator DefOrUseSet::SetMetadata(op_t CurrOp, SMPMetadataType Status) {
	// To change a field within a set, we must grab a copy, change the copy,
	//  delete the old set member, and insert the updated copy as a new member.
	set<DefOrUse, LessDefUse>::iterator CurrRef = this->FindRef(CurrOp);
	assert(CurrRef != this->Refs.end());
	DefOrUse NewCopy = (*CurrRef);
	NewCopy.SetMetadataStatus(Status);
	this->Refs.erase(CurrRef);
	pair<set<DefOrUse, LessDefUse>::iterator, bool> InsertResult;
	InsertResult = this->Refs.insert(NewCopy);
	assert(InsertResult.second);
	CurrRef = InsertResult.first;
	return CurrRef;
} // end of DefOrUseSet::SetMetadata()
// Change the indirect write status for a reference.
set<DefOrUse, LessDefUse>::iterator DefOrUseSet::SetIndWrite(op_t CurrOp, bool IndWriteFlag) {
	// To change a field within a set, we must grab a copy, change the copy,
	//  delete the old set member, and insert the updated copy as a new member.
	set<DefOrUse, LessDefUse>::iterator CurrRef = this->FindRef(CurrOp);
	assert(CurrRef != this->Refs.end());
	DefOrUse NewCopy = (*CurrRef);
	NewCopy.SetIndWrite(IndWriteFlag);
	this->Refs.erase(CurrRef);
	pair<set<DefOrUse, LessDefUse>::iterator, bool> InsertResult;
	InsertResult = this->Refs.insert(NewCopy);
	assert(InsertResult.second);
	CurrRef = InsertResult.first;
	return CurrRef;
} // end of DefOrUseSet::SetIndWrite()

// Change the ignore apparent truncation flag for a reference.
set<DefOrUse, LessDefUse>::iterator DefOrUseSet::SetNoTruncation(op_t CurrOp, bool NoTruncFlag) {
	// To change a field within a set, we must grab a copy, change the copy,
	//  delete the old set member, and insert the updated copy as a new member.
	set<DefOrUse, LessDefUse>::iterator CurrRef = this->FindRef(CurrOp);
	assert(CurrRef != this->Refs.end());
	DefOrUse NewCopy = (*CurrRef);
	NewCopy.SetNoTruncation(NoTruncFlag);
	this->Refs.erase(CurrRef);
	pair<set<DefOrUse, LessDefUse>::iterator, bool> InsertResult;
	InsertResult = this->Refs.insert(NewCopy);
	assert(InsertResult.second);
	CurrRef = InsertResult.first;
	return CurrRef;
} // end of DefOrUseSet::SetNoTruncation()

// Change the ignore apparent overflow flag for a reference.
set<DefOrUse, LessDefUse>::iterator DefOrUseSet::SetNoOverflow(op_t CurrOp, bool NoOverflowFlag) {
	// To change a field within a set, we must grab a copy, change the copy,
	//  delete the old set member, and insert the updated copy as a new member.
	set<DefOrUse, LessDefUse>::iterator CurrRef = this->FindRef(CurrOp);
	assert(CurrRef != this->Refs.end());
	DefOrUse NewCopy = (*CurrRef);
	NewCopy.SetNoOverflow(NoOverflowFlag);
	this->Refs.erase(CurrRef);
	pair<set<DefOrUse, LessDefUse>::iterator, bool> InsertResult;
	InsertResult = this->Refs.insert(NewCopy);
	assert(InsertResult.second);
	CurrRef = InsertResult.first;
	return CurrRef;
} // end of DefOrUseSet::SetNoOverflow()

// Debug printing.
	set<DefOrUse, LessDefUse>::iterator CurrRef;
	for (CurrRef = this->Refs.begin(); CurrRef != this->Refs.end(); ++CurrRef) {
		CurrRef->Dump();
	}
clc5q's avatar
clc5q committed
// Do all types agree, ignoring any flags registers in the set? This is used
//  for conditional move instructions; if all types agree, it does not matter
//  whether the move happens or not.
bool DefOrUseSet::TypesAgreeNoFlags(void) {
	bool FoundFirstUse = false;
	set<DefOrUse, LessDefUse>::iterator CurrUse;
	SMPOperandType UseType = UNINIT;
	for (CurrUse = this->Refs.begin(); CurrUse != this->Refs.end(); ++CurrUse) {
		if (!(CurrUse->GetOp().is_reg(X86_FLAGS_REG))) { // ignore flags
			if (!FoundFirstUse) {
				FoundFirstUse = true;
				UseType = CurrUse->GetType();
			}
			else {
				if (IsNotEqType(CurrUse->GetType(), UseType)) {
					return false; // inconsistent types
				}
			}
		}
	}
	return true;
} // end of DefOrUseSet::TypesAgreeNoFlags()

clc5q's avatar
clc5q committed
// *****************************************************************
// Class DefOrUseList
// *****************************************************************

// Default constructor.
DefOrUseList::DefOrUseList(void) {
clc5q's avatar
clc5q committed
	return;
}

// Set a Def or Use into the list, along with its type.
clc5q's avatar
clc5q committed
void DefOrUseList::SetRef(op_t Ref, SMPOperandType Type, int SSASub) {
	DefOrUse CurrRef(Ref, Type, SSASub);
	this->Refs.push_back(CurrRef);
clc5q's avatar
clc5q committed
	return;
}

// Get a reference by index.
clc5q's avatar
clc5q committed
DefOrUse DefOrUseList::GetRef(size_t index) const {
clc5q's avatar
clc5q committed
	return Refs[index];
}

// Change the SSA subscript for a reference.
void DefOrUseList::SetSSANum(size_t index, int NewSSASub) {
	this->Refs[index].SetSSANum(NewSSASub);
	return;
}

// Change the operand type for a reference.
void DefOrUseList::SetType(size_t index, SMPOperandType Type, const SMPInstr* Instr) {
	this->Refs[index].SetType(Type,Instr);
	return;
}

// Debug printing.
void DefOrUseList::Dump(void) const {
	for (size_t index = 0; index < this->Refs.size(); ++index) {
		Refs[index].Dump();
	}
	return;
}

// Erase duplicate entries, in case SMPInstr::MDFixupDefUseLists() adds one.
void DefOrUseList::EraseDuplicates(void) {
	set<op_t, LessOp> TempRefs; // Use STL set to find duplicates
	set<op_t, LessOp>::iterator TempIter;
	vector<DefOrUse>::iterator RefIter;

	RefIter = this->Refs.begin();
	while (RefIter != this->Refs.end()) {
		TempIter = TempRefs.find(RefIter->GetOp());
		if (TempIter == TempRefs.end()) { // not already in set
			TempRefs.insert(RefIter->GetOp());
			++RefIter;
		}
		else { // found it in set already
			RefIter = this->Refs.erase(RefIter);
		}
	}
	return;
} // end of DefOrUseList::EraseDuplicates()

clc5q's avatar
clc5q committed
// *****************************************************************
// Class SMPPhiFunction
// *****************************************************************

// Constructor
SMPPhiFunction::SMPPhiFunction(int GlobIndex, const DefOrUse &Def) {
clc5q's avatar
clc5q committed
	this->index = GlobIndex;
clc5q's avatar
clc5q committed
	return;
clc5q's avatar
clc5q committed
}

DefOrUse SMPPhiFunction::GetDefCopy(void) const {
	DefOrUse DefCopy(this->DefName);
	return DefCopy;
}

clc5q's avatar
clc5q committed
// Add a phi item to the list
void SMPPhiFunction::PushBack(DefOrUse Ref) {
	this->SubscriptedOps.SetRef(Ref.GetOp(), Ref.GetType(), Ref.GetSSANum());
	return;
}

// Set the SSA number of the defined variable.
void SMPPhiFunction::SetSSADef(int NewSSASub) {
	this->DefName.SetSSANum(NewSSASub);
	return;
}

// Set the SSA number of the input variable.
void SMPPhiFunction::SetSSARef(size_t index, int NewSSASub) {
	this->SubscriptedOps.SetSSANum(index, NewSSASub);
	return;
}

// Set the type of the defined variable.
void SMPPhiFunction::SetDefType(SMPOperandType Type, const SMPInstr* Instr) {
	this->DefName.SetType(Type, Instr);
	return;
}

// Set the type of the input variable.
void SMPPhiFunction::SetRefType(size_t index, SMPOperandType Type, const SMPInstr* Instr) {
	this->SubscriptedOps.SetType(index, Type, Instr);
// Set the metadata status of the DEF variable.
void SMPPhiFunction::SetDefMetadata(SMPMetadataType Status) {
	this->DefName.SetMetadataStatus(Status);
	return;
} // end of SMPPhiFunction::SetDefMetadata()

// Does at least one USE have a type other than UNINIT?
bool SMPPhiFunction::HasTypedUses(void) {
	size_t index;
	for (index = 0; index < this->GetPhiListSize(); ++index) {
		if (UNINIT != this->GetUseType(index))
			return true;
	}
	return false;
} // end of SMPPhiFunction::HasTypedUses()

// Return the result of applying the conditional type propagation meet operator
//  over all the USE types.
SMPOperandType SMPPhiFunction::ConditionalMeetType(void) const {
	SMPOperandType MeetType;
	SMPOperandType PtrType = UNINIT;
	SMPOperandType NumericType = UNINIT; // can end up NUMERIC or CODEPTR
	bool FoundUNINIT  = false; // any USE type UNINIT?
	bool FoundNUMERIC = false; // any USE type NUMERIC?
	bool FoundPOINTER = false; // includes all POINTER subtypes
	bool FoundUNKNOWN = false; // any USE type UNKNOWN?
	bool FoundPTROFFSET = false; // any USE type PTROFFSET?
	bool FoundNEGATEDPTR = false; // any USE type NEGATEDPTR?
	bool ProfilerDerived = false; // was any USE type Profiler-derived?

	for (size_t index = 0; index < this->GetPhiListSize(); ++index) {
		SMPOperandType UseType = this->GetUseType(index);
		if (IsEqType(UseType, UNINIT))
			FoundUNINIT = true;
		else if (IsNumeric(UseType)) {
			FoundNUMERIC = true;
			if (IsEqType(NumericType, CODEPTR)) {
				// Already refined. If current type agrees, leave it
				//  alone, else revert to generic type NUMERIC.
				if (IsNotEqType(UseType, NumericType))
					NumericType = NUMERIC;
			}
			else {
				// Have not yet refined NumericType; might still be UNINIT.
				if (IsEqType(UNINIT, NumericType))
					NumericType = UseType;
				else { // NumericType is NUMERIC; leave it as NUMERIC.
					assert(IsEqType(NUMERIC, NumericType));
				}
			}
		}
		else if (IsDataPtr(UseType)) {
			FoundPOINTER = true;
			// Perform a meet over the pointer types.
			if (IsRefinedDataPtr(PtrType)) {
				// Already refined. If current type agrees, leave it
				//  alone, else revert to generic type POINTER.
				if (IsNotEqType(UseType, PtrType))
					PtrType = POINTER;
			}
			else {
				// Have not yet refined PtrType; might still be UNINIT.
				if (IsEqType(UNINIT, PtrType))
					PtrType = UseType;
				else { // PtrType is POINTER because we saw POINTER or
					// had a conflict between pointer refinements; leave
					// it as POINTER.
					assert(IsEqType(POINTER, PtrType));
				}
			}
		}
		else if (IsEqType(PTROFFSET, UseType)) 
			FoundPTROFFSET = true;
		else if (IsEqType(NEGATEDPTR, UseType)) 
			FoundNEGATEDPTR = true;
		else if (IsUnknown(UseType))
			FoundUNKNOWN = true;

		if (IsProfDerived(UseType))
			ProfilerDerived = true;
	}

	// Use the boolean flags to compute the meet function.
	if (FoundUNKNOWN || (FoundNUMERIC && FoundPOINTER) 
		|| ((FoundNUMERIC || FoundPOINTER || FoundNEGATEDPTR) && FoundPTROFFSET)
		|| ((FoundNUMERIC || FoundPOINTER || FoundPTROFFSET) && FoundNEGATEDPTR))
		MeetType = UNKNOWN;
	else if (FoundNUMERIC)
		MeetType = NumericType;
	else if (FoundPOINTER)
		MeetType = PtrType;
	else if (FoundPTROFFSET)
		MeetType = PTROFFSET;
	else if (FoundNEGATEDPTR)
		MeetType = NEGATEDPTR;
	else {
		assert(FoundUNINIT);
		MeetType = UNINIT;
	}
	if (ProfilerDerived)
		MeetType = MakeProfDerived(MeetType);
	return MeetType;
} // end of SMPPhiFunction::ConditionalMeetType()

// Debug printing.
void SMPPhiFunction::Dump(void) const {
// *****************************************************************
// Class SMPDefUseChain
// *****************************************************************

// Constructors
SMPDefUseChain::SMPDefUseChain(void) {
	this->SSAName.type = o_void;
	this->RefInstrs.push_back((unsigned short) BADADDR);
	return;
}

SMPDefUseChain::SMPDefUseChain(op_t Name, ea_t Def) {
	return;
}

// Set the variable name.
void SMPDefUseChain::SetName(op_t Name) {
	if (o_reg == Name.type) {
		// We want to map AH, AL, and AX to EAX, etc. throughout our data flow analysis
		//  and type inference systems.
		CanonicalizeOpnd(Name);
	this->SSAName = Name;
	return;
}

// Set the DEF instruction.
void SMPDefUseChain::SetDef(ea_t Def) {
	this->RefInstrs[0] = (unsigned short) Def;
	return;
}

// Push a USE onto the list
void SMPDefUseChain::PushUse(ea_t Use) {
	this->RefInstrs.push_back((unsigned short) Use);
// Set the indirect memory write flag.
void SMPDefUseChain::SetIndWrite(bool IndMemWrite) {
	this->IndWrite = IndMemWrite;
	return;
}

void SMPDefUseChain::Dump(int SSANum) const {
	PrintListOperand(this->SSAName, SSANum);
	if (this->RefInstrs.size() < 1) {
	SMP_msg("\n DEF: %x USEs: ", this->RefInstrs.at(0));
	size_t index;
	for (index = 1; index < this->RefInstrs.size(); ++index)
		SMP_msg("%x ", this->RefInstrs.at(index));
	SMP_msg("\n");
	return;
} // end of SMPDefUseChain::Dump()

// *****************************************************************
// Class SMPDUChainArray
// *****************************************************************
SMPDUChainArray::SMPDUChainArray(void) {
	this->SSAName.type = o_void;
	this->DUChains.clear();
SMPDUChainArray::SMPDUChainArray(op_t Name, ea_t FirstAddrMinusOne) {
	if (o_reg == Name.type) {
		// We want to map AH, AL, and AX to EAX, etc. throughout our data flow analysis
		//  and type inference systems.
		CanonicalizeOpnd(Name);
	this->BaseAddr = FirstAddrMinusOne;
	this->DUChains.clear();
ea_t SMPDUChainArray::GetLastUse(int SSANum) const {
	ea_t TempAddr = DUChains.at(SSANum).GetLastUse();
	if (BADADDR != TempAddr) {
		// If BADADDR, leave it as BADADDR. Otherwise, add in BaseAddr.
		TempAddr += this->BaseAddr;
	}
	return TempAddr;
}

void SMPDUChainArray::SetName(op_t Name, ea_t FirstAddrMinusOne) {
	if (o_reg == Name.type) {
		// We want to map AH, AL, and AX to EAX, etc. throughout our data flow analysis
		//  and type inference systems.
		CanonicalizeOpnd(Name);
	this->BaseAddr = FirstAddrMinusOne;
	for (index = 0; index < this->GetSize(); ++index) {
		this->DUChains.at(index).Dump((int) index);
	}
	return;
}

// *****************************************************************
// Class SMPCompleteDUChains
// *****************************************************************

// DEBUG dump.
void SMPCompleteDUChains::Dump(void) const {
	size_t index;
	for (index = 0; index < this->ChainsByName.size(); ++index) {
		this->ChainsByName.at(index).Dump();
	}
	return;
} // end of SMPCompleteDUChains::Dump()

// *****************************************************************
// Class STARSBitSet
// *****************************************************************

// Constructors.
STARSBitSet::STARSBitSet() {
	this->BitLimit = 0;
}

// Get methods
bool STARSBitSet::GetBit(size_t BitIndex) const {
	size_t ByteIndex = BitIndex / 8;
	size_t BitNumber = BitIndex % 8;
	return (0 != (this->STARSBits.at(ByteIndex) & STARSBitMasks[BitNumber]));
}

// Set methods
void STARSBitSet::AllocateBits(size_t Size) {
	size_t Bytes = Size / 8;
	size_t ExtraBits = Size % 8;
		this->STARSBits.resize(1 + Bytes);
		this->STARSBits.resize(Bytes);
	}
	for (Bytes = 0; Bytes < this->STARSBits.size(); ++Bytes) {
		this->STARSBits[Bytes] = 0;
	}
}

void STARSBitSet::SetBit(size_t BitIndex) {
	size_t ByteIndex = BitIndex / 8;
	size_t BitNumber = BitIndex % 8;
	this->STARSBits[ByteIndex] |= STARSBitMasks[BitNumber];
	return;
}

void STARSBitSet::ResetBit(size_t BitIndex) {
	size_t ByteIndex = BitIndex / 8;
	size_t BitNumber = BitIndex % 8;
	this->STARSBits[ByteIndex] &= (~STARSBitMasks[BitNumber]);
	return;
}

// Query methods

// Returns false if all bits are zero, true otherwise.
bool STARSBitSet::IsAnyBitSet(void) const {
	bool FoundSetBit = false;
	size_t ByteIndex;
	for (ByteIndex = 0; ByteIndex < this->STARSBits.size(); ++ByteIndex) {
		if (0 != this->STARSBits[ByteIndex]) {
			FoundSetBit = true;
			break;
		}
	}

	return FoundSetBit;
}

// Map system or library call name to FG info about its return value.
static map<string, struct FineGrainedInfo> ReturnRegisterTypeMap;

// Map system or library call name to the annotation substring that
//  guides saturating arithmetic or other continuation policies in 
//  the case of integer error detection of a value passed to that call.
// If we don't care about a certain call, we return an empty string.
static map<string, string> IntegerErrorCallSinkMap;

void InitIntegerErrorCallSinkMap(void) {
	pair<string, string> MapEntry;
	pair<map<string, string>::iterator, bool> InsertResult;

	MapEntry.first = string("malloc");
	MapEntry.second = string("SINKMALLOC");
	InsertResult = IntegerErrorCallSinkMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = string("calloc");
	MapEntry.second = string("SINKMALLOC");
	InsertResult = IntegerErrorCallSinkMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = string("realloc");
	MapEntry.second = string("SINKMALLOC");
	InsertResult = IntegerErrorCallSinkMap.insert(MapEntry);
	assert(InsertResult.second);

	return;
}

// Return sink string for call name from the sink map.
// If we don't care find the call name, we return an empty string.
void GetSinkStringForCallName(string CalleeName, string &SinkString) {
	map<string, string>::iterator MapIter;

	SinkString.clear(); // empty string, append map string if found later
	MapIter = IntegerErrorCallSinkMap.find(CalleeName);

	if (MapIter != IntegerErrorCallSinkMap.end()) { // found it
		SinkString.append(MapIter->second);
	}
	return;
}

// Map system or library call name to the argument number that
//  should have an unsigned value and should be guarded from the
//  signedness error that results from copying a signed value
//  into the outgoing argument. Argument numbers are zero-based.
//  We will return 0 when there is no argument to worry about
//  for a particular library or system call name.
static map<string, unsigned int> UnsignedArgPositionMap;

void InitUnsignedArgPositionMap(void) {
	pair<string, unsigned int> MapEntry;
	pair<map<string, unsigned int>::iterator, bool> InsertResult;

	// <string.h>
	MapEntry.first = string("memchr");
	MapEntry.second = STARS_ARG_POS_2;
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = string("memcmp");
	MapEntry.second = STARS_ARG_POS_2;
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = string("memcpy");
	MapEntry.second = STARS_ARG_POS_2;
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = string("memmove");
	MapEntry.second = STARS_ARG_POS_2;
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = string("memset");
	MapEntry.second = STARS_ARG_POS_2;
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = string("strncat");
	MapEntry.second = STARS_ARG_POS_2;
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = string("strncmp");
	MapEntry.second = STARS_ARG_POS_2;
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = string("strncpy");
	MapEntry.second = STARS_ARG_POS_2;
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = string("strxfrm");
	MapEntry.second = STARS_ARG_POS_2;
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	// <stdlib.h>
	MapEntry.first = string("malloc");
	MapEntry.second = STARS_ARG_POS_0;
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = string("calloc");
	MapEntry.second = (STARS_ARG_POS_0 | STARS_ARG_POS_1);
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = string("realloc");
	MapEntry.second = STARS_ARG_POS_1;
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = string("bsearch");
	MapEntry.second = (STARS_ARG_POS_2 | STARS_ARG_POS_3);
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = string("qsort");
	MapEntry.second = (STARS_ARG_POS_1 | STARS_ARG_POS_2);
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = string("mblen");
	MapEntry.second = STARS_ARG_POS_1;
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = string("mbtowc");
	MapEntry.second = STARS_ARG_POS_2;
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = string("mbstowcs");
	MapEntry.second = STARS_ARG_POS_2;
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = string("wcstombs");
	MapEntry.second = STARS_ARG_POS_2;
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	// <stdio.h>
	MapEntry.first = string("setvbuf");
	MapEntry.second = STARS_ARG_POS_3;
	InsertResult = UnsignedArgPositionMap.insert(MapEntry);
	assert(InsertResult.second);

	return;
}

// Return unsigned arg position bitset for call name from the sink map.
// If we don't care find the call name, we return 0.
void GetUnsignedArgPositionsForCallName(string CalleeName, unsigned int &ArgPosBits) {
	map<string, unsigned int>::iterator MapIter;

	ArgPosBits = 0; // Change if found later
	MapIter = UnsignedArgPositionMap.find(CalleeName);

	if (MapIter != UnsignedArgPositionMap.end()) { // found it
		ArgPosBits = MapIter->second;
	}
	return;
}

// Utility to count bits set in an unsigned int, e.g. ArgPosBits.
unsigned int CountBitsSet(unsigned int ArgPosBits) {
	unsigned int count; // count accumulates the total bits set in ArgPosBits
	for (count = 0; ArgPosBits; ++count) {
		ArgPosBits &= (ArgPosBits - 1); // clear the least significant bit set
	}
	// Brian Kernighan's method goes through as many iterations as there are set bits. 
	//  So if we have a 32-bit word with only the high bit set, then it will only go once through the loop.
	// Published in 1988, the C Programming Language 2nd Ed. (by Brian W. Kernighan and Dennis M. Ritchie) mentions this in exercise 2-9.
	//  On April 19, 2006 Don Knuth pointed out to me that this method "was first published by Peter Wegner in CACM 3 (1960), 322.
	//  (Also discovered independently by Derrick Lehmer and published in 1964 in a book edited by Beckenbach.)"
	return count;
}

// Initialize the FG info for the return register from any library function
//  whose name implies that we know certain return values (e.g. atoi() returns
//  a signed integer, while strtoul() returns an unsigned long).
void GetLibFuncFGInfo(string FuncName, struct FineGrainedInfo &InitFGInfo) {
	map<string, struct FineGrainedInfo>::iterator FindIter;

	FindIter = ReturnRegisterTypeMap.find(FuncName);
	if (FindIter == ReturnRegisterTypeMap.end()) { // not found
		InitFGInfo.SignMiscInfo = 0;
		InitFGInfo.SizeInfo = 0;
	}
	else { // found
		InitFGInfo = FindIter->second;
	}
	return;
} // end of GetLibFuncFGInfo()

// Initialize the lookup maps that are used to define the FG info that can
//  be inferred from a library function name.
void InitLibFuncFGInfoMaps(void) {
	op_t DummyOp = InitOp;
	struct FineGrainedInfo FGEntry;
	pair<string, struct FineGrainedInfo> MapEntry;
	pair<map<string, struct FineGrainedInfo>::iterator, bool> InsertResult;

	// Add functions that return signed integers.
	FGEntry.SignMiscInfo = FG_MASK_SIGNED;
	FGEntry.SizeInfo = (FG_MASK_INTEGER | ComputeOperandBitWidthMask(DummyOp, sizeof(int)));
	MapEntry.second = FGEntry;

	MapEntry.first = "atoi";
	InsertResult = ReturnRegisterTypeMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = "strcmp";
	InsertResult = ReturnRegisterTypeMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = "strncmp";
	InsertResult = ReturnRegisterTypeMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = "memcmp";
	InsertResult = ReturnRegisterTypeMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = "isalnum";
	InsertResult = ReturnRegisterTypeMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = "isalpha";
	InsertResult = ReturnRegisterTypeMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = "islower";
	InsertResult = ReturnRegisterTypeMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = "isupper";
	InsertResult = ReturnRegisterTypeMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = "isdigit";
	InsertResult = ReturnRegisterTypeMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = "isxdigit";
	InsertResult = ReturnRegisterTypeMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = "iscntrl";
	InsertResult = ReturnRegisterTypeMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = "isgraph";
	InsertResult = ReturnRegisterTypeMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = "isblank";
	InsertResult = ReturnRegisterTypeMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = "isspace";
	InsertResult = ReturnRegisterTypeMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = "isprint";
	InsertResult = ReturnRegisterTypeMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = "ispunct";
	InsertResult = ReturnRegisterTypeMap.insert(MapEntry);
	assert(InsertResult.second);

	// Functions that return signed longs.
	if (sizeof(long int) != sizeof(int)) {
		FGEntry.SizeInfo = (FG_MASK_INTEGER | ComputeOperandBitWidthMask(DummyOp, sizeof(long int)));
		MapEntry.second = FGEntry;
	}

	MapEntry.first = "atol";
	InsertResult = ReturnRegisterTypeMap.insert(MapEntry);
	assert(InsertResult.second);

	MapEntry.first = "strtol";
	InsertResult = ReturnRegisterTypeMap.insert(MapEntry);
	assert(InsertResult.second);

	// Functions that return signed long longs.
	if (sizeof(long long int) != sizeof(long int)) {