VirtualBox

Changeset 86701 in vbox for trunk/src/VBox/VMM/VMMR3


Ignore:
Timestamp:
Oct 25, 2020 6:20:09 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
141085
Message:

VMM/DBGF: Start implementing support for int3 breakpoints, bugref:9837

File:
1 edited

Legend:

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

    r86699 r86701  
    643643
    644644/**
     645 * Adds the given int3 breakpoint to the appropriate lookup tables.
     646 *
     647 * @returns VBox status code.
     648 * @param   pUVM                The user mode VM handle.
     649 * @param   hBp                 The breakpoint handle to add.
     650 * @param   pBp                 The internal breakpoint state.
     651 */
     652static int dbgfR3BpInt3Add(PUVM pUVM, DBGFBP hBp, PDBGFBPINT pBp)
     653{
     654    AssertReturn(DBGF_BP_PUB_GET_TYPE(pBp->Pub.fFlagsAndType) == DBGFBPTYPE_INT3, VERR_DBGF_BP_IPE_3);
     655
     656    int rc = VINF_SUCCESS;
     657    uint16_t idxL1 = DBGF_BP_INT3_L1_IDX_EXTRACT_FROM_ADDR(pBp->Pub.u.Int3.GCPtr);
     658    uint8_t  cTries = 16;
     659
     660    while (cTries--)
     661    {
     662        uint32_t u32Entry = ASMAtomicReadU32(&pUVM->dbgf.s.paBpLocL1R3[idxL1]);
     663
     664        if (u32Entry == DBGF_BP_INT3_L1_ENTRY_TYPE_NULL)
     665        {
     666            /*
     667             * No breakpoint assigned so far for this entry, create an entry containing
     668             * the direct breakpoint handle and try to exchange it atomically.
     669             */
     670            u32Entry = DBGF_BP_INT3_L1_ENTRY_CREATE_BP_HND(hBp);
     671            if (ASMAtomicCmpXchgU32(&pUVM->dbgf.s.paBpLocL1R3[idxL1], u32Entry, DBGF_BP_INT3_L1_ENTRY_TYPE_NULL))
     672                break;
     673        }
     674        else
     675        {
     676            uint8_t u8Type = DBGF_BP_INT3_L1_ENTRY_GET_TYPE(u32Entry);
     677            if (u8Type == DBGF_BP_INT3_L1_ENTRY_TYPE_BP_HND)
     678            {
     679                /** @todo Allocate a new root entry and one leaf to accomodate for the two handles,
     680                 * then replace the new entry. */
     681                rc = VERR_NOT_IMPLEMENTED;
     682                break;
     683            }
     684            else if (u8Type == DBGF_BP_INT3_L1_ENTRY_TYPE_L2_IDX)
     685            {
     686                /** @todo Walk the L2 tree searching for the correct spot, add the new entry
     687                 * and rebalance the tree. */
     688                rc = VERR_NOT_IMPLEMENTED;
     689                break;
     690            }
     691        }
     692    }
     693
     694    if (   RT_SUCCESS(rc)
     695        && !cTries) /* Too much contention, abort with an error. */
     696        rc = VERR_DBGF_BP_INT3_ADD_TRIES_REACHED;
     697
     698    return rc;
     699}
     700
     701
     702/**
     703 * Removes the given int3 breakpoint from all lookup tables.
     704 *
     705 * @returns VBox status code.
     706 * @param   pUVM                The user mode VM handle.
     707 * @param   hBp                 The breakpoint handle to remove.
     708 * @param   pBp                 The internal breakpoint state.
     709 */
     710static int dbgfR3BpInt3Remove(PUVM pUVM, DBGFBP hBp, PDBGFBPINT pBp)
     711{
     712    AssertReturn(DBGF_BP_PUB_GET_TYPE(pBp->Pub.fFlagsAndType) == DBGFBPTYPE_INT3, VERR_DBGF_BP_IPE_3);
     713
     714    int rc = VINF_SUCCESS;
     715    uint16_t idxL1 = DBGF_BP_INT3_L1_IDX_EXTRACT_FROM_ADDR(pBp->Pub.u.Int3.GCPtr);
     716
     717    for (;;)
     718    {
     719        uint32_t u32Entry = ASMAtomicReadU32(&pUVM->dbgf.s.paBpLocL1R3[idxL1]);
     720        AssertReturn(u32Entry != DBGF_BP_INT3_L1_ENTRY_TYPE_NULL, VERR_DBGF_BP_IPE_6);
     721
     722        uint8_t u8Type = DBGF_BP_INT3_L1_ENTRY_GET_TYPE(u32Entry);
     723        if (u8Type == DBGF_BP_INT3_L1_ENTRY_TYPE_BP_HND)
     724        {
     725            /* Single breakpoint, just exchange atomically with the null value. */
     726            if (ASMAtomicCmpXchgU32(&pUVM->dbgf.s.paBpLocL1R3[idxL1], DBGF_BP_INT3_L1_ENTRY_TYPE_NULL, u32Entry))
     727                break;
     728            break;
     729        }
     730        else if (u8Type == DBGF_BP_INT3_L1_ENTRY_TYPE_L2_IDX)
     731        {
     732            /** @todo Walk the L2 tree searching for the correct spot, remove the entry
     733             * and rebalance the tree. */
     734            RT_NOREF(hBp);
     735            rc = VERR_NOT_IMPLEMENTED;
     736            break;
     737        }
     738    }
     739
     740    return rc;
     741}
     742
     743
     744/**
    645745 * @callback_method_impl{FNVMMEMTRENDEZVOUS}
    646746 */
     
    678778 * @param   hBp                 The breakpoint handle to arm.
    679779 * @param   pBp                 The internal breakpoint state pointer for the handle.
     780 *
     781 * @thread Any thread.
    680782 */
    681783static int dbgfR3BpArm(PUVM pUVM, DBGFBP hBp, PDBGFBPINT pBp)
     
    704806        }
    705807        case DBGFBPTYPE_INT3:
     808        {
     809            dbgfR3BpSetEnabled(pBp, true /*fEnabled*/);
     810
     811            /** @todo When we enable the first int3 breakpoint we should do this in an EMT rendezvous
     812             * as the VMX code intercepts #BP only when at least one int3 breakpoint is enabled.
     813             * A racing vCPU might trigger it and forward it to the guest causing panics/crashes/havoc. */
     814            /*
     815             * Save current byte and write the int3 instruction byte.
     816             */
     817            rc = PGMPhysSimpleReadGCPhys(pVM, &pBp->Pub.u.Int3.bOrg, pBp->Pub.u.Int3.PhysAddr, sizeof(pBp->Pub.u.Int3.bOrg));
     818            if (RT_SUCCESS(rc))
     819            {
     820                static const uint8_t s_bInt3 = 0xcc;
     821                rc = PGMPhysSimpleWriteGCPhys(pVM, pBp->Pub.u.Int3.PhysAddr, &s_bInt3, sizeof(s_bInt3));
     822                if (RT_SUCCESS(rc))
     823                {
     824                    ASMAtomicIncU32(&pVM->dbgf.s.cEnabledInt3Breakpoints);
     825                    Log(("DBGF: Set breakpoint at %RGv (Phys %RGp)\n", pBp->Pub.u.Int3.GCPtr, pBp->Pub.u.Int3.PhysAddr));
     826                }
     827            }
     828
     829            if (RT_FAILURE(rc))
     830                dbgfR3BpSetEnabled(pBp, false /*fEnabled*/);
     831
     832            break;
     833        }
    706834        case DBGFBPTYPE_PORT_IO:
    707835        case DBGFBPTYPE_MMIO:
     
    724852 * @param   hBp                 The breakpoint handle to disarm.
    725853 * @param   pBp                 The internal breakpoint state pointer for the handle.
     854 *
     855 * @thread Any thread.
    726856 */
    727857static int dbgfR3BpDisarm(PUVM pUVM, DBGFBP hBp, PDBGFBPINT pBp)
     
    750880        }
    751881        case DBGFBPTYPE_INT3:
     882        {
     883            dbgfR3BpSetEnabled(pBp, false /*fEnabled*/);
     884
     885            /*
     886             * Check that the current byte is the int3 instruction, and restore the original one.
     887             * We currently ignore invalid bytes.
     888             */
     889            uint8_t bCurrent = 0;
     890            rc = PGMPhysSimpleReadGCPhys(pVM, &bCurrent, pBp->Pub.u.Int3.PhysAddr, sizeof(bCurrent));
     891            if (   RT_SUCCESS(rc)
     892                && bCurrent == 0xcc)
     893            {
     894                rc = PGMPhysSimpleWriteGCPhys(pVM, pBp->Pub.u.Int3.PhysAddr, &pBp->Pub.u.Int3.bOrg, sizeof(pBp->Pub.u.Int3.bOrg));
     895                if (RT_SUCCESS(rc))
     896                {
     897                    ASMAtomicDecU32(&pVM->dbgf.s.cEnabledInt3Breakpoints);
     898                    Log(("DBGF: Removed breakpoint at %RGv (Phys %RGp)\n", pBp->Pub.u.Int3.GCPtr, pBp->Pub.u.Int3.PhysAddr));
     899                }
     900            }
     901
     902            if (RT_FAILURE(rc))
     903                dbgfR3BpSetEnabled(pBp, true /*fEnabled*/);
     904
     905            break;
     906        }
    752907        case DBGFBPTYPE_PORT_IO:
    753908        case DBGFBPTYPE_MMIO:
     
    8771032            pBp->Pub.u.Int3.GCPtr     = pAddress->FlatPtr;
    8781033
    879             /* Enable the breakpoint. */
    880             rc = dbgfR3BpArm(pUVM, hBp, pBp);
     1034            /* Add the breakpoint to the lookup tables. */
     1035            rc = dbgfR3BpInt3Add(pUVM, hBp, pBp);
    8811036            if (RT_SUCCESS(rc))
    8821037            {
    883                 *phBp = hBp;
    884                 return VINF_SUCCESS;
     1038                /* Enable the breakpoint. */
     1039                rc = dbgfR3BpArm(pUVM, hBp, pBp);
     1040                if (RT_SUCCESS(rc))
     1041                {
     1042                    *phBp = hBp;
     1043                    return VINF_SUCCESS;
     1044                }
     1045
     1046                int rc2 = dbgfR3BpInt3Remove(pUVM, hBp, pBp); AssertRC(rc2);
    8851047            }
    8861048        }
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