diff options
Diffstat (limited to 'source/distorm/decoder.c')
-rw-r--r-- | source/distorm/decoder.c | 651 |
1 files changed, 651 insertions, 0 deletions
diff --git a/source/distorm/decoder.c b/source/distorm/decoder.c new file mode 100644 index 0000000..a54e5b5 --- /dev/null +++ b/source/distorm/decoder.c @@ -0,0 +1,651 @@ +/* +decoder.c + +diStorm3 - Powerful disassembler for X86/AMD64 +http://ragestorm.net/distorm/ +distorm at gmail dot com +Copyright (C) 2003-2016 Gil Dabah +This library is licensed under the BSD license. See the file COPYING. +*/ + + +#include "decoder.h" +#include "instructions.h" +#include "insts.h" +#include "prefix.h" +#include "x86defs.h" +#include "operands.h" +#include "insts.h" +#include "distorm/mnemonics.h" +#include "compat.h" + + +/* Instruction Prefixes - Opcode - ModR/M - SIB - Displacement - Immediate */ + +static _DecodeType decode_get_effective_addr_size(_DecodeType dt, _iflags decodedPrefixes) +{ + /* + * This table is to map from the current decoding mode to an effective address size: + * Decode16 -> Decode32 + * Decode32 -> Decode16 + * Decode64 -> Decode32 + */ + static volatile _DecodeType AddrSizeTable[] = {Decode32Bits, Decode16Bits, Decode32Bits}; + + /* Switch to non default mode if prefix exists, only for ADDRESS SIZE. */ + if (decodedPrefixes & INST_PRE_ADDR_SIZE) dt = AddrSizeTable[dt]; + return dt; +} + +static _DecodeType decode_get_effective_op_size(_DecodeType dt, _iflags decodedPrefixes, unsigned int rex, _iflags instFlags) +{ + /* + * This table is to map from the current decoding mode to an effective operand size: + * Decode16 -> Decode32 + * Decode32 -> Decode16 + * Decode64 -> Decode16 + * Not that in 64bits it's a bit more complicated, because of REX and promoted instructions. + */ + static volatile _DecodeType OpSizeTable[] = {Decode32Bits, Decode16Bits, Decode16Bits}; + + if (decodedPrefixes & INST_PRE_OP_SIZE) return OpSizeTable[dt]; + + if (dt == Decode64Bits) { + /* + * REX Prefix toggles data size to 64 bits. + * Operand size prefix toggles data size to 16. + * Default data size is 32 bits. + * Promoted instructions are 64 bits if they don't require a REX perfix. + * Non promoted instructions are 64 bits if the REX prefix exists. + */ + /* Automatically promoted instructions have only INST_64BITS SET! */ + if (((instFlags & (INST_64BITS | INST_PRE_REX)) == INST_64BITS) || + /* Other instructions in 64 bits can be promoted only with a REX prefix. */ + ((decodedPrefixes & INST_PRE_REX) && (rex & PREFIX_EX_W))) dt = Decode64Bits; + else dt = Decode32Bits; /* Default. */ + } + return dt; +} + +/* A helper macro to convert from diStorm's CPU flags to EFLAGS. */ +#define CONVERT_FLAGS_TO_EFLAGS(dst, src, field) dst->field = ((src->field & D_COMPACT_SAME_FLAGS) | \ + ((src->field & D_COMPACT_IF) ? D_IF : 0) | \ + ((src->field & D_COMPACT_DF) ? D_DF : 0) | \ + ((src->field & D_COMPACT_OF) ? D_OF : 0)); + +static _DecodeResult decode_inst(_CodeInfo* ci, _PrefixState* ps, _DInst* di) +{ + /* Remember whether the instruction is privileged. */ + uint16_t privilegedFlag = 0; + + /* The ModR/M byte of the current instruction. */ + unsigned int modrm = 0; + + /* The REX/VEX prefix byte value. */ + unsigned int vrex = ps->vrex; + + /* + * Backup original input, so we can use it later if a problem occurs + * (like not enough data for decoding, invalid opcode, etc). + */ + const uint8_t* startCode = ci->code; + + /* Holds the info about the current found instruction. */ + _InstInfo* ii = NULL; + _InstInfo iip; /* Privileged instruction cache. */ + _InstSharedInfo* isi = NULL; + + /* Used only for special CMP instructions which have pseudo opcodes suffix. */ + unsigned char cmpType = 0; + + /* + * Indicates whether it is right to LOCK the instruction by decoding its first operand. + * Only then you know if it's ok to output the LOCK prefix's text... + * Used for first operand only. + */ + int lockable = FALSE; + + /* Calculate (and cache) effective-operand-size and effective-address-size only once. */ + _DecodeType effOpSz, effAdrSz; + _iflags instFlags; + + ii = inst_lookup(ci, ps); + if (ii == NULL) goto _Undecodable; + isi = &InstSharedInfoTable[ii->sharedIndex]; + instFlags = FlagsTable[isi->flagsIndex]; + privilegedFlag = ii->opcodeId & OPCODE_ID_PRIVILEGED; + + if (privilegedFlag) { + /* + * Copy the privileged instruction info so we can remove the privileged bit + * from the opcodeId field. This makes sure we're not modifying the tables + * in case we lookup this privileged instruction later. + */ + iip = *ii; + iip.opcodeId &= ~OPCODE_ID_PRIVILEGED; + ii = &iip; + } + + /* + * If both REX and OpSize are available we will have to disable the OpSize, because REX has precedence. + * However, only if REX.W is set ! + * We had to wait with this test, since the operand size may be a mandatory prefix, + * and we know it only after prefetching. + */ + if ((ps->prefixExtType == PET_REX) && + (ps->decodedPrefixes & INST_PRE_OP_SIZE) && + (!ps->isOpSizeMandatory) && + (vrex & PREFIX_EX_W)) { + ps->decodedPrefixes &= ~INST_PRE_OP_SIZE; + prefixes_ignore(ps, PFXIDX_OP_SIZE); + } + + /* + * In this point we know the instruction we are about to decode and its operands (unless, it's an invalid one!), + * so it makes it the right time for decoding-type suitability testing. + * Which practically means, don't allow 32 bits instructions in 16 bits decoding mode, but do allow + * 16 bits instructions in 32 bits decoding mode, of course... + + * NOTE: Make sure the instruction set for 32 bits has explicitly this specific flag set. + * NOTE2: Make sure the instruction set for 64 bits has explicitly this specific flag set. + + * If this is the case, drop what we've got and restart all over after DB'ing that byte. + + * Though, don't drop an instruction which is also supported in 16 and 32 bits. + */ + + /* ! ! ! DISABLED UNTIL FURTHER NOTICE ! ! ! Decode16Bits CAN NOW DECODE 32 BITS INSTRUCTIONS ! ! !*/ + /* if (ii && (dt == Decode16Bits) && (instFlags & INST_32BITS) && (~instFlags & INST_16BITS)) ii = NULL; */ + + /* Drop instructions which are invalid in 64 bits. */ + if ((ci->dt == Decode64Bits) && (instFlags & INST_INVALID_64BITS)) goto _Undecodable; + + /* If it's only a 64 bits instruction drop it in other decoding modes. */ + if ((ci->dt != Decode64Bits) && (instFlags & INST_64BITS_FETCH)) goto _Undecodable; + + if (instFlags & INST_MODRM_REQUIRED) { + /* If the ModRM byte is not part of the opcode, skip the last byte code, so code points now to ModRM. */ + if (~instFlags & INST_MODRM_INCLUDED) { + ci->code++; + if (--ci->codeLen < 0) goto _Undecodable; + } + modrm = *ci->code; + + /* Some instructions enforce that reg=000, so validate that. (Specifically EXTRQ). */ + if ((instFlags & INST_FORCE_REG0) && (((modrm >> 3) & 7) != 0)) goto _Undecodable; + /* Some instructions enforce that mod=11, so validate that. */ + if ((instFlags & INST_MODRR_REQUIRED) && (modrm < INST_DIVIDED_MODRM)) goto _Undecodable; + } + + ci->code++; /* Skip the last byte we just read (either last opcode's byte code or a ModRM). */ + + /* Cache the effective operand-size and address-size. */ + effOpSz = decode_get_effective_op_size(ci->dt, ps->decodedPrefixes, vrex, instFlags); + effAdrSz = decode_get_effective_addr_size(ci->dt, ps->decodedPrefixes); + + COMPAT(memset)(di, 0, sizeof(_DInst)); + di->base = R_NONE; + + /* + * Try to extract the next operand only if the latter exists. + * For example, if there is not first operand, no reason to try to extract second operand... + * I decided that a for-break is better for readability in this specific case than goto. + * Note: do-while with a constant 0 makes the compiler warning about it. + */ + for (;;) { + if (isi->d != OT_NONE) { + if (!operands_extract(ci, di, ii, instFlags, (_OpType)isi->d, ONT_1, modrm, ps, effOpSz, effAdrSz, &lockable)) goto _Undecodable; + } else break; + + if (isi->s != OT_NONE) { + if (!operands_extract(ci, di, ii, instFlags, (_OpType)isi->s, ONT_2, modrm, ps, effOpSz, effAdrSz, NULL)) goto _Undecodable; + } else break; + + /* Use third operand, only if the flags says this InstInfo requires it. */ + if (instFlags & INST_USE_OP3) { + if (!operands_extract(ci, di, ii, instFlags, (_OpType)((_InstInfoEx*)ii)->op3, ONT_3, modrm, ps, effOpSz, effAdrSz, NULL)) goto _Undecodable; + } else break; + + /* Support for a fourth operand is added for (i.e:) INSERTQ instruction. */ + if (instFlags & INST_USE_OP4) { + if (!operands_extract(ci, di, ii, instFlags, (_OpType)((_InstInfoEx*)ii)->op4, ONT_4, modrm, ps, effOpSz, effAdrSz, NULL)) goto _Undecodable; + } + break; + } /* Continue here after all operands were extracted. */ + + /* If it were a 3DNow! instruction, we will have to find the instruction itself now that we got its operands extracted. */ + if (instFlags & INST_3DNOW_FETCH) { + ii = inst_lookup_3dnow(ci); + if (ii == NULL) goto _Undecodable; + isi = &InstSharedInfoTable[ii->sharedIndex]; + instFlags = FlagsTable[isi->flagsIndex]; + } + + /* Check whether pseudo opcode is needed, only for CMP instructions: */ + if (instFlags & INST_PSEUDO_OPCODE) { + if (--ci->codeLen < 0) goto _Undecodable; + cmpType = *ci->code; + ci->code++; + if (instFlags & INST_PRE_VEX) { + /* AVX Comparison type must be between 0 to 32, otherwise Reserved. */ + if (cmpType >= INST_VCMP_MAX_RANGE) goto _Undecodable; + } else { + /* SSE Comparison type must be between 0 to 8, otherwise Reserved. */ + if (cmpType >= INST_CMP_MAX_RANGE) goto _Undecodable; + } + } + + /* + * There's a limit of 15 bytes on instruction length. The only way to violate + * this limit is by putting redundant prefixes before an instruction. + * start points to first prefix if any, otherwise it points to instruction first byte. + */ + if ((ci->code - ps->start) > INST_MAXIMUM_SIZE) goto _Undecodable; /* Drop instruction. */ + + /* + * If we reached here the instruction was fully decoded, we located the instruction in the DB and extracted operands. + * Use the correct mnemonic according to the DT. + * If we are in 32 bits decoding mode it doesn't necessarily mean we will choose mnemonic2, alas, + * it means that if there is a mnemonic2, it will be used. + */ + + /* Start with prefix LOCK. */ + if ((lockable == TRUE) && (instFlags & INST_PRE_LOCK)) { + ps->usedPrefixes |= INST_PRE_LOCK; + di->flags |= FLAG_LOCK; + } else if ((instFlags & INST_PRE_REPNZ) && (ps->decodedPrefixes & INST_PRE_REPNZ)) { + ps->usedPrefixes |= INST_PRE_REPNZ; + di->flags |= FLAG_REPNZ; + } else if ((instFlags & INST_PRE_REP) && (ps->decodedPrefixes & INST_PRE_REP)) { + ps->usedPrefixes |= INST_PRE_REP; + di->flags |= FLAG_REP; + } + + /* If it's JeCXZ the ADDR_SIZE prefix affects them. */ + if ((instFlags & (INST_PRE_ADDR_SIZE | INST_USE_EXMNEMONIC)) == (INST_PRE_ADDR_SIZE | INST_USE_EXMNEMONIC)) { + ps->usedPrefixes |= INST_PRE_ADDR_SIZE; + if (effAdrSz == Decode16Bits) di->opcode = ii->opcodeId; + else if (effAdrSz == Decode32Bits) di->opcode = ((_InstInfoEx*)ii)->opcodeId2; + /* Ignore REX.W in 64bits, JECXZ is promoted. */ + else /* Decode64Bits */ di->opcode = ((_InstInfoEx*)ii)->opcodeId3; + } + + /* LOOPxx instructions are also native instruction, but they are special case ones, ADDR_SIZE prefix affects them. */ + else if ((instFlags & (INST_PRE_ADDR_SIZE | INST_NATIVE)) == (INST_PRE_ADDR_SIZE | INST_NATIVE)) { + di->opcode = ii->opcodeId; + + /* If LOOPxx gets here from 64bits, it must be Decode32Bits because Address Size prefix is set. */ + ps->usedPrefixes |= INST_PRE_ADDR_SIZE; + } + /* + * Note: + * If the instruction is prefixed by operand size we will format it in the non-default decoding mode! + * So there might be a situation that an instruction of 32 bit gets formatted in 16 bits decoding mode. + * Both ways should end up with a correct and expected formatting of the text. + */ + else if (effOpSz == Decode16Bits) { /* Decode16Bits */ + + /* Set operand size. */ + FLAG_SET_OPSIZE(di, Decode16Bits); + + /* + * If it's a special instruction which has two mnemonics, then use the 16 bits one + update usedPrefixes. + * Note: use 16 bits mnemonic if that instruction supports 32 bit or 64 bit explicitly. + */ + if ((instFlags & INST_USE_EXMNEMONIC) && ((instFlags & (INST_32BITS | INST_64BITS)) == 0)) ps->usedPrefixes |= INST_PRE_OP_SIZE; + di->opcode = ii->opcodeId; + } else if (effOpSz == Decode32Bits) { /* Decode32Bits */ + + /* Set operand size. */ + FLAG_SET_OPSIZE(di, Decode32Bits); + + /* Give a chance for special mnemonic instruction in 32 bits decoding. */ + if (instFlags & INST_USE_EXMNEMONIC) { + ps->usedPrefixes |= INST_PRE_OP_SIZE; + /* Is it a special instruction which has another mnemonic for mod=11 ? */ + if (instFlags & INST_MNEMONIC_MODRM_BASED) { + if (modrm >= INST_DIVIDED_MODRM) di->opcode = ii->opcodeId; + else di->opcode = ((_InstInfoEx*)ii)->opcodeId2; + } else di->opcode = ((_InstInfoEx*)ii)->opcodeId2; + } else di->opcode = ii->opcodeId; + } else { /* Decode64Bits, note that some instructions might be decoded in Decode32Bits above. */ + + /* Set operand size. */ + FLAG_SET_OPSIZE(di, Decode64Bits); + + if (instFlags & (INST_USE_EXMNEMONIC | INST_USE_EXMNEMONIC2)) { + /* + * We shouldn't be here for MODRM based mnemonics with a MOD=11, + * because they must not use REX (otherwise it will get to the wrong instruction which share same opcode). + * See XRSTOR and XSAVEOPT. + */ + if ((instFlags & INST_MNEMONIC_MODRM_BASED) && (modrm >= INST_DIVIDED_MODRM)) goto _Undecodable; + + /* Use third mnemonic, for 64 bits. */ + if ((instFlags & INST_USE_EXMNEMONIC2) && (vrex & PREFIX_EX_W)) { + ps->usedPrefixes |= INST_PRE_REX; + di->opcode = ((_InstInfoEx*)ii)->opcodeId3; + } else di->opcode = ((_InstInfoEx*)ii)->opcodeId2; /* Use second mnemonic. */ + } else di->opcode = ii->opcodeId; + } + + /* If it's a native instruction use OpSize Prefix. */ + if ((instFlags & INST_NATIVE) && (ps->decodedPrefixes & INST_PRE_OP_SIZE)) ps->usedPrefixes |= INST_PRE_OP_SIZE; + + /* Check VEX mnemonics: */ + if ((instFlags & INST_PRE_VEX) && + (((((_InstInfoEx*)ii)->flagsEx & INST_MNEMONIC_VEXW_BASED) && (vrex & PREFIX_EX_W)) || + ((((_InstInfoEx*)ii)->flagsEx & INST_MNEMONIC_VEXL_BASED) && (vrex & PREFIX_EX_L)))) { + di->opcode = ((_InstInfoEx*)ii)->opcodeId2; + } + + /* Or is it a special CMP instruction which needs a pseudo opcode suffix ? */ + if (instFlags & INST_PSEUDO_OPCODE) { + /* + * The opcodeId is the offset to the FIRST pseudo compare mnemonic, + * we will have to fix it so it offsets into the corrected mnemonic. + * Therefore, we use another table to fix the offset. + */ + if (instFlags & INST_PRE_VEX) { + /* Use the AVX pseudo compare mnemonics table. */ + di->opcode = ii->opcodeId + VCmpMnemonicOffsets[cmpType]; + } else { + /* Use the SSE pseudo compare mnemonics table. */ + di->opcode = ii->opcodeId + CmpMnemonicOffsets[cmpType]; + } + } + + /* + * Store the address size inside the flags. + * This is necessary for the caller to know the size of rSP when using PUSHA for example. + */ + FLAG_SET_ADDRSIZE(di, effAdrSz); + + /* Copy DST_WR flag. */ + if (instFlags & INST_DST_WR) di->flags |= FLAG_DST_WR; + + /* Set the unused prefixes mask. */ + di->unusedPrefixesMask = prefixes_set_unused_mask(ps); + + /* Fix privileged. Assumes the privilegedFlag is 0x8000 only. */ + di->flags |= privilegedFlag; + + /* Copy instruction meta. */ + di->meta = isi->meta; + if (di->segment == 0) di->segment = R_NONE; + + /* Take into account the O_MEM base register for the mask. */ + if (di->base != R_NONE) di->usedRegistersMask |= _REGISTERTORCLASS[di->base]; + + /* Copy CPU affected flags. */ + CONVERT_FLAGS_TO_EFLAGS(di, isi, modifiedFlagsMask); + CONVERT_FLAGS_TO_EFLAGS(di, isi, testedFlagsMask); + CONVERT_FLAGS_TO_EFLAGS(di, isi, undefinedFlagsMask); + + /* Calculate the size of the instruction we've just decoded. */ + di->size = (uint8_t)((ci->code - startCode) & 0xff); + return DECRES_SUCCESS; + +_Undecodable: /* If the instruction couldn't be decoded for some reason, drop the first byte. */ + COMPAT(memset)(di, 0, sizeof(_DInst)); + di->base = R_NONE; + + di->size = 1; + /* Clean prefixes just in case... */ + ps->usedPrefixes = 0; + + /* Special case for WAIT instruction: If it's dropped, you have to return a valid instruction! */ + if (*startCode == INST_WAIT_INDEX) { + di->opcode = I_WAIT; + META_SET_ISC(di, ISC_INTEGER); + return DECRES_SUCCESS; + } + + /* Mark that we didn't manage to decode the instruction well, caller will drop it. */ + return DECRES_INPUTERR; +} + +/* + * decode_internal + * + * supportOldIntr - Since now we work with new structure instead of the old _DecodedInst, we are still interested in backward compatibility. + * So although, the array is now of type _DInst, we want to read it in jumps of the old array element's size. + * This is in order to save memory allocation for conversion between the new and the old structures. + * It really means we can do the conversion in-place now. + */ +_DecodeResult decode_internal(_CodeInfo* _ci, int supportOldIntr, _DInst result[], unsigned int maxResultCount, unsigned int* usedInstructionsCount) +{ + _PrefixState ps; + unsigned int prefixSize; + _CodeInfo ci; + unsigned int features; + unsigned int mfc; + + _OffsetType codeOffset = _ci->codeOffset; + const uint8_t* code = _ci->code; + int codeLen = _ci->codeLen; + + /* + * This is used for printing only, it is the real offset of where the whole instruction begins. + * We need this variable in addition to codeOffset, because prefixes might change the real offset an instruction begins at. + * So we keep track of both. + */ + _OffsetType startInstOffset = 0; + + const uint8_t* p; + + /* Current working decoded instruction in results. */ + unsigned int nextPos = 0; + _DInst *pdi = NULL; + + _OffsetType addrMask = (_OffsetType)-1; + + _DecodeResult decodeResult; + +#ifdef DISTORM_LIGHT + (void) supportOldIntr; /* Unreferenced. */ + + /* + * Only truncate address if we are using the decompose interface. + * Otherwise, we use the textual interface which needs full addresses for formatting bytes output. + * So distorm_format will truncate later. + */ + if (_ci->features & DF_MAXIMUM_ADDR32) addrMask = 0xffffffff; + else if (_ci->features & DF_MAXIMUM_ADDR16) addrMask = 0xffff; +#endif + + /* No entries are used yet. */ + *usedInstructionsCount = 0; + ci.dt = _ci->dt; + _ci->nextOffset = codeOffset; + + /* Decode instructions as long as we have what to decode/enough room in entries. */ + while (codeLen > 0) { + + /* startInstOffset holds the displayed offset of current instruction. */ + startInstOffset = codeOffset; + + COMPAT(memset)(&ps, 0, (size_t)((char*)&ps.pfxIndexer[0] - (char*)&ps)); + COMPAT(memset)(ps.pfxIndexer, PFXIDX_NONE, sizeof(int) * PFXIDX_MAX); + ps.start = code; + ps.last = code; + prefixSize = 0; + + if (prefixes_is_valid(*code, ci.dt)) { + prefixes_decode(code, codeLen, &ps, ci.dt); + /* Count prefixes, start points to first prefix. */ + prefixSize = (unsigned int)(ps.last - ps.start); + /* + * It might be that we will just notice that we ran out of bytes, or only prefixes + * so we will have to drop everything and halt. + * Also take into consideration of flow control instruction filter. + */ + codeLen -= prefixSize; + if ((codeLen == 0) || (prefixSize == INST_MAXIMUM_SIZE)) { + if (~_ci->features & DF_RETURN_FC_ONLY) { + /* Make sure there is enough room. */ + if (nextPos + (ps.last - code) > maxResultCount) return DECRES_MEMORYERR; + + for (p = code; p < ps.last; p++, startInstOffset++) { + /* Use next entry. */ +#ifndef DISTORM_LIGHT + if (supportOldIntr) { + pdi = (_DInst*)((char*)result + nextPos * sizeof(_DecodedInst)); + } + else +#endif /* DISTORM_LIGHT */ + { + pdi = &result[nextPos]; + } + nextPos++; + COMPAT(memset)(pdi, 0, sizeof(_DInst)); + + pdi->flags = FLAG_NOT_DECODABLE; + pdi->imm.byte = *p; + pdi->size = 1; + pdi->addr = startInstOffset & addrMask; + } + *usedInstructionsCount = nextPos; /* Include them all. */ + } + if (codeLen == 0) break; /* Bye bye, out of bytes. */ + } + code += prefixSize; + codeOffset += prefixSize; + + /* If we got only prefixes continue to next instruction. */ + if (prefixSize == INST_MAXIMUM_SIZE) continue; + } + + /* + * Now we decode the instruction and only then we do further prefixes handling. + * This is because the instruction could not be decoded at all, or an instruction requires + * a mandatory prefix, or some of the prefixes were useless, etc... + + * Even if there were a mandatory prefix, we already took into account its size as a normal prefix. + * so prefixSize includes that, and the returned size in pdi is simply the size of the real(=without prefixes) instruction. + */ + if (ci.dt == Decode64Bits) { + if (ps.decodedPrefixes & INST_PRE_REX) { + /* REX prefix must precede first byte of instruction. */ + if (ps.rexPos != (code - 1)) { + ps.decodedPrefixes &= ~INST_PRE_REX; + ps.prefixExtType = PET_NONE; + prefixes_ignore(&ps, PFXIDX_REX); + } + /* + * We will disable operand size prefix, + * if it exists only after decoding the instruction, since it might be a mandatory prefix. + * This will be done after calling inst_lookup in decode_inst. + */ + } + /* In 64 bits, segment overrides of CS, DS, ES and SS are ignored. So don't take'em into account. */ + if (ps.decodedPrefixes & INST_PRE_SEGOVRD_MASK32) { + ps.decodedPrefixes &= ~INST_PRE_SEGOVRD_MASK32; + prefixes_ignore(&ps, PFXIDX_SEG); + } + } + + /* Make sure there is at least one more entry to use, for the upcoming instruction. */ + if (nextPos + 1 > maxResultCount) return DECRES_MEMORYERR; +#ifndef DISTORM_LIGHT + if (supportOldIntr) { + pdi = (_DInst*)((char*)result + nextPos * sizeof(_DecodedInst)); + } + else +#endif /* DISTORM_LIGHT */ + { + pdi = &result[nextPos]; + } + nextPos++; + + /* + * The reason we copy these two again is because we have to keep track on the input ourselves. + * There might be a case when an instruction is invalid, and then it will be counted as one byte only. + * But that instruction already read a byte or two from the stream and only then returned the error. + * Thus, we end up unsynchronized on the stream. + * This way, we are totally safe, because we keep track after the call to decode_inst, using the returned size. + */ + ci.code = code; + ci.codeLen = codeLen; + /* Nobody uses codeOffset in the decoder itself, so spare it. */ + + decodeResult = decode_inst(&ci, &ps, pdi); + + /* See if we need to filter this instruction. */ + if ((_ci->features & DF_RETURN_FC_ONLY) && (META_GET_FC(pdi->meta) == FC_NONE)) decodeResult = DECRES_FILTERED; + + /* Set address to the beginning of the instruction. */ + pdi->addr = startInstOffset & addrMask; + /* pdi->disp &= addrMask; */ + + if ((decodeResult == DECRES_INPUTERR) && (ps.decodedPrefixes & INST_PRE_VEX)) { + if (ps.prefixExtType == PET_VEX3BYTES) { + prefixSize -= 2; + codeLen += 2; + } else if (ps.prefixExtType == PET_VEX2BYTES) { + prefixSize -= 1; + codeLen += 1; + } + ps.last = ps.start + prefixSize - 1; + code = ps.last + 1; + codeOffset = startInstOffset + prefixSize; + } else { + /* Advance to next instruction. */ + codeLen -= pdi->size; + codeOffset += pdi->size; + code += pdi->size; + + /* Instruction's size should include prefixes. */ + pdi->size += (uint8_t)prefixSize; + } + + /* Drop all prefixes and the instruction itself, because the instruction wasn't successfully decoded. */ + if ((decodeResult == DECRES_INPUTERR) && (~_ci->features & DF_RETURN_FC_ONLY)) { + nextPos--; /* Undo last result. */ + if ((prefixSize + 1) > 0) { /* 1 for the first instruction's byte. */ + if ((nextPos + prefixSize + 1) > maxResultCount) return DECRES_MEMORYERR; + + for (p = ps.start; p < ps.last + 1; p++, startInstOffset++) { + /* Use next entry. */ +#ifndef DISTORM_LIGHT + if (supportOldIntr) { + pdi = (_DInst*)((char*)result + nextPos * sizeof(_DecodedInst)); + } + else +#endif /* DISTORM_LIGHT */ + { + pdi = &result[nextPos]; + } + nextPos++; + + COMPAT(memset)(pdi, 0, sizeof(_DInst)); + pdi->flags = FLAG_NOT_DECODABLE; + pdi->imm.byte = *p; + pdi->size = 1; + pdi->addr = startInstOffset & addrMask; + } + } + } else if (decodeResult == DECRES_FILTERED) nextPos--; /* Return it to pool, since it was filtered. */ + + /* Alright, the caller can read, at least, up to this one. */ + *usedInstructionsCount = nextPos; + /* Fix next offset. */ + _ci->nextOffset = codeOffset; + + /* Check whether we need to stop on any flow control instruction. */ + features = _ci->features; + mfc = META_GET_FC(pdi->meta); + if ((decodeResult == DECRES_SUCCESS) && (features & DF_STOP_ON_FLOW_CONTROL)) { + if (((features & DF_STOP_ON_CALL) && (mfc == FC_CALL)) || + ((features & DF_STOP_ON_RET) && (mfc == FC_RET)) || + ((features & DF_STOP_ON_SYS) && (mfc == FC_SYS)) || + ((features & DF_STOP_ON_UNC_BRANCH) && (mfc == FC_UNC_BRANCH)) || + ((features & DF_STOP_ON_CND_BRANCH) && (mfc == FC_CND_BRANCH)) || + ((features & DF_STOP_ON_INT) && (mfc == FC_INT)) || + ((features & DF_STOP_ON_CMOV) && (mfc == FC_CMOV))) + return DECRES_SUCCESS; + } + } + + return DECRES_SUCCESS; +} |