VirtualBox

Changeset 41781 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jun 16, 2012 7:02:30 PM (13 years ago)
Author:
vboxsync
Message:

DIS: Prefetch instruction bytes before starting to disassemble, inline all fetchers. Poison the state a bit in strict builds.

Location:
trunk/src/VBox/Disassembler
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Disassembler/DisasmCore.cpp

    r41760 r41781  
    2626#include <VBox/log.h>
    2727#include <iprt/assert.h>
     28#include <iprt/param.h>
    2829#include <iprt/string.h>
    2930#include <iprt/stdarg.h>
     
    4647*   Internal Functions                                                         *
    4748*******************************************************************************/
    48 static int      disInstrWorker(PDISCPUSTATE pCpu, RTUINTPTR uInstrAddr, PCDISOPCODE paOneByteMap, uint32_t *pcbInstr);
    49 static unsigned disParseInstruction(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISCPUSTATE pCpu);
    50 
    51 static unsigned QueryModRM(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu, unsigned *pSibInc = NULL);
    52 static unsigned QueryModRM_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu, unsigned *pSibInc = NULL);
    53 static void     UseSIB(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu);
    54 static unsigned ParseSIB_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu);
    55 
    5649static void     disasmModRMReg(PDISCPUSTATE pCpu, PCDISOPCODE pOp, unsigned idx, PDISOPPARAM pParam, int fRegAddr);
    5750static void     disasmModRMReg16(PDISCPUSTATE pCpu, PCDISOPCODE pOp, unsigned idx, PDISOPPARAM pParam);
    5851static void     disasmModRMSReg(PDISCPUSTATE pCpu, PCDISOPCODE pOp, unsigned idx, PDISOPPARAM pParam);
    59 
    60 static void     disValidateLockSequence(PDISCPUSTATE pCpu);
    61 
    62 /* Read functions */
    63 static uint8_t  disReadByte(PDISCPUSTATE pCpu, RTUINTPTR pAddress);
    64 static uint16_t disReadWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress);
    65 static uint32_t disReadDWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress);
    66 static uint64_t disReadQWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress);
    67 static DECLCALLBACK(int) disReadBytesDefault(PDISCPUSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead);
    6852
    6953
     
    227211
    228212
     213
     214
     215
     216//*****************************************************************************
     217/* Read functions for getting the opcode bytes */
     218//*****************************************************************************
     219
     220
    229221/**
    230  * Parses one guest instruction.
     222 * @interface_method_impl{FNDISREADBYTES, The default byte reader callber.}
     223 */
     224static DECLCALLBACK(int) disReadBytesDefault(PDISCPUSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
     225{
     226#ifdef IN_RING0
     227    AssertMsgFailed(("disReadWord with no read callback in ring 0!!\n"));
     228    RT_BZERO(&pDis->abInstr[offInstr], cbMaxRead);
     229    pDis->cbCachedInstr = offInstr + cbMaxRead;
     230    return VERR_DIS_NO_READ_CALLBACK;
     231#else
     232    uint8_t const  *pbSrc        = (uint8_t const *)(uintptr_t)pDis->uInstrAddr + offInstr;
     233    size_t          cbLeftOnPage = (uintptr_t)pbSrc & PAGE_OFFSET_MASK;
     234    uint8_t         cbToRead     = cbLeftOnPage >= cbMaxRead
     235                                 ? cbMaxRead
     236                                 : cbLeftOnPage <= cbMinRead
     237                                 ? cbMinRead
     238                                 : (uint8_t)cbLeftOnPage;
     239    memcpy(&pDis->abInstr[offInstr], pbSrc, cbToRead);
     240    pDis->cbCachedInstr = offInstr + cbToRead;
     241    return VINF_SUCCESS;
     242#endif
     243}
     244
     245
     246/**
     247 * Read more bytes into the DISCPUSTATE::abInstr buffer, advance
     248 * DISCPUSTATE::cbCachedInstr.
    231249 *
    232  * The result is found in pCpu and pcbInstr.
     250 * Will set DISCPUSTATE::rc on failure, but still advance cbCachedInstr.
    233251 *
    234  * @returns VBox status code.
    235  * @param   pvInstr         Address of the instruction to decode.  This is a
    236  *                          real address in the current context that can be
    237  *                          accessed without faulting.  (Consider
    238  *                          DISInstrWithReader if this isn't the case.)
    239  * @param   enmCpuMode      The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
    240  * @param   pfnReadBytes    Callback for reading instruction bytes.
    241  * @param   pvUser          User argument for the instruction reader. (Ends up in pvUser.)
    242  * @param   pCpu            Pointer to cpu structure. Will be initialized.
    243  * @param   pcbInstr        Where to store the size of the instruction.
    244  *                          NULL is allowed.  This is also stored in
    245  *                          PDISCPUSTATE::cbInstr.
     252 * The caller shall fend off reads beyond the DISCPUSTATE::abInstr buffer.
     253 *
     254 * @param   pCpu                The disassembler state.
     255 * @param   off                 The offset of the read request.
     256 * @param   cbMin               The size of the read request that needs to be
     257 *                              satisfied.
    246258 */
    247 DISDECL(int) DISInstr(const void *pvInstr, DISCPUMODE enmCpuMode, PDISCPUSTATE pCpu, uint32_t *pcbInstr)
    248 {
    249     return DISInstEx((uintptr_t)pvInstr, enmCpuMode, DISOPTYPE_ALL, NULL /*pfnReadBytes*/, NULL /*pvUser*/, pCpu, pcbInstr);
     259DECL_NO_INLINE(static, void) disReadMore(PDISCPUSTATE pCpu, uint8_t off, uint8_t cbMin)
     260{
     261    Assert(cbMin + off <= sizeof(pCpu->abInstr));
     262
     263    /*
     264     * Adjust the incoming request to not overlap with bytes that has already
     265     * been read and to make sure we don't leave unread gaps.
     266     */
     267    if (off < pCpu->cbCachedInstr)
     268    {
     269        Assert(off + cbMin > pCpu->cbCachedInstr);
     270        cbMin -= pCpu->cbCachedInstr - off;
     271        off = pCpu->cbCachedInstr;
     272    }
     273    else if (off > pCpu->cbCachedInstr)
     274    {
     275        cbMin += off - pCpu->cbCachedInstr;
     276        off = pCpu->cbCachedInstr;
     277    }
     278
     279    /*
     280     * Do the read.
     281     * (No need to zero anything on failure as abInstr is already zeroed by the
     282     * DISInstrEx API.)
     283     */
     284    int rc = pCpu->pfnReadBytes(pCpu, off, cbMin, sizeof(pCpu->abInstr) - off);
     285    if (RT_SUCCESS(rc))
     286    {
     287        Assert(pCpu->cbCachedInstr >= off + cbMin);
     288        Assert(pCpu->cbCachedInstr <= sizeof(pCpu->abInstr));
     289    }
     290    else
     291    {
     292        Log(("disReadMore failed with rc=%Rrc!!\n", rc));
     293        pCpu->rc = VERR_DIS_MEM_READ;
     294    }
    250295}
    251296
    252297
    253298/**
    254  * Parses one guest instruction.
     299 * Function for handling a 8-bit cache miss.
    255300 *
    256  * The result is found in pCpu and pcbInstr.
     301 * @returns The requested byte.
     302 * @param   pCpu                The disassembler state.
     303 * @param   off                 The offset of the byte relative to the
     304 *                              instruction.
     305 */
     306DECL_NO_INLINE(static, uint8_t) disReadByteSlow(PDISCPUSTATE pCpu, RTUINTPTR off)
     307{
     308    if (RT_UNLIKELY(off >= DIS_MAX_INSTR_LENGTH))
     309    {
     310        Log(("disReadByte: too long instruction...\n"));
     311        pCpu->rc = VERR_DIS_TOO_LONG_INSTR;
     312        return 0;
     313    }
     314
     315    if (off <= pCpu->cbCachedInstr)
     316        disReadMore(pCpu, off, 1);
     317
     318    return pCpu->abInstr[off];
     319}
     320
     321
     322/**
     323 * Read a byte (8-bit) instruction byte by offset.
    257324 *
    258  * @returns VBox status code.
    259  * @param   uInstrAddr      Address of the instruction to decode. What this means
    260  *                          is left to the pfnReadBytes function.
    261  * @param   enmCpuMode      The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
    262  * @param   pfnReadBytes    Callback for reading instruction bytes.
    263  * @param   pvUser          User argument for the instruction reader. (Ends up in pvUser.)
    264  * @param   pCpu            Pointer to cpu structure. Will be initialized.
    265  * @param   pcbInstr        Where to store the size of the instruction.
    266  *                          NULL is allowed.  This is also stored in
    267  *                          PDISCPUSTATE::cbInstr.
     325 * @returns The requested byte.
     326 * @param   pCpu                The disassembler state.
     327 * @param   uAddress            The address.
    268328 */
    269 DISDECL(int) DISInstrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser,
    270                                 PDISCPUSTATE pCpu, uint32_t *pcbInstr)
    271 {
    272     return DISInstEx(uInstrAddr, enmCpuMode, DISOPTYPE_ALL, pfnReadBytes, pvUser, pCpu, pcbInstr);
     329DECLINLINE(uint8_t) disReadByteByOff(PDISCPUSTATE pCpu, RTUINTPTR off)
     330{
     331    if (RT_UNLIKELY(off >= pCpu->cbCachedInstr))
     332        return disReadByteSlow(pCpu, off);
     333
     334    return pCpu->abInstr[off];
    273335}
    274336
    275337
    276338/**
    277  * Disassembles on instruction, details in @a pCpu and length in @a pcbInstr.
     339 * Read a byte (8-bit) instruction byte.
    278340 *
    279  * @returns VBox status code.
    280  * @param   uInstrAddr      Address of the instruction to decode. What this means
    281  *                          is left to the pfnReadBytes function.
    282  * @param   enmCpuMode      The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
    283  * @param   pfnReadBytes    Callback for reading instruction bytes.
    284  * @param   fFilter         Instruction type filter.
    285  * @param   pvUser          User argument for the instruction reader. (Ends up in pvUser.)
    286  * @param   pCpu            Pointer to CPU structure. With the exception of
    287  *                          DISCPUSTATE::pvUser2, the structure will be
    288  *                          completely initialized by this API, i.e. no input is
    289  *                          taken from it.
    290  * @param   pcbInstr        Where to store the size of the instruction.  (This
    291  *                          is also stored in PDISCPUSTATE::cbInstr.)  Optional.
     341 * @returns The requested byte.
     342 * @param   pCpu                The disassembler state.
     343 * @param   uAddress            The address.
    292344 */
    293 DISDECL(int) DISInstEx(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter,
    294                        PFNDISREADBYTES pfnReadBytes, void *pvUser,
    295                        PDISCPUSTATE pCpu, uint32_t *pcbInstr)
    296 {
    297     PCDISOPCODE paOneByteMap;
    298 
    299     /*
    300      * Initialize the CPU state.
    301      * Note! The RT_BZERO make ASSUMPTIONS about the placement of pvUser2.
    302      */
    303     RT_BZERO(pCpu, RT_OFFSETOF(DISCPUSTATE, pvUser2));
    304 
    305     pCpu->uCpuMode          = enmCpuMode;
    306     if (enmCpuMode == DISCPUMODE_64BIT)
    307     {
    308         paOneByteMap        = g_aOneByteMapX64;
    309         pCpu->uAddrMode     = DISCPUMODE_64BIT;
    310         pCpu->uOpMode       = DISCPUMODE_32BIT;
    311     }
    312     else
    313     {
    314         paOneByteMap        = g_aOneByteMapX86;
    315         pCpu->uAddrMode     = enmCpuMode;
    316         pCpu->uOpMode       = enmCpuMode;
    317     }
    318     pCpu->fPrefix           = DISPREFIX_NONE;
    319     pCpu->idxSegPrefix      = DISSELREG_DS;
    320     pCpu->uInstrAddr        = uInstrAddr;
    321     pCpu->pfnDisasmFnTable  = g_apfnFullDisasm;
    322     pCpu->fFilter           = fFilter;
    323     pCpu->rc                = VINF_SUCCESS;
    324     pCpu->pfnReadBytes      = pfnReadBytes ? pfnReadBytes : disReadBytesDefault;
    325     pCpu->pvUser    = pvUser;
    326 
    327     return disInstrWorker(pCpu, uInstrAddr, paOneByteMap, pcbInstr);
     345DECL_FORCE_INLINE(uint8_t) disReadByte(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
     346{
     347    return disReadByteByOff(pCpu, uAddress - pCpu->uInstrAddr);
    328348}
    329349
    330350
    331351/**
    332  * Internal worker for DISInstEx.
     352 * Function for handling a 16-bit cache miss.
    333353 *
    334  * @returns VBox status code.
    335  * @param   pCpu            Initialized cpu state.
    336  * @param   paOneByteMap    The one byte opcode map to use.
    337  * @param   uInstrAddr      Instruction address.
    338  * @param   pcbInstr        Where to store the instruction size. Can be NULL.
     354 * @returns The requested word.
     355 * @param   pCpu                The disassembler state.
     356 * @param   off                 The offset of the word relative to the
     357 *                              instruction.
    339358 */
    340 static int disInstrWorker(PDISCPUSTATE pCpu, RTUINTPTR uInstrAddr, PCDISOPCODE paOneByteMap, uint32_t *pcbInstr)
    341 {
    342     /*
    343      * Parse byte by byte.
    344      */
    345     unsigned  iByte = 0;
    346     unsigned  cbInc;
    347     for (;;)
    348     {
    349         uint8_t codebyte = disReadByte(pCpu, uInstrAddr+iByte);
    350         uint8_t opcode   = paOneByteMap[codebyte].uOpcode;
    351 
    352         /* Hardcoded assumption about OP_* values!! */
    353         if (opcode <= OP_LAST_PREFIX)
     359DECL_NO_INLINE(static, uint16_t) disReadWordSlow(PDISCPUSTATE pCpu, RTUINTPTR off)
     360{
     361    if (RT_UNLIKELY(off + 2 > DIS_MAX_INSTR_LENGTH))
     362    {
     363        Log(("disReadWord: too long instruction...\n"));
     364        pCpu->rc = VERR_DIS_TOO_LONG_INSTR;
     365        if (off < DIS_MAX_INSTR_LENGTH)
     366            return pCpu->abInstr[off];
     367        return 0;
     368    }
     369
     370    if (off + 2 < pCpu->cbCachedInstr)
     371        disReadMore(pCpu, off, 2);
     372
     373#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
     374    return *(uint16_t const *)&pCpu->abInstr[off];
     375#else
     376    return RT_MAKE_U16(pCpu->abInstr[off], pCpu->abInstr[off + 1]);
     377#endif
     378}
     379
     380
     381/**
     382 * Read a word (16-bit) instruction byte by offset.
     383 *
     384 * @returns The requested word.
     385 * @param   pCpu                The disassembler state.
     386 * @param   uAddress            The address.
     387 */
     388DECLINLINE(uint16_t) disReadWordByOff(PDISCPUSTATE pCpu, RTUINTPTR off)
     389{
     390    if (RT_UNLIKELY(off + 2 > pCpu->cbCachedInstr))
     391        return disReadWordSlow(pCpu, off);
     392
     393#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
     394    return *(uint16_t const *)&pCpu->abInstr[off];
     395#else
     396    return RT_MAKE_U16(pCpu->abInstr[off], pCpu->abInstr[off + 1]);
     397#endif
     398}
     399
     400
     401/**
     402 * Read a word (16-bit) instruction byte.
     403 *
     404 * @returns The requested word.
     405 * @param   pCpu                The disassembler state.
     406 * @param   uAddress            The address.
     407 */
     408DECL_FORCE_INLINE(uint16_t) disReadWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
     409{
     410    return disReadWordByOff(pCpu, uAddress - pCpu->uInstrAddr);
     411}
     412
     413
     414/**
     415 * Function for handling a 32-bit cache miss.
     416 *
     417 * @returns The requested dword.
     418 * @param   pCpu                The disassembler state.
     419 * @param   off                 The offset of the dword relative to the
     420 *                              instruction.
     421 */
     422DECL_NO_INLINE(static, uint32_t) disReadDWordSlow(PDISCPUSTATE pCpu, RTUINTPTR off)
     423{
     424    if (RT_UNLIKELY(off + 2 > DIS_MAX_INSTR_LENGTH))
     425    {
     426        Log(("disReadDWord: too long instruction...\n"));
     427        pCpu->rc = VERR_DIS_TOO_LONG_INSTR;
     428        switch ((RTUINTPTR)DIS_MAX_INSTR_LENGTH - off)
    354429        {
    355             /* The REX prefix must precede the opcode byte(s). Any other placement is ignored. */
    356             if (opcode != OP_REX)
    357             {
    358                 /** Last prefix byte (for SSE2 extension tables); don't include the REX prefix */
    359                 pCpu->bLastPrefix = opcode;
    360                 pCpu->fPrefix &= ~DISPREFIX_REX;
    361             }
    362 
    363             switch (opcode)
    364             {
    365             case OP_INVALID:
    366                 if (pcbInstr)
    367                     *pcbInstr = iByte + 1;
    368                 return pCpu->rc = VERR_DIS_INVALID_OPCODE;
    369 
    370             // segment override prefix byte
    371             case OP_SEG:
    372                 pCpu->idxSegPrefix = (DISSELREG)(paOneByteMap[codebyte].fParam1 - OP_PARM_REG_SEG_START);
    373                 /* Segment prefixes for CS, DS, ES and SS are ignored in long mode. */
    374                 if (   pCpu->uCpuMode != DISCPUMODE_64BIT
    375                     || pCpu->idxSegPrefix >= DISSELREG_FS)
    376                 {
    377                     pCpu->fPrefix   |= DISPREFIX_SEG;
    378                 }
    379                 iByte += sizeof(uint8_t);
    380                 continue;   //fetch the next byte
    381 
    382             // lock prefix byte
    383             case OP_LOCK:
    384                 pCpu->fPrefix |= DISPREFIX_LOCK;
    385                 iByte       += sizeof(uint8_t);
    386                 continue;   //fetch the next byte
    387 
    388             // address size override prefix byte
    389             case OP_ADDRSIZE:
    390                 pCpu->fPrefix |= DISPREFIX_ADDRSIZE;
    391                 if (pCpu->uCpuMode == DISCPUMODE_16BIT)
    392                     pCpu->uAddrMode = DISCPUMODE_32BIT;
    393                 else
    394                 if (pCpu->uCpuMode == DISCPUMODE_32BIT)
    395                     pCpu->uAddrMode = DISCPUMODE_16BIT;
    396                 else
    397                     pCpu->uAddrMode = DISCPUMODE_32BIT;     /* 64 bits */
    398 
    399                 iByte        += sizeof(uint8_t);
    400                 continue;   //fetch the next byte
    401 
    402             // operand size override prefix byte
    403             case OP_OPSIZE:
    404                 pCpu->fPrefix |= DISPREFIX_OPSIZE;
    405                 if (pCpu->uCpuMode == DISCPUMODE_16BIT)
    406                     pCpu->uOpMode = DISCPUMODE_32BIT;
    407                 else
    408                     pCpu->uOpMode = DISCPUMODE_16BIT;  /* for 32 and 64 bits mode (there is no 32 bits operand size override prefix) */
    409 
    410                 iByte        += sizeof(uint8_t);
    411                 continue;   //fetch the next byte
    412 
    413             // rep and repne are not really prefixes, but we'll treat them as such
    414             case OP_REPE:
    415                 pCpu->fPrefix |= DISPREFIX_REP;
    416                 iByte       += sizeof(uint8_t);
    417                 continue;   //fetch the next byte
    418 
    419             case OP_REPNE:
    420                 pCpu->fPrefix |= DISPREFIX_REPNE;
    421                 iByte       += sizeof(uint8_t);
    422                 continue;   //fetch the next byte
    423 
    424             case OP_REX:
    425                 Assert(pCpu->uCpuMode == DISCPUMODE_64BIT);
    426                 /* REX prefix byte */
    427                 pCpu->fPrefix   |= DISPREFIX_REX;
    428                 pCpu->fRexPrefix = DISPREFIX_REX_OP_2_FLAGS(paOneByteMap[codebyte].fParam1);
    429                 iByte           += sizeof(uint8_t);
    430 
    431                 if (pCpu->fRexPrefix & DISPREFIX_REX_FLAGS_W)
    432                     pCpu->uOpMode = DISCPUMODE_64BIT;  /* overrides size prefix byte */
    433                 continue;   //fetch the next byte
    434             }
    435         }
    436 
    437         unsigned uIdx = iByte;
    438         iByte += sizeof(uint8_t); //first opcode byte
    439 
    440         pCpu->bOpCode = codebyte;
    441 
    442         cbInc = disParseInstruction(uInstrAddr + iByte, &paOneByteMap[pCpu->bOpCode], pCpu);
    443         iByte += cbInc;
    444         break;
    445     }
    446 
    447     pCpu->cbInstr = iByte;
    448     if (pcbInstr)
    449         *pcbInstr = iByte;
    450 
    451     if (pCpu->fPrefix & DISPREFIX_LOCK)
    452         disValidateLockSequence(pCpu);
    453 
    454     return pCpu->rc;
    455 }
     430            case 1:
     431                return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], 0, 0, 0);
     432            case 2:
     433                return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], 0, 0);
     434            case 3:
     435                return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], 0);
     436        }
     437        return 0;
     438    }
     439
     440    if (off + 2 < pCpu->cbCachedInstr)
     441        disReadMore(pCpu, off, 2);
     442
     443#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
     444    return *(uint32_t const *)&pCpu->abInstr[off];
     445#else
     446    return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3]);
     447#endif
     448}
     449
     450
     451/**
     452 * Read a dword (32-bit) instruction byte by offset.
     453 *
     454 * @returns The requested dword.
     455 * @param   pCpu                The disassembler state.
     456 * @param   uAddress            The address.
     457 */
     458DECLINLINE(uint32_t) disReadDWordByOff(PDISCPUSTATE pCpu, RTUINTPTR off)
     459{
     460    if (RT_UNLIKELY(off + 2 > pCpu->cbCachedInstr))
     461        return disReadDWordSlow(pCpu, off);
     462
     463#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
     464    return *(uint32_t const *)&pCpu->abInstr[off];
     465#else
     466    return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3]);
     467#endif
     468}
     469
     470
     471/**
     472 * Read a dword (32-bit) instruction byte.
     473 *
     474 * @returns The requested dword.
     475 * @param   pCpu                The disassembler state.
     476 * @param   uAddress            The address.
     477 */
     478DECL_FORCE_INLINE(uint32_t) disReadDWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
     479{
     480    return disReadDWordByOff(pCpu, uAddress - pCpu->uInstrAddr);
     481}
     482
     483
     484/**
     485 * Function for handling a 64-bit cache miss.
     486 *
     487 * @returns The requested qword.
     488 * @param   pCpu                The disassembler state.
     489 * @param   off                 The offset of the qword relative to the
     490 *                              instruction.
     491 */
     492DECL_NO_INLINE(static, uint64_t) disReadQWordSlow(PDISCPUSTATE pCpu, RTUINTPTR off)
     493{
     494    if (RT_UNLIKELY(off + 2 > DIS_MAX_INSTR_LENGTH))
     495    {
     496        Log(("disReadQWord: too long instruction...\n"));
     497        pCpu->rc = VERR_DIS_TOO_LONG_INSTR;
     498        switch ((RTUINTPTR)DIS_MAX_INSTR_LENGTH - off)
     499        {
     500            case 1:
     501                return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], 0, 0, 0,   0, 0, 0, 0);
     502            case 2:
     503                return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], 0, 0,   0, 0, 0, 0);
     504            case 3:
     505                return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], 0,   0, 0, 0, 0);
     506            case 4:
     507                return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3],
     508                                           pCpu->abInstr[off + 4], 0, 0, 0);
     509            case 5:
     510                return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3],
     511                                           pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], 0, 0);
     512            case 6:
     513                return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3],
     514                                           pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], pCpu->abInstr[off + 6], 0);
     515        }
     516        return 0;
     517    }
     518
     519    if (off + 2 < pCpu->cbCachedInstr)
     520        disReadMore(pCpu, off, 2);
     521
     522#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
     523    return *(uint64_t const *)&pCpu->abInstr[off];
     524#else
     525    return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off    ], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3],
     526                               pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], pCpu->abInstr[off + 6], pCpu->abInstr[off + 7]);
     527#endif
     528}
     529
     530
     531/**
     532 * Read a qword (64-bit) instruction byte by offset.
     533 *
     534 * @returns The requested qword.
     535 * @param   pCpu                The disassembler state.
     536 * @param   uAddress            The address.
     537 */
     538DECLINLINE(uint64_t) disReadQWordByOff(PDISCPUSTATE pCpu, RTUINTPTR off)
     539{
     540    if (RT_UNLIKELY(off + 2 > pCpu->cbCachedInstr))
     541        return disReadQWordSlow(pCpu, off);
     542
     543#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
     544    return *(uint64_t const *)&pCpu->abInstr[off];
     545#else
     546    return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off    ], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3],
     547                               pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], pCpu->abInstr[off + 6], pCpu->abInstr[off + 7]);
     548#endif
     549}
     550
     551
     552/**
     553 * Read a qword (64-bit) instruction byte.
     554 *
     555 * @returns The requested qword.
     556 * @param   pCpu                The disassembler state.
     557 * @param   uAddress            The address.
     558 */
     559DECL_FORCE_INLINE(uint64_t) disReadQWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
     560{
     561    return disReadQWordByOff(pCpu, uAddress - pCpu->uInstrAddr);
     562}
     563
     564
     565
    456566//*****************************************************************************
    457567//*****************************************************************************
     
    20402150    pCpu->ModRM.Bits.Reg = MODRM_REG(ModRM);
    20412151
    2042     modrmsize = QueryModRM(uCodePtr+sizeof(uint8_t), pOp, pParam, pCpu);
     2152    modrmsize = QueryModRM(uCodePtr+sizeof(uint8_t), pOp, pParam, pCpu, NULL);
    20432153
    20442154    uint8_t opcode = disReadByte(pCpu, uCodePtr+sizeof(uint8_t)+modrmsize);
     
    23822492    pParam->fUse |= DISUSE_REG_SEG;
    23832493    pParam->Base.idxSegReg = (DISSELREG)idx;
    2384 }
    2385 
    2386 
    2387 //*****************************************************************************
    2388 /* Read functions for getting the opcode bytes */
    2389 //*****************************************************************************
    2390 
    2391 
    2392 static DECLCALLBACK(int) disReadBytesDefault(PDISCPUSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
    2393 {
    2394 #ifdef IN_RING0
    2395     AssertMsgFailed(("disReadWord with no read callback in ring 0!!\n"));
    2396     RT_BZERO(&pDis->abInstr[offInstr], cbMaxRead);
    2397     pDis->cbCachedInstr = offInstr + cbMaxRead;
    2398     return VERR_DIS_NO_READ_CALLBACK;
    2399 #else
    2400     memcpy(&pDis->abInstr[offInstr], (uint8_t const *)(uintptr_t)pDis->uInstrAddr + offInstr, cbMaxRead);
    2401     pDis->cbCachedInstr = offInstr + cbMaxRead;
    2402     return VINF_SUCCESS;
    2403 #endif
    2404 }
    2405 
    2406 
    2407 /**
    2408  * Read more bytes into the DISCPUSTATE::abInstr buffer, advance
    2409  * DISCPUSTATE::cbCachedInstr.
    2410  *
    2411  * Will set DISCPUSTATE::rc on failure, but still advance cbCachedInstr.
    2412  *
    2413  * The caller shall fend off reads beyond the DISCPUSTATE::abInstr buffer.
    2414  *
    2415  * @param   pCpu                The disassembler state.
    2416  * @param   off                 The offset of the read request.
    2417  * @param   cbMin               The size of the read request that needs to be
    2418  *                              satisfied.
    2419  */
    2420 DECL_NO_INLINE(static, void) disReadMore(PDISCPUSTATE pCpu, uint8_t off, uint8_t cbMin)
    2421 {
    2422     Assert(cbMin + off <= sizeof(pCpu->abInstr));
    2423 
    2424     /*
    2425      * Adjust the incoming request to not overlap with bytes that has already
    2426      * been read and to make sure we don't leave unread gaps.
    2427      */
    2428     if (off < pCpu->cbCachedInstr)
    2429     {
    2430         Assert(off + cbMin > pCpu->cbCachedInstr);
    2431         cbMin -= pCpu->cbCachedInstr - off;
    2432         off = pCpu->cbCachedInstr;
    2433     }
    2434     else if (off > pCpu->cbCachedInstr)
    2435     {
    2436         cbMin += off - pCpu->cbCachedInstr;
    2437         off = pCpu->cbCachedInstr;
    2438     }
    2439 
    2440     /*
    2441      * Do the read.
    2442      * (No need to zero anything on failure as abInstr is already zeroed by the
    2443      * DISInstrEx API.)
    2444      */
    2445     int rc = pCpu->pfnReadBytes(pCpu, off, cbMin, sizeof(pCpu->abInstr) - off);
    2446     if (RT_SUCCESS(rc))
    2447     {
    2448         Assert(pCpu->cbCachedInstr >= off + cbMin);
    2449         Assert(pCpu->cbCachedInstr <= sizeof(pCpu->abInstr));
    2450     }
    2451     else
    2452     {
    2453         Log(("disReadMore failed with rc=%Rrc!!\n", rc));
    2454         pCpu->rc = VERR_DIS_MEM_READ;
    2455     }
    2456 }
    2457 
    2458 
    2459 /**
    2460  * Function for handling a 8-bit read beyond the max instruction length.
    2461  *
    2462  * @returns 0
    2463  * @param   pCpu                The disassembler state.
    2464  * @param   uAddress            The address.
    2465  */
    2466 DECL_NO_INLINE(static, uint8_t) disReadByteBad(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
    2467 {
    2468     Log(("disReadByte: too long instruction...\n"));
    2469     pCpu->rc = VERR_DIS_TOO_LONG_INSTR;
    2470     return 0;
    2471 }
    2472 
    2473 
    2474 /**
    2475  * Read a byte (8-bit) instruction byte.
    2476  *
    2477  * @returns The requested byte.
    2478  * @param   pCpu                The disassembler state.
    2479  * @param   uAddress            The address.
    2480  */
    2481 static uint8_t disReadByte(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
    2482 {
    2483     RTUINTPTR off = uAddress - pCpu->uInstrAddr;
    2484     if (RT_UNLIKELY(off + 1 > DIS_MAX_INSTR_LENGTH))
    2485         return disReadByteBad(pCpu, uAddress);
    2486 
    2487     if (off + 1 > pCpu->cbCachedInstr)
    2488         disReadMore(pCpu, off, 1);
    2489     return pCpu->abInstr[off];
    2490 }
    2491 
    2492 
    2493 /**
    2494  * Function for handling a 16-bit read beyond the max instruction length.
    2495  *
    2496  * @returns 0
    2497  * @param   pCpu                The disassembler state.
    2498  * @param   uAddress            The address.
    2499  */
    2500 DECL_NO_INLINE(static, uint16_t) disReadWordBad(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
    2501 {
    2502     Log(("disReadWord: too long instruction...\n"));
    2503     pCpu->rc = VERR_DIS_TOO_LONG_INSTR;
    2504     RTUINTPTR off = uAddress - pCpu->uInstrAddr;
    2505     if (off < DIS_MAX_INSTR_LENGTH)
    2506         return pCpu->abInstr[off];
    2507     return 0;
    2508 }
    2509 
    2510 
    2511 /**
    2512  * Read a word (16-bit) instruction byte.
    2513  *
    2514  * @returns The requested byte.
    2515  * @param   pCpu                The disassembler state.
    2516  * @param   uAddress            The address.
    2517  */
    2518 static uint16_t disReadWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
    2519 {
    2520     RTUINTPTR off = uAddress - pCpu->uInstrAddr;
    2521     if (RT_UNLIKELY(off + 2 > DIS_MAX_INSTR_LENGTH))
    2522         return disReadWordBad(pCpu, uAddress);
    2523 
    2524     if (off + 2 > pCpu->cbCachedInstr)
    2525         disReadMore(pCpu, off, 2);
    2526 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK
    2527     return *(uint16_t const *)&pCpu->abInstr[off];
    2528 #else
    2529     return RT_MAKE_U16(pCpu->abInstr[off], pCpu->abInstr[off + 1]);
    2530 #endif
    2531 }
    2532 
    2533 
    2534 /**
    2535  * Function for handling a 32-bit read beyond the max instruction length.
    2536  *
    2537  * @returns 0
    2538  * @param   pCpu                The disassembler state.
    2539  * @param   uAddress            The address.
    2540  */
    2541 DECL_NO_INLINE(static, uint32_t) disReadDWordBad(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
    2542 {
    2543     Log(("disReadDWord: too long instruction...\n"));
    2544     pCpu->rc = VERR_DIS_TOO_LONG_INSTR;
    2545     RTUINTPTR off = uAddress - pCpu->uInstrAddr;
    2546     switch ((RTUINTPTR)DIS_MAX_INSTR_LENGTH - off)
    2547     {
    2548         case 1:
    2549             return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], 0, 0, 0);
    2550         case 2:
    2551             return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], 0, 0);
    2552         case 3:
    2553             return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], 0);
    2554         default:
    2555             return 0;
    2556     }
    2557     return 0;
    2558 }
    2559 
    2560 
    2561 /**
    2562  * Read a word (32-bit) instruction byte.
    2563  *
    2564  * @returns The requested byte.
    2565  * @param   pCpu                The disassembler state.
    2566  * @param   uAddress            The address.
    2567  */
    2568 static uint32_t disReadDWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
    2569 {
    2570     RTUINTPTR off = uAddress - pCpu->uInstrAddr;
    2571     if (RT_UNLIKELY(off + 4 > DIS_MAX_INSTR_LENGTH))
    2572         return disReadDWordBad(pCpu, uAddress);
    2573 
    2574     if (off + 4 > pCpu->cbCachedInstr)
    2575         disReadMore(pCpu, off, 4);
    2576 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK
    2577     return *(uint32_t const *)&pCpu->abInstr[off];
    2578 #else
    2579     return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3]);
    2580 #endif
    2581 }
    2582 
    2583 
    2584 /**
    2585  * Function for handling a 64-bit read beyond the max instruction length.
    2586  *
    2587  * @returns 0
    2588  * @param   pCpu                The disassembler state.
    2589  * @param   uAddress            The address.
    2590  */
    2591 DECL_NO_INLINE(static, uint64_t) disReadQWordBad(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
    2592 {
    2593     Log(("disReadQWord: too long instruction...\n"));
    2594     pCpu->rc = VERR_DIS_TOO_LONG_INSTR;
    2595     RTUINTPTR off = uAddress - pCpu->uInstrAddr;
    2596     switch ((RTUINTPTR)DIS_MAX_INSTR_LENGTH - off)
    2597     {
    2598         case 1:
    2599             return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], 0, 0, 0,   0, 0, 0, 0);
    2600         case 2:
    2601             return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], 0, 0,   0, 0, 0, 0);
    2602         case 3:
    2603             return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], 0,   0, 0, 0, 0);
    2604         case 4:
    2605             return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3],
    2606                                        pCpu->abInstr[off + 4], 0, 0, 0);
    2607         case 5:
    2608             return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3],
    2609                                        pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], 0, 0);
    2610         case 6:
    2611             return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3],
    2612                                        pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], pCpu->abInstr[off + 6], 0);
    2613         default:
    2614             return 0;
    2615     }
    2616     return 0;
    2617 }
    2618 
    2619 
    2620 /**
    2621  * Read a word (64-bit) instruction byte.
    2622  *
    2623  * @returns The requested byte.
    2624  * @param   pCpu                The disassembler state.
    2625  * @param   uAddress            The address.
    2626  */
    2627 static uint64_t disReadQWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
    2628 {
    2629     RTUINTPTR off = uAddress - pCpu->uInstrAddr;
    2630     if (RT_UNLIKELY(off + 8 > DIS_MAX_INSTR_LENGTH))
    2631         return disReadQWordBad(pCpu, uAddress);
    2632 
    2633     if (off + 8 > pCpu->cbCachedInstr)
    2634         disReadMore(pCpu, off, 8);
    2635 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK
    2636     return *(uint64_t const *)&pCpu->abInstr[off];
    2637 #else
    2638     return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off    ], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3],
    2639                                pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], pCpu->abInstr[off + 6], pCpu->abInstr[off + 7]);
    2640 #endif
    26412494}
    26422495
     
    27242577}
    27252578
     2579
     2580/**
     2581 * Internal worker for DISInstEx.
     2582 *
     2583 * @returns VBox status code.
     2584 * @param   pCpu            Initialized cpu state.
     2585 * @param   paOneByteMap    The one byte opcode map to use.
     2586 * @param   uInstrAddr      Instruction address.
     2587 * @param   pcbInstr        Where to store the instruction size. Can be NULL.
     2588 */
     2589static int disInstrWorker(PDISCPUSTATE pCpu, RTUINTPTR uInstrAddr, PCDISOPCODE paOneByteMap, uint32_t *pcbInstr)
     2590{
     2591    /*
     2592     * Parse byte by byte.
     2593     */
     2594    size_t offByte = 0;
     2595    for (;;)
     2596    {
     2597        uint8_t codebyte = disReadByteByOff(pCpu, offByte++);
     2598        uint8_t opcode   = paOneByteMap[codebyte].uOpcode;
     2599
     2600        /* Hardcoded assumption about OP_* values!! */
     2601        if (opcode <= OP_LAST_PREFIX)
     2602        {
     2603            /* The REX prefix must precede the opcode byte(s). Any other placement is ignored. */
     2604            if (opcode != OP_REX)
     2605            {
     2606                /** Last prefix byte (for SSE2 extension tables); don't include the REX prefix */
     2607                pCpu->bLastPrefix = opcode;
     2608                pCpu->fPrefix &= ~DISPREFIX_REX;
     2609            }
     2610
     2611            switch (opcode)
     2612            {
     2613            case OP_INVALID:
     2614                if (pcbInstr)
     2615                    *pcbInstr = (uint32_t)offByte;
     2616                return pCpu->rc = VERR_DIS_INVALID_OPCODE;
     2617
     2618            // segment override prefix byte
     2619            case OP_SEG:
     2620                pCpu->idxSegPrefix = (DISSELREG)(paOneByteMap[codebyte].fParam1 - OP_PARM_REG_SEG_START);
     2621                /* Segment prefixes for CS, DS, ES and SS are ignored in long mode. */
     2622                if (   pCpu->uCpuMode != DISCPUMODE_64BIT
     2623                    || pCpu->idxSegPrefix >= DISSELREG_FS)
     2624                {
     2625                    pCpu->fPrefix   |= DISPREFIX_SEG;
     2626                }
     2627                continue;   //fetch the next byte
     2628
     2629            // lock prefix byte
     2630            case OP_LOCK:
     2631                pCpu->fPrefix |= DISPREFIX_LOCK;
     2632                continue;   //fetch the next byte
     2633
     2634            // address size override prefix byte
     2635            case OP_ADDRSIZE:
     2636                pCpu->fPrefix |= DISPREFIX_ADDRSIZE;
     2637                if (pCpu->uCpuMode == DISCPUMODE_16BIT)
     2638                    pCpu->uAddrMode = DISCPUMODE_32BIT;
     2639                else
     2640                if (pCpu->uCpuMode == DISCPUMODE_32BIT)
     2641                    pCpu->uAddrMode = DISCPUMODE_16BIT;
     2642                else
     2643                    pCpu->uAddrMode = DISCPUMODE_32BIT;     /* 64 bits */
     2644                continue;   //fetch the next byte
     2645
     2646            // operand size override prefix byte
     2647            case OP_OPSIZE:
     2648                pCpu->fPrefix |= DISPREFIX_OPSIZE;
     2649                if (pCpu->uCpuMode == DISCPUMODE_16BIT)
     2650                    pCpu->uOpMode = DISCPUMODE_32BIT;
     2651                else
     2652                    pCpu->uOpMode = DISCPUMODE_16BIT;  /* for 32 and 64 bits mode (there is no 32 bits operand size override prefix) */
     2653                continue;   //fetch the next byte
     2654
     2655            // rep and repne are not really prefixes, but we'll treat them as such
     2656            case OP_REPE:
     2657                pCpu->fPrefix |= DISPREFIX_REP;
     2658                continue;   //fetch the next byte
     2659
     2660            case OP_REPNE:
     2661                pCpu->fPrefix |= DISPREFIX_REPNE;
     2662                continue;   //fetch the next byte
     2663
     2664            case OP_REX:
     2665                Assert(pCpu->uCpuMode == DISCPUMODE_64BIT);
     2666                /* REX prefix byte */
     2667                pCpu->fPrefix   |= DISPREFIX_REX;
     2668                pCpu->fRexPrefix = DISPREFIX_REX_OP_2_FLAGS(paOneByteMap[codebyte].fParam1);
     2669                if (pCpu->fRexPrefix & DISPREFIX_REX_FLAGS_W)
     2670                    pCpu->uOpMode = DISCPUMODE_64BIT;  /* overrides size prefix byte */
     2671                continue;   //fetch the next byte
     2672            }
     2673        }
     2674
     2675        /* first opcode byte. */
     2676        pCpu->bOpCode = codebyte;
     2677        offByte += disParseInstruction(uInstrAddr + offByte, &paOneByteMap[pCpu->bOpCode], pCpu);
     2678        break;
     2679    }
     2680
     2681    pCpu->cbInstr = offByte;
     2682    if (pcbInstr)
     2683        *pcbInstr = offByte;
     2684
     2685    if (pCpu->fPrefix & DISPREFIX_LOCK)
     2686        disValidateLockSequence(pCpu);
     2687
     2688    return pCpu->rc;
     2689}
     2690
     2691
     2692/**
     2693 * Disassembles on instruction, details in @a pCpu and length in @a pcbInstr.
     2694 *
     2695 * @returns VBox status code.
     2696 * @param   uInstrAddr      Address of the instruction to decode. What this means
     2697 *                          is left to the pfnReadBytes function.
     2698 * @param   enmCpuMode      The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
     2699 * @param   pfnReadBytes    Callback for reading instruction bytes.
     2700 * @param   fFilter         Instruction type filter.
     2701 * @param   pvUser          User argument for the instruction reader. (Ends up in pvUser.)
     2702 * @param   pCpu            Pointer to CPU structure. With the exception of
     2703 *                          DISCPUSTATE::pvUser2, the structure will be
     2704 *                          completely initialized by this API, i.e. no input is
     2705 *                          taken from it.
     2706 * @param   pcbInstr        Where to store the size of the instruction.  (This
     2707 *                          is also stored in PDISCPUSTATE::cbInstr.)  Optional.
     2708 */
     2709DISDECL(int) DISInstEx(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter,
     2710                       PFNDISREADBYTES pfnReadBytes, void *pvUser,
     2711                       PDISCPUSTATE pCpu, uint32_t *pcbInstr)
     2712{
     2713    PCDISOPCODE paOneByteMap;
     2714
     2715    /*
     2716     * Initialize the CPU state.
     2717     * Note! The RT_BZERO make ASSUMPTIONS about the placement of pvUser2.
     2718     */
     2719    RT_BZERO(pCpu, RT_OFFSETOF(DISCPUSTATE, pvUser2));
     2720
     2721#ifdef VBOX_STRICT /* poison */
     2722    pCpu->Param1.Base.idxGenReg  = 0xc1;
     2723    pCpu->Param2.Base.idxGenReg  = 0xc2;
     2724    pCpu->Param3.Base.idxGenReg  = 0xc3;
     2725    pCpu->Param1.Index.idxGenReg = 0xc4;
     2726    pCpu->Param2.Index.idxGenReg = 0xc5;
     2727    pCpu->Param3.Index.idxGenReg = 0xc6;
     2728    pCpu->Param1.uDisp.u64 = UINT64_C(0xd1d1d1d1d1d1d1d1);
     2729    pCpu->Param2.uDisp.u64 = UINT64_C(0xd2d2d2d2d2d2d2d2);
     2730    pCpu->Param3.uDisp.u64 = UINT64_C(0xd3d3d3d3d3d3d3d3);
     2731    pCpu->Param1.uValue    = UINT64_C(0xb1b1b1b1b1b1b1b1);
     2732    pCpu->Param2.uValue    = UINT64_C(0xb2b2b2b2b2b2b2b2);
     2733    pCpu->Param3.uValue    = UINT64_C(0xb3b3b3b3b3b3b3b3);
     2734    pCpu->Param1.uScale    = 28;
     2735    pCpu->Param2.uScale    = 29;
     2736    pCpu->Param3.uScale    = 30;
     2737#endif
     2738
     2739    pCpu->uCpuMode          = enmCpuMode;
     2740    if (enmCpuMode == DISCPUMODE_64BIT)
     2741    {
     2742        paOneByteMap        = g_aOneByteMapX64;
     2743        pCpu->uAddrMode     = DISCPUMODE_64BIT;
     2744        pCpu->uOpMode       = DISCPUMODE_32BIT;
     2745    }
     2746    else
     2747    {
     2748        paOneByteMap        = g_aOneByteMapX86;
     2749        pCpu->uAddrMode     = enmCpuMode;
     2750        pCpu->uOpMode       = enmCpuMode;
     2751    }
     2752    pCpu->fPrefix           = DISPREFIX_NONE;
     2753    pCpu->idxSegPrefix      = DISSELREG_DS;
     2754    pCpu->uInstrAddr        = uInstrAddr;
     2755    pCpu->pfnDisasmFnTable  = g_apfnFullDisasm;
     2756    pCpu->fFilter           = fFilter;
     2757    pCpu->rc                = VINF_SUCCESS;
     2758    pCpu->pfnReadBytes      = pfnReadBytes ? pfnReadBytes : disReadBytesDefault;
     2759    pCpu->pvUser            = pvUser;
     2760
     2761    /*
     2762     * Read some bytes into the cache.  (If this fail we continue as nothing
     2763     * has gone wrong since this is what would happen if we didn't precharge
     2764     * the cache here.)
     2765     */
     2766    int rc = pCpu->pfnReadBytes(pCpu, 0, 1, sizeof(pCpu->abInstr));
     2767    if (RT_SUCCESS(rc))
     2768    {
     2769        Assert(pCpu->cbCachedInstr >= 1);
     2770        Assert(pCpu->cbCachedInstr <= sizeof(pCpu->abInstr));
     2771    }
     2772    else
     2773    {
     2774        Log(("Initial read failed with rc=%Rrc!!\n", rc));
     2775        pCpu->rc = VERR_DIS_MEM_READ;
     2776    }
     2777
     2778    return disInstrWorker(pCpu, uInstrAddr, paOneByteMap, pcbInstr);
     2779}
     2780
     2781
     2782/**
     2783 * Parses one guest instruction.
     2784 *
     2785 * The result is found in pCpu and pcbInstr.
     2786 *
     2787 * @returns VBox status code.
     2788 * @param   uInstrAddr      Address of the instruction to decode. What this means
     2789 *                          is left to the pfnReadBytes function.
     2790 * @param   enmCpuMode      The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
     2791 * @param   pfnReadBytes    Callback for reading instruction bytes.
     2792 * @param   pvUser          User argument for the instruction reader. (Ends up in pvUser.)
     2793 * @param   pCpu            Pointer to cpu structure. Will be initialized.
     2794 * @param   pcbInstr        Where to store the size of the instruction.
     2795 *                          NULL is allowed.  This is also stored in
     2796 *                          PDISCPUSTATE::cbInstr.
     2797 */
     2798DISDECL(int) DISInstrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser,
     2799                                PDISCPUSTATE pCpu, uint32_t *pcbInstr)
     2800{
     2801    return DISInstEx(uInstrAddr, enmCpuMode, DISOPTYPE_ALL, pfnReadBytes, pvUser, pCpu, pcbInstr);
     2802}
     2803
     2804
     2805/**
     2806 * Parses one guest instruction.
     2807 *
     2808 * The result is found in pCpu and pcbInstr.
     2809 *
     2810 * @returns VBox status code.
     2811 * @param   pvInstr         Address of the instruction to decode.  This is a
     2812 *                          real address in the current context that can be
     2813 *                          accessed without faulting.  (Consider
     2814 *                          DISInstrWithReader if this isn't the case.)
     2815 * @param   enmCpuMode      The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
     2816 * @param   pfnReadBytes    Callback for reading instruction bytes.
     2817 * @param   pvUser          User argument for the instruction reader. (Ends up in pvUser.)
     2818 * @param   pCpu            Pointer to cpu structure. Will be initialized.
     2819 * @param   pcbInstr        Where to store the size of the instruction.
     2820 *                          NULL is allowed.  This is also stored in
     2821 *                          PDISCPUSTATE::cbInstr.
     2822 */
     2823DISDECL(int) DISInstr(const void *pvInstr, DISCPUMODE enmCpuMode, PDISCPUSTATE pCpu, uint32_t *pcbInstr)
     2824{
     2825    return DISInstEx((uintptr_t)pvInstr, enmCpuMode, DISOPTYPE_ALL, NULL /*pfnReadBytes*/, NULL /*pvUser*/, pCpu, pcbInstr);
     2826}
     2827
  • trunk/src/VBox/Disassembler/testcase/tstDisasm-1.cpp

    r41751 r41781  
    2424#include <iprt/string.h>
    2525#include <iprt/err.h>
     26#include <iprt/time.h>
    2627
    2728
     
    7374        off += cb;
    7475    }
     76}
    7577
     78static void testPerformance(const char *pszSub, uint8_t const *pabInstrs, uintptr_t uEndPtr, DISCPUMODE enmDisCpuMode)
     79{
     80    RTTestISubF("Performance - %s", pszSub);
     81
     82    size_t const    cbInstrs = uEndPtr - (uintptr_t)pabInstrs;
     83    uint64_t        cInstrs  = 0;
     84    uint64_t        nsStart  = RTTimeNanoTS();
     85    for (uint32_t i = 0; i < _512K; i++) /* the samples are way to small. :-) */
     86    {
     87        for (size_t off = 0; off < cbInstrs; cInstrs++)
     88        {
     89            uint32_t        cb = 1;
     90            DISCPUSTATE     Cpu;
     91            DISInstr(&pabInstrs[off], enmDisCpuMode, &Cpu, &cb);
     92            off += cb;
     93        }
     94    }
     95    uint64_t cNsElapsed = RTTimeNanoTS() - nsStart;
     96
     97    RTTestIValueF(cNsElapsed, RTTESTUNIT_NS, "%s-Total", pszSub);
     98    RTTestIValueF(cNsElapsed / cInstrs, RTTESTUNIT_NS_PER_CALL, "%s-per-instruction", pszSub);
    7699}
    77100
     
    85108    RTTestBanner(hTest);
    86109
    87     testDisas("32-bit", (uint8_t const *)(uintptr_t)TestProc32, (uintptr_t)&TestProc32_EndProc, DISCPUMODE_32BIT);
    88 #ifndef RT_OS_OS2
    89     testDisas("64-bit", (uint8_t const *)(uintptr_t)TestProc64, (uintptr_t)&TestProc64_EndProc, DISCPUMODE_64BIT);
    90 #endif
     110    static const struct
     111    {
     112        const char     *pszDesc;
     113        uint8_t const  *pbStart;
     114        uintptr_t       uEndPtr;
     115        DISCPUMODE      enmCpuMode;
     116    } aSnippets[] =
     117    {
     118        { "32-bit",     (uint8_t const *)(uintptr_t)TestProc32, (uintptr_t)&TestProc32_EndProc, DISCPUMODE_32BIT },
     119        { "64-bit",     (uint8_t const *)(uintptr_t)TestProc64, (uintptr_t)&TestProc64_EndProc, DISCPUMODE_64BIT },
     120    };
     121
     122    for (unsigned i = 0; i < RT_ELEMENTS(aSnippets); i++)
     123        testDisas(aSnippets[i].pszDesc, aSnippets[i].pbStart, aSnippets[i].uEndPtr, aSnippets[i].enmCpuMode);
     124
     125    if (RTTestIErrorCount() == 0)
     126    {
     127        for (unsigned i = 0; i < RT_ELEMENTS(aSnippets); i++)
     128            testPerformance(aSnippets[i].pszDesc, aSnippets[i].pbStart, aSnippets[i].uEndPtr, aSnippets[i].enmCpuMode);
     129    }
    91130
    92131    return RTTestSummaryAndDestroy(hTest);
  • trunk/src/VBox/Disassembler/testcase/tstDisasm-2.cpp

    r41760 r41781  
    166166
    167167/**
    168  * Callback for reading bytes.
     168 * @interface_method_impl{FNDISREADBYTES}
    169169 */
    170170static DECLCALLBACK(int) MyDisasInstrRead(PDISCPUSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette