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",
"BND0", "BND1", "BND2", "BND3",
"XMM16", "XMM17", "XMM18", "XMM19", "XMM20", "XMM21", "XMM22", "XMM23",
"XMM24", "XMM25", "XMM26", "XMM27", "XMM28", "XMM29", "XMM30", "XMM31",
"YMM16", "YMM17", "YMM18", "YMM19", "YMM20", "YMM21", "YMM22", "YMM23",
"YMM24", "YMM25", "YMM26", "YMM27", "YMM28", "YMM29", "YMM30", "YMM31",
"XMM0", "XMM1", "XMM2", "XMM3", "XMM4", "XMM5", "XMM6", "XMM7",
"XMM8", "XMM9", "XMM10", "XMM11", "XMM12", "XMM13", "XMM14", "XMM15",
"ZMM16", "ZMM17", "ZMM18", "ZMM19", "ZMM20", "ZMM21", "ZMM22", "ZMM23",
"ZMM24", "ZMM25", "ZMM26", "ZMM27", "ZMM28", "ZMM29", "ZMM30", "ZMM31",
"K0", "K1", "K2", "K3", "K4", "K5", "K6", "K7",
// 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(STARS_regnum_t RegNum) {
assert(RegNum != ((STARS_regnum_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 *QDWordRegStrings[8] = { "R8D", "R9D", "R10D", "R11D", "R12D", "R13D", "R14D", "R15D" };
const char *QWWordRegStrings[8] = { "R8W", "R9W", "R10W", "R11W", "R12W", "R13W", "R14W", "R15W" };
const char *QByteRegStrings[8] = { "R8L", "R9L", "R10L", "R11L", "R12L", "R13L", "R14L", "R15L" };
const char *SignednessStrings[4] = { "UNKNOWNSIGN", "SIGNED", "UNSIGNED", "UNKNOWNSIGN" };
const char *LeaSignednessStrings[4] = { "NOFLAGUNKNOWNSIGN", "NOFLAGSIGNED", "NOFLAGUNSIGNED", "NOFLAGUNKNOWNSIGN" };
const char *SPARKFloatingPointStackRegNames[8] = { "FloatingPointStackDummy", "FloatingPointStackDummy1", "FloatingPointStackDummy1", "FloatingPointStackDummy1",
"FloatingPointStackDummy1", "FloatingPointStackDummy1", "FloatingPointStackDummy1", "FloatingPointStackDummy1" };
// Distinguishes subword regs from their parent regs
const char *MDGetRegNumName(STARS_regnum_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];
else if ((ByteWidth < 8) && (RegNum >= STARS_x86_R_r8) && (RegNum <= STARS_x86_R_r15)) {
if (ByteWidth == 4)
return QDWordRegStrings[RegNum - STARS_x86_R_r8];
else if (ByteWidth == 2)
return QWWordRegStrings[RegNum - STARS_x86_R_r8];
else if (ByteWidth == 1)
return QByteRegStrings[RegNum - STARS_x86_R_r8];
else
return ErrorStrings[0];
}
return RegNames[RegNum];
// Distinguishes subword regs from their parent regs, uses SPARK dummy names for FP stack.
const char *MDGetSPARKRegNumName(STARS_regnum_t RegNum, uint16_t ByteWidth) {
if ((RegNum >= STARS_x86_R_st0) && (RegNum <= STARS_x86_R_st7))
return SPARKFloatingPointStackRegNames[RegNum - STARS_x86_R_st0];
else
return MDGetRegNumName(RegNum, ByteWidth);
}
// Distinguishes subword regs from their parent regs
const char *MDGetRegName(const STARSOpndTypePtr &RegOp) {
if (!(RegOp->IsRegOp() || RegOp->IsFloatingPointRegOp()))
return ErrorStrings[0];
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) {
int HashValue = 0;
if (DefOp->IsRegOp()) {
HashValue = ((SSANum << 16) | ((int)(DefOp->GetReg())));
}
return HashValue;
}
// Hash a global name and SSA number into an int, for use in SMPFunction.GlobalDefAddrBySSA map
int64_t HashGlobalStackNameAndSSA(const STARSOpndTypePtr &DefOp, int SSANum, bool UseFP) {
int64_t HashValue = 0;
assert(MDIsDirectStackAccessOpnd(DefOp, UseFP));
HashValue = ((((int64_t) SSANum) << 32) | (((uint64_t)(DefOp->GetAddr())) & 0xffffffff));
// 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(STARS_regnum_t RegNum, bool Has64BitOpnds) {
assert(RegNum != ((STARS_regnum_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 = CurrOp->GetByteWidth();
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");
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
}
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.
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 (MDCanonicalizeSubReg(Opnd1->GetReg()) == MDCanonicalizeSubReg(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 STARS_regnum_t Reg1, const STARS_regnum_t Reg2) {
STARS_regnum_t SReg1 = MDCanonicalizeSubReg(Reg1);
STARS_regnum_t SReg2 = MDCanonicalizeSubReg(Reg2);
return (SReg1 < SReg2);
} // end of MDLessReg()
bool MDEqReg(const STARS_regnum_t Reg1, const STARS_regnum_t Reg2) {
STARS_regnum_t SReg1 = MDCanonicalizeSubReg(Reg1);
STARS_regnum_t SReg2 = MDCanonicalizeSubReg(Reg2);
return (SReg1 == SReg2);
} // end of MDEqReg()
bool MDLessRegOpnd(const STARSOpndTypePtr &RegOp1, const STARSOpndTypePtr &RegOp2) {
STARS_regnum_t SReg1 = MDCanonicalizeSubReg(RegOp1->GetReg());
STARS_regnum_t SReg2 = MDCanonicalizeSubReg(RegOp2->GetReg());
return ((SReg1 < SReg2) || ((SReg1 == SReg2) && (RegOp1->GetByteWidth() < RegOp2->GetByteWidth())));
} // end of MDLessRegOpnd()
STARS_regnum_t MDCanonicalizeSubReg(const STARS_regnum_t Reg1) {
bool Subword = ((Reg1 >= FIRST_X86_SUBWORD_REG) && (Reg1 <= LAST_X86_SUBWORD_REG));
if (Subword) {
// See enumeration RegNo in intel.hpp.
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
switch (SReg1) {
case STARS_x86_R_al:
case STARS_x86_R_ah:
SReg1 = STARS_x86_R_ax;
break;
case STARS_x86_R_cl:
case STARS_x86_R_ch:
SReg1 = STARS_x86_R_cx;
break;
case STARS_x86_R_dl:
case STARS_x86_R_dh:
SReg1 = STARS_x86_R_dx;
break;
case STARS_x86_R_bl:
case STARS_x86_R_bh:
SReg1 = STARS_x86_R_bx;
break;
case STARS_x86_R_spl:
SReg1 = STARS_x86_R_sp;
break;
case STARS_x86_R_bpl:
SReg1 = STARS_x86_R_bp;
break;
case STARS_x86_R_sil:
SReg1 = STARS_x86_R_si;
break;
case STARS_x86_R_dil:
SReg1 = STARS_x86_R_di;
break;
default:
assert(false);
} // end switch (SReg1)
return SReg1;
} // end of MDCanonicalizeSubReg()
#if 0
// If TempOp is a register, call MDCanonicalizeSubReg() on it.
void CanonicalizeOpnd(STARSOpndTypePtr &TempOp) {
if (TempOp->IsRegOp()) {
STARS_regnum_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 > TempOp->GetByteWidth()) {
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 && (!CurrOp->IsStaticMemOp()))
clc5q
committed
;
else
indirect = true;
}
if (0 != CurrOp->GetSIBScaleFactor())
clc5q
committed
indirect = true;
if (!indirect && (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
STARS_RegNo BaseReg = (STARS_RegNo) CurrOp->GetReg();
if (CurrOp->IsStaticMemOp()) { // no base register for o_mem
if (!((0 == BaseReg) || (MD_FRAME_POINTER_REG == BaseReg))) {
SMP_msg("ERROR: o_mem base reg %d ignored \n", BaseReg);
clc5q
committed
}
#endif
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 (MemOp->IsStaticMemOp()) {
BaseReg = STARS_x86_R_none;
// Only IndexReg is 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()
// MACHINE DEPENDENT: Does MemOp have both a base reg and an index reg, or a scaled index reg?
bool MDIsIndexedMemoryAccess(const STARSOpndTypePtr &MemOp) {
bool EIPRelativeAccess = (MemOp->HasSegReg() && (STARS_x86_R_cs == MemOp->GetSegReg()));
EIPRelativeAccess = (MemOp->GetReg() == STARS_x86_R_ip);
}
if (EIPRelativeAccess)
return true;
int BaseReg, IndexReg;
uint16_t Scale;
STARS_ea_t Offset;
MDExtractAddressFields(MemOp, BaseReg, IndexReg, Scale, Offset);
return ((Scale != 0) || ((BaseReg != STARS_x86_R_none) && (IndexReg != STARS_x86_R_none)));
}
// 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 R_none, access is direct.
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() && (STARS_x86_R_ip != CurrOp->GetReg())) || MDIsDirectStackAccessOpnd(CurrOp, UseFP)));
// MACHINE DEPENDENT: Is operand a caller-saved register?
bool MDIsCallerSavedReg(const STARSOpndTypePtr &CurrOp) {
if (! CurrOp->IsRegOp())
STARS_regnum_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) {
if ((nullptr != CurrOp) && 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, char OutString[STARS_MAXSTR], bool Has64BitOperands) {
int BaseReg;
int IndexReg;
uint16_t ScaleFactor;
uint16_t ByteWidth = Opnd->GetByteWidth();
STARS_ea_t offset;
char ScaleString[4];
if (Has64BitOperands)
ByteWidth = 8;
SMP_strncat(OutString, "[", STARS_MAXSTR - 1);
MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, offset);
if (ScaleFactor > 0) {
ScaleFactor = 1 << ScaleFactor;
(void) SMP_snprintf(ScaleString, 4, "%d", ScaleFactor);
}
if (BaseReg != STARS_x86_R_none) {
(void) SMP_strncat(OutString, MDGetRegNumName((STARS_regnum_t) BaseReg, ByteWidth), STARS_MAXSTR - 1);
if (IndexReg != STARS_x86_R_none) {
(void) SMP_strncat(OutString, "+", STARS_MAXSTR-1);
(void) SMP_strncat(OutString, MDGetRegNumName((STARS_regnum_t) IndexReg, ByteWidth), 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((STARS_regnum_t) IndexReg, ByteWidth), 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, STARS_regnum_t SegReg, bool UseFP, bool Has64BitOperands) {
int BaseReg;
int IndexReg;
uint16_t ScaleFactor;
uint16_t ByteWidth = Opnd->GetByteWidth();
STARS_ea_t offset;
char OutString[STARS_MAXSTR] = {'(', '\0'};
char ScaleString[4];
if (Has64BitOperands)
ByteWidth = 8;
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)) {
#if STARS_SPARK_EMIT_SEGMENT_REGS
(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) {
#if STARS_SPARK_EMIT_SEGMENT_REGS
(void) SMP_strncat(OutString, " + ", STARS_MAXSTR-1);
(void) SMP_strncat(OutString, "X86.", STARS_MAXSTR-1);
(void) SMP_strncat(OutString, MDGetRegNumName((STARS_regnum_t) BaseReg, ByteWidth), STARS_MAXSTR - 1);
if (global_STARS_program->GetSTARS_ISA_Bytewidth() > ByteWidth) {
++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((STARS_regnum_t) IndexReg, ByteWidth), STARS_MAXSTR - 1);
if (global_STARS_program->GetSTARS_ISA_Bytewidth() > ByteWidth) {
++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) {
#if STARS_SPARK_EMIT_SEGMENT_REGS
(void) SMP_strncat(OutString, " + ", STARS_MAXSTR-1);
(void) SMP_strncat(OutString, "X86.", STARS_MAXSTR-1);
(void) SMP_strncat(OutString, MDGetRegNumName((STARS_regnum_t) IndexReg, ByteWidth), STARS_MAXSTR - 1);
if (global_STARS_program->GetSTARS_ISA_Bytewidth() > ByteWidth) {
++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()
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
void SPARKAnnotSIBToString(const STARSOpndTypePtr &Opnd, bool HasOffset, std::string &OutString, STARS_regnum_t SegReg, bool UseFP, bool Has64BitOperands) {
int BaseReg;
int IndexReg;
uint16_t ScaleFactor;
uint16_t ByteWidth = Opnd->GetByteWidth();
STARS_ea_t offset;
char OutString2[STARS_MAXSTR] = { '(', '\0' };
char ScaleString[4];
if (Has64BitOperands)
ByteWidth = 8;
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)) {
SegRegPrefix = false;
}
#if STARS_SPARK_EMIT_SEGMENT_REGS
else {
(void)SMP_strncat(OutString2, "X86.", STARS_MAXSTR - 1);
(void)SMP_strncat(OutString2, MDGetRegNumName(SegReg, RegSizes[SegReg]), STARS_MAXSTR - 1);
}
#endif
}
if (ScaleFactor > 0) {
ScaleFactor = 1 << (ScaleFactor - 1);
(void) SMP_snprintf(ScaleString, 4, "%d", ScaleFactor);
}
if (BaseReg != STARS_x86_R_none) {
#if STARS_SPARK_EMIT_SEGMENT_REGS
if (SegRegPrefix) {
(void) SMP_strncat(OutString2, " + ", STARS_MAXSTR - 1);
}
#endif
(void) SMP_strncat(OutString2, "X86.", STARS_MAXSTR - 1);
(void) SMP_strncat(OutString2, MDGetRegNumName((STARS_regnum_t) BaseReg, ByteWidth), STARS_MAXSTR - 1);
if (global_STARS_program->GetSTARS_ISA_Bytewidth() > ByteWidth) {
++SubwordAddressRegCount;
}
if (IndexReg != STARS_x86_R_none) {
(void) SMP_strncat(OutString2, " + ", STARS_MAXSTR - 1);
(void) SMP_strncat(OutString2, "X86.", STARS_MAXSTR - 1);
(void) SMP_strncat(OutString2, MDGetRegNumName((STARS_regnum_t)IndexReg, ByteWidth), STARS_MAXSTR - 1);
if (global_STARS_program->GetSTARS_ISA_Bytewidth() > ByteWidth) {
++SubwordAddressRegCount;
}
if (ScaleFactor > 0) {
(void) SMP_strncat(OutString2, "*", STARS_MAXSTR - 1);
(void) SMP_strncat(OutString2, ScaleString, STARS_MAXSTR - 1);
}
}
}
else if (IndexReg != STARS_x86_R_none) {
#if STARS_SPARK_EMIT_SEGMENT_REGS
if (SegRegPrefix) {
(void) SMP_strncat(OutString2, " + ", STARS_MAXSTR - 1);
}
#endif
(void) SMP_strncat(OutString2, "X86.", STARS_MAXSTR - 1);
(void) SMP_strncat(OutString2, MDGetRegNumName((STARS_regnum_t)IndexReg, ByteWidth), STARS_MAXSTR - 1);
if (global_STARS_program->GetSTARS_ISA_Bytewidth() > ByteWidth) {
++SubwordAddressRegCount;
}
if (ScaleFactor > 0) {
(void) SMP_strncat(OutString2, "*", STARS_MAXSTR - 1);
(void) SMP_strncat(OutString2, ScaleString, STARS_MAXSTR - 1);
}
}
else if (!SegRegPrefix) {
SMP_msg("ERROR: No BaseReg, no IndexReg in SIB\n");
}
if (!HasOffset) // can close the parens around regs
(void) SMP_strncat(OutString2, ")", STARS_MAXSTR - 1);
OutString.assign(OutString2);
return;