VirtualBox

Changeset 41753 in vbox for trunk/src


Ignore:
Timestamp:
Jun 15, 2012 12:30:46 PM (13 years ago)
Author:
vboxsync
Message:

DIS: Read instruction bytes thru DISCPUSTATE::abInstr.

File:
1 edited

Legend:

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

    r41748 r41753  
    2929#include <iprt/stdarg.h>
    3030#include "DisasmInternal.h"
     31
     32
     33/*******************************************************************************
     34*   Defined Constants And Macros                                               *
     35*******************************************************************************/
     36/** This must be less or equal to DISCPUSTATE::abInstr. */
     37#define DIS_MAX_INSTR_LENGTH 16
     38
     39/** Whether we can do unaligned access. */
     40#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)
     41# define DIS_HOST_UNALIGNED_ACCESS_OK
     42#endif
    3143
    3244
     
    433445    }
    434446
    435     AssertMsg(pCpu->cbInstr == iByte || RT_FAILURE_NP(pCpu->rc), ("%u %u\n", pCpu->cbInstr, iByte));
    436447    pCpu->cbInstr = iByte;
    437448    if (pcbInstr)
     
    23742385
    23752386
    2376 /**
    2377  * Slow path for storing instruction bytes.
    2378  *
    2379  * @param   pCpu                The disassembler state.
    2380  * @param   uAddress            The address.
    2381  * @param   pbSrc               The bytes.
    2382  * @param   cbSrc               The number of bytes.
    2383  */
    2384 DECL_NO_INLINE(static, void)
    2385 disStoreInstrBytesSlow(PDISCPUSTATE pCpu, RTUINTPTR uAddress, const uint8_t *pbSrc, size_t cbSrc)
    2386 {
    2387     /*
    2388      * Figure out which case it is.
    2389      */
    2390     uint32_t  cbInstr = pCpu->cbInstr;
    2391     RTUINTPTR off     = uAddress - pCpu->uInstrAddr;
    2392     if (off < cbInstr)
    2393     {
    2394         if (off + cbSrc <= cbInstr)
    2395         {
    2396             AssertMsg(memcmp(&pCpu->abInstr[off], pbSrc, cbSrc) == 0,
    2397                       ("%RTptr LB %zx off=%RTptr (%.*Rhxs)", uAddress, cbSrc, off, cbInstr, pCpu->abInstr));
    2398             return; /* fully re-reading old stuff. */
    2399         }
    2400 
    2401         /* Only partially re-reading stuff, skip ahead and add the rest. */
    2402         uint32_t cbAlreadyRead = cbInstr - (uint32_t)off;
    2403         Assert(memcmp(&pCpu->abInstr[off], pbSrc, cbAlreadyRead) == 0);
    2404         uAddress += cbAlreadyRead;
    2405         pbSrc    += cbAlreadyRead;
    2406         cbSrc    -= cbAlreadyRead;
    2407     }
    2408 
    2409     if (off >= sizeof(pCpu->abInstr))
    2410     {
    2411         /* The instruction is too long! This shouldn't happen. */
    2412         AssertMsgFailed(("%RTptr LB %zx off=%RTptr (%.*Rhxs)", uAddress, cbSrc, off, cbInstr, pCpu->abInstr));
    2413         return;
    2414     }
    2415     else if (off > cbInstr)
    2416     {
    2417         /* Mind the gap - this shouldn't happen, but read the gap bytes if it does. */
    2418         AssertMsgFailed(("%RTptr LB %zx off=%RTptr (%.16Rhxs)", uAddress, cbSrc, off, cbInstr, pCpu->abInstr));
    2419         uint32_t cbGap = off - cbInstr;
    2420         int rc = pCpu->pfnReadBytes(pCpu, &pCpu->abInstr[cbInstr], uAddress - cbGap, cbGap);
    2421         if (RT_FAILURE(rc))
    2422         {
    2423             pCpu->rc = VERR_DIS_MEM_READ;
    2424             RT_BZERO(&pCpu->abInstr[cbInstr], cbGap);
    2425         }
    2426         pCpu->cbInstr = cbInstr = off;
    2427     }
    2428 
    2429     /*
    2430      * Copy the bytes.
    2431      */
    2432     if (off + cbSrc <= sizeof(pCpu->abInstr))
    2433     {
    2434         memcpy(&pCpu->abInstr[cbInstr], pbSrc, cbSrc);
    2435         pCpu->cbInstr = cbInstr + (uint32_t)cbSrc;
    2436     }
    2437     else
    2438     {
    2439         size_t cbToCopy = sizeof(pCpu->abInstr) - off;
    2440         memcpy(&pCpu->abInstr[cbInstr], pbSrc, cbToCopy);
    2441         pCpu->cbInstr = sizeof(pCpu->abInstr);
    2442         AssertMsgFailed(("%RTptr LB %zx off=%RTptr (%.*Rhxs)", uAddress, cbSrc, off, sizeof(pCpu->abInstr), pCpu->abInstr));
    2443     }
    2444 }
     2387//*****************************************************************************
     2388/* Read functions for getting the opcode bytes */
     2389//*****************************************************************************
     2390
    24452391
    24462392static DECLCALLBACK(int) disReadBytesDefault(PDISCPUSTATE pCpu, uint8_t *pbDst, RTUINTPTR uSrcAddr, uint32_t cbToRead)
     
    24562402}
    24572403
    2458 //*****************************************************************************
    2459 /* Read functions for getting the opcode bytes */
    2460 //*****************************************************************************
     2404
     2405/**
     2406 * Read more bytes into the DISCPUSTATE::abInstr buffer, advance
     2407 * DISCPUSTATE::cbCachedInstr.
     2408 *
     2409 * Will set DISCPUSTATE::rc on failure, but still advance cbCachedInstr.
     2410 *
     2411 * The caller shall fend off reads beyond the DISCPUSTATE::abInstr buffer.
     2412 *
     2413 * @param   pCpu                The disassembler state.
     2414 * @param   off                 The offset of the read request.
     2415 * @param   cbMin               The size of the read request that needs to be
     2416 *                              satisfied.
     2417 */
     2418DECL_NO_INLINE(static, void) disReadMore(PDISCPUSTATE pCpu, uint8_t off, uint8_t cbMin)
     2419{
     2420    Assert(cbMin + off <= sizeof(pCpu->abInstr));
     2421
     2422    /*
     2423     * Adjust the incoming request to not overlap with bytes that has already
     2424     * been read and to make sure we don't leave unread gaps.
     2425     */
     2426    if (off < pCpu->cbCachedInstr)
     2427    {
     2428        Assert(off + cbMin > pCpu->cbCachedInstr);
     2429        cbMin -= pCpu->cbCachedInstr - off;
     2430        off = pCpu->cbCachedInstr;
     2431    }
     2432    else if (off > pCpu->cbCachedInstr)
     2433    {
     2434        cbMin += off - pCpu->cbCachedInstr;
     2435        off = pCpu->cbCachedInstr;
     2436    }
     2437
     2438    /*
     2439     * Do the read.  No need to zero anything, abInstr is already zeroed by the
     2440     * DISInstrEx API.
     2441     */
     2442    /** @todo Change the callback API so it can read more, thus avoid lots of
     2443     *        calls or it doing its own caching. */
     2444    int rc = pCpu->pfnReadBytes(pCpu, &pCpu->abInstr[off], pCpu->uInstrAddr + off, cbMin);
     2445    if (RT_FAILURE(rc))
     2446    {
     2447        Log(("disReadMore failed with rc=%Rrc!!\n", rc));
     2448        pCpu->rc = VERR_DIS_MEM_READ;
     2449    }
     2450    pCpu->cbCachedInstr = off + cbMin;
     2451}
     2452
     2453
     2454/**
     2455 * Function for handling a 8-bit read beyond the max instruction length.
     2456 *
     2457 * @returns 0
     2458 * @param   pCpu                The disassembler state.
     2459 * @param   uAddress            The address.
     2460 */
     2461DECL_NO_INLINE(static, uint8_t) disReadByteBad(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
     2462{
     2463    Log(("disReadByte: too long instruction...\n"));
     2464    pCpu->rc = VERR_DIS_TOO_LONG_INSTR;
     2465    return 0;
     2466}
     2467
     2468
     2469/**
     2470 * Read a byte (8-bit) instruction byte.
     2471 *
     2472 * @returns The requested byte.
     2473 * @param   pCpu                The disassembler state.
     2474 * @param   uAddress            The address.
     2475 */
    24612476static uint8_t disReadByte(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
    24622477{
    2463     uint8_t bTemp = 0;
    2464     int rc = pCpu->pfnReadBytes(pCpu, &bTemp, uAddress, sizeof(bTemp));
    2465     if (RT_FAILURE(rc))
    2466     {
    2467         Log(("disReadByte failed!!\n"));
    2468         pCpu->rc = VERR_DIS_MEM_READ;
    2469     }
    2470 
    2471 /** @todo change this into reading directly into abInstr and use it as a
    2472  *        cache. */
    2473     if (RT_LIKELY(   pCpu->uInstrAddr + pCpu->cbInstr == uAddress
    2474                   && pCpu->cbInstr + sizeof(bTemp) < sizeof(pCpu->abInstr)))
    2475         pCpu->abInstr[pCpu->cbInstr++] = bTemp;
    2476     else
    2477         disStoreInstrBytesSlow(pCpu, uAddress, &bTemp, sizeof(bTemp));
    2478 
    2479     return bTemp;
    2480 }
    2481 //*****************************************************************************
    2482 //*****************************************************************************
     2478    RTUINTPTR off = uAddress - pCpu->uInstrAddr;
     2479    if (RT_UNLIKELY(off + 1 > DIS_MAX_INSTR_LENGTH))
     2480        return disReadByteBad(pCpu, uAddress);
     2481
     2482    if (off + 1 > pCpu->cbCachedInstr)
     2483        disReadMore(pCpu, off, 1);
     2484    return pCpu->abInstr[off];
     2485}
     2486
     2487
     2488/**
     2489 * Function for handling a 16-bit read beyond the max instruction length.
     2490 *
     2491 * @returns 0
     2492 * @param   pCpu                The disassembler state.
     2493 * @param   uAddress            The address.
     2494 */
     2495DECL_NO_INLINE(static, uint16_t) disReadWordBad(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
     2496{
     2497    Log(("disReadWord: too long instruction...\n"));
     2498    pCpu->rc = VERR_DIS_TOO_LONG_INSTR;
     2499    RTUINTPTR off = uAddress - pCpu->uInstrAddr;
     2500    if (off < DIS_MAX_INSTR_LENGTH)
     2501        return pCpu->abInstr[off];
     2502    return 0;
     2503}
     2504
     2505
     2506/**
     2507 * Read a word (16-bit) instruction byte.
     2508 *
     2509 * @returns The requested byte.
     2510 * @param   pCpu                The disassembler state.
     2511 * @param   uAddress            The address.
     2512 */
    24832513static uint16_t disReadWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
    24842514{
    2485     RTUINT16U uTemp;
    2486     uTemp.u = 0;
    2487     int rc = pCpu->pfnReadBytes(pCpu, uTemp.au8, uAddress, sizeof(uTemp));
    2488     if (RT_FAILURE(rc))
    2489     {
    2490         Log(("disReadWord failed!!\n"));
    2491         pCpu->rc = VERR_DIS_MEM_READ;
    2492     }
    2493 
    2494     if (RT_LIKELY(   pCpu->uInstrAddr + pCpu->cbInstr == uAddress
    2495                   && pCpu->cbInstr + sizeof(uTemp) < sizeof(pCpu->abInstr)))
    2496     {
    2497         pCpu->abInstr[pCpu->cbInstr    ] = uTemp.au8[0];
    2498         pCpu->abInstr[pCpu->cbInstr + 1] = uTemp.au8[1];
    2499         pCpu->cbInstr += 2;
    2500     }
    2501     else
    2502         disStoreInstrBytesSlow(pCpu, uAddress, uTemp.au8, sizeof(uTemp));
    2503 
    2504     return uTemp.u;
    2505 }
    2506 //*****************************************************************************
    2507 //*****************************************************************************
     2515    RTUINTPTR off = uAddress - pCpu->uInstrAddr;
     2516    if (RT_UNLIKELY(off + 2 > DIS_MAX_INSTR_LENGTH))
     2517        return disReadWordBad(pCpu, uAddress);
     2518
     2519    if (off + 2 > pCpu->cbCachedInstr)
     2520        disReadMore(pCpu, off, 2);
     2521#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
     2522    return *(uint16_t const *)&pCpu->abInstr[off];
     2523#else
     2524    return RT_MAKE_U16(pCpu->abInstr[off], pCpu->abInstr[off + 1]);
     2525#endif
     2526}
     2527
     2528
     2529/**
     2530 * Function for handling a 32-bit read beyond the max instruction length.
     2531 *
     2532 * @returns 0
     2533 * @param   pCpu                The disassembler state.
     2534 * @param   uAddress            The address.
     2535 */
     2536DECL_NO_INLINE(static, uint32_t) disReadDWordBad(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
     2537{
     2538    Log(("disReadDWord: too long instruction...\n"));
     2539    pCpu->rc = VERR_DIS_TOO_LONG_INSTR;
     2540    RTUINTPTR off = uAddress - pCpu->uInstrAddr;
     2541    switch ((RTUINTPTR)DIS_MAX_INSTR_LENGTH - off)
     2542    {
     2543        case 1:
     2544            return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], 0, 0, 0);
     2545        case 2:
     2546            return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], 0, 0);
     2547        case 3:
     2548            return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], 0);
     2549        default:
     2550            return 0;
     2551    }
     2552    return 0;
     2553}
     2554
     2555
     2556/**
     2557 * Read a word (32-bit) instruction byte.
     2558 *
     2559 * @returns The requested byte.
     2560 * @param   pCpu                The disassembler state.
     2561 * @param   uAddress            The address.
     2562 */
    25082563static uint32_t disReadDWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
    25092564{
    2510     RTUINT32U uTemp;
    2511     uTemp.u = 0;
    2512     int rc = pCpu->pfnReadBytes(pCpu, uTemp.au8, uAddress, sizeof(uTemp));
    2513     if (RT_FAILURE(rc))
    2514     {
    2515         Log(("disReadDWord failed!!\n"));
    2516         pCpu->rc = VERR_DIS_MEM_READ;
    2517     }
    2518 
    2519     if (RT_LIKELY(   pCpu->uInstrAddr + pCpu->cbInstr == uAddress
    2520                   && pCpu->cbInstr + sizeof(uTemp) < sizeof(pCpu->abInstr)))
    2521     {
    2522         pCpu->abInstr[pCpu->cbInstr    ] = uTemp.au8[0];
    2523         pCpu->abInstr[pCpu->cbInstr + 1] = uTemp.au8[1];
    2524         pCpu->abInstr[pCpu->cbInstr + 2] = uTemp.au8[2];
    2525         pCpu->abInstr[pCpu->cbInstr + 3] = uTemp.au8[3];
    2526         pCpu->cbInstr += 4;
    2527     }
    2528     else
    2529         disStoreInstrBytesSlow(pCpu, uAddress, uTemp.au8, sizeof(uTemp));
    2530 
    2531     return uTemp.u;
    2532 }
    2533 //*****************************************************************************
    2534 //*****************************************************************************
     2565    RTUINTPTR off = uAddress - pCpu->uInstrAddr;
     2566    if (RT_UNLIKELY(off + 4 > DIS_MAX_INSTR_LENGTH))
     2567        return disReadDWordBad(pCpu, uAddress);
     2568
     2569    if (off + 4 > pCpu->cbCachedInstr)
     2570        disReadMore(pCpu, off, 4);
     2571#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
     2572    return *(uint32_t const *)&pCpu->abInstr[off];
     2573#else
     2574    return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3]);
     2575#endif
     2576}
     2577
     2578
     2579/**
     2580 * Function for handling a 64-bit read beyond the max instruction length.
     2581 *
     2582 * @returns 0
     2583 * @param   pCpu                The disassembler state.
     2584 * @param   uAddress            The address.
     2585 */
     2586DECL_NO_INLINE(static, uint64_t) disReadQWordBad(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
     2587{
     2588    Log(("disReadQWord: too long instruction...\n"));
     2589    pCpu->rc = VERR_DIS_TOO_LONG_INSTR;
     2590    RTUINTPTR off = uAddress - pCpu->uInstrAddr;
     2591    switch ((RTUINTPTR)DIS_MAX_INSTR_LENGTH - off)
     2592    {
     2593        case 1:
     2594            return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], 0, 0, 0,   0, 0, 0, 0);
     2595        case 2:
     2596            return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], 0, 0,   0, 0, 0, 0);
     2597        case 3:
     2598            return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], 0,   0, 0, 0, 0);
     2599        case 4:
     2600            return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3],
     2601                                       pCpu->abInstr[off + 4], 0, 0, 0);
     2602        case 5:
     2603            return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3],
     2604                                       pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], 0, 0);
     2605        case 6:
     2606            return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3],
     2607                                       pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], pCpu->abInstr[off + 6], 0);
     2608        default:
     2609            return 0;
     2610    }
     2611    return 0;
     2612}
     2613
     2614
     2615/**
     2616 * Read a word (64-bit) instruction byte.
     2617 *
     2618 * @returns The requested byte.
     2619 * @param   pCpu                The disassembler state.
     2620 * @param   uAddress            The address.
     2621 */
    25352622static uint64_t disReadQWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
    25362623{
    2537     RTUINT64U uTemp;
    2538     uTemp.u = 0;
    2539     int rc = pCpu->pfnReadBytes(pCpu, uTemp.au8, uAddress, sizeof(uTemp));
    2540     if (RT_FAILURE(rc))
    2541     {
    2542         Log(("disReadQWord %x failed!!\n", uAddress));
    2543         pCpu->rc = VERR_DIS_MEM_READ;
    2544     }
    2545 
    2546     if (RT_LIKELY(   pCpu->uInstrAddr + pCpu->cbInstr == uAddress
    2547                   && pCpu->cbInstr + sizeof(uTemp) < sizeof(pCpu->abInstr)))
    2548     {
    2549         pCpu->abInstr[pCpu->cbInstr    ] = uTemp.au8[0];
    2550         pCpu->abInstr[pCpu->cbInstr + 1] = uTemp.au8[1];
    2551         pCpu->abInstr[pCpu->cbInstr + 2] = uTemp.au8[2];
    2552         pCpu->abInstr[pCpu->cbInstr + 3] = uTemp.au8[3];
    2553         pCpu->abInstr[pCpu->cbInstr + 4] = uTemp.au8[4];
    2554         pCpu->abInstr[pCpu->cbInstr + 5] = uTemp.au8[5];
    2555         pCpu->abInstr[pCpu->cbInstr + 6] = uTemp.au8[6];
    2556         pCpu->abInstr[pCpu->cbInstr + 7] = uTemp.au8[7];
    2557         pCpu->cbInstr += 8;
    2558     }
    2559     else
    2560         disStoreInstrBytesSlow(pCpu, uAddress, uTemp.au8, sizeof(uTemp));
    2561 
    2562     return uTemp.u;
    2563 }
     2624    RTUINTPTR off = uAddress - pCpu->uInstrAddr;
     2625    if (RT_UNLIKELY(off + 8 > DIS_MAX_INSTR_LENGTH))
     2626        return disReadQWordBad(pCpu, uAddress);
     2627
     2628    if (off + 8 > pCpu->cbCachedInstr)
     2629        disReadMore(pCpu, off, 8);
     2630#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
     2631    return *(uint64_t const *)&pCpu->abInstr[off];
     2632#else
     2633    return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off    ], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3],
     2634                               pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], pCpu->abInstr[off + 6], pCpu->abInstr[off + 7]);
     2635#endif
     2636}
     2637
    25642638
    25652639
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