Newer
Older
/*
* SMPInstr.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 by Zephyr Software LLC
* e-mail: {clc,jwd}@zephyr-software.com
* URL : http://www.zephyr-software.com/
*
//
// SMPInstr.cpp
//
// This module performs the instruction level analyses needed for the
// SMP project (Software Memory Protection).
//
using namespace std;
#include <string>
#include <cstring>
#include <pro.h>
#include <assert.h>
#include <ida.hpp>
#include <idp.hpp>
#include <allins.hpp>
#include <auto.hpp>
#include <bytes.hpp>
#include <funcs.hpp>
#include <intel.hpp>
#include <loader.hpp>
#include <lines.hpp>
#include <name.hpp>
clc5q
committed
#include "SMPDBInterface.h"
#include "SMPStaticAnalyzer.h"
#include "SMPDataFlowAnalysis.h"
#include "SMPInstr.h"
#include "SMPProgram.h"
// Set to 1 for debugging output
#define SMP_DEBUG 1
#define SMP_DEBUG2 0 // verbose
#define SMP_DEBUG_XOR 0
#define SMP_DEBUG_BUILD_RTL 1 // should be left on, serious errors!
#define SMP_VERBOSE_DEBUG_BUILD_RTL 0
#define SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE 0
#define SMP_VERBOSE_DEBUG_INFER_TYPES 0
#define SMP_CALL_TRASHES_REGS 1 // Add DEFs of caller-saved regs to CALL instructions
#define SMP_BASEREG_POINTER_TYPE 1 // Initialize Base Register USEs to type POINTER?
#define SMP_OPTIMIZE_ADD_TO_NUMERIC 0 // optimizing annotation type -5
#define SMP_IDENTIFY_POINTER_ADDRESS_REG 0 // optimizing annotation POINTER
#define SMP_CHILDACCESS_ALL_CODE 0 // CHILDACCESS annotations for all funcs, or just analyzed funcs?
#define SPECIAL_CASE_CARRY_BORROW 0 // Treat sbb/adc different from sub/add annotations?
#define SMP_BUILD_SPECIAL_ADC_SBB_RTL 0 // Explicit RTL subtree for carry flag?
clc5q
committed
#define SMP_AGGRESSIVE_TYPE_INFERENCE 1 // Shorten iterations by quick propagation in InferOperatorType()
clc5q
committed
#define SMP_ANNOTATE_ALL_MEMORY_OPERANDS 0 // Info annotation for all memory read and write operands?
// Make the CF_CHG1 .. CF_CHG6 and CF_USE1..CF_USE6 macros more usable
// by allowing us to pick them up with an array index.
static ulong DefMacros[UA_MAXOP] = {CF_CHG1, CF_CHG2, CF_CHG3, CF_CHG4, CF_CHG5, CF_CHG6};
static ulong UseMacros[UA_MAXOP] = {CF_USE1, CF_USE2, CF_USE3, CF_USE4, CF_USE5, CF_USE6};
// Text to be printed in each optimizing annotation explaining why
// the annotation was emitted.
static const char *OptExplanation[LAST_TYPE_CATEGORY + 1] =
{ "NoOpt", "NoMetaUpdate", "AlwaysNUM", "NUMVia2ndSrcIMMEDNUM",
"Always1stSrc", "1stSrcVia2ndSrcIMMEDNUM", "AlwaysPtr",
"AlwaysNUM", "AlwaysNUM", "NUMViaFPRegDest", "NumericSources",
"StackMemoryTracking", "NumericSources", "NumericMemDest",
"NeverMemDest", "SafeIfNoIndexing"
static const char *OperatorText[LAST_SMP_OPERATOR + 1] =
{ "SMP_NULL_OPERATOR", "SMP_CALL", "SMP_INPUT", "SMP_OUTPUT", "SMP_ADDRESS_OF",
"SMP_U_LEFT_SHIFT", "SMP_S_LEFT_SHIFT", "SMP_U_RIGHT_SHIFT", "SMP_S_RIGHT_SHIFT",
"SMP_ROTATE_LEFT", "SMP_ROTATE_LEFT_CARRY", "SMP_ROTATE_RIGHT", "SMP_ROTATE_RIGHT_CARRY",
"SMP_DECREMENT", "SMP_INCREMENT",
"SMP_ADD", "SMP_ADD_CARRY", "SMP_SUBTRACT", "SMP_SUBTRACT_BORROW", "SMP_U_MULTIPLY",
"SMP_S_MULTIPLY", "SMP_U_DIVIDE", "SMP_S_DIVIDE", "SMP_U_REMAINDER",
"SMP_SIGN_EXTEND", "SMP_ZERO_EXTEND", "SMP_ASSIGN", "SMP_BITWISE_AND",
"SMP_BITWISE_OR", "SMP_BITWISE_NOT", "SMP_BITWISE_XOR", "SMP_BITWISE_AND_NOT", "SMP_NEGATE",
"SMP_S_COMPARE", "SMP_U_COMPARE", "SMP_LESS_THAN", "SMP_GREATER_THAN",
"SMP_LESS_EQUAL", "SMP_GREATER_EQUAL", "SMP_EQUAL", "SMP_NOT_EQUAL",
"SMP_LOGICAL_AND", "SMP_LOGICAL_OR", "SMP_UNARY_NUMERIC_OPERATION",
"SMP_BINARY_NUMERIC_OPERATION", "SMP_SYSTEM_OPERATION",
"SMP_UNARY_FLOATING_ARITHMETIC", "SMP_BINARY_FLOATING_ARITHMETIC",
"SMP_REVERSE_SHIFT_U", "SMP_SHUFFLE", "SMP_COMPARE_EQ_AND_SET",
"SMP_COMPARE_GT_AND_SET", "SMP_INTERLEAVE", "SMP_CONCATENATE"
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
// Does the CurrOperator definitely indicate a signed or unsigned operation?
bool OperatorHasSignedness(SMPoperator CurrOperator) {
bool DetectedSignedness;
switch (CurrOperator) {
case SMP_NULL_OPERATOR:
DetectedSignedness = false;
break;
case SMP_CALL: // CALL instruction
DetectedSignedness = true;
break;
case SMP_INPUT: // input from port
case SMP_OUTPUT: // output to port
case SMP_ADDRESS_OF: // take effective address
DetectedSignedness = false;
break;
case SMP_U_LEFT_SHIFT: // unsigned left shift
case SMP_U_RIGHT_SHIFT: // unsigned right shift
case SMP_ROTATE_LEFT:
case SMP_ROTATE_LEFT_CARRY: // rotate left through carry
case SMP_ROTATE_RIGHT:
case SMP_ROTATE_RIGHT_CARRY: // rotate right through carry
case SMP_U_MULTIPLY:
case SMP_U_DIVIDE:
case SMP_U_REMAINDER:
case SMP_ZERO_EXTEND:
case SMP_BITWISE_NOT: // unary operator
case SMP_BITWISE_XOR:
case SMP_BITWISE_AND_NOT:
case SMP_U_COMPARE: // unsigned compare (AND-based)
DetectedSignedness = true;
break;
case SMP_S_LEFT_SHIFT: // signed left shift
case SMP_S_RIGHT_SHIFT: // signed right shift
case SMP_S_MULTIPLY:
case SMP_S_DIVIDE:
case SMP_SIGN_EXTEND:
case SMP_NEGATE: // unary negation
case SMP_S_COMPARE: // signed compare (subtraction-based)
case SMP_LESS_THAN: // boolean test operators
case SMP_GREATER_THAN:
case SMP_LESS_EQUAL:
case SMP_GREATER_EQUAL:
DetectedSignedness = true;
break;
case SMP_DECREMENT:
case SMP_INCREMENT:
case SMP_ADD:
case SMP_ADD_CARRY: // add with carry
case SMP_SUBTRACT:
case SMP_SUBTRACT_BORROW: // subtract with borrow
case SMP_ASSIGN:
case SMP_BITWISE_AND:
case SMP_BITWISE_OR:
case SMP_EQUAL:
case SMP_NOT_EQUAL:
case SMP_LOGICAL_AND:
case SMP_LOGICAL_OR:
case SMP_UNARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result
case SMP_BINARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result
case SMP_SYSTEM_OPERATION: // for instructions such as CPUID, RDTSC, etc.; NUMERIC
DetectedSignedness = false;
break;
case SMP_UNARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC
case SMP_BINARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC
DetectedSignedness = true;
break;
case SMP_REVERSE_SHIFT_U: // Shift right operand by bit count in left operand
case SMP_SHUFFLE: // Shuffle bytes, words, etc. within destination operation per source mask
case SMP_COMPARE_EQ_AND_SET: // Compare for equality and set fields to all 1's or all 0's
case SMP_COMPARE_GT_AND_SET: // Compare for greater-than and set fields to all 1's or all 0's
case SMP_INTERLEAVE: // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC
case SMP_CONCATENATE: // extended-precision concatenation; NUMERIC
DetectedSignedness = true;
break;
default:
DetectedSignedness = false;
clc5q
committed
SMP_msg("ERROR: Unknown operator in OperatorHasSignedness: %d\n", CurrOperator);
break;
} // end switch on operator
return DetectedSignedness;
} // end of OperatorHasSignedness()
// *****************************************************************
// Class SMPGuard
// *****************************************************************
// Constructor
SMPGuard::SMPGuard(void) {
this->LeftOperand.type = o_void;
this->RightOperand.type = o_void;
this->GuardOp = SMP_NULL_OPERATOR;
// Debug print
void SMPGuard::Dump(void) {
clc5q
committed
SMP_msg("GUARD: ");
clc5q
committed
SMP_msg(" %s ", OperatorText[this->GuardOp]);
clc5q
committed
SMP_msg(":");
return;
} // end of SMPGuard::Dump()
// *****************************************************************
// Class SMPRegTransfer
// *****************************************************************
// Constructor
SMPRegTransfer::SMPRegTransfer(void) {
this->Guard = NULL;
this->LeftOperand.type = o_void;
this->RightOperand.type = o_void;
this->RTop.oper = SMP_NULL_OPERATOR;
this->RTop.NonSpeculativeType = UNINIT;
this->RightRT = NULL;
return;
}
// Destructor
SMPRegTransfer::~SMPRegTransfer() {
#if 0
clc5q
committed
SMP_msg("Destroying SMPRegTransfer.\n");
#endif
if (NULL != this->RightRT)
delete this->RightRT;
if (NULL != this->Guard)
delete this->Guard;
return;
}
// Debug print
void SMPRegTransfer::Dump(void) {
if (NULL != this->Guard)
this->Guard->Dump();
// Left operand
if (o_void != this->LeftOperand.type)
PrintOperand(this->LeftOperand);
// Then the operator
clc5q
committed
SMP_msg(" %s ", OperatorText[this->GetOperator()]);
// then the right operand or subtree
if (this->HasRightSubTree())
this->GetRightTree()->Dump();
else if (o_void != this->RightOperand.type)
PrintOperand(this->RightOperand);
return;
}
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
// *****************************************************************
// Class SMPRTL
// *****************************************************************
// Constructor
SMPRTL::SMPRTL() {
this->ExtraKills.clear();
this->RTCount = 0;
return;
}
// Destructor
SMPRTL::~SMPRTL() {
for (size_t index = 0; index < this->RTCount; ++index) {
delete (this->RTvector[index]);
}
this->ExtraKills.clear();
return;
}
// Get methods
SMPRegTransfer *SMPRTL::GetRT(size_t index) {
if (index > this->RTCount)
return NULL;
else
return this->RTvector[index];
}
// Set methods
void SMPRTL::push_back(SMPRegTransfer *NewEffect) {
assert(SMP_RT_LIMIT > this->RTCount);
this->RTvector[this->RTCount] = NewEffect;
++(this->RTCount);
return;
}
// Printing methods
void SMPRTL::Dump(void) {
size_t index;
if (0 < this->RTCount) {
clc5q
committed
SMP_msg("RTL: ");
for (index = 0; index < this->RTCount; ++index) {
this->RTvector[index]->Dump();
}
for (index = 0; index < this->ExtraKills.size(); ++index) {
clc5q
committed
SMP_msg(" KILL: ");
PrintOperand(this->ExtraKills.at(index));
}
clc5q
committed
SMP_msg("\n");
}
return;
} // end of SMPRTL::Dump()
// *****************************************************************
// Class SMPInstr
// *****************************************************************
// Constructor for instruction.
SMPInstr::SMPInstr(ea_t addr) {
this->ResetGoodRTL();
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
367
368
369
this->ResetJumpTarget();
this->ResetBlockTerm();
this->ResetTailCall();
this->ResetCondTailCall();
this->ResetCallUsedAsJump();
this->ResetDirectRecursiveCall();
this->ResetInterrupt();
#else
this->booleans1 = 0;
#endif
#if 0
this->ResetNop();
this->ResetRegClearIdiom();
this->ResetDefsFlags();
this->ResetUsesFlags();
this->ResetFarBranchComputed();
this->ResetBranchesToFarChunk();
this->ResetIndirectMemWrite();
this->ResetIndirectMemRead();
#else
this->booleans2 = 0;
#endif
#if 0
this->ResetLoadFromStack();
this->ResetMultiplicationBitsDiscarded();
this->ResetTypeInferenceComplete();
this->ResetCategoryInferenceComplete();
this->ResetDEFsTyped();
this->ResetUSEsTyped();
#else
this->booleans3 = 0;
#endif
this->DeadRegsString[0] = '\0';
this->CallTarget = BADADDR;
this->AddSubSourceType = UNINIT;
this->AddSubUseType = UNINIT;
clc5q
committed
this->AddSubSourceOp = InitOp;
this->AddSubUseOp = InitOp;
this->DEFMemOp = InitOp;
this->USEMemOp = InitOp;
this->LeaUSEMemOp = InitOp;
this->MoveSource = InitOp;
this->BasicBlock = NULL;
clc5q
committed
this->features = 0;
this->StackPtrOffset = 0;
clc5q
committed
this->type = DEFAULT;
this->OptType = 0;
this->Defs.clear();
this->Uses.clear();
clc5q
committed
// Destructor.
clc5q
committed
SMPInstr::~SMPInstr() {
this->Defs.clear();
this->Uses.clear();
clc5q
committed
return;
clc5q
committed
}
char *SMPInstr::GetDisasm(void) const {
return DisAsmText.GetDisAsm(this->GetAddr());
}
// Is the instruction the type that terminates a basic block?
bool SMPInstr::IsBasicBlockTerminator() const {
return ((type == JUMP) || (type == COND_BRANCH)
|| (type == INDIR_JUMP) || (type == RETURN));
}
// Get non-flags DEF, usually for arithmetic opcode.
set<DefOrUse, LessDefUse>::iterator SMPInstr::GetFirstNonFlagsDef(void) {
set<DefOrUse, LessDefUse>::iterator DefIter;
op_t DefOp;
for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
DefOp = DefIter->GetOp();
if (!((o_reg == DefOp.type) && DefOp.is_reg(MD_FLAGS_REG)))
break; // found a non-flags-reg DEF.
}
return DefIter;
}
// Is the destination operand a memory reference?
bool SMPInstr::HasDestMemoryOperand(void) {
} // end of SMPInstr::HasDestMemoryOperand()
// Is a source operand a memory reference?
bool SMPInstr::HasSourceMemoryOperand(void) {
} // end of SMPInstr::HasSourceMemoryOperand()
// Get the first memory operand in the DEF list.
op_t SMPInstr::MDGetMemDefOp(void) {
} // end of SMPInstr::MDGetMemDefOp()
// Get the first memory operand in the USE list.
op_t SMPInstr::MDGetMemUseOp(void) {
} // end of SMPInstr::MDGetMemUseOp()
clc5q
committed
// Does any USE have type NEGATEDPTR?
bool SMPInstr::HasNegatedPtrUSE(void) {
bool UseFound = false;
set<DefOrUse, LessDefUse>::iterator UseIter;
SMPOperandType UseType;
for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
UseType = UseIter->GetType();
if (IsEqType(UseType, NEGATEDPTR)) {
UseFound = true;
break;
}
}
return UseFound;
} // end of SMPInstr::HasNegatedPtrUSE()
// Detect indirect memory DEFs or USEs
void SMPInstr::AnalyzeIndirectRefs(bool UseFP) {
op_t DefMemOp = this->MDGetMemDefOp();
op_t UseMemOp = this->MDGetMemUseOp();
if (o_void != DefMemOp.type) {
// Found a memory DEF. Is it indirect?
if (MDIsIndirectMemoryOpnd(DefMemOp, UseFP)) {
this->SetIndirectMemWrite();
}
}
if (o_void != UseMemOp.type) {
// Found a memory USE. Is it indirect?
if (MDIsIndirectMemoryOpnd(UseMemOp, UseFP)) {
this->SetIndirectMemRead();
}
}
return;
} // end of SMPInstr::AnalyzeIndirectRefs()
set<DefOrUse, LessDefUse>::iterator SMPInstr::GetPointerAddressReg(op_t MemOp) {
int BaseReg;
int IndexReg;
ushort ScaleFactor;
ea_t displacement;
set<DefOrUse, LessDefUse>::iterator PtrIter;
if ((NULL == this->BasicBlock) || (NULL == this->BasicBlock->GetFunc())) {
clc5q
committed
SMP_msg("ERROR: NULL member pointers in SMPInstr::GetPointerAddressReg() at %x \n",
this->address);
return this->GetLastUse();
}
bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer();
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
MDExtractAddressFields(MemOp, BaseReg, IndexReg, ScaleFactor,
displacement);
if ((R_none != BaseReg) && (R_sp != BaseReg)
&& (!(UseFP && (R_bp == BaseReg)))) {
op_t BaseOp = InitOp;
BaseOp.type = o_reg;
BaseOp.reg = (ushort) BaseReg;
PtrIter = this->FindUse(BaseOp);
assert(PtrIter != this->GetLastUse());
if (IsDataPtr(PtrIter->GetType())) {
return PtrIter;
}
}
if ((R_none != IndexReg) && (R_sp != IndexReg)
&& (!(UseFP && (R_bp == IndexReg)))) {
op_t IndexOp = InitOp;
IndexOp.type = o_reg;
IndexOp.reg = (ushort) IndexReg;
PtrIter = this->FindUse(IndexOp);
assert(PtrIter != this->GetLastUse());
if (IsDataPtr(PtrIter->GetType())) {
return PtrIter;
}
}
PtrIter = this->GetLastUse();
return PtrIter;
} // end of SMPInstr::GetPointerAddressReg()
// Does the instruction whose flags are in F have a numeric type
// as the second source operand?
// NOTE: We can only analyze immediate values now. When data flow analyses are implemented,
// we will be able to analyze many non-immediate operands.
#define IMMEDNUM_LOWER -8191
#define IMMEDNUM_UPPER 8191
bool SMPInstr::IsSecondSrcOperandNumeric(flags_t F) const {
bool SecondOpImm = (this->SMPcmd.Operands[1].type == o_imm);
uval_t TempImm;
TempImm = this->SMPcmd.Operands[1].value;
return (SecondOpImm && IsImmedNumeric(TempImm));
} // end of SMPInstr::IsSecondSrcOperandNumeric()
// Determine the type of the USE-only operand for add and subtract
// instructions. If it is NUMERIC or PROF_NUMERIC, an optimizing
// annotation will result.
// As a byproduct, find the type of the USE/DEF operand as well.
void SMPInstr::SetAddSubSourceType(void) {
// Walk the RTL and find the operands we care about.
// The RTL should look like: opnd1 := (opnd1 op opnd2), where op is
// and add or subtract operator. Within the parentheses, the type
// of opnd1 is our AddSubUseType and opnd1 is our AddSubUseOp, while
// the type of opnd2 is our AddSubSourceType.
if (this->RTL.GetCount() < 1)
return; // no RTL, no leave types as UNINIT.
assert(this->RTL.GetRT(0)->HasRightSubTree());
SMPRegTransfer *RightTree = this->RTL.GetRT(0)->GetRightTree();
op_t LeftOp, RightOp;
LeftOp = RightTree->GetLeftOperand(); // Use (also DEF) operand
#if SMP_BUILD_SPECIAL_ADC_SBB_RTL
if ((NN_adc != this->SMPcmd.itype) && (NN_sbb != this->SMPcmd.itype)) {
assert(!(RightTree->HasRightSubTree()));
RightOp = RightTree->GetRightOperand(); // Src (non-DEF) operand
}
else {
// Add with carry and subtract with borrow have an extra level
// to the tree RTL, e.g. for add with carry:
// opnd1 := (opnd1 + (opnd2 + carryflag))
assert(RightTree->HasRightSubTree());
RightTree = RightTree->GetRightTree();
RightOp = RightTree->GetLeftOperand();
}
#else
assert(!(RightTree->HasRightSubTree()));
RightOp = RightTree->GetRightOperand(); // Src (non-DEF) operand
#endif
set<DefOrUse, LessDefUse>::iterator UseIter, SrcIter;
SrcIter = this->FindUse(RightOp);
assert(SrcIter != this->GetLastUse());
this->AddSubSourceType = SrcIter->GetType();
this->AddSubSourceOp = RightOp;
UseIter = this->FindUse(LeftOp);
assert(UseIter != this->GetLastUse());
this->AddSubUseType = UseIter->GetType();
this->AddSubUseOp = LeftOp;
return;
} // end of SMPInstr::SetAddSubSourceType()
// Are all DEFs in the DEF set NUMERIC type?
bool AllNumeric = (this->Defs.GetSize() > 0); // false if no DEFs, true otherwise
set<DefOrUse, LessDefUse>::iterator CurrDef;
for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
// We ignore the stack pointer for pop instructions and consider only
// the register DEF of the pop.
if (this->MDIsPopInstr() && CurrDef->GetOp().is_reg(R_sp))
continue;
clc5q
committed
AllNumeric = (AllNumeric && IsNumeric(CurrDef->GetType()));
}
return AllNumeric;
} // end of SMPInstr::AllDefsNumeric()
// Were the types of any DEFs derived from profiler info?
bool SMPInstr::AnyDefsProfiled(void)
{
bool profd = false;
set<DefOrUse, LessDefUse>::iterator CurrDef;
for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
profd = (profd || IsProfDerived(CurrDef->GetType()));
}
return profd;
}
// Do all DEFs have DEF_METADATA_UNUSED status?
bool SMPInstr::AllDefMetadataUnused(void) {
bool AllUnused = (this->Defs.GetSize() > 0); // false if no DEFs, true otherwise
set<DefOrUse, LessDefUse>::iterator CurrDef;
for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
AllUnused = (AllUnused
&& (DEF_METADATA_UNUSED == CurrDef->GetMetadataStatus()));
}
return AllUnused;
} // end of SMPInstr::AllDefMetadataUnused()
// DEBUG print operands for Inst.
void SMPInstr::PrintOperands(void) const {
op_t Opnd;
for (int i = 0; i < UA_MAXOP; ++i) {
Opnd = SMPcmd.Operands[i];
PrintOneOperand(Opnd, this->features, i);
}
clc5q
committed
SMP_msg(" \n");
return;
} // end of SMPInstr::PrintOperands()
// Complete DEBUG printing.
void SMPInstr::Dump(void) {
clc5q
committed
SMP_msg("%x %d SMPitype: %d %s\n", this->address, this->SMPcmd.size, (int) this->type,
DisAsmText.GetDisAsm(this->GetAddr()));
clc5q
committed
SMP_msg("USEs: ");
this->Uses.Dump();
clc5q
committed
SMP_msg("DEFs: ");
this->Defs.Dump();
this->RTL.Dump();
#if SMP_VERBOSE_DUMP
this->PrintOperands();
#endif
clc5q
committed
SMP_msg("\n");
return;
} // end of SMPInstr::Dump()
// Print out the destination operand list for the instruction, given
// the OptCategory for the instruction as a hint.
char * SMPInstr::DestString(int OptType) {
static char DestList[MAXSTR];
DestList[0] = 'Z'; // Make sure there are no leftovers from last call
DestList[1] = 'Z';
DestList[2] = '\0';
set<DefOrUse, LessDefUse>::iterator CurrDef;
for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
op_t DefOpnd = CurrDef->GetOp();
if (DefOpnd.is_reg(X86_FLAGS_REG)) // don't print flags as a destination
continue;
// We want to ignore the stack pointer DEF for pops and just include
// the register DEF for the pop.
if (DefOpnd.is_reg(R_sp) && this->MDIsPopInstr())
continue;
if (o_reg == DefOpnd.type) {
ushort DestReg = DefOpnd.reg;
if (0 == RegDestCount) {
clc5q
committed
SMP_strncpy(DestList, RegNames[DestReg], 1 + strlen(RegNames[DestReg]));
clc5q
committed
SMP_strncat(DestList, " ", MAXSTR);
SMP_strncat(DestList, RegNames[DestReg], MAXSTR);
}
++RegDestCount;
}
}
if (0 >= RegDestCount) {
clc5q
committed
SMP_msg("WARNING: No destination registers: %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
clc5q
committed
SMP_strncat(DestList, " ZZ ", MAXSTR);
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
}
return DestList;
} // end of SMPInstr::DestString()
// Equality operator for SMPInstr. Key field is address.
int SMPInstr::operator==(const SMPInstr &rhs) const {
if (this->address != rhs.GetAddr())
return 0;
else
return 1;
}
// Inequality operator for SMPInstr. Key field is address.
int SMPInstr::operator!=(const SMPInstr &rhs) const {
return (this->address != rhs.GetAddr());
}
// Less than operator for sorting SMPInstr lists. Key field is address.
int SMPInstr::operator<(const SMPInstr &rhs) const {
return (this->address < rhs.GetAddr());
}
// Less than or equal operator for sorting SMPInstr lists. Key field is address.
int SMPInstr::operator<=(const SMPInstr &rhs) const {
return (this->address <= rhs.GetAddr());
}
#define MD_FIRST_ENTER_INSTR NN_enterw
#define MD_LAST_ENTER_INSTR NN_enterq
// Is this instruction the one that allocates space on the
// stack for the local variables?
bool SMPInstr::MDIsFrameAllocInstr(void) {
// The frame allocating instruction should look like:
// sub esp,48 or add esp,-64 etc.
op_t ESPOp = InitOp;
ESPOp.type = o_reg;
ESPOp.reg = R_sp;
if ((SMPcmd.itype == NN_sub) || (SMPcmd.itype == NN_add)) {
if (this->GetLastDef() != this->Defs.FindRef(ESPOp)) {
// We know that an addition or subtraction is being
// performed on the stack pointer. This should not be
// possible within the prologue except at the stack
// frame allocation instruction, so return true. We
// could be more robust in this analysis in the future. **!!**
// CAUTION: If a compiler allocates 64 bytes for locals
// and 16 bytes for outgoing arguments in a single
// instruction: sub esp,80
// you cannot insist on finding sub esp,LocSize
// To make this more robust, we are going to insist that
// an allocation of stack space is either performed by
// adding a negative immediate value, or by subtracting
// a positive immediate value. We will throw in, free of
// charge, a subtraction of a register, which is how alloca()
// usually allocates stack space.
// PHASE ORDERING: Should we use the Operands[] instead of the USE list? **!!**
set<DefOrUse, LessDefUse>::iterator CurrUse;
for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) {
if (o_imm == CurrUse->GetOp().type) {
signed long TempImm = (signed long) CurrUse->GetOp().value;
if (((0 > TempImm) && (this->SMPcmd.itype == NN_add))
|| ((0 < TempImm) && (this->SMPcmd.itype == NN_sub))) {
return true;
}
}
else if ((o_reg == CurrUse->GetOp().type)
&& (!CurrUse->GetOp().is_reg(R_sp)) // skip the ESP operand
&& (this->SMPcmd.itype == NN_sub)) { // sub esp,reg: alloca() ?
return true;
}
}
}
}
else if ((this->SMPcmd.itype >= MD_FIRST_ENTER_INSTR)
&& (this->SMPcmd.itype <= MD_LAST_ENTER_INSTR)) {
return true;
}
return false;
} // end of SMPInstr::MDIsFrameAllocInstr()
#define MD_FIRST_LEAVE_INSTR NN_leavew
#define MD_LAST_LEAVE_INSTR NN_leaveq
// Is this instruction in the epilogue the one that deallocates the local
// vars region of the stack frame?
bool SMPInstr::MDIsFrameDeallocInstr(bool UseFP, asize_t LocalVarsSize) {
// The usual compiler idiom for the prologue on x86 is to
// deallocate the local var space with: mov esp,ebp
// It could be add esp,constant. We can be tricked by
// add esp,constant when the constant is just the stack
// adjustment after a call. We will have to insist that
// the immediate operand have at least the value of
// LocalVarsSize for this second form, and that UseFP be true
// for the first form.
set<DefOrUse, LessDefUse>::iterator FirstDef = this->GetFirstDef();
set<DefOrUse, LessDefUse>::iterator FirstUse = this->GetFirstUse();
if ((SMPcmd.itype >= MD_FIRST_LEAVE_INSTR) && (SMPcmd.itype <= MD_LAST_LEAVE_INSTR))
return true;
else if (this->HasDestMemoryOperand() || this->HasSourceMemoryOperand()) {
// Don't get fooled by USE or DEF entries of EBP or ESP that come
// from memory operands, e.g. mov eax,[ebp-20]
return false;
}
else if (UseFP && (this->SMPcmd.itype == NN_mov)
&& (FirstDef->GetOp().is_reg(R_sp))
&& (FirstUse->GetOp().is_reg(R_bp)))
return true;
else if ((this->SMPcmd.itype == NN_add)
&& (FirstDef->GetOp().is_reg(R_sp))) {
set<DefOrUse, LessDefUse>::iterator SecondUse = ++FirstUse;
if (SecondUse == this->Uses.GetLastRef())
return false; // no more USEs ... strange for ADD instruction
if (SecondUse->GetOp().is_imm((uval_t) LocalVarsSize))
return true;
else if (SecondUse->GetOp().type == o_imm) {
signed long TempImm = (signed long) this->SMPcmd.Operands[1].value;
if (0 > TempImm) // adding a negative to ESP; alloc, not dealloc
return false;
else {
clc5q
committed
SMP_msg("Used imprecise LocalVarsSize to find dealloc instr.\n");
return true;
}
}
else
return false;
}
else
return false;
} // end of SMPInstr::MDIsFrameDeallocInstr()
// Is instruction a no-op? There are 1-byte, 2-byte, etc., versions of no-ops.
bool SMPInstr::MDIsNop(void) const {
bool IsNop = false;
ushort opcode = this->SMPcmd.itype;
// NOTE: More examples have arisen, e.g. xchg reg with itself. !!!!!!
IsNop = true;
else if (NN_mov == opcode) {
if ((o_reg == this->SMPcmd.Operands[0].type)
&& this->SMPcmd.Operands[1].is_reg(this->SMPcmd.Operands[0].reg)) {
// We have a register to register move with source == destination.
IsNop = true;
}
}
else if (NN_lea == opcode) {
if ((o_reg == this->SMPcmd.Operands[0].type)
&& (o_displ == this->SMPcmd.Operands[1].type)
&& (0 == this->SMPcmd.Operands[1].addr)) {
// We are looking for 6-byte no-ops like lea esi,[esi+0]
ushort destreg = this->SMPcmd.Operands[0].reg;
if ((this->SMPcmd.Operands[1].hasSIB)
&& (destreg == (ushort) sib_base(this->SMPcmd.Operands[1]))
&& (R_sp == sib_index(this->SMPcmd.Operands[1]))) {
// R_sp signifies no SIB index register. So, we have
// lea reg,[reg+0] with reg being the same in both place,
// once as Operands[0] and once as the base reg in Operands[1].
IsNop = true;
}
else if (destreg == this->SMPcmd.Operands[1].reg) {
IsNop = true;
}
}
}
return IsNop;
} // end of SMPInstr::MDIsNop()
// Is non-multiply arithmetic instruction that can possibly overflow?
bool SMPInstr::MDIsOverflowingOpcode(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_adc == opcode) || (NN_add == opcode) || (NN_inc == opcode)
|| (NN_neg == opcode) || (NN_xadd == opcode));
}
// Is non-multiply arithmetic instruction that can possibly underflow?
bool SMPInstr::MDIsUnderflowingOpcode(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_dec == opcode) || (NN_sbb == opcode) || (NN_sub == opcode));
}
clc5q
committed
// Is potentially benign overflow instruction?
bool SMPInstr::MDIsMaybeBenignOverflowOpcode(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_adc == opcode) || (NN_add == opcode));
}
// Is potentially benign underflow instruction?
bool SMPInstr::MDIsMaybeBenignUnderflowOpcode(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_neg == opcode) || (NN_sbb == opcode) || (NN_sub == opcode));
}
clc5q
committed
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
// Is definitely benign underflow instruction?
// NOTE: Overlaps with MDIsMaybeBenignUnderflowOpcode(), so call this one first.
bool SMPInstr::MDIsDefiniteBenignUnderflowOpcode(void) {
unsigned short opcode = this->SMPcmd.itype;
// gcc use: sbb edx,edx as a tricky way to get all zeroes or all ones into edx.
// (Some sort of saturation?)
// The "underflow" on the subtraction is irrelevant and benign.
return ((NN_sbb == opcode) && (this->SubtractsFromItself()));
}
// Does a subtraction operator get applied to same left and right operands?
bool SMPInstr::SubtractsFromItself(void) {
bool SelfSubtract = false;
size_t RTLCount = this->RTL.GetCount();
for (size_t index = 0; index < RTLCount; ++index) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(index);
if ((CurrRT != NULL) && (CurrRT->HasRightSubTree())) {
CurrRT = CurrRT->GetRightTree();
SMPoperator CurrOp = CurrRT->GetOperator();
if ((SMP_SUBTRACT_BORROW == CurrOp) || (SMP_SUBTRACT == CurrOp)) {
if (!(CurrRT->HasRightSubTree())) {
// NOTE: Must change this code when we build more precise SMP_SUBTRACT_BORROW RTL.
op_t LeftOp = CurrRT->GetLeftOperand();
op_t RightOp = CurrRT->GetRightOperand();
SelfSubtract = IsEqOp(RightOp, LeftOp);
}
break;
}
}
}
return SelfSubtract;
} // end of SMPInstr::SubtractsFromItself()
// MACHINE DEPENDENT: Is instruction a return instruction?
bool SMPInstr::MDIsReturnInstr(void) const {
return ((this->SMPcmd.itype == NN_retn) || (this->SMPcmd.itype == NN_retf));
}
// MACHINE DEPENDENT: Is instruction a POP instruction?
#define FIRST_POP_INST NN_pop
#define LAST_POP_INST NN_popfq
bool SMPInstr::MDIsPopInstr(void) const {
return ((this->SMPcmd.itype >= FIRST_POP_INST)
&& (this->SMPcmd.itype <= LAST_POP_INST));
}
// MACHINE DEPENDENT: Is instruction a PUSH instruction?
#define FIRST_PUSH_INST NN_push
#define LAST_PUSH_INST NN_pushfq
bool SMPInstr::MDIsPushInstr(void) const {
return ((this->SMPcmd.itype >= FIRST_PUSH_INST)
&& (this->SMPcmd.itype <= LAST_PUSH_INST));
}
// MACHINE DEPENDENT: Is instruction an ENTER instruction?
bool SMPInstr::MDIsEnterInstr(void) const {
return ((this->SMPcmd.itype >= MD_FIRST_ENTER_INSTR)
&& (this->SMPcmd.itype <= MD_LAST_ENTER_INSTR));
}
// MACHINE DEPENDENT: Is instruction a LEAVE instruction?
bool SMPInstr::MDIsLeaveInstr(void) const {
return ((this->SMPcmd.itype >= MD_FIRST_LEAVE_INSTR)
&& (this->SMPcmd.itype <= MD_LAST_LEAVE_INSTR));
#define MD_FIRST_COND_MOVE_INSTR NN_cmova
#define MD_LAST_COND_MOVE_INSTR NN_fcmovnu
// MACHINE DEPENDENT: Is instruction a conditional move?
bool SMPInstr::MDIsConditionalMoveInstr(void) const {
return ((this->SMPcmd.itype >= MD_FIRST_COND_MOVE_INSTR)
&& (this->SMPcmd.itype <= MD_LAST_COND_MOVE_INSTR));
}
// MACHINE DEPENDENT: Do opcode/operands definitely indicate signed arithmetic?
// Generally, this is only true for certain variants of multiplication and division.
bool SMPInstr::MDIsSignedArithmetic(void) const {
unsigned short opcode = this->SMPcmd.itype;
if (NN_idiv == opcode)
return true;
if (NN_imul == opcode) {
// If we discard the upper N bits of the multiplication result, then the
// lower N bits are the same for signed and unsigned multiplication, and
// gcc/g++ often use the IMUL opcode for both signed and unsigned multiplies
// when only N bits of result are retained. Therefore, the SIGNED nature of
// IMUL operands can only be inferred from the case in which 2N bits are kept.
return (!(this->AreMultiplicationBitsDiscarded()));
}
else { // idiv and imul are only possible signed cases
return false;
}
} // end of SMPInstr::MDIsSignedArithmetic()
// MACHINE DEPENDENT: Is instruction a conditional jump based on an unsigned condition?
bool SMPInstr::MDIsUnsignedBranch(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_ja == opcode) || (NN_jae == opcode) || (NN_jb == opcode) || (NN_jbe == opcode)
|| (NN_jna == opcode) || (NN_jnae == opcode) || (NN_jnb == opcode) || (NN_jnbe == opcode));
}
// MACHINE DEPENDENT: Is instruction a conditional jump based on a signed condition?
bool SMPInstr::MDIsSignedBranch(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_jg == opcode) || (NN_jge == opcode) || (NN_jl == opcode) || (NN_jle == opcode)
|| (NN_jng == opcode) || (NN_jnge == opcode) || (NN_jnl == opcode) || (NN_jnle == opcode)
|| (NN_js == opcode) || (NN_jns == opcode));
}
// MACHINE DEPENDENT: Is instruction a boolean set based on an unsigned condition?
bool SMPInstr::MDIsUnsignedSetValue(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_seta == opcode) || (NN_setae == opcode) || (NN_setb == opcode) || (NN_setbe == opcode)
|| (NN_setna == opcode) || (NN_setnae == opcode) || (NN_setnb == opcode) || (NN_setnbe == opcode));
}
// MACHINE DEPENDENT: Is instruction a boolean set based on a signed condition?
bool SMPInstr::MDIsSignedSetValue(void) const {