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 <ua.hpp>
#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_PACK_SIGNED", "SMP_PACK_UNSIGNED",
"SMP_AVERAGE_UNSIGNED", "SMP_MULTIPLY_AND_ADD", "SMP_SUM_OF_DIFFS",
"SMP_MAX_S", "SMP_MAX_U", "SMP_MIN_S", "SMP_MIN_U", "SMP_ABS_VALUE",
"SMP_INTERLEAVE", "SMP_CONCATENATE"
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
// 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_PACK_S: // Pack operands into extended-precision register, signed saturation for loss of precision
case SMP_PACK_U: // Pack operands into extended-precision register, unsigned saturation for loss of precision
case SMP_AVERAGE_U: // Average of unsigned operands
case SMP_MULTIPLY_AND_ADD: // multiply and add (or multiply and accumulate)
case SMP_SUM_OF_DIFFS: // sum over two vectors of absolute values of differences of their elements
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;
}
266
267
268
269
270
271
272
273
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
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
// Compute operand-dependent change in stack pointer value.
sval_t SMPRegTransfer::ComputeStackPointerAlteration(bool IsLeaveInstr, asize_t LocalVarsSize) {
sval_t delta = 0;
// Search for the pattern: stack_pointer := ...
if (SMP_ASSIGN == this->GetOperator()) {
op_t DefOp = this->GetLeftOperand();
if (DefOp.is_reg(MD_STACK_POINTER_REG)) {
// We have the code pattern stack_pointer := ...
// We expect to find an overall RT structure of:
// stack_pointer := stack_pointer binaryoperator constant
// If the binaryoperator is addition or subtraction, then
// we use the constant to determine our return value.
// If the binaryoperator is a bitwise AND, then we return
// a special code. Delta is unknown but can probably be treated
// as zero, assuming that no stack-pointer-relative accesses to
// the stack region above the current stack pointer occur later.
// If we have a non-constant operand, we return an error code
// to indicate that we cannot compute the delta.
// If we don't have a binary operator, we return an error code,
// unless we find a stack frame deallocation: esp := ebp
if (!this->HasRightSubTree()) {
op_t UseOp = this->GetRightOperand();
if (UseOp.is_reg(MD_FRAME_POINTER_REG)) {
// Found esp := ebp (deallocation of stack frame)
delta = (sval_t) LocalVarsSize;
}
else {
delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
}
}
else {
SMPRegTransfer *RightRT = this->GetRightTree();
SMPoperator RightOperator = RightRT->GetOperator();
op_t RightDefOp = RightRT->GetLeftOperand();
if (IsLeaveInstr) {
// Found the RT esp := ebp + 4 that adjusts the stack pointer
// for an x86 LEAVE instruction. esp := ebp is equivalent
// to esp := esp + localvarssize, so delta becomes
// localvarssize + 4.
assert(SMP_ADD == RightOperator);
assert(!RightRT->HasRightSubTree());
assert(RightDefOp.is_reg(X86_FRAME_POINTER_REG));
delta = 4 + (sval_t) LocalVarsSize;
}
else if (!RightDefOp.is_reg(MD_STACK_POINTER_REG) || RightRT->HasRightSubTree()) {
// Not the right code pattern; unknown effect on stack pointer.
delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
}
else {
// We have stack_pointer := stack_pointer operator ...
op_t RightUseOp = RightRT->GetRightOperand();
// Check the operator
if (SMP_BITWISE_AND == RightOperator) {
delta = (sval_t) SMP_STACK_POINTER_BITWISE_AND_CODE;
}
else {
if (o_imm != RightUseOp.type) {
// Don't know how to deal with adding non-constant to stack pointer
delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
}
else if (SMP_ADD == RightOperator) {
delta = (sval_t) RightUseOp.value;
}
else if (SMP_SUBTRACT == RightOperator) {
delta = (0 - ((sval_t) RightUseOp.value));
}
else {
delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
}
}
}
}
}
}
return delta;
} // end of SMPRegTransfer::ComputeStackPointerAlteration()
// 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;
}
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
// *****************************************************************
// 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()
// Accumulate stack pointer alteration total across all RTs.
sval_t SMPRTL::TotalStackPointerAlteration(bool IsLeaveInstr, asize_t LocalVarsSize) {
sval_t TotalDelta = 0;
sval_t IncrementalDelta;
for (size_t index = 0; index < this->RTCount; ++index) {
IncrementalDelta = this->RTvector[index]->ComputeStackPointerAlteration(IsLeaveInstr, LocalVarsSize);
if ((SMP_STACK_DELTA_ERROR_CODE == IncrementalDelta)
|| (SMP_STACK_POINTER_BITWISE_AND_CODE == IncrementalDelta)) {
TotalDelta = IncrementalDelta; // pass code back
break; // exit loop and return coded value
}
else {
TotalDelta += IncrementalDelta;
}
}
return TotalDelta;
} // end of SMPRTL::TotalStackPointerAlteration()
// *****************************************************************
// Class SMPInstr
// *****************************************************************
// Constructor for instruction.
SMPInstr::SMPInstr(ea_t addr) {
this->ResetGoodRTL();
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
471
472
473
474
475
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();
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
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);
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
}
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
// 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()));
}