/* * decode - Reads the appropriate instruction table to obtain the unique ID of * an instruction. * * @param type - See modRMRequired(). * @param insnContext - See modRMRequired(). * @param opcode - See modRMRequired(). * @param modRM - The ModR/M byte if required, or any value if not. * @return - The UID of the instruction, or 0 on failure. */ static InstrUID decode(OpcodeType type, InstructionContext insnContext, uint8_t opcode, uint8_t modRM) { const struct ModRMDecision* dec = 0; switch (type) { case ONEBYTE: dec = &ONEBYTE_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode]; break; case TWOBYTE: dec = &TWOBYTE_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode]; break; case THREEBYTE_38: dec = &THREEBYTE38_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode]; break; case THREEBYTE_3A: dec = &THREEBYTE3A_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode]; break; case THREEBYTE_A6: dec = &THREEBYTEA6_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode]; break; case THREEBYTE_A7: dec = &THREEBYTEA7_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode]; break; } switch (dec->modrm_type) { default: debug("Corrupt table! Unknown modrm_type"); return 0; case MODRM_ONEENTRY: return modRMTable[dec->instructionIDs]; case MODRM_SPLITRM: if (modFromModRM(modRM) == 0x3) return modRMTable[dec->instructionIDs+1]; return modRMTable[dec->instructionIDs]; case MODRM_SPLITREG: if (modFromModRM(modRM) == 0x3) return modRMTable[dec->instructionIDs+((modRM & 0x38) >> 3)+8]; return modRMTable[dec->instructionIDs+((modRM & 0x38) >> 3)]; case MODRM_FULL: return modRMTable[dec->instructionIDs+modRM]; } }
/* * decode - Reads the appropriate instruction table to obtain the unique ID of * an instruction. * * @param type - See modRMRequired(). * @param insnContext - See modRMRequired(). * @param opcode - See modRMRequired(). * @param modRM - The ModR/M byte if required, or any value if not. */ static InstrUID decode(OpcodeType type, InstructionContext insnContext, uint8_t opcode, uint8_t modRM) { struct ModRMDecision* dec; switch (type) { default: unreachable("Unknown opcode type"); case ONEBYTE: dec = &ONEBYTE_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode]; break; case TWOBYTE: dec = &TWOBYTE_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode]; break; case THREEBYTE_38: dec = &THREEBYTE38_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode]; break; case THREEBYTE_3A: dec = &THREEBYTE3A_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode]; break; } switch (dec->modrm_type) { default: unreachable("Corrupt table! Unknown modrm_type"); case MODRM_ONEENTRY: return dec->instructionIDs[0]; case MODRM_SPLITRM: if (modFromModRM(modRM) == 0x3) return dec->instructionIDs[1]; else return dec->instructionIDs[0]; case MODRM_FULL: return dec->instructionIDs[modRM]; } return 0; }
/* * readSIB - Consumes the SIB byte to determine addressing information for an * instruction. * * @param insn - The instruction whose SIB byte is to be read. * @return - 0 if the SIB byte was successfully read; nonzero otherwise. */ static int readSIB(struct InternalInstruction* insn) { SIBIndex sibIndexBase = 0; SIBBase sibBaseBase = 0; uint8_t index, base; dbgprintf(insn, "readSIB()"); if (insn->consumedSIB) return 0; insn->consumedSIB = TRUE; switch (insn->addressSize) { case 2: dbgprintf(insn, "SIB-based addressing doesn't work in 16-bit mode"); return -1; break; case 4: sibIndexBase = SIB_INDEX_EAX; sibBaseBase = SIB_BASE_EAX; break; case 8: sibIndexBase = SIB_INDEX_RAX; sibBaseBase = SIB_BASE_RAX; break; } if (consumeByte(insn, &insn->sib)) return -1; index = indexFromSIB(insn->sib) | (xFromREX(insn->rexPrefix) << 3); switch (index) { case 0x4: insn->sibIndex = SIB_INDEX_NONE; break; default: insn->sibIndex = (SIBIndex)(sibIndexBase + index); if (insn->sibIndex == SIB_INDEX_sib || insn->sibIndex == SIB_INDEX_sib64) insn->sibIndex = SIB_INDEX_NONE; break; } switch (scaleFromSIB(insn->sib)) { case 0: insn->sibScale = 1; break; case 1: insn->sibScale = 2; break; case 2: insn->sibScale = 4; break; case 3: insn->sibScale = 8; break; } base = baseFromSIB(insn->sib) | (bFromREX(insn->rexPrefix) << 3); switch (base) { case 0x5: switch (modFromModRM(insn->modRM)) { case 0x0: insn->eaDisplacement = EA_DISP_32; insn->sibBase = SIB_BASE_NONE; break; case 0x1: insn->eaDisplacement = EA_DISP_8; insn->sibBase = (insn->addressSize == 4 ? SIB_BASE_EBP : SIB_BASE_RBP); break; case 0x2: insn->eaDisplacement = EA_DISP_32; insn->sibBase = (insn->addressSize == 4 ? SIB_BASE_EBP : SIB_BASE_RBP); break; case 0x3: debug("Cannot have Mod = 0b11 and a SIB byte"); return -1; } break; default: insn->sibBase = (SIBBase)(sibBaseBase + base); break; } return 0; }
/* * readModRM - Consumes all addressing information (ModR/M byte, SIB byte, and * displacement) for an instruction and interprets it. * * @param insn - The instruction whose addressing information is to be read. * @return - 0 if the information was successfully read; nonzero otherwise. */ static int readModRM(struct InternalInstruction* insn) { uint8_t mod, rm, reg; dbgprintf(insn, "readModRM()"); if (insn->consumedModRM) return 0; if (consumeByte(insn, &insn->modRM)) return -1; insn->consumedModRM = TRUE; mod = modFromModRM(insn->modRM); rm = rmFromModRM(insn->modRM); reg = regFromModRM(insn->modRM); /* * This goes by insn->registerSize to pick the correct register, which messes * up if we're using (say) XMM or 8-bit register operands. That gets fixed in * fixupReg(). */ switch (insn->registerSize) { case 2: insn->regBase = MODRM_REG_AX; insn->eaRegBase = EA_REG_AX; break; case 4: insn->regBase = MODRM_REG_EAX; insn->eaRegBase = EA_REG_EAX; break; case 8: insn->regBase = MODRM_REG_RAX; insn->eaRegBase = EA_REG_RAX; break; } reg |= rFromREX(insn->rexPrefix) << 3; rm |= bFromREX(insn->rexPrefix) << 3; insn->reg = (Reg)(insn->regBase + reg); switch (insn->addressSize) { case 2: insn->eaBaseBase = EA_BASE_BX_SI; switch (mod) { case 0x0: if (rm == 0x6) { insn->eaBase = EA_BASE_NONE; insn->eaDisplacement = EA_DISP_16; if (readDisplacement(insn)) return -1; } else { insn->eaBase = (EABase)(insn->eaBaseBase + rm); insn->eaDisplacement = EA_DISP_NONE; } break; case 0x1: insn->eaBase = (EABase)(insn->eaBaseBase + rm); insn->eaDisplacement = EA_DISP_8; if (readDisplacement(insn)) return -1; break; case 0x2: insn->eaBase = (EABase)(insn->eaBaseBase + rm); insn->eaDisplacement = EA_DISP_16; if (readDisplacement(insn)) return -1; break; case 0x3: insn->eaBase = (EABase)(insn->eaRegBase + rm); if (readDisplacement(insn)) return -1; break; } break; case 4: case 8: insn->eaBaseBase = (insn->addressSize == 4 ? EA_BASE_EAX : EA_BASE_RAX); switch (mod) { case 0x0: insn->eaDisplacement = EA_DISP_NONE; /* readSIB may override this */ switch (rm) { case 0x4: case 0xc: /* in case REXW.b is set */ insn->eaBase = (insn->addressSize == 4 ? EA_BASE_sib : EA_BASE_sib64); readSIB(insn); if (readDisplacement(insn)) return -1; break; case 0x5: insn->eaBase = EA_BASE_NONE; insn->eaDisplacement = EA_DISP_32; if (readDisplacement(insn)) return -1; break; default: insn->eaBase = (EABase)(insn->eaBaseBase + rm); break; } break; case 0x1: case 0x2: insn->eaDisplacement = (mod == 0x1 ? EA_DISP_8 : EA_DISP_32); switch (rm) { case 0x4: case 0xc: /* in case REXW.b is set */ insn->eaBase = EA_BASE_sib; readSIB(insn); if (readDisplacement(insn)) return -1; break; default: insn->eaBase = (EABase)(insn->eaBaseBase + rm); if (readDisplacement(insn)) return -1; break; } break; case 0x3: insn->eaDisplacement = EA_DISP_NONE; insn->eaBase = (EABase)(insn->eaRegBase + rm); break; } break; } /* switch (insn->addressSize) */ return 0; }