VirtualBox

Changeset 86701 in vbox for trunk


Ignore:
Timestamp:
Oct 25, 2020 6:20:09 PM (4 years ago)
Author:
vboxsync
Message:

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

Location:
trunk
Files:
6 edited

Legend:

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

    r86699 r86701  
    341341/** Internal processing error \#5 in the DBGF breakpoint manager code. */
    342342#define VERR_DBGF_BP_IPE_5                  (-1230)
     343/** 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)
    343347/** @} */
    344348
  • trunk/include/VBox/vmm/dbgf.h

    r86699 r86701  
    5151 */
    5252VMMRZ_INT_DECL(int) DBGFRZTrap01Handler(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCUINTREG uDr6, bool fAltStepping);
    53 VMMRZ_INT_DECL(int) DBGFRZTrap03Handler(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame);
     53VMMRZ_INT_DECL(int) DBGFRZTrap03Handler(PVMCC pVM, PVMCPUCC pVCpu, PCPUMCTXCORE pRegFrame);
    5454/** @} */
    5555#endif
  • trunk/include/VBox/vmm/vm.h

    r86118 r86701  
    13921392            /** The number of enabled hardware I/O breakpoints. */
    13931393            uint8_t                     cEnabledHwIoBreakpoints;
     1394#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    13941395            /** The number of enabled INT3 breakpoints. */
    13951396            uint8_t                     cEnabledInt3Breakpoints;
    13961397            uint8_t                     abPadding[1]; /**< Unused padding space up for grabs. */
     1398#else
     1399            uint16_t                    u16Pad; /**< Unused padding space up for grabs. */
     1400            /** The number of enabled INT3 breakpoints. */
     1401            volatile uint32_t           cEnabledInt3Breakpoints;
     1402#endif
    13971403        } const     ro;
    13981404#endif
  • 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        }
  • trunk/src/VBox/VMM/VMMRZ/DBGFRZ.cpp

    r86666 r86701  
    190190}
    191191
     192#ifdef VBOX_WITH_LOTS_OF_DBGF_BPS
     193# ifdef IN_RING0
     194/**
     195 * Returns the internal breakpoint state for the given handle.
     196 *
     197 * @returns Pointer to the internal breakpoint state or NULL if the handle is invalid.
     198 * @param   pVM                 The ring-0 VM structure pointer.
     199 * @param   hBp                 The breakpoint handle to resolve.
     200 * @param   ppBpR0              Where to store the pointer to the ring-0 only part of the breakpoint
     201 *                              on success, optional.
     202 */
     203DECLINLINE(PDBGFBPINT) dbgfR0BpGetByHnd(PVMCC pVM, DBGFBP hBp, PDBGFBPINTR0 *ppBpR0)
     204{
     205    uint32_t idChunk  = DBGF_BP_HND_GET_CHUNK_ID(hBp);
     206    uint32_t idxEntry = DBGF_BP_HND_GET_ENTRY(hBp);
     207
     208    AssertReturn(idChunk < DBGF_BP_CHUNK_COUNT, NULL);
     209    AssertReturn(idxEntry < DBGF_BP_COUNT_PER_CHUNK, NULL);
     210
     211    PDBGFBPCHUNKR0 pBpChunk = &pVM->dbgfr0.s.aBpChunks[idChunk];
     212    AssertPtrReturn(pBpChunk->paBpBaseSharedR0, NULL);
     213
     214    if (ppBpR0)
     215        *ppBpR0 = &pBpChunk->paBpBaseR0Only[idxEntry];
     216    return &pBpChunk->paBpBaseSharedR0[idxEntry];
     217}
     218# endif
     219
     220
     221/**
     222 * Executes the actions associated with the given breakpoint.
     223 *
     224 * @returns VBox status code.
     225 * @param   pVM         The cross context VM structure.
     226 * @param   pVCpu       The cross context virtual CPU structure.
     227 * @param   pRegFrame   Pointer to the register frame for the trap.
     228 * @param   hBp         The breakpoint handle which hit.
     229 * @param   pBp         The shared breakpoint state.
     230 * @param   pBpR0       The ring-0 only breakpoint state.
     231 * @param   fInHyper    Flag whether the breakpoint triggered in hypervisor code.
     232 */
     233DECLINLINE(int) dbgfRZBpHit(PVMCC pVM, PVMCPUCC pVCpu, PCPUMCTXCORE pRegFrame,
     234                            DBGFBP hBp, PDBGFBPINT pBp, PDBGFBPINTR0 pBpR0, bool fInHyper)
     235{
     236    uint64_t cHits = ASMAtomicIncU64(&pBp->Pub.cHits);
     237    pVCpu->dbgf.s.hBpActive = hBp;
     238
     239    /** @todo Owner handling. */
     240
     241    LogFlow(("dbgfRZBpHit: hit breakpoint %u at %04x:%RGv cHits=0x%RX64\n",
     242             hBp, pRegFrame->cs.Sel, pRegFrame->rip, cHits));
     243    return fInHyper
     244         ? VINF_EM_DBG_HYPER_BREAKPOINT
     245         : VINF_EM_DBG_BREAKPOINT;
     246}
     247#endif /* !VBOX_WITH_LOTS_OF_DBGF_BPS */
    192248
    193249/**
     
    202258 * @param   pRegFrame   Pointer to the register frame for the trap.
    203259 */
    204 VMMRZ_INT_DECL(int) DBGFRZTrap03Handler(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame)
     260VMMRZ_INT_DECL(int) DBGFRZTrap03Handler(PVMCC pVM, PVMCPUCC pVCpu, PCPUMCTXCORE pRegFrame)
    205261{
    206262#ifdef IN_RC
     
    247303        }
    248304    }
     305#else
     306# ifdef IN_RC
     307# error "You lucky person have the pleasure to implement the raw mode part for this!"
     308# endif
     309
     310    if (pVM->dbgfr0.s.CTX_SUFF(paBpLocL1))
     311    {
     312        RTGCPTR GCPtrBp;
     313        int rc = SELMValidateAndConvertCSAddr(pVCpu, pRegFrame->eflags, pRegFrame->ss.Sel, pRegFrame->cs.Sel, &pRegFrame->cs,
     314# ifdef IN_RC
     315                                              pRegFrame->eip - 1,
     316# else
     317                                              pRegFrame->rip /* no -1 in R0 */,
     318# endif
     319                                              &GCPtrBp);
     320        AssertRCReturn(rc, rc);
     321
     322        const uint16_t idxL1      = DBGF_BP_INT3_L1_IDX_EXTRACT_FROM_ADDR(GCPtrBp);
     323        const uint32_t u32L1Entry = ASMAtomicReadU32(&pVM->dbgfr0.s.CTX_SUFF(paBpLocL1)[idxL1]);
     324
     325        LogFlowFunc(("GCPtrBp=%RGv idxL1=%u u32L1Entry=%#x\n", GCPtrBp, idxL1, u32L1Entry));
     326        if (u32L1Entry != DBGF_BP_INT3_L1_ENTRY_TYPE_NULL)
     327        {
     328            uint8_t u8Type = DBGF_BP_INT3_L1_ENTRY_GET_TYPE(u32L1Entry);
     329            if (u8Type == DBGF_BP_INT3_L1_ENTRY_TYPE_BP_HND)
     330            {
     331                DBGFBP hBp = DBGF_BP_INT3_L1_ENTRY_GET_BP_HND(u32L1Entry);
     332
     333                /* Query the internal breakpoint state from the handle. */
     334                PDBGFBPINTR0 pBpR0 = NULL;
     335                PDBGFBPINT pBp = dbgfR0BpGetByHnd(pVM, hBp, &pBpR0);
     336                if (   pBp
     337                    && DBGF_BP_PUB_GET_TYPE(pBp->Pub.fFlagsAndType) == DBGFBPTYPE_INT3)
     338                {
     339                    if (pBp->Pub.u.Int3.GCPtr == (RTGCUINTPTR)GCPtrBp)
     340                        return dbgfRZBpHit(pVM, pVCpu, pRegFrame, hBp, pBp, pBpR0, fInHyper);
     341                    /* else Genuine guest trap. */
     342                }
     343                /** @todo else Guru meditation */
     344            }
     345            else if (u8Type == DBGF_BP_INT3_L1_ENTRY_TYPE_L2_IDX)
     346            {
     347                /** @todo Walk the L2 tree searching for the correct spot. */
     348            }
     349            /** @todo else Guru meditation */
     350        }
     351    }
    249352#endif /* !VBOX_WITH_LOTS_OF_DBGF_BPS */
    250353
  • trunk/src/VBox/VMM/include/DBGFInternal.h

    r86699 r86701  
    788788
    789789
     790/** @name DBGF int3 L1 lookup table entry types.
     791 * @{ */
     792/** No breakpoint handle assigned for this entry - special value which can be used
     793 * for comparison with the whole entry. */
     794#define DBGF_BP_INT3_L1_ENTRY_TYPE_NULL                 UINT32_C(0)
     795/** Direct breakpoint handle. */
     796#define DBGF_BP_INT3_L1_ENTRY_TYPE_BP_HND               1
     797/** Index into the L2 tree denoting the root of a search tree. */
     798#define DBGF_BP_INT3_L1_ENTRY_TYPE_L2_IDX               2
     799/** @} */
     800
     801
     802/** Returns the entry type for the given L1 lookup table entry. */
     803#define DBGF_BP_INT3_L1_ENTRY_GET_TYPE(a_u32Entry)      ((a_u32Entry) >> 28)
     804/** Returns a DBGF breakpoint handle from the given L1 lookup table entry,
     805 * type needs to be DBGF_BP_INT3_L1_ENTRY_TYPE_BP_HND. */
     806#define DBGF_BP_INT3_L1_ENTRY_GET_BP_HND(a_u32Entry)    ((DBGFBP)((a_u32Entry) & UINT32_C(0x0fffffff)))
     807/** Returns a L2 index from the given L1 lookup table entry,
     808 * type needs to be DBGF_BP_INT3_L1_ENTRY_TYPE_L2_IDX. */
     809#define DBGF_BP_INT3_L1_ENTRY_GET_L2_IDX(a_u32Entry)    ((a_u32Entry) & UINT32_C(0x0fffffff))
     810/** Creates a L1 entry value from the given type and data. */
     811#define DBGF_BP_INT3_L1_ENTRY_CREATE(a_Type, a_u32Data) ((((uint32_t)(a_Type)) << 28) | ((a_u32Data) & UINT32_C(0x0fffffff)))
     812/** Creates a breakpoint handle type L1 lookup entry. */
     813#define DBGF_BP_INT3_L1_ENTRY_CREATE_BP_HND(a_hBp)      DBGF_BP_INT3_L1_ENTRY_CREATE(DBGF_BP_INT3_L1_ENTRY_TYPE_BP_HND, a_hBp)
     814/** Creates a L2 index type L1 lookup entry. */
     815#define DBGF_BP_INT3_L1_ENTRY_CREATE_L2_IDX(a_idxL2)    DBGF_BP_INT3_L1_ENTRY_CREATE(DBGF_BP_INT3_L1_ENTRY_TYPE_L2_IDX, a_idxL2)
     816
     817/** Extracts the lowest bits from the given GC pointer used as an index into the L1 lookup table. */
     818#define DBGF_BP_INT3_L1_IDX_EXTRACT_FROM_ADDR(a_GCPtr)  ((uint16_t)((a_GCPtr) & UINT16_C(0xffff)))
     819
    790820/**
    791821 * The internal breakpoint state, shared part.
     
    920950    uint8_t                     cEnabledInt3Breakpoints;
    921951    uint8_t                     abPadding; /**< Unused padding space up for grabs. */
     952    uint32_t                    uPadding;
    922953#else
    923     uint16_t                    u16Pad;
     954    uint16_t                    u16Pad; /**< Unused padding space up for grabs. */
     955    /** The number of enabled INT3 breakpoints. */
     956    volatile uint32_t           cEnabledInt3Breakpoints;
    924957#endif
    925     uint32_t                    uPadding;
    926958
    927959    /** Debugger Attached flag.
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