diff --git a/.gitattributes b/.gitattributes index c533adcbbce2b33dc5f5a1d4aac57f1060669dd0..df0eef64a3ea2f49f7cf7f3879ef118533f40bc8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,6 +3,5 @@ /README.txt -text /SMP-analyze.sh -text /SMP.idc -text -/SMPStaticAnalyzer.cpp -text /makefile -text /plugin.script -text diff --git a/SMPStaticAnalyzer.cpp b/SMPStaticAnalyzer.cpp deleted file mode 100644 index 4fcf8b9e76bb9ab67134610db226b0758d700b50..0000000000000000000000000000000000000000 --- a/SMPStaticAnalyzer.cpp +++ /dev/null @@ -1,1629 +0,0 @@ -// -// SMPStaticAnalyzer.cpp -// -// This plugin performs the static analyses needed for the SMP project -// (Software Memory Protection). -// - -#include <ida.hpp> -#include <idp.hpp> -#include <allins.hpp> -#include <auto.hpp> -#include <bytes.hpp> -#include <funcs.hpp> -#include <intel.hpp> -#include <loader.hpp> -#include <lines.hpp> -#include <name.hpp> - -// Set to 1 for debugging output -#define SMP_DEBUG 1 -#define SMP_DEBUG2 0 // verbose -#define SMP_DEBUG3 0 // verbose -#define SMP_DEBUG_TYPE0 0 // Output instr info for OptType = 0 - -// Set to 1 when doing a binary search using SMP_DEBUG_COUNT to find -// which function is causing a problem. -#define SMP_BINARY_DEBUG 0 - -#define SMP_DEBUG_COUNT 356 // How many funcs to process in problem search - - -// Define optimization categories for instructions. -static int OptCategory[NN_last+1]; -// Initialize the OptCategory[] array. -void InitOptCategory(void); - -static char *RegNames[R_of + 1] = - { "EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI", - "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", - "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH", - "SPL", "BPL", "SIL", "DIL", "EIP", "ES", "CS", "SS", - "DS", "FS", "GS", "CF", "ZF", "SF", "OF" - }; - -// Print out the destination operand list for the instruction, given -// the OptCategory for the instruction as a hint. -char *DestString(insn_t, int, char *); - -#define LAST_OPT_CATEGORY 9 -static char *OptExplanation[LAST_OPT_CATEGORY + 1] = - { "NoOpt", "NoMetaUpdate", "AlwaysNUM", "NUMVia2ndSrcIMMEDNUM", - "Always1stSrc", "1stSrcVia2ndSrcIMMEDNUM", "AlwaysPtr", - "AlwaysNUM", "AlwaysNUM", "NUMViaFPRegDest" - }; - -void IDAP_run(int); - -// Is the destination operand a memory reference? -bool IsDestMemoryOperand(insn_t Inst) { - if (Inst.Operands[0].type == o_void) - return false; - else - return ((Inst.Operands[0].type == o_mem) - || (Inst.Operands[0].type == o_phrase) - || (Inst.Operands[0].type == o_displ)); -} - -// Is the source operand a memory reference? -bool IsSrcMemoryOperand(insn_t Inst) { - if (Inst.Operands[1].type == o_void) - return false; - else - return ((Inst.Operands[1].type == o_mem) - || (Inst.Operands[1].type == o_phrase) - || (Inst.Operands[1].type == o_displ)); -} - -// DEBUG Print DEF and/or USE for an operand. -void PrintDefUse(ulong feature, int OpNum) { - // CF_ macros number the operands from 1 to 6, while OpNum - // is a 0 to 5 index into the insn_t.Operands[] array. - switch (OpNum) { - case 0: - if (feature & CF_CHG1) - msg(" DEF"); - if (feature & CF_USE1) - msg(" USE"); - break; - case 1: - if (feature & CF_CHG2) - msg(" DEF"); - if (feature & CF_USE2) - msg(" USE"); - break; - case 2: - if (feature & CF_CHG3) - msg(" DEF"); - if (feature & CF_USE3) - msg(" USE"); - break; - case 3: - if (feature & CF_CHG4) - msg(" DEF"); - if (feature & CF_USE4) - msg(" USE"); - break; - case 4: - if (feature & CF_CHG5) - msg(" DEF"); - if (feature & CF_USE5) - msg(" USE"); - break; - case 5: - if (feature & CF_CHG6) - msg(" DEF"); - if (feature & CF_USE6) - msg(" USE"); - break; - } - return; -} // end PrintDefUse() - -// DEBUG print SIB info for an operand. -void PrintSIB(op_t Opnd) { - int BaseReg = sib_base(Opnd); - short IndexReg = sib_index(Opnd); - int ScaleFactor = sib_scale(Opnd); -#define NAME_LEN 5 - char BaseName[NAME_LEN] = {'N', 'o', 'n', 'e', '\0'}; - char IndexName[NAME_LEN] = {'N', 'o', 'n', 'e', '\0'}; - if (BaseReg != R_bp) { // SIB code for NO BASE REG - qstrncpy(BaseName, RegNames[BaseReg], NAME_LEN - 1); - } - if (IndexReg != R_sp) { // SIB code for NO INDEX REG - qstrncpy(IndexName, RegNames[IndexReg], NAME_LEN -1); - } - msg(" Base %s Index %s Scale %d", BaseName, IndexName, ScaleFactor); -} // end PrintSIB() - -// DEBUG print operands for Inst. -void PrintOperands(insn_t Inst) { - op_t Opnd; - ulong CanonicalFeatures = Inst.get_canon_feature(); - for (int i = 0; i < UA_MAXOP; ++i) { - Opnd = Inst.Operands[i]; - if (Opnd.type == o_void) - continue; - else if (Opnd.type == o_mem) { - msg(" Operand %d : memory : addr: %x", i, Opnd.addr); - PrintDefUse(CanonicalFeatures, i); - if (Opnd.hasSIB) { // has SIB info - PrintSIB(Opnd); - } - } - else if (Opnd.type == o_phrase) { - msg(" Operand %d : memory phrase :", i); - PrintDefUse(CanonicalFeatures, i); - if (Opnd.hasSIB) { // has SIB info - PrintSIB(Opnd); - } - else { // no SIB info - ushort IndexReg = Opnd.phrase; - msg(" reg %s", RegNames[IndexReg]); - } - } - else if (Opnd.type == o_displ) { - ushort IndexReg = Opnd.phrase; - ea_t offset = Opnd.addr; - msg(" Operand %d : memory displ : reg %s displ %d", i, - RegNames[IndexReg], offset); - PrintDefUse(CanonicalFeatures, i); - if (Opnd.hasSIB) - msg(" \n WARNING: SIB for o_displ type"); - } - else if (Opnd.type == o_reg) { - msg(" Operand %d : register", i); - msg(" regno: %d", Opnd.reg); - PrintDefUse(CanonicalFeatures, i); - } - else if (Opnd.type == o_imm) { - msg(" Operand %d : immed", i); - PrintDefUse(CanonicalFeatures, i); - } - else if (Opnd.type == o_far) { - msg(" Operand %d : FarPtrImmed", i); - PrintDefUse(CanonicalFeatures, i); - } - else if (Opnd.type == o_near) { - msg(" Operand %d : NearPtrImmed", i); - PrintDefUse(CanonicalFeatures, i); - } - else { - msg(" Operand %d : unknown", i); - PrintDefUse(CanonicalFeatures, i); - } - if (!(Opnd.showed())) - msg(" HIDDEN "); - } - msg(" \n"); - return; -} - -// 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 AnnotateStackConstants(bool UseFP, insn_t Inst, char *disasm, FILE *AnnotFile) { - op_t Opnd; - for (int i = 0; i < UA_MAXOP; ++i) { - Opnd = Inst.Operands[i]; - if (Opnd.type == o_displ) { - ea_t offset = Opnd.addr; - if (Opnd.hasSIB && (0 != offset)) { - int BaseReg = sib_base(Opnd); - short IndexReg = sib_index(Opnd); -#define NAME_LEN 5 - if (BaseReg == R_sp) { // EBP cannot be base reg in SIB - // ESP-relative constant offset - qfprintf(AnnotFile, - "%x %d PTRIMMEDESP STACK %d %s\n", - Inst.ea, Inst.size, offset, disasm); - } - else if (IndexReg == R_bp) { // ESP cannot be index reg - // EBP-relative constant offset - qfprintf(AnnotFile, - "%x %d PTRIMMEDEBP STACK %d %s\n", - Inst.ea, Inst.size, offset, disasm); - } - } - else { - int BaseReg = Opnd.reg; - if (offset != 0) { // Don't annotate zero ??? - if (UseFP && (R_bp == BaseReg)) { - // EBP-relative constant offset - qfprintf(AnnotFile, - "%x %d PTRIMMEDEBP STACK %d %s\n", - Inst.ea, Inst.size, offset, disasm); - } - else if (R_sp == BaseReg) { - // ESP-relative constant offset - qfprintf(AnnotFile, - "%x %d PTRIMMEDESP STACK %d %s\n", - Inst.ea, Inst.size, offset, disasm); - } - } - } // end (if Opnd.hasSIB ... else ... ) - } // end if (Opnd.type == o_displ) - } // end for all operands - return; -} // end AnnotateStackConstants() - -// 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, using a heuristic -// that values in the range +/- 8K are numeric and others are -// probably addresses. 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 IsSecondOperandNumeric(flags_t F, insn_t Instr, char *disasm) { - bool SecondOpImm = (Instr.Operands[1].type == o_imm); - signed long TempImm; - - if (SecondOpImm) { - TempImm = (signed long) Instr.Operands[1].value; - } - -#if SMP_DEBUG - if (SecondOpImm && (0 > TempImm)) { -#if 0 - msg("Negative immediate: %d Hex: %x ASM: %s\n", TempImm, - Instr.Operands[1].value, disasm); -#endif - } - else if ((!SecondOpImm) && (Instr.Operands[1].type == o_imm)) { - msg("Problem with flags on immediate src operand: %s\n", disasm); - } -#endif - - return (SecondOpImm && (TempImm > IMMEDNUM_LOWER) - && (TempImm < IMMEDNUM_UPPER)); -} // end IsSecondoperandNumeric() - -// Is the instruction the one that allocates space on the -// stack for the local variables of size LocSize? -bool IsFrameAllocInstr(insn_t Instr, asize_t LocSize) { - // The frame allocating instruction should look like: - // sub esp,48 or add esp,-64 etc. - if ((Instr.itype == NN_sub) || (Instr.itype == NN_add)) { - if ((Instr.Operands[0].type == o_reg) - && (Instr.Operands[0].reg == R_sp)) { - // We know that an addition or subtraction is being - // performed on the stack pointer. This should not be - // possible within the prologue except at the stack - // frame allocation instruction, so return true. We - // could be more robust in this analysis in the future. **!!** - return true; - } - } - return false; -} // end IsFrameAllocInstr() - -// Get the stack frame info so we can emit stack -// annotations when we reach the stack allocation -// instruction that sets aside space for local vars. -// Return the address of the instruction at which these -// annotations should be emitted. This should normally -// be an instruction such as: sub esp,48 -// However, for a function with no local variables at all, -// we will need to determine which instruction should be -// considered to be the final instruction of the function -// prologue and return its address. -ea_t GetStackFrameInfo(func_t *FuncInfo, char *FuncName, - asize_t &LocalVarsSize, ushort &CalleeSavedRegsSize, - int &ReturnAddressSize, asize_t &IncomingArgsSize) { - // member_t *FrameMember; - // struc_t *FrameStruct = get_frame(FuncInfo); - - // The sizes of the three regions of the stack frame other than the - // return address are stored in the function structure. - LocalVarsSize = FuncInfo->frsize; - CalleeSavedRegsSize = FuncInfo->frregs; - IncomingArgsSize = FuncInfo->argsize; - - // The return address size can be obtained in a machine independent - // way by calling get_frame_retsize(). - ReturnAddressSize = get_frame_retsize(FuncInfo); - - // Now, if LocalVarsSize is not zero, we need to find the instruction - // in the function prologue that allocates space on the stack for - // local vars. This code could be made more robust in the future - // by matching LocalVarsSize to the immediate value in the allocation - // instruction. **!!** - if (0 < LocalVarsSize) { - for (ea_t addr = FuncInfo->startEA; addr < FuncInfo->endEA; - addr = get_item_end(addr)) { - flags_t InstrFlags = getFlags(addr); - if (isHead(InstrFlags) && isCode(InstrFlags)) { - ua_ana0(addr); - if (IsFrameAllocInstr(cmd, LocalVarsSize)) { - return addr; - } - } - } - // Could not find the frame allocating instruction. Bad. - // Emit diagnostic and return the first instruction in the - // function. - msg("ERROR: Could not find stack frame allocation in %s\n", - FuncName); - return FuncInfo->startEA; - } - // else LocalVarsSize was zero, meaning that we need to search for the - // end of the function prologue code and emit stack frame annotations - // from that address (i.e. this function returns that address). We - // will approximate this by finding the end of the sequence of PUSH - // instructions at the beginning of the function. The last PUSH - // instruction should be the last callee-save-reg instruction. We can - // make this more robust in the future by making sure that we do not - // count a PUSH of anything other than a register. **!!** - else { - ea_t SaveAddr = FuncInfo->startEA; - for (ea_t addr = FuncInfo->startEA; addr < FuncInfo->endEA; - addr = get_item_end(addr)) { - flags_t InstrFlags = getFlags(addr); - if (isHead(InstrFlags) && isCode(InstrFlags)) { - ua_ana0(addr); - if (cmd.itype == NN_push) { - SaveAddr = addr; - } - else { - return SaveAddr; - } - } - } - // If we reach this spot, we have a function composed entirely - // of PUSH instructions, with not even a return instruction. - // Very bad news! - msg("FATAL ERROR in StaticAnalyzer::GetStackFrameInfo\n"); - return SaveAddr; - } // end if (0 < LocalVarsSize) ... else ... -} // end GetStackFrameInfo() - -// Emit the annotations describing the regions of the stack frame. -void EmitStackFrameAnnotations(ea_t addr, insn_t Instr, char *disasm, - FILE *AnnotFile, - asize_t LocalVarsSize, ushort CalleeSavedRegsSize, - int RetAddrSize, asize_t IncomingArgsSize) { - if (0 < IncomingArgsSize) - qfprintf(AnnotFile, "%x %d INARGS STACK esp + %d %s \n", - addr, IncomingArgsSize, - (LocalVarsSize + CalleeSavedRegsSize + RetAddrSize), - disasm); - if (0 < RetAddrSize) - qfprintf(AnnotFile, "%x %d MEMORYHOLE STACK esp + %d ReturnAddress \n", - addr, RetAddrSize, (LocalVarsSize + CalleeSavedRegsSize)); - if (0 < CalleeSavedRegsSize) - qfprintf(AnnotFile, "%x %d MEMORYHOLE STACK esp + %d CalleeSavedRegs \n", - addr, CalleeSavedRegsSize, LocalVarsSize); - if (0 < LocalVarsSize) - qfprintf(AnnotFile, "%x %d LOCALFRAME STACK esp + %d LocalVars \n", - addr, LocalVarsSize, 0); - return; -} // end EmitStackFrameAnnotations() - -static int idaapi idp_callback(void *, int event_id, va_list va) { - if (event_id == ph.auto_empty_finally) { // IDA analysis is done - IDAP_run(0); - qexit(0); - } - return 0; -} - -int IDAP_init(void) { - // Skip this plugin if it was not specified by the user on the - // command line. - if (get_plugin_options("SMPStaticAnalyzer") == NULL) { - return PLUGIN_SKIP; - } - // Ensure correct working environment. - if ((inf.filetype != f_ELF) && (inf.filetype != f_PE)) { - error("Executable format must be PE or ELF."); - return PLUGIN_SKIP; - } - if (ph.id != PLFM_386) { - error("Processor must be x86."); - return PLUGIN_SKIP; - } - hook_to_notification_point(HT_IDP, idp_callback, NULL); - InitOptCategory(); - return PLUGIN_KEEP; -} - -void IDAP_term(void) { - unhook_from_notification_point(HT_IDP, idp_callback, NULL); - return; -} - -void IDAP_run(int arg) { - // The types of data objects based on their first operand flags. - char *DataTypes[] = { "VOID", "NUMHEX", "NUMDEC", "CHAR", - "SEG", "OFFSET", "NUMBIN", "NUMOCT", "ENUM", "FORCED", - "STRUCTOFFSET", "STACKVAR", "NUMFLOAT", "UNKNOWN", - "UNKNOWN", "UNKNOWN", 0}; - - segment_t *seg; - char buf[MAXSTR]; - ea_t ea; - flags_t ObjFlags; - bool ReadOnlyFlag; - FILE *SymsFile; - int OptCount[LAST_OPT_CATEGORY + 1]; - int AnnotationCount[LAST_OPT_CATEGORY + 1]; - -#if SMP_DEBUG - int FuncsProcessed = 0; - msg("Beginning IDAP_run.\n"); -#endif - // Open the output file. - SymsFile = qfopen("SMP.annot", "w"); - if (NULL == SymsFile) { - error("FATAL: Cannot open output file SMP.annot\n"); - return; - } - - (void) memset(OptCount, 0, sizeof(OptCount)); - (void) memset(AnnotationCount, 0, sizeof(AnnotationCount)); - - // First, examine the data segments and print info about static - // data, such as name/address/size. Do the same for functions in - // code segments. - // Loop through all segments. - for (int SegIndex = 0; SegIndex < get_segm_qty(); ++SegIndex) { - seg = getnseg(SegIndex); - - // We are only interested in the data segments of type - // SEG_DATA, SEG_BSS and SEG_COMM. - if ((seg->type == SEG_DATA) || (seg->type == SEG_BSS) - || (seg->type == SEG_COMM)) { - // Loop through each of the segments we are interested in, - // examining all data objects (effective addresses). - ReadOnlyFlag = ((seg->perm & SEGPERM_READ) && (!(seg->perm & SEGPERM_WRITE))); -#if SMP_DEBUG - msg("Starting data segment of type %d\n", seg->type); - if (ReadOnlyFlag) { - msg("Read-only data segment.\n"); - } -#endif - ea = seg->startEA; - while (ea < seg->endEA) { - ObjFlags = get_flags_novalue(ea); - // Only process head bytes of data objects, i.e. isData(). - if (isData(ObjFlags)) { - // Compute the size of the data object. - ea_t NextEA = ea; - do { - NextEA = nextaddr(NextEA); - } while ((NextEA < seg->endEA) && (!isHead(get_flags_novalue(NextEA)))); - size_t ObjSize = (size_t) (NextEA - ea); - // Get the data object name using its address. - char *TrueName = get_true_name(BADADDR, ea, buf, sizeof(buf)); - if (NULL == TrueName) { - qstrncpy(buf, "SMP_dummy0", 12); - } - // Output the name, address, size, and type info. - if (ReadOnlyFlag) { - qfprintf(SymsFile, - "%x %d OBJECT GLOBAL %s %s RO\n", ea, ObjSize, - buf, DataTypes[get_optype_flags0(ObjFlags) >> 20]); - } - else { - qfprintf(SymsFile, - "%x %d OBJECT GLOBAL %s %s RW\n", ea, ObjSize, - buf, DataTypes[get_optype_flags0(ObjFlags) >> 20]); - } - // Move on to next data object - ea = NextEA; - } - else { - ea = nextaddr(ea); - } - } // end while (ea < seg->endEA) - } // end if (seg->type == SEG_DATA ...) - else if (seg->type == SEG_CODE) { -#if SMP_DEBUG - msg("Starting code segment.\n"); -#endif - for (size_t FuncIndex = 0; FuncIndex < get_func_qty(); ++FuncIndex) { - func_t *FuncInfo = getn_func(FuncIndex); - char FuncName[MAXSTR]; - size_t FuncSize = FuncInfo->endEA - FuncInfo->startEA; - bool UseBP = (0 != (FuncInfo->flags & (FUNC_FRAME | FUNC_BOTTOMBP))); - bool StaticFunc = (0 != (FuncInfo->flags & FUNC_STATIC)); - asize_t LocalVarsSize; - ushort CalleeSavedRegsSize; - int RetAddrSize; - asize_t IncomingArgsSize; - ea_t LocalVarsAllocInstr; - // If more than one SEG_CODE segment, only process - // functions within the current segment. Don't know - // if multiple code segments are possible, but - // get_func_qty() is for the whole program, not just - // the current segment. - if ((FuncInfo->startEA < seg->startEA) - || (FuncInfo->endEA > seg->endEA)) { - continue; - } - // Get the function name - get_func_name(FuncInfo->startEA, FuncName, sizeof(FuncName)-1); - - if (StaticFunc) { - qfprintf(SymsFile, - "%x %d FUNC LOCAL %s ", FuncInfo->startEA, - FuncSize, FuncName); - } - else { - qfprintf(SymsFile, - "%x %d FUNC GLOBAL %s ", FuncInfo->startEA, - FuncSize, FuncName); - } - if (UseBP) { - qfprintf(SymsFile, "USEFP "); - } - else { - qfprintf(SymsFile, "NOFP "); - } - if (FuncInfo->does_return()) { - qfprintf(SymsFile, "\n"); - } - else { - qfprintf(SymsFile, "NORET \n"); - } - -#if SMP_BINARY_DEBUG - if (FuncsProcessed++ > SMP_DEBUG_COUNT) { - msg("Debug termination. FuncName = %s \n", FuncName); - msg("Function startEA: %x endEA: %x \n", - FuncInfo->startEA, FuncInfo->endEA); - break; - } -#endif -#if SMP_BINARY_DEBUG - if (FuncsProcessed > SMP_DEBUG_COUNT) { - msg("Final FuncName: %s \n", FuncName); - } -#endif - // Get the stack frame info so we can emit stack - // annotations when we reach the stack allocation - // instruction that sets aside space for local vars. - LocalVarsAllocInstr = GetStackFrameInfo(FuncInfo, FuncName, - LocalVarsSize, CalleeSavedRegsSize, RetAddrSize, - IncomingArgsSize); - // Loop through all instructions in the function. - // Output optimization annotations for those - // instructions that do not require full computation - // of their memory metadata by the Memory Monitor SDT. - for (ea_t addr = FuncInfo->startEA; addr < FuncInfo->endEA; - addr = get_item_end(addr)) { - flags_t InstrFlags = getFlags(addr); - if (isHead(InstrFlags) && isCode(InstrFlags)) { - char disasm[MAXSTR]; // disassembly text for instr - int OptType; // OptCategory for current instr - bool MemDest; // memory destination operand? - bool SrcDest; // memory source operand? - bool SecondOperandNum; // numeric 2nd src operand? - - // Fill cmd structure with disassembly of instr - // and get the instr disassembly text. - ua_ana0(addr); - (void) generate_disasm_line(addr, disasm, sizeof(disasm) - 1); - // Remove interactive color-coding tags. - tag_remove(disasm, disasm, 0); -#if SMP_BINARY_DEBUG - if (FuncsProcessed > SMP_DEBUG_COUNT) { - msg("Disasm: %s \n", disasm); - } -#endif - - MemDest = IsDestMemoryOperand(cmd); - SrcDest = IsSrcMemoryOperand(cmd); - SecondOperandNum = IsSecondOperandNumeric(InstrFlags, - cmd, disasm); - // Get optimization category. - OptType = OptCategory[cmd.itype]; - ++OptCount[OptType]; // keep count for debugging info - - // If this is the instruction which allocated space - // for local variables, we want to emit annotations - // describing the stack frame. - if (addr == LocalVarsAllocInstr) { - EmitStackFrameAnnotations(addr, cmd, disasm, - SymsFile, LocalVarsSize, CalleeSavedRegsSize, - RetAddrSize, IncomingArgsSize); - } - -#if SMP_DEBUG3 - // if (MemDest || SrcDest) { - if (OptType >= 0) { - msg("OptType: %d %s", OptType, disasm); - PrintOperands(cmd); - } -#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 - SDTInstrumentation = true; - break; - } - - case 1: // nothing for SDT to do - { qfprintf(SymsFile, "%x %d INSTR LOCAL NoMetaUpdate %s \n", - addr, -1, disasm); - ++AnnotationCount[OptType]; - break; - } - - case 4: // INC, DEC, etc.: no SDT work unless MemDest - { if (MemDest || SrcDest) { - SDTInstrumentation = true; - break; // treat as category 0 - } - qfprintf(SymsFile, "%x %d 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 || SrcDest) { - SDTInstrumentation = true; - break; // treat as category 0 - } - if (SecondOperandNum) { // treat as category 1 - qfprintf(SymsFile, "%x %d INSTR LOCAL %s %s \n", - addr, -1, OptExplanation[OptType], disasm); - ++AnnotationCount[OptType]; - } - break; - } - - case 6: // Only OS code should include these; problem for SDT - { if (MemDest) { - SDTInstrumentation = true; - break; // treat as category 0 - } - qfprintf(SymsFile, "%x %d INSTR LOCAL AlwaysPTR %s \n", - - addr, -OptType, disasm); - ++AnnotationCount[OptType]; - break; - } - - case 8: // Implicitly writes to EDX:EAX, always numeric. - { qfprintf(SymsFile, "%x %d 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(SymsFile, "%x %d INSTR LOCAL %s %s \n", - 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 (!SecondOperandNum) { - msg("MOV: not 2nd op numeric: %s\n", disasm); - PrintOperands(cmd); - } - } -#endif - SDTInstrumentation = true; - if (MemDest) break; // treat as category 0 - if ((OptType == 2) || (OptType == 7) || SecondOperandNum) { - qfprintf(SymsFile, "%x %d INSTR LOCAL n %s %s %s \n", - addr, -2, DestString(cmd, OptType, disasm), - 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) { - AnnotateStackConstants(UseBP, cmd, disasm, SymsFile); - } - } // end if (isHead && isCode) - } // end for (ea_t addr = FuncInfo->startEA; ...) - } // end for (size_t FuncIndex = 0; ...) - } // end else if (seg->type === SEG_CODE) - else { -#if SMP_DEBUG - msg("Not processing segment of type %d \n", seg->type); -#endif - } - } // end for (int SegIndex = 0; ... ) - -#if 0 // Segments produced slightly more useful data objects than names. - // Next, for comparison, loop through all names and print the - // name, address, and size for all data objects. - size_t NumberOfNames = get_nlist_size(); -#if SMP_DEBUG - msg("Processing %d names. \n", NumberOfNames); -#endif - for (int i = 0; i < (int) NumberOfNames; ++i) { - ea = get_nlist_ea(i); - ObjFlags = get_flags_novalue(ea); - if (isData(ObjFlags)) { - // Compute the size of the data object. - ea_t NextEA = ea; - seg = getseg(ea); - do { - NextEA = nextaddr(NextEA); - } while ((NextEA < seg->endEA) && isTail(get_flags_novalue(NextEA))); - size_t ObjSize = (size_t) (NextEA - ea); - // Get the data object name using its address. - get_true_name(BADADDR, ea, buf, sizeof(buf)); - // Output the name, address, size, and type info. - qfprintf(SymsFile, - "%x %d OBJECT GLOBAL %s %s \n", ea, ObjSize, - buf, DataTypes[get_optype_flags0(ObjFlags) >> 20]); - } - } // end for (int i = 0; i < NumberOfNames; ...) -#endif - - for (int OptType = 0; OptType <= LAST_OPT_CATEGORY; ++OptType) { - msg("Optimization Category Count %d: %d Annotations: %d\n", - OptType, OptCount[OptType], AnnotationCount[OptType]); - } - - qfclose(SymsFile); - return; -} // end IDAP_run() - -char IDAP_comment[] = "UVa SMP/NICECAP Project"; -char IDAP_help[] = "Good luck"; -char IDAP_name[] = "SMPStaticAnalyzer"; -char IDAP_hotkey[] = "Alt-J"; - -plugin_t PLUGIN = { - IDP_INTERFACE_VERSION, - 0, - IDAP_init, - IDAP_term, - IDAP_run, - IDAP_comment, - IDAP_help, - IDAP_name, - IDAP_hotkey -}; - -// Print out the destination operand list for the instruction, given -// the OptCategory for the instruction as a hint. -char *DestString(insn_t Instr, int OptType, char *disasm) { - static char DestList[MAXSTR]; - if (OptType != 7) { - if (Instr.Operands[0].type != o_reg) { - msg("Problem: destination operand not memory and not reg: %d %d %s \n", - Instr.Operands[0].type, Instr.Operands[1].type, disasm); - } - else { - ushort DestReg = Instr.Operands[0].reg; - qstrncpy(DestList, RegNames[DestReg], - 1 + strlen(RegNames[DestReg])); -#if 1 - qstrncat(DestList, " ZZ ", MAXSTR); -#endif - return DestList; - } - } - else { // OptType 7 could have one or two destinations. - // NOTE: FIX later. Currently a clone of code above. ** -#if SMP_DEBUG3 - msg("OptType 7: %s\n", disasm); - PrintOperands(Instr); -#endif - if (Instr.Operands[0].type != o_reg) { - msg("Problem: destination operand not memory and not reg: %d %d %s\n", - Instr.Operands[0].type, Instr.Operands[1].type, disasm); - } - else { - ushort DestReg = Instr.Operands[0].reg; - qstrncpy(DestList, RegNames[DestReg], - 1 + strlen(RegNames[DestReg])); -#if 1 - qstrncat(DestList, " ZZ ", MAXSTR); -#endif - return DestList; - } - } - DestList[0] = '\0'; - return DestList; -} // end of DestString() - - -// Initialize the OptCategory[] array to define how we emit -// optimizing annotations. -void InitOptCategory(void) { - // Default category is 0, no optimization without knowing context. - (void) memset(OptCategory, 0, sizeof(OptCategory)); - // Category 1 instructions never need updating of their memory - // metadata by the Memory Monitor SDT. Currently, this is because - // these instructions only have effects on registers we do not maintain - // metadata for, such as the EIP and the FLAGS, e.g. jumps, compares. - // Category 2 instructions always have a result type of 'n' (number). - // Category 3 instructions have a result type of 'n' (number) - // whenever the second source operand is an immediate operand of type 'n'. - // NOTE: MOV is only current example, and this will take some thought if - // other examples arise. - // Category 4 instructions have a result type identical to the 1st source operand type. - // NOTE: This is currently set for single-operand instructions such as - // INC, DEC. As a result, these are treated pretty much as if - // they were category 1 instructions, as there is no metadata update, - // unless the operand is a memory operand (i.e. mem or [reg]). - // If new instructions are added to this category that are not single - // operand and do require some updating, the category should be split. - // Category 5 instructions have a result type identical to the 1st source operand - // type whenever the 2nd source operand is an operand of type 'n'. - // If the destination is memory, metadata still needs to be checked; if - // not, no metadata check is needed, so it becomes category 1. - // Category 6 instructions always have a result type of 'p' (pointer). - // Category 7 instructions are category 2 instructions with two destinations, - // such as multiply and divide instructions that affect EDX:EAX. There are - // forms of these instructions that only have one destination, so they have - // to be distinguished via the operand info. - // Category 8 instructions implicitly write a numeric value to EDX:EAX, but - // EDX and EAX are not listed as operands. RDTSC, RDPMC, RDMSR, and other - // instructions that copy machine registers into EDX:EAX are category 8. - // Category 9 instructions are floating point instructions that either - // have a memory destination (treat as category 0) or a FP reg destination - // (treat as category 1). - - // NOTE: The Memory Monitor SDT needs just three categories, corresponding - // to categories 0, 1, and all others. For all categories > 1, the - // annotation should tell the SDT exactly how to update its metadata. - // For example, a division instruction will write type 'n' (NUM) as - // the metadata for result registers EDX:EAX. So, the annotation should - // list 'n', EDX, EAX, and a terminator of '/'. CWD (convert word to - // doubleword) should have a list of 'n', EAX, '/'. - -OptCategory[NN_null] = 0; // Unknown Operation -OptCategory[NN_aaa] = 2; // ASCII Adjust after Addition -OptCategory[NN_aad] = 2; // ASCII Adjust AX before Division -OptCategory[NN_aam] = 2; // ASCII Adjust AX after Multiply -OptCategory[NN_aas] = 2; // ASCII Adjust AL after Subtraction -OptCategory[NN_adc] = 5; // Add with Carry -OptCategory[NN_add] = 5; // Add -OptCategory[NN_and] = 0; // Logical AND -OptCategory[NN_arpl] = 1; // Adjust RPL Field of Selector -OptCategory[NN_bound] = 1; // Check Array Index Against Bounds -OptCategory[NN_bsf] = 2; // Bit Scan Forward -OptCategory[NN_bsr] = 2; // Bit Scan Reverse -OptCategory[NN_bt] = 2; // Bit Test -OptCategory[NN_btc] = 2; // Bit Test and Complement -OptCategory[NN_btr] = 2; // Bit Test and Reset -OptCategory[NN_bts] = 2; // Bit Test and Set -OptCategory[NN_call] = 1; // Call Procedure -OptCategory[NN_callfi] = 1; // Indirect Call Far Procedure -OptCategory[NN_callni] = 1; // Indirect Call Near Procedure -OptCategory[NN_cbw] = 2; // AL -> AX (with sign) ** No ops? -OptCategory[NN_cwde] = 2; // AX -> EAX (with sign) ** -OptCategory[NN_cdqe] = 2; // EAX -> RAX (with sign) ** -OptCategory[NN_clc] = 1; // Clear Carry Flag -OptCategory[NN_cld] = 1; // Clear Direction Flag -OptCategory[NN_cli] = 1; // Clear Interrupt Flag -OptCategory[NN_clts] = 1; // Clear Task-Switched Flag in CR0 -OptCategory[NN_cmc] = 1; // Complement Carry Flag -OptCategory[NN_cmp] = 1; // Compare Two Operands -OptCategory[NN_cmps] = 1; // Compare Strings -OptCategory[NN_cwd] = 2; // AX -> DX:AX (with sign) -OptCategory[NN_cdq] = 2; // EAX -> EDX:EAX (with sign) -OptCategory[NN_cqo] = 2; // RAX -> RDX:RAX (with sign) -OptCategory[NN_daa] = 2; // Decimal Adjust AL after Addition -OptCategory[NN_das] = 2; // Decimal Adjust AL after Subtraction -OptCategory[NN_dec] = 4; // Decrement by 1 -OptCategory[NN_div] = 7; // Unsigned Divide -OptCategory[NN_enterw] = 0; // Make Stack Frame for Procedure Parameters ** -OptCategory[NN_enter] = 0; // Make Stack Frame for Procedure Parameters ** -OptCategory[NN_enterd] = 0; // Make Stack Frame for Procedure Parameters ** -OptCategory[NN_enterq] = 0; // Make Stack Frame for Procedure Parameters ** -OptCategory[NN_hlt] = 0; // Halt -OptCategory[NN_idiv] = 7; // Signed Divide -OptCategory[NN_imul] = 7; // Signed Multiply -OptCategory[NN_in] = 0; // Input from Port ** -OptCategory[NN_inc] = 4; // Increment by 1 -OptCategory[NN_ins] = 2; // Input Byte(s) from Port to String ** -OptCategory[NN_int] = 1; // Call to Interrupt Procedure -OptCategory[NN_into] = 1; // Call to Interrupt Procedure if Overflow Flag = 1 -OptCategory[NN_int3] = 1; // Trap to Debugger -OptCategory[NN_iretw] = 1; // Interrupt Return -OptCategory[NN_iret] = 1; // Interrupt Return -OptCategory[NN_iretd] = 1; // Interrupt Return (use32) -OptCategory[NN_iretq] = 1; // Interrupt Return (use64) -OptCategory[NN_ja] = 1; // Jump if Above (CF=0 & ZF=0) -OptCategory[NN_jae] = 1; // Jump if Above or Equal (CF=0) -OptCategory[NN_jb] = 1; // Jump if Below (CF=1) -OptCategory[NN_jbe] = 1; // Jump if Below or Equal (CF=1 | ZF=1) -OptCategory[NN_jc] = 1; // Jump if Carry (CF=1) -OptCategory[NN_jcxz] = 1; // Jump if CX is 0 -OptCategory[NN_jecxz] = 1; // Jump if ECX is 0 -OptCategory[NN_jrcxz] = 1; // Jump if RCX is 0 -OptCategory[NN_je] = 1; // Jump if Equal (ZF=1) -OptCategory[NN_jg] = 1; // Jump if Greater (ZF=0 & SF=OF) -OptCategory[NN_jge] = 1; // Jump if Greater or Equal (SF=OF) -OptCategory[NN_jl] = 1; // Jump if Less (SF!=OF) -OptCategory[NN_jle] = 1; // Jump if Less or Equal (ZF=1 | SF!=OF) -OptCategory[NN_jna] = 1; // Jump if Not Above (CF=1 | ZF=1) -OptCategory[NN_jnae] = 1; // Jump if Not Above or Equal (CF=1) -OptCategory[NN_jnb] = 1; // Jump if Not Below (CF=0) -OptCategory[NN_jnbe] = 1; // Jump if Not Below or Equal (CF=0 & ZF=0) -OptCategory[NN_jnc] = 1; // Jump if Not Carry (CF=0) -OptCategory[NN_jne] = 1; // Jump if Not Equal (ZF=0) -OptCategory[NN_jng] = 1; // Jump if Not Greater (ZF=1 | SF!=OF) -OptCategory[NN_jnge] = 1; // Jump if Not Greater or Equal (ZF=1) -OptCategory[NN_jnl] = 1; // Jump if Not Less (SF=OF) -OptCategory[NN_jnle] = 1; // Jump if Not Less or Equal (ZF=0 & SF=OF) -OptCategory[NN_jno] = 1; // Jump if Not Overflow (OF=0) -OptCategory[NN_jnp] = 1; // Jump if Not Parity (PF=0) -OptCategory[NN_jns] = 1; // Jump if Not Sign (SF=0) -OptCategory[NN_jnz] = 1; // Jump if Not Zero (ZF=0) -OptCategory[NN_jo] = 1; // Jump if Overflow (OF=1) -OptCategory[NN_jp] = 1; // Jump if Parity (PF=1) -OptCategory[NN_jpe] = 1; // Jump if Parity Even (PF=1) -OptCategory[NN_jpo] = 1; // Jump if Parity Odd (PF=0) -OptCategory[NN_js] = 1; // Jump if Sign (SF=1) -OptCategory[NN_jz] = 1; // Jump if Zero (ZF=1) -OptCategory[NN_jmp] = 1; // Jump -OptCategory[NN_jmpfi] = 1; // Indirect Far Jump -OptCategory[NN_jmpni] = 1; // Indirect Near Jump -OptCategory[NN_jmpshort] = 1; // Jump Short (not used) -OptCategory[NN_lahf] = 2; // Load Flags into AH Register -OptCategory[NN_lar] = 2; // Load Access Rights Byte -OptCategory[NN_lea] = 0; // Load Effective Address ** -OptCategory[NN_leavew] = 0; // High Level Procedure Exit ** -OptCategory[NN_leave] = 0; // High Level Procedure Exit ** -OptCategory[NN_leaved] = 0; // High Level Procedure Exit ** -OptCategory[NN_leaveq] = 0; // High Level Procedure Exit ** -OptCategory[NN_lgdt] = 0; // Load Global Descriptor Table Register -OptCategory[NN_lidt] = 0; // Load Interrupt Descriptor Table Register -OptCategory[NN_lgs] = 6; // Load Full Pointer to GS:xx -OptCategory[NN_lss] = 6; // Load Full Pointer to SS:xx -OptCategory[NN_lds] = 6; // Load Full Pointer to DS:xx -OptCategory[NN_les] = 6; // Load Full Pointer to ES:xx -OptCategory[NN_lfs] = 6; // Load Full Pointer to FS:xx -OptCategory[NN_lldt] = 0; // Load Local Descriptor Table Register -OptCategory[NN_lmsw] = 1; // Load Machine Status Word -OptCategory[NN_lock] = 1; // Assert LOCK# Signal Prefix -OptCategory[NN_lods] = 0; // Load String -OptCategory[NN_loopw] = 1; // Loop while ECX != 0 -OptCategory[NN_loop] = 1; // Loop while CX != 0 -OptCategory[NN_loopd] = 1; // Loop while ECX != 0 -OptCategory[NN_loopq] = 1; // Loop while RCX != 0 -OptCategory[NN_loopwe] = 1; // Loop while CX != 0 and ZF=1 -OptCategory[NN_loope] = 1; // Loop while rCX != 0 and ZF=1 -OptCategory[NN_loopde] = 1; // Loop while ECX != 0 and ZF=1 -OptCategory[NN_loopqe] = 1; // Loop while RCX != 0 and ZF=1 -OptCategory[NN_loopwne] = 1; // Loop while CX != 0 and ZF=0 -OptCategory[NN_loopne] = 1; // Loop while rCX != 0 and ZF=0 -OptCategory[NN_loopdne] = 1; // Loop while ECX != 0 and ZF=0 -OptCategory[NN_loopqne] = 1; // Loop while RCX != 0 and ZF=0 -OptCategory[NN_lsl] = 6; // Load Segment Limit -OptCategory[NN_ltr] = 1; // Load Task Register -OptCategory[NN_mov] = 3; // Move Data -OptCategory[NN_movsp] = 3; // Move to/from Special Registers -OptCategory[NN_movs] = 0; // Move Byte(s) from String to String -OptCategory[NN_movsx] = 3; // Move with Sign-Extend -OptCategory[NN_movzx] = 3; // Move with Zero-Extend -OptCategory[NN_mul] = 7; // Unsigned Multiplication of AL or AX -OptCategory[NN_neg] = 2; // Two's Complement Negation -OptCategory[NN_nop] = 1; // No Operation -OptCategory[NN_not] = 2; // One's Complement Negation -OptCategory[NN_or] = 0; // Logical Inclusive OR -OptCategory[NN_out] = 0; // Output to Port -OptCategory[NN_outs] = 0; // Output Byte(s) to Port -OptCategory[NN_pop] = 0; // Pop a word from the Stack -OptCategory[NN_popaw] = 0; // Pop all General Registers -OptCategory[NN_popa] = 0; // Pop all General Registers -OptCategory[NN_popad] = 0; // Pop all General Registers (use32) -OptCategory[NN_popaq] = 0; // Pop all General Registers (use64) -OptCategory[NN_popfw] = 1; // Pop Stack into Flags Register ** -OptCategory[NN_popf] = 1; // Pop Stack into Flags Register ** -OptCategory[NN_popfd] = 1; // Pop Stack into Eflags Register ** -OptCategory[NN_popfq] = 1; // Pop Stack into Rflags Register ** -OptCategory[NN_push] = 0; // Push Operand onto the Stack -OptCategory[NN_pushaw] = 0; // Push all General Registers -OptCategory[NN_pusha] = 0; // Push all General Registers -OptCategory[NN_pushad] = 0; // Push all General Registers (use32) -OptCategory[NN_pushaq] = 0; // Push all General Registers (use64) -OptCategory[NN_pushfw] = 0; // Push Flags Register onto the Stack -OptCategory[NN_pushf] = 0; // Push Flags Register onto the Stack -OptCategory[NN_pushfd] = 0; // Push Flags Register onto the Stack (use32) -OptCategory[NN_pushfq] = 0; // Push Flags Register onto the Stack (use64) -OptCategory[NN_rcl] = 2; // Rotate Through Carry Left -OptCategory[NN_rcr] = 2; // Rotate Through Carry Right -OptCategory[NN_rol] = 2; // Rotate Left -OptCategory[NN_ror] = 2; // Rotate Right -OptCategory[NN_rep] = 0; // Repeat String Operation -OptCategory[NN_repe] = 0; // Repeat String Operation while ZF=1 -OptCategory[NN_repne] = 0; // Repeat String Operation while ZF=0 -OptCategory[NN_retn] = 0; // Return Near from Procedure -OptCategory[NN_retf] = 0; // Return Far from Procedure -OptCategory[NN_sahf] = 1; // Store AH into Flags Register -OptCategory[NN_sal] = 2; // Shift Arithmetic Left -OptCategory[NN_sar] = 2; // Shift Arithmetic Right -OptCategory[NN_shl] = 2; // Shift Logical Left -OptCategory[NN_shr] = 2; // Shift Logical Right -OptCategory[NN_sbb] = 5; // Integer Subtraction with Borrow -OptCategory[NN_scas] = 1; // Compare String -OptCategory[NN_seta] = 2; // Set Byte if Above (CF=0 & ZF=0) -OptCategory[NN_setae] = 2; // Set Byte if Above or Equal (CF=0) -OptCategory[NN_setb] = 2; // Set Byte if Below (CF=1) -OptCategory[NN_setbe] = 2; // Set Byte if Below or Equal (CF=1 | ZF=1) -OptCategory[NN_setc] = 2; // Set Byte if Carry (CF=1) -OptCategory[NN_sete] = 2; // Set Byte if Equal (ZF=1) -OptCategory[NN_setg] = 2; // Set Byte if Greater (ZF=0 & SF=OF) -OptCategory[NN_setge] = 2; // Set Byte if Greater or Equal (SF=OF) -OptCategory[NN_setl] = 2; // Set Byte if Less (SF!=OF) -OptCategory[NN_setle] = 2; // Set Byte if Less or Equal (ZF=1 | SF!=OF) -OptCategory[NN_setna] = 2; // Set Byte if Not Above (CF=1 | ZF=1) -OptCategory[NN_setnae] = 2; // Set Byte if Not Above or Equal (CF=1) -OptCategory[NN_setnb] = 2; // Set Byte if Not Below (CF=0) -OptCategory[NN_setnbe] = 2; // Set Byte if Not Below or Equal (CF=0 & ZF=0) -OptCategory[NN_setnc] = 2; // Set Byte if Not Carry (CF=0) -OptCategory[NN_setne] = 2; // Set Byte if Not Equal (ZF=0) -OptCategory[NN_setng] = 2; // Set Byte if Not Greater (ZF=1 | SF!=OF) -OptCategory[NN_setnge] = 2; // Set Byte if Not Greater or Equal (ZF=1) -OptCategory[NN_setnl] = 2; // Set Byte if Not Less (SF=OF) -OptCategory[NN_setnle] = 2; // Set Byte if Not Less or Equal (ZF=0 & SF=OF) -OptCategory[NN_setno] = 2; // Set Byte if Not Overflow (OF=0) -OptCategory[NN_setnp] = 2; // Set Byte if Not Parity (PF=0) -OptCategory[NN_setns] = 2; // Set Byte if Not Sign (SF=0) -OptCategory[NN_setnz] = 2; // Set Byte if Not Zero (ZF=0) -OptCategory[NN_seto] = 2; // Set Byte if Overflow (OF=1) -OptCategory[NN_setp] = 2; // Set Byte if Parity (PF=1) -OptCategory[NN_setpe] = 2; // Set Byte if Parity Even (PF=1) -OptCategory[NN_setpo] = 2; // Set Byte if Parity Odd (PF=0) -OptCategory[NN_sets] = 2; // Set Byte if Sign (SF=1) -OptCategory[NN_setz] = 2; // Set Byte if Zero (ZF=1) -OptCategory[NN_sgdt] = 0; // Store Global Descriptor Table Register -OptCategory[NN_sidt] = 0; // Store Interrupt Descriptor Table Register -OptCategory[NN_shld] = 2; // Double Precision Shift Left -OptCategory[NN_shrd] = 2; // Double Precision Shift Right -OptCategory[NN_sldt] = 6; // Store Local Descriptor Table Register -OptCategory[NN_smsw] = 2; // Store Machine Status Word -OptCategory[NN_stc] = 1; // Set Carry Flag -OptCategory[NN_std] = 1; // Set Direction Flag -OptCategory[NN_sti] = 1; // Set Interrupt Flag -OptCategory[NN_stos] = 0; // Store String -OptCategory[NN_str] = 6; // Store Task Register -OptCategory[NN_sub] = 5; // Integer Subtraction -OptCategory[NN_test] = 1; // Logical Compare -OptCategory[NN_verr] = 1; // Verify a Segment for Reading -OptCategory[NN_verw] = 1; // Verify a Segment for Writing -OptCategory[NN_wait] = 1; // Wait until BUSY# Pin is Inactive (HIGH) -OptCategory[NN_xchg] = 0; // Exchange Register/Memory with Register -OptCategory[NN_xlat] = 0; // Table Lookup Translation -OptCategory[NN_xor] = 2; // Logical Exclusive OR - -// -// 486 instructions -// - -OptCategory[NN_cmpxchg] = 0; // Compare and Exchange -OptCategory[NN_bswap] = 1; // Swap bytes in register -OptCategory[NN_xadd] = 0; // t<-dest; dest<-src+dest; src<-t -OptCategory[NN_invd] = 1; // Invalidate Data Cache -OptCategory[NN_wbinvd] = 1; // Invalidate Data Cache (write changes) -OptCategory[NN_invlpg] = 1; // Invalidate TLB entry - -// -// Pentium instructions -// - -OptCategory[NN_rdmsr] = 8; // Read Machine Status Register -OptCategory[NN_wrmsr] = 1; // Write Machine Status Register -OptCategory[NN_cpuid] = 8; // Get CPU ID -OptCategory[NN_cmpxchg8b] = 0; // Compare and Exchange Eight Bytes -OptCategory[NN_rdtsc] = 8; // Read Time Stamp Counter -OptCategory[NN_rsm] = 1; // Resume from System Management Mode - -// -// Pentium Pro instructions -// - -OptCategory[NN_cmova] = 0; // Move if Above (CF=0 & ZF=0) -OptCategory[NN_cmovb] = 0; // Move if Below (CF=1) -OptCategory[NN_cmovbe] = 0; // Move if Below or Equal (CF=1 | ZF=1) -OptCategory[NN_cmovg] = 0; // Move if Greater (ZF=0 & SF=OF) -OptCategory[NN_cmovge] = 0; // Move if Greater or Equal (SF=OF) -OptCategory[NN_cmovl] = 0; // Move if Less (SF!=OF) -OptCategory[NN_cmovle] = 0; // Move if Less or Equal (ZF=1 | SF!=OF) -OptCategory[NN_cmovnb] = 0; // Move if Not Below (CF=0) -OptCategory[NN_cmovno] = 0; // Move if Not Overflow (OF=0) -OptCategory[NN_cmovnp] = 0; // Move if Not Parity (PF=0) -OptCategory[NN_cmovns] = 0; // Move if Not Sign (SF=0) -OptCategory[NN_cmovnz] = 0; // Move if Not Zero (ZF=0) -OptCategory[NN_cmovo] = 0; // Move if Overflow (OF=1) -OptCategory[NN_cmovp] = 0; // Move if Parity (PF=1) -OptCategory[NN_cmovs] = 0; // Move if Sign (SF=1) -OptCategory[NN_cmovz] = 0; // Move if Zero (ZF=1) -OptCategory[NN_fcmovb] = 1; // Floating Move if Below -OptCategory[NN_fcmove] = 1; // Floating Move if Equal -OptCategory[NN_fcmovbe] = 1; // Floating Move if Below or Equal -OptCategory[NN_fcmovu] = 1; // Floating Move if Unordered -OptCategory[NN_fcmovnb] = 1; // Floating Move if Not Below -OptCategory[NN_fcmovne] = 1; // Floating Move if Not Equal -OptCategory[NN_fcmovnbe] = 1; // Floating Move if Not Below or Equal -OptCategory[NN_fcmovnu] = 1; // Floating Move if Not Unordered -OptCategory[NN_fcomi] = 1; // FP Compare, result in EFLAGS -OptCategory[NN_fucomi] = 1; // FP Unordered Compare, result in EFLAGS -OptCategory[NN_fcomip] = 1; // FP Compare, result in EFLAGS, pop stack -OptCategory[NN_fucomip] = 1; // FP Unordered Compare, result in EFLAGS, pop stack -OptCategory[NN_rdpmc] = 8; // Read Performance Monitor Counter - -// -// FPP instructuions -// - -OptCategory[NN_fld] = 1; // Load Real ** Infer src is 'n' -OptCategory[NN_fst] = 9; // Store Real -OptCategory[NN_fstp] = 9; // Store Real and Pop -OptCategory[NN_fxch] = 1; // Exchange Registers -OptCategory[NN_fild] = 1; // Load Integer ** Infer src is 'n' -OptCategory[NN_fist] = 0; // Store Integer -OptCategory[NN_fistp] = 0; // Store Integer and Pop -OptCategory[NN_fbld] = 1; // Load BCD -OptCategory[NN_fbstp] = 1; // Store BCD and Pop -OptCategory[NN_fadd] = 1; // Add Real -OptCategory[NN_faddp] = 1; // Add Real and Pop -OptCategory[NN_fiadd] = 1; // Add Integer -OptCategory[NN_fsub] = 1; // Subtract Real -OptCategory[NN_fsubp] = 1; // Subtract Real and Pop -OptCategory[NN_fisub] = 1; // Subtract Integer -OptCategory[NN_fsubr] = 1; // Subtract Real Reversed -OptCategory[NN_fsubrp] = 1; // Subtract Real Reversed and Pop -OptCategory[NN_fisubr] = 1; // Subtract Integer Reversed -OptCategory[NN_fmul] = 1; // Multiply Real -OptCategory[NN_fmulp] = 1; // Multiply Real and Pop -OptCategory[NN_fimul] = 1; // Multiply Integer -OptCategory[NN_fdiv] = 1; // Divide Real -OptCategory[NN_fdivp] = 1; // Divide Real and Pop -OptCategory[NN_fidiv] = 1; // Divide Integer -OptCategory[NN_fdivr] = 1; // Divide Real Reversed -OptCategory[NN_fdivrp] = 1; // Divide Real Reversed and Pop -OptCategory[NN_fidivr] = 1; // Divide Integer Reversed -OptCategory[NN_fsqrt] = 1; // Square Root -OptCategory[NN_fscale] = 1; // Scale: st(0) <- st(0) * 2^st(1) -OptCategory[NN_fprem] = 1; // Partial Remainder -OptCategory[NN_frndint] = 1; // Round to Integer -OptCategory[NN_fxtract] = 1; // Extract exponent and significand -OptCategory[NN_fabs] = 1; // Absolute value -OptCategory[NN_fchs] = 1; // Change Sign -OptCategory[NN_fcom] = 1; // Compare Real -OptCategory[NN_fcomp] = 1; // Compare Real and Pop -OptCategory[NN_fcompp] = 1; // Compare Real and Pop Twice -OptCategory[NN_ficom] = 1; // Compare Integer -OptCategory[NN_ficomp] = 1; // Compare Integer and Pop -OptCategory[NN_ftst] = 1; // Test -OptCategory[NN_fxam] = 1; // Examine -OptCategory[NN_fptan] = 1; // Partial tangent -OptCategory[NN_fpatan] = 1; // Partial arctangent -OptCategory[NN_f2xm1] = 1; // 2^x - 1 -OptCategory[NN_fyl2x] = 1; // Y * lg2(X) -OptCategory[NN_fyl2xp1] = 1; // Y * lg2(X+1) -OptCategory[NN_fldz] = 1; // Load +0.0 -OptCategory[NN_fld1] = 1; // Load +1.0 -OptCategory[NN_fldpi] = 1; // Load PI=3.14... -OptCategory[NN_fldl2t] = 1; // Load lg2(10) -OptCategory[NN_fldl2e] = 1; // Load lg2(e) -OptCategory[NN_fldlg2] = 1; // Load lg10(2) -OptCategory[NN_fldln2] = 1; // Load ln(2) -OptCategory[NN_finit] = 1; // Initialize Processor -OptCategory[NN_fninit] = 1; // Initialize Processor (no wait) -OptCategory[NN_fsetpm] = 1; // Set Protected Mode -OptCategory[NN_fldcw] = 1; // Load Control Word -OptCategory[NN_fstcw] = 0; // Store Control Word -OptCategory[NN_fnstcw] = 0; // Store Control Word (no wait) -OptCategory[NN_fstsw] = 2; // Store Status Word to memory or AX -OptCategory[NN_fnstsw] = 2; // Store Status Word (no wait) to memory or AX -OptCategory[NN_fclex] = 1; // Clear Exceptions -OptCategory[NN_fnclex] = 1; // Clear Exceptions (no wait) -OptCategory[NN_fstenv] = 0; // Store Environment -OptCategory[NN_fnstenv] = 0; // Store Environment (no wait) -OptCategory[NN_fldenv] = 1; // Load Environment -OptCategory[NN_fsave] = 0; // Save State -OptCategory[NN_fnsave] = 0; // Save State (no wait) -OptCategory[NN_frstor] = 1; // Restore State ** infer src is 'n' -OptCategory[NN_fincstp] = 1; // Increment Stack Pointer -OptCategory[NN_fdecstp] = 1; // Decrement Stack Pointer -OptCategory[NN_ffree] = 1; // Free Register -OptCategory[NN_fnop] = 1; // No Operation -OptCategory[NN_feni] = 1; // (8087 only) -OptCategory[NN_fneni] = 1; // (no wait) (8087 only) -OptCategory[NN_fdisi] = 1; // (8087 only) -OptCategory[NN_fndisi] = 1; // (no wait) (8087 only) - -// -// 80387 instructions -// - -OptCategory[NN_fprem1] = 1; // Partial Remainder ( < half ) -OptCategory[NN_fsincos] = 1; // t<-cos(st); st<-sin(st); push t -OptCategory[NN_fsin] = 1; // Sine -OptCategory[NN_fcos] = 1; // Cosine -OptCategory[NN_fucom] = 1; // Compare Unordered Real -OptCategory[NN_fucomp] = 1; // Compare Unordered Real and Pop -OptCategory[NN_fucompp] = 1; // Compare Unordered Real and Pop Twice - -// -// Instructions added 28.02.96 -// - -OptCategory[NN_setalc] = 2; // Set AL to Carry Flag ** -OptCategory[NN_svdc] = 0; // Save Register and Descriptor -OptCategory[NN_rsdc] = 0; // Restore Register and Descriptor -OptCategory[NN_svldt] = 0; // Save LDTR and Descriptor -OptCategory[NN_rsldt] = 0; // Restore LDTR and Descriptor -OptCategory[NN_svts] = 1; // Save TR and Descriptor -OptCategory[NN_rsts] = 1; // Restore TR and Descriptor -OptCategory[NN_icebp] = 1; // ICE Break Point -OptCategory[NN_loadall] = 0; // Load the entire CPU state from ES:EDI - -// -// MMX instructions -// - -OptCategory[NN_emms] = 1; // Empty MMX state -OptCategory[NN_movd] = 9; // Move 32 bits -OptCategory[NN_movq] = 9; // Move 64 bits -OptCategory[NN_packsswb] = 1; // Pack with Signed Saturation (Word->Byte) -OptCategory[NN_packssdw] = 1; // Pack with Signed Saturation (Dword->Word) -OptCategory[NN_packuswb] = 1; // Pack with Unsigned Saturation (Word->Byte) -OptCategory[NN_paddb] = 1; // Packed Add Byte -OptCategory[NN_paddw] = 1; // Packed Add Word -OptCategory[NN_paddd] = 1; // Packed Add Dword -OptCategory[NN_paddsb] = 1; // Packed Add with Saturation (Byte) -OptCategory[NN_paddsw] = 1; // Packed Add with Saturation (Word) -OptCategory[NN_paddusb] = 1; // Packed Add Unsigned with Saturation (Byte) -OptCategory[NN_paddusw] = 1; // Packed Add Unsigned with Saturation (Word) -OptCategory[NN_pand] = 1; // Bitwise Logical And -OptCategory[NN_pandn] = 1; // Bitwise Logical And Not -OptCategory[NN_pcmpeqb] = 1; // Packed Compare for Equal (Byte) -OptCategory[NN_pcmpeqw] = 1; // Packed Compare for Equal (Word) -OptCategory[NN_pcmpeqd] = 1; // Packed Compare for Equal (Dword) -OptCategory[NN_pcmpgtb] = 1; // Packed Compare for Greater Than (Byte) -OptCategory[NN_pcmpgtw] = 1; // Packed Compare for Greater Than (Word) -OptCategory[NN_pcmpgtd] = 1; // Packed Compare for Greater Than (Dword) -OptCategory[NN_pmaddwd] = 1; // Packed Multiply and Add -OptCategory[NN_pmulhw] = 1; // Packed Multiply High -OptCategory[NN_pmullw] = 1; // Packed Multiply Low -OptCategory[NN_por] = 1; // Bitwise Logical Or -OptCategory[NN_psllw] = 1; // Packed Shift Left Logical (Word) -OptCategory[NN_pslld] = 1; // Packed Shift Left Logical (Dword) -OptCategory[NN_psllq] = 1; // Packed Shift Left Logical (Qword) -OptCategory[NN_psraw] = 1; // Packed Shift Right Arithmetic (Word) -OptCategory[NN_psrad] = 1; // Packed Shift Right Arithmetic (Dword) -OptCategory[NN_psrlw] = 1; // Packed Shift Right Logical (Word) -OptCategory[NN_psrld] = 1; // Packed Shift Right Logical (Dword) -OptCategory[NN_psrlq] = 1; // Packed Shift Right Logical (Qword) -OptCategory[NN_psubb] = 1; // Packed Subtract Byte -OptCategory[NN_psubw] = 1; // Packed Subtract Word -OptCategory[NN_psubd] = 1; // Packed Subtract Dword -OptCategory[NN_psubsb] = 1; // Packed Subtract with Saturation (Byte) -OptCategory[NN_psubsw] = 1; // Packed Subtract with Saturation (Word) -OptCategory[NN_psubusb] = 1; // Packed Subtract Unsigned with Saturation (Byte) -OptCategory[NN_psubusw] = 1; // Packed Subtract Unsigned with Saturation (Word) -OptCategory[NN_punpckhbw] = 1; // Unpack High Packed Data (Byte->Word) -OptCategory[NN_punpckhwd] = 1; // Unpack High Packed Data (Word->Dword) -OptCategory[NN_punpckhdq] = 1; // Unpack High Packed Data (Dword->Qword) -OptCategory[NN_punpcklbw] = 1; // Unpack Low Packed Data (Byte->Word) -OptCategory[NN_punpcklwd] = 1; // Unpack Low Packed Data (Word->Dword) -OptCategory[NN_punpckldq] = 1; // Unpack Low Packed Data (Dword->Qword) -OptCategory[NN_pxor] = 1; // Bitwise Logical Exclusive Or - -// -// Undocumented Deschutes processor instructions -// - -OptCategory[NN_fxsave] = 1; // Fast save FP context ** to where? -OptCategory[NN_fxrstor] = 1; // Fast restore FP context ** from where? - -// Pentium II instructions - -OptCategory[NN_sysenter] = 1; // Fast Transition to System Call Entry Point -OptCategory[NN_sysexit] = 1; // Fast Transition from System Call Entry Point - -// 3DNow! instructions - -OptCategory[NN_pavgusb] = 1; // Packed 8-bit Unsigned Integer Averaging -OptCategory[NN_pfadd] = 1; // Packed Floating-Point Addition -OptCategory[NN_pfsub] = 1; // Packed Floating-Point Subtraction -OptCategory[NN_pfsubr] = 1; // Packed Floating-Point Reverse Subtraction -OptCategory[NN_pfacc] = 1; // Packed Floating-Point Accumulate -OptCategory[NN_pfcmpge] = 1; // Packed Floating-Point Comparison, Greater or Equal -OptCategory[NN_pfcmpgt] = 1; // Packed Floating-Point Comparison, Greater -OptCategory[NN_pfcmpeq] = 1; // Packed Floating-Point Comparison, Equal -OptCategory[NN_pfmin] = 1; // Packed Floating-Point Minimum -OptCategory[NN_pfmax] = 1; // Packed Floating-Point Maximum -OptCategory[NN_pi2fd] = 1; // Packed 32-bit Integer to Floating-Point -OptCategory[NN_pf2id] = 1; // Packed Floating-Point to 32-bit Integer -OptCategory[NN_pfrcp] = 1; // Packed Floating-Point Reciprocal Approximation -OptCategory[NN_pfrsqrt] = 1; // Packed Floating-Point Reciprocal Square Root Approximation -OptCategory[NN_pfmul] = 1; // Packed Floating-Point Multiplication -OptCategory[NN_pfrcpit1] = 1; // Packed Floating-Point Reciprocal First Iteration Step -OptCategory[NN_pfrsqit1] = 1; // Packed Floating-Point Reciprocal Square Root First Iteration Step -OptCategory[NN_pfrcpit2] = 1; // Packed Floating-Point Reciprocal Second Iteration Step -OptCategory[NN_pmulhrw] = 1; // Packed Floating-Point 16-bit Integer Multiply with rounding -OptCategory[NN_femms] = 1; // Faster entry/exit of the MMX or floating-point state -OptCategory[NN_prefetch] = 1; // Prefetch at least a 32-byte line into L1 data cache -OptCategory[NN_prefetchw] = 1; // Prefetch processor cache line into L1 data cache (mark as modified) - - -// Pentium III instructions - -OptCategory[NN_addps] = 1; // Packed Single-FP Add -OptCategory[NN_addss] = 1; // Scalar Single-FP Add -OptCategory[NN_andnps] = 1; // Bitwise Logical And Not for Single-FP -OptCategory[NN_andps] = 1; // Bitwise Logical And for Single-FP -OptCategory[NN_cmpps] = 1; // Packed Single-FP Compare -OptCategory[NN_cmpss] = 1; // Scalar Single-FP Compare -OptCategory[NN_comiss] = 1; // Scalar Ordered Single-FP Compare and Set EFLAGS -OptCategory[NN_cvtpi2ps] = 1; // Packed signed INT32 to Packed Single-FP conversion -OptCategory[NN_cvtps2pi] = 1; // Packed Single-FP to Packed INT32 conversion -OptCategory[NN_cvtsi2ss] = 1; // Scalar signed INT32 to Single-FP conversion -OptCategory[NN_cvtss2si] = 2; // Scalar Single-FP to signed INT32 conversion -OptCategory[NN_cvttps2pi] = 1; // Packed Single-FP to Packed INT32 conversion (truncate) -OptCategory[NN_cvttss2si] = 2; // Scalar Single-FP to signed INT32 conversion (truncate) -OptCategory[NN_divps] = 1; // Packed Single-FP Divide -OptCategory[NN_divss] = 1; // Scalar Single-FP Divide -OptCategory[NN_ldmxcsr] = 1; // Load Streaming SIMD Extensions Technology Control/Status Register -OptCategory[NN_maxps] = 1; // Packed Single-FP Maximum -OptCategory[NN_maxss] = 1; // Scalar Single-FP Maximum -OptCategory[NN_minps] = 1; // Packed Single-FP Minimum -OptCategory[NN_minss] = 1; // Scalar Single-FP Minimum -OptCategory[NN_movaps] = 9; // Move Aligned Four Packed Single-FP ** infer memsrc 'n'? -OptCategory[NN_movhlps] = 1; // Move High to Low Packed Single-FP -OptCategory[NN_movhps] = 1; // Move High Packed Single-FP -OptCategory[NN_movlhps] = 1; // Move Low to High Packed Single-FP -OptCategory[NN_movlps] = 1; // Move Low Packed Single-FP -OptCategory[NN_movmskps] = 1; // Move Mask to Register -OptCategory[NN_movss] = 9; // Move Scalar Single-FP -OptCategory[NN_movups] = 9; // Move Unaligned Four Packed Single-FP -OptCategory[NN_mulps] = 1; // Packed Single-FP Multiply -OptCategory[NN_mulss] = 1; // Scalar Single-FP Multiply -OptCategory[NN_orps] = 1; // Bitwise Logical OR for Single-FP Data -OptCategory[NN_rcpps] = 1; // Packed Single-FP Reciprocal -OptCategory[NN_rcpss] = 1; // Scalar Single-FP Reciprocal -OptCategory[NN_rsqrtps] = 1; // Packed Single-FP Square Root Reciprocal -OptCategory[NN_rsqrtss] = 1; // Scalar Single-FP Square Root Reciprocal -OptCategory[NN_shufps] = 1; // Shuffle Single-FP -OptCategory[NN_sqrtps] = 1; // Packed Single-FP Square Root -OptCategory[NN_sqrtss] = 1; // Scalar Single-FP Square Root -OptCategory[NN_stmxcsr] = 0; // Store Streaming SIMD Extensions Technology Control/Status Register ** Infer dest is 'n' -OptCategory[NN_subps] = 1; // Packed Single-FP Subtract -OptCategory[NN_subss] = 1; // Scalar Single-FP Subtract -OptCategory[NN_ucomiss] = 1; // Scalar Unordered Single-FP Compare and Set EFLAGS -OptCategory[NN_unpckhps] = 1; // Unpack High Packed Single-FP Data -OptCategory[NN_unpcklps] = 1; // Unpack Low Packed Single-FP Data -OptCategory[NN_xorps] = 1; // Bitwise Logical XOR for Single-FP Data -OptCategory[NN_pavgb] = 1; // Packed Average (Byte) -OptCategory[NN_pavgw] = 1; // Packed Average (Word) -OptCategory[NN_pextrw] = 2; // Extract Word -OptCategory[NN_pinsrw] = 1; // Insert Word -OptCategory[NN_pmaxsw] = 1; // Packed Signed Integer Word Maximum -OptCategory[NN_pmaxub] = 1; // Packed Unsigned Integer Byte Maximum -OptCategory[NN_pminsw] = 1; // Packed Signed Integer Word Minimum -OptCategory[NN_pminub] = 1; // Packed Unsigned Integer Byte Minimum -OptCategory[NN_pmovmskb] = 1; // Move Byte Mask to Integer -OptCategory[NN_pmulhuw] = 1; // Packed Multiply High Unsigned -OptCategory[NN_psadbw] = 1; // Packed Sum of Absolute Differences -OptCategory[NN_pshufw] = 1; // Packed Shuffle Word -OptCategory[NN_maskmovq] = 0; // Byte Mask write ** Infer dest is 'n' -OptCategory[NN_movntps] = 0; // Move Aligned Four Packed Single-FP Non Temporal * infer dest is 'n' -OptCategory[NN_movntq] = 0; // Move 64 Bits Non Temporal ** Infer dest is 'n' -OptCategory[NN_prefetcht0] = 1; // Prefetch to all cache levels -OptCategory[NN_prefetcht1] = 1; // Prefetch to all cache levels -OptCategory[NN_prefetcht2] = 1; // Prefetch to L2 cache -OptCategory[NN_prefetchnta] = 1; // Prefetch to L1 cache -OptCategory[NN_sfence] = 1; // Store Fence - -// Pentium III Pseudo instructions - -OptCategory[NN_cmpeqps] = 1; // Packed Single-FP Compare EQ -OptCategory[NN_cmpltps] = 1; // Packed Single-FP Compare LT -OptCategory[NN_cmpleps] = 1; // Packed Single-FP Compare LE -OptCategory[NN_cmpunordps] = 1; // Packed Single-FP Compare UNORD -OptCategory[NN_cmpneqps] = 1; // Packed Single-FP Compare NOT EQ -OptCategory[NN_cmpnltps] = 1; // Packed Single-FP Compare NOT LT -OptCategory[NN_cmpnleps] = 1; // Packed Single-FP Compare NOT LE -OptCategory[NN_cmpordps] = 1; // Packed Single-FP Compare ORDERED -OptCategory[NN_cmpeqss] = 1; // Scalar Single-FP Compare EQ -OptCategory[NN_cmpltss] = 1; // Scalar Single-FP Compare LT -OptCategory[NN_cmpless] = 1; // Scalar Single-FP Compare LE -OptCategory[NN_cmpunordss] = 1; // Scalar Single-FP Compare UNORD -OptCategory[NN_cmpneqss] = 1; // Scalar Single-FP Compare NOT EQ -OptCategory[NN_cmpnltss] = 1; // Scalar Single-FP Compare NOT LT -OptCategory[NN_cmpnless] = 1; // Scalar Single-FP Compare NOT LE -OptCategory[NN_cmpordss] = 1; // Scalar Single-FP Compare ORDERED - -// AMD K7 instructions - -// Revisit AMD if we port to it. -OptCategory[NN_pf2iw] = 0; // Packed Floating-Point to Integer with Sign Extend -OptCategory[NN_pfnacc] = 0; // Packed Floating-Point Negative Accumulate -OptCategory[NN_pfpnacc] = 0; // Packed Floating-Point Mixed Positive-Negative Accumulate -OptCategory[NN_pi2fw] = 0; // Packed 16-bit Integer to Floating-Point -OptCategory[NN_pswapd] = 0; // Packed Swap Double Word - -// Undocumented FP instructions (thanks to norbert.juffa@adm.com) - -OptCategory[NN_fstp1] = 9; // Alias of Store Real and Pop -OptCategory[NN_fcom2] = 1; // Alias of Compare Real -OptCategory[NN_fcomp3] = 1; // Alias of Compare Real and Pop -OptCategory[NN_fxch4] = 1; // Alias of Exchange Registers -OptCategory[NN_fcomp5] = 1; // Alias of Compare Real and Pop -OptCategory[NN_ffreep] = 1; // Free Register and Pop -OptCategory[NN_fxch7] = 1; // Alias of Exchange Registers -OptCategory[NN_fstp8] = 9; // Alias of Store Real and Pop -OptCategory[NN_fstp9] = 9; // Alias of Store Real and Pop - -// Pentium 4 instructions - -OptCategory[NN_addpd] = 1; // Add Packed Double-Precision Floating-Point Values -OptCategory[NN_addsd] = 1; // Add Scalar Double-Precision Floating-Point Values -OptCategory[NN_andnpd] = 1; // Bitwise Logical AND NOT of Packed Double-Precision Floating-Point Values -OptCategory[NN_andpd] = 1; // Bitwise Logical AND of Packed Double-Precision Floating-Point Values -OptCategory[NN_clflush] = 1; // Flush Cache Line -OptCategory[NN_cmppd] = 1; // Compare Packed Double-Precision Floating-Point Values -OptCategory[NN_cmpsd] = 1; // Compare Scalar Double-Precision Floating-Point Values -OptCategory[NN_comisd] = 1; // Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS -OptCategory[NN_cvtdq2pd] = 1; // Convert Packed Doubleword Integers to Packed Single-Precision Floating-Point Values -OptCategory[NN_cvtdq2ps] = 1; // Convert Packed Doubleword Integers to Packed Double-Precision Floating-Point Values -OptCategory[NN_cvtpd2dq] = 1; // Convert Packed Double-Precision Floating-Point Values to Packed Doubleword Integers -OptCategory[NN_cvtpd2pi] = 1; // Convert Packed Double-Precision Floating-Point Values to Packed Doubleword Integers -OptCategory[NN_cvtpd2ps] = 1; // Convert Packed Double-Precision Floating-Point Values to Packed Single-Precision Floating-Point Values -OptCategory[NN_cvtpi2pd] = 1; // Convert Packed Doubleword Integers to Packed Double-Precision Floating-Point Values -OptCategory[NN_cvtps2dq] = 1; // Convert Packed Single-Precision Floating-Point Values to Packed Doubleword Integers -OptCategory[NN_cvtps2pd] = 1; // Convert Packed Single-Precision Floating-Point Values to Packed Double-Precision Floating-Point Values -OptCategory[NN_cvtsd2si] = 2; // Convert Scalar Double-Precision Floating-Point Value to Doubleword Integer -OptCategory[NN_cvtsd2ss] = 1; // Convert Scalar Double-Precision Floating-Point Value to Scalar Single-Precision Floating-Point Value -OptCategory[NN_cvtsi2sd] = 1; // Convert Doubleword Integer to Scalar Double-Precision Floating-Point Value -OptCategory[NN_cvtss2sd] = 1; // Convert Scalar Single-Precision Floating-Point Value to Scalar Double-Precision Floating-Point Value -OptCategory[NN_cvttpd2dq] = 1; // Convert With Truncation Packed Double-Precision Floating-Point Values to Packed Doubleword Integers -OptCategory[NN_cvttpd2pi] = 1; // Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Doubleword Integers -OptCategory[NN_cvttps2dq] = 1; // Convert With Truncation Packed Single-Precision Floating-Point Values to Packed Doubleword Integers -OptCategory[NN_cvttsd2si] = 2; // Convert with Truncation Scalar Double-Precision Floating-Point Value to Doubleword Integer -OptCategory[NN_divpd] = 1; // Divide Packed Double-Precision Floating-Point Values -OptCategory[NN_divsd] = 1; // Divide Scalar Double-Precision Floating-Point Values -OptCategory[NN_lfence] = 1; // Load Fence -OptCategory[NN_maskmovdqu] = 0; // Store Selected Bytes of Double Quadword ** Infer dest is 'n' -OptCategory[NN_maxpd] = 1; // Return Maximum Packed Double-Precision Floating-Point Values -OptCategory[NN_maxsd] = 1; // Return Maximum Scalar Double-Precision Floating-Point Value -OptCategory[NN_mfence] = 1; // Memory Fence -OptCategory[NN_minpd] = 1; // Return Minimum Packed Double-Precision Floating-Point Values -OptCategory[NN_minsd] = 1; // Return Minimum Scalar Double-Precision Floating-Point Value -OptCategory[NN_movapd] = 9; // Move Aligned Packed Double-Precision Floating-Point Values ** Infer dest is 'n' -OptCategory[NN_movdq2q] = 1; // Move Quadword from XMM to MMX Register -OptCategory[NN_movdqa] = 9; // Move Aligned Double Quadword ** Infer dest is 'n' -OptCategory[NN_movdqu] = 9; // Move Unaligned Double Quadword ** Infer dest is 'n' -OptCategory[NN_movhpd] = 9; // Move High Packed Double-Precision Floating-Point Values ** Infer dest is 'n' -OptCategory[NN_movlpd] = 9; // Move Low Packed Double-Precision Floating-Point Values ** Infer dest is 'n' -OptCategory[NN_movmskpd] = 2; // Extract Packed Double-Precision Floating-Point Sign Mask -OptCategory[NN_movntdq] = 0; // Store Double Quadword Using Non-Temporal Hint -OptCategory[NN_movnti] = 0; // Store Doubleword Using Non-Temporal Hint -OptCategory[NN_movntpd] = 0; // Store Packed Double-Precision Floating-Point Values Using Non-Temporal Hint -OptCategory[NN_movq2dq] = 1; // Move Quadword from MMX to XMM Register -OptCategory[NN_movsd] = 9; // Move Scalar Double-Precision Floating-Point Values -OptCategory[NN_movupd] = 9; // Move Unaligned Packed Double-Precision Floating-Point Values -OptCategory[NN_mulpd] = 1; // Multiply Packed Double-Precision Floating-Point Values -OptCategory[NN_mulsd] = 1; // Multiply Scalar Double-Precision Floating-Point Values -OptCategory[NN_orpd] = 1; // Bitwise Logical OR of Double-Precision Floating-Point Values -OptCategory[NN_paddq] = 1; // Add Packed Quadword Integers -OptCategory[NN_pause] = 1; // Spin Loop Hint -OptCategory[NN_pmuludq] = 1; // Multiply Packed Unsigned Doubleword Integers -OptCategory[NN_pshufd] = 1; // Shuffle Packed Doublewords -OptCategory[NN_pshufhw] = 1; // Shuffle Packed High Words -OptCategory[NN_pshuflw] = 1; // Shuffle Packed Low Words -OptCategory[NN_pslldq] = 1; // Shift Double Quadword Left Logical -OptCategory[NN_psrldq] = 1; // Shift Double Quadword Right Logical -OptCategory[NN_psubq] = 1; // Subtract Packed Quadword Integers -OptCategory[NN_punpckhqdq] = 1; // Unpack High Data -OptCategory[NN_punpcklqdq] = 1; // Unpack Low Data -OptCategory[NN_shufpd] = 1; // Shuffle Packed Double-Precision Floating-Point Values -OptCategory[NN_sqrtpd] = 1; // Compute Square Roots of Packed Double-Precision Floating-Point Values -OptCategory[NN_sqrtsd] = 1; // Compute Square Rootof Scalar Double-Precision Floating-Point Value -OptCategory[NN_subpd] = 1; // Subtract Packed Double-Precision Floating-Point Values -OptCategory[NN_subsd] = 1; // Subtract Scalar Double-Precision Floating-Point Values -OptCategory[NN_ucomisd] = 1; // Unordered Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS -OptCategory[NN_unpckhpd] = 1; // Unpack and Interleave High Packed Double-Precision Floating-Point Values -OptCategory[NN_unpcklpd] = 1; // Unpack and Interleave Low Packed Double-Precision Floating-Point Values -OptCategory[NN_xorpd] = 1; // Bitwise Logical OR of Double-Precision Floating-Point Values - - -// AMD syscall/sysret instructions NOTE: not AMD, found in Intel manual - -OptCategory[NN_syscall] = 1; // Low latency system call -OptCategory[NN_sysret] = 1; // Return from system call - -// AMD64 instructions NOTE: not AMD, found in Intel manual - -OptCategory[NN_swapgs] = 1; // Exchange GS base with KernelGSBase MSR - -// New Pentium instructions (SSE3) - -OptCategory[NN_movddup] = 9; // Move One Double-FP and Duplicate -OptCategory[NN_movshdup] = 9; // Move Packed Single-FP High and Duplicate -OptCategory[NN_movsldup] = 9; // Move Packed Single-FP Low and Duplicate - -// Missing AMD64 instructions NOTE: also found in Intel manual - -OptCategory[NN_movsxd] = 2; // Move with Sign-Extend Doubleword -OptCategory[NN_cmpxchg16b] = 0; // Compare and Exchange 16 Bytes - -// SSE3 instructions - -OptCategory[NN_addsubpd] = 1; // Add /Sub packed DP FP numbers -OptCategory[NN_addsubps] = 1; // Add /Sub packed SP FP numbers -OptCategory[NN_haddpd] = 1; // Add horizontally packed DP FP numbers -OptCategory[NN_haddps] = 1; // Add horizontally packed SP FP numbers -OptCategory[NN_hsubpd] = 1; // Sub horizontally packed DP FP numbers -OptCategory[NN_hsubps] = 1; // Sub horizontally packed SP FP numbers -OptCategory[NN_monitor] = 1; // Set up a linear address range to be monitored by hardware -OptCategory[NN_mwait] = 1; // Wait until write-back store performed within the range specified by the MONITOR instruction -OptCategory[NN_fisttp] = 2; // Store ST in intXX (chop) and pop -OptCategory[NN_lddqu] = 0; // Load unaligned integer 128-bit - -// SSSE3 instructions - -OptCategory[NN_psignb] = 1; // Packed SIGN Byte -OptCategory[NN_psignw] = 1; // Packed SIGN Word -OptCategory[NN_psignd] = 1; // Packed SIGN Doubleword -OptCategory[NN_pshufb] = 1; // Packed Shuffle Bytes -OptCategory[NN_pmulhrsw] = 1; // Packed Multiply High with Round and Scale -OptCategory[NN_pmaddubsw] = 1; // Multiply and Add Packed Signed and Unsigned Bytes -OptCategory[NN_phsubsw] = 1; // Packed Horizontal Subtract and Saturate -OptCategory[NN_phaddsw] = 1; // Packed Horizontal Add and Saturate -OptCategory[NN_phaddw] = 1; // Packed Horizontal Add Word -OptCategory[NN_phaddd] = 1; // Packed Horizontal Add Doubleword -OptCategory[NN_phsubw] = 1; // Packed Horizontal Subtract Word -OptCategory[NN_phsubd] = 1; // Packed Horizontal Subtract Doubleword -OptCategory[NN_palignr] = 1; // Packed Align Right -OptCategory[NN_pabsb] = 1; // Packed Absolute Value Byte -OptCategory[NN_pabsw] = 1; // Packed Absolute Value Word -OptCategory[NN_pabsd] = 1; // Packed Absolute Value Doubleword - -// VMX instructions - -OptCategory[NN_vmcall] = 1; // Call to VM Monitor -OptCategory[NN_vmclear] = 0; // Clear Virtual Machine Control Structure -OptCategory[NN_vmlaunch] = 1; // Launch Virtual Machine -OptCategory[NN_vmresume] = 1; // Resume Virtual Machine -OptCategory[NN_vmptrld] = 6; // Load Pointer to Virtual Machine Control Structure -OptCategory[NN_vmptrst] = 0; // Store Pointer to Virtual Machine Control Structure -OptCategory[NN_vmread] = 0; // Read Field from Virtual Machine Control Structure -OptCategory[NN_vmwrite] = 0; // Write Field from Virtual Machine Control Structure -OptCategory[NN_vmxoff] = 1; // Leave VMX Operation -OptCategory[NN_vmxon] = 1; // Enter VMX Operation - -OptCategory[NN_last] = 1; - - return; - -}