VirtualBox

Changeset 84488 in vbox for trunk/src/VBox/VMM


Ignore:
Timestamp:
May 25, 2020 10:21:02 AM (5 years ago)
Author:
vboxsync
Message:

VMM/DBGFTracer: Implement support for guest memory read/write events, bugref:9210

The data from guest memory transfers need to be aggregated from the indivudual event entries
before they can be written out.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/DBGFAllTracer.cpp

    r84458 r84488  
    9494                               size_t cbEvtDesc, uint64_t *pidEvt)
    9595{
     96    LogFlowFunc(("pVM=%p pThisCC=%p hEvtSrc=%llu enmTraceEvt=%u idEvtPrev=%llu pvEvtDesc=%p cbEvtDesc=%zu pidEvt=%p\n",
     97                 pVM, pThisCC, hEvtSrc, enmTraceEvt, idEvtPrev, pvEvtDesc, cbEvtDesc, pidEvt));
     98
    9699    PDBGFTRACERSHARED pSharedCC = pThisCC->CTX_SUFF(pShared);
    97100    size_t cRingBufEvts = dbgfTracerGetRingBufSz(pThisCC) / DBGF_TRACER_EVT_SZ;
     
    109112         * get its act together.
    110113         */
     114        AssertMsgFailed(("Flush thread can't keep up with event amount!\n"));
    111115    }
    112116
  • trunk/src/VBox/VMM/VMMR3/DBGFR3Tracer.cpp

    r84458 r84488  
    222222
    223223
    224 #if 0
    225224static const RTTRACELOGEVTITEMDESC g_DevGCPhysRwStartEvtItems[] =
    226225{
    227226    {"GCPhys",        "Physical guest address being accessed",                  RTTRACELOGTYPE_UINT64,   0},
    228227    {"cbXfer",        "Number of bytes being transfered",                       RTTRACELOGTYPE_UINT64,   0},
    229     {"idRw",          "Event ID for tracking larger accesses",                  RTTRACELOGTYPE_UINT64,   0},
    230     {"ab"}
    231 };
    232 #endif
     228};
     229
     230
     231static const RTTRACELOGEVTDESC g_DevGCPhysReadEvtDesc =
     232{
     233    "Dev.GCPhysRead",
     234    "Device read data from guest physical memory",
     235    RTTRACELOGEVTSEVERITY_DEBUG,
     236    RT_ELEMENTS(g_DevGCPhysRwStartEvtItems),
     237    &g_DevGCPhysRwStartEvtItems[0]
     238};
     239
     240
     241static const RTTRACELOGEVTDESC g_DevGCPhysWriteEvtDesc =
     242{
     243    "Dev.GCPhysWrite",
     244    "Device wrote data to guest physical memory",
     245    RTTRACELOGEVTSEVERITY_DEBUG,
     246    RT_ELEMENTS(g_DevGCPhysRwStartEvtItems),
     247    &g_DevGCPhysRwStartEvtItems[0]
     248};
     249
     250
     251static const RTTRACELOGEVTITEMDESC g_DevGCPhysRwDataEvtItems[] =
     252{
     253    {"abData",        "The data being read/written",                            RTTRACELOGTYPE_RAWDATA,  0}
     254};
     255
     256static const RTTRACELOGEVTDESC g_DevGCPhysRwDataEvtDesc =
     257{
     258    "Dev.GCPhysRwData",
     259    "The data being read or written",
     260    RTTRACELOGEVTSEVERITY_DEBUG,
     261    RT_ELEMENTS(g_DevGCPhysRwDataEvtItems),
     262    &g_DevGCPhysRwDataEvtItems[0]
     263};
    233264
    234265
     
    239270
    240271/**
     272 * Returns an unused guest memory read/write data aggregation structure.
     273 *
     274 * @returns Pointer to a new aggregation structure or NULL if out of memory.
     275 * @param   pThis                   The DBGF tracer instance.
     276 */
     277static PDBGFTRACERGCPHYSRWAGG dbgfTracerR3EvtGCPhysRwAggNew(PDBGFTRACERINSR3 pThis)
     278{
     279    for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aGstMemRwData); i++)
     280    {
     281        if (pThis->aGstMemRwData[i].idEvtStart == DBGF_TRACER_EVT_HDR_ID_INVALID)
     282            return &pThis->aGstMemRwData[i];
     283    }
     284
     285    return NULL;
     286}
     287
     288
     289/**
     290 * Find the guest memory read/write data aggregation structure for the given event ID.
     291 *
     292 * @returns Pointer to a new aggregation structure or NULL if not found.
     293 * @param   pThis                   The DBGF tracer instance.
     294 * @param   idEvtPrev               The event ID to look for.
     295 */
     296static PDBGFTRACERGCPHYSRWAGG dbgfTracerR3EvtGCPhysRwAggFind(PDBGFTRACERINSR3 pThis, uint64_t idEvtPrev)
     297{
     298    for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aGstMemRwData); i++)
     299    {
     300        if (   pThis->aGstMemRwData[i].idEvtStart != DBGF_TRACER_EVT_HDR_ID_INVALID
     301            && pThis->aGstMemRwData[i].idEvtPrev == idEvtPrev)
     302            return &pThis->aGstMemRwData[i];
     303    }
     304
     305    return NULL;
     306}
     307
     308
     309/**
     310 * Starts a new guest memory read/write event.
     311 *
     312 * @returns VBox status code.
     313 * @param   pThis                   The DBGF tracer instance.
     314 * @param   pEvtHdr                 The event header.
     315 * @param   pEvtGCPhysRw            The guest memory read/write event descriptor.
     316 * @param   pEvtDesc                The event descriptor written to the trace log.
     317 */
     318static int dbgfTracerR3EvtGCPhysRwStart(PDBGFTRACERINSR3 pThis, PCDBGFTRACEREVTHDR pEvtHdr,
     319                                        PCDBGFTRACEREVTGCPHYS pEvtGCPhysRw, PCRTTRACELOGEVTDESC pEvtDesc)
     320{
     321    /* Write out the event header first in any case. */
     322    int rc = RTTraceLogWrEvtAddL(pThis->hTraceLog, pEvtDesc, RTTRACELOG_WR_ADD_EVT_F_GRP_START,
     323                                 pEvtHdr->idEvt, pEvtHdr->hEvtSrc, pEvtGCPhysRw->GCPhys, pEvtGCPhysRw->cbXfer);
     324    if (RT_SUCCESS(rc))
     325    {
     326        /*
     327         * If the amount of data is small enough to fit into the single event descriptor we can skip allocating
     328         * an aggregation tracking structure and write the event containing the complete data out immediately.
     329         */
     330        if (pEvtGCPhysRw->cbXfer <= sizeof(pEvtGCPhysRw->abData))
     331        {
     332            size_t cbEvtData = pEvtGCPhysRw->cbXfer;
     333
     334            rc = RTTraceLogWrEvtAdd(pThis->hTraceLog, &g_DevGCPhysRwDataEvtDesc, RTTRACELOG_WR_ADD_EVT_F_GRP_FINISH,
     335                                    pEvtHdr->idEvt, pEvtHdr->hEvtSrc, &pEvtGCPhysRw->abData[0], &cbEvtData);
     336        }
     337        else
     338        {
     339            /* Slow path, find an empty aggregation structure. */
     340            PDBGFTRACERGCPHYSRWAGG pDataAgg = dbgfTracerR3EvtGCPhysRwAggNew(pThis);
     341            if (RT_LIKELY(pDataAgg))
     342            {
     343                /* Initialize it. */
     344                pDataAgg->idEvtStart = pEvtHdr->idEvt;
     345                pDataAgg->idEvtPrev  = pEvtHdr->idEvt;
     346                pDataAgg->cbXfer     = pEvtGCPhysRw->cbXfer;
     347                pDataAgg->cbLeft     = pDataAgg->cbXfer;
     348                pDataAgg->offBuf     = 0;
     349
     350                /* Need to reallocate the buffer to hold the complete data? */
     351                if (RT_UNLIKELY(pDataAgg->cbBufMax < pDataAgg->cbXfer))
     352                {
     353                    uint8_t *pbBufNew = (uint8_t *)RTMemRealloc(pDataAgg->pbBuf, pDataAgg->cbXfer);
     354                    if (RT_LIKELY(pbBufNew))
     355                    {
     356                        pDataAgg->pbBuf    = pbBufNew;
     357                        pDataAgg->cbBufMax = pDataAgg->cbXfer;
     358                    }
     359                    else
     360                        rc = VERR_NO_MEMORY;
     361                }
     362
     363                if (RT_SUCCESS(rc))
     364                {
     365                    memcpy(pDataAgg->pbBuf, &pEvtGCPhysRw->abData[0], sizeof(pEvtGCPhysRw->abData));
     366                    pDataAgg->offBuf += sizeof(pEvtGCPhysRw->abData);
     367                    pDataAgg->cbLeft -= sizeof(pEvtGCPhysRw->abData);
     368                }
     369            }
     370            else
     371                rc = VERR_NO_MEMORY;
     372
     373            if (RT_FAILURE(rc))
     374            {
     375                LogRelMax(10, ("DBGF: Creating new data aggregation structure for guest memory read/write failed with %Rrc, trace log will not contain data for this event!\n", rc));
     376
     377                /* Write out the finish event without any data. */
     378                size_t cbEvtData = 0;
     379                rc = RTTraceLogWrEvtAdd(pThis->hTraceLog, &g_DevGCPhysRwDataEvtDesc, RTTRACELOG_WR_ADD_EVT_F_GRP_FINISH,
     380                                        pEvtHdr->idEvt, pEvtHdr->hEvtSrc, NULL, &cbEvtData);
     381                if (pDataAgg) /* Reset the aggregation event. */
     382                    pDataAgg->idEvtStart = DBGF_TRACER_EVT_HDR_ID_INVALID;
     383            }
     384        }
     385    }
     386
     387    return rc;
     388}
     389
     390
     391/**
     392 * Continues a previously started guest memory read/write event.
     393 *
     394 * @returns VBox status code.
     395 * @param   pThis                   The DBGF tracer instance.
     396 * @param   pEvtHdr                 The event header.
     397 * @param   pvData                  The data to log.
     398 */
     399static int dbgfTracerR3EvtGCPhysRwContinue(PDBGFTRACERINSR3 pThis, PCDBGFTRACEREVTHDR pEvtHdr, void *pvData)
     400{
     401    int rc = VINF_SUCCESS;
     402    PDBGFTRACERGCPHYSRWAGG pDataAgg = dbgfTracerR3EvtGCPhysRwAggFind(pThis, pEvtHdr->idEvtPrev);
     403
     404    if (RT_LIKELY(pDataAgg))
     405    {
     406        size_t cbThisXfer = RT_MIN(pDataAgg->cbLeft, DBGF_TRACER_EVT_PAYLOAD_SZ);
     407
     408        memcpy(pDataAgg->pbBuf + pDataAgg->offBuf, pvData, cbThisXfer);
     409        pDataAgg->offBuf += cbThisXfer;
     410        pDataAgg->cbLeft -= cbThisXfer;
     411
     412        if (!pDataAgg->cbLeft)
     413        {
     414            /* All data aggregated, write it out and reset the structure. */
     415            rc = RTTraceLogWrEvtAdd(pThis->hTraceLog, &g_DevGCPhysRwDataEvtDesc, RTTRACELOG_WR_ADD_EVT_F_GRP_FINISH,
     416                                    pDataAgg->idEvtStart, pEvtHdr->hEvtSrc, pDataAgg->pbBuf, &pDataAgg->cbXfer);
     417            pDataAgg->offBuf     = 0;
     418            pDataAgg->idEvtStart = DBGF_TRACER_EVT_HDR_ID_INVALID;
     419        }
     420        else
     421            pDataAgg->idEvtPrev = pEvtHdr->idEvt; /* So the next event containing more data can find the aggregation structure. */
     422    }
     423    else /* This can only happen if creating a new structure failed before. */
     424        rc = VERR_DBGF_TRACER_IPE_1;
     425
     426    return rc;
     427}
     428
     429
     430/**
    241431 * Processes the given event.
    242432 *
     
    248438{
    249439    int rc = VINF_SUCCESS;
     440
     441    LogFlowFunc(("pThis=%p pEvtHdr=%p{idEvt=%llu,enmEvt=%u}\n",
     442                 pThis, pEvtHdr, pEvtHdr->idEvt, pEvtHdr->enmEvt));
    250443
    251444    switch (pEvtHdr->enmEvt)
     
    343536        case DBGFTRACEREVT_GCPHYS_READ:
    344537        case DBGFTRACEREVT_GCPHYS_WRITE:
     538        {
     539            PCRTTRACELOGEVTDESC pEvtDesc =   pEvtHdr->enmEvt == DBGFTRACEREVT_GCPHYS_WRITE
     540                                           ? &g_DevGCPhysWriteEvtDesc
     541                                           : &g_DevGCPhysReadEvtDesc;
     542
     543            /* If the previous event ID is invalid this starts a new read/write we have to aggregate all the data for. */
     544            if (pEvtHdr->idEvtPrev == DBGF_TRACER_EVT_HDR_ID_INVALID)
     545            {
     546                PCDBGFTRACEREVTGCPHYS pEvtGCPhysRw = (PCDBGFTRACEREVTGCPHYS)(pEvtHdr + 1);
     547                rc = dbgfTracerR3EvtGCPhysRwStart(pThis, pEvtHdr, pEvtGCPhysRw, pEvtDesc);
     548            }
     549            else
     550            {
     551                /* Continuation of a started read or write, look up the right tracking structure and process the new data. */
     552                void *pvData = pEvtHdr + 1;
     553                rc = dbgfTracerR3EvtGCPhysRwContinue(pThis, pEvtHdr, pvData);
     554            }
     555            break;
     556        }
    345557        default:
    346558            AssertLogRelMsgFailed(("Invalid or unsupported event: %u!\n", pEvtHdr->enmEvt));
     
    459671    pThis->fShutdown = false;
    460672
     673    for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aGstMemRwData); i++)
     674        pThis->aGstMemRwData[i].idEvtStart = DBGF_TRACER_EVT_HDR_ID_INVALID;
     675
    461676    /* Try to create a file based trace log. */
    462677    int rc = RTTraceLogWrCreateFile(&pThis->hTraceLog, RTBldCfgVersion(), pszTraceFilePath);
     
    470685     * to invalid values.
    471686     */
    472     uint64_t cEvtEntries = pShared->cbRingBuf % DBGF_TRACER_EVT_SZ;
     687    uint64_t cEvtEntries = pShared->cbRingBuf / DBGF_TRACER_EVT_SZ;
    473688    PDBGFTRACEREVTHDR pEvtHdr = (PDBGFTRACEREVTHDR)pThis->pbRingBufR3;
    474689    for (uint32_t i = 0; i < cEvtEntries; i++)
     
    686901 * Deregisters the given event source handle.
    687902 *
    688  * @returns VBox stauts code.
     903 * @returns VBox status code.
    689904 * @param   pVM                     The cross context VM structure.
    690905 * @param   hEvtSrc                 The event source handle to deregister.
  • trunk/src/VBox/VMM/include/DBGFInternal.h

    r84458 r84488  
    378378
    379379/**
     380 * Guest memory read/write data aggregation.
     381 */
     382typedef struct DBGFTRACERGCPHYSRWAGG
     383{
     384    /** The event ID which started the aggregation (used for the group ID when writing out the event). */
     385    uint64_t                                idEvtStart;
     386    /** The previous event ID used to link all the chunks together. */
     387    uint64_t                                idEvtPrev;
     388    /** Number of bytes being transfered. */
     389    size_t                                  cbXfer;
     390    /** Amount of data left to aggregate before it can be written. */
     391    size_t                                  cbLeft;
     392    /** Amount of bytes allocated. */
     393    size_t                                  cbBufMax;
     394    /** Offset into the buffer to write next. */
     395    size_t                                  offBuf;
     396    /** Pointer to the allocated buffer. */
     397    uint8_t                                 *pbBuf;
     398} DBGFTRACERGCPHYSRWAGG;
     399/** Pointer to a guest memory read/write data aggregation structure. */
     400typedef DBGFTRACERGCPHYSRWAGG *PDBGFTRACERGCPHYSRWAGG;
     401
     402
     403/**
    380404 * Tracer instance data, ring-3
    381405 */
     
    407431    /** The trace log writer handle. */
    408432    RTTRACELOGWR                            hTraceLog;
     433    /** Guest memory data aggregation structures to track
     434     * currently pending guest memory reads/writes. */
     435    DBGFTRACERGCPHYSRWAGG                   aGstMemRwData[10];
    409436} DBGFTRACERINSR3;
    410437/** Pointer to a tarcer instance - Ring-3 Ptr. */
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