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 <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 STARS_DUMP_FG_INFO 1 // show signedness of DEFs and USEs in dump
#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?
#define SMP_AGGRESSIVE_SIGN_TRANSFER 1 // More transfer of signedness across instructions
#define STARS_NO_SHIFT_SIGNEDNESS_IN_SCALEFACTOR 0 // unsigned left shift for scale factors is really unknownsign multiply
// 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_GENERAL_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_NE_AND_SET", "SMP_COMPARE_GT_AND_SET",
"SMP_COMPARE_GE_AND_SET", "SMP_COMPARE_LT_AND_SET", "SMP_COMPARE_LE_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_CONVERT_INT_TO_FP", "SMP_CONVERT_FP_TO_INT", "SMP_CREATE_MASK",
"SMP_INTERLEAVE", "SMP_CONCATENATE", "SMP_EXTRACT_ZERO_EXTEND",
"SMP_ENCRYPTION_OPERATION", "SMP_SIGNAL"
#if 0
// 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
case SMP_GENERAL_COMPARE:
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
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
case SMP_SHUFFLE: // Shuffle bytes, words, etc. within destination operation per source mask
clc5q
committed
case SMP_SIGNAL: // signal or raise exception
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_COMPARE_EQ_AND_SET: // Compare for equality and set fields to all 1's or all 0's
case SMP_COMPARE_NE_AND_SET: // Compare for inequality 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_COMPARE_GE_AND_SET: // Compare for greater-than-or-equal and set fields to all 1's or all 0's
case SMP_COMPARE_LT_AND_SET: // Compare for less-than and set fields to all 1's or all 0's
case SMP_COMPARE_LE_AND_SET: // Compare for less-than-or-equal 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_MAX_S: // dest := signed_max(dest, src)
case SMP_MAX_U: // dest := unsigned_max(dest, src)
case SMP_MIN_S: // dest := signed_min(dest, src)
case SMP_MIN_U: // dest := unsigned_min(dest, src)
case SMP_ABSOLUTE_VALUE: // take absolute value
case SMP_CONVERT_INT_TO_FP: // convert integer to floating point
case SMP_CONVERT_FP_TO_INT: // convert floating point to integer
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()
#endif
// *****************************************************************
// Class SMPGuard
// *****************************************************************
// Constructor
SMPGuard::SMPGuard(void) {
this->LeftOperand.type = o_void;
this->RightOperand.type = o_void;
this->GuardOp = SMP_NULL_OPERATOR;
clc5q
committed
void SMPGuard::Dump(void) const {
clc5q
committed
SMP_msg("GUARD: ");
clc5q
committed
SMP_msg(" %s ", OperatorText[this->GuardOp]);
clc5q
committed
SMP_msg(":");
return;
} // end of SMPGuard::Dump()
// *****************************************************************
// Class SMPRegTransfer
// *****************************************************************
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->ParentInst = 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;
}
// Get the left operand, and normalize it if it is a stack operand.
op_t SMPRegTransfer::GetLeftOperand(void) const {
op_t TempOp = this->LeftOperand;
// AreDefsNormalized and AreUsesNormalized should always agree, but we
// use Defs for left operands and Uses for right operands, which is not
// strictly true, but there is no difference in results.
if (this->ParentInst->AreDefsNormalized()) {
ea_t InstAddr = this->ParentInst->GetAddr();
TempOp = this->ParentInst->GetBlock()->GetFunc()->GetNormalizedOperand(InstAddr, TempOp);
}
return TempOp;
} // end of SMPRegTransfer::GetLeftOperand()
// Get the right operand, and normalize it if it is a stack operand.
op_t SMPRegTransfer::GetRightOperand(void) const {
op_t TempOp = this->RightOperand;
if (this->ParentInst->AreDefsNormalized()) {
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
ea_t InstAddr = this->ParentInst->GetAddr();
TempOp = this->ParentInst->GetBlock()->GetFunc()->GetNormalizedOperand(InstAddr, TempOp);
}
return TempOp;
} // end of SMPRegTransfer::GetRightOperand()
// Does RTL subtract a non-immediate value from the stack pointer?
bool SMPRegTransfer::IsAllocaRTL(void) {
bool AllocaFound = false;
// Search for the pattern: stack_pointer := stack_pointer minus non-immediate
if ((SMP_ASSIGN == this->GetOperator()) && (this->HasRightSubTree())) {
op_t DefOp = this->GetLeftOperand();
if (DefOp.is_reg(MD_STACK_POINTER_REG)) {
// We have the code pattern stack_pointer := ...
SMPRegTransfer *RightRT = this->GetRightTree();
SMPoperator RightOperator = RightRT->GetOperator();
op_t RightDefOp = RightRT->GetLeftOperand();
if ((RightDefOp.is_reg(MD_STACK_POINTER_REG)) && (SMP_SUBTRACT == RightOperator)) {
// We have the code pattern stack_pointer := stack_pointer minus ...
if (RightRT->HasRightSubTree()) {
AllocaFound = true; // not an immediate rightop, whatever it is
}
else {
op_t RightUseOp = RightRT->GetRightOperand();
if (o_imm != RightUseOp.type) {
AllocaFound = true;
}
}
}
}
}
return AllocaFound;
} // end of SMPRegTransfer::IsAllocaRTL()
// Compute operand-dependent change in stack pointer value.
clc5q
committed
sval_t SMPRegTransfer::ComputeStackPointerAlteration(bool IsLeaveInstr, sval_t IncomingDelta, sval_t FramePtrDelta) {
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();
clc5q
committed
if (UseOp.is_reg(MD_FRAME_POINTER_REG)) { // !!!!****!!!! Should validate that frame pointer reg is used as frame pointer
// Found esp := ebp (deallocation of stack frame)
clc5q
committed
delta = FramePtrDelta - IncomingDelta;
assert(delta >= 0); // e.g. -4 - -12 => +8 for an 8-byte frame
clc5q
committed
// !!!!****!!!!**** Need to look up deltas for registers that
// were used to hold a copy of the stack pointer.
// For now, just consider it an error.
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
clc5q
committed
// to esp := <esp when frame ptr was set up>, so delta becomes
// <esp delta when frame ptr was set up> - IncomingDelta + 4.
assert(SMP_ADD == RightOperator);
assert(!RightRT->HasRightSubTree());
assert(RightDefOp.is_reg(X86_FRAME_POINTER_REG));
clc5q
committed
delta = 4 + FramePtrDelta - IncomingDelta;
clc5q
committed
else if (RightRT->HasRightSubTree()) {
// Not the right code pattern; unknown effect on stack pointer.
delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
}
clc5q
committed
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
else if (!RightDefOp.is_reg(MD_STACK_POINTER_REG)) {
// We have stack_pointer := something1 operator something2
// where something1 is not the stack_pointer. It might be
// the frame pointer, e.g. SP := FP-12. We can compute this
// stack delta because we know the delta when the FP was set up.
op_t RightUseOp = RightRT->GetRightOperand();
if (RightDefOp.is_reg(MD_FRAME_POINTER_REG) && (o_imm == RightUseOp.type)) {
// We have SP := FP operator immediate
delta = FramePtrDelta - IncomingDelta; // partial computation: SP := BP
assert(delta >= 0); // e.g. -4 - -12 => +8 for an 8-byte frame
if (SMP_ADD == RightOperator) {
delta += RightUseOp.value;
}
else if (SMP_SUBTRACT == RightOperator) {
delta -= RightUseOp.value;
}
else {
// Not the right code pattern; unknown effect on stack pointer.
delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
}
}
else {
// !!!!****!!!!**** Need to look up deltas for registers that
// were used to hold a copy of the stack pointer.
// For now, just consider it an error.
delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
}
}
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
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()
clc5q
committed
void SMPRegTransfer::Dump(void) const {
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;
}
// *****************************************************************
// 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
clc5q
committed
SMPRegTransfer *SMPRTL::GetRT(size_t index) const {
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;
}
clc5q
committed
void SMPRTL::Dump(void) const {
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.
clc5q
committed
sval_t SMPRTL::TotalStackPointerAlteration(bool IsLeaveInstr, sval_t IncomingDelta, sval_t FramePtrDelta) {
sval_t TotalDelta = 0;
sval_t IncrementalDelta;
for (size_t index = 0; index < this->RTCount; ++index) {
clc5q
committed
IncrementalDelta = this->RTvector[index]->ComputeStackPointerAlteration(IsLeaveInstr, IncomingDelta, FramePtrDelta);
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();
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
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->booleans4 = 0;
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.
clc5q
committed
op_t SMPInstr::MDGetMemDefOp(void) const {
} // end of SMPInstr::MDGetMemDefOp()
// Get the first memory operand in the USE list.
clc5q
committed
op_t SMPInstr::MDGetMemUseOp(void) const {
} // end of SMPInstr::MDGetMemUseOp()
// return BADADDR if not jump, target addr otherwise.
clc5q
committed
ea_t SMPInstr::GetJumpTarget(void) const {
ea_t TargetAddr = BADADDR;
if (this->HasGoodRTL()) {
// We want to find an RTL of the form: inst_ptr_reg := code_addr
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
op_t DefOp = CurrRT->GetLeftOperand();
if (DefOp.is_reg(MD_INSTRUCTION_POINTER_REG)) {
if ((SMP_ASSIGN == CurrRT->GetOperator()) && (!CurrRT->HasRightSubTree())) {
op_t UseOp = CurrRT->GetRightOperand();
if ((o_near == UseOp.type) || (o_far == UseOp.type)) { // address
TargetAddr = UseOp.addr;
}
}
}
}
return TargetAddr;
} // end SMPInstr::GetJumpTarget()
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();
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
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.
clc5q
committed
SMP_msg("%x %d SMPitype: %d %s\n", this->address, this->SMPcmd.size, (int) this->type,
DisAsmText.GetDisAsm(this->GetAddr()));
875
876
877
878
879
880
881
882
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
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
#if STARS_DUMP_FG_INFO
SMP_msg("USEs: ");
if (NULL == this->GetBlock()) { // during early improvement of disasm
this->Uses.Dump();
SMP_msg("DEFs: ");
this->Defs.Dump();
}
else {
set<DefOrUse, LessDefUse>::iterator UseIter, DefIter;
op_t UseOp, DefOp;
int UseHashValue, DefHashValue, UseSSANum, DefSSANum;
unsigned short SignMiscInfo, SignMask;
bool LocalName;
for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
UseIter->Dump();
UseOp = UseIter->GetOp();
if (o_reg == UseOp.type) {
LocalName = this->GetBlock()->IsLocalName(UseOp);
UseSSANum = UseIter->GetSSANum();
UseHashValue = HashGlobalNameAndSSA(UseOp, UseSSANum);
if (LocalName) {
SignMiscInfo = this->GetBlock()->GetUseSignMiscInfo(UseHashValue);
}
else {
SignMiscInfo = this->GetBlock()->GetFunc()->GetUseSignMiscInfo(UseHashValue);
}
SignMask = SignMiscInfo & FG_MASK_SIGNEDNESS_BITS;
if (SignMask == FG_MASK_SIGNED) {
SMP_msg(" Si ");
}
else if (SignMask == FG_MASK_UNSIGNED) {
SMP_msg(" Un ");
}
else if (SignMask == FG_MASK_INCONSISTENT_SIGN) {
SMP_msg(" Xs ");
}
}
SMP_msg("\n");
}
SMP_msg("DEFs: ");
for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
DefIter->Dump();
DefOp = DefIter->GetOp();
if (o_reg == DefOp.type) {
LocalName = this->GetBlock()->IsLocalName(DefOp);
DefSSANum = DefIter->GetSSANum();
DefHashValue = HashGlobalNameAndSSA(DefOp, DefSSANum);
if (LocalName) {
SignMiscInfo = this->GetBlock()->GetDefSignMiscInfo(DefHashValue);
}
else {
SignMiscInfo = this->GetBlock()->GetFunc()->GetDefSignMiscInfo(DefHashValue);
}
SignMask = SignMiscInfo & FG_MASK_SIGNEDNESS_BITS;
if (SignMask == FG_MASK_SIGNED) {
SMP_msg(" Si ");
}
else if (SignMask == FG_MASK_UNSIGNED) {
SMP_msg(" Un ");
}
else if (SignMask == FG_MASK_INCONSISTENT_SIGN) {
SMP_msg(" Xs ");
}
}
SMP_msg("\n");
}
}
#else
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);
}
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;
}