VirtualBox

Changeset 99236 in vbox


Ignore:
Timestamp:
Mar 30, 2023 3:30:26 PM (20 months ago)
Author:
vboxsync
Message:

Disassember: Continue separation of the common disassembler and x86 specific parts, bugref:10394

Location:
trunk/src/VBox/Disassembler
Files:
4 edited
1 copied
2 moved

Legend:

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

    r99220 r99236  
    3838
    3939
     40/*********************************************************************************************************************************
     41*   Defined Constants And Macros                                                                                                 *
     42*********************************************************************************************************************************/
     43
     44
     45/*********************************************************************************************************************************
     46*   Internal Functions                                                                                                           *
     47*********************************************************************************************************************************/
     48
     49/**
     50 * @interface_method_impl{FNDISREADBYTES, The default byte reader callber.}
     51 */
     52static DECLCALLBACK(int) disReadBytesDefault(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
     53{
     54#if 0 /*def IN_RING0 - why? */
     55    RT_NOREF_PV(cbMinRead);
     56    AssertMsgFailed(("disReadWord with no read callback in ring 0!!\n"));
     57    RT_BZERO(&pDis->u.abInstr[offInstr], cbMaxRead);
     58    pDis->cbCachedInstr = offInstr + cbMaxRead;
     59    return VERR_DIS_NO_READ_CALLBACK;
     60#else
     61    uint8_t const  *pbSrc        = (uint8_t const *)(uintptr_t)pDis->uInstrAddr + offInstr;
     62    size_t          cbLeftOnPage = (uintptr_t)pbSrc & PAGE_OFFSET_MASK;
     63    uint8_t         cbToRead     = cbLeftOnPage >= cbMaxRead
     64                                 ? cbMaxRead
     65                                 : cbLeftOnPage <= cbMinRead
     66                                 ? cbMinRead
     67                                 : (uint8_t)cbLeftOnPage;
     68    memcpy(&pDis->u.abInstr[offInstr], pbSrc, cbToRead);
     69    pDis->cbCachedInstr = offInstr + cbToRead;
     70    return VINF_SUCCESS;
     71#endif
     72}
     73
     74
     75/**
     76 * Read more bytes into the DISSTATE::u.abInstr buffer, advance
     77 * DISSTATE::cbCachedInstr.
     78 *
     79 * Will set DISSTATE::rc on failure, but still advance cbCachedInstr.
     80 *
     81 * The caller shall fend off reads beyond the DISSTATE::u.abInstr buffer.
     82 *
     83 * @param   pDis                The disassembler state.
     84 * @param   offInstr            The offset of the read request.
     85 * @param   cbMin               The size of the read request that needs to be
     86 *                              satisfied.
     87 */
     88DECLHIDDEN(void) disReadMore(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMin)
     89{
     90    Assert(cbMin + offInstr <= sizeof(pDis->u.abInstr));
     91
     92    /*
     93     * Adjust the incoming request to not overlap with bytes that has already
     94     * been read and to make sure we don't leave unread gaps.
     95     */
     96    if (offInstr < pDis->cbCachedInstr)
     97    {
     98        Assert(offInstr + cbMin > pDis->cbCachedInstr);
     99        cbMin -= pDis->cbCachedInstr - offInstr;
     100        offInstr = pDis->cbCachedInstr;
     101    }
     102    else if (offInstr > pDis->cbCachedInstr)
     103    {
     104        cbMin += offInstr - pDis->cbCachedInstr;
     105        offInstr = pDis->cbCachedInstr;
     106    }
     107
     108    /*
     109     * Do the read.
     110     * (No need to zero anything on failure as u.abInstr is already zeroed by the
     111     * DISInstrEx API.)
     112     */
     113    int rc = pDis->pfnReadBytes(pDis, offInstr, cbMin, sizeof(pDis->u.abInstr) - offInstr);
     114    if (RT_SUCCESS(rc))
     115    {
     116        Assert(pDis->cbCachedInstr >= offInstr + cbMin);
     117        Assert(pDis->cbCachedInstr <= sizeof(pDis->u.abInstr));
     118    }
     119    else
     120    {
     121        Log(("disReadMore failed with rc=%Rrc!!\n", rc));
     122        pDis->rc = rc;
     123    }
     124}
     125
     126
     127/**
     128 * Function for handling a 8-bit cache miss.
     129 *
     130 * @returns The requested byte.
     131 * @param   pDis                The disassembler state.
     132 * @param   offInstr            The offset of the byte relative to the
     133 *                              instruction.
     134 */
     135DECLHIDDEN(uint8_t) disReadByteSlow(PDISSTATE pDis, size_t offInstr)
     136{
     137    if (RT_LIKELY(offInstr < DIS_MAX_INSTR_LENGTH))
     138    {
     139        disReadMore(pDis, (uint8_t)offInstr, 1);
     140        return pDis->u.abInstr[offInstr];
     141    }
     142
     143    Log(("disReadByte: too long instruction...\n"));
     144    pDis->rc = VERR_DIS_TOO_LONG_INSTR;
     145    ssize_t cbLeft = (ssize_t)(sizeof(pDis->u.abInstr) - offInstr);
     146    if (cbLeft > 0)
     147        return pDis->u.abInstr[offInstr];
     148    return 0;
     149}
     150
     151
     152/**
     153 * Function for handling a 16-bit cache miss.
     154 *
     155 * @returns The requested word.
     156 * @param   pDis                The disassembler state.
     157 * @param   offInstr            The offset of the word relative to the
     158 *                              instruction.
     159 */
     160DECLHIDDEN(uint16_t) disReadWordSlow(PDISSTATE pDis, size_t offInstr)
     161{
     162    if (RT_LIKELY(offInstr + 2 <= DIS_MAX_INSTR_LENGTH))
     163    {
     164        disReadMore(pDis, (uint8_t)offInstr, 2);
     165#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
     166        return *(uint16_t const *)&pDis->u.abInstr[offInstr];
     167#else
     168        return RT_MAKE_U16(pDis->u.abInstr[offInstr], pDis->u.abInstr[offInstr + 1]);
     169#endif
     170    }
     171
     172    Log(("disReadWord: too long instruction...\n"));
     173    pDis->rc = VERR_DIS_TOO_LONG_INSTR;
     174    ssize_t cbLeft = (ssize_t)(sizeof(pDis->u.abInstr) - offInstr);
     175    switch (cbLeft)
     176    {
     177        case 1:
     178            return pDis->u.abInstr[offInstr];
     179        default:
     180            if (cbLeft >= 2)
     181                return RT_MAKE_U16(pDis->u.abInstr[offInstr], pDis->u.abInstr[offInstr + 1]);
     182            return 0;
     183    }
     184}
     185
     186
     187/**
     188 * Function for handling a 32-bit cache miss.
     189 *
     190 * @returns The requested dword.
     191 * @param   pDis                The disassembler state.
     192 * @param   offInstr            The offset of the dword relative to the
     193 *                              instruction.
     194 */
     195DECLHIDDEN(uint32_t) disReadDWordSlow(PDISSTATE pDis, size_t offInstr)
     196{
     197    if (RT_LIKELY(offInstr + 4 <= DIS_MAX_INSTR_LENGTH))
     198    {
     199        disReadMore(pDis, (uint8_t)offInstr, 4);
     200#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
     201        return *(uint32_t const *)&pDis->u.abInstr[offInstr];
     202#else
     203        return RT_MAKE_U32_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
     204                                   pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3]);
     205#endif
     206    }
     207
     208    Log(("disReadDWord: too long instruction...\n"));
     209    pDis->rc = VERR_DIS_TOO_LONG_INSTR;
     210    ssize_t cbLeft = (ssize_t)(sizeof(pDis->u.abInstr) - offInstr);
     211    switch (cbLeft)
     212    {
     213        case 1:
     214            return RT_MAKE_U32_FROM_U8(pDis->u.abInstr[offInstr], 0, 0, 0);
     215        case 2:
     216            return RT_MAKE_U32_FROM_U8(pDis->u.abInstr[offInstr], pDis->u.abInstr[offInstr + 1], 0, 0);
     217        case 3:
     218            return RT_MAKE_U32_FROM_U8(pDis->u.abInstr[offInstr], pDis->u.abInstr[offInstr + 1], pDis->u.abInstr[offInstr + 2], 0);
     219        default:
     220            if (cbLeft >= 4)
     221                return RT_MAKE_U32_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
     222                                           pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3]);
     223            return 0;
     224    }
     225}
     226
     227
     228/**
     229 * Function for handling a 64-bit cache miss.
     230 *
     231 * @returns The requested qword.
     232 * @param   pDis                The disassembler state.
     233 * @param   offInstr            The offset of the qword relative to the
     234 *                              instruction.
     235 */
     236DECLHIDDEN(uint64_t) disReadQWordSlow(PDISSTATE pDis, size_t offInstr)
     237{
     238    if (RT_LIKELY(offInstr + 8 <= DIS_MAX_INSTR_LENGTH))
     239    {
     240        disReadMore(pDis, (uint8_t)offInstr, 8);
     241#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
     242        return *(uint64_t const *)&pDis->u.abInstr[offInstr];
     243#else
     244        return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
     245                                   pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3],
     246                                   pDis->u.abInstr[offInstr + 4], pDis->u.abInstr[offInstr + 5],
     247                                   pDis->u.abInstr[offInstr + 6], pDis->u.abInstr[offInstr + 7]);
     248#endif
     249    }
     250
     251    Log(("disReadQWord: too long instruction...\n"));
     252    pDis->rc = VERR_DIS_TOO_LONG_INSTR;
     253    ssize_t cbLeft = (ssize_t)(sizeof(pDis->u.abInstr) - offInstr);
     254    switch (cbLeft)
     255    {
     256        case 1:
     257            return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr], 0, 0, 0,   0, 0, 0, 0);
     258        case 2:
     259            return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr], pDis->u.abInstr[offInstr + 1], 0, 0,   0, 0, 0, 0);
     260        case 3:
     261            return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
     262                                       pDis->u.abInstr[offInstr + 2], 0,   0, 0, 0, 0);
     263        case 4:
     264            return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
     265                                       pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3],
     266                                       0, 0, 0, 0);
     267        case 5:
     268            return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
     269                                       pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3],
     270                                       pDis->u.abInstr[offInstr + 4], 0, 0, 0);
     271        case 6:
     272            return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
     273                                       pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3],
     274                                       pDis->u.abInstr[offInstr + 4], pDis->u.abInstr[offInstr + 5],
     275                                       0, 0);
     276        case 7:
     277            return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
     278                                       pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3],
     279                                       pDis->u.abInstr[offInstr + 4], pDis->u.abInstr[offInstr + 5],
     280                                       pDis->u.abInstr[offInstr + 6], 0);
     281        default:
     282            if (cbLeft >= 8)
     283                return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
     284                                           pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3],
     285                                           pDis->u.abInstr[offInstr + 4], pDis->u.abInstr[offInstr + 5],
     286                                           pDis->u.abInstr[offInstr + 6], pDis->u.abInstr[offInstr + 7]);
     287            return 0;
     288    }
     289}
     290
     291
     292/**
     293 * Inlined worker that initializes the disassembler state.
     294 *
     295 * @returns The primary opcode map to use.
     296 * @param   pDis            The disassembler state.
     297 * @param   uInstrAddr      The instruction address.
     298 * @param   enmCpuMode      The CPU mode.
     299 * @param   fFilter         The instruction filter settings.
     300 * @param   pfnReadBytes    The byte reader, can be NULL.
     301 * @param   pvUser          The user data for the reader.
     302 */
     303DECL_FORCE_INLINE(PCDISOPCODE)
     304disInitializeState(PDISSTATE pDis, RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter,
     305                   PFNDISREADBYTES pfnReadBytes, void *pvUser)
     306{
     307    RT_ZERO(*pDis);
     308
     309    pDis->rc                = VINF_SUCCESS;
     310    pDis->uInstrAddr        = uInstrAddr;
     311    pDis->pfnReadBytes      = pfnReadBytes ? pfnReadBytes : disReadBytesDefault;
     312    pDis->pvUser            = pvUser;
     313    pDis->uCpuMode          = (uint8_t)enmCpuMode;
     314    return disInitializeStateX86(pDis, enmCpuMode, fFilter);
     315}
     316
     317
     318/**
     319 * Disassembles on instruction, details in @a pDis and length in @a pcbInstr.
     320 *
     321 * @returns VBox status code.
     322 * @param   uInstrAddr      Address of the instruction to decode. What this means
     323 *                          is left to the pfnReadBytes function.
     324 * @param   enmCpuMode      The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
     325 * @param   pfnReadBytes    Callback for reading instruction bytes.
     326 * @param   fFilter         Instruction type filter.
     327 * @param   pvUser          User argument for the instruction reader. (Ends up in pvUser.)
     328 * @param   pDis            Pointer to disassembler state (output).
     329 * @param   pcbInstr        Where to store the size of the instruction.  (This
     330 *                          is also stored in PDISSTATE::cbInstr.)  Optional.
     331 */
     332DISDECL(int) DISInstrEx(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter,
     333                        PFNDISREADBYTES pfnReadBytes, void *pvUser,
     334                        PDISSTATE pDis, uint32_t *pcbInstr)
     335{
     336
     337    PCDISOPCODE paOneByteMap = disInitializeState(pDis, uInstrAddr, enmCpuMode, fFilter, pfnReadBytes, pvUser);
     338    disPrefetchBytes(pDis);
     339    return disInstrWorkerX86(pDis, paOneByteMap, pcbInstr);
     340}
     341
     342
     343/**
     344 * Disassembles on instruction partially or fully from prefetched bytes, details
     345 * in @a pDis and length in @a pcbInstr.
     346 *
     347 * @returns VBox status code.
     348 * @param   uInstrAddr      Address of the instruction to decode. What this means
     349 *                          is left to the pfnReadBytes function.
     350 * @param   enmCpuMode      The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
     351 * @param   pvPrefetched    Pointer to the prefetched bytes.
     352 * @param   cbPrefetched    The number of valid bytes pointed to by @a
     353 *                          pbPrefetched.
     354 * @param   pfnReadBytes    Callback for reading instruction bytes.
     355 * @param   fFilter         Instruction type filter.
     356 * @param   pvUser          User argument for the instruction reader. (Ends up in pvUser.)
     357 * @param   pDis            Pointer to disassembler state (output).
     358 * @param   pcbInstr        Where to store the size of the instruction.  (This
     359 *                          is also stored in PDISSTATE::cbInstr.)  Optional.
     360 */
     361DISDECL(int) DISInstrWithPrefetchedBytes(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter,
     362                                         void const *pvPrefetched, size_t cbPretched,
     363                                         PFNDISREADBYTES pfnReadBytes, void *pvUser,
     364                                         PDISSTATE pDis, uint32_t *pcbInstr)
     365{
     366    PCDISOPCODE paOneByteMap = disInitializeState(pDis, uInstrAddr, enmCpuMode, fFilter, pfnReadBytes, pvUser);
     367
     368    if (!cbPretched)
     369        disPrefetchBytes(pDis);
     370    else
     371    {
     372        if (cbPretched >= sizeof(pDis->u.abInstr))
     373        {
     374            memcpy(pDis->u.abInstr, pvPrefetched, sizeof(pDis->u.abInstr));
     375            pDis->cbCachedInstr = (uint8_t)sizeof(pDis->u.abInstr);
     376        }
     377        else
     378        {
     379            memcpy(pDis->u.abInstr, pvPrefetched, cbPretched);
     380            pDis->cbCachedInstr = (uint8_t)cbPretched;
     381        }
     382    }
     383
     384    return disInstrWorkerX86(pDis, paOneByteMap, pcbInstr);
     385}
     386
     387
     388/**
     389 * Parses one guest instruction.
     390 *
     391 * The result is found in pDis and pcbInstr.
     392 *
     393 * @returns VBox status code.
     394 * @param   uInstrAddr      Address of the instruction to decode. What this means
     395 *                          is left to the pfnReadBytes function.
     396 * @param   enmCpuMode      The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
     397 * @param   pfnReadBytes    Callback for reading instruction bytes.
     398 * @param   pvUser          User argument for the instruction reader. (Ends up in pvUser.)
     399 * @param   pDis            Pointer to disassembler state (output).
     400 * @param   pcbInstr        Where to store the size of the instruction.
     401 *                          NULL is allowed.  This is also stored in
     402 *                          PDISSTATE::cbInstr.
     403 */
     404DISDECL(int) DISInstrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser,
     405                                PDISSTATE pDis, uint32_t *pcbInstr)
     406{
     407    return DISInstrEx(uInstrAddr, enmCpuMode, DISOPTYPE_ALL, pfnReadBytes, pvUser, pDis, pcbInstr);
     408}
     409
     410
     411/**
     412 * Parses one guest instruction.
     413 *
     414 * The result is found in pDis and pcbInstr.
     415 *
     416 * @returns VBox status code.
     417 * @param   pvInstr         Address of the instruction to decode.  This is a
     418 *                          real address in the current context that can be
     419 *                          accessed without faulting.  (Consider
     420 *                          DISInstrWithReader if this isn't the case.)
     421 * @param   enmCpuMode      The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
     422 * @param   pfnReadBytes    Callback for reading instruction bytes.
     423 * @param   pvUser          User argument for the instruction reader. (Ends up in pvUser.)
     424 * @param   pDis            Pointer to disassembler state (output).
     425 * @param   pcbInstr        Where to store the size of the instruction.
     426 *                          NULL is allowed.  This is also stored in
     427 *                          PDISSTATE::cbInstr.
     428 */
     429DISDECL(int) DISInstr(const void *pvInstr, DISCPUMODE enmCpuMode, PDISSTATE pDis, uint32_t *pcbInstr)
     430{
     431    return DISInstrEx((uintptr_t)pvInstr, enmCpuMode, DISOPTYPE_ALL, NULL /*pfnReadBytes*/, NULL /*pvUser*/, pDis, pcbInstr);
     432}
     433
     434
     435#ifndef DIS_CORE_ONLY
    40436/**
    41437 * Disassembles one instruction
     
    58454                           pDis, pcbInstr, pszOutput, cbOutput);
    59455}
     456
    60457
    61458/**
     
    84481}
    85482
     483
    86484/**
    87485 * Disassembles one instruction; only fully disassembly an instruction if it matches the filter criteria
     
    123521    return rc;
    124522}
    125 
     523#endif /* DIS_CORE_ONLY */
     524
  • trunk/src/VBox/Disassembler/DisasmCore-x86-amd64.cpp

    r99235 r99236  
    3939#include <iprt/string.h>
    4040#include <iprt/stdarg.h>
    41 #include "DisasmInternal.h"
     41#include "DisasmInternal-x86-amd64.h"
    4242
    4343
     
    4545*   Defined Constants And Macros                                                                                                 *
    4646*********************************************************************************************************************************/
    47 /** This must be less or equal to DISSTATE::u.abInstr.
    48  * See Vol3A/Table 6-2 and Vol3B/Section22.25 for instance.  */
    49 #define DIS_MAX_INSTR_LENGTH    15
    50 
    51 /** Whether we can do unaligned access. */
    52 #if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)
    53 # define DIS_HOST_UNALIGNED_ACCESS_OK
    54 #endif
    5547
    5648
     
    232224
    233225
    234 
    235 
    236 
    237 /********************************************************************************************************************************
    238  *
    239  *
    240  * Read functions for getting the opcode bytes
    241  *
    242  *
    243  ********************************************************************************************************************************/
    244 
    245 /**
    246  * @interface_method_impl{FNDISREADBYTES, The default byte reader callber.}
    247  */
    248 static DECLCALLBACK(int) disReadBytesDefault(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
    249 {
    250 #if 0 /*def IN_RING0 - why? */
    251     RT_NOREF_PV(cbMinRead);
    252     AssertMsgFailed(("disReadWord with no read callback in ring 0!!\n"));
    253     RT_BZERO(&pDis->u.abInstr[offInstr], cbMaxRead);
    254     pDis->cbCachedInstr = offInstr + cbMaxRead;
    255     return VERR_DIS_NO_READ_CALLBACK;
    256 #else
    257     uint8_t const  *pbSrc        = (uint8_t const *)(uintptr_t)pDis->uInstrAddr + offInstr;
    258     size_t          cbLeftOnPage = (uintptr_t)pbSrc & PAGE_OFFSET_MASK;
    259     uint8_t         cbToRead     = cbLeftOnPage >= cbMaxRead
    260                                  ? cbMaxRead
    261                                  : cbLeftOnPage <= cbMinRead
    262                                  ? cbMinRead
    263                                  : (uint8_t)cbLeftOnPage;
    264     memcpy(&pDis->u.abInstr[offInstr], pbSrc, cbToRead);
    265     pDis->cbCachedInstr = offInstr + cbToRead;
    266     return VINF_SUCCESS;
    267 #endif
    268 }
    269 
    270 
    271 /**
    272  * Read more bytes into the DISSTATE::u.abInstr buffer, advance
    273  * DISSTATE::cbCachedInstr.
    274  *
    275  * Will set DISSTATE::rc on failure, but still advance cbCachedInstr.
    276  *
    277  * The caller shall fend off reads beyond the DISSTATE::u.abInstr buffer.
    278  *
    279  * @param   pDis                The disassembler state.
    280  * @param   offInstr            The offset of the read request.
    281  * @param   cbMin               The size of the read request that needs to be
    282  *                              satisfied.
    283  */
    284 DECL_NO_INLINE(static, void) disReadMore(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMin)
    285 {
    286     Assert(cbMin + offInstr <= sizeof(pDis->u.abInstr));
    287 
    288     /*
    289      * Adjust the incoming request to not overlap with bytes that has already
    290      * been read and to make sure we don't leave unread gaps.
    291      */
    292     if (offInstr < pDis->cbCachedInstr)
    293     {
    294         Assert(offInstr + cbMin > pDis->cbCachedInstr);
    295         cbMin -= pDis->cbCachedInstr - offInstr;
    296         offInstr = pDis->cbCachedInstr;
    297     }
    298     else if (offInstr > pDis->cbCachedInstr)
    299     {
    300         cbMin += offInstr - pDis->cbCachedInstr;
    301         offInstr = pDis->cbCachedInstr;
    302     }
    303 
    304     /*
    305      * Do the read.
    306      * (No need to zero anything on failure as u.abInstr is already zeroed by the
    307      * DISInstrEx API.)
    308      */
    309     int rc = pDis->pfnReadBytes(pDis, offInstr, cbMin, sizeof(pDis->u.abInstr) - offInstr);
    310     if (RT_SUCCESS(rc))
    311     {
    312         Assert(pDis->cbCachedInstr >= offInstr + cbMin);
    313         Assert(pDis->cbCachedInstr <= sizeof(pDis->u.abInstr));
    314     }
    315     else
    316     {
    317         Log(("disReadMore failed with rc=%Rrc!!\n", rc));
    318         pDis->rc = rc;
    319     }
    320 }
    321 
    322 
    323 /**
    324  * Function for handling a 8-bit cache miss.
    325  *
    326  * @returns The requested byte.
    327  * @param   pDis                The disassembler state.
    328  * @param   offInstr            The offset of the byte relative to the
    329  *                              instruction.
    330  */
    331 DECL_NO_INLINE(static, uint8_t) disReadByteSlow(PDISSTATE pDis, size_t offInstr)
    332 {
    333     if (RT_LIKELY(offInstr < DIS_MAX_INSTR_LENGTH))
    334     {
    335         disReadMore(pDis, (uint8_t)offInstr, 1);
    336         return pDis->u.abInstr[offInstr];
    337     }
    338 
    339     Log(("disReadByte: too long instruction...\n"));
    340     pDis->rc = VERR_DIS_TOO_LONG_INSTR;
    341     ssize_t cbLeft = (ssize_t)(sizeof(pDis->u.abInstr) - offInstr);
    342     if (cbLeft > 0)
    343         return pDis->u.abInstr[offInstr];
    344     return 0;
    345 }
    346 
    347 
    348 /**
    349  * Read a byte (8-bit) instruction.
    350  *
    351  * @returns The requested byte.
    352  * @param   pDis                The disassembler state.
    353  * @param   uAddress            The address.
    354  */
    355 DECLINLINE(uint8_t) disReadByte(PDISSTATE pDis, size_t offInstr)
    356 {
    357     if (offInstr >= pDis->cbCachedInstr)
    358         return disReadByteSlow(pDis, offInstr);
    359     return pDis->u.abInstr[offInstr];
    360 }
    361 
    362 
    363 /**
    364  * Function for handling a 16-bit cache miss.
    365  *
    366  * @returns The requested word.
    367  * @param   pDis                The disassembler state.
    368  * @param   offInstr            The offset of the word relative to the
    369  *                              instruction.
    370  */
    371 DECL_NO_INLINE(static, uint16_t) disReadWordSlow(PDISSTATE pDis, size_t offInstr)
    372 {
    373     if (RT_LIKELY(offInstr + 2 <= DIS_MAX_INSTR_LENGTH))
    374     {
    375         disReadMore(pDis, (uint8_t)offInstr, 2);
    376 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK
    377         return *(uint16_t const *)&pDis->u.abInstr[offInstr];
    378 #else
    379         return RT_MAKE_U16(pDis->u.abInstr[offInstr], pDis->u.abInstr[offInstr + 1]);
    380 #endif
    381     }
    382 
    383     Log(("disReadWord: too long instruction...\n"));
    384     pDis->rc = VERR_DIS_TOO_LONG_INSTR;
    385     ssize_t cbLeft = (ssize_t)(sizeof(pDis->u.abInstr) - offInstr);
    386     switch (cbLeft)
    387     {
    388         case 1:
    389             return pDis->u.abInstr[offInstr];
    390         default:
    391             if (cbLeft >= 2)
    392                 return RT_MAKE_U16(pDis->u.abInstr[offInstr], pDis->u.abInstr[offInstr + 1]);
    393             return 0;
    394     }
    395 }
    396 
    397 
    398 /**
    399  * Read a word (16-bit) instruction.
    400  *
    401  * @returns The requested word.
    402  * @param   pDis                The disassembler state.
    403  * @param   offInstr            The offset of the qword relative to the
    404  *                              instruction.
    405  */
    406 DECLINLINE(uint16_t) disReadWord(PDISSTATE pDis, size_t offInstr)
    407 {
    408     if (offInstr + 2 > pDis->cbCachedInstr)
    409         return disReadWordSlow(pDis, offInstr);
    410 
    411 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK
    412     return *(uint16_t const *)&pDis->u.abInstr[offInstr];
    413 #else
    414     return RT_MAKE_U16(pDis->u.abInstr[offInstr], pDis->u.abInstr[offInstr + 1]);
    415 #endif
    416 }
    417 
    418 
    419 /**
    420  * Function for handling a 32-bit cache miss.
    421  *
    422  * @returns The requested dword.
    423  * @param   pDis                The disassembler state.
    424  * @param   offInstr            The offset of the dword relative to the
    425  *                              instruction.
    426  */
    427 DECL_NO_INLINE(static, uint32_t) disReadDWordSlow(PDISSTATE pDis, size_t offInstr)
    428 {
    429     if (RT_LIKELY(offInstr + 4 <= DIS_MAX_INSTR_LENGTH))
    430     {
    431         disReadMore(pDis, (uint8_t)offInstr, 4);
    432 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK
    433         return *(uint32_t const *)&pDis->u.abInstr[offInstr];
    434 #else
    435         return RT_MAKE_U32_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
    436                                    pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3]);
    437 #endif
    438     }
    439 
    440     Log(("disReadDWord: too long instruction...\n"));
    441     pDis->rc = VERR_DIS_TOO_LONG_INSTR;
    442     ssize_t cbLeft = (ssize_t)(sizeof(pDis->u.abInstr) - offInstr);
    443     switch (cbLeft)
    444     {
    445         case 1:
    446             return RT_MAKE_U32_FROM_U8(pDis->u.abInstr[offInstr], 0, 0, 0);
    447         case 2:
    448             return RT_MAKE_U32_FROM_U8(pDis->u.abInstr[offInstr], pDis->u.abInstr[offInstr + 1], 0, 0);
    449         case 3:
    450             return RT_MAKE_U32_FROM_U8(pDis->u.abInstr[offInstr], pDis->u.abInstr[offInstr + 1], pDis->u.abInstr[offInstr + 2], 0);
    451         default:
    452             if (cbLeft >= 4)
    453                 return RT_MAKE_U32_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
    454                                            pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3]);
    455             return 0;
    456     }
    457 }
    458 
    459 
    460 /**
    461  * Read a dword (32-bit) instruction.
    462  *
    463  * @returns The requested dword.
    464  * @param   pDis                The disassembler state.
    465  * @param   offInstr            The offset of the qword relative to the
    466  *                              instruction.
    467  */
    468 DECLINLINE(uint32_t) disReadDWord(PDISSTATE pDis, size_t offInstr)
    469 {
    470     if (offInstr + 4 > pDis->cbCachedInstr)
    471         return disReadDWordSlow(pDis, offInstr);
    472 
    473 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK
    474     return *(uint32_t const *)&pDis->u.abInstr[offInstr];
    475 #else
    476     return RT_MAKE_U32_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
    477                                pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3]);
    478 #endif
    479 }
    480 
    481 
    482 /**
    483  * Function for handling a 64-bit cache miss.
    484  *
    485  * @returns The requested qword.
    486  * @param   pDis                The disassembler state.
    487  * @param   offInstr            The offset of the qword relative to the
    488  *                              instruction.
    489  */
    490 DECL_NO_INLINE(static, uint64_t) disReadQWordSlow(PDISSTATE pDis, size_t offInstr)
    491 {
    492     if (RT_LIKELY(offInstr + 8 <= DIS_MAX_INSTR_LENGTH))
    493     {
    494         disReadMore(pDis, (uint8_t)offInstr, 8);
    495 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK
    496         return *(uint64_t const *)&pDis->u.abInstr[offInstr];
    497 #else
    498         return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
    499                                    pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3],
    500                                    pDis->u.abInstr[offInstr + 4], pDis->u.abInstr[offInstr + 5],
    501                                    pDis->u.abInstr[offInstr + 6], pDis->u.abInstr[offInstr + 7]);
    502 #endif
    503     }
    504 
    505     Log(("disReadQWord: too long instruction...\n"));
    506     pDis->rc = VERR_DIS_TOO_LONG_INSTR;
    507     ssize_t cbLeft = (ssize_t)(sizeof(pDis->u.abInstr) - offInstr);
    508     switch (cbLeft)
    509     {
    510         case 1:
    511             return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr], 0, 0, 0,   0, 0, 0, 0);
    512         case 2:
    513             return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr], pDis->u.abInstr[offInstr + 1], 0, 0,   0, 0, 0, 0);
    514         case 3:
    515             return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
    516                                        pDis->u.abInstr[offInstr + 2], 0,   0, 0, 0, 0);
    517         case 4:
    518             return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
    519                                        pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3],
    520                                        0, 0, 0, 0);
    521         case 5:
    522             return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
    523                                        pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3],
    524                                        pDis->u.abInstr[offInstr + 4], 0, 0, 0);
    525         case 6:
    526             return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
    527                                        pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3],
    528                                        pDis->u.abInstr[offInstr + 4], pDis->u.abInstr[offInstr + 5],
    529                                        0, 0);
    530         case 7:
    531             return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
    532                                        pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3],
    533                                        pDis->u.abInstr[offInstr + 4], pDis->u.abInstr[offInstr + 5],
    534                                        pDis->u.abInstr[offInstr + 6], 0);
    535         default:
    536             if (cbLeft >= 8)
    537                 return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
    538                                            pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3],
    539                                            pDis->u.abInstr[offInstr + 4], pDis->u.abInstr[offInstr + 5],
    540                                            pDis->u.abInstr[offInstr + 6], pDis->u.abInstr[offInstr + 7]);
    541             return 0;
    542     }
    543 }
    544 
    545 
    546 /**
    547  * Read a qword (64-bit) instruction.
    548  *
    549  * @returns The requested qword.
    550  * @param   pDis                The disassembler state.
    551  * @param   uAddress            The address.
    552  */
    553 DECLINLINE(uint64_t) disReadQWord(PDISSTATE pDis, size_t offInstr)
    554 {
    555     if (offInstr + 8 > pDis->cbCachedInstr)
    556         return disReadQWordSlow(pDis, offInstr);
    557 
    558 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK
    559     return *(uint64_t const *)&pDis->u.abInstr[offInstr];
    560 #else
    561     return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
    562                                pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3],
    563                                pDis->u.abInstr[offInstr + 4], pDis->u.abInstr[offInstr + 5],
    564                                pDis->u.abInstr[offInstr + 6], pDis->u.abInstr[offInstr + 7]);
    565 #endif
    566 }
    567 
    568 
    569 
    570226//*****************************************************************************
    571227//*****************************************************************************
     
    26722328 * @param   pcbInstr        Where to store the instruction size. Can be NULL.
    26732329 */
    2674 static int disInstrWorker(PDISSTATE pDis, PCDISOPCODE paOneByteMap, uint32_t *pcbInstr)
     2330DECLHIDDEN(int) disInstrWorkerX86(PDISSTATE pDis, PCDISOPCODE paOneByteMap, uint32_t *pcbInstr)
    26752331{
    26762332    /*
     
    28012457 * @param   pvUser          The user data for the reader.
    28022458 */
    2803 DECL_FORCE_INLINE(PCDISOPCODE)
    2804 disInitializeState(PDISSTATE pDis, RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter,
    2805                    PFNDISREADBYTES pfnReadBytes, void *pvUser)
     2459DECLHIDDEN(PCDISOPCODE) disInitializeStateX86(PDISSTATE pDis, DISCPUMODE enmCpuMode, uint32_t fFilter)
    28062460{
    28072461    RT_ZERO(*pDis);
     
    28302484    pDis->arch.x86.fFilter           = fFilter;
    28312485
    2832     pDis->rc                = VINF_SUCCESS;
    2833     pDis->uInstrAddr        = uInstrAddr;
    2834     pDis->pfnReadBytes      = pfnReadBytes ? pfnReadBytes : disReadBytesDefault;
    2835     pDis->pvUser            = pvUser;
    2836     pDis->uCpuMode          = (uint8_t)enmCpuMode;
    28372486    PCDISOPCODE paOneByteMap;
    28382487    if (enmCpuMode == DISCPUMODE_64BIT)
     
    28502499    return paOneByteMap;
    28512500}
    2852 
    2853 
    2854 /**
    2855  * Reads some bytes into the cache.
    2856  *
    2857  * While this will set DISSTATE::rc on failure, the caller should disregard
    2858  * this since that is what would happen if we didn't prefetch bytes prior to the
    2859  * instruction parsing.
    2860  *
    2861  * @param   pDis                The disassembler state.
    2862  */
    2863 DECL_FORCE_INLINE(void) disPrefetchBytes(PDISSTATE pDis)
    2864 {
    2865     /*
    2866      * Read some bytes into the cache.  (If this fail we continue as nothing
    2867      * has gone wrong since this is what would happen if we didn't precharge
    2868      * the cache here.)
    2869      */
    2870     int rc = pDis->pfnReadBytes(pDis, 0, 1, sizeof(pDis->u.abInstr));
    2871     if (RT_SUCCESS(rc))
    2872     {
    2873         Assert(pDis->cbCachedInstr >= 1);
    2874         Assert(pDis->cbCachedInstr <= sizeof(pDis->u.abInstr));
    2875     }
    2876     else
    2877     {
    2878         Log(("Initial read failed with rc=%Rrc!!\n", rc));
    2879         pDis->rc = rc;
    2880     }
    2881 }
    2882 
    2883 
    2884 /**
    2885  * Disassembles on instruction, details in @a pDis and length in @a pcbInstr.
    2886  *
    2887  * @returns VBox status code.
    2888  * @param   uInstrAddr      Address of the instruction to decode. What this means
    2889  *                          is left to the pfnReadBytes function.
    2890  * @param   enmCpuMode      The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
    2891  * @param   pfnReadBytes    Callback for reading instruction bytes.
    2892  * @param   fFilter         Instruction type filter.
    2893  * @param   pvUser          User argument for the instruction reader. (Ends up in pvUser.)
    2894  * @param   pDis            Pointer to disassembler state (output).
    2895  * @param   pcbInstr        Where to store the size of the instruction.  (This
    2896  *                          is also stored in PDISSTATE::cbInstr.)  Optional.
    2897  */
    2898 DISDECL(int) DISInstrEx(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter,
    2899                         PFNDISREADBYTES pfnReadBytes, void *pvUser,
    2900                         PDISSTATE pDis, uint32_t *pcbInstr)
    2901 {
    2902 
    2903     PCDISOPCODE paOneByteMap = disInitializeState(pDis, uInstrAddr, enmCpuMode, fFilter, pfnReadBytes, pvUser);
    2904     disPrefetchBytes(pDis);
    2905     return disInstrWorker(pDis, paOneByteMap, pcbInstr);
    2906 }
    2907 
    2908 
    2909 /**
    2910  * Disassembles on instruction partially or fully from prefetched bytes, details
    2911  * in @a pDis and length in @a pcbInstr.
    2912  *
    2913  * @returns VBox status code.
    2914  * @param   uInstrAddr      Address of the instruction to decode. What this means
    2915  *                          is left to the pfnReadBytes function.
    2916  * @param   enmCpuMode      The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
    2917  * @param   pvPrefetched    Pointer to the prefetched bytes.
    2918  * @param   cbPrefetched    The number of valid bytes pointed to by @a
    2919  *                          pbPrefetched.
    2920  * @param   pfnReadBytes    Callback for reading instruction bytes.
    2921  * @param   fFilter         Instruction type filter.
    2922  * @param   pvUser          User argument for the instruction reader. (Ends up in pvUser.)
    2923  * @param   pDis            Pointer to disassembler state (output).
    2924  * @param   pcbInstr        Where to store the size of the instruction.  (This
    2925  *                          is also stored in PDISSTATE::cbInstr.)  Optional.
    2926  */
    2927 DISDECL(int) DISInstrWithPrefetchedBytes(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter,
    2928                                          void const *pvPrefetched, size_t cbPretched,
    2929                                          PFNDISREADBYTES pfnReadBytes, void *pvUser,
    2930                                          PDISSTATE pDis, uint32_t *pcbInstr)
    2931 {
    2932     PCDISOPCODE paOneByteMap = disInitializeState(pDis, uInstrAddr, enmCpuMode, fFilter, pfnReadBytes, pvUser);
    2933 
    2934     if (!cbPretched)
    2935         disPrefetchBytes(pDis);
    2936     else
    2937     {
    2938         if (cbPretched >= sizeof(pDis->u.abInstr))
    2939         {
    2940             memcpy(pDis->u.abInstr, pvPrefetched, sizeof(pDis->u.abInstr));
    2941             pDis->cbCachedInstr = (uint8_t)sizeof(pDis->u.abInstr);
    2942         }
    2943         else
    2944         {
    2945             memcpy(pDis->u.abInstr, pvPrefetched, cbPretched);
    2946             pDis->cbCachedInstr = (uint8_t)cbPretched;
    2947         }
    2948     }
    2949 
    2950     return disInstrWorker(pDis, paOneByteMap, pcbInstr);
    2951 }
    2952 
    2953 
    2954 
    2955 /**
    2956  * Parses one guest instruction.
    2957  *
    2958  * The result is found in pDis and pcbInstr.
    2959  *
    2960  * @returns VBox status code.
    2961  * @param   uInstrAddr      Address of the instruction to decode. What this means
    2962  *                          is left to the pfnReadBytes function.
    2963  * @param   enmCpuMode      The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
    2964  * @param   pfnReadBytes    Callback for reading instruction bytes.
    2965  * @param   pvUser          User argument for the instruction reader. (Ends up in pvUser.)
    2966  * @param   pDis            Pointer to disassembler state (output).
    2967  * @param   pcbInstr        Where to store the size of the instruction.
    2968  *                          NULL is allowed.  This is also stored in
    2969  *                          PDISSTATE::cbInstr.
    2970  */
    2971 DISDECL(int) DISInstrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser,
    2972                                 PDISSTATE pDis, uint32_t *pcbInstr)
    2973 {
    2974     return DISInstrEx(uInstrAddr, enmCpuMode, DISOPTYPE_ALL, pfnReadBytes, pvUser, pDis, pcbInstr);
    2975 }
    2976 
    2977 
    2978 /**
    2979  * Parses one guest instruction.
    2980  *
    2981  * The result is found in pDis and pcbInstr.
    2982  *
    2983  * @returns VBox status code.
    2984  * @param   pvInstr         Address of the instruction to decode.  This is a
    2985  *                          real address in the current context that can be
    2986  *                          accessed without faulting.  (Consider
    2987  *                          DISInstrWithReader if this isn't the case.)
    2988  * @param   enmCpuMode      The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
    2989  * @param   pfnReadBytes    Callback for reading instruction bytes.
    2990  * @param   pvUser          User argument for the instruction reader. (Ends up in pvUser.)
    2991  * @param   pDis            Pointer to disassembler state (output).
    2992  * @param   pcbInstr        Where to store the size of the instruction.
    2993  *                          NULL is allowed.  This is also stored in
    2994  *                          PDISSTATE::cbInstr.
    2995  */
    2996 DISDECL(int) DISInstr(const void *pvInstr, DISCPUMODE enmCpuMode, PDISSTATE pDis, uint32_t *pcbInstr)
    2997 {
    2998     return DISInstrEx((uintptr_t)pvInstr, enmCpuMode, DISOPTYPE_ALL, NULL /*pfnReadBytes*/, NULL /*pvUser*/, pDis, pcbInstr);
    2999 }
    3000 
  • trunk/src/VBox/Disassembler/DisasmInternal-x86-amd64.h

    r99231 r99236  
    2626 */
    2727
    28 #ifndef VBOX_INCLUDED_SRC_DisasmInternal_h
    29 #define VBOX_INCLUDED_SRC_DisasmInternal_h
     28#ifndef VBOX_INCLUDED_SRC_DisasmInternal_x86_amd64_h
     29#define VBOX_INCLUDED_SRC_DisasmInternal_x86_amd64_h
    3030#ifndef RT_WITHOUT_PRAGMA_ONCE
    3131# pragma once
     
    3333
    3434#include <VBox/types.h>
     35#include <VBox/err.h>
    3536#include <VBox/dis.h>
    36 
    37 
    38 /** @defgroup grp_dis_int Internals.
     37#include <VBox/log.h>
     38
     39#include <iprt/param.h>
     40#include "DisasmInternal.h"
     41
     42
     43/** @addtogroup grp_dis_int Internals.
    3944 * @ingroup grp_dis
    4045 * @{
     
    227232/** @} */
    228233
    229 /** @def OP
    230  * Wrapper which initializes an DISOPCODE.
    231  * We must use this so that we can exclude unused fields in order
    232  * to save precious bytes in the GC version.
    233  *
    234  * @internal
    235  */
    236 #if DISOPCODE_FORMAT == 0
    237 # define OP(pszOpcode, idxParse1, idxParse2, idxParse3, opcode, param1, param2, param3, optype) \
    238     { pszOpcode, idxParse1, idxParse2, idxParse3, 0, opcode, param1, param2, param3, 0, 0, optype }
    239 # define OPVEX(pszOpcode, idxParse1, idxParse2, idxParse3, idxParse4, opcode, param1, param2, param3, param4, optype) \
    240     { pszOpcode, idxParse1, idxParse2, idxParse3, idxParse4, opcode, param1, param2, param3, param4, 0, optype | DISOPTYPE_X86_SSE }
    241 
    242 #elif DISOPCODE_FORMAT == 16
    243 # define OP(pszOpcode, idxParse1, idxParse2, idxParse3, opcode, param1, param2, param3, optype) \
    244     { optype,                 opcode, idxParse1, idxParse2, param1, param2, idxParse3, param3, 0,      0         }
    245 # define OPVEX(pszOpcode, idxParse1, idxParse2, idxParse3, idxParse4, opcode, param1, param2, param3, param4, optype) \
    246     { optype | DISOPTYPE_X86_SSE, opcode, idxParse1, idxParse2, param1, param2, idxParse3, param3, param4, idxParse4 }
    247 
    248 #elif DISOPCODE_FORMAT == 15
    249 # define OP(pszOpcode, idxParse1, idxParse2, idxParse3, opcode, param1, param2, param3, optype) \
    250     { opcode, idxParse1, idxParse2, idxParse3, param1, param2, param3, optype,                 0,      0         }
    251 # define OPVEX(pszOpcode, idxParse1, idxParse2, idxParse3, idxParse4, opcode, param1, param2, param3, param4, optype) \
    252     { opcode, idxParse1, idxParse2, idxParse3, param1, param2, param3, optype | DISOPTYPE_X86_SSE, param4, idxParse4 }
    253 #else
    254 # error Unsupported DISOPCODE_FORMAT value
    255 #endif
    256 
    257 
    258 size_t disFormatBytes(PCDISSTATE pDis, char *pszDst, size_t cchDst, uint32_t fFlags);
    259 
    260 /** @} */
    261 #endif /* !VBOX_INCLUDED_SRC_DisasmInternal_h */
    262 
     234
     235/** @} */
     236#endif /* !VBOX_INCLUDED_SRC_DisasmInternal_x86_amd64_h */
     237
  • trunk/src/VBox/Disassembler/DisasmInternal.h

    r99220 r99236  
    3333
    3434#include <VBox/types.h>
     35#include <VBox/err.h>
    3536#include <VBox/dis.h>
     37#include <VBox/log.h>
     38
     39#include <iprt/param.h>
    3640
    3741
     
    4145 */
    4246
    43 /** @name Index into g_apfnCalcSize and g_apfnFullDisasm.
    44  * @{ */
    45 enum IDX_Parse
    46 {
    47   IDX_ParseNop = 0,
    48   IDX_ParseModRM,
    49   IDX_UseModRM,
    50   IDX_ParseImmByte,
    51   IDX_ParseImmBRel,
    52   IDX_ParseImmUshort,
    53   IDX_ParseImmV,
    54   IDX_ParseImmVRel,
    55   IDX_ParseImmAddr,
    56   IDX_ParseFixedReg,
    57   IDX_ParseImmUlong,
    58   IDX_ParseImmQword,
    59   IDX_ParseTwoByteEsc,
    60   IDX_ParseGrp1,
    61   IDX_ParseShiftGrp2,
    62   IDX_ParseGrp3,
    63   IDX_ParseGrp4,
    64   IDX_ParseGrp5,
    65   IDX_Parse3DNow,
    66   IDX_ParseGrp6,
    67   IDX_ParseGrp7,
    68   IDX_ParseGrp8,
    69   IDX_ParseGrp9,
    70   IDX_ParseGrp10,
    71   IDX_ParseGrp12,
    72   IDX_ParseGrp13,
    73   IDX_ParseGrp14,
    74   IDX_ParseGrp15,
    75   IDX_ParseGrp16,
    76   IDX_ParseGrp17,
    77   IDX_ParseModFence,
    78   IDX_ParseYv,
    79   IDX_ParseYb,
    80   IDX_ParseXv,
    81   IDX_ParseXb,
    82   IDX_ParseEscFP,
    83   IDX_ParseNopPause,
    84   IDX_ParseImmByteSX,
    85   IDX_ParseImmZ,
    86   IDX_ParseThreeByteEsc4,
    87   IDX_ParseThreeByteEsc5,
    88   IDX_ParseImmAddrF,
    89   IDX_ParseInvOpModRM,
    90   IDX_ParseVex2b,
    91   IDX_ParseVex3b,
    92   IDX_ParseVexDest,
    93   IDX_ParseMax
    94 };
    95 AssertCompile(IDX_ParseMax < 64 /* Packed DISOPCODE assumption. */);
    96 /** @}  */
    97 
    98 /**
    99  * Opcode map descriptor.
    100  *
    101  * This is used a number of places to save storage space where there are lots of
    102  * invalid instructions and the beginning or end of the map.
    103  */
    104 typedef struct DISOPMAPDESC
    105 {
    106     /** Pointer to the opcodes described by this structure. */
    107     PCDISOPCODE     papOpcodes;
    108 #if ARCH_BITS <= 32
    109     uint16_t
    110 #else
    111     uint32_t
    112 #endif
    113     /** The map index corresponding to the first papOpcodes entry. */
    114                     idxFirst,
    115     /** Number of opcodes in the map. */
    116                     cOpcodes;
    117 } DISOPMAPDESC;
    118 /** Pointer to a const opcode map descriptor. */
    119 typedef DISOPMAPDESC const *PCDISOPMAPDESC;
    120 
    121 /** @name Opcode maps.
    122  * @{ */
    123 extern const DISOPCODE g_InvalidOpcode[1];
    124 
    125 extern const DISOPCODE g_aOneByteMapX86[256];
    126 extern const DISOPCODE g_aOneByteMapX64[256];
    127 extern const DISOPCODE g_aTwoByteMapX86[256];
    128 
    129 /** Two byte opcode map with prefix 0x66 */
    130 extern const DISOPCODE g_aTwoByteMapX86_PF66[256];
    131 
    132 /** Two byte opcode map with prefix 0xF2 */
    133 extern const DISOPCODE g_aTwoByteMapX86_PFF2[256];
    134 
    135 /** Two byte opcode map with prefix 0xF3 */
    136 extern const DISOPCODE g_aTwoByteMapX86_PFF3[256];
    137 
    138 /** Three byte opcode map (0xF 0x38) */
    139 extern PCDISOPCODE const g_apThreeByteMapX86_0F38[16];
    140 
    141 /** Three byte opcode map with prefix 0x66 (0xF 0x38) */
    142 extern PCDISOPCODE const g_apThreeByteMapX86_660F38[16];
    143 
    144 /** Three byte opcode map with prefix 0xF2 (0xF 0x38) */
    145 extern PCDISOPCODE const g_apThreeByteMapX86_F20F38[16];
    146 
    147 /** Three byte opcode map with prefix 0xF3 (0xF 0x38) */
    148 extern PCDISOPCODE const g_apThreeByteMapX86_F30F38[16];
    149 
    150 extern PCDISOPCODE const g_apThreeByteMapX86_0F3A[16];
    151 
    152 /** Three byte opcode map with prefix 0x66 (0xF 0x3A) */
    153 extern PCDISOPCODE const g_apThreeByteMapX86_660F3A[16];
    154 
    155 /** Three byte opcode map with prefixes 0x66 0xF2 (0xF 0x38) */
    156 extern PCDISOPCODE const g_apThreeByteMapX86_66F20F38[16];
    157 
    158 /** VEX opcodes table defined by [VEX.m-mmmm - 1].
    159   * 0Fh, 0F38h, 0F3Ah correspondingly, VEX.pp = 00b */
    160 extern PCDISOPMAPDESC const g_apVexOpcodesMapRanges_None[3];
    161 
    162 /** VEX opcodes table defined by [VEX.m-mmmm - 1].
    163   * 0Fh, 0F38h, 0F3Ah correspondingly, VEX.pp = 01b (66h) */
    164 extern PCDISOPMAPDESC const g_apVexOpcodesMapRanges_66H[3];
    165 
    166 /** 0Fh, 0F38h, 0F3Ah correspondingly, VEX.pp = 10b (F3h) */
    167 extern PCDISOPMAPDESC const g_apVexOpcodesMapRanges_F3H[3];
    168 
    169 /** 0Fh, 0F38h, 0F3Ah correspondingly, VEX.pp = 11b (F2h) */
    170 extern PCDISOPMAPDESC const g_apVexOpcodesMapRanges_F2H[3];
    171 
    172 /** Two dimmentional map descriptor array: first index is by VEX.pp (prefix),
    173  * second by the VEX.mmmm (map).
    174  * The latter has to be bounced checked as we only have the first 4 maps. */
    175 extern PCDISOPMAPDESC const g_aapVexOpcodesMapRanges[4][4];
    176 /** @} */
    177 
    178 /** @name Opcode extensions (Group tables)
    179  * @{ */
    180 extern const DISOPCODE g_aMapX86_Group1[8*4];
    181 extern const DISOPCODE g_aMapX86_Group2[8*6];
    182 extern const DISOPCODE g_aMapX86_Group3[8*2];
    183 extern const DISOPCODE g_aMapX86_Group4[8];
    184 extern const DISOPCODE g_aMapX86_Group5[8];
    185 extern const DISOPCODE g_aMapX86_Group6[8];
    186 extern const DISOPCODE g_aMapX86_Group7_mem[8];
    187 extern const DISOPCODE g_aMapX86_Group7_mod11_rm000[8];
    188 extern const DISOPCODE g_aMapX86_Group7_mod11_rm001[8];
    189 extern const DISOPCODE g_aMapX86_Group8[8];
    190 extern const DISOPCODE g_aMapX86_Group9[8];
    191 extern const DISOPCODE g_aMapX86_Group10[8];
    192 extern const DISOPCODE g_aMapX86_Group11[8*2];
    193 extern const DISOPCODE g_aMapX86_Group12[8*2];
    194 extern const DISOPCODE g_aMapX86_Group13[8*2];
    195 extern const DISOPCODE g_aMapX86_Group14[8*2];
    196 extern const DISOPCODE g_aMapX86_Group15_mem[8];
    197 extern const DISOPCODE g_aMapX86_Group15_mod11_rm000[8];
    198 extern const DISOPCODE g_aMapX86_Group16[8];
    199 extern const DISOPCODE g_aMapX86_Group17[8*2];
    200 extern const DISOPCODE g_aMapX86_NopPause[2];
    201 /** @} */
    202 
    203 /** 3DNow! map (0x0F 0x0F prefix) */
    204 extern const DISOPCODE g_aTwoByteMapX86_3DNow[256];
    205 
    206 /** Floating point opcodes starting with escape byte 0xDF
    207  * @{ */
    208 extern const DISOPCODE g_aMapX86_EscF0_Low[8];
    209 extern const DISOPCODE g_aMapX86_EscF0_High[16*4];
    210 extern const DISOPCODE g_aMapX86_EscF1_Low[8];
    211 extern const DISOPCODE g_aMapX86_EscF1_High[16*4];
    212 extern const DISOPCODE g_aMapX86_EscF2_Low[8];
    213 extern const DISOPCODE g_aMapX86_EscF2_High[16*4];
    214 extern const DISOPCODE g_aMapX86_EscF3_Low[8];
    215 extern const DISOPCODE g_aMapX86_EscF3_High[16*4];
    216 extern const DISOPCODE g_aMapX86_EscF4_Low[8];
    217 extern const DISOPCODE g_aMapX86_EscF4_High[16*4];
    218 extern const DISOPCODE g_aMapX86_EscF5_Low[8];
    219 extern const DISOPCODE g_aMapX86_EscF5_High[16*4];
    220 extern const DISOPCODE g_aMapX86_EscF6_Low[8];
    221 extern const DISOPCODE g_aMapX86_EscF6_High[16*4];
    222 extern const DISOPCODE g_aMapX86_EscF7_Low[8];
    223 extern const DISOPCODE g_aMapX86_EscF7_High[16*4];
    224 
    225 extern const PCDISOPCODE g_apMapX86_FP_Low[8];
    226 extern const PCDISOPCODE g_apMapX86_FP_High[8];
    227 /** @} */
     47/** This must be less or equal to DISSTATE::u.abInstr.
     48 * See Vol3A/Table 6-2 and Vol3B/Section22.25 for instance.  */
     49#define DIS_MAX_INSTR_LENGTH    15
     50
     51/** Whether we can do unaligned access. */
     52#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)
     53# define DIS_HOST_UNALIGNED_ACCESS_OK
     54#endif
     55
    22856
    22957/** @def OP
     
    25684
    25785
     86/* Common */
     87DECLHIDDEN(void)     disReadMore(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMin);
     88DECLHIDDEN(uint8_t)  disReadByteSlow(PDISSTATE pDis, size_t offInstr);
     89DECLHIDDEN(uint16_t) disReadWordSlow(PDISSTATE pDis, size_t offInstr);
     90DECLHIDDEN(uint32_t) disReadDWordSlow(PDISSTATE pDis, size_t offInstr);
     91DECLHIDDEN(uint64_t) disReadQWordSlow(PDISSTATE pDis, size_t offInstr);
     92
     93
     94/**
     95 * Read a byte (8-bit) instruction.
     96 *
     97 * @returns The requested byte.
     98 * @param   pDis                The disassembler state.
     99 * @param   uAddress            The address.
     100 */
     101DECL_FORCE_INLINE(uint8_t) disReadByte(PDISSTATE pDis, size_t offInstr)
     102{
     103    if (offInstr >= pDis->cbCachedInstr)
     104        return disReadByteSlow(pDis, offInstr);
     105    return pDis->u.abInstr[offInstr];
     106}
     107
     108
     109/**
     110 * Read a word (16-bit) instruction.
     111 *
     112 * @returns The requested word.
     113 * @param   pDis                The disassembler state.
     114 * @param   offInstr            The offset of the qword relative to the
     115 *                              instruction.
     116 */
     117DECL_FORCE_INLINE(uint16_t) disReadWord(PDISSTATE pDis, size_t offInstr)
     118{
     119    if (offInstr + 2 > pDis->cbCachedInstr)
     120        return disReadWordSlow(pDis, offInstr);
     121
     122#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
     123    return *(uint16_t const *)&pDis->u.abInstr[offInstr];
     124#else
     125    return RT_MAKE_U16(pDis->u.abInstr[offInstr], pDis->u.abInstr[offInstr + 1]);
     126#endif
     127}
     128
     129
     130/**
     131 * Read a dword (32-bit) instruction.
     132 *
     133 * @returns The requested dword.
     134 * @param   pDis                The disassembler state.
     135 * @param   offInstr            The offset of the qword relative to the
     136 *                              instruction.
     137 */
     138DECL_FORCE_INLINE(uint32_t) disReadDWord(PDISSTATE pDis, size_t offInstr)
     139{
     140    if (offInstr + 4 > pDis->cbCachedInstr)
     141        return disReadDWordSlow(pDis, offInstr);
     142
     143#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
     144    return *(uint32_t const *)&pDis->u.abInstr[offInstr];
     145#else
     146    return RT_MAKE_U32_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
     147                               pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3]);
     148#endif
     149}
     150
     151
     152/**
     153 * Read a qword (64-bit) instruction.
     154 *
     155 * @returns The requested qword.
     156 * @param   pDis                The disassembler state.
     157 * @param   uAddress            The address.
     158 */
     159DECL_FORCE_INLINE(uint64_t) disReadQWord(PDISSTATE pDis, size_t offInstr)
     160{
     161    if (offInstr + 8 > pDis->cbCachedInstr)
     162        return disReadQWordSlow(pDis, offInstr);
     163
     164#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
     165    return *(uint64_t const *)&pDis->u.abInstr[offInstr];
     166#else
     167    return RT_MAKE_U64_FROM_U8(pDis->u.abInstr[offInstr    ], pDis->u.abInstr[offInstr + 1],
     168                               pDis->u.abInstr[offInstr + 2], pDis->u.abInstr[offInstr + 3],
     169                               pDis->u.abInstr[offInstr + 4], pDis->u.abInstr[offInstr + 5],
     170                               pDis->u.abInstr[offInstr + 6], pDis->u.abInstr[offInstr + 7]);
     171#endif
     172}
     173
     174
     175/**
     176 * Reads some bytes into the cache.
     177 *
     178 * While this will set DISSTATE::rc on failure, the caller should disregard
     179 * this since that is what would happen if we didn't prefetch bytes prior to the
     180 * instruction parsing.
     181 *
     182 * @param   pDis                The disassembler state.
     183 */
     184DECL_FORCE_INLINE(void) disPrefetchBytes(PDISSTATE pDis)
     185{
     186    /*
     187     * Read some bytes into the cache.  (If this fail we continue as nothing
     188     * has gone wrong since this is what would happen if we didn't precharge
     189     * the cache here.)
     190     */
     191    int rc = pDis->pfnReadBytes(pDis, 0, 1, sizeof(pDis->u.abInstr));
     192    if (RT_SUCCESS(rc))
     193    {
     194        Assert(pDis->cbCachedInstr >= 1);
     195        Assert(pDis->cbCachedInstr <= sizeof(pDis->u.abInstr));
     196    }
     197    else
     198    {
     199        Log(("Initial read failed with rc=%Rrc!!\n", rc));
     200        pDis->rc = rc;
     201    }
     202}
     203
     204
     205/* x86/amd64 */
     206DECLHIDDEN(PCDISOPCODE) disInitializeStateX86(PDISSTATE pDis, DISCPUMODE enmCpuMode, uint32_t fFilter);
     207DECLHIDDEN(int)         disInstrWorkerX86(PDISSTATE pDis, PCDISOPCODE paOneByteMap, uint32_t *pcbInstr);
     208
    258209size_t disFormatBytes(PCDISSTATE pDis, char *pszDst, size_t cchDst, uint32_t fFlags);
    259210
  • trunk/src/VBox/Disassembler/DisasmTables-x86-amd64.cpp

    r99235 r99236  
    3232#include <VBox/dis.h>
    3333#include <VBox/disopcode-x86-amd64.h>
    34 #include "DisasmInternal.h"
     34#include "DisasmInternal-x86-amd64.h"
    3535
    3636
  • trunk/src/VBox/Disassembler/DisasmTablesX64.cpp

    r99220 r99236  
    3232#include <VBox/dis.h>
    3333#include <VBox/disopcode-x86-amd64.h>
    34 #include "DisasmInternal.h"
     34#include "DisasmInternal-x86-amd64.h"
    3535
    3636
  • trunk/src/VBox/Disassembler/Makefile.kmk

    r98439 r99236  
    4040DisasmR3_SOURCES        = \
    4141        Disasm.cpp \
    42         DisasmCore.cpp \
    43         DisasmTables.cpp \
     42        DisasmCore-x86-amd64.cpp \
     43        DisasmTables-x86-amd64.cpp \
    4444        DisasmTablesX64.cpp \
    4545        DisasmMisc.cpp \
     
    6161 DisasmCoreR3_DEFS       = IN_DIS DIS_CORE_ONLY
    6262 DisasmCoreR3_SOURCES    = \
    63         DisasmCore.cpp \
    64         DisasmTables.cpp \
     63        Disasm.cpp \
     64        DisasmCore-x86-amd64.cpp \
     65        DisasmTables-x86-amd64.cpp \
    6566        DisasmTablesX64.cpp \
    6667        DisasmMisc.cpp
     
    7172  DisasmRC_DEFS           = IN_DIS IN_RT_RC DIS_CORE_ONLY
    7273  DisasmRC_SOURCES        = \
    73         DisasmCore.cpp \
    74         DisasmTables.cpp \
     74        Disasm.cpp \
     75        DisasmCore-x86-amd64.cpp \
     76        DisasmTables-x86-amd64.cpp \
    7577        DisasmTablesX64.cpp \
    7678        DisasmMisc.cpp
     
    8183 DisasmR0_DEFS           = IN_DIS IN_RT_R0 DIS_CORE_ONLY
    8284 DisasmR0_SOURCES        = \
    83         DisasmCore.cpp \
    84         DisasmTables.cpp \
     85        Disasm.cpp \
     86        DisasmCore-x86-amd64.cpp \
     87        DisasmTables-x86-amd64.cpp \
    8588        DisasmTablesX64.cpp \
    8689        DisasmMisc.cpp
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