Skip to content
Snippets Groups Projects
STARSProgram.cpp 377 KiB
Newer Older
/* STARSProgram.cpp: Base class
 * Copyright 2015 by Zephyr Software LLC 
 */

#include <cstring>
#include <algorithm>
#include <iostream>
#include <sstream>
#include "interfaces/STARSTypes.h"
#include "interfaces/SMPDBInterface.h"
// #include "interfaces/abstract/all.h"
#include "base/SMPDataFlowAnalysis.h"


void STARS_Program_t::MDInitializeCallerSavedRegs(void) {
	this->STARS_MDCallerSavedRegs.clear();
	bool x86_64_ISA_flag = false;
#ifdef __EA64__
	x86_64_ISA_flag = (this->GetSTARS_ISA_Bitwidth() == 64);
#endif
	if (!x86_64_ISA_flag) {
		// 32-bit x86 uses EAX, ECX, EDX as caller-saved.
		this->STARS_MDCallerSavedRegs.push_back(STARS_x86_R_ax);
		this->STARS_MDCallerSavedRegs.push_back(STARS_x86_R_cx);
		this->STARS_MDCallerSavedRegs.push_back(STARS_x86_R_dx);
	}
	else {
		// 64-bit x86 uses EDI, ESI, EDX, ECX, R8 and R9
		//  in that order. After six arguments that fit into
		//  these regs, arguments are passed on the stack.
		// In addition, registers EAX, R10 and R11 are caller-saved
		//  but are not used to pass arguments.
		this->STARS_MDCallerSavedRegs.push_back(STARS_x86_R_ax);
		this->STARS_MDCallerSavedRegs.push_back(STARS_x86_R_cx);
		this->STARS_MDCallerSavedRegs.push_back(STARS_x86_R_dx);
		this->STARS_MDCallerSavedRegs.push_back(STARS_x86_R_si);
		this->STARS_MDCallerSavedRegs.push_back(STARS_x86_R_di);
		this->STARS_MDCallerSavedRegs.push_back(STARS_x86_R_r8);
		this->STARS_MDCallerSavedRegs.push_back(STARS_x86_R_r9);
		this->STARS_MDCallerSavedRegs.push_back(STARS_x86_R_r10);
		this->STARS_MDCallerSavedRegs.push_back(STARS_x86_R_r11);
	}
	return;
} // end of STARS_IDA_Program_t::MDInitializeCallerSavedRegs()

void STARS_Program_t::MDInitializeArgumentRegs(void) {
	bool x86_64_ISA_flag = false;
#ifdef __EA64__
	x86_64_ISA_flag = (this->GetSTARS_ISA_Bitwidth() == 64);
#endif
	if (x86_64_ISA_flag) {
		this->STARS_MDArgumentRegs.push_back(STARS_x86_R_di);
		this->STARS_MDArgumentRegs.push_back(STARS_x86_R_si);
		this->STARS_MDArgumentRegs.push_back(STARS_x86_R_dx);
		this->STARS_MDArgumentRegs.push_back(STARS_x86_R_cx);
		this->STARS_MDArgumentRegs.push_back(STARS_x86_R_r8);
		this->STARS_MDArgumentRegs.push_back(STARS_x86_R_r9);
	}
	else {
		this->STARS_MDArgumentRegs.clear();
	}
	return;
} // end of STARS_IDA_Program_t::MDInitializeArgumentRegs()

void STARS_Program_t::MDInitializeCalleeSavedRegs(void) {
	this->STARS_MDCalleeSavedRegs.clear();
	bool x86_64_ISA_flag = false;
#ifdef __EA64__
	x86_64_ISA_flag = (this->GetSTARS_ISA_Bitwidth() == 64);
#endif
	if (!x86_64_ISA_flag) {
		// 32-bit x86 uses EAX, ECX, EDX as caller-saved, EBX, EBP, ESI, EDI as callee-saved.
		this->STARS_MDCalleeSavedRegs.push_back(STARS_x86_R_bx);
		this->STARS_MDCalleeSavedRegs.push_back(STARS_x86_R_bp);
		this->STARS_MDCalleeSavedRegs.push_back(STARS_x86_R_si);
		this->STARS_MDCalleeSavedRegs.push_back(STARS_x86_R_di);
	}
	else {
		// 64-bit x86 uses EDI, ESI, EDX, ECX, R8 and R9
		//  in that order. After six arguments that fit into
		//  these regs, arguments are passed on the stack.
		// In addition, registers EAX, R10 and R11 are caller-saved
		//  but are not used to pass arguments. The rest, besides RSP,
		//  are callee-saved.
		this->STARS_MDCalleeSavedRegs.push_back(STARS_x86_R_bx);
		this->STARS_MDCalleeSavedRegs.push_back(STARS_x86_R_bp);
		this->STARS_MDCalleeSavedRegs.push_back(STARS_x86_R_r12);
		this->STARS_MDCalleeSavedRegs.push_back(STARS_x86_R_r13);
		this->STARS_MDCalleeSavedRegs.push_back(STARS_x86_R_r14);
		this->STARS_MDCalleeSavedRegs.push_back(STARS_x86_R_r15);
	}
	return;
} // end of STARS_IDA_Program_t::MDInitializeCalleeSavedRegs()

bool STARS_Program_t::OpenFiles(void) {
	bool success = this->OpenSecondaryFilesOnly();
	if (success) {
		this->STARS_AnnotFile = SMP_fopen(this->AnnotFileName.c_str(), "w");
		if (NULL == this->STARS_AnnotFile) {
			SMP_msg("FATAL ERROR: Cannot open annotations file %s\n", this->AnnotFileName.c_str());
			(void)SMP_fclose(this->STARS_XrefsFile);
			(void)SMP_fclose(this->STARS_CallReturnFile);
			(void)SMP_fclose(this->STARS_UninitVarFile);
			(void)SMP_fclose(this->ZST_AlarmFile);
			(void)SMP_fclose(this->STARS_InfoAnnotFile);
#if ZST_EMIT_SPARK_ADA_TRANSLATION
			(void)SMP_fclose(this->ZST_SPARKHeaderFile);
			(void)SMP_fclose(this->ZST_SPARKSourceFile);
#endif
			success = false;
		}
	}

	return success;
} // end of STARS_Program_t::OpenFiles()

