/* * Copyright 2002-2019 Intel Corporation. * * This software is provided to you as Sample Source Code as defined in the accompanying * End User License Agreement for the Intel(R) Software Development Products ("Agreement") * section 1.L. * * This software and the related documents are provided as is, with no express or implied * warranties, other than those that are expressly stated in the License. */ /* * Check some of the static properties of operands. * * This tool inserts no analysis routines, since it is a check for instruction static properties. * * Since it needs to know the semantics of machine instructions, it's architecture specific. */ #include #include #include #include #include #include "pin.H" using std::ofstream; using std::string; using std::endl; KNOB KnobOutput(KNOB_MODE_WRITEONCE,"pintool", "o", "operandtool.out", "Name for log file"); static ofstream out; /* We have this set of operand property functions INS_OperandIsAddressGenerator INS_OperandIsBranchDisplacement INS_OperandIsFixedMemop INS_OperandIsGsOrFsReg INS_OperandIsImmediate INS_OperandIsImplicit INS_OperandIsMemory INS_OperandIsReg INS_OperandRead INS_OperandReadAndWritten INS_OperandReadOnly INS_OperandWritten INS_OperandWrittenOnly We test all of them. */ /* Define some instruction properties */ enum operandProp_e { isAddressGenerator = 1<<0, isBranchDisplacement = 1<<1, isFixedMemoOp = 1<<2, isImmediate = 1<<3, isImplicit = 1<<4, isMemory = 1<<5, isReg = 1<<6, isRead = 1<<7, isReadWrite = 1<<8, isReadOnly = 1<<9, isWrite = 1<<10, isWriteOnly = 1<<11, allTests = (1<<12)-1 }; typedef BOOL (*OperandTestFunction_t)(INS, UINT32); /* Functions in the same order as above... */ static OperandTestFunction_t testFunctions[] = { INS_OperandIsAddressGenerator, INS_OperandIsBranchDisplacement, INS_OperandIsFixedMemop, INS_OperandIsImmediate, INS_OperandIsImplicit, INS_OperandIsMemory, INS_OperandIsReg, INS_OperandRead, INS_OperandReadAndWritten, INS_OperandReadOnly, INS_OperandWritten, INS_OperandWrittenOnly }; static const char * testNames[] = { "&", "B", "F", "Imm", "Implicit", "Mem", "Reg", "R", "R/W", "Ro", "W", "Wo" }; #define NumTestFunctions ((sizeof(testFunctions)/sizeof(testFunctions[0]))) /* Define the properties we want to test for a specific operand of a given instruction. * We define here the opcode, operand, which tests to run, and the expected result. * Additional tests could be added here. The only hard part is to find instructions which * have a restricted enough set of operands that you can know statically which operand you need to * look at. * * I was hoping that being able to choose the subset of operands to test would make this easier. * I haven't actually found a use for that, since every test so far uses "allTests". * * On IA-32 Linux this covers all of the tests and requires that each gives both TRUE and FALSE answers. * On Intel64 (where you're unlikely to see INT), we're missing a test for IMMEDIATE. Since that's covered * on IA-32 I think it's OK. */ static struct instructionTest { UINT32 opcode; /* Opcode */ INT32 operand; /* Operand to test; if < 0 INS_OperandCount()-operand */ UINT32 testProps; /* Mask of properties to test */ UINT32 result; /* Expected result of the tests */ instructionTest (UINT32 opc, UINT32 opd, UINT32 props, UINT32 res) : opcode(opc), operand(opd), testProps(props), result(res) {} } tests [] = { instructionTest(XED_ICLASS_LEA, 0, allTests, isReg | isWrite | isWriteOnly ), instructionTest(XED_ICLASS_LEA, 1, allTests, isAddressGenerator | isRead | isReadOnly ), // Target memory operand of MOVS instructionTest(XED_ICLASS_MOVSD, 0, allTests, isFixedMemoOp | isMemory | isImplicit | isWrite | isWriteOnly ), // Target base register of MOVS instructionTest(XED_ICLASS_MOVSD, 1, allTests, isImplicit | isRead | isReadWrite | isWrite ), #if (TARGET_IA32E) // Same test for MOVSQ instructionTest(XED_ICLASS_MOVSQ, 0, allTests, isFixedMemoOp | isMemory | isImplicit | isWrite | isWriteOnly ), instructionTest(XED_ICLASS_MOVSQ, 1, allTests, isImplicit | isRead | isReadWrite | isWrite ), #endif // JZ, has branch displacement instructionTest(XED_ICLASS_JZ, 0, allTests, isBranchDisplacement | isRead | isReadOnly), // INT has an immediate (at least, other than int3 which we don't expect to see) instructionTest(XED_ICLASS_INT, 0, allTests, isImmediate | isRead | isReadOnly), }; #define NumTestDescriptions (sizeof(tests)/sizeof(tests[0])) static string formatMask(UINT32 m) { string r; BOOL first = TRUE; for (UINT32 i=0; iopcode != op) continue; /* Aha, a test which applies to this opcode */ UINT32 result = 0; INT32 operand = t->operand; if (operand < 0) operand = INS_OperandCount(ins) - operand; // Run all the property enquiries and accumulate the results. for (UINT32 i=0;itestProps & (1<result) { testCounts[op].failed++; out << std::setw(50) << std::left << INS_Disassemble(ins) << std::right << "Operand " << operand << " Expected '" << formatMask(t->result) << "' Got '" << formatMask(result) << "'" << endl; } } } static void AtEnd(INT32 code, VOID *arg) { out << "Target exited with code : " << code << endl << endl; UINT32 failures = 0; for (UINT32 i=0; i