Newer
Older
else if (RightNumeric) {
// pointer minus NUMERIC keeps same pointer type
CurrRT->SetOperatorType(LeftType, this);
updated = true;
}
}
else { // we have an operator type for the SMP_SUBTRACT
clc5q
committed
bool OperatorPointer = IsDataPtr(OperType);
if (CurrRT->HasRightSubTree()) {
// Must need to iterate through the right tree again, as the operator
// has been typed.
if (UNINIT == RightType) {
if (OperatorPointer) {
// PTR := PTR - ?? ==> ?? is NUMERIC
CurrRT->GetRightTree()->SetOperatorType(NUMERIC, this);
updated = true;
}
else if (OperType == PTROFFSET) {
clc5q
committed
// PTROFFSET := PTR - ?? ==> ?? is PTR
CurrRT->GetRightTree()->SetOperatorType(LeftType, this);
updated = true;
}
}
updated |= this->InferOperatorType(CurrRT->GetRightTree());
break;
}
else { // right operand; propagate operator type if needed
if (UNINIT == RightType) {
if (OperatorPointer) {
// PTR := PTR - ?? ==> ?? is NUMERIC
RightUse = this->SetUseType(RightOp, NUMERIC);
updated = true;
assert(RightUse != this->GetLastUse());
}
else if (OperType == PTROFFSET) {
// PTROFFSET := PTR - ?? ==> ?? is PTR
RightUse = this->SetUseType(RightOp, LeftType);
updated = true;
}
break;
}
}
} // end if OperType is UNINIT ... else ...
} // end if LeftNumeric ... else if LeftPointer ...
else if (UNINIT == LeftType) {
// We make add-with-carry and subtract-with-borrow exceptions
// to the type propagation. LeftOp could have POINTER type
// inferred later; these instructions can change the type of
// the register from POINTER to NUMERIC, unlike regular
// add and subtract opcodes.
if ((UNINIT != OperType)
&& (SMP_SUBTRACT_BORROW != CurrOp)) {
LeftUse = this->SetUseType(LeftOp, OperType);
assert(LeftUse != this->GetLastUse());
updated = true;
}
}
break;
// Extract the current types of right and left operands and SMP_ASSIGN operator.
OperType = CurrRT->GetOperatorType();
DefOp = CurrRT->GetLeftOperand();
CurrDef = this->Defs.FindRef(DefOp);
assert(CurrDef != this->GetLastDef()); // found it
LeftType = CurrDef->GetType();
if (CurrRT->HasRightSubTree()) {
RightType = CurrRT->GetRightTree()->GetOperatorType();
}
else {
UseOp = CurrRT->GetRightOperand();
if (o_void == UseOp.type) {
msg("ERROR: void operand for SMP_ASSIGN in %s\n", this->GetDisasm());
return false;
}
else {
CurrUse = this->Uses.FindRef(UseOp);
if (CurrUse == this->GetLastUse()) {
msg("WARNING: Adding missing USE of ");
PrintOperand(UseOp);
msg(" in %s\n", this->GetDisasm());
this->Uses.SetRef(UseOp);
updated = true;
}
// We keep it simple by only trying to propagate one step at a time, from
// the right operand or tree up to the SMP_ASSIGN operator, then from
// the operator to the left (DEF) operand, or from left up to operator
// and down the right, depending on where the existing types are.
if (DebugFlag) {
msg("%x LeftType: %d OperatorType: %d RightType: %d\n", this->address, LeftType,
OperType, RightType);
}
if ((UNINIT == RightType) && (UNINIT == LeftType)) {
// We will only try to solve the right hand side on this iteration.
if (CurrRT->HasRightSubTree()) {
updated |= this->InferOperatorType(CurrRT->GetRightTree());
else if (UNINIT == OperType) {
// UNINIT SMP_ASSIGN operator, but either LeftType or RightType is not UNINIT.
if (UNINIT != RightType) {
// We have to special case conditional moves. Only if both operands
// (the source and the prior value of the potential destination,
// which was added to the USE set by BuildMoveRTL()) agree in type
// can we propagate their common type to the operator and ultimately
// to the DEF.
if ((!this->MDIsConditionalMoveInstr()) || this->Uses.TypesAgreeNoFlags()) {
CurrRT->SetOperatorType(RightType, this);
updated = true;
}
}
else {
CurrRT->SetOperatorType(LeftType, this);
updated = true;
}
break;
}
else if (UNINIT == LeftType) {
// SMP_ASSIGN operator has type, so propagate it.
LeftType = OperType;
CurrDef = this->SetDefType(DefOp, OperType);
// Propagate the new DEF type unless it is an indirect memory access.
// Future: Propagate until re-DEF of addressing register terminates
// the propagation. **!!**
if (!MDIsIndirectMemoryOpnd(DefOp, this->BasicBlock->GetFunc()->UsesFramePointer())) {
bool IsMemOp = (o_reg != DefOp.type);
bool MemPropagate = MDIsStackAccessOpnd(DefOp, UseFP);
#if SMP_PROPAGATE_MEM_TYPES
;
#else
clc5q
committed
// Be conservative and only propagate register DEFs and SAFE stack locs.
// We can improve this in the future. **!!**
MemPropagate = MemPropagate && SafeFunc;
#endif
if ((o_reg == DefOp.type) || MemPropagate) {
clc5q
committed
int SSANum = CurrDef->GetSSANum();
if (this->BasicBlock->IsLocalName(DefOp)) {
(void) this->BasicBlock->PropagateLocalDefType(DefOp, LeftType,
this->GetAddr(), SSANum, IsMemOp);
}
else { // global name
this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
(void) this->BasicBlock->PropagateGlobalDefType(DefOp, LeftType,
SSANum, IsMemOp);
}
}
}
break;
}
else if (UNINIT == RightType) {
// SMP_ASSIGN operator has type, so propagate it.
if (CurrRT->HasRightSubTree()) {
CurrRT->GetRightTree()->SetOperatorType(OperType, this);
updated = true;
updated |= this->InferOperatorType(CurrRT->GetRightTree());
}
else {
// For conditional moves, propagate to the pseudo-USE of the
// destination register as well as the source operand.
if (this->MDIsConditionalMoveInstr()) {
CurrUse = this->FindUse(DefOp);
assert(CurrUse != this->GetLastUse());
if (UNINIT == CurrUse->GetType())
CurrUse = this->SetUseType(DefOp, OperType);
else if (OperType != CurrUse->GetType()) {
msg("WARNING: Avoiding lattice oscillation from type %d to %d at %x for: ",
CurrUse->GetType(), OperType, this->address);
PrintOperand(CurrUse->GetOp());
msg("\n");
}
}
CurrUse = this->SetUseType(UseOp, OperType);
updated = true;
msg("ERROR: Unknown operator in %s\n", this->GetDisasm());
break;
} // end switch on operator
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
// Determine if type inference is finished for this register transfer.
if (updated && (!TypeInferenceFinished)) {
bool FinishedRight = false;
bool FinishedLeft = false;
bool FinishedOperator = (CurrRT->GetOperatorType() != UNINIT);
if (FinishedOperator) {
switch (CurrOp) {
case SMP_INPUT: // input from port
case SMP_OUTPUT: // output to port
case SMP_SIGN_EXTEND:
case SMP_ZERO_EXTEND:
case SMP_ADDRESS_OF: // take effective address
case SMP_SYSTEM_OPERATION: // for instructions such as CPUID, RDTSC, etc.; NUMERIC
case SMP_BITWISE_NOT: // unary operator
case SMP_NEGATE: // unary negation
case SMP_DECREMENT:
case SMP_INCREMENT:
case SMP_UNARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result
case SMP_UNARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC
// Unary operators have no right operand.
FinishedRight = true;
break;
default: // All binary operators come here
if (CurrRT->HasRightSubTree()) {
FinishedRight = CurrRT->GetRightTree()->IsTypeInferenceComplete();
}
else {
UseOp = CurrRT->GetRightOperand();
if (UseOp.type != o_void) {
CurrUse = this->Uses.FindRef(UseOp);
assert(CurrUse != this->GetLastUse());
FinishedRight = (CurrUse->GetType() != UNINIT);
}
else { // if o_void, no further type inference on it is possible.
FinishedRight = true;
}
}
if (FinishedRight) { // no point checking left op if right op is not finished
DefOp = CurrRT->GetLeftOperand();
if (DefOp.type != o_void) {
if (SMP_ASSIGN == CurrOp) {
CurrDef = this->Defs.FindRef(DefOp);
assert(CurrDef != this->GetLastDef());
FinishedLeft = (CurrDef->GetType() != UNINIT);
}
else { // not ASSIGN, so really a UseOp not DefOp
CurrUse = this->Uses.FindRef(DefOp);
assert(CurrUse != this->GetLastUse());
FinishedLeft = (CurrUse->GetType() != UNINIT);
}
}
else { // if o_void, no further type inference on it is possible.
FinishedLeft = true;
}
}
break;
} // end switch on CurrOp
TypeInferenceFinished = (FinishedLeft && FinishedRight);
} // end if (FinishedOperator)
} // end if (updated && (!TypeInferenceFinished))
if (TypeInferenceFinished) {
CurrRT->SetTypeInferenceComplete();
}
return updated;
} // end of SMPInstr::InferOperatorType()
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
// Transfer function: Does operator propagate signedness of its operands to its result?
bool SMPInstr::DoesOperatorTransferSign(SMPoperator CurrOp) {
bool transfer = false;
switch (CurrOp) {
case SMP_NULL_OPERATOR:
case SMP_CALL: // CALL instruction
case SMP_INPUT: // input from port
case SMP_OUTPUT: // output to port
case SMP_SYSTEM_OPERATION: // for instructions such as CPUID, RDTSC, etc.; NUMERIC
// No concept of signedness for some operators
break;
case SMP_ADDRESS_OF: // take effective address
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)
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:
// Inherently unsigned and signed operators force the signedness
// of their results, rather than propagating the signedness of
// their operands.
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
transfer = true;
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
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
transfer = true;
break;
default:
msg("ERROR: Unknown operator in %s\n", this->GetDisasm());
break;
} // end switch on operator
return transfer;
} // end of SMPInstr::DoesOperatorTransferSign()
// Initial inferences (if any) about FG info of operand based solely on the RTL operator type above it in RTL.
bool SMPInstr::InitFGInfoFromOperator(SMPoperator CurrOp, struct FineGrainedInfo &InitFG) {
bool changed = false;
switch (CurrOp) {
case SMP_NULL_OPERATOR:
break;
case SMP_CALL: // CALL instruction
InitFG.SignMiscInfo |= FG_MASK_UNSIGNED; // target address is unsigned 32-bit
InitFG.SizeInfo |= (MD_NORMAL_BITWIDTH_MASK | FG_MASK_CODEPOINTER);
changed = true;
break;
case SMP_INPUT: // input from port
case SMP_OUTPUT: // output to port
case SMP_ADDRESS_OF: // take effective address
case SMP_U_COMPARE: // unsigned compare (AND-based)
case SMP_S_COMPARE: // signed compare (subtraction-based)
// NOTE: The AND-based and subtraction-based comparisons are used
// on lots of operands of all types, and the conditional jump that
// follows determines signedness, not the operator.
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:
InitFG.SignMiscInfo |= FG_MASK_UNSIGNED;
changed = 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_LESS_THAN: // boolean test operators
case SMP_GREATER_THAN:
case SMP_LESS_EQUAL:
case SMP_GREATER_EQUAL:
// Special case: If signed multiply operator, it might sometimes
// be used for unsigned operands when upper bits of the result
// are discarded, because there is no difference in the result bits
// between unsigned and signed multiplcation when only the lower
// N bits are retained and the upper N bits are discarded.
if ((SMP_S_MULTIPLY == CurrOp) && (!(this->MDIsSignedArithmetic()))) {
break;
}
InitFG.SignMiscInfo |= FG_MASK_SIGNED;
changed = true;
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
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
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
InitFG.SignMiscInfo |= FG_MASK_SIGNED;
InitFG.SizeInfo |= FG_MASK_FLOAT_MMX;
changed = 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
InitFG.SignMiscInfo |= FG_MASK_SIGNED;
InitFG.SizeInfo |= (FG_MASK_FLOAT_MMX | FG_MASK_BITWIDTH_128);
changed = true;
break;
default:
msg("ERROR: Unknown operator in %s\n", this->GetDisasm());
break;
} // end switch on operator
return changed;
} // end of SMPInstr::InitFGInfoFromOperator()
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
// Helper to take USE operand, find its SSANum, and return its UseHashValue.
int SMPInstr::GetUseOpHashAndSSA(op_t UseOp, int &SSANum) {
op_t SearchOp = UseOp;
SearchOp.reg = MDCanonicalizeSubReg(UseOp.reg);
set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(SearchOp);
assert(UseIter != this->GetLastUse());
SSANum = UseIter->GetSSANum();
int UseHashValue = HashGlobalNameAndSSA(SearchOp, SSANum);
return UseHashValue;
} // end of SMPInstr::GetUseOpHashAndSSA()
// Helper to take DEF operand, find its SSANum, and return its DefHashValue.
int SMPInstr::GetDefOpHashAndSSA(op_t DefOp, int &SSANum) {
op_t SearchOp = DefOp;
SearchOp.reg = MDCanonicalizeSubReg(DefOp.reg);
set<DefOrUse, LessDefUse>::iterator DefIter = this->FindDef(SearchOp);
assert(DefIter != this->GetLastDef());
SSANum = DefIter->GetSSANum();
int DefHashValue = HashGlobalNameAndSSA(SearchOp, SSANum);
return DefHashValue;
} // end of SMPInstr::GetDefOpHashAndSSA()
// helper for InferOperatorFGInfo() to update DEF maps, return true if changed maps
bool SMPInstr::UpdateDefOpFGInfo(op_t DefOp, struct FineGrainedInfo NewFG) {
bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
set<DefOrUse, LessDefUse>::iterator DefIter;
int SSANum;
int DefHashValue;
op_t SearchOp;
bool LocalName;
struct FineGrainedInfo OldFG, UnionFG;
// If operator is inherently signed, then we will have
// a sign bit set in NewFG from InitFGInfoFromOperator().
DefHashValue = this->GetDefOpHashAndSSA(DefOp, SSANum);
LocalName = this->BasicBlock->IsLocalName(DefOp);
if (LocalName) {
// Get old FG info from block level.
OldFG = this->BasicBlock->GetDefFGInfo(DefHashValue);
}
else { // global name
// Get old FG info from function level.
OldFG = this->BasicBlock->GetFunc()->GetDefFGInfo(DefHashValue);
}
UnionFG.SignMiscInfo = OldFG.SignMiscInfo | NewFG.SignMiscInfo;
UnionFG.SizeInfo = OldFG.SizeInfo | NewFG.SizeInfo;
if ((OldFG.SignMiscInfo != UnionFG.SignMiscInfo) || (OldFG.SizeInfo != UnionFG.SizeInfo)) {
// The signs they are a-changin'.
MapsChanged = true;
if (LocalName)
this->BasicBlock->UpdateDefFGInfo(DefHashValue, UnionFG);
this->BasicBlock->GetFunc()->UpdateDefFGInfo(DefHashValue, UnionFG);
}
return MapsChanged;
} // end of SMPInstr::UpdateDefOpFGInfo()
// helper for InferOperatorFGInfo() to update USE maps, return true if changed maps
bool SMPInstr::UpdateUseOpFGInfo(op_t UseOp, struct FineGrainedInfo NewFG) {
bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
int SSANum;
int UseHashValue;
bool LocalName;
struct FineGrainedInfo OldFG, UnionFG;
// If operator is inherently signed, then we will have
// a sign bit set in NewFG from InitFGInfoFromOperator().
UseHashValue = this->GetUseOpHashAndSSA(UseOp, SSANum);
LocalName = this->BasicBlock->IsLocalName(UseOp);
if (LocalName) {
// Get old FG info from block level.
OldFG = this->BasicBlock->GetUseFGInfo(UseHashValue);
}
else { // global name
// Get old FG info from function level.
OldFG = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue);
}
UnionFG.SignMiscInfo = OldFG.SignMiscInfo | NewFG.SignMiscInfo;
UnionFG.SizeInfo = OldFG.SizeInfo | NewFG.SizeInfo;
if ((OldFG.SignMiscInfo != UnionFG.SignMiscInfo) || (OldFG.SizeInfo != UnionFG.SizeInfo)) {
// The signs they are a-changin'.
MapsChanged = true;
if (LocalName)
this->BasicBlock->UpdateUseFGInfo(UseHashValue, UnionFG);
this->BasicBlock->GetFunc()->UpdateUseFGInfo(UseHashValue, UnionFG);
}
return MapsChanged;
} // end of SMPInstr::UpdateUseOpFGInfo()
// Helper to fetch DEF signedness info for UseOp that has none.
unsigned short SMPInstr::GetDefSignInfoFromUseOp(op_t UseOp) {
int SSANum, UseHashValue;
bool LocalName;
UseHashValue = this->GetUseOpHashAndSSA(UseOp, SSANum);
LocalName = this->BasicBlock->IsLocalName(UseOp);
if (LocalName) {
// Get old sign info from block level.
return this->BasicBlock->GetDefSignMiscInfo(UseHashValue);
}
else { // global name
// Get old sign info from function level.
return this->BasicBlock->GetFunc()->GetDefSignMiscInfo(UseHashValue);
}
} // end of SMPInstr::GetDefSignInfoFromUseOp()
// infer FG info, + width on FirstIter; pass out FG info for op subtree, return true if change made to any FG info map.
bool SMPInstr::InferOperatorFGInfo(SMPRegTransfer *CurrRT, bool FirstIter, struct FineGrainedInfo &OpFG) {
bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
bool NewChange = false; // Bit changes from InitFGInfoFromOperator() ?
SMPoperator CurrOp = CurrRT->GetOperator();
struct FineGrainedInfo LeftFG, OldLeftFG;
struct FineGrainedInfo RightFG, OldRightFG;
op_t LeftOp, RightOp;
unsigned short WidthMask, SignMask;
bool CurrOpTransfersSign = this->DoesOperatorTransferSign(CurrOp);
bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer();
bool success;
int DefHashValue, UseHashValue, SSANum;
// Recurse to the right first, so we can do a depth-first accumulation of FG info.
RightFG.SignMiscInfo = 0;
RightFG.SizeInfo = 0;
if (CurrRT->HasRightSubTree()) {
if (FirstIter) { // Get width as well as signedness
NewChange = this->InitFGInfoFromOperator(CurrOp, RightFG);
} // end if (FirstIter)
MapsChanged |= this->InferOperatorFGInfo(CurrRT->GetRightTree(), FirstIter, RightFG);
}
else {
RightOp = CurrRT->GetRightOperand();
if ((RightOp.type == o_reg) && !RightOp.is_reg(MD_INSTRUCTION_POINTER_REG)) {
if (FirstIter) { // Get width as well as signedness
NewChange = this->InitFGInfoFromOperator(CurrOp, RightFG);
WidthMask = ComputeOperandBitWidthMask(RightOp, 0);
RightFG.SizeInfo |= WidthMask;
} // end if (FirstIter)
#define SMP_AGGRESSIVE_SIGN_TRANSFER 1
#if SMP_AGGRESSIVE_SIGN_TRANSFER
else {
// On all iterations other than 1st, see if USE has FG info.
UseHashValue = this->GetUseOpHashAndSSA(RightOp, SSANum);
if (this->BasicBlock->IsLocalName(RightOp)) {
// Get FG info from block.
RightFG = this->BasicBlock->GetUseFGInfo(UseHashValue);
}
else {
// Get FG info from function level.
RightFG = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue);
}
}
#endif
// Propagate signedness on all iterations.
// If operator is inherently signed, then we will have
// a sign bit set in RightFG from InitFGInfoFromOperator().
if ((RightFG.SignMiscInfo == 0) && CurrOpTransfersSign) {
// We have a USE with no sign info. See if we
// can get sign info from the DEF of this USE so we can
// transfer it up the RTL tree.
RightFG.SignMiscInfo =
(FG_MASK_SIGNEDNESS_BITS & (this->GetDefSignInfoFromUseOp(RightOp)));
}
if ((RightFG.SignMiscInfo != 0) || (RightFG.SizeInfo != 0))
MapsChanged |= this->UpdateUseOpFGInfo(RightOp, RightFG);
} // end if (RightOP is o_reg)
else if (MDIsStackAccessOpnd(RightOp, UseFP)) {
// We used to assume that all FG info transfers from stack locations to
// the target registers of stack loads happened in SMPInstr::MDSetWidthSignInfo(),
// in an early pass that needed no iteration. The FG info was loaded from the
// StackFGInfo that was computed in SMPFunction::FindOutgoingArgsSize() based solely
// on whether the load was sign-extended or zero-extended. Of course, many stack
// locations have neither kind of signed/unsigned load. So, if we see a store to
// a stack location with no signedness, we transfer the signedness of the RightFG
// to the stack location FGInfo in the code below that processes the LeftOp.
// As a result, we now have a need to examine regular loads from the stack to
// see if there is signedness info for the stack location.
success = this->BasicBlock->GetFunc()->MDGetFGStackLocInfo(this->address, RightOp, RightFG);
if (success) {
SignMask = (RightFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
RightFG.SizeInfo = 0; // only want to transfer signedness
}
}
} // end if (right subtree) else right operand
LeftFG.SignMiscInfo = 0;
LeftFG.SizeInfo = 0;
LeftOp = CurrRT->GetLeftOperand();
bool OpIsDEF = (SMP_ASSIGN == CurrOp);
// Skip control-flow assignments to the instruction pointer register.
if ((LeftOp.type == o_reg) && !LeftOp.is_reg(MD_INSTRUCTION_POINTER_REG)) {
if (FirstIter) { // Get width as well as signedness
NewChange = this->InitFGInfoFromOperator(CurrOp, LeftFG);
// Special case: For sign-extended and zero-extended loads,
// we don't know whether the DEF will always be USEd as
// the smaller or larger size. For example, we could
// zero-extend a 16-bit stack location into a 32-bit register
// just because the compiler always loads unsigned shorts
// that way, but we might never use it as a 32-bit value.
// So there is no truncation if we store only 16 bits later.
// By setting the target of an extended load to zero width,
// we signal that we want the maximum USE width to determine
// whether the store is truncated (see EmitIntegerErrorAnnotations).
WidthMask = ComputeOperandBitWidthMask(LeftOp, 0);
if (OpIsDEF) {
if (this->MDIsSignedLoad(SignMask)) {
WidthMask = 0;
}
// DEF inherits sign from right hand side.
LeftFG.SignMiscInfo |= RightFG.SignMiscInfo;
else if ((LeftFG.SignMiscInfo == 0) && CurrOpTransfersSign) {
// We have a USE, not a DEF, with no sign info. See if we
// can get sign info from the DEF of this USE so we can
// transfer it up the RTL tree.
LeftFG.SignMiscInfo =
(FG_MASK_SIGNEDNESS_BITS & (this->GetDefSignInfoFromUseOp(LeftOp)));
LeftFG.SizeInfo |= WidthMask;
if ((LeftFG.SignMiscInfo != 0) || (LeftFG.SizeInfo != 0)) {
// Either NewChanged or CurrOpTransfersSign is true or we set WidthMask above.
// See if we would change the FG map entry.
if (OpIsDEF) { // Need DEF map info
MapsChanged |= this->UpdateDefOpFGInfo(LeftOp, LeftFG);
}
else { // need USE map info
MapsChanged |= this->UpdateUseOpFGInfo(LeftOp, LeftFG);
}
} // end if non-zero LeftFG info
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
#if SMP_AGGRESSIVE_SIGN_TRANSFER
else {
// On all iterations other than 1st, see if LeftOp has FG info.
if (!OpIsDEF) { // LeftOp is a USE
UseHashValue = this->GetUseOpHashAndSSA(LeftOp, SSANum);
if (this->BasicBlock->IsLocalName(LeftOp)) {
// Get FG info from block.
LeftFG = this->BasicBlock->GetUseFGInfo(UseHashValue);
}
else {
// Get FG info from function level.
LeftFG = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue);
}
}
else { // LeftOp is a DEF
DefHashValue = this->GetDefOpHashAndSSA(LeftOp, SSANum);
if (this->BasicBlock->IsLocalName(LeftOp)) {
// Get FG info from block.
LeftFG = this->BasicBlock->GetDefFGInfo(DefHashValue);
}
else {
// Get FG info from function level.
LeftFG = this->BasicBlock->GetFunc()->GetDefFGInfo(DefHashValue);
}
// See if RightFG has sign info to transfer to LeftFG.
SignMask = (RightFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
if ((SignMask != 0) && (SignMask != (LeftFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS))) {
// SignMask from RightFG has bits that will change LeftFG.SignMiscInfo.
LeftFG.SignMiscInfo |= SignMask;
MapsChanged |= this->UpdateDefOpFGInfo(LeftOp, LeftFG);
}
}
}
#endif
} // end of register case for LeftOp
else if (OpIsDEF && MDIsStackAccessOpnd(LeftOp, UseFP)
&& (!this->BasicBlock->GetFunc()->IsInOutgoingArgsRegion(LeftOp))) {
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
// For stores into the stack, if the operand being stored has signedness
// and the stack location has no signedness, then we have a case where
// none of the loads from the stack location were signed, so it is
// safe to infer signedness of the stack location based on what is being
// stored into it, as no store signedness will conflict with load signedness.
success = this->BasicBlock->GetFunc()->MDGetFGStackLocInfo(this->address, LeftOp, LeftFG);
assert(success);
if (0 == (LeftFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS)) {
// No previous signedness info for the stack location.
// Get signedness info from RightFG.
SignMask = (RightFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
if ((0 != SignMask) && (FG_MASK_INCONSISTENT_SIGN != SignMask)) {
// Operand being stored has signedness.
// Transfer the signedness to the stack location.
struct FineGrainedInfo TempFG;
TempFG.SignMiscInfo = SignMask;
TempFG.SizeInfo = 0; // just update signedness
success = this->BasicBlock->GetFunc()->MDUpdateFGStackLocInfo(this->address, LeftOp, TempFG);
MapsChanged |= success;
}
}
}
// Prepare to return FG info for operator. First, OR the left and right FG infos.
if (NewChange || MapsChanged || CurrOpTransfersSign) {
OpFG.SignMiscInfo |= LeftFG.SignMiscInfo;
OpFG.SizeInfo |= LeftFG.SizeInfo;
OpFG.SignMiscInfo |= RightFG.SignMiscInfo;
OpFG.SizeInfo |= RightFG.SizeInfo;
}
// An operator could override the width or signedness info of its operands.
if (CurrOp == SMP_ADDRESS_OF) {
// Result is 32-bit data pointer.
OpFG.SizeInfo &= (~FG_MASK_BITWIDTH_FIELDS); // clear all width bits
OpFG.SizeInfo |= (FG_MASK_BITWIDTH_32 | FG_MASK_DATAPOINTER);
OpFG.SignMiscInfo &= (~FG_MASK_SIGNED);
OpFG.SignMiscInfo |= FG_MASK_UNSIGNED;
}
return MapsChanged;
} // end of SMPInstr::InferOperatorFGInfo()
// infer width on first pass, signedness on all passes
bool SMPInstr::InferFGInfo(unsigned short IterCount) {
bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
struct FineGrainedInfo OpFG;
SMPitype DFType = this->GetDataFlowType();
assert(0 < IterCount); // start IterCount at 1, not 0.
if (DFType != DEFAULT) {
// We have a control flow instruction, e.g. call, return, branch, jump
// No data operands unless these instructions are indirect through a register,
// and the indirect operand is a memory operand in that case, e.g. [eax].
return MapsChanged;
}
for (size_t index = 0; index < this->RTL.GetCount(); ++index) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(index);
if (SMP_NULL_OPERATOR == CurrRT->GetOperator()) // nothing to infer
continue;
OpFG.SignMiscInfo = 0;
OpFG.SizeInfo = 0;
MapsChanged |= this->InferOperatorFGInfo(CurrRT, (1 == IterCount), OpFG);
if (SMP_CALL == CurrRT->GetOperator()) // no LeftOp DEF
continue;
} // end for all RTs in the RTL
return MapsChanged;
} // end of SMPInstr::InferFGInfo()
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
// Get the meet of the metadata types of all non-flags DEFs.
SMPMetadataType SMPInstr::GetDefMetadataType(void) {
SMPMetadataType MeetType = DEF_METADATA_UNANALYZED;
set<DefOrUse, LessDefUse>::iterator CurrDef;
for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
SMPMetadataType CurrType;
op_t DefOp = CurrDef->GetOp();
if (DefOp.is_reg(X86_FLAGS_REG))
continue; // flags are always unused metadata; irrelevant
CurrType = CurrDef->GetMetadataStatus();
if (MeetType == CurrType)
continue; // no meet operation to perform
// Any time we find USED metadata, that overrides all other types.
if (CurrType == DEF_METADATA_USED)
return CurrType;
if (MeetType == DEF_METADATA_UNANALYZED)
MeetType = CurrType;
else if (MeetType < DEF_METADATA_REDUNDANT) {
// Conflict between types of different DEFs. It could be that
// a multiply or divide instruction DEFs EAX and EDX, and one
// of them is used in a store and the other is unused. In that
// case, the final MeetType is USED and we can return. Or, if
// one type is UNUSED and the other is REDUNDANT, we can set
// the final type to the REDUNDANT type and return. The USED case
// is handled above, so we must have the UNUSED vs. REDUNDANT case.
assert(CurrType >= DEF_METADATA_REDUNDANT);
MeetType = CurrType;
}
else { // MeetType REDUNDANT, not equal to CurrType.
if (CurrType >= DEF_METADATA_REDUNDANT) {
// One type is profile derived, both are REDUNDANT.
MeetType = DEF_METADATA_PROF_REDUNDANT;
}
else {
assert(DEF_METADATA_UNUSED == CurrType);
// leave MeetType as REDUNDANT
}
}
} // end for all DEFs
return MeetType;
} // end of SMPInstr::GetDefMetadataType()
// Handle x86 opcode SIB byte annotations.
void SMPInstr::MDAnnotateSIBStackConstants(FILE *AnnotFile, op_t Opnd, ea_t offset, bool UseFP) {
int BaseReg;
int IndexReg;
ea_t displacement;
ushort ScaleFactor;
MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, displacement);
if (BaseReg == R_sp) { // ESP cannot be IndexReg
// ESP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
this->SMPcmd.ea, this->SMPcmd.size, offset, this->disasm);
}
else if (UseFP && ((IndexReg == R_bp) || (BaseReg == R_bp))) {
// EBP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
this->SMPcmd.ea, this->SMPcmd.size, offset, this->disasm);
}
return;
} // end of MDAnnotateSIBStackConstants
// Emit annotations for constants used as ptr offsets from EBP or
// ESP into the stack frame. Only pay attention to EBP-relative
// offsets if EBP is being used as a frame pointer (UseFP == true).
void SMPInstr::AnnotateStackConstants(bool UseFP, FILE *AnnotFile) {
op_t Opnd;
ea_t offset;
int BaseReg;
int IndexReg;
ushort ScaleFactor;
#if 0
if (this->address == 0x80925f4) {
msg("PROBLEM INSTRUCTION: \n");
this->PrintOperands();
}
#endif
for (int i = 0; i < UA_MAXOP; ++i) {
Opnd = this->SMPcmd.Operands[i];
if ((Opnd.type == o_displ) || (Opnd.type == o_phrase))
MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, offset);
if (Opnd.type == o_displ) {
if (Opnd.hasSIB) {
MDAnnotateSIBStackConstants(AnnotFile, Opnd, offset, UseFP);
}
else { // no SIB
if (BaseReg == R_sp) {
// ESP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
this->SMPcmd.ea, this->SMPcmd.size, offset, disasm);
}
else if (UseFP && (BaseReg == R_bp)) {
// EBP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
this->SMPcmd.ea, this->SMPcmd.size, offset, disasm);
}
} // end if (Opnd.hasSIB) ... else ...
} // end if (Opnd.type == o_displ)
else if (Opnd.type == o_phrase) {
offset = 0; // mmStrata thinks [esp] is [esp+0]
if (Opnd.hasSIB) {
MDAnnotateSIBStackConstants(AnnotFile, Opnd, offset, UseFP);
}
else { // Something like [ecx]; is it [esp] or [ebp] ?
if (BaseReg == R_sp) {
// ESP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
this->SMPcmd.ea, this->SMPcmd.size, offset, disasm);
}
else if (UseFP && (BaseReg == R_bp)) {
// EBP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
this->SMPcmd.ea, this->SMPcmd.size, offset, disasm);
}
} // end if (Opnd.hasSIB) ... else ...
} // end else if (Opnd.type == o_phrase)
} // end for all operands
// If we move a stack pointer or frame pointer into another register, we
// need to annotate the implicit zero offset, e.g. mov edi,esp == mov edi,esp+0
// and edi is becoming a stack pointer that mmStrata needs to track.
if (this->MDIsStackPointerCopy(UseFP)) {
// Two possibilities: a move of the stack pointer, or an "lea"
// opcode, e.g. lea eax,[eap+8] ==> eax:=esp+8. In the move
// instruction (e.g. mov eax,esp), we have the implicit zero
// offset from the stack pointer register, but in the lea case,
// we might have zero or some other offset (lea eax,[esp] has
// the implicit zero).
int ESPoffset = 0;
if (NN_lea == this->SMPcmd.itype) {
ESPoffset = this->MDGetImmedUse();
}
// NOTE: Looks like this next line should be "else" because an lea instruction
// looks like it has a memory operand, hence it has already been handled above.
// We are getting duplicate annotations for lea instructions.
if (UseFP && this->GetFirstUse()->GetOp().is_reg(R_bp)) {
qfprintf(AnnotFile, "%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
this->SMPcmd.ea, this->SMPcmd.size, ESPoffset, disasm);
}
else {
qfprintf(AnnotFile, "%10x %6d PTRIMMEDESP STACK %d displ %s\n",
this->SMPcmd.ea, this->SMPcmd.size, ESPoffset, disasm);
}
}
return;
} // end of SMPInstr::AnnotateStackConstants()
// Emit all annotations for the instruction in the absence of RTL type inference.
void SMPInstr::EmitAnnotations(bool UseFP, bool AllocSeen, bool NeedsFrame, FILE *AnnotFile, FILE *InfoAnnotFile) {
ea_t addr = this->address;
flags_t InstrFlags = getFlags(addr);
bool MemDest = this->HasDestMemoryOperand();
bool MemSrc = this->HasSourceMemoryOperand();
bool SecondSrcOperandImmNum = this->IsSecondSrcOperandNumeric(InstrFlags); // assumes 2nd source is Imm or not-numeric?!
clc5q
committed
bool NoWarnFlag = false; // NOWARN annotation emitted?
clc5q
committed
bool OrphanCode = (NULL == this->BasicBlock);
ProfilerInformation *ProfInfo = NULL;
if (!OrphanCode)
ProfInfo = this->BasicBlock->GetFunc()->GetProg()->GetProfInfo();
#endif
++OptCount[OptType]; // keep count for debugging info
// If the instruction is a CALL (or INDIR_CALL that has been resolved to
// a single target address), then we need to see if the call is to a
// function that has been forbidden by a security policy. If so, we
// need to output a security alert.
// In the near future, we will output SPRI instrumentation to prevent
// the system/library call from executing.
if ((BADADDR != this->CallTarget) && (!this->IsCallUsedAsJump())) {
// We have a resolved call target address, either via direct or indirect call.
string FuncName = this->GetTrimmedCalledFunctionName();
ZST_SysCallType FuncCallType = GetCallTypeFromFuncName(FuncName);
ZST_Policy FuncCallPolicy = GetPolicyFromCallType(FuncCallType);
if (ZST_DISALLOW == FuncCallPolicy) {
if ((NULL != this->GetBlock()) && (NULL != this->GetBlock()->GetFunc())) {
qfprintf(ZST_AlarmFile, "ALARM: Call to %s will be disallowed at %x in %s\n",
FuncName.c_str(), this->address, this->GetBlock()->GetFunc()->GetFuncName());
}
else {
qfprintf(ZST_AlarmFile, "ALARM: Call to %s will be disallowed at %x\n", FuncName.c_str(), this->address);
}
qfprintf(ZST_AlarmFile, "ALARM REASON: Call policy is DISALLOW for all calls of type %s\n", CallTypeNames[FuncCallType]);
qfprintf(InfoAnnotFile, "%10x %6d INSTR SECURITYCALL Disallow 1 1 %s \n", addr, this->SMPcmd.size, disasm);
}
}