VirtualBox

Changeset 86726 in vbox


Ignore:
Timestamp:
Oct 28, 2020 10:10:29 AM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
141114
Message:

VMM/DBGF: Implement L2 binary search tree node insertion and walking the tree in R0, bugref:9837

Location:
trunk
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/err.h

    r86701 r86726  
    331331/** The breakpoint owner handle is still used by one or more breakpoints. */
    332332#define VERR_DBGF_OWNER_BUSY                (-1225)
     333/** Number of tries to add an int3 breakpoint table to the lookup tables reached. */
     334#define VERR_DBGF_BP_INT3_ADD_TRIES_REACHED (-1226)
    333335/** Internal processing error \#1 in the DBGF breakpoint manager code. */
    334 #define VERR_DBGF_BP_IPE_1                  (-1226)
     336#define VERR_DBGF_BP_IPE_1                  (-1227)
    335337/** Internal processing error \#2 in the DBGF breakpoint manager code. */
    336 #define VERR_DBGF_BP_IPE_2                  (-1227)
     338#define VERR_DBGF_BP_IPE_2                  (-1228)
    337339/** Internal processing error \#3 in the DBGF breakpoint manager code. */
    338 #define VERR_DBGF_BP_IPE_3                  (-1228)
     340#define VERR_DBGF_BP_IPE_3                  (-1229)
    339341/** Internal processing error \#4 in the DBGF breakpoint manager code. */
    340 #define VERR_DBGF_BP_IPE_4                  (-1229)
     342#define VERR_DBGF_BP_IPE_4                  (-1230)
    341343/** Internal processing error \#5 in the DBGF breakpoint manager code. */
    342 #define VERR_DBGF_BP_IPE_5                  (-1230)
     344#define VERR_DBGF_BP_IPE_5                  (-1231)
    343345/** Internal processing error \#6 in the DBGF breakpoint manager code. */
    344 #define VERR_DBGF_BP_IPE_6                  (-1231)
    345 /** Number of tries to add an int3 breakpoint table to the lookup tables reached. */
    346 #define VERR_DBGF_BP_INT3_ADD_TRIES_REACHED (-1232)
     346#define VERR_DBGF_BP_IPE_6                  (-1232)
     347/** Internal processing error \#7 in the DBGF breakpoint manager code. */
     348#define VERR_DBGF_BP_IPE_7                  (-1233)
     349/** Internal processing error \#8 in the DBGF breakpoint manager code. */
     350#define VERR_DBGF_BP_IPE_8                  (-1234)
     351/** Internal processing error \#9 in the DBGF breakpoint manager code. */
     352#define VERR_DBGF_BP_IPE_9                  (-1235)
     353/** Level 2 lookup failed because the L1 lookup table is corrupted. */
     354#define VERR_DBGF_BP_L1_LOOKUP_FAILED       (-1236)
     355/** Level 2 lookup failed because the L2 lookup table is corrupted. */
     356#define VERR_DBGF_BP_L2_LOOKUP_FAILED       (-1237)
    347357/** @} */
    348358
  • trunk/src/VBox/VMM/VMMR3/DBGFR3Bp.cpp

    r86704 r86726  
    157157#include <iprt/mem.h>
    158158
     159#include "DBGFInline.h"
     160
    159161
    160162/*********************************************************************************************************************************
     
    855857
    856858/**
     859 * Returns the pointer to the L2 table entry from the given index.
     860 *
     861 * @returns Current context pointer to the L2 table entry or NULL if the provided index value is invalid.
     862 * @param   pUVM        The user mode VM handle.
     863 * @param   idxL2       The L2 table index to resolve.
     864 *
     865 * @note The content of the resolved L2 table entry is not validated!.
     866 */
     867DECLINLINE(PDBGFBPL2ENTRY) dbgfR3BpL2GetByIdx(PUVM pUVM, uint32_t idxL2)
     868{
     869    uint32_t idChunk  = DBGF_BP_L2_IDX_GET_CHUNK_ID(idxL2);
     870    uint32_t idxEntry = DBGF_BP_L2_IDX_GET_ENTRY(idxL2);
     871
     872    AssertReturn(idChunk < DBGF_BP_L2_TBL_CHUNK_COUNT, NULL);
     873    AssertReturn(idxEntry < DBGF_BP_L2_TBL_ENTRIES_PER_CHUNK, NULL);
     874
     875    PDBGFBPL2TBLCHUNKR3 pL2Chunk = &pUVM->dbgf.s.aBpL2TblChunks[idChunk];
     876    AssertPtrReturn(pL2Chunk->pbmAlloc, NULL);
     877    AssertReturn(ASMBitTest(pL2Chunk->pbmAlloc, idxEntry), NULL);
     878
     879    return &pL2Chunk->CTX_SUFF(pL2Base)[idxEntry];
     880}
     881
     882
     883/**
     884 * Creates a binary search tree with the given root and leaf nodes.
     885 *
     886 * @returns VBox status code.
     887 * @param   pUVM                The user mode VM handle.
     888 * @param   idxL1               The index into the L1 table where the created tree should be linked into.
     889 * @param   u32EntryOld         The old entry in the L1 table used to compare with in the atomic update.
     890 * @param   hBpRoot             The root node DBGF handle to assign.
     891 * @param   GCPtrRoot           The root nodes GC pointer to use as a key.
     892 * @param   hBpLeaf             The leafs node DBGF handle to assign.
     893 * @param   GCPtrLeaf           The leafs node GC pointer to use as a key.
     894 */
     895static int dbgfR3BpInt3L2BstCreate(PUVM pUVM, uint32_t idxL1, uint32_t u32EntryOld,
     896                                   DBGFBP hBpRoot, RTGCUINTPTR GCPtrRoot,
     897                                   DBGFBP hBpLeaf, RTGCUINTPTR GCPtrLeaf)
     898{
     899    AssertReturn(GCPtrRoot != GCPtrLeaf, VERR_DBGF_BP_IPE_9);
     900    Assert(DBGF_BP_INT3_L1_IDX_EXTRACT_FROM_ADDR(GCPtrRoot) == DBGF_BP_INT3_L1_IDX_EXTRACT_FROM_ADDR(GCPtrLeaf));
     901
     902    /* Allocate two nodes. */
     903    uint32_t idxL2Root = 0;
     904    PDBGFBPL2ENTRY pL2Root = NULL;
     905    int rc = dbgfR3BpL2TblEntryAlloc(pUVM, &idxL2Root, &pL2Root);
     906    if (RT_SUCCESS(rc))
     907    {
     908        uint32_t idxL2Leaf = 0;
     909        PDBGFBPL2ENTRY pL2Leaf = NULL;
     910        rc = dbgfR3BpL2TblEntryAlloc(pUVM, &idxL2Leaf, &pL2Leaf);
     911        if (RT_SUCCESS(rc))
     912        {
     913            dbgfBpL2TblEntryInit(pL2Leaf, hBpLeaf, GCPtrLeaf, DBGF_BP_L2_ENTRY_IDX_END, DBGF_BP_L2_ENTRY_IDX_END, 0 /*iDepth*/);
     914            if (GCPtrLeaf < GCPtrRoot)
     915                dbgfBpL2TblEntryInit(pL2Root, hBpRoot, GCPtrRoot, idxL2Leaf, DBGF_BP_L2_ENTRY_IDX_END, 0 /*iDepth*/);
     916            else
     917                dbgfBpL2TblEntryInit(pL2Root, hBpRoot, GCPtrRoot, DBGF_BP_L2_ENTRY_IDX_END, idxL2Leaf, 0 /*iDepth*/);
     918
     919            uint32_t const u32Entry = DBGF_BP_INT3_L1_ENTRY_CREATE_L2_IDX(idxL2Root);
     920            if (ASMAtomicCmpXchgU32(&pUVM->dbgf.s.paBpLocL1R3[idxL1], u32Entry, u32EntryOld))
     921                return VINF_SUCCESS;
     922
     923            /* The L1 entry has changed due to another thread racing us during insertion, free nodes and try again. */
     924            rc = VINF_TRY_AGAIN;
     925            dbgfR3BpL2TblEntryFree(pUVM, idxL2Leaf, pL2Leaf);
     926        }
     927
     928        dbgfR3BpL2TblEntryFree(pUVM, idxL2Root, pL2Root);
     929    }
     930
     931    return rc;
     932}
     933
     934
     935/**
     936 * Inserts the given breakpoint handle into an existing binary search tree.
     937 *
     938 * @returns VBox status code.
     939 * @param   pUVM                The user mode VM handle.
     940 * @param   idxL2Root           The index of the tree root in the L2 table.
     941 * @param   hBpRoot             The node DBGF handle to insert.
     942 * @param   GCPtrRoot           The nodes GC pointer to use as a key.
     943 */
     944static int dbgfR3BpInt2L2BstNodeInsert(PUVM pUVM, uint32_t idxL2Root, DBGFBP hBp, RTGCUINTPTR GCPtr)
     945{
     946    /* Allocate a new node first. */
     947    uint32_t idxL2Nd = 0;
     948    PDBGFBPL2ENTRY pL2Nd = NULL;
     949    int rc = dbgfR3BpL2TblEntryAlloc(pUVM, &idxL2Nd, &pL2Nd);
     950    if (RT_SUCCESS(rc))
     951    {
     952        /* Walk the tree and find the correct node to insert to. */
     953        PDBGFBPL2ENTRY pL2Entry = dbgfR3BpL2GetByIdx(pUVM, idxL2Root);
     954        while (RT_LIKELY(pL2Entry))
     955        {
     956            /* Make a copy of the entry. */
     957            DBGFBPL2ENTRY L2Entry;
     958            L2Entry.u64GCPtrKeyAndBpHnd1       = ASMAtomicReadU64((volatile uint64_t *)&pL2Entry->u64GCPtrKeyAndBpHnd1);
     959            L2Entry.u64LeftRightIdxDepthBpHnd2 = ASMAtomicReadU64((volatile uint64_t *)&pL2Entry->u64LeftRightIdxDepthBpHnd2);
     960
     961            RTGCUINTPTR GCPtrL2Entry = DBGF_BP_L2_ENTRY_GET_GCPTR(L2Entry.u64GCPtrKeyAndBpHnd1);
     962            AssertBreak(GCPtr != GCPtrL2Entry);
     963
     964            /* Not found, get to the next level. */
     965            uint32_t idxL2Next =   (GCPtr < GCPtrL2Entry)
     966                                 ? DBGF_BP_L2_ENTRY_GET_IDX_LEFT(L2Entry.u64LeftRightIdxDepthBpHnd2)
     967                                 : DBGF_BP_L2_ENTRY_GET_IDX_RIGHT(L2Entry.u64LeftRightIdxDepthBpHnd2);
     968            if (idxL2Next == DBGF_BP_L2_ENTRY_IDX_END)
     969            {
     970                /* Insert the new node here. */
     971                dbgfBpL2TblEntryInit(pL2Nd, hBp, GCPtr, DBGF_BP_L2_ENTRY_IDX_END, DBGF_BP_L2_ENTRY_IDX_END, 0 /*iDepth*/);
     972                if (GCPtr < GCPtrL2Entry)
     973                    dbgfBpL2TblEntryUpdateLeft(pL2Entry, idxL2Next, 0 /*iDepth*/);
     974                else
     975                    dbgfBpL2TblEntryUpdateRight(pL2Entry, idxL2Next, 0 /*iDepth*/);
     976                return VINF_SUCCESS;
     977            }
     978
     979            pL2Entry = dbgfR3BpL2GetByIdx(pUVM, idxL2Next);
     980        }
     981
     982        rc = VERR_DBGF_BP_L2_LOOKUP_FAILED;
     983        dbgfR3BpL2TblEntryFree(pUVM, idxL2Nd, pL2Nd);
     984    }
     985
     986    return rc;
     987}
     988
     989
     990/**
     991 * Adds the given breakpoint handle keyed with the GC pointer to the proper L2 binary search tree
     992 * possibly creating a new tree.
     993 *
     994 * @returns VBox status code.
     995 * @param   pUVM                The user mode VM handle.
     996 * @param   idxL1               The index into the L1 table the breakpoint uses.
     997 * @param   hBp                 The breakpoint handle which is to be added.
     998 * @param   GCPtr               The GC pointer the breakpoint is keyed with.
     999 */
     1000static int dbgfR3BpInt3L2BstNodeAdd(PUVM pUVM, uint32_t idxL1, DBGFBP hBp, RTGCUINTPTR GCPtr)
     1001{
     1002    int rc = RTSemFastMutexRequest(pUVM->dbgf.s.hMtxBpL2Wr); AssertRC(rc);
     1003
     1004    uint32_t u32Entry = ASMAtomicReadU32(&pUVM->dbgf.s.paBpLocL1R3[idxL1]); /* Re-read, could get raced by a remove operation. */
     1005    uint8_t u8Type = DBGF_BP_INT3_L1_ENTRY_GET_TYPE(u32Entry);
     1006    if (u8Type == DBGF_BP_INT3_L1_ENTRY_TYPE_BP_HND)
     1007    {
     1008        /* Create a new search tree, gather the necessary information first. */
     1009        DBGFBP hBp2 = DBGF_BP_INT3_L1_ENTRY_GET_BP_HND(u32Entry);
     1010        PDBGFBPINT pBp2 = dbgfR3BpGetByHnd(pUVM, hBp2);
     1011        AssertStmt(VALID_PTR(pBp2), rc = VERR_DBGF_BP_IPE_7);
     1012        if (RT_SUCCESS(rc))
     1013            rc = dbgfR3BpInt3L2BstCreate(pUVM, idxL1, u32Entry, hBp, GCPtr, hBp2, pBp2->Pub.u.Int3.GCPtr);
     1014    }
     1015    else if (u8Type == DBGF_BP_INT3_L1_ENTRY_TYPE_L2_IDX)
     1016        rc = dbgfR3BpInt2L2BstNodeInsert(pUVM, DBGF_BP_INT3_L1_ENTRY_GET_L2_IDX(u32Entry), hBp, GCPtr);
     1017
     1018    int rc2 = RTSemFastMutexRelease(pUVM->dbgf.s.hMtxBpL2Wr); AssertRC(rc2);
     1019    return rc;
     1020}
     1021
     1022
     1023/**
     1024 * Removes the given breakpoint handle keyed with the GC pointer from the L2 binary search tree
     1025 * pointed to by the given L2 root index.
     1026 *
     1027 * @returns VBox status code.
     1028 * @param   pUVM                The user mode VM handle.
     1029 * @param   idxL1               The index into the L1 table pointing to the binary search tree.
     1030 * @param   idxL2Root           The L2 table index where the tree root is located.
     1031 * @param   hBp                 The breakpoint handle which is to be removed.
     1032 * @param   GCPtr               The GC pointer the breakpoint is keyed with.
     1033 */
     1034static int dbgfR3BpInt2L2BstNodeRemove(PUVM pUVM, uint32_t idxL1, uint32_t idxL2Root, DBGFBP hBp, RTGCUINTPTR GCPtr)
     1035{
     1036    int rc = RTSemFastMutexRequest(pUVM->dbgf.s.hMtxBpL2Wr); AssertRC(rc);
     1037
     1038    RT_NOREF(idxL1, idxL2Root, hBp, GCPtr);
     1039
     1040    int rc2 = RTSemFastMutexRelease(pUVM->dbgf.s.hMtxBpL2Wr); AssertRC(rc2);
     1041
     1042    return rc;
     1043}
     1044
     1045
     1046/**
    8571047 * Adds the given int3 breakpoint to the appropriate lookup tables.
    8581048 *
     
    8861076        else
    8871077        {
    888             uint8_t u8Type = DBGF_BP_INT3_L1_ENTRY_GET_TYPE(u32Entry);
    889             if (u8Type == DBGF_BP_INT3_L1_ENTRY_TYPE_BP_HND)
    890             {
    891                 /** @todo Allocate a new root entry and one leaf to accomodate for the two handles,
    892                  * then replace the new entry. */
    893                 rc = VERR_NOT_IMPLEMENTED;
    894                 break;
    895             }
    896             else if (u8Type == DBGF_BP_INT3_L1_ENTRY_TYPE_L2_IDX)
    897             {
    898                 /** @todo Walk the L2 tree searching for the correct spot, add the new entry
    899                  * and rebalance the tree. */
    900                 rc = VERR_NOT_IMPLEMENTED;
    901                 break;
    902             }
     1078            rc = dbgfR3BpInt3L2BstNodeAdd(pUVM, idxL1, hBp, pBp->Pub.u.Int3.GCPtr);
     1079            if (rc == VINF_TRY_AGAIN)
     1080                continue;
     1081
     1082            break;
    9031083        }
    9041084    }
     
    9131093
    9141094/**
     1095 * @callback_method_impl{FNVMMEMTRENDEZVOUS}
     1096 */
     1097static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpInt3RemoveEmtWorker(PVM pVM, PVMCPU pVCpu, void *pvUser)
     1098{
     1099    DBGFBP hBp = (DBGFBP)(uintptr_t)pvUser;
     1100
     1101    VMCPU_ASSERT_EMT(pVCpu);
     1102    VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
     1103
     1104    PUVM pUVM = pVM->pUVM;
     1105    PDBGFBPINT pBp = dbgfR3BpGetByHnd(pUVM, hBp);
     1106    AssertPtrReturn(pBp, VERR_DBGF_BP_IPE_8);
     1107
     1108    int rc = VINF_SUCCESS;
     1109    if (pVCpu->idCpu == 0)
     1110    {
     1111        uint16_t idxL1 = DBGF_BP_INT3_L1_IDX_EXTRACT_FROM_ADDR(pBp->Pub.u.Int3.GCPtr);
     1112        uint32_t u32Entry = ASMAtomicReadU32(&pUVM->dbgf.s.paBpLocL1R3[idxL1]);
     1113        AssertReturn(u32Entry != DBGF_BP_INT3_L1_ENTRY_TYPE_NULL, VERR_DBGF_BP_IPE_6);
     1114
     1115        uint8_t u8Type = DBGF_BP_INT3_L1_ENTRY_GET_TYPE(u32Entry);
     1116        if (u8Type == DBGF_BP_INT3_L1_ENTRY_TYPE_BP_HND)
     1117        {
     1118            /* Single breakpoint, just exchange atomically with the null value. */
     1119            if (!ASMAtomicCmpXchgU32(&pUVM->dbgf.s.paBpLocL1R3[idxL1], DBGF_BP_INT3_L1_ENTRY_TYPE_NULL, u32Entry))
     1120            {
     1121                /*
     1122                 * A breakpoint addition must have raced us converting the L1 entry to an L2 index type, re-read
     1123                 * and remove the node from the created binary search tree.
     1124                 *
     1125                 * This works because after the entry was converted to an L2 index it can only be converted back
     1126                 * to a direct handle by removing one or more nodes which always goes through the fast mutex
     1127                 * protecting the L2 table. Likewise adding a new breakpoint requires grabbing the mutex as well
     1128                 * so there is serialization here and the node can be removed safely without having to worry about
     1129                 * concurrent tree modifications.
     1130                 */
     1131                u32Entry = ASMAtomicReadU32(&pUVM->dbgf.s.paBpLocL1R3[idxL1]);
     1132                AssertReturn(DBGF_BP_INT3_L1_ENTRY_GET_TYPE(u32Entry) == DBGF_BP_INT3_L1_ENTRY_TYPE_L2_IDX, VERR_DBGF_BP_IPE_9);
     1133
     1134                rc = dbgfR3BpInt2L2BstNodeRemove(pUVM, idxL1, DBGF_BP_INT3_L1_ENTRY_GET_L2_IDX(u32Entry),
     1135                                                 hBp, pBp->Pub.u.Int3.GCPtr);
     1136            }
     1137        }
     1138        else if (u8Type == DBGF_BP_INT3_L1_ENTRY_TYPE_L2_IDX)
     1139            rc = dbgfR3BpInt2L2BstNodeRemove(pUVM, idxL1, DBGF_BP_INT3_L1_ENTRY_GET_L2_IDX(u32Entry),
     1140                                             hBp, pBp->Pub.u.Int3.GCPtr);
     1141    }
     1142
     1143    return rc;
     1144}
     1145
     1146
     1147/**
    9151148 * Removes the given int3 breakpoint from all lookup tables.
    9161149 *
     
    9241157    AssertReturn(DBGF_BP_PUB_GET_TYPE(pBp->Pub.fFlagsAndType) == DBGFBPTYPE_INT3, VERR_DBGF_BP_IPE_3);
    9251158
    926     int rc = VINF_SUCCESS;
    927     uint16_t idxL1 = DBGF_BP_INT3_L1_IDX_EXTRACT_FROM_ADDR(pBp->Pub.u.Int3.GCPtr);
    928 
    929     for (;;)
    930     {
    931         uint32_t u32Entry = ASMAtomicReadU32(&pUVM->dbgf.s.paBpLocL1R3[idxL1]);
    932         AssertReturn(u32Entry != DBGF_BP_INT3_L1_ENTRY_TYPE_NULL, VERR_DBGF_BP_IPE_6);
    933 
    934         uint8_t u8Type = DBGF_BP_INT3_L1_ENTRY_GET_TYPE(u32Entry);
    935         if (u8Type == DBGF_BP_INT3_L1_ENTRY_TYPE_BP_HND)
    936         {
    937             /* Single breakpoint, just exchange atomically with the null value. */
    938             if (ASMAtomicCmpXchgU32(&pUVM->dbgf.s.paBpLocL1R3[idxL1], DBGF_BP_INT3_L1_ENTRY_TYPE_NULL, u32Entry))
    939                 break;
    940             break;
    941         }
    942         else if (u8Type == DBGF_BP_INT3_L1_ENTRY_TYPE_L2_IDX)
    943         {
    944             /** @todo Walk the L2 tree searching for the correct spot, remove the entry
    945              * and rebalance the tree. */
    946             RT_NOREF(hBp);
    947             rc = VERR_NOT_IMPLEMENTED;
    948             break;
    949         }
    950     }
    951 
    952     return rc;
     1159    /*
     1160     * This has to be done by an EMT rendezvous in order to not have an EMT traversing
     1161     * any L2 trees while it is being removed.
     1162     */
     1163    return VMMR3EmtRendezvous(pUVM->pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpInt3RemoveEmtWorker, (void *)(uintptr_t)hBp);
    9531164}
    9541165
  • trunk/src/VBox/VMM/VMMRZ/DBGFRZ.cpp

    r86704 r86726  
    246246         : VINF_EM_DBG_BREAKPOINT;
    247247}
     248
     249
     250/**
     251 * Returns the pointer to the L2 table entry from the given index.
     252 *
     253 * @returns Current context pointer to the L2 table entry or NULL if the provided index value is invalid.
     254 * @param   pVM         The cross context VM structure.
     255 * @param   idxL2       The L2 table index to resolve.
     256 *
     257 * @note The content of the resolved L2 table entry is not validated!.
     258 */
     259DECLINLINE(PCDBGFBPL2ENTRY) dbgfRZBpL2GetByIdx(PVMCC pVM, uint32_t idxL2)
     260{
     261    uint32_t idChunk  = DBGF_BP_L2_IDX_GET_CHUNK_ID(idxL2);
     262    uint32_t idxEntry = DBGF_BP_L2_IDX_GET_ENTRY(idxL2);
     263
     264    AssertReturn(idChunk < DBGF_BP_L2_TBL_CHUNK_COUNT, NULL);
     265    AssertReturn(idxEntry < DBGF_BP_L2_TBL_ENTRIES_PER_CHUNK, NULL);
     266
     267    PDBGFBPL2TBLCHUNKR0 pL2Chunk = &pVM->dbgfr0.s.aBpL2TblChunks[idChunk];
     268    AssertPtrReturn(pL2Chunk->paBpL2TblBaseSharedR0, NULL);
     269
     270    return &pL2Chunk->CTX_SUFF(paBpL2TblBaseShared)[idxEntry];
     271}
     272
     273
     274/**
     275 * Walks the L2 table starting at the given root index searching for the given key.
     276 *
     277 * @returns VBox status code.
     278 * @param   pVM         The cross context VM structure.
     279 * @param   pVCpu       The cross context virtual CPU structure.
     280 * @param   pRegFrame   Pointer to the register frame for the trap.
     281 * @param   fInHyper    Flag whether the breakpoint triggered in hypervisor code.
     282 * @param   idxL2Root   L2 table index of the table root.
     283 * @param   GCPtrKey    The key to search for.
     284 */
     285static int dbgfRZBpL2Walk(PVMCC pVM, PVMCPUCC pVCpu, PCPUMCTXCORE pRegFrame, bool fInHyper,
     286                          uint32_t idxL2Root, RTGCUINTPTR GCPtrKey)
     287{
     288    /** @todo We don't use the depth right now but abort the walking after a fixed amount of levels. */
     289    uint8_t iDepth = 32;
     290    PCDBGFBPL2ENTRY pL2Entry = dbgfRZBpL2GetByIdx(pVM, idxL2Root);
     291
     292    while (RT_LIKELY(   iDepth-- > 0
     293                     && pL2Entry))
     294    {
     295        /* Make a copy of the entry before verification. */
     296        DBGFBPL2ENTRY L2Entry;
     297        L2Entry.u64GCPtrKeyAndBpHnd1       = ASMAtomicReadU64((volatile uint64_t *)&pL2Entry->u64GCPtrKeyAndBpHnd1);
     298        L2Entry.u64LeftRightIdxDepthBpHnd2 = ASMAtomicReadU64((volatile uint64_t *)&pL2Entry->u64LeftRightIdxDepthBpHnd2);
     299
     300        RTGCUINTPTR GCPtrL2Entry = DBGF_BP_L2_ENTRY_GET_GCPTR(L2Entry.u64GCPtrKeyAndBpHnd1);
     301        if (GCPtrKey == GCPtrL2Entry)
     302        {
     303            DBGFBP hBp = DBGF_BP_L2_ENTRY_GET_BP_HND(L2Entry.u64GCPtrKeyAndBpHnd1, L2Entry.u64LeftRightIdxDepthBpHnd2);
     304
     305            /* Query the internal breakpoint state from the handle. */
     306            PDBGFBPINTR0 pBpR0 = NULL;
     307            PDBGFBPINT pBp = dbgfR0BpGetByHnd(pVM, hBp, &pBpR0);
     308            if (   pBp
     309                && DBGF_BP_PUB_GET_TYPE(pBp->Pub.fFlagsAndType) == DBGFBPTYPE_INT3)
     310                return dbgfRZBpHit(pVM, pVCpu, pRegFrame, hBp, pBp, pBpR0, fInHyper);
     311
     312            /* The entry got corrupted, just abort. */
     313            return VERR_DBGF_BP_L2_LOOKUP_FAILED;
     314        }
     315
     316        /* Not found, get to the next level. */
     317        uint32_t idxL2Next =   (GCPtrKey < GCPtrL2Entry)
     318                             ? DBGF_BP_L2_ENTRY_GET_IDX_LEFT(L2Entry.u64LeftRightIdxDepthBpHnd2)
     319                             : DBGF_BP_L2_ENTRY_GET_IDX_RIGHT(L2Entry.u64LeftRightIdxDepthBpHnd2);
     320        /* It is genuine guest trap or we hit some assertion if we are at the end. */
     321        if (idxL2Next == DBGF_BP_L2_ENTRY_IDX_END)
     322            return fInHyper
     323                 ? VINF_EM_DBG_HYPER_ASSERTION
     324                 : VINF_EM_RAW_GUEST_TRAP;
     325
     326        pL2Entry = dbgfRZBpL2GetByIdx(pVM, idxL2Next);
     327    }
     328
     329    return VERR_DBGF_BP_L2_LOOKUP_FAILED;
     330}
    248331#endif /* !VBOX_WITH_LOTS_OF_DBGF_BPS */
    249332
     
    342425                    /* else Genuine guest trap. */
    343426                }
    344                 /** @todo else Guru meditation */
     427
     428                return VERR_DBGF_BP_L1_LOOKUP_FAILED;
    345429            }
    346430            else if (u8Type == DBGF_BP_INT3_L1_ENTRY_TYPE_L2_IDX)
    347             {
    348                 /** @todo Walk the L2 tree searching for the correct spot. */
    349             }
    350             /** @todo else Guru meditation */
     431                return dbgfRZBpL2Walk(pVM, pVCpu, pRegFrame, fInHyper, DBGF_BP_INT3_L1_ENTRY_GET_L2_IDX(u32L1Entry),
     432                                      DBGF_BP_INT3_L2_KEY_EXTRACT_FROM_ADDR((RTGCUINTPTR)GCPtrBp));
     433
     434            /* Some invalid type. */
     435            return VERR_DBGF_BP_L1_LOOKUP_FAILED;
    351436        }
    352437    }
  • trunk/src/VBox/VMM/include/DBGFInternal.h

    r86704 r86726  
    956956typedef const DBGFBPL2ENTRY *PCDBGFBPL2ENTRY;
    957957
     958/** Extracts the part from the given GC pointer used as the key in the L2 binary search tree. */
     959#define DBGF_BP_INT3_L2_KEY_EXTRACT_FROM_ADDR(a_GCPtr)  ((uint64_t)((a_GCPtr) >> 16))
     960
    958961/** An invalid breakpoint chunk ID. */
    959962#define DBGF_BP_L2_IDX_CHUNK_ID_INVALID             UINT32_MAX
     
    967970/** Number of bits for the left/right index pointers. */
    968971#define DBGF_BP_L2_ENTRY_LEFT_RIGHT_IDX_BITS            22
     972/** Special index value marking the end of a tree. */
     973#define DBGF_BP_L2_ENTRY_IDX_END                        UINT32_C(0x3fffff)
     974/** Number of bits to shift the breakpoint handle in the first part. */
     975#define DBGF_BP_L2_ENTRY_BP_1ST_SHIFT                   48
     976/** Mask for the first part of the breakpoint handle. */
     977#define DBGF_BP_L2_ENTRY_BP_1ST_MASK                    UINT32_C(0x0000ffff)
     978/** Number of bits to shift the breakpoint handle in the second part. */
     979#define DBGF_BP_L2_ENTRY_BP_2ND_SHIFT                   52
     980/** Mask for the second part of the breakpoint handle. */
     981#define DBGF_BP_L2_ENTRY_BP_2ND_MASK                    UINT32_C(0x0fff0000)
     982/** Mask for the second part of the breakpoint handle stored in the L2 entry. */
     983#define DBGF_BP_L2_ENTRY_BP_2ND_L2_ENTRY_MASK           UINT64_C(0xfff0000000000000)
     984/** Number of bits to shift the depth in the second part. */
     985#define DBGF_BP_L2_ENTRY_DEPTH_SHIFT                    44
     986/** Mask for the depth. */
     987#define DBGF_BP_L2_ENTRY_DEPTH_MASK                     UINT8_MAX
     988/** Number of bits to shift the right L2 index in the second part. */
     989#define DBGF_BP_L2_ENTRY_RIGHT_IDX_SHIFT                22
     990/** Number of bits to shift the left L2 index in the second part. */
     991#define DBGF_BP_L2_ENTRY_LEFT_IDX_SHIFT                 0
    969992/** Index mask. */
    970993#define DBGF_BP_L2_ENTRY_LEFT_RIGHT_IDX_MASK            (RT_BIT_32(DBGF_BP_L2_ENTRY_LEFT_RIGHT_IDX_BITS) - 1)
     994/** Left index mask. */
     995#define DBGF_BP_L2_ENTRY_LEFT_IDX_MASK                  (DBGF_BP_L2_ENTRY_LEFT_RIGHT_IDX_MASK << DBGF_BP_L2_ENTRY_LEFT_IDX_SHIFT)
     996/** Right index mask. */
     997#define DBGF_BP_L2_ENTRY_RIGHT_IDX_MASK                 (DBGF_BP_L2_ENTRY_LEFT_RIGHT_IDX_MASK << DBGF_BP_L2_ENTRY_RIGHT_IDX_SHIFT)
    971998/** Returns the upper 6 bytes of the GC pointer from the given breakpoint entry. */
    972999#define DBGF_BP_L2_ENTRY_GET_GCPTR(a_u64GCPtrKeyAndBpHnd1) ((a_u64GCPtrKeyAndBpHnd1) & UINT64_C(0x0000ffffffffffff))
    9731000/** Returns the breakpoint handle from both L2 entry members. */
    9741001#define DBGF_BP_L2_ENTRY_GET_BP_HND(a_u64GCPtrKeyAndBpHnd1, a_u64LeftRightIdxDepthBpHnd2) \
    975     ((DBGFBP)(((a_u64GCPtrKeyAndBpHnd1) >> 48) | (((a_u64LeftRightIdxDepthBpHnd2) >> 52) << 16)))
     1002    ((DBGFBP)(((a_u64GCPtrKeyAndBpHnd1) >> DBGF_BP_L2_ENTRY_BP_1ST_SHIFT) | (((a_u64LeftRightIdxDepthBpHnd2) >> DBGF_BP_L2_ENTRY_BP_2ND_SHIFT) << 16)))
    9761003/** Extracts the depth of the second 64bit L2 entry value. */
    977 #define DBGF_BP_L2_ENTRY_GET_DEPTH(a_u64LeftRightIdxDepthBpHnd2) ((uint8_t)(((a_u64LeftRightIdxDepthBpHnd2) >> 44) & UINT8_MAX))
     1004#define DBGF_BP_L2_ENTRY_GET_DEPTH(a_u64LeftRightIdxDepthBpHnd2) ((uint8_t)(((a_u64LeftRightIdxDepthBpHnd2) >> DBGF_BP_L2_ENTRY_DEPTH_SHIFT) & DBGF_BP_L2_ENTRY_DEPTH_MASK))
    9781005/** Extracts the lower right index value from the L2 entry value. */
    9791006#define DBGF_BP_L2_ENTRY_GET_IDX_RIGHT(a_u64LeftRightIdxDepthBpHnd2) \
Note: See TracChangeset for help on using the changeset viewer.

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