Newer
Older
(void) this->BasicBlock->PropagateLocalDefType(DefOp, STACKPTR, this->GetAddr());
}
else { // global name
if (DebugFlag) msg("Name was global\n");
this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
(void) this->BasicBlock->PropagateGlobalDefType(DefOp, STACKPTR, SSANum);
}
}
#endif
}
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
else if ((o_fpreg == DefOp.type) || (o_mmxreg == DefOp.type) || (o_xmmreg == DefOp.type)) {
if (DebugFlag) msg("Setting floating point reg DEF to NUMERIC\n");
CurrDef = this->SetDefType(DefOp, NUMERIC);
if (this->BasicBlock->IsLocalName(DefOp)) {
(void) this->BasicBlock->PropagateLocalDefType(DefOp, NUMERIC, this->GetAddr());
}
else { // global name
this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
(void) this->BasicBlock->PropagateGlobalDefType(DefOp, NUMERIC, CurrDef->GetSSANum());
}
}
#if 0 // could these registers have pointers in them?
else if ((o_trreg == DefOp.type) || (o_dbreg == DefOp.type) || (o_crreg == DefOp.type)) {
if (DebugFlag) msg("Setting special reg DEF to NUMERIC\n");
CurrDef = this->SetDefType(DefOp, NUMERIC);
if (this->BasicBlock->IsLocalName(DefOp)) {
(void) this->BasicBlock->PropagateLocalDefType(DefOp, NUMERIC, this->GetAddr());
}
else { // global name
this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
(void) this->BasicBlock->PropagateGlobalDefType(DefOp, NUMERIC, CurrDef->GetSSANum());
}
}
#endif
++CurrDef;
} // end while all DEFs via CurrDef
return;
} // end of SMPInstr::SetImmedTypes()
// Infer DEF, USE, and RTL SMPoperator types within the instruction based on the type
// of operator, the type category of the instruction, and the previously known types
// of the operands.
bool SMPInstr::InferTypes(void) {
bool changed = false;
int TypeCategory = SMPTypeCategory[this->SMPcmd.itype];
set<DefOrUse, LessDefUse>::iterator CurrDef;
set<DefOrUse, LessDefUse>::iterator CurrUse;
op_t DefOp, UseOp;
#if SMP_VERBOSE_DEBUG_INFER_TYPES
DebugFlag |= (0 == strcmp("__libc_csu_fini", this->BasicBlock->GetFunc()->GetFuncName()));
#endif
if (DebugFlag) {
msg("opcode: %d TypeCategory: %d\n", this->SMPcmd.itype, TypeCategory);
}
// If we are already finished with all types, return false.
if (this->TypeInferenceComplete)
return false;
// The control flow instructions can be handled simply based on their type
// and do not need an RTL walk.
SMPitype DFAType = this->GetDataFlowType();
if (DebugFlag) {
msg("DFAType: %d CategoryInference: %d\n", DFAType, this->CategoryInference);
}
if ((DFAType >= JUMP) && (DFAType <= INDIR_CALL)) {
// All USEs are either the flags (NUMERIC) or the target address (CODEPTR).
CurrUse = this->GetFirstUse();
while (CurrUse != this->GetLastUse()) {
UseOp = CurrUse->GetOp();
if (UseOp.is_reg(X86_FLAGS_REG))
CurrUse = this->SetUseType(UseOp, NUMERIC);
else
CurrUse = this->SetUseType(UseOp, CODEPTR);
++CurrUse;
}
this->TypeInferenceComplete = true;
return true;
}
// First, see if we can infer something about DEFs and USEs just from the
// type category of the instruction.
if (!this->CategoryInference) {
switch (TypeCategory) {
case 0: // no inference possible just from type category
case 1: // no inference possible just from type category
case 3: // MOV instructions; inference will come from source to dest in RTL walk.
case 5: // binary arithmetic; inference will come in RTL walk.
case 10: // binary arithmetic; inference will come in RTL walk.
case 11: // push and pop instructions; inference will come in RTL walk.
case 12: // exchange instructions; inference will come in RTL walk.
this->CategoryInference = true;
break;
case 2: // Result type is always NUMERIC.
case 7: // Result type is always NUMERIC.
case 8: // Result type is always NUMERIC.
case 9: // Result type is always NUMERIC.
case 13: // Result type is always NUMERIC.
case 14: // Result type is always NUMERIC.
case 15: // Result type is always NUMERIC.
CurrDef = this->GetFirstDef();
while (CurrDef != this->GetLastDef()) {
if (NUMERIC != CurrDef->GetType()) {
DefOp = CurrDef->GetOp();
SSANum = CurrDef->GetSSANum();
CurrDef = this->SetDefType(DefOp, NUMERIC);
changed = true;
if (this->BasicBlock->IsLocalName(DefOp)) {
(void) this->BasicBlock->PropagateLocalDefType(DefOp, NUMERIC,
this->GetAddr());
}
else { // global name
this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
(void) this->BasicBlock->PropagateGlobalDefType(DefOp, NUMERIC,
SSANum);
}
}
++CurrDef;
}
CategoryInference = true;
break;
case 4: // Unary INC, DEC, etc.: dest=source, so type remains the same
assert(this->RTL.GetRT(0)->HasRightSubTree());
UseOp = this->RTL.GetRT(0)->GetLeftOperand(); // USE == DEF
CurrUse = this->Uses.FindRef(UseOp);
assert(CurrUse != this->GetLastUse());
if (UNINIT != CurrUse->GetType()) {
// Only one USE, and it has a type assigned, so assign that type
// to the DEF.
CurrDef = this->GetFirstDef();
while (CurrDef != this->GetLastDef()) {
// Two DEFs: EFLAGS is NUMERIC, dest==source
DefOp = CurrDef->GetOp();
SSANum = CurrDef->GetSSANum();
if (DefOp.is_reg(X86_FLAGS_REG)) {
CurrDef = this->SetDefType(DefOp, NUMERIC);
if (this->BasicBlock->IsLocalName(DefOp)) {
(void) this->BasicBlock->PropagateLocalDefType(DefOp, NUMERIC,
this->GetAddr());
}
else { // global name
this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
(void) this->BasicBlock->PropagateGlobalDefType(DefOp, NUMERIC,
SSANum);
}
}
else {
CurrDef = this->SetDefType(DefOp, CurrUse->GetType());
if (this->BasicBlock->IsLocalName(DefOp)) {
(void) this->BasicBlock->PropagateLocalDefType(DefOp, NUMERIC,
this->GetAddr());
}
else { // global name
this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
(void) this->BasicBlock->PropagateGlobalDefType(DefOp, NUMERIC,
SSANum);
}
}
++CurrDef;
}
CategoryInference = true;
changed = true;
}
break;
case 6: // Result is always POINTER
DefOp = this->GetFirstDef()->GetOp();
SSANum = this->GetFirstDef()->GetSSANum();
CurrDef = this->SetDefType(DefOp, POINTER);
CategoryInference = true;
changed = true;
if (this->BasicBlock->IsLocalName(DefOp)) {
(void) this->BasicBlock->PropagateLocalDefType(DefOp, NUMERIC,
this->GetAddr());
}
else { // global name
this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
(void) this->BasicBlock->PropagateGlobalDefType(DefOp, NUMERIC,
SSANum);
}
break;
default:
msg("ERROR: Unknown type category for %s\n", this->GetDisasm());
CategoryInference = true;
break;
} // end switch on TypeCategory
} // end if (!CategoryInference)
// Walk the RTL and infer types based on operators and operands.
if (DebugFlag) {
msg("RTcount: %d\n", this->RTL.GetCount());
}
for (size_t index = 0; index < this->RTL.GetCount(); ++index) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(index);
if (UNINIT != CurrRT->GetOperatorType()) // all done with this RT **!!** NO
continue;
if (SMP_NULL_OPERATOR == CurrRT->GetOperator()) // nothing to infer
continue;
changed |= this->InferOperatorType(CurrRT);
if (DebugFlag) {
msg("returned from InferOperatorType\n");
}
} // end for all RTs in the RTL
return changed;
} // end of SMPInstr::InferTypes()
// Infer the type of an operator within an RT based on the types of its operands and
// based on the operator itself. Recurse down the tree if necessary.
// Return true if the operator type of the RT is updated.
bool SMPInstr::InferOperatorType(SMPRegTransfer *CurrRT) {
bool updated = false;
bool LeftNumeric, RightNumeric;
bool LeftPointer, RightPointer;
set<DefOrUse, LessDefUse>::iterator CurrDef;
set<DefOrUse, LessDefUse>::iterator CurrUse;
SMPOperandType LeftType = UNINIT;
SMPOperandType RightType = UNINIT;
op_t UseOp, DefOp;
SMPoperator CurrOp = CurrRT->GetOperator();
#if SMP_VERBOSE_DEBUG_INFER_TYPES
DebugFlag |= (0 == strcmp("__libc_csu_fini", this->BasicBlock->GetFunc()->GetFuncName()));
#endif
// See if we can infer the operator type from the operator itself. If so,
// we don't need to recurse down the tree because lower operators no longer
// matter to the final DEF.
#if SMP_VERBOSE_DEBUG_INFER_TYPES
msg("Entered InferOperatorType for CurrOp: %d\n", CurrOp);
#endif
switch (CurrOp) {
case SMP_NULL_OPERATOR:
break;
case SMP_CALL: // CALL instruction
if (UNINIT == CurrRT->GetOperatorType()) {
CurrRT->SetOperatorType(CODEPTR);
updated = true;
UseOp = CurrRT->GetRightOperand();
CurrUse = this->Uses.FindRef(UseOp);
assert(CurrUse != this->GetLastUse());
if (UNINIT == CurrUse->GetType()) {
CurrUse = this->SetUseType(UseOp, CODEPTR);
}
else if (CODEPTR != CurrUse->GetType()) {
msg("WARNING: call target is type %d, setting to CODEPTR at %x in %s\n",
CurrUse->GetType(), this->GetAddr(), this->GetDisasm());
CurrUse = this->SetUseType(UseOp, CODEPTR);
}
}
break;
case SMP_INPUT: // input from port
if (UNINIT == CurrRT->GetOperatorType()) {
CurrRT->SetOperatorType(UNKNOWN); // Leave DEF as UNINIT and infer later
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
updated = true;
}
break;
case SMP_OUTPUT: // output to port
break;
case SMP_ADDRESS_OF: // take effective address
if (UNINIT == CurrRT->GetOperatorType()) {
CurrRT->SetOperatorType(POINTER);
// Left operand is having its address taken, but we cannot infer what its
// type is.
updated = true;
}
break;
case SMP_U_LEFT_SHIFT: // unsigned left shift
case SMP_S_LEFT_SHIFT: // signed left shift
case SMP_U_RIGHT_SHIFT: // unsigned right shift
case SMP_S_RIGHT_SHIFT: // signed 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_ADD_CARRY: // add with carry
case SMP_SUBTRACT_BORROW: // subtract with borrow
case SMP_U_MULTIPLY:
case SMP_S_MULTIPLY:
case SMP_U_DIVIDE:
case SMP_S_DIVIDE:
case SMP_U_REMAINDER:
case SMP_SIGN_EXTEND:
case SMP_ZERO_EXTEND:
case SMP_BITWISE_NOT: // unary operator
case SMP_BITWISE_XOR:
case SMP_NEGATE: // unary negation
case SMP_S_COMPARE: // signed compare (subtraction-based)
case SMP_U_COMPARE: // unsigned compare (AND-based)
case SMP_LESS_THAN: // boolean test operators
case SMP_GREATER_THAN:
case SMP_LESS_EQUAL:
case SMP_GREATER_EQUAL:
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_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
if (UNINIT == CurrRT->GetOperatorType()) {
CurrRT->SetOperatorType(NUMERIC);
updated = true;
}
// Left operand should be NUMERIC if it exists.
UseOp = CurrRT->GetLeftOperand();
if (UseOp.type != o_void) {
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, NUMERIC, -1);
updated = true;
}
else if (UNINIT == CurrUse->GetType()) {
CurrUse = this->SetUseType(UseOp, NUMERIC);
updated = true;
}
}
// Right operand should be NUMERIC if it exists.
if (CurrRT->HasRightSubTree()) {
// Recurse into subtree
updated |= this->InferOperatorType(CurrRT->GetRightTree());
}
else {
UseOp = CurrRT->GetRightOperand();
if (UseOp.type != o_void) {
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, NUMERIC, -1);
updated = true;
}
else if (UNINIT == CurrUse->GetType()) {
CurrUse = this->SetUseType(UseOp, NUMERIC);
updated = true;
}
}
}
break;
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
case SMP_INCREMENT:
case SMP_DECREMENT:
// The type of the right operand is propagated to the operator, or vice
// versa, whichever receives a type first.
assert(!CurrRT->HasRightSubTree());
UseOp = CurrRT->GetLeftOperand();
assert(o_void != UseOp.type);
CurrUse = this->Uses.FindRef(UseOp);
if (CurrUse == this->GetLastUse()) {
msg("WARNING: Adding missing USE of ");
PrintOperand(UseOp);
msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm());
this->Uses.SetRef(UseOp);
updated = true;
break;
}
if (UNINIT == CurrRT->GetOperatorType()) {
if (UNINIT != CurrUse->GetType()) {
// Propagate operand type up to the operator.
CurrRT->SetOperatorType(CurrUse->GetType());
updated = true;
}
}
else if (UNINIT == CurrUse->GetType()) {
// Propagate operator type to operand.
CurrUse = this->SetUseType(UseOp, CurrRT->GetOperatorType());
updated = true;
}
break;
case SMP_ADD:
case SMP_SUBTRACT:
case SMP_BITWISE_AND:
case SMP_BITWISE_OR:
// If both operands are NUMERIC, operator and result are NUMERIC.
// If one operand is NUMERIC and the other is not UNINIT and not NUMERIC,
// then the operator and the result will inherit this second type.
if (UNINIT == CurrRT->GetOperatorType()) {
UseOp = CurrRT->GetLeftOperand();
assert(o_void != UseOp.type);
CurrUse = this->Uses.FindRef(UseOp);
if (CurrUse == this->GetLastUse()) {
msg("WARNING: Adding missing USE of ");
PrintOperand(UseOp);
msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm());
this->Uses.SetRef(UseOp);
updated = true;
LeftNumeric = false;
break;
LeftType = CurrUse->GetType();
LeftNumeric = (NUMERIC == LeftType);
#if SMP_VERBOSE_DEBUG_INFER_TYPES
msg("LeftType: %d LeftNumeric: %d\n", LeftType, LeftNumeric);
#endif
// Process right operand
if (CurrRT->HasRightSubTree()) {
updated |= this->InferOperatorType(CurrRT->GetRightTree());
RightType = CurrRT->GetRightTree()->GetOperatorType();
if (UNINIT == RightType) {
break;
}
else {
RightNumeric = (NUMERIC == RightType);
#if SMP_VERBOSE_DEBUG_INFER_TYPES
msg("Right subtree RightType: %dRightNumeric: %d\n", RightType, RightNumeric);
#endif
}
}
else {
UseOp = CurrRT->GetRightOperand();
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;
RightNumeric = false;
break;
RightType = CurrUse->GetType();
RightNumeric = (NUMERIC == RightType);
#if SMP_VERBOSE_DEBUG_INFER_TYPES
msg("RightType: %d RightNumeric: %d\n", RightType, RightNumeric);
#endif
} // end if RightSubtree else RightOperand
// Infer operator type from LeftNumeric and RightNumeric
LeftPointer = ((LeftType >= POINTER) && (LeftType <= HEAPPTR));
RightPointer = ((RightType >= POINTER) && (RightType <= HEAPPTR));
if (LeftNumeric && RightNumeric) {
CurrRT->SetOperatorType(NUMERIC);
updated = true;
}
else if (LeftNumeric || RightNumeric) {
if (LeftNumeric && (UNINIT != RightType)) {
CurrRT->SetOperatorType(RightType);
updated = true;
}
else if (RightNumeric && (UNINIT != LeftType)) {
CurrRT->SetOperatorType(LeftType);
updated = true;
}
}
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
else if (LeftPointer && RightPointer) {
// Arithmetic on two pointers
if (SMP_ADD == CurrOp) {
CurrRT->SetOperatorType(UNKNOWN);
}
else if (SMP_SUBTRACT == CurrOp) {
CurrRT->SetOperatorType(PTROFFSET);
}
else { // bitwise AND or OR of two pointers
msg("WARNING: hash of two pointers in %s\n", this->GetDisasm());
CurrRT->SetOperatorType(NUMERIC); // hash operation?
}
updated = true;
}
else if ((LeftPointer && (RightType == PTROFFSET))
|| (RightPointer && (LeftType == PTROFFSET))) {
// Arithmetic on PTR and PTROFFSET
if (SMP_ADD == CurrOp) {
// We assume (A-B) is being added to B or vice versa **!!**
CurrRT->SetOperatorType(POINTER);
}
else if (SMP_SUBTRACT == CurrOp) {
// We assume B - (B - A) == A **!!**
CurrRT->SetOperatorType(POINTER);
}
else { // bitwise AND or OR of pointer and pointer difference
msg("WARNING: hash of PTROFFSET and POINTER at %x in %s\n",
this->GetAddr(), this->GetDisasm());
CurrRT->SetOperatorType(NUMERIC); // hash operation?
}
updated = true;
}
} // end if UNINIT operator type
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
else { // operator has type other than UNINIT
UseOp = CurrRT->GetLeftOperand();
CurrUse = this->FindUse(UseOp);
assert(CurrUse != this->GetLastUse());
if (UNINIT == CurrUse->GetType()) {
CurrUse = this->SetUseType(UseOp, CurrRT->GetOperatorType());
updated = true;
assert(CurrUse != this->GetLastUse());
}
if (CurrRT->HasRightSubTree()) {
// Must need to iterate through the right tree again, as the operator
// has been typed.
RightType = CurrRT->GetRightTree()->GetOperatorType();
if (UNINIT == RightType) {
CurrRT->GetRightTree()->SetOperatorType(CurrRT->GetOperatorType());
updated = true;
}
updated |= this->InferOperatorType(CurrRT->GetRightTree());
}
else { // right operand; propagate operator type if needed
UseOp = CurrRT->GetRightOperand();
CurrUse = this->FindUse(UseOp);
assert(CurrUse != this->GetLastUse());
if (UNINIT == CurrUse->GetType()) {
CurrUse = this->SetUseType(UseOp, CurrRT->GetOperatorType());
updated = true;
assert(CurrUse != this->GetLastUse());
}
}
}
break;
case SMP_ASSIGN:
// If right operand has a type, it becomes the type of the SMP_ASSIGN
// operator and also of the left operand.
DefOp = CurrRT->GetLeftOperand();
CurrDef = this->Defs.FindRef(DefOp);
assert(CurrDef != this->GetLastDef()); // found it
if ((UNINIT == CurrRT->GetOperatorType()) && !CurrRT->HasRightSubTree()) {
#if SMP_VERBOSE_DEBUG_INFER_TYPES
msg("SMP_ASSIGN with UNINIT operator and no subtree.\n");
#endif
// we have a right operand, still have not inferred SMP_ASSIGN type
UseOp = CurrRT->GetRightOperand();
if (o_void == UseOp.type) {
msg("ERROR: void operand for SMP_ASSIGN in %s\n", this->GetDisasm());
return false;
}
else {
#if SMP_VERBOSE_DEBUG_INFER_TYPES
msg("SMP_ASSIGN with right operand op_t.type: %d\n", UseOp.type);
#endif
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;
}
else if (UNINIT != CurrUse->GetType()) {
#if SMP_VERBOSE_DEBUG_INFER_TYPES
msg("SMP_ASSIGN with right operand type %d\n", CurrUse->GetType());
#endif
// SMP_ASSIGN operator and DEF inherit type of the USE
CurrRT->SetOperatorType(CurrUse->GetType());
if (CurrDef->GetType() != CurrUse->GetType()) {
#if SMP_VERBOSE_DEBUG_INFER_TYPES
msg("SMP_ASSIGN changing DEF type to USE type.\n");
#endif
// DEF type is changing.
CurrDef = this->SetDefType(DefOp, CurrUse->GetType());
#if SMP_VERBOSE_DEBUG_INFER_TYPES
msg("SMP_ASSIGN changed DEF type to USE type.\n");
#endif
if (this->BasicBlock->IsLocalName(DefOp)) {
#if SMP_VERBOSE_DEBUG_INFER_TYPES
msg("SMP_ASSIGN DEF name was local.\n");
#endif
(void) this->BasicBlock->PropagateLocalDefType(DefOp,
CurrUse->GetType(), this->GetAddr());
}
else { // global name
#if SMP_VERBOSE_DEBUG_INFER_TYPES
msg("SMP_ASSIGN DEF name was global.\n");
#endif
int SSANum = CurrDef->GetSSANum();
#if SMP_VERBOSE_DEBUG_INFER_TYPES
msg("SMP_ASSIGN DEF SSA: %d\n", SSANum);
#endif
this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
(void) this->BasicBlock->PropagateGlobalDefType(DefOp,
CurrUse->GetType(), SSANum);
}
}
else { // UNINIT right operand and current operator
if (UNINIT != CurrDef->GetType()) {
// Type of DEF has been inferred from its USEs, so
// propagate to operator and right hand side of this RTL.
CurrUse = this->SetUseType(UseOp, CurrDef->GetType());
CurrRT->SetOperatorType(CurrDef->GetType());
updated = true;
}
}
else { // either non-UNINIT operator or right subtree at this point, or both
#if SMP_VERBOSE_DEBUG_INFER_TYPES
msg("SMP_ASSIGN with operator type: %d\n", CurrRT->GetOperatorType());
#endif
if (CurrRT->HasRightSubTree()) { // we have a right subtree
RightType = CurrRT->GetRightTree()->GetOperatorType();
if ((UNINIT == RightType) && (UNINIT != CurrRT->GetOperatorType())) {
// Propagate SMP_ASSIGN operator type to right subtree
RightType = CurrRT->GetOperatorType();
CurrRT->GetRightTree()->SetOperatorType(RightType);
updated = true;
updated |= this->InferOperatorType(CurrRT->GetRightTree());
}
else {
updated |= this->InferOperatorType(CurrRT->GetRightTree());
RightType = CurrRT->GetRightTree()->GetOperatorType();
}
#if SMP_VERBOSE_DEBUG_INFER_TYPES
msg("Right subtree RightType: %d\n", RightType);
#endif
else { // not right subtree; must be non-UNINIT current operator
UseOp = CurrRT->GetRightOperand();
CurrUse = this->Uses.FindRef(UseOp);
assert(CurrUse != this->GetLastUse());
RightType = CurrUse->GetType();
if (UNINIT == RightType) {
assert(UNINIT != CurrRT->GetOperatorType());
RightType = CurrRT->GetOperatorType();
CurrUse = this->SetUseType(UseOp, RightType);
assert(CurrUse != this->GetLastUse());
updated = true;
}
#if SMP_VERBOSE_DEBUG_INFER_TYPES
msg("RightType: %d\n", RightType);
#endif
}
if ((UNINIT == CurrRT->GetOperatorType()) && (UNINIT != RightType)) {
// We are now ready to propagate the type from the right
CurrRT->SetOperatorType(RightType);
updated = true;
// Propagate ASSIGN type to left (DEF) operand.
DefOp = CurrRT->GetLeftOperand();
CurrDef = this->Defs.FindRef(DefOp);
assert(CurrDef != this->GetLastDef());
#if SMP_VERBOSE_DEBUG_INFER_TYPES
msg("Propagated Right subtree RightType: %d\n", RightType);
#endif
if ((CurrDef->GetType() != UNINIT) && (CurrDef->GetType() != RightType)) {
msg("WARNING: changing type of ASSIGN DEF from %d to %d at %x in %s\n",
CurrDef->GetType(), RightType, this->GetAddr(), this->GetDisasm());
CurrDef = this->SetDefType(DefOp, RightType);
if (this->BasicBlock->IsLocalName(DefOp)) {
(void) this->BasicBlock->PropagateLocalDefType(DefOp,
RightType, this->GetAddr());
}
else { // global name
int SSANum = CurrDef->GetSSANum();
this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
(void) this->BasicBlock->PropagateGlobalDefType(DefOp, RightType,
SSANum);
}
} // end if propagating type from the right operand
} // end if UNINIT operator and no subtree ... else ...
break;
default:
msg("Unknown operator in %s\n", this->GetDisasm());
break;
} // end switch on operator
return updated;
} // end of SMPInstr::InferOperatorType()
// Handle x86 opcode SIB byte annotations.
void SMPInstr::MDAnnotateSIBStackConstants(FILE *AnnotFile, op_t Opnd, ea_t offset, bool UseFP) {
int BaseReg = sib_base(Opnd);
short IndexReg = sib_index(Opnd);
if (BaseReg == R_none) {
msg("BaseReg of R_none at %x\n", this->address);
}
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) && (Opnd.type != o_mem)))) {
// EBP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
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;
#if 0
if (this->address == 0x80925f4) {
msg("PROBLEM INSTRUCTION: \n");
this->PrintOperands();
}
#endif
for (int i = 0; i < UA_MAXOP; ++i) {
Opnd = SMPcmd.Operands[i];
if (Opnd.type == o_displ) {
ea_t offset = Opnd.addr;
if (Opnd.hasSIB) {
MDAnnotateSIBStackConstants(AnnotFile, Opnd, offset, UseFP);
}
else { // no SIB
ushort BaseReg = Opnd.reg;
if (BaseReg == R_sp) {
// ESP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
SMPcmd.ea, SMPcmd.size, offset, disasm);
}
else if (UseFP && (BaseReg == R_bp)) {
// EBP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
SMPcmd.ea, SMPcmd.size, offset, disasm);
}
} // end if (Opnd.hasSIB) ... else ...
} // end if (Opnd.type == o_displ)
else if (Opnd.type == o_phrase) {
ea_t offset = 0; // mmStrata thinks [esp] is [esp+0]
if (Opnd.hasSIB) {
MDAnnotateSIBStackConstants(AnnotFile, Opnd, offset, UseFP);
}
else { // Something like [ecx]
ushort BaseReg = Opnd.reg;
if (BaseReg == R_sp) {
// ESP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
SMPcmd.ea, SMPcmd.size, offset, disasm);
}
else if (UseFP && (BaseReg == R_bp)) {
// EBP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
SMPcmd.ea, 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)) {
if (UseFP && this->GetFirstUse()->GetOp().is_reg(R_bp)) {
qfprintf(AnnotFile, "%10x %6d PTRIMMEDEBP STACK 0 displ %s\n",
SMPcmd.ea, SMPcmd.size, disasm);
}
else {
qfprintf(AnnotFile, "%10x %6d PTRIMMEDESP STACK 0 displ %s\n",
SMPcmd.ea, SMPcmd.size, disasm);
}
}
return;
} // end of SMPInstr::AnnotateStackConstants()
// Emit all annotations for the instruction in the absence of RTL type inference.
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
void SMPInstr::EmitAnnotations(bool UseFP, bool AllocSeen, FILE *AnnotFile) {
ea_t addr = this->address;
flags_t InstrFlags = getFlags(addr);
bool MemDest = this->HasDestMemoryOperand();
bool MemSrc = this->HasSourceMemoryOperand();
bool SecondSrcOperandNum = this->IsSecondSrcOperandNumeric(InstrFlags);
++OptCount[OptType]; // keep count for debugging info
#if SMP_DEBUG_MEM
if (MemDest || MemSrc) {
msg("OptType: %d %s", OptType, disasm);
this->PrintOperands();
}
#endif
// Emit appropriate optimization annotations.
bool SDTInstrumentation = false;
switch (OptType) {
case 0: // SDT will have to handle these
{
#if SMP_DEBUG_TYPE0
msg("OptType 0: %x %s\n", addr, disasm);
#endif
// mmStrata wants to suppress warnings on the PUSH
// instructions that precede the LocalVarsAllocInstr
// (i.e. the PUSHes of callee-saved regs).
if (!AllocSeen && this->MDIsPushInstr()) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL NoWarn %s \n",
addr, -3, disasm);
}
else {
SDTInstrumentation = true;
}
break;
}
case 1: // nothing for SDT to do
{ qfprintf(AnnotFile, "%10x %6d INSTR LOCAL NoMetaUpdate %s \n",
addr, -1, disasm);
++AnnotationCount[OptType];
break;
}
case 4: // INC, DEC, etc.: no SDT work unless MemDest
{ if (MemDest || MemSrc) {
SDTInstrumentation = true;
break; // treat as category 0
}
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL Always1stSrc %s \n",
addr, -1, disasm);
++AnnotationCount[OptType];
break;
}
case 5: // ADD, etc.: If numeric 2nd src operand, no SDT work.
{ if (MemDest || MemSrc) {
SDTInstrumentation = true;
break; // treat as category 0
}
clc5q
committed
if (SecondSrcOperandNum && !this->MDIsFrameAllocInstr()) { // treat as category 1
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
addr, -1, OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
}
clc5q
committed
else {
SDTInstrumentation = true;
}
break;
}
case 6: // Only OS code should include these; problem for SDT
{ if (MemDest) {
SDTInstrumentation = true;
break; // treat as category 0
}
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL AlwaysPTR %s \n",
addr, -OptType, disasm);
++AnnotationCount[OptType];
break;
}
case 8: // Implicitly writes to EDX:EAX, always numeric.
{ qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n EDX EAX ZZ %s %s \n",
addr, -2, OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
SDTInstrumentation = true;
break;
}
case 9: // Either writes to FP reg (cat. 1) or memory (cat. 0)
{ if (MemDest) {
#if SMP_DEBUG
// MemDest seems to happen too much.
msg("Floating point MemDest: %s \n", disasm);
#endif
SDTInstrumentation = true;
break; // treat as category 0
}
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
addr, -1, OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
break;
}
default: // 2,3,7: Optimization possibilities depend on operands
{
#if SMP_DEBUG2
if (OptType == 3) { // MOV instr class
if (MemDest) {
msg("MemDest on MOV: %s\n", disasm);
}
else if (!SecondSrcOperandNum) {
msg("MOV: not 2nd op numeric: %s\n", disasm);
this->PrintOperands();
}
}
#endif
SDTInstrumentation = true;
if (MemDest) {
#if SMP_DEBUG_XOR
if (OptType == 2)
msg("MemDest on OptType 2: %s\n", disasm);
#endif
break; // treat as category 0
}
if ((OptType == 2) || (OptType == 7) || SecondSrcOperandNum) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s %s %s \n",
addr, -2, this->DestString(OptType),
OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
}
break;
}
} // end switch (OptType)
// If mmStrata is going to have to deal with the
// instruction, then we can annotate EBP and ESP
// relative constant offsets. If we have emitted
// an annotation of type -1, there is no point
// in telling mmStrata about these constants.
if (SDTInstrumentation) {
this->AnnotateStackConstants(UseFP, AnnotFile);
if (strlen(this->DeadRegsString) > 0) {
// Optimize by informing mmStrata of dead registers. It can avoid saving
// and restoring dead state. This is particularly important for EFLAGS,
// as restoring the flags is a pipeline serializing instruction.
qfprintf(AnnotFile, "%10x %6d INSTR DEADREGS %s ZZ %s \n",
addr, this->SMPcmd.size, this->DeadRegsString, disasm);
}
}
return;
} // end of SMPInstr::EmitAnnotations()
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
// Emit all annotations for the instruction using RTL type inference.
void SMPInstr::EmitTypeAnnotations(bool UseFP, bool AllocSeen, FILE *AnnotFile) {
ea_t addr = this->address;
flags_t InstrFlags = getFlags(addr);
int TypeGroup = SMPTypeCategory[this->SMPcmd.itype];
bool NumericDEFs = this->AllDefsNumeric(); // all DEFs are NUMERIC or CODEPTR
bool MemDest = this->HasDestMemoryOperand();
bool MemSrc = this->HasSourceMemoryOperand();
bool SecondSrcOperandNum = this->IsSecondSrcOperandNumeric(InstrFlags);
++OptCount[this->OptType]; // keep count for debugging info
// Emit appropriate optimization annotations.
bool SDTInstrumentation = false;
switch (OptType) {
case 0: // SDT will have to handle these
{
// mmStrata wants to suppress warnings on the PUSH
// instructions that precede the LocalVarsAllocInstr
// (i.e. the PUSHes of callee-saved regs).
if (!AllocSeen && this->MDIsPushInstr()) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL NoWarn %s \n",
addr, -3, disasm);
}
else {
SDTInstrumentation = true;
}
break;
}
case 1: // nothing for SDT to do
{ qfprintf(AnnotFile, "%10x %6d INSTR LOCAL NoMetaUpdate %s \n",
addr, -1, disasm);
++AnnotationCount[OptType];
break;
}
case 4: // INC, DEC, etc.: no SDT work unless MemDest
{ if (MemDest || MemSrc) { // pretty conservative here?
SDTInstrumentation = true;
break; // treat as category 0
}
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL Always1stSrc %s \n",
addr, -1, disasm);
++AnnotationCount[OptType];
break;
}
case 5: // ADD, etc.: If numeric 2nd src operand, no SDT work.
{
#if 1
if (MemDest || MemSrc) {
SDTInstrumentation = true;
break; // treat as category 0
}
#endif
if (SecondSrcOperandNum && !this->MDIsFrameAllocInstr()) { // treat as category 1
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
addr, -1, OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
}
else if (NumericDEFs) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s NumericDEFs %s \n",
addr, -2, this->DestString(OptType), disasm);
++AnnotationCount[OptType];