bool STARS_Program_t::OpenMainAnnotationFile(void) {
	bool success = true;
	this->STARS_AnnotFile = SMP_fopen(this->AnnotFileName.c_str(), "w");
	if (NULL == this->STARS_AnnotFile) {
		SMP_msg("FATAL ERROR: Cannot open annotations file %s\n", this->AnnotFileName.c_str());
		success = false;
	}
	return success;
} // end of STARS_Program_t::OpenMainAnnotationFile()


bool STARS_Program_t::OpenSecondaryFilesOnly(void) {
	// Open the output files except for the main annotation file.
	assert(0 < this->RootFileName.size());  // SetRootFileName() must be called previously.

	string ZSTAlarmFileName(this->GetRootFileName());
	string AlarmFileSuffix(".alarms");
	ZSTAlarmFileName += AlarmFileSuffix;
	string XrefsFileName(this->GetRootFileName());
	string XrefsFileSuffix(".STARSxrefs");
	XrefsFileName += XrefsFileSuffix;
	string CallRetFileName(this->GetRootFileName());
	string CallRetFileSuffix(".STARScallreturn");
	CallRetFileName += CallRetFileSuffix;
	string UninitVarFileName(this->GetRootFileName());
	string UninitVarFileSuffix(".STARSuninit");
	UninitVarFileName += UninitVarFileSuffix;
#if ZST_EMIT_SPARK_ADA_TRANSLATION
	// Extract "foo" from "foo.exe" to get the Ada package name
	istringstream StreamRootName(this->RootFileName);
	(void)std::getline(StreamRootName, this->PackageName, '.');
	if (this->PackageName.empty()) {
		SMP_msg("ERROR: Could not extract an Ada package name from the root of file name %s\n", this->RootFileName.c_str());
		return false;
	}


	// Convert dashes to underscores in the package name to suit Ada standards.
	replace(this->PackageName.begin(), this->PackageName.end(), '-', '_');

	string SPARKSourceFileName(this->PackageName);
	string SPARKSourceFileSuffix(".ZSTSPARK.adb");
	SPARKSourceFileName += SPARKSourceFileSuffix;
	string SPARKHeaderFileName(this->PackageName);
	string SPARKHeaderFileSuffix(".ZSTSPARK.ads");
	SPARKHeaderFileName += SPARKHeaderFileSuffix;
#endif

	this->STARS_XrefsFile = SMP_fopen(XrefsFileName.c_str(), "w");
	if (NULL == this->STARS_XrefsFile) {
		SMP_msg("FATAL ERROR: Cannot open STARS code xrefs file %s\n", XrefsFileName.c_str());
		return false;
	}

	this->STARS_CallReturnFile = SMP_fopen(CallRetFileName.c_str(), "w");
	if (NULL == this->STARS_CallReturnFile) {
		SMP_msg("FATAL ERROR: Cannot open STARS calls and returns info file %s\n", CallRetFileName.c_str());
		(void)SMP_fclose(this->STARS_XrefsFile);
		return false;
	}

	this->STARS_UninitVarFile = SMP_fopen(UninitVarFileName.c_str(), "w");
	if (NULL == this->STARS_UninitVarFile) {
		SMP_msg("FATAL ERROR: Cannot open STARS uninitialized vars info file %s\n", UninitVarFileName.c_str());
		(void)SMP_fclose(this->STARS_XrefsFile);
		(void)SMP_fclose(this->STARS_CallReturnFile);
		return false;
	}

	this->ZST_AlarmFile = SMP_fopen(ZSTAlarmFileName.c_str(), "w");
	if (NULL == this->ZST_AlarmFile) {
		SMP_msg("FATAL ERROR: Cannot open security alarms file %s\n", ZSTAlarmFileName.c_str());
		(void)SMP_fclose(this->STARS_XrefsFile);
		(void)SMP_fclose(this->STARS_CallReturnFile);
		(void)SMP_fclose(this->STARS_UninitVarFile);
		return false;
	}

	this->STARS_InfoAnnotFile = SMP_fopen(this->InfoAnnotFileName.c_str(), "w");
	if (NULL == this->STARS_InfoAnnotFile) {
		SMP_msg("FATAL ERROR: Cannot open annotations file %s\n", this->InfoAnnotFileName.c_str());
		(void)SMP_fclose(this->STARS_XrefsFile);
		(void)SMP_fclose(this->STARS_CallReturnFile);
		(void)SMP_fclose(this->STARS_UninitVarFile);
		(void)SMP_fclose(this->ZST_AlarmFile);
#if ZST_EMIT_SPARK_ADA_TRANSLATION
	this->ZST_SPARKSourceFile = SMP_fopen(SPARKSourceFileName.c_str(), "w");
	if (NULL == this->ZST_SPARKSourceFile) {
		SMP_msg("FATAL ERROR: Cannot open SPARK-Ada source output file %s\n", SPARKSourceFileName.c_str());
		(void)SMP_fclose(this->STARS_XrefsFile);
		(void)SMP_fclose(this->STARS_CallReturnFile);
		(void)SMP_fclose(this->STARS_UninitVarFile);
		(void)SMP_fclose(this->ZST_AlarmFile);
		(void)SMP_fclose(this->STARS_InfoAnnotFile);
		return false;
	}
	this->ZST_SPARKHeaderFile = SMP_fopen(SPARKHeaderFileName.c_str(), "w");
	if (NULL == this->ZST_SPARKHeaderFile) {
		SMP_msg("FATAL ERROR: Cannot open SPARK-Ada header output file %s\n", SPARKHeaderFileName.c_str());
		(void)SMP_fclose(this->STARS_XrefsFile);
		(void)SMP_fclose(this->STARS_CallReturnFile);
		(void)SMP_fclose(this->STARS_UninitVarFile);
		(void)SMP_fclose(this->ZST_AlarmFile);
		(void)SMP_fclose(this->STARS_InfoAnnotFile);
		(void)SMP_fclose(this->ZST_SPARKSourceFile);

} // end of STARS_Program_t::OpenSecondaryFilesOnly()

void STARS_Program_t::CloseFiles(void) {
	(void) SMP_fclose(this->STARS_AnnotFile);
	(void) SMP_fclose(this->STARS_InfoAnnotFile);

#if ZST_EMIT_SPARK_ADA_TRANSLATION
	(void) SMP_fclose(this->ZST_SPARKSourceFile);
	(void) SMP_fclose(this->ZST_SPARKHeaderFile);
#endif
	(void) SMP_fclose(this->ZST_AlarmFile);
	(void) SMP_fclose(this->STARS_CallReturnFile);
	(void) SMP_fclose(this->STARS_XrefsFile);
	(void) SMP_fclose(this->STARS_UninitVarFile);

	return;
} // end of STARS_Program_t::CloseFiles()

// Apply new mode to the AnnotFile.
bool STARS_Program_t::ReopenAnnotFile(const char *mode) {
	FILE *TempHandle = freopen(NULL, mode, this->GetAnnotFile());
	bool success = (NULL != TempHandle);
	if  (success) {
		this->STARS_AnnotFile = TempHandle;
	}
	return success;
}

void STARS_Program_t::InitData(void) {
clc5q's avatar
clc5q committed
	this->IDAProDriver = false;  // default; set to true explicitly from IDA Pro code.
clc5q's avatar
clc5q committed
	this->CurrentFileNumber = 0;
	this->ZST_AlarmFile = NULL;
	this->STARS_CallReturnFile = NULL;
	this->STARS_XrefsFile = NULL;

	this->MDInitializeArgumentRegs();
	this->MDInitializeCallerSavedRegs(); 
	this->MDInitializeCalleeSavedRegs();
	// Initialize global counters for statistics-gathering purposes.
	STARS_SPARK_IndentCount = 1;
	UnusedStructCount = 0;
	UnusedIntCount = 0;
	DeadMetadataCount = 0;
	LiveMetadataCount = 0;
	ResolvedIndirectJumpCount = 0;
	UnresolvedIndirectJumpCount = 0;
	ConstantDEFCount = 0;
	AlwaysTakenBranchCount = 0;
	NeverTakenBranchCount = 0;
	SubwordRegCount = 0;
	SubwordMemCount = 0;
	SubwordAddressRegCount = 0;
	SPARKOperandCount = 0;
#if SMP_COUNT_MEMORY_ALLOCATIONS
	SMPInstCount = 0;
	SMPBlockCount = 0;
	SMPDefUseChainCount = 0;
	SMPFuncCount = 0;
	SMPGlobalVarCount = 0;
	SMPLocalVarCount = 0;
	SMPInstBytes = 0;
	SMPDefUseChainBytes = 0;
#endif
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
	NumericAnnotationsCount12 = 0;
	NumericAnnotationsCount3 = 0;
	TruncationAnnotationsCount = 0;
	SignednessWithoutTruncationCount = 0;
	LeaInstOverflowCount = 0;
	WidthDoublingTruncationCount = 0;
	BenignOverflowInstCount = 0;
	BenignOverflowDefCount = 0;
	SuppressStackPtrOverflowCount = 0;
	SuppressLiveFlagsOverflowCount = 0;
	LiveMultiplyBitsCount = 0;
	BenignTruncationCount = 0;
	SuppressTruncationRegPiecesAllUsed = 0;
	SuppressSignednessOnTruncation = 0;
#endif
#if STARS_SCCP_GATHER_STATISTICS
	SCCPFuncsWithArgWriteCount = 0;
	SCCPFuncsWithConstantArgWriteCount = 0;
	SCCPOutgoingArgWriteCount = 0;
	SCCPConstantOutgoingArgWriteCount = 0;
#endif
	STARS_MaxBlockCount = 0;

	(void) memset(this->OptCount, 0, sizeof(this->OptCount));
	(void) memset(this->AnnotationCount, 0, sizeof(this->AnnotationCount));
	this->STARS_PerformReducedAnalysis = false;
	this->STARS_PerformLevel2ReducedAnalysis = false;
	this->STARS_PerformFuncPtrShadowing = false;
	this->STARS_PerformArgShadowing = false;
	this->STARS_PerformCFGImprovement = false;
	this->STARS_PerformDeepLoopAnalyses = false;
	this->ShadowID = 1;
	this->STARS_TotalCodeSize = 0;

	this->InitOptCategory();
	this->InitStackAlteration();
	this->InitDFACategory();
	this->InitTypeCategory();
	this->InitSMPDefsFlags();
	this->InitSMPUsesFlags();
	this->InitLibFuncFGInfoMaps();
	InitIntegerErrorCallSinkMap();
	InitUnsignedArgPositionMap();
	InitTaintWarningArgPositionMap();
	InitPointerArgPositionMap();
	InitLibraryFuncNames();

	return;
} // end of STARS_Program_t::InitData()

// These two constants should agree with their counterparts in ZST-policy.c.
#define ZST_MAX_FILE_NAME_LEN 1024
#define ZST_MAX_CALL_NAME_LEN 64

// Convert a call type string from the policy file, such as "FILECALLS", to the
//  corresponding ZST_SysCallType, such as ZST_FILE_CALL.
ZST_SysCallType STARS_Program_t::ConvertStringToCallType(char *Str2) {
	ZST_SysCallType ReturnVal;
	if (0 == strcmp("PRIVILEGECALLS", Str2)) {
		ReturnVal = ZST_HIGHPRIVILEGE_CALL;
	}
	else if (0 == strcmp("FILECALLS", Str2)) {
		ReturnVal = ZST_FILE_CALL;
	}
	else if (0 == strcmp("NETWORKCALLS", Str2)) {
		ReturnVal = ZST_NETWORK_CALL;
	}
	else {
		ReturnVal = ZST_UNMONITORED_CALL;
	}
	return ReturnVal;
} // end of STARS_Program_t::ConvertStringToCallType()

// Convert a policy string from the policy file, such as "DISALLOW", to
//  the corresponding ZST_Policy value, such as ZST_DISALLOW.
ZST_Policy STARS_Program_t::ConvertStringToPolicy(char *Str3) {
	ZST_Policy ReturnVal;
	if (0 == strcmp("DISALLOW", Str3)) {
		ReturnVal = ZST_DISALLOW;
	}
	else if (0 == strcmp("WHITELIST", Str3)) {
		ReturnVal = ZST_WHITELIST;
	}
	else if (0 == strcmp("BLACKLIST", Str3)) {
		ReturnVal = ZST_BLACKLIST;
	}
	else { // error handling precedes calls to this function
		ReturnVal = ZST_ALLOWALL;
	}
	return ReturnVal;
} // end of STARS_Program_t::ConvertStringToPolicy()

// Given a function name, return its Zephyr Security Toolkit call type.
ZST_SysCallType STARS_Program_t::GetCallTypeFromFuncName(string SysCallName) const {
	ZST_SysCallType ReturnVal;
	map<string, ZST_SysCallType>::const_iterator FindIter = this->ZST_FuncTypeMap.find(SysCallName);
	if (FindIter == this->ZST_FuncTypeMap.end()) { // not found; might not even be system call
		ReturnVal = ZST_UNMONITORED_CALL;
	}
	else {
		ReturnVal = FindIter->second;
	}
	return ReturnVal;
} // end of GetCallTypeFromFuncName()

// Get the user-specified security policy for the given call type.
ZST_Policy STARS_Program_t::GetPolicyFromCallType(ZST_SysCallType CallType) const {
	ZST_Policy ReturnVal;
	map<ZST_SysCallType, ZST_Policy>::const_iterator FindIter = ZST_TypePolicyMap.find(CallType);
	if (FindIter == ZST_TypePolicyMap.end()) {
		// Policy not found; default to ALLOW_ALL
		ReturnVal = ZST_ALLOWALL;
	}
	else {
		ReturnVal = FindIter->second;
	}
	return ReturnVal;
} // end of STARS_Program_t::GetPolicyFromCallType()

// Given a call type and called function name, is it on the location whitelist
//  for that call type?
// NOTE: HANDLE CASE IN WHICH WHITELISTED LOCATION IS A PREFIX, TERMINATING in a slash.
bool STARS_Program_t::IsLocationWhitelisted(ZST_SysCallType CallType, string LocationName) const {
	set<string>::const_iterator FindIter;
	bool ReturnVal;

	if (CallType == ZST_FILE_CALL) {
		FindIter = ZST_FileLocWhitelist.find(LocationName);
		ReturnVal = (FindIter != ZST_FileLocWhitelist.end());
	}
	else if (CallType == ZST_NETWORK_CALL) {
		FindIter = ZST_NetworkLocWhitelist.find(LocationName);
		ReturnVal = (FindIter != ZST_NetworkLocWhitelist.end());
	}
	else { // should not be here
		ReturnVal = false;
	}
	return ReturnVal;
} // end of STARS_Program_t::IsLocationWhitelisted()

// Given a call type and called function name, is it on the location blacklist
//  for that call type?
// NOTE: HANDLE CASE IN WHICH BLACKLISTED LOCATION IS A PREFIX, TERMINATING in a slash.
bool STARS_Program_t::IsLocationBlacklisted(ZST_SysCallType CallType, string LocationName) const {
	set<string>::const_iterator FindIter;
	bool ReturnVal;

	if (CallType == ZST_FILE_CALL) {
		FindIter = ZST_FileLocBlacklist.find(LocationName);
		ReturnVal = (FindIter != ZST_FileLocBlacklist.end());
	}
	else if (CallType == ZST_NETWORK_CALL) {
		FindIter = ZST_NetworkLocBlacklist.find(LocationName);
		ReturnVal = (FindIter != ZST_NetworkLocBlacklist.end());
	}
	else { // should not be here
		ReturnVal = false;
	}
	return ReturnVal;
} // end of STARS_Program_t::IsLocationBlacklisted()

// Given a called function name, does it produce only benign numeric errors when
//  its returned values are used in arithmetic? (i.e. it is a trusted input)
bool STARS_Program_t::IsNumericSafeSystemCall(string CallName) const {
	set<string>::const_iterator FindIter = ZST_SystemCallNumericWhitelist.find(CallName);
	bool ReturnVal = (FindIter != ZST_SystemCallNumericWhitelist.end());
	return ReturnVal;
}
bool STARS_Program_t::IsCalleeSavedReg(STARS_regnum_t RegNum) const {
	std::list<STARS_regnum_t>::const_iterator CalleeSavedIter = this->STARS_MDCalleeSavedRegs.cbegin();
	while (CalleeSavedIter != this->STARS_MDCalleeSavedRegs.cend()) {
		if (*CalleeSavedIter == RegNum) {
			found = true;
			break;
		}
		++CalleeSavedIter;
	}
	return found;
}

bool STARS_Program_t::IsCallerSavedReg(STARS_regnum_t RegNum) const {
	std::list<STARS_regnum_t>::const_iterator CallerSavedIter = this->STARS_MDCallerSavedRegs.cbegin();
	while (CallerSavedIter != this->STARS_MDCallerSavedRegs.cend()) {
		if (*CallerSavedIter == RegNum) {
			found = true;
			break;
		}
		else if (*CallerSavedIter > RegNum) {
			break; // passed it in sorted list; return false
		}
		++CallerSavedIter;
	}
	return found;
}

// return true and set ArgPos if RegNum is an InArg
bool STARS_Program_t::GetArgRegPosition(STARS_regnum_t RegNum, std::size_t &ArgPos) const {
	bool found = false;
	std::list<STARS_regnum_t>::const_iterator ArgRegsIter = this->STARS_MDArgumentRegs.cbegin();
	ArgPos = 0;
	while (ArgRegsIter != this->STARS_MDArgumentRegs.cend()) {
		if (*ArgRegsIter == RegNum) {
			found = true;
			break;
		}
		++ArgRegsIter;
		++ArgPos;
	}
	return found;
}

bool STARS_Program_t::IsArgumentReg(STARS_regnum_t RegNum) const {
	bool found = false;
	std::list<STARS_regnum_t>::const_iterator ArgRegsIter = this->STARS_MDArgumentRegs.cbegin();
	while (ArgRegsIter != this->STARS_MDArgumentRegs.cend()) {
		if (*ArgRegsIter == RegNum) {
			found = true;
			break;
		}
		++ArgRegsIter;
	}
	return found;
}

bool STARS_Program_t::AreInstIDsInSameFunction(const STARS_ea_t InstID1, const STARS_ea_t InstID2) const {
	STARS_Function_t *Func1 = SMP_get_func(InstID1);
	STARS_Function_t *Func2 = SMP_get_func(InstID2);
	return ((NULL != Func1) && (NULL != Func2) && (Func1->get_startEA() == Func2->get_startEA()));
}

void STARS_Program_t::PrintTypeCode(IBType TypeCode){
	if (ZST_RETURN == TypeCode) {
		SMP_fprintf(this->GetXrefsFile(), "RETURNTARGET\n");
	}
	else if (ZST_SWITCHTABLE == TypeCode) {
		SMP_fprintf(this->GetXrefsFile(), "SWITCHTABLE\n");
	}
	else if (ZST_INDIRCALL == TypeCode) {
		SMP_fprintf(this->GetXrefsFile(), "INDIRCALL\n");
	}
	else if (ZST_COMPUTEDGOTO == TypeCode) {
		SMP_fprintf(this->GetXrefsFile(), "COMPUTEDGOTOHEURISTIC\n");
	}
	else if (ZST_CODEADDRESSTAKEN == TypeCode) {
		SMP_fprintf(this->GetXrefsFile(), "CODEADDRESSTAKEN\n");
	}
	else if (ZST_UNREACHABLEBLOCK == TypeCode) {
		SMP_fprintf(this->GetXrefsFile(), "UNREACHABLEBLOCK\n");
	}
	else {
		SMP_fprintf(this->GetXrefsFile(), "UNKNOWN\n");
	}
	return;
}


// Utility functions to print code xrefs to STARS_XrefsFile
clc5q's avatar
clc5q committed
bool STARS_Program_t::PrintCodeToCodeXref(STARS_ea_t FromAddr, STARS_ea_t ToAddr, std::size_t InstrSize, IBType TypeCode) {
	bool success = false;
	if (IsAddressInCodeRange(ToAddr)) {
clc5q's avatar
clc5q committed
		success = true;
		SMP_fprintf(this->GetXrefsFile(), "%18llx %6zu INSTR XREF IBT FROMIB %18llx ",
			(unsigned long long) ToAddr, InstrSize, (unsigned long long) FromAddr);
		this->PrintTypeCode(TypeCode);
clc5q's avatar
clc5q committed
	return success;
// Utility functions to print code xrefs to STARS_XrefsFile
clc5q's avatar
clc5q committed
bool STARS_Program_t::PrintReturnInstXref(STARS_ea_t RetInstAddr, STARS_ea_t TargetAddr, std::size_t InstrSize, bool TailCallTargetAddr) {
	bool success = false;
clc5q's avatar
clc5q committed
	if (IsAddressInCodeRange(TargetAddr)) {
clc5q's avatar
clc5q committed
		success = true;
clc5q's avatar
clc5q committed
		FILE *XrefsFile = this->GetXrefsFile();
		SMP_fprintf(XrefsFile, "%18llx %6zu INSTR XREF IBT FROMIB %18llx ",
			(unsigned long long) TargetAddr, InstrSize, (unsigned long long) RetInstAddr);
clc5q's avatar
clc5q committed
		if (!TailCallTargetAddr) {
			SMP_fprintf(XrefsFile, "RETURNTARGET\n");
		}
		else {
			SMP_fprintf(XrefsFile, "TAILCALLRETURNTARGET\n");
		}
clc5q's avatar
clc5q committed
	return success;
void STARS_Program_t::PrintDataToCodeXref(STARS_ea_t FromDataAddr, STARS_ea_t ToCodeAddr, std::size_t InstrSize) {
	if (IsAddressInCodeRange(ToCodeAddr)) {
		SMP_fprintf(this->GetXrefsFile(), "%18llx %6zu INSTR XREF IBT FROMDATA %18llx \n",
			(unsigned long long) ToCodeAddr, InstrSize, (unsigned long long) FromDataAddr);
	}
void STARS_Program_t::PrintUnknownCodeXref(STARS_ea_t ToAddr, std::size_t InstrSize, IBType TypeCode) {
	SMP_fprintf(this->GetXrefsFile(), "%18llx %6zu INSTR XREF IBT FROMUNKNOWN ",
		(unsigned long long) ToAddr, InstrSize);
	this->PrintTypeCode(TypeCode);
// Utility functions to signify code xrefs are complete in STARS_XrefsFile for FromAddr
clc5q's avatar
clc5q committed
void STARS_Program_t::PrintCodeToCodeXrefComplete(STARS_ea_t FromAddr, std::size_t InstrSize, std::size_t IBTCount, IBType TypeCode) {
	if (IsAddressInCodeRange(FromAddr)) {
clc5q's avatar
clc5q committed
		SMP_fprintf(this->GetXrefsFile(), "%18llx %6zu INSTR XREF FROMIB COMPLETE %6zu ",
			(unsigned long long) FromAddr, InstrSize, IBTCount);
		this->PrintTypeCode(TypeCode);
// Read the foo.exe.policy file to initialize our security policies for system calls.
void STARS_Program_t::ZST_InitPolicies(void) {
	string ZSTPolicyFileName(this->GetRootFileName());
	string PolicyFileSuffix(".policy");
	ZSTPolicyFileName += PolicyFileSuffix;
	FILE *PolicyFile = SMP_fopen(ZSTPolicyFileName.c_str(), "r");
	char Str1[ZST_MAX_CALL_NAME_LEN], Str2[ZST_MAX_CALL_NAME_LEN], Str3[ZST_MAX_FILE_NAME_LEN];

	string SafeSystemCall1("gettimeofday");
	this->ZST_SystemCallNumericWhitelist.insert(SafeSystemCall1);

	if (NULL != PolicyFile) {
		while (!SMP_feof(PolicyFile)) {
			int ItemsRead = SMP_fscanf(PolicyFile, "%63s %63s %1023s", Str1, Str2, Str3);
			if (3 != ItemsRead) {
				SMP_msg("ERROR: Line in %s had %d items instead of the required 3; line ignored.\n", ZSTPolicyFileName.c_str(), ItemsRead);
			}
			else {
				string ThirdStr(Str3);
				pair<set<string>::iterator, bool> SetInsertResult;
				if (0 == strcmp(Str1, "SECURITYPOLICY")) {
					ZST_SysCallType TempCallType = ConvertStringToCallType(Str2);
					ZST_Policy TempPolicy = ConvertStringToPolicy(Str3);
					pair<map<ZST_SysCallType, ZST_Policy>::iterator, bool> InsertResult;
					pair<ZST_SysCallType, ZST_Policy> TempPair(TempCallType, TempPolicy);
					InsertResult = this->ZST_TypePolicyMap.insert(TempPair);
					if (!(InsertResult.second)) {
						SMP_msg("ERROR: Could not insert security policy %s for %s. Possible duplicate or conflicting policies.\n",
							Str3, Str2);
					}
				}
				else if (0 == strcmp(Str1, "FILELOCATION")) {
					if (0 == strcmp(Str2, "WHITELIST")) {
						SetInsertResult = this->ZST_FileLocWhitelist.insert(ThirdStr);
						if (!(SetInsertResult.second)) {
							SMP_msg("WARNING: Duplicate file whitelist location %s ignored.\n", Str3);
						}
					}
					else if (0 == strcmp(Str2, "BLACKLIST")) {
						SetInsertResult = this->ZST_FileLocBlacklist.insert(ThirdStr);
						if (!(SetInsertResult.second)) {
							SMP_msg("WARNING: Duplicate file blacklist location %s ignored.\n", Str3);
						}
					}
					else {
						SMP_msg("ERROR: Unknown second field value in policy line: %s %s %s ; ignored\n", Str1, Str2, Str3);
					}
				}
				else if (0 == strcmp(Str1, "NETWORKLOCATION")) {
					if (0 == strcmp(Str2, "WHITELIST")) {
						SetInsertResult = this->ZST_NetworkLocWhitelist.insert(ThirdStr);
						if (!(SetInsertResult.second)) {
							SMP_msg("WARNING: Duplicate network whitelist location %s ignored.\n", Str3);
						}
					}
					else if (0 == strcmp(Str2, "BLACKLIST")) {
						SetInsertResult = this->ZST_NetworkLocBlacklist.insert(ThirdStr);
						if (!(SetInsertResult.second)) {
							SMP_msg("WARNING: Duplicate network blacklist location %s ignored.\n", Str3);
						}
					}
					else {
						SMP_msg("ERROR: Unknown second field value in policy line: %s %s %s ; ignored\n", Str1, Str2, Str3);
					}
				}
				else {
					SMP_msg("ERROR: Unknown first field value in policy line: %s %s %s ; ignored\n", Str1, Str2, Str3);
				}
			}
		}
		if (0 == SMP_fclose(PolicyFile)) {
			SMP_msg("Policy file %s successfully closed; all policies recorded.\n", ZSTPolicyFileName.c_str());
		}
		else {
			SMP_msg("ERROR: fclose failed on policy file %s. However, policies should be in effect.\n", ZSTPolicyFileName.c_str());
		}
		// Now, initialize the system call name maps.
		pair<map<string, ZST_SysCallType>::iterator, bool> FuncInsertResult;
		// Do all the high privilege calls first.
		string SysFuncName("putenv");
		pair<string, ZST_SysCallType> FuncNamePolicyPair(SysFuncName, ZST_HIGHPRIVILEGE_CALL);
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("setenv");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("setegid");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("seteuid");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("setgid");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("setpgid");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("setregid");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("setreuid");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("setuid");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("execl");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("execv");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("execle");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("execve");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("execlp");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("execvp");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("system");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);

		// Now do all the file operation calls.
		FuncNamePolicyPair.second = ZST_FILE_CALL;
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("chdir");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("chmod");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("chown");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("creat");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("creat64");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("fopen");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("freopen");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("open");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("open64");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("mknod");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("remove");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("rmdir");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("unlink");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);

		// Finally, handle all the network connection calls.
		FuncNamePolicyPair.second = ZST_NETWORK_CALL;
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("socket");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("socketpair");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("pipe");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("bind");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("listen");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("accept");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
		FuncNamePolicyPair.first.clear();
		FuncNamePolicyPair.first.append("connect");
		FuncInsertResult = this->ZST_FuncTypeMap.insert(FuncNamePolicyPair);
		assert(FuncInsertResult.second);
	}
	else {
		SMP_msg("WARNING: No policy file %s found. System call policies not in effect.\n", ZSTPolicyFileName.c_str());
	}
	return;
} // end of STARS_Program_t::ZST_InitPolicies()

// Initialize the OptCategory[] array to define how we emit optimizing annotations.
void STARS_Program_t::InitOptCategory(void) {
	// Default category is 0, no optimization without knowing context.
	(void)memset(OptCategory, 0, sizeof(OptCategory));
	// Category 1 instructions never need updating of their memory
	//  metadata by the Memory Monitor SDT. Currently, this is because
	//  these instructions only have effects on registers we do not maintain
	//  metadata for, such as the EIP and the FLAGS, e.g. jumps, compares,
	//  or because they are no-ops, including machine-dependent no-op idioms.
	//  Effects on floating-point regs are always NUMERIC and can be put into
	//  categury 1 because mmStrata knows these registers are NUMERIC and does
	//  not keep a metadata map for them.
	// Category 2 instructions always have a result type of 'n' (number).
	// Category 3 instructions have a result type of 'n' (number)
	//  whenever the second source operand is an operand of type 'n'.
	//  NOTE: MOV is only current example, and this will take some thought if 
	//   other examples arise.
	// Category 4 instructions have a result type identical to the 1st source operand type.
	//  NOTE: This is currently set for single-operand instructions such as
	//   INC, DEC. As a result, these are treated pretty much as if
	//   they were category 1 instructions, as there is no metadata update,
	//   unless the operand is a memory operand (i.e. mem or [reg]).
	//   If new instructions are added to this category that are not single
	//   operand and do require some updating, the category should be split.
	// Category 5 instructions have a result type identical to the 1st source operand
	//  type whenever the 2nd source operand is an operand of type 'n'.
	//  If the destination is memory, metadata still needs to be checked; if
	//  not, no metadata check is needed, so it becomes category 1.
	// Category 6 instructions always have a result type of 'p' (pointer).
	// Category 7 instructions are category 2 instructions with two destinations,
	//  such as multiply and divide instructions that affect EDX:EAX. There are
	//  forms of these instructions that only have one destination, so they have
	//  to be distinguished via the operand info.
	// Category 8 instructions implicitly write a numeric value to EDX:EAX, but
	//  EDX and EAX are not listed as operands. RDTSC, RDPMC, RDMSR, and other
	//  instructions that copy machine registers into EDX:EAX are category 8.
	// Category 9 instructions are floating point instructions that either
	//  have a memory destination (treat as category 0) or a FP reg destination
	//  (treat as category 1).
	// Category 10 instructions are the same as category 8, but also write
	//  to register ECX in addition to EDX:EAX.

	// NOTE: The Memory Monitor SDT needs just three categories, corresponding
	//  to categories 0, 1, and all others. For all categories > 1, the
	//  annotation should tell the SDT exactly how to update its metadata.
	//  For example, a division instruction will write type 'n' (NUM) as
	//  the metadata for result registers EDX:EAX. So, the annotation should
	//  list 'n', EDX, EAX, and a terminator of ZZ. CWD (convert word to
	//  doubleword) should have a list of 'n', EAX, ZZ.

	OptCategory[STARS_NN_null] = 0;            // Unknown Operation
	OptCategory[STARS_NN_aaa] = 2;                 // ASCII Adjust after Addition
	OptCategory[STARS_NN_aad] = 2;                 // ASCII Adjust AX before Division
	OptCategory[STARS_NN_aam] = 2;                 // ASCII Adjust AX after Multiply
	OptCategory[STARS_NN_aas] = 2;                 // ASCII Adjust AL after Subtraction
	OptCategory[STARS_NN_adc] = 5;                 // Add with Carry
	OptCategory[STARS_NN_add] = 5;                 // Add
	OptCategory[STARS_NN_and] = 0;                 // Logical AND
	OptCategory[STARS_NN_arpl] = 1;                // Adjust RPL Field of Selector
	OptCategory[STARS_NN_bound] = 1;               // Check Array Index Against Bounds
	OptCategory[STARS_NN_bsf] = 2;                 // Bit Scan Forward
	OptCategory[STARS_NN_bsr] = 2;                 // Bit Scan Reverse
	OptCategory[STARS_NN_bt] = 0;                  // Bit Test
	OptCategory[STARS_NN_btc] = 0;                 // Bit Test and Complement
	OptCategory[STARS_NN_btr] = 0;                 // Bit Test and Reset
	OptCategory[STARS_NN_bts] = 0;                 // Bit Test and Set
	OptCategory[STARS_NN_call] = 1;                // Call Procedure
	OptCategory[STARS_NN_callfi] = 1;              // Indirect Call Far Procedure
	OptCategory[STARS_NN_callni] = 1;              // Indirect Call Near Procedure
	OptCategory[STARS_NN_cbw] = 2;                 // AL -> AX (with sign)            ** No ops?
	OptCategory[STARS_NN_cwde] = 2;                // AX -> EAX (with sign)           **
	OptCategory[STARS_NN_cdqe] = 2;                // EAX -> RAX (with sign)          **
	OptCategory[STARS_NN_clc] = 1;                 // Clear Carry Flag
	OptCategory[STARS_NN_cld] = 1;                 // Clear Direction Flag
	OptCategory[STARS_NN_cli] = 1;                 // Clear Interrupt Flag
	OptCategory[STARS_NN_clts] = 1;                // Clear Task-Switched Flag in CR0
	OptCategory[STARS_NN_cmc] = 1;                 // Complement Carry Flag
	OptCategory[STARS_NN_cmp] = 1;                 // Compare Two Operands
	OptCategory[STARS_NN_cmps] = 1;                // Compare Strings
	OptCategory[STARS_NN_cwd] = 2;                 // AX -> DX:AX (with sign)
	OptCategory[STARS_NN_cdq] = 2;                 // EAX -> EDX:EAX (with sign)
	OptCategory[STARS_NN_cqo] = 2;                 // RAX -> RDX:RAX (with sign)
	OptCategory[STARS_NN_daa] = 2;                 // Decimal Adjust AL after Addition
	OptCategory[STARS_NN_das] = 2;                 // Decimal Adjust AL after Subtraction
	OptCategory[STARS_NN_dec] = 4;                 // Decrement by 1
	OptCategory[STARS_NN_div] = 7;                 // Unsigned Divide
	OptCategory[STARS_NN_enterw] = 0;              // Make Stack Frame for Procedure Parameters  **
	OptCategory[STARS_NN_enter] = 0;               // Make Stack Frame for Procedure Parameters  **
	OptCategory[STARS_NN_enterd] = 0;              // Make Stack Frame for Procedure Parameters  **
	OptCategory[STARS_NN_enterq] = 0;              // Make Stack Frame for Procedure Parameters  **
	OptCategory[STARS_NN_hlt] = 0;                 // Halt
	OptCategory[STARS_NN_idiv] = 7;                // Signed Divide
	OptCategory[STARS_NN_imul] = 7;                // Signed Multiply
	OptCategory[STARS_NN_in] = 0;                  // Input from Port                         **
	OptCategory[STARS_NN_inc] = 4;                 // Increment by 1
	OptCategory[STARS_NN_ins] = 2;                 // Input Byte(s) from Port to String       **
	OptCategory[STARS_NN_int] = 0;                 // Call to Interrupt Procedure
	OptCategory[STARS_NN_into] = 0;                // Call to Interrupt Procedure if Overflow Flag = 1
	OptCategory[STARS_NN_int3] = 0;                // Trap to Debugger
	OptCategory[STARS_NN_iretw] = 0;               // Interrupt Return
	OptCategory[STARS_NN_iret] = 0;                // Interrupt Return
	OptCategory[STARS_NN_iretd] = 0;               // Interrupt Return (use32)
	OptCategory[STARS_NN_iretq] = 0;               // Interrupt Return (use64)
	OptCategory[STARS_NN_ja] = 1;                  // Jump if Above (CF=0 & ZF=0)
	OptCategory[STARS_NN_jae] = 1;                 // Jump if Above or Equal (CF=0)
	OptCategory[STARS_NN_jb] = 1;                  // Jump if Below (CF=1)
	OptCategory[STARS_NN_jbe] = 1;                 // Jump if Below or Equal (CF=1 | ZF=1)
	OptCategory[STARS_NN_jc] = 1;                  // Jump if Carry (CF=1)
	OptCategory[STARS_NN_jcxz] = 1;                // Jump if CX is 0
	OptCategory[STARS_NN_jecxz] = 1;               // Jump if ECX is 0
	OptCategory[STARS_NN_jrcxz] = 1;               // Jump if RCX is 0
	OptCategory[STARS_NN_je] = 1;                  // Jump if Equal (ZF=1)
	OptCategory[STARS_NN_jg] = 1;                  // Jump if Greater (ZF=0 & SF=OF)
	OptCategory[STARS_NN_jge] = 1;                 // Jump if Greater or Equal (SF=OF)
	OptCategory[STARS_NN_jl] = 1;                  // Jump if Less (SF!=OF)
	OptCategory[STARS_NN_jle] = 1;                 // Jump if Less or Equal (ZF=1 | SF!=OF)
	OptCategory[STARS_NN_jna] = 1;                 // Jump if Not Above (CF=1 | ZF=1)
	OptCategory[STARS_NN_jnae] = 1;                // Jump if Not Above or Equal (CF=1)
	OptCategory[STARS_NN_jnb] = 1;                 // Jump if Not Below (CF=0)
	OptCategory[STARS_NN_jnbe] = 1;                // Jump if Not Below or Equal (CF=0 & ZF=0)
	OptCategory[STARS_NN_jnc] = 1;                 // Jump if Not Carry (CF=0)
	OptCategory[STARS_NN_jne] = 1;                 // Jump if Not Equal (ZF=0)
	OptCategory[STARS_NN_jng] = 1;                 // Jump if Not Greater (ZF=1 | SF!=OF)
	OptCategory[STARS_NN_jnge] = 1;                // Jump if Not Greater or Equal (SF!=OF)
	OptCategory[STARS_NN_jnl] = 1;                 // Jump if Not Less (SF=OF)
	OptCategory[STARS_NN_jnle] = 1;                // Jump if Not Less or Equal (ZF=0 & SF=OF)
	OptCategory[STARS_NN_jno] = 1;                 // Jump if Not Overflow (OF=0)
	OptCategory[STARS_NN_jnp] = 1;                 // Jump if Not Parity (PF=0)
	OptCategory[STARS_NN_jns] = 1;                 // Jump if Not Sign (SF=0)
	OptCategory[STARS_NN_jnz] = 1;                 // Jump if Not Zero (ZF=0)
	OptCategory[STARS_NN_jo] = 1;                  // Jump if Overflow (OF=1)
	OptCategory[STARS_NN_jp] = 1;                  // Jump if Parity (PF=1)
	OptCategory[STARS_NN_jpe] = 1;                 // Jump if Parity Even (PF=1)
	OptCategory[STARS_NN_jpo] = 1;                 // Jump if Parity Odd  (PF=0)
	OptCategory[STARS_NN_js] = 1;                  // Jump if Sign (SF=1)
	OptCategory[STARS_NN_jz] = 1;                  // Jump if Zero (ZF=1)
	OptCategory[STARS_NN_jmp] = 1;                 // Jump
	OptCategory[STARS_NN_jmpfi] = 1;               // Indirect Far Jump
	OptCategory[STARS_NN_jmpni] = 1;               // Indirect Near Jump
	OptCategory[STARS_NN_jmpshort] = 1;            // Jump Short (not used)
	OptCategory[STARS_NN_lahf] = 2;                // Load Flags into AH Register
	OptCategory[STARS_NN_lar] = 2;                 // Load Access Rights Byte
	OptCategory[STARS_NN_lea] = 0;                 // Load Effective Address           **
	OptCategory[STARS_NN_leavew] = 0;              // High Level Procedure Exit        **
	OptCategory[STARS_NN_leave] = 0;               // High Level Procedure Exit        **