Newer
Older
/*
* SMPDataFlowAnalysis.cpp - <see below>.
*
* Copyright (c) 2000, 2001, 2010 - University of Virginia
*
* This file is part of the Memory Error Detection System (MEDS) infrastructure.
* This file may be used and modified for non-commercial purposes as long as
* all copyright, permission, and nonwarranty notices are preserved.
* Redistribution is prohibited without prior written consent from the University
* of Virginia.
*
* Please contact the authors for restrictions applying to commercial use.
*
* THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Author: University of Virginia
* e-mail: jwd@virginia.com
* URL : http://www.cs.virginia.edu/
*
* Additional copyrights 2010, 2011, 2012, 2013, 2014, 2015 by Zephyr Software LLC
* e-mail: {clc,jwd}@zephyr-software.com
* URL : http://www.zephyr-software.com/
*
// This module contains common types an helper classes needed for the
#include <string>
#include <cassert>
#include "interfaces/SMPDBInterface.h"
#include "base/SMPDataFlowAnalysis.h"
#include "base/SMPInstr.h"
#include "base/SMPBasicBlock.h"
#include "base/SMPFunction.h"
using namespace std;
// Set these to 1 for debugging output
#define SMP_DEBUG_CONTROLFLOW 0 // tells what processing stage is entered
#define SMP_DEBUG_CHUNKS 1 // tracking down tail chunks for functions
#define SMP_DEBUG_FRAMEFIXUP 0 // Fixing up stack frame info the way we want the offsets
#define SMP_DEBUG_OPERAND_TYPES 1 // leave on; warnings that should never happen
#define STARS_DEBUG_DUMP_IDENTIFY_HIDDEN_OPERANDS 0 // print HIDDEN if operand.showed() is false
#define MAX_IDA_REG STARS_x86_R_last
// Bit masks for extracting bits from a STARSBitSet unsigned char.
const unsigned char STARSBitMasks[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
{ "EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI",
"R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
"AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH",
"SPL", "BPL", "SIL", "DIL", "EIP", "ES", "CS", "SS",
"DS", "FS", "GS", "CF", "ZF", "SF", "OF", "PF",
"AF", "TF", "IF", "DF", "EFLAGS", "FPU_ST0", "FPU_ST1", "FPU_ST2",
"FPU_ST3", "FPU_ST4", "FPU_ST5", "FPU_ST6", "FPU_ST7", "FPU_CTRL", "FPU_STAT", "FPU_TAGS",
"MMX0", "MMX1", "MMX2", "MMX3", "MMX4", "MMX5", "MMX6", "MMX7",
"XMM0", "XMM1", "XMM2", "XMM3", "XMM4", "XMM5", "XMM6", "XMM7",
"XMM8", "XMM9", "XMM10", "XMM11", "XMM12", "XMM13", "XMM14", "XMM15",
"MXCSR",
"YMM0", "YMM1", "YMM2", "YMM3", "YMM4", "YMM5", "YMM6", "YMM7",
"YMM8", "YMM9", "YMM10", "YMM11", "YMM12", "YMM13", "YMM14", "YMM15",
// NOTE: Review these sizes. Alter when annotation diffs can be isolated to the change.
// !!!!****!!!! FP reg stack should be 10-byte registers, right?
const unsigned char RegSizes[MAX_IDA_REG + 1] =
{ 4, 4, 4, 4, 4, 4, 4, 4,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 4, 2, 2, 2,
2, 2, 2, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 10, 10, 10,
10, 10, 10, 10, 10, 4, 4, 4,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
4,
32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32,
unsigned char GetRegSize(uint16_t RegNum) {
assert(RegNum != ((uint16_t) STARS_x86_R_none));
return RegSizes[RegNum];
}
const char RegDtyps[MAX_IDA_REG + 1] =
{ STARS_dt_dword, STARS_dt_dword, STARS_dt_dword, STARS_dt_dword, STARS_dt_dword, STARS_dt_dword, STARS_dt_dword, STARS_dt_dword,
STARS_dt_qword, STARS_dt_qword, STARS_dt_qword, STARS_dt_qword, STARS_dt_qword, STARS_dt_qword, STARS_dt_qword, STARS_dt_qword,
STARS_dt_byte, STARS_dt_byte, STARS_dt_byte, STARS_dt_byte, STARS_dt_byte, STARS_dt_byte, STARS_dt_byte, STARS_dt_byte,
STARS_dt_byte, STARS_dt_byte, STARS_dt_byte, STARS_dt_byte, STARS_dt_dword, STARS_dt_dword, STARS_dt_dword, STARS_dt_dword,
STARS_dt_dword, STARS_dt_dword, STARS_dt_dword, STARS_dt_dword, STARS_dt_dword, STARS_dt_dword, STARS_dt_dword, STARS_dt_dword,
STARS_dt_dword, STARS_dt_dword, STARS_dt_dword, STARS_dt_dword, STARS_dt_dword, STARS_dt_tbyte, STARS_dt_tbyte, STARS_dt_tbyte,
STARS_dt_tbyte, STARS_dt_tbyte, STARS_dt_tbyte, STARS_dt_tbyte, STARS_dt_tbyte, STARS_dt_word, STARS_dt_word, STARS_dt_word,
STARS_dt_byte16, STARS_dt_byte16, STARS_dt_byte16, STARS_dt_byte16, STARS_dt_byte16, STARS_dt_byte16, STARS_dt_byte16, STARS_dt_byte16,
STARS_dt_byte16, STARS_dt_byte16, STARS_dt_byte16, STARS_dt_byte16, STARS_dt_byte16, STARS_dt_byte16, STARS_dt_byte16, STARS_dt_byte16,
STARS_dt_byte16, STARS_dt_byte16, STARS_dt_byte16, STARS_dt_byte16, STARS_dt_byte16, STARS_dt_byte16, STARS_dt_byte16, STARS_dt_byte16,
STARS_dt_word,
STARS_dt_byte32, STARS_dt_byte32, STARS_dt_byte32, STARS_dt_byte32, STARS_dt_byte32, STARS_dt_byte32, STARS_dt_byte32, STARS_dt_byte32,
STARS_dt_byte32, STARS_dt_byte32, STARS_dt_byte32, STARS_dt_byte32, STARS_dt_byte32, STARS_dt_byte32, STARS_dt_byte32, STARS_dt_byte32,
STARS_dt_word
const char *ErrorStrings[1] = { "ERROR_REG" };
const char *WordRegStrings[8] = { "AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI" };
const char *QWordRegStrings[8] = { "RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI" };
const char *SignednessStrings[4] = { "UNKNOWNSIGN", "SIGNED", "UNSIGNED", "UNKNOWNSIGN" };
const char *LeaSignednessStrings[4] = { "NOFLAGUNKNOWNSIGN", "NOFLAGSIGNED", "NOFLAGUNSIGNED", "NOFLAGUNKNOWNSIGN" };
// Distinguishes subword regs from their parent regs
const char *MDGetRegNumName(uint16_t RegNum, uint16_t ByteWidth) {
if ((STARS_x86_R_none == RegNum) || (MAX_IDA_REG < RegNum))
return ErrorStrings[0];
else if ((ByteWidth == 2) && (RegNum >= STARS_x86_R_ax) && (RegNum <= STARS_x86_R_di)) {
// 16-bit registers
return WordRegStrings[RegNum];
else if ((ByteWidth == 8) && (RegNum >= STARS_x86_R_ax) && (RegNum <= STARS_x86_R_di)) {
// 64-bit registers
return QWordRegStrings[RegNum];
return RegNames[RegNum];
// Distinguishes subword regs from their parent regs
const char *MDGetRegName(const STARSOpndTypePtr &RegOp) {
if (!RegOp->IsRegOp())
return ErrorStrings[0];
uint16_t RegNum = RegOp->GetReg();
uint16_t ByteWidth = RegOp->GetByteWidth();
return MDGetRegNumName(RegNum, ByteWidth);
}
SMPitype DFACategory[STARS_NN_last+1];
// Define instruction categories for data type analysis.
int SMPTypeCategory[STARS_NN_last+1];
// Define which instructions define and use the CPU flags.
bool SMPDefsFlags[STARS_NN_last + 1];
bool SMPUsesFlags[STARS_NN_last + 1];
// Hash a global name and SSA number into an int, for use in SMPFunction.GlobalDefAddrBySSA map
int HashGlobalNameAndSSA(const STARSOpndTypePtr &DefOp, int SSANum) {
assert(DefOp->IsRegOp());
return ((SSANum << 16) | ((int)(DefOp->GetReg())));
// Get the size in bytes of the data type of an operand.
size_t GetOpDataSize(const STARSOpndTypePtr &DataOp) {
char OpDtyp = DataOp->GetOpDtyp();
if (DataOp->IsRegOp()) {
DataSize = RegSizes[DataOp->GetReg()];
if (OpDtyp == STARS_dt_word) {
DataSize = 2;
#if 0
SMP_msg("Found 16-bit register using dtyp field.\n");
#endif
}
else if (OpDtyp == STARS_dt_qword) {
DataSize = 8;
#if 0
SMP_msg("Found 64-bit register using dtyp field.\n");
#endif
}
return DataSize;
}
switch (OpDtyp) {
case STARS_dt_byte:
case STARS_dt_word:
case STARS_dt_dword:
case STARS_dt_float:
case STARS_dt_code:
case STARS_dt_unicode:
case STARS_dt_string:
case STARS_dt_double:
case STARS_dt_qword:
case STARS_dt_tbyte:
DataSize = 10;
break;
case STARS_dt_packreal:
case STARS_dt_byte16:
case STARS_dt_ldbl:
case STARS_dt_fword:
case STARS_dt_3byte:
case STARS_dt_byte32:
DataSize = 32;
break;
case STARS_dt_byte64:
DataSize = 64;
break;
SMP_msg("ERROR: unexpected data type %d in GetOpDataSize() :", OpDtyp);
clc5q
committed
SMP_msg("\n");
DataSize = global_STARS_program->GetSTARS_ISA_dtyp();
break;
}
return DataSize;
} // end of GetOpDataSize()
// Get the IDA Pro register size (dtyp) field
char GetRegDtyp(uint16_t RegNum, bool Has64BitOpnds) {
assert(RegNum != ((uint16_t) STARS_x86_R_none));
assert(RegNum < MAX_IDA_REG);
char RegDtyp = RegDtyps[RegNum];
if ((global_STARS_program->GetSTARS_ISA_Bytewidth() == 8) && Has64BitOpnds && (RegDtyp == STARS_dt_dword) && (RegNum <= STARS_x86_R_ip)) {
// 32-bit IDA general regs are 64-bit for x86-64
RegDtyp = STARS_dt_qword;
}
return RegDtyp;
}
// Return one of the bit width masks for the current operand.
// Pass in DataSize in bytes if known, else pass in DataSize = 0.
unsigned short ComputeOperandBitWidthMask(const STARSOpndTypePtr &CurrOp, size_t DataSize) {
unsigned short BitWidthMask = 32;
if (0 == DataSize)
DataSize = GetOpDataSize(CurrOp);
if (4 == DataSize)
BitWidthMask = FG_MASK_BITWIDTH_32;
else if (8 == DataSize)
BitWidthMask = FG_MASK_BITWIDTH_64;
else if (1 == DataSize)
BitWidthMask = FG_MASK_BITWIDTH_8;
else if (2 == DataSize)
BitWidthMask = FG_MASK_BITWIDTH_16;
else if (16 == DataSize)
BitWidthMask = FG_MASK_BITWIDTH_128;
else if (3 == DataSize)
BitWidthMask = FG_MASK_BITWIDTH_24;
else if (6 == DataSize)
BitWidthMask = FG_MASK_BITWIDTH_48;
else if (10 == DataSize)
BitWidthMask = FG_MASK_BITWIDTH_80;
else if (12 == DataSize)
BitWidthMask = FG_MASK_BITWIDTH_96;
else if (32 == DataSize)
BitWidthMask = FG_MASK_BITWIDTH_256;
else {
SMP_msg("ERROR: Unknown DataSize: %zu bytes ", DataSize);
PrintOperand(CurrOp);
clc5q
committed
SMP_msg("\n");
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
}
return BitWidthMask;
} // end of ComputeOperandBitWidthMask()
// Compute largest bit width from a SignMiscInfo bit mask.
size_t LargestBitWidthFromMask(unsigned short WidthTypeInfo) {
unsigned short BitWidthMask = WidthTypeInfo & FG_MASK_BITWIDTH_FIELDS;
size_t LargestWidth = 0;
// Go from highest bit width to lowest.
if (BitWidthMask & FG_MASK_BITWIDTH_256)
LargestWidth = 256;
else if (BitWidthMask & FG_MASK_BITWIDTH_128)
LargestWidth = 128;
else if (BitWidthMask & FG_MASK_BITWIDTH_96)
LargestWidth = 96;
else if (BitWidthMask & FG_MASK_BITWIDTH_64)
LargestWidth = 64;
else if (BitWidthMask & FG_MASK_BITWIDTH_48)
LargestWidth = 48;
else if (BitWidthMask & FG_MASK_BITWIDTH_32)
LargestWidth = 32;
else if (BitWidthMask & FG_MASK_BITWIDTH_24)
LargestWidth = 24;
else if (BitWidthMask & FG_MASK_BITWIDTH_16)
LargestWidth = 16;
else if (BitWidthMask & FG_MASK_BITWIDTH_8)
LargestWidth = 8;
return LargestWidth;
} // end of LargestBitWidthFromMask()
// Is CurrOp a general purpose register? (not flags, instruction pointer, non-integer reg, etc.)
bool MDIsGeneralPurposeReg(const STARSOpndTypePtr &CurrOp) {
bool success = (nullptr != CurrOp);
if (success) {
// intel.hpp defines two ranges that are general purpose regs in enum RegNo.
uint16_t CurrReg = CurrOp->GetReg();
success = (CurrOp->IsRegOp() && ((CurrReg >= STARS_x86_R_ax) && (CurrReg <= STARS_x86_R_dil)));
}
return success;
clc5q
committed
// Are operands equal?
bool IsEqOp(const STARSOpndTypePtr &Opnd1, const STARSOpndTypePtr &Opnd2)
{
if ((nullptr == Opnd1) && (nullptr == Opnd2))
return true;
if ((nullptr == Opnd1) || (nullptr == Opnd2))
return false;
clc5q
committed
// this expression is logically equiv. to "equal"
//
// truth table:
//
// O1 O2 O1<O2 !(O1<O2) O2<O1 !(O2<O1) !(O1<O2)&&!(O2<O1) ==
// 0 0 0 1 0 1 1 1
// 0 1 1 0 0 0 0 0
// 1 0 0 1 1 0 0 0
// 1 1 0 1 0 0 1 1
return !(*Opnd1 < *Opnd2) && !(*Opnd2 < *Opnd1);
clc5q
committed
} // end of function IsEqOp()
// Are operands equal, ignoring bitwidth differences for register operands?
bool IsEqOpIgnoreBitwidth(const STARSOpndTypePtr &Opnd1, const STARSOpndTypePtr &Opnd2) {
if (Opnd1->GetOpType() != Opnd2->GetOpType())
if (Opnd1->IsRegOp())
return (Opnd1->GetReg() == Opnd2->GetReg()); // no concern for subword regs; AX == EAX == RAX
else
return IsEqOp(Opnd1, Opnd2);
clc5q
committed
} // end of function IsEqOpIgnoreBitwidth()
// We need to make subword registers equal to their containing registers when we
// do comparisons, so that we will realize that register EAX is killed by a prior DEF
// of register AL, for example, and vice versa. To keep sets ordered strictly,
// we also have to make AL and AH be equal to each other as well as equal to EAX.
bool MDLessReg(const uint16_t Reg1, const uint16_t Reg2) {
uint16_t SReg1 = MDCanonicalizeSubReg(Reg1);
uint16_t SReg2 = MDCanonicalizeSubReg(Reg2);
return (SReg1 < SReg2);
} // end of MDLessReg()
bool MDEqReg(const uint16_t Reg1, const uint16_t Reg2) {
uint16_t SReg1 = MDCanonicalizeSubReg(Reg1);
uint16_t SReg2 = MDCanonicalizeSubReg(Reg2);
return (SReg1 == SReg2);
} // end of MDEqReg()
bool MDLessRegOpnd(const STARSOpndTypePtr &RegOp1, const STARSOpndTypePtr &RegOp2) {
uint16_t SReg1 = MDCanonicalizeSubReg(RegOp1->GetReg());
uint16_t SReg2 = MDCanonicalizeSubReg(RegOp2->GetReg());
return ((SReg1 < SReg2) || ((SReg1 == SReg2) && (RegOp1->GetByteWidth() < RegOp2->GetByteWidth())));
} // end of MDLessRegOpnd()
uint16_t MDCanonicalizeSubReg(const uint16_t Reg1) {
bool Subword = ((Reg1 >= FIRST_X86_SUBWORD_REG) && (Reg1 <= LAST_X86_SUBWORD_REG));
uint16_t SReg1 = Reg1;
if (Subword) {
// See enumeration RegNo in intel.hpp.
if (SReg1 < STARS_x86_R_ah) // AL, CL, DL or BL
SReg1 -= (STARS_x86_R_al - STARS_x86_R_ax);
else // AH, CH, DH, BH, SPL, BPL, SIL, DIL
SReg1 -= (STARS_x86_R_ah - STARS_x86_R_ax);
return SReg1;
} // end of MDCanonicalizeSubReg()
#if 0
// If TempOp is a register, call MDCanonicalizeSubReg() on it.
void CanonicalizeOpnd(STARSOpndTypePtr &TempOp) {
if (TempOp->IsRegOp()) {
uint16_t NewReg = MDCanonicalizeSubReg(TempOp->GetReg());
if (TempOp->GetReg() != NewReg) {
TempOp->SetReg(NewReg);
}
}
}
#else
// If TempOp is a register, call MDCanonicalizeSubReg() on it.
void CanonicalizeOpnd(STARSOpndTypePtr &TempOp) {
if (TempOp->IsRegOp()) {
if (4 > GetOpDataSize(TempOp)) {
TempOp->SetReg(MDCanonicalizeSubReg(TempOp->GetReg()));
// Convert 32-bit regs to 64-bit on 64-bit binaries.
uint16_t CanonicalByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth();
if (TempOp->GetByteWidth() < CanonicalByteWidth) {
TempOp->SetByteWidth(CanonicalByteWidth);
}
bool MDIsStackOrFramePointerReg(const STARSOpndTypePtr &RegOp, bool UseFP) {
bool PtrReg = false;
if (RegOp->IsRegOp()) {
PtrReg = RegOp->MatchesReg(MD_STACK_POINTER_REG) || (UseFP && RegOp->MatchesReg(MD_FRAME_POINTER_REG));
}
return PtrReg;
}
// In SSA computations, we are storing the GlobalNames index into the op_t fields
// n, offb, and offo. This function extracts an unsigned int from these three 8-bit
// fields.
unsigned int ExtractGlobalIndex(const STARSOpndTypePtr &GlobalOp) {
return GlobalOp->GetOpGlobalIndex();
void SetGlobalIndex(STARSOpndTypePtr TempOp, size_t index) {
TempOp->SetOpGlobalIndex(index);
return;
}
int MD_STARS_sib_base(const STARSOpndTypePtr &x) { // get extended sib base
return x->MDGetSIBBaseReg();
short MD_STARS_sib_index(const STARSOpndTypePtr &x) { // get extended sib index
return x->MDGetSIBIndexReg();
clc5q
committed
// Return true if CurrOp could be an indirect memory reference.
bool MDIsIndirectMemoryOpnd(const STARSOpndTypePtr &CurrOp, bool UseFP) {
clc5q
committed
bool indirect = false;
if ((nullptr == CurrOp) || (! CurrOp->IsMemOp()))
clc5q
committed
return false;
if (CurrOp->HasSIBByte()) {
STARS_RegNo BaseReg = (STARS_RegNo)MD_STARS_sib_base(CurrOp);
STARS_RegNo IndexReg = (STARS_RegNo)MD_STARS_sib_index(CurrOp);
if ((STARS_x86_R_none != IndexReg) && (MD_STACK_POINTER_REG != IndexReg)) {
if ((MD_FRAME_POINTER_REG == IndexReg) && UseFP)
clc5q
committed
;
else
indirect = true;
}
if (0 != CurrOp->GetSIBScaleFactor())
clc5q
committed
indirect = true;
if (STARS_x86_R_none != BaseReg) {
if ((BaseReg == MD_FRAME_POINTER_REG) && CurrOp->IsStaticMemOp()) {
clc5q
committed
; // EBP ==> no base register for o_mem type
}
else if ((BaseReg == MD_FRAME_POINTER_REG) && UseFP)
clc5q
committed
; // EBP used as frame pointer for direct access
else if (BaseReg == MD_STACK_POINTER_REG)
clc5q
committed
; // ESP used as stack pointer for direct access
else
indirect = true; // conservative; some register used for addressing
// other than a stack or frame pointer
}
} // end if hasSIB
else { // no SIB; can have base register only
if (CurrOp->IsStaticMemOp()) { // no base register for o_mem
if (!((STARS_x86_R_none == BaseReg) || (MD_FRAME_POINTER_REG == BaseReg))) {
clc5q
committed
SMP_msg("base reg %d ignored \n", BaseReg);
clc5q
committed
}
}
else if ((BaseReg == MD_FRAME_POINTER_REG) && UseFP)
clc5q
committed
; // EBP used as frame pointer for direct access
else if (BaseReg == MD_STACK_POINTER_REG)
clc5q
committed
; // ESP used as stack pointer for direct access
else {
indirect = true;
}
}
return indirect;
} // end MDIsIndirectMemoryOpnd()
// Extract the base and index registers and scale factor and displacement from the
// memory operand.
void MDExtractAddressFields(const STARSOpndTypePtr &MemOp, int &BaseReg, int &IndexReg, uint16_t &Scale, STARS_ea_t &Offset) {
assert(MemOp->IsMemOp());
clc5q
committed
Scale = 0;
BaseReg = STARS_x86_R_none;
IndexReg = STARS_x86_R_none;
Offset = MemOp->GetAddr();
clc5q
committed
if (MemOp->HasSIBByte()) {
BaseReg = MD_STARS_sib_base(MemOp);
IndexReg = (int) MD_STARS_sib_index(MemOp);
if (MD_STACK_POINTER_REG == IndexReg) // signifies no index register
IndexReg = STARS_x86_R_none;
if (STARS_x86_R_none != IndexReg) {
Scale = (uint16_t) MemOp->GetSIBScaleFactor();
clc5q
committed
}
if (STARS_x86_R_none != BaseReg) {
if ((BaseReg == MD_FRAME_POINTER_REG) && MemOp->IsStaticMemOp()) {
BaseReg = STARS_x86_R_none;
// **!!** BaseReg allowed for o_mem with SIB byte???
clc5q
committed
}
}
}
else { // no SIB byte; can have base reg but no index reg or scale factor
BaseReg = (int) MemOp->GetReg(); // cannot be STARS_x86_R_none for no SIB case
if (MemOp->IsStaticMemOp()) {
BaseReg = STARS_x86_R_none; // no Base register for o_mem operands
clc5q
committed
}
}
return;
} // end of MDExtractAddressFields()
// Is CurrOp a memory operand?
bool IsMemOperand(const STARSOpndTypePtr &CurrOp) {
return ((nullptr != CurrOp) && CurrOp->IsMemOp());
}
// MACHINE DEPENDENT: Is CurrOp the flags register?
bool MDIsFlagsReg(const STARSOpndTypePtr &CurrOp) {
return ((nullptr != CurrOp) && CurrOp->MatchesReg(X86_FLAGS_REG));
clc5q
committed
// MACHINE DEPENDENT: Is register a stack pointer or frame pointer?
bool MDIsStackPtrReg(int RegNumber, bool UseFP) {
return ((RegNumber == MD_STACK_POINTER_REG) || (UseFP && (RegNumber == MD_FRAME_POINTER_REG)));
clc5q
committed
}
// MACHINE DEPENDENT: Is operand a stack memory access?
bool MDIsStackAccessOpnd(const STARSOpndTypePtr &CurrOp, bool UseFP) {
int BaseReg;
int IndexReg;
uint16_t ScaleFactor;
STARS_ea_t offset;
if ((nullptr == CurrOp) || ((!CurrOp->IsMemDisplacementOp()) && (!CurrOp->IsMemNoDisplacementOp()))) {
return false;
}
MDExtractAddressFields(CurrOp, BaseReg, IndexReg, ScaleFactor, offset);
clc5q
committed
return MDIsStackPtrReg(BaseReg, UseFP);
} // end of MDIsStackAccessOpnd()
// MACHINE DEPENDENT: Is operand a direct stack memory access?
bool MDIsDirectStackAccessOpnd(const STARSOpndTypePtr &CurrOp, bool UseFP) {
int BaseReg;
int IndexReg;
uint16_t ScaleFactor;
STARS_ea_t offset;
if ((nullptr == CurrOp) || ((! CurrOp->IsMemDisplacementOp()) && (! CurrOp->IsMemNoDisplacementOp()))) {
return false;
}
MDExtractAddressFields(CurrOp, BaseReg, IndexReg, ScaleFactor, offset);
// When the IndexReg is
return (MDIsStackPtrReg(BaseReg, UseFP) && (IndexReg == STARS_x86_R_none));
} // end of MDIsDirectStackAccessOpnd()
// MACHINE DEPENDENT: Is operand trackable in data flow analyses (i.e. a direct stack memory access or a register?)
bool MDIsDataFlowOpnd(const STARSOpndTypePtr &CurrOp, bool UseFP) {
return ((nullptr != CurrOp) && (CurrOp->IsRegOp() || MDIsDirectStackAccessOpnd(CurrOp, UseFP)));
// MACHINE DEPENDENT: Is operand a caller-saved register?
bool MDIsCallerSavedReg(const STARSOpndTypePtr &CurrOp) {
if (! CurrOp->IsRegOp())
uint16_t CurrReg = MDCanonicalizeSubReg(CurrOp->GetReg());
return ((STARS_x86_R_ax == CurrReg) || (STARS_x86_R_cx == CurrReg) || (STARS_x86_R_dx == CurrReg));
// If CurrOp would change when reg is canonicalized, then return CurrOp->clone(), else return CurrOp;
STARSOpndTypePtr CloneIfSubwordReg(const STARSOpndTypePtr &CurrOp) {
uint16_t CurrReg = CurrOp->GetReg();
if (CurrOp->IsRegOp()) {
if (global_STARS_program->GetSTARS_ISA_Bytewidth() > CurrOp->GetByteWidth()) {
return CurrOp->clone();
}
else {
return CurrOp;
}
}
else {
return CurrOp;
}
} // end of CloneIfSubwordReg()
// If CurrOp would change when Canonicalized or stack-normalized, then return CurrOp->clone(), else return CurrOp;
STARSOpndTypePtr CloneIfNecessary(const STARSOpndTypePtr &CurrOp, bool UseFP) {
if (MDIsStackAccessOpnd(CurrOp, UseFP)) {
return CurrOp->clone();
}
else {
return CloneIfSubwordReg(CurrOp);
}
} // end of CloneIfNecessary()
// DEBUG Print DEF and/or USE for an operand.
void PrintDefUse(unsigned long feature, int OpNum) {
// CF_ macros number the operands from 1 to 6, while OpNum
// is a 0 to 5 index into the insn_t.Operands[] array.
// OpNum == -1 is a signal that this is a DEF or USE or VarKillSet etc.
// operand and not an instruction operand.
if (-1 == OpNum)
return;
switch (OpNum) {
case 0:
if (feature & STARS_CF_CHG1)
clc5q
committed
SMP_msg(" DEF");
if (feature & STARS_CF_USE1)
clc5q
committed
SMP_msg(" USE");
break;
case 1:
if (feature & STARS_CF_CHG2)
clc5q
committed
SMP_msg(" DEF");
if (feature & STARS_CF_USE2)
clc5q
committed
SMP_msg(" USE");
break;
case 2:
if (feature & STARS_CF_CHG3)
clc5q
committed
SMP_msg(" DEF");
if (feature & STARS_CF_USE3)
clc5q
committed
SMP_msg(" USE");
break;
case 3:
if (feature & STARS_CF_CHG4)
clc5q
committed
SMP_msg(" DEF");
if (feature & STARS_CF_USE4)
clc5q
committed
SMP_msg(" USE");
break;
case 4:
if (feature & STARS_CF_CHG5)
clc5q
committed
SMP_msg(" DEF");
if (feature & STARS_CF_USE5)
clc5q
committed
SMP_msg(" USE");
break;
case 5:
if (feature & STARS_CF_CHG6)
clc5q
committed
SMP_msg(" DEF");
if (feature & STARS_CF_USE6)
clc5q
committed
SMP_msg(" USE");
break;
}
return;
} // end PrintDefUse()
// DEBUG print SIB info for an operand.
void PrintSIB(const STARSOpndTypePtr &Opnd) {
int BaseReg;
int IndexReg;
uint16_t ScaleFactor;
STARS_ea_t offset;
#define NAME_LEN 5
char BaseName[NAME_LEN] = {'N', 'o', 'n', 'e', '\0'};
char IndexName[NAME_LEN] = {'N', 'o', 'n', 'e', '\0'};
MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, offset);
if (BaseReg != STARS_x86_R_none)
SMP_strncpy(BaseName, RegNames[BaseReg], NAME_LEN - 1);
if (IndexReg != STARS_x86_R_none) {
SMP_strncpy(IndexName, RegNames[IndexReg], NAME_LEN -1);
}
SMP_msg(" Base %s Index %s Scale %d Flag4 %d", BaseName, IndexName, ScaleFactor, Opnd->GetSpecFlag4());
} // end PrintSIB()
// Annotations: concisely print SIB info for an operand.
void AnnotPrintSIB(const STARSOpndTypePtr &Opnd, bool HasOffset, FILE *OutFile) {
int BaseReg;
int IndexReg;
uint16_t ScaleFactor;
STARS_ea_t offset;
char OutString[STARS_MAXSTR] = {'[', '\0'};
char ScaleString[4];
MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, offset);
if (ScaleFactor > 0) {
ScaleFactor = 1 << (ScaleFactor - 1);
(void) SMP_snprintf(ScaleString, 4, "%d", ScaleFactor);
}
if (BaseReg != STARS_x86_R_none) {
(void) SMP_strncat(OutString, MDGetRegNumName(BaseReg, RegSizes[BaseReg]), STARS_MAXSTR - 1);
if (IndexReg != STARS_x86_R_none) {
(void) SMP_strncat(OutString, "+", STARS_MAXSTR-1);
(void) SMP_strncat(OutString, MDGetRegNumName(IndexReg, RegSizes[IndexReg]), STARS_MAXSTR - 1);
if (ScaleFactor > 0) {
(void) SMP_strncat(OutString, "*", STARS_MAXSTR-1);
(void) SMP_strncat(OutString, ScaleString, STARS_MAXSTR-1);
}
}
}
else if (IndexReg != STARS_x86_R_none) {
(void) SMP_strncat(OutString, MDGetRegNumName(IndexReg, RegSizes[IndexReg]), STARS_MAXSTR - 1);
if (ScaleFactor > 0) {
(void) SMP_strncat(OutString, "*", STARS_MAXSTR-1);
(void) SMP_strncat(OutString, ScaleString, STARS_MAXSTR-1);
}
}
else {
clc5q
committed
SMP_msg("ERROR: No BaseReg, no IndexReg in SIB\n");
}
if (!HasOffset) // can close the brackets around regs
(void) SMP_strncat(OutString, "]", STARS_MAXSTR-1);
clc5q
committed
SMP_fprintf(OutFile, " %s", OutString);
} // end AnnotPrintSIB()
// Annotations: concisely print SIB info for an operand.
void SPARKAnnotPrintSIB(const STARSOpndTypePtr &Opnd, bool HasOffset, FILE *OutFile, uint16_t SegReg, bool UseFP) {
int BaseReg;
int IndexReg;
uint16_t ScaleFactor;
STARS_ea_t offset;
char OutString[STARS_MAXSTR] = {'(', '\0'};
char ScaleString[4];
MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, offset);
bool SegRegPrefix = STARS_x86_is_segreg((int) SegReg);
if (SegRegPrefix) {
// Emit segment register string unless it is just the stack segment plus a stack operand,
// where the stack segment is implied anyway.
if ((SegReg == STARS_x86_R_ss) && MDIsStackAccessOpnd(Opnd, UseFP)) {
(void) SMP_strncat(OutString, "X86.", STARS_MAXSTR-1);
(void) SMP_strncat(OutString, MDGetRegNumName(SegReg, RegSizes[SegReg]), STARS_MAXSTR-1);
if (ScaleFactor > 0) {
ScaleFactor = 1 << (ScaleFactor - 1);
(void) SMP_snprintf(ScaleString, 4, "%d", ScaleFactor);
}
if (BaseReg != STARS_x86_R_none) {
(void) SMP_strncat(OutString, " + ", STARS_MAXSTR-1);
(void) SMP_strncat(OutString, "X86.", STARS_MAXSTR-1);
(void) SMP_strncat(OutString, MDGetRegNumName(BaseReg, RegSizes[BaseReg]), STARS_MAXSTR-1);
if (global_STARS_program->GetSTARS_ISA_Bytewidth() > RegSizes[BaseReg]) {
++SubwordAddressRegCount;
}
if (IndexReg != STARS_x86_R_none) {
(void) SMP_strncat(OutString, " + ", STARS_MAXSTR-1);
(void) SMP_strncat(OutString, "X86.", STARS_MAXSTR-1);
(void) SMP_strncat(OutString, MDGetRegNumName(IndexReg, RegSizes[IndexReg]), STARS_MAXSTR-1);
if (global_STARS_program->GetSTARS_ISA_Bytewidth() > RegSizes[IndexReg]) {
++SubwordAddressRegCount;
}
if (ScaleFactor > 0) {
(void) SMP_strncat(OutString, "*", STARS_MAXSTR-1);
(void) SMP_strncat(OutString, ScaleString, STARS_MAXSTR-1);
}
}
}
else if (IndexReg != STARS_x86_R_none) {
(void) SMP_strncat(OutString, " + ", STARS_MAXSTR-1);
(void) SMP_strncat(OutString, "X86.", STARS_MAXSTR-1);
(void) SMP_strncat(OutString, MDGetRegNumName(IndexReg, RegSizes[IndexReg]), STARS_MAXSTR - 1);
if (global_STARS_program->GetSTARS_ISA_Bytewidth() > RegSizes[IndexReg]) {
++SubwordAddressRegCount;
}
if (ScaleFactor > 0) {
(void) SMP_strncat(OutString, "*", STARS_MAXSTR-1);
(void) SMP_strncat(OutString, ScaleString, STARS_MAXSTR-1);
}
}
SMP_msg("ERROR: No BaseReg, no IndexReg in SIB\n");
}
if (!HasOffset) // can close the parens around regs
(void) SMP_strncat(OutString, ")", STARS_MAXSTR-1);
SMP_fprintf(OutFile, " %s", OutString);
} // end SPARKAnnotPrintSIB()
// Debug: print one operand from an instruction or DEF or USE list.
void PrintOneOperand(const STARSOpndTypePtr &Opnd, uint32_t features, int OpNum) {
if ((nullptr != Opnd) && (!Opnd->IsVoidOp())) {
PrintOperand(Opnd);
PrintDefUse(features, OpNum);
}
return;
} // end of PrintOneOperand()
// Debug: print one operand.
void PrintOperand(const STARSOpndTypePtr &Opnd) {
if ((nullptr == Opnd) || (Opnd->IsVoidOp()))
else if (Opnd->IsStaticMemOp()) {
SMP_msg(" Operand: memory : addr: %lx", (unsigned long) Opnd->GetAddr());
if (Opnd->HasSIBByte()) {
PrintSIB(Opnd);
}
}
else if (Opnd->IsMemNoDisplacementOp()) {
clc5q
committed
SMP_msg(" Operand: memory phrase :");
if (Opnd->HasSIBByte()) { // has SIB info
PrintSIB(Opnd);
}
else { // no SIB info
uint16_t BaseReg = Opnd->GetReg();
clc5q
committed
SMP_msg(" reg %s", RegNames[BaseReg]);
if (Opnd->GetAddr() != 0) {
SMP_msg(" \n ERROR: addr for o_phrase type: %lx\n", (unsigned long) Opnd->GetAddr());
else if (Opnd->IsMemDisplacementOp()) {
clc5q
committed
SMP_msg(" Operand: memory displ :");
STARS_ea_t offset = Opnd->GetAddr();
int SignedOffset = (int) offset;
if (Opnd->HasSIBByte()) {
SMP_msg(" displ %d", SignedOffset);
uint16_t BaseReg = Opnd->GetReg();
SMP_msg(" reg %s displ %d", RegNames[BaseReg], SignedOffset);
else if (Opnd->IsRegOp()) {
SMP_msg(" Operand: register %s", MDGetRegName(Opnd));
else if (Opnd->IsImmedOp()) {
SMP_msg(" Operand: immed %ld", (long) Opnd->GetImmedValue());
}
else if (Opnd->IsFarPointer()) {
SMP_msg(" Operand: FarPtrImmed addr: %lx", (unsigned long) Opnd->GetAddr());
else if (Opnd->IsNearPointer()) {
SMP_msg(" Operand: NearPtrImmed addr: %lx", (unsigned long) Opnd->GetAddr());
else if (Opnd->IsTestRegOp()) {
SMP_msg(" Operand: TestReg reg: %d", Opnd->GetReg());
else if (Opnd->IsDebugRegOp()) {
SMP_msg(" Operand: DebugReg reg: %d", Opnd->GetReg());
else if (Opnd->IsControlRegOp()) {
SMP_msg(" Operand: ControlReg reg: %d", Opnd->GetReg());
else if (Opnd->IsFloatingPointRegOp()) {
SMP_msg(" Operand: FloatReg reg: %d", Opnd->GetReg());
else if (Opnd->IsMMXRegOp()) {
SMP_msg(" Operand: MMXReg reg: %d", Opnd->GetReg());
else if (Opnd->IsXMMRegOp()) {
SMP_msg(" Operand: XMMReg reg: %d", Opnd->GetReg());
else if (Opnd->IsYMMRegOp()) {
SMP_msg(" Operand: YMMReg reg: %d", Opnd->GetReg());
clc5q
committed
SMP_msg(" Operand: unknown");
if (!(Opnd->IsVisible()))
clc5q
committed
SMP_msg(" HIDDEN ");
} // end of PrintOperand()
// Print an operand that has no features flags or operand position number, such
// as the op_t types found in lists and sets throughout the blocks, phi functions, etc.
void PrintListOperand(const STARSOpndTypePtr &Opnd, int SSANum) {
if ((nullptr != Opnd) && (!Opnd->IsVoidOp())) {
clc5q
committed
SMP_msg(" SSANum: %d ", SSANum);
} // end of PrintListOperand()
// Annotations: concisely print one operand.
void AnnotPrintOperand(const STARSOpndTypePtr &Opnd, FILE *OutFile) {
if (Opnd->IsStaticMemOp()) {
SMP_fprintf(OutFile, " %llx", (unsigned long long) Opnd->GetAddr());
if (Opnd->HasSIBByte()) {
AnnotPrintSIB(Opnd, false, OutFile);
}
}
else if (Opnd->IsMemNoDisplacementOp()) {
if (Opnd->HasSIBByte()) { // has SIB info
AnnotPrintSIB(Opnd, false, OutFile);
}
else { // no SIB info
uint16_t BaseReg = Opnd->GetReg();
SMP_fprintf(OutFile, " [%s]", MDGetRegNumName(BaseReg, RegSizes[BaseReg]));
}
if (Opnd->GetAddr() != 0) {
SMP_msg(" \n ERROR: addr for o_phrase type: %lx\n", (unsigned long) Opnd->GetAddr());
}
}
else if (Opnd->IsMemDisplacementOp()) {
STARS_ea_t offset = Opnd->GetAddr();
int SignedOffset = (int) offset;
if (Opnd->HasSIBByte()) {
AnnotPrintSIB(Opnd, (SignedOffset != 0), OutFile);
if (SignedOffset > 0) // print plus sign
clc5q
committed
SMP_fprintf(OutFile, "+%d]", SignedOffset);
else if (SignedOffset < 0) // minus sign will print automatically
clc5q
committed
SMP_fprintf(OutFile, "%d]", SignedOffset);
}
else {
uint16_t BaseReg = Opnd->GetReg();
if (SignedOffset >= 0) // print plus sign
SMP_fprintf(OutFile, " [%s+%d]", MDGetRegNumName(BaseReg, RegSizes[BaseReg]), SignedOffset);
else // minus sign will print automatically
SMP_fprintf(OutFile, " [%s%d]", MDGetRegNumName(BaseReg, RegSizes[BaseReg]), SignedOffset);
}
}
else if (Opnd->IsRegOp()) {
clc5q
committed
SMP_fprintf(OutFile, " %s", MDGetRegName(Opnd));
}
else if (Opnd->IsImmedOp()) {
SMP_fprintf(OutFile, " %ld", (long) Opnd->GetImmedValue());
}
else if ((Opnd->IsFarPointer()) || (Opnd->IsNearPointer())) {
SMP_fprintf(OutFile, " %llx", (unsigned long long) Opnd->GetAddr());
}
else {
clc5q
committed
SMP_fprintf(OutFile, " ERROROP");
}
return;
} // end of AnnotPrintOperand()
// Print opcode string.
void PrintOpcode(uint16_t opcode, FILE *OutFile) {
switch (opcode) {
case STARS_NN_null: // Unknown Operation
case STARS_NN_aaa: // ASCII Adjust after Addition
case STARS_NN_aad: // ASCII Adjust AX before Division
case STARS_NN_aam: // ASCII Adjust AX after Multiply
case STARS_NN_aas: // ASCII Adjust AL after Subtraction
case STARS_NN_adc: // Add with Carry
SMP_fprintf(OutFile, "ERROR");
break;
case STARS_NN_add: // Add
SMP_fprintf(OutFile, "add");
break;
case STARS_NN_and: // Logical AND
SMP_fprintf(OutFile, "and");
break;
case STARS_NN_arpl: // Adjust RPL Field of Selector
case STARS_NN_bound: // Check Array Index Against Bounds
case STARS_NN_bsf: // Bit Scan Forward
case STARS_NN_bsr: // Bit Scan Reverse
case STARS_NN_bt: // Bit Test
case STARS_NN_btc: // Bit Test and Complement
case STARS_NN_btr: // Bit Test and Reset
case STARS_NN_bts: // Bit Test and Set
SMP_fprintf(OutFile, "ERROR");
break;
case STARS_NN_call: // Call Procedure
case STARS_NN_callfi: // Indirect Call Far Procedure
case STARS_NN_callni: // Indirect Call Near Procedure
SMP_fprintf(OutFile, "");
break;
case STARS_NN_cbw: // AL -> AX (with sign)
case STARS_NN_cwde: // AX -> EAX (with sign)