Skip to content
Snippets Groups Projects
STARSIDAInstruction.cpp 18.6 KiB
Newer Older
jdh8d's avatar
jdh8d committed

#include "interfaces/idapro/all.h"

#include "interfaces/STARSTypes.h"
#include "interfaces/STARSIDATypes.h"
#include "base/SMPDataFlowAnalysis.h"
#include "base/SMPInstr.h"
jdh8d's avatar
jdh8d committed
#include "interfaces/SMPDBInterface.h"
#include "interfaces/abstract/all.h"

jdh8d's avatar
jdh8d committed
#if 0
#include <pro.h>
#include <nalt.hpp>
#include <ua.hpp>
#include <xref.hpp>
jdh8d's avatar
jdh8d committed
#endif
static uint32_t UseMacros[STARS_UA_MAXOP] = {STARS_CF_USE1, STARS_CF_USE2, STARS_CF_USE3, STARS_CF_USE4, STARS_CF_USE5, STARS_CF_USE6};
static uint32_t DefMacros[STARS_UA_MAXOP] = {STARS_CF_CHG1, STARS_CF_CHG2, STARS_CF_CHG3, STARS_CF_CHG4, STARS_CF_CHG5, STARS_CF_CHG6};
STARS_InstructionID_t STARS_IDA_Instruction_t::GetNextInstructionID(void) const {
clc5q's avatar
clc5q committed
	STARS_ea_t addr = this->m_id.GetIDWithinFile();
	SMPInstr TempInst(addr);
	if (!TempInst.FillCmd()) {
		return STARS_BADADDR;
	}
	STARS_ea_t next_addr = addr + TempInst.GetSize();
clc5q's avatar
clc5q committed
	return STARS_InstructionID_t(next_addr, this->m_id.GetFileNum());
STARS_InstructionID_t STARS_IDA_Instruction_t::GetTargetInstructionID(void) const {
	assert(NULL != this->STARScmd.Operands[0]);
	STARS_ea_t TargetAddr = this->STARScmd.Operands[0]->GetAddr();
clc5q's avatar
clc5q committed
	return STARS_InstructionID_t(TargetAddr, this->m_id.GetFileNum());
void STARS_IDA_Instruction_t::InitOperand(op_t &InitOp) const {
#if 0
	InitOp.n = 0;
	InitOp.type = o_void;
	InitOp.offb = 0;
	InitOp.offo = 0;
	InitOp.flags = 0;
	InitOp.set_showed();
	// NOTE: InitOp.dtyp field is initialized in IDAP_run() to 32 or 64 bits.
	InitOp.reg = R_none;
	InitOp.value = 0;
	InitOp.addr = 0;
	InitOp.specval = 0;
	InitOp.specflag1 = 0;
	InitOp.specflag2 = 0;
	InitOp.specflag3 = 0;
	InitOp.specflag4 = 0;
#else
#pragma GCC diagnostic ignored "-Wclass-memaccess"
	(void) memset(&InitOp, 0, sizeof(op_t));
clc5q's avatar
clc5q committed
#if (IDA_SDK_VERSION < 700)
	InitOp.dtyp = global_STARS_program->GetSTARS_ISA_dtyp();
clc5q's avatar
clc5q committed
#else
	InitOp.dtype = global_STARS_program->GetSTARS_ISA_dtyp();
#endif
#if IDA_SDK_VERSION < 680
#else
	InitOp.set_shown();
#endif
#endif

	return;
} // end of STARS_IDA_Instruction_t::InitOperand()

// Get instruction info by address from IDA Pro.
bool STARS_IDA_Instruction_t::STARS_GetCmd(void) {
	bool success = true;
	int InstrLen = 0;

	this->VoidOpndsPtr = nullptr;
	op_t TempOp;
	this->InitOperand(TempOp);
	this->VoidOpndsPtr = dynamic_pointer_cast<STARS_op_t>(std::make_shared<STARS_IDA_op_t>(TempOp));

	// Fill cmd structure with disassembly of instr
clc5q's avatar
clc5q committed
#if (IDA_SDK_VERSION < 700)
clc5q's avatar
clc5q committed
	InstrLen = decode_insn(m_id.GetIDWithinFile());
	// Copy cmd fields to member STARScmd.
	this->STARScmd.itype = cmd.itype;
	this->STARScmd.size = cmd.size;
	this->STARScmd.auxpref = cmd.auxpref;
	this->STARScmd.segpref = cmd.segpref;
	this->STARScmd.insnpref = cmd.insnpref;
	this->STARScmd.flags = cmd.flags;
clc5q's avatar
clc5q committed
	// Get the canonical features into member STARSfeatures.
	this->STARSfeatures = cmd.get_canon_feature();
#else
	insn_t NewInsn;
	InstrLen = ::decode_insn(&NewInsn, m_id.GetIDWithinFile());
clc5q's avatar
clc5q committed
	// Copy cmd fields to member STARScmd.
	this->STARScmd.itype = NewInsn.itype;
	this->STARScmd.size = NewInsn.size;
	this->STARScmd.auxpref = NewInsn.auxpref;
	this->STARScmd.segpref = NewInsn.segpref;
	this->STARScmd.insnpref = NewInsn.insnpref;
	this->STARScmd.flags = NewInsn.flags;
	// Get the canonical features into member STARSfeatures.
#if (IDA_SDK_VERSION < 750)
clc5q's avatar
clc5q committed
	this->STARSfeatures = NewInsn.get_canon_feature();
#else
	this->STARSfeatures = NewInsn.get_canon_feature(PH);
#endif
clc5q's avatar
clc5q committed
#endif

clc5q's avatar
clc5q committed
		SMP_msg("ERROR: decode_insn failed at %ullx in file %u\n", (unsigned long long) m_id.GetIDWithinFile(), m_id.GetFileNum());
		for (int i = 0; i < STARS_UA_MAXOP; ++i) {
			this->STARScmd.Operands.push_back(nullptr);
			this->STARScmd.Operands[i] = this->MakeVoidOpnd();
		}
	for (int i = 0; i < STARS_UA_MAXOP; ++i) {
clc5q's avatar
clc5q committed
#if (IDA_SDK_VERSION < 700)
		this->STARScmd.Operands.push_back(std::make_shared<STARS_IDA_op_t>(cmd.Operands[i]));
clc5q's avatar
clc5q committed
#else
		this->STARScmd.Operands.push_back(std::make_shared<STARS_IDA_op_t>(NewInsn.ops[i]));
#endif
		assert(dynamic_pointer_cast<STARS_IDA_op_t>(this->STARScmd.Operands[i]) != nullptr);
		dynamic_pointer_cast<STARS_IDA_op_t>(this->STARScmd.Operands[i])->SetSpecFlag4(0);
		if (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64) {
			// Copy the cmd.rex prefix into the op_t.specflag4 field for each operand
			//  that has a SIB byte.
			dynamic_pointer_cast<STARS_IDA_op_t>(this->STARScmd.Operands[i])->SetSpecFlag4(this->STARScmd.rex);
			char Flag4Value = this->STARScmd.Operands[i]->GetSpecFlag4();
			if (this->STARScmd.Operands[i]->IsMemOp() && (Flag4Value & STARS_REX_R)) {
				// Only various register types can have the registger extension, e.g. RBX becomes R11 with extension bit.
				Flag4Value -= STARS_REX_R;
				dynamic_pointer_cast<STARS_IDA_op_t>(this->STARScmd.Operands[i])->SetSpecFlag4(Flag4Value);
			}
		}
#endif
		// See comments on STARS_VEXPR and STARS_VSIB in SMPDataFlowAnalysis.h.
		//  These bits do not (as of IDA Pro 6.4) conflict with cmd.rex bits.
clc5q's avatar
clc5q committed
#if (IDA_SDK_VERSION < 700)
		if ((cmd.auxpref & aux_vexpr) != 0) {
clc5q's avatar
clc5q committed
#else
		if ((NewInsn.auxpref & aux_vexpr) != 0) {
#endif
			dynamic_pointer_cast<STARS_IDA_op_t>(this->STARScmd.Operands[i])->SetBitInSpecFlag4(STARS_VEXPR);
		switch (this->STARScmd.itype) {
		    case NN_vgatherdps:
			case NN_vgatherdpd:
			case NN_vgatherqps:
			case NN_vgatherqpd:
			case NN_vpgatherdd:
			case NN_vpgatherdq:
			case NN_vpgatherqd:
			case NN_vpgatherqq:
			  dynamic_pointer_cast<STARS_IDA_op_t>(this->STARScmd.Operands[i])->SetBitInSpecFlag4(STARS_VSIB);
	} // end for all operands
	// Simplify the operand encoding so that identical operands don't appear to be different.
	for (std::size_t i = 0; i < STARS_UA_MAXOP; ++i) {
		this->GetOpnd(i)->CleanOpndEncoding();
	return success;
} // end of STARS_IDA_Instruction_t::STARS_GetCmd()
bool STARS_IDA_Instruction_t::Has64BitOperands(void) {
#ifdef __EA64__
	return (((this->STARScmd.auxpref & aux_use64) != 0)
		&& ((this->STARScmd.rex & REX_W) != 0
		|| (((this->STARScmd.auxpref & aux_natop) != 0) && this->OpcodeDefaultsTo64BitOperands())));
	// 64-bit segment, rex.w or insns-64
#else
	return false;
#endif
}

bool STARS_IDA_Instruction_t::Uses32BitAddressing(void) const {
	int Temp = this->STARScmd.auxpref & (aux_use32 | aux_use64 | aux_natad);
	return (Temp == (aux_natad | aux_use32))
		|| (Temp == 0)
		|| (Temp == aux_use64);
}

bool STARS_IDA_Instruction_t::IsUseOpnd(std::size_t OpndNum) const {
   return (this->GetInstFeatures() & UseMacros[OpndNum]);
}

bool STARS_IDA_Instruction_t::IsDefOpnd(std::size_t OpndNum) const {
   return (this->GetInstFeatures() & DefMacros[OpndNum]);
}

// set the USE bit
void STARS_IDA_Instruction_t::SetOpUsed(std::size_t OpndNum) {
	this->STARSfeatures |= UseMacros[OpndNum];
	return;
} 

// reset the USE bit
void STARS_IDA_Instruction_t::SetOpNotUsed(std::size_t OpndNum) {
	this->STARSfeatures &= (~UseMacros[OpndNum]);
	return;
} 

// set the DEF bit
void STARS_IDA_Instruction_t::SetOpDefed(std::size_t OpndNum) {
	this->STARSfeatures |= DefMacros[OpndNum]; 
	return;
}

// reset the DEF bit
void STARS_IDA_Instruction_t::SetOpNotDefed(std::size_t OpndNum) {
	this->STARSfeatures &= (~DefMacros[OpndNum]);
	return;
} 

// Fix up IDA Pro IMUL instruction by removing operand 1
void STARS_IDA_Instruction_t::RemoveIDAOp1ForIMUL(void) {
	this->STARScmd.Operands[1] = this->STARScmd.Operands[2];
	this->STARScmd.Operands[2] = this->VoidOpndsPtr;
clc5q's avatar
clc5q committed
STARSOpndTypePtr STARS_IDA_Instruction_t::MakeVoidOpnd(void) const {
	return this->VoidOpndsPtr;
} // end of STARS_IDA_Instruction_t::MakeVoidOpnd()

STARSOpndTypePtr STARS_IDA_Instruction_t::MakeImmediateOpnd(STARS_uval_t value) const {
	op_t TempOp;
	this->InitOperand(TempOp);
	return dynamic_pointer_cast<STARS_op_t>(std::make_shared<STARS_IDA_op_t>(TempOp));
} // end of STARS_IDA_Instruction_t::MakeVoidOpnd()

STARSOpndTypePtr STARS_IDA_Instruction_t::MakeRegOpnd(STARS_regnum_t RegNum, bool DefaultToMachineWidth) {
	op_t TempOp;
	this->InitOperand(TempOp);
clc5q's avatar
clc5q committed
#if (IDA_SDK_VERSION < 700)
	TempOp.dtyp = GetRegDtyp(RegNum, (DefaultToMachineWidth && (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)));
clc5q's avatar
clc5q committed
#else
	TempOp.dtype = GetRegDtyp(RegNum, (DefaultToMachineWidth && (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)));
#endif
	TempOp.reg = RegNum;
	return dynamic_pointer_cast<STARS_op_t>(std::make_shared<STARS_IDA_op_t>(TempOp));
} // end of STARS_IDA_Instruction_t::MakeRegOpnd()

STARSOpndTypePtr STARS_IDA_Instruction_t::MakeFloatingPointRegOpnd(STARS_regnum_t RegNum) {
	op_t TempOp;
	this->InitOperand(TempOp);
	if (RegNum < STARS_x86_R_st0) {
		// X86 encodes STARS_x86_R_st0 as register 0, STARS_x86_R_st1 as register 1, with o_fpreg flag indicating adjustment.
		//  We want to encode using the STARS_regnum_t enumeration alone.
		RegNum = (STARS_regnum_t) (((int) STARS_x86_R_st0) + ((int) RegNum));
	}
clc5q's avatar
clc5q committed
#if (IDA_SDK_VERSION < 700)
	TempOp.dtyp = GetRegDtyp(RegNum, false);
clc5q's avatar
clc5q committed
#else
	TempOp.dtype = GetRegDtyp(RegNum, false);
#endif
	return dynamic_pointer_cast<STARS_op_t>(std::make_shared<STARS_IDA_op_t>(TempOp));
} // end of STARS_IDA_Instruction_t::MakeFloatingPointRegOpnd()

STARSOpndTypePtr STARS_IDA_Instruction_t::MakeMMXRegOpnd(STARS_regnum_t RegNum) {
	op_t TempOp;
	this->InitOperand(TempOp);
	TempOp.type = o_mmxreg;
	TempOp.reg = RegNum;
clc5q's avatar
clc5q committed
#if (IDA_SDK_VERSION < 700)
	TempOp.dtyp = GetRegDtyp(RegNum, false);
clc5q's avatar
clc5q committed
#else
	TempOp.dtype = GetRegDtyp(RegNum, false);
#endif
	return dynamic_pointer_cast<STARS_op_t>(std::make_shared<STARS_IDA_op_t>(TempOp));
} // end of STARS_IDA_Instruction_t::MakeMMXRegOpnd()

STARSOpndTypePtr STARS_IDA_Instruction_t::MakeXMMRegOpnd(STARS_regnum_t RegNum) {
	op_t TempOp;
	this->InitOperand(TempOp);
	TempOp.type = o_xmmreg;
	TempOp.reg = RegNum;
clc5q's avatar
clc5q committed
#if (IDA_SDK_VERSION < 700)
	TempOp.dtyp = GetRegDtyp(RegNum, false);
clc5q's avatar
clc5q committed
#else
	TempOp.dtype = GetRegDtyp(RegNum, false);
#endif
	return dynamic_pointer_cast<STARS_op_t>(std::make_shared<STARS_IDA_op_t>(TempOp));
} // end of STARS_IDA_Instruction_t::MakeXMMRegOpnd()

STARSOpndTypePtr STARS_IDA_Instruction_t::MakeYMMRegOpnd(STARS_regnum_t RegNum) {
	op_t TempOp;
	this->InitOperand(TempOp);
	TempOp.type = o_ymmreg;
	TempOp.reg = RegNum;
clc5q's avatar
clc5q committed
#if (IDA_SDK_VERSION < 700)
	TempOp.dtyp = GetRegDtyp(RegNum, false);
clc5q's avatar
clc5q committed
#else
	TempOp.dtype = GetRegDtyp(RegNum, false);
#endif
	return dynamic_pointer_cast<STARS_op_t>(std::make_shared<STARS_IDA_op_t>(TempOp));
} // end of STARS_IDA_Instruction_t::MakeYMMRegOpnd()

clc5q's avatar
clc5q committed
STARSOpndTypePtr STARS_IDA_Instruction_t::MakeNearPointerOpnd(STARS_ea_t TargetAddr) const {
	op_t TempOp;
	this->InitOperand(TempOp);
	TempOp.type = o_near;
	TempOp.addr = TargetAddr;
	return dynamic_pointer_cast<STARS_op_t>(std::make_shared<STARS_IDA_op_t>(TempOp));
}

STARSOpndTypePtr STARS_IDA_Instruction_t::MakeMemPhraseOpnd(STARS_regnum_t BaseRegNum, STARS_regnum_t IndexRegNum, uint16_t ScaleFactor) {
	// TODO: Construct SIB byte when IndexRegNum is used.
	op_t TempOp;
	this->InitOperand(TempOp);
	TempOp.type = o_phrase;
	TempOp.reg = BaseRegNum;
clc5q's avatar
clc5q committed
#if (IDA_SDK_VERSION < 700)
	TempOp.dtyp = GetRegDtyp(BaseRegNum, this->Has64BitOperands());
clc5q's avatar
clc5q committed
#else
	TempOp.dtype = GetRegDtyp(BaseRegNum, this->Has64BitOperands());
#endif
	return dynamic_pointer_cast<STARS_op_t>(std::make_shared<STARS_IDA_op_t>(TempOp));
} // end of STARS_IDA_Instruction_t::MakeMemPhraseOpnd()

STARSOpndTypePtr STARS_IDA_Instruction_t::MakeMemDisplacementOpnd(STARS_regnum_t BaseRegNum, STARS_regnum_t IndexRegNum, uint16_t ScaleFactor, STARS_ea_t offset) {
	// TODO: Construct SIB byte when IndexRegNum is used.
	op_t TempOp;
	this->InitOperand(TempOp);
	TempOp.type = o_displ;
	TempOp.reg = BaseRegNum;
	TempOp.addr = (ea_t) offset;
clc5q's avatar
clc5q committed
#if (IDA_SDK_VERSION < 700)
	TempOp.dtyp = GetRegDtyp(BaseRegNum, this->Has64BitOperands());
clc5q's avatar
clc5q committed
#else
	TempOp.dtype = GetRegDtyp(BaseRegNum, this->Has64BitOperands());
#endif
	return dynamic_pointer_cast<STARS_op_t>(std::make_shared<STARS_IDA_op_t>(TempOp));
} // end of STARS_IDA_Instruction_t::MakeMemDisplacementOpnd()

bool STARS_IDA_Instruction_t::IsBranchToFarChunk(SMPInstr *CurrInst, STARS_ea_t &TargetAddr) {
	bool FarBranch = false;
	set<DefOrUse, LessDefUse>::iterator CurrUse;
	func_t *CurrChunk = ::get_fchunk(this->m_id.GetIDWithinFile());
	if (nullptr != CurrChunk) { // CurrInst is not an orphan
		for (CurrUse = CurrInst->GetFirstUse(); CurrUse != CurrInst->GetLastUse(); ++CurrUse) {
			STARSOpndTypePtr JumpTarget = CurrUse->GetOp();
			if (JumpTarget->IsNearPointer() || JumpTarget->IsFarPointer()) {
				// Branches to a code address
				TargetAddr = JumpTarget->GetAddr();
				// stdclib sometimes has jumps to zero and calls to zero. These are dead code.
				if ((0 != TargetAddr) && (STARS_BADADDR != TargetAddr)) {
					func_t *TargetChunk = ::get_fchunk(TargetAddr);
					// Is target address within the same chunk as the branch?
clc5q's avatar
clc5q committed
#if (IDA_SDK_VERSION < 700)
					FarBranch = (NULL == TargetChunk) || (CurrChunk->startEA != TargetChunk->startEA);
clc5q's avatar
clc5q committed
#else
					FarBranch = (NULL == TargetChunk) || (CurrChunk->start_ea != TargetChunk->start_ea);
clc5q's avatar
clc5q committed
#endif
	}
	return FarBranch;
} // end of STARS_IDA_Instruction_t::IsBranchToFarChunk()
bool STARS_IDA_Instruction_t::IsPushFromFixedCall(void) const {
	STARS_ea_t TargetAddr = this->STARScmd.Operands[0]->GetAddr();
	bool PushOfInternalAddress = global_STARS_program->AreInstIDsInSameFunction(this->m_id.GetIDWithinFile(), TargetAddr);
	return PushOfInternalAddress;
}
STARS_InstructionID_Set_t STARS_IDA_Instruction_t::GetReferencedInstructionIDs(bool &success) {
	assert(false);
	return STARS_InstructionID_Set_t();
}

// Get inst IDs of jump targets, call targets, etc., including for analyzeable indirect calls and jumps; success = false otherwise
STARS_InstructionID_Set_t STARS_IDA_Instruction_t::GetTargetedInstructionIDs(bool &success) {
	STARS_InstructionID_Set_t TargetIDSet;

	// Use code xrefs to find non-fallthrough code targets.
	SMP_xref_t InstXrefs;
	for (bool ok = InstXrefs.SMP_first_from(this->m_id.GetIDWithinFile(), XREF_FAR); ok; ok = InstXrefs.SMP_next_from()) {
		if (!InstXrefs.GetIscode())
			break; // no need to go on to data xrefs
		assert(fl_F != InstXrefs.GetType()); // should not be ordinary fall-through
		STARS_ea_t TargetAddr = InstXrefs.GetTo();
		assert(STARS_BADADDR != TargetAddr);
		STARS_InstructionID_t TargetID(TargetAddr);
		pair<STARS_InstructionID_Set_t::iterator, bool> InsertResult = TargetIDSet.insert(TargetID);
		assert(InsertResult.second);
	}

	success = (!TargetIDSet.empty());
	return TargetIDSet;
}

// return inst ID addr for fall-through from this inst
STARS_ea_t STARS_IDA_Instruction_t::GetFallThroughInstID(void) {
	STARS_ea_t FallThroughAddr = STARS_BADADDR;
	SMP_xref_t InstXrefs;
	for (bool ok = InstXrefs.SMP_first_from(this->m_id.GetIDWithinFile(), XREF_ALL); ok; ok = InstXrefs.SMP_next_from()) {
		if (!InstXrefs.GetIscode())
			break; // no need to go on to data xrefs
		if (fl_F == InstXrefs.GetType()) { // ordinary fall-through
			FallThroughAddr = InstXrefs.GetTo();
			break;
		}
	}
	if (STARS_BADADDR == FallThroughAddr) {
		// We could try to use SMPBasicBlock::FindCallInstFallThrough() here
		//  to audit the completeness of the Xrefs.
		;
	}

	return FallThroughAddr;
} // end of STARS_IDA_Instruction_t::GetFallThroughInstID()

// Analyze the indirect jump at IndirJumpInst, put switch table info in TableInfo if available, return false otherwise.
// Note: The TableInfo.FollowNodeNum field must be determined by later analysis.
bool STARS_IDA_Instruction_t::AnalyzeSwitchStatement(SMPInstr *IndirJumpInst, struct SwitchTableInfo &TableInfo) {
	bool success = false;
	assert(NULL != IndirJumpInst);
	assert(INDIR_JUMP == IndirJumpInst->GetDataFlowType());
	STARS_ea_t IndirJumpAddr = IndirJumpInst->GetAddr();
clc5q's avatar
clc5q committed
#if (IDA_SDK_VERSION < 700)
	switch_info_ex_t SwitchInfo;
	if (get_switch_info_ex(IndirJumpAddr, &SwitchInfo, sizeof(SwitchInfo)) > 0) {
clc5q's avatar
clc5q committed
#else
	switch_info_t SwitchInfo;
	if (get_switch_info(&SwitchInfo, IndirJumpAddr) > 0) {
#endif
		casevec_t CaseVector;
		eavec_t TargetAddrsVector;
clc5q's avatar
clc5q committed
#if (IDA_SDK_VERSION < 700)
		success = ::calc_switch_cases(IndirJumpAddr, &SwitchInfo, &CaseVector, &TargetAddrsVector);
clc5q's avatar
clc5q committed
#else
		success = ::calc_switch_cases(&CaseVector, &TargetAddrsVector, IndirJumpAddr, SwitchInfo);
#endif
		if (success) {
			success = (CaseVector.size() == TargetAddrsVector.size()); // sanity check
		}
		if (success) {
			// Transfer data into TableInfo.
			TableInfo.FollowNodeNum = SMP_BLOCKNUM_UNINIT;
			TableInfo.IDomBlockNum = SMP_BLOCKNUM_UNINIT;
			TableInfo.IndirJumpBlockNum = IndirJumpInst->GetBlock()->GetNumber();
			TableInfo.DefaultJumpAddr = SwitchInfo.defjump; // will be STARS_BADADDR if no default case
			if (STARS_BADADDR != TableInfo.DefaultJumpAddr) {
				// We have a default case
				// Guard against bad disassembly by making sure the default case addr is in the function.
				if (! IndirJumpInst->GetBlock()->GetFunc()->IsInstIDInFunc(TableInfo.DefaultJumpAddr)) {
					success = false;
					SMP_msg("ERROR: AnalyzeSwitchStatement: Switch default case addr %llx not in func %s\n", (uint64_t)TableInfo.DefaultJumpAddr,
						IndirJumpInst->GetBlock()->GetFunc()->GetFuncName());
					return success;
				}
				SMPBasicBlock *DefaultCaseBlock = IndirJumpInst->GetBlock()->GetFunc()->GetBlockFromInstAddr(TableInfo.DefaultJumpAddr);
				assert(NULL != DefaultCaseBlock);
				int DefaultBlockNum = DefaultCaseBlock->GetNumber();
				assert(SMP_BLOCKNUM_UNINIT != DefaultBlockNum);
				TableInfo.DefaultCaseBlockNum = DefaultBlockNum;
			}
			else {
				TableInfo.DefaultCaseBlockNum = SMP_BLOCKNUM_UNINIT;
			}
			std::size_t IndexLimit = CaseVector.size();
			for (std::size_t Index = 0; Index < IndexLimit; ++Index) {
				std::vector<STARS_sval_t> CurrCaseValues;
				std::size_t CaseIndexLimit = CaseVector[Index].size();
				for (std::size_t CaseIndex = 0; CaseIndex < CaseIndexLimit; ++CaseIndex) {
					// Can have case 2, case 4, case 7 etc. all map to one target block
					CurrCaseValues.push_back((STARS_sval_t) CaseVector[Index].at(CaseIndex));
				}
				TableInfo.IndexValue.push_back(CurrCaseValues);
				STARS_ea_t TargetAddr = (STARS_ea_t) TargetAddrsVector[Index];
				// Translate TargetAddr to a block number.
				if (STARS_BADADDR == TargetAddr) {
					success = false;
					break;
				}
				int TargetBlockNum = IndirJumpInst->GetBlock()->GetFunc()->GetBlockNumFromInstAddr(TargetAddr);
				if (SMP_BLOCKNUM_UNINIT == TargetBlockNum) {
					success = false;
					break;
				}
				TableInfo.CaseBlockNums.push_back(TargetBlockNum);
			} // end for Index = 0 to IndexLimit
		} // end if success
	} // end if get_switch_info_ex() > 0
	return success;
} // end of STARS_IDA_Instruction_t::AnalyzeSwitchStatement()