VirtualBox

Changeset 86754 in vbox for trunk/src


Ignore:
Timestamp:
Oct 29, 2020 7:59:22 AM (4 years ago)
Author:
vboxsync
Message:

VMM/DBGF: Implement DBGFR3BpEnum() and dbgfR3BpGetByAddr() for int3 breakpoint types, bugref:9837

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR3/DBGFR3Bp.cpp

    r86749 r86754  
    342342
    343343/**
    344  * Get a breakpoint give by address.
    345  *
    346  * @returns The breakpoint handle on success or NIL_DBGF if not found.
    347  * @param   pUVM                The user mode VM handle.
    348  * @param   enmType             The breakpoint type.
    349  * @param   GCPtr               The breakpoint address.
    350  * @param   ppBp                Where to store the pointer to the internal breakpoint state on success, optional.
    351  */
    352 static DBGFBP dbgfR3BpGetByAddr(PUVM pUVM, DBGFBPTYPE enmType, RTGCUINTPTR GCPtr, PDBGFBPINT *ppBp)
    353 {
    354     DBGFBP hBp = NIL_DBGFBP;
    355 
    356     switch (enmType)
    357     {
    358         case DBGFBPTYPE_REG:
    359         {
    360             PVM pVM = pUVM->pVM;
    361             VM_ASSERT_VALID_EXT_RETURN(pVM, NIL_DBGFBP);
    362 
    363             for (uint32_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
    364             {
    365                 PDBGFBPHW pHwBp = &pVM->dbgf.s.aHwBreakpoints[i];
    366 
    367                 AssertCompileSize(DBGFBP, sizeof(uint32_t));
    368                 DBGFBP hBpTmp = ASMAtomicReadU32(&pHwBp->hBp);
    369                 if (   pHwBp->GCPtr == GCPtr
    370                     && hBpTmp != NIL_DBGFBP)
    371                 {
    372                     hBp = hBpTmp;
    373                     break;
    374                 }
    375             }
    376 
    377             break;
    378         }
    379 
    380         case DBGFBPTYPE_INT3:
    381             break;
    382 
    383         default:
    384             AssertMsgFailed(("enmType=%d\n", enmType));
    385             break;
    386     }
    387 
    388     if (   hBp != NIL_DBGFBP
    389         && ppBp)
    390         *ppBp =  dbgfR3BpGetByHnd(pUVM, hBp);
    391     return hBp;
    392 }
    393 
    394 
    395 /**
    396344 * @callback_method_impl{FNVMMEMTRENDEZVOUS}
    397345 */
     
    12641212
    12651213/**
     1214 * Get a breakpoint give by address.
     1215 *
     1216 * @returns The breakpoint handle on success or NIL_DBGF if not found.
     1217 * @param   pUVM                The user mode VM handle.
     1218 * @param   enmType             The breakpoint type.
     1219 * @param   GCPtr               The breakpoint address.
     1220 * @param   ppBp                Where to store the pointer to the internal breakpoint state on success, optional.
     1221 */
     1222static DBGFBP dbgfR3BpGetByAddr(PUVM pUVM, DBGFBPTYPE enmType, RTGCUINTPTR GCPtr, PDBGFBPINT *ppBp)
     1223{
     1224    DBGFBP hBp = NIL_DBGFBP;
     1225
     1226    switch (enmType)
     1227    {
     1228        case DBGFBPTYPE_REG:
     1229        {
     1230            PVM pVM = pUVM->pVM;
     1231            VM_ASSERT_VALID_EXT_RETURN(pVM, NIL_DBGFBP);
     1232
     1233            for (uint32_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
     1234            {
     1235                PDBGFBPHW pHwBp = &pVM->dbgf.s.aHwBreakpoints[i];
     1236
     1237                AssertCompileSize(DBGFBP, sizeof(uint32_t));
     1238                DBGFBP hBpTmp = ASMAtomicReadU32(&pHwBp->hBp);
     1239                if (   pHwBp->GCPtr == GCPtr
     1240                    && hBpTmp != NIL_DBGFBP)
     1241                {
     1242                    hBp = hBpTmp;
     1243                    break;
     1244                }
     1245            }
     1246
     1247            break;
     1248        }
     1249
     1250        case DBGFBPTYPE_INT3:
     1251        {
     1252            const uint16_t idxL1      = DBGF_BP_INT3_L1_IDX_EXTRACT_FROM_ADDR(GCPtr);
     1253            const uint32_t u32L1Entry = ASMAtomicReadU32(&pUVM->dbgf.s.CTX_SUFF(paBpLocL1)[idxL1]);
     1254
     1255            if (u32L1Entry != DBGF_BP_INT3_L1_ENTRY_TYPE_NULL)
     1256            {
     1257                uint8_t u8Type = DBGF_BP_INT3_L1_ENTRY_GET_TYPE(u32L1Entry);
     1258                if (u8Type == DBGF_BP_INT3_L1_ENTRY_TYPE_BP_HND)
     1259                    hBp = DBGF_BP_INT3_L1_ENTRY_GET_BP_HND(u32L1Entry);
     1260                else if (u8Type == DBGF_BP_INT3_L1_ENTRY_TYPE_L2_IDX)
     1261                {
     1262                    RTGCUINTPTR GCPtrKey = DBGF_BP_INT3_L2_KEY_EXTRACT_FROM_ADDR(GCPtr);
     1263                    PDBGFBPL2ENTRY pL2Nd = dbgfR3BpL2GetByIdx(pUVM, DBGF_BP_INT3_L1_ENTRY_GET_L2_IDX(u32L1Entry));
     1264
     1265                    for (;;)
     1266                    {
     1267                        AssertPtr(pL2Nd);
     1268
     1269                        RTGCUINTPTR GCPtrL2Entry = DBGF_BP_L2_ENTRY_GET_GCPTR(pL2Nd->u64GCPtrKeyAndBpHnd1);
     1270                        if (GCPtrKey == GCPtrL2Entry)
     1271                        {
     1272                            hBp = DBGF_BP_L2_ENTRY_GET_BP_HND(pL2Nd->u64GCPtrKeyAndBpHnd1, pL2Nd->u64LeftRightIdxDepthBpHnd2);
     1273                            break;
     1274                        }
     1275
     1276                        /* Not found, get to the next level. */
     1277                        uint32_t idxL2Next =   (GCPtrKey < GCPtrL2Entry)
     1278                                             ? DBGF_BP_L2_ENTRY_GET_IDX_LEFT(pL2Nd->u64LeftRightIdxDepthBpHnd2)
     1279                                             : DBGF_BP_L2_ENTRY_GET_IDX_RIGHT(pL2Nd->u64LeftRightIdxDepthBpHnd2);
     1280                        /* Address not found if the entry denotes the end. */
     1281                        if (idxL2Next == DBGF_BP_L2_ENTRY_IDX_END)
     1282                            break;
     1283
     1284                        pL2Nd = dbgfR3BpL2GetByIdx(pUVM, idxL2Next);
     1285                    }
     1286                }
     1287            }
     1288            break;
     1289        }
     1290
     1291        default:
     1292            AssertMsgFailed(("enmType=%d\n", enmType));
     1293            break;
     1294    }
     1295
     1296    if (   hBp != NIL_DBGFBP
     1297        && ppBp)
     1298        *ppBp =  dbgfR3BpGetByHnd(pUVM, hBp);
     1299    return hBp;
     1300}
     1301
     1302
     1303/**
    12661304 * @callback_method_impl{FNVMMEMTRENDEZVOUS}
    12671305 */
     
    16031641    AssertRCReturn(rc, rc);
    16041642
    1605     DBGFBP hBp = NIL_DBGFBP;
    1606     PDBGFBPINT pBp = NULL;
    1607     rc = dbgfR3BpAlloc(pUVM, hOwner, pvUser, DBGFBPTYPE_INT3, iHitTrigger, iHitDisable, &hBp, &pBp);
     1643    /*
     1644     * Translate & save the breakpoint address into a guest-physical address.
     1645     */
     1646    RTGCPHYS GCPhysBpAddr = NIL_RTGCPHYS;
     1647    rc = DBGFR3AddrToPhys(pUVM, idSrcCpu, pAddress, &GCPhysBpAddr);
    16081648    if (RT_SUCCESS(rc))
    16091649    {
    16101650        /*
    1611          * Translate & save the breakpoint address into a guest-physical address.
     1651         * The physical address from DBGFR3AddrToPhys() is the start of the page,
     1652         * we need the exact byte offset into the page while writing to it in dbgfR3BpInt3Arm().
    16121653         */
    1613         rc = DBGFR3AddrToPhys(pUVM, idSrcCpu, pAddress, &pBp->Pub.u.Int3.PhysAddr);
     1654        GCPhysBpAddr |= (pAddress->FlatPtr & X86_PAGE_OFFSET_MASK);
     1655
     1656        PDBGFBPINT pBp = NULL;
     1657        DBGFBP hBp = dbgfR3BpGetByAddr(pUVM, DBGFBPTYPE_INT3, pAddress->FlatPtr, &pBp);
     1658        if (    hBp != NIL_DBGFBP
     1659            &&  pBp->Pub.u.Int3.PhysAddr == GCPhysBpAddr)
     1660        {
     1661            rc = VINF_SUCCESS;
     1662            if (!DBGF_BP_PUB_IS_ENABLED(pBp->Pub.fFlagsAndType))
     1663                rc = dbgfR3BpArm(pUVM, hBp, pBp);
     1664            if (RT_SUCCESS(rc))
     1665            {
     1666                rc = VINF_DBGF_BP_ALREADY_EXIST;
     1667                if (phBp)
     1668                    *phBp = hBp;
     1669            }
     1670            return rc;
     1671        }
     1672
     1673        rc = dbgfR3BpAlloc(pUVM, hOwner, pvUser, DBGFBPTYPE_INT3, iHitTrigger, iHitDisable, &hBp, &pBp);
    16141674        if (RT_SUCCESS(rc))
    16151675        {
    1616             /*
    1617              * The physical address from DBGFR3AddrToPhys() is the start of the page,
    1618              * we need the exact byte offset into the page while writing to it in dbgfR3BpInt3Arm().
    1619              */
    1620             pBp->Pub.u.Int3.PhysAddr |= (pAddress->FlatPtr & X86_PAGE_OFFSET_MASK);
    1621             pBp->Pub.u.Int3.GCPtr     = pAddress->FlatPtr;
     1676            pBp->Pub.u.Int3.PhysAddr = GCPhysBpAddr;
     1677            pBp->Pub.u.Int3.GCPtr    = pAddress->FlatPtr;
    16221678
    16231679            /* Add the breakpoint to the lookup tables. */
     
    16351691                int rc2 = dbgfR3BpInt3Remove(pUVM, hBp, pBp); AssertRC(rc2);
    16361692            }
    1637         }
    1638 
    1639         dbgfR3BpFree(pUVM, hBp, pBp);
     1693
     1694            dbgfR3BpFree(pUVM, hBp, pBp);
     1695        }
    16401696    }
    16411697
     
    20122068
    20132069/**
    2014  * EMT worker for DBGFR3BpEnum().
     2070 * Enumerate the breakpoints.
    20152071 *
    20162072 * @returns VBox status code.
     
    20192075 * @param   pvUser      The user argument to pass to the callback.
    20202076 *
    2021  * @thread  EMT
    2022  * @internal
    2023  */
    2024 static DECLCALLBACK(int) dbgfR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
    2025 {
    2026     /*
    2027      * Validate input.
    2028      */
    2029     PVM pVM = pUVM->pVM;
    2030     VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
    2031     AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
    2032 
    2033     RT_NOREF(pvUser);
    2034 
    2035     return VERR_NOT_IMPLEMENTED;
    2036 }
    2037 
    2038 
    2039 /**
    2040  * Enumerate the breakpoints.
    2041  *
    2042  * @returns VBox status code.
    2043  * @param   pUVM        The user mode VM handle.
    2044  * @param   pfnCallback The callback function.
    2045  * @param   pvUser      The user argument to pass to the callback.
    2046  *
    2047  * @thread  Any thread but the callback will be called from EMT.
     2077 * @thread  Any thread.
    20482078 */
    20492079VMMR3DECL(int) DBGFR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
    20502080{
    2051     /*
    2052      * This must be done on EMT.
    2053      */
    2054     int rc = VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpEnum, 3, pUVM, pfnCallback, pvUser);
    2055     LogFlow(("DBGFR3BpEnum: returns %Rrc\n", rc));
    2056     return rc;
    2057 }
    2058 
     2081    UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
     2082
     2083    for (uint32_t idChunk = 0; idChunk < RT_ELEMENTS(pUVM->dbgf.s.aBpChunks); idChunk++)
     2084    {
     2085        PDBGFBPCHUNKR3 pBpChunk = &pUVM->dbgf.s.aBpChunks[idChunk];
     2086
     2087        if (pBpChunk->idChunk == DBGF_BP_CHUNK_ID_INVALID)
     2088            break; /* Stop here as the first non allocated chunk means there is no one allocated afterwards as well. */
     2089
     2090        if (pBpChunk->cBpsFree < DBGF_BP_COUNT_PER_CHUNK)
     2091        {
     2092            /* Scan the bitmap for allocated entries. */
     2093            int32_t iAlloc = ASMBitFirstSet(pBpChunk->pbmAlloc, DBGF_BP_COUNT_PER_CHUNK);
     2094            if (iAlloc != -1)
     2095            {
     2096                do
     2097                {
     2098                    DBGFBP hBp = DBGF_BP_HND_CREATE(idChunk, (uint32_t)iAlloc);
     2099                    PDBGFBPINT pBp = dbgfR3BpGetByHnd(pUVM, hBp);
     2100
     2101                    /* Make a copy of the breakpoints public data to have a consistent view. */
     2102                    DBGFBPPUB BpPub;
     2103                    BpPub.cHits         = ASMAtomicReadU64((volatile uint64_t *)&pBp->Pub.cHits);
     2104                    BpPub.iHitTrigger   = ASMAtomicReadU64((volatile uint64_t *)&pBp->Pub.iHitTrigger);
     2105                    BpPub.iHitDisable   = ASMAtomicReadU64((volatile uint64_t *)&pBp->Pub.iHitDisable);
     2106                    BpPub.hOwner        = ASMAtomicReadU32((volatile uint32_t *)&pBp->Pub.hOwner);
     2107                    BpPub.fFlagsAndType = ASMAtomicReadU32((volatile uint32_t *)&pBp->Pub.fFlagsAndType);
     2108                    memcpy(&BpPub.u, &pBp->Pub.u, sizeof(pBp->Pub.u)); /* Is constant after allocation. */
     2109
     2110                    /* Check if a removal raced us. */
     2111                    if (ASMBitTest(pBpChunk->pbmAlloc, iAlloc))
     2112                    {
     2113                        int rc = pfnCallback(pUVM, pvUser, hBp, &BpPub);
     2114                        if (RT_FAILURE(rc) || rc == VINF_CALLBACK_RETURN)
     2115                            return rc;
     2116                    }
     2117
     2118                    iAlloc = ASMBitNextSet(pBpChunk->pbmAlloc, DBGF_BP_COUNT_PER_CHUNK, iAlloc);
     2119                } while (iAlloc != -1);
     2120            }
     2121        }
     2122    }
     2123
     2124    return VINF_SUCCESS;
     2125}
     2126
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