VirtualBox

Changeset 86666 in vbox for trunk


Ignore:
Timestamp:
Oct 21, 2020 3:01:32 PM (4 years ago)
Author:
vboxsync
Message:

include/VBox,VMM,DBGF: Some boilerplate for the new breakpoint manager which is disabled by default (can be built with VBOX_WITH_LOTS_OF_DBGF_BPS), bugref:9837

Location:
trunk
Files:
9 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/Config.kmk

    r86643 r86666  
    446446 VBOX_WITH_RAM_IN_KERNEL := 1
    447447endif
     448# Enables the new breakpoint handling code, see @bugref{9837}
     449# VBOX_WITH_LOTS_OF_DBGF_BPS = 1
    448450## @}
    449451
  • trunk/include/VBox/err.h

    r86099 r86666  
    326326/** Internal processing error \#1 in the DBGF core code. */
    327327#define VERR_DBGF_IPE_1                     (-1223)
     328/** Returned by a breakpoint callback when guest execution should be suspended
     329 * and the VM should be dropped into the debugger. */
     330#define VINF_DBGF_BP_HALT                   (1224)
     331/** The breakpoint owner handle is still used by one or more breakpoints. */
     332#define VERR_DBGF_OWNER_BUSY                (-1225)
    328333/** @} */
    329334
  • trunk/include/VBox/types.h

    r84826 r86666  
    521521/** RC pointer to a DBGF tracer instance. */
    522522typedef RCPTRTYPE(struct DBGFTRACERINSRC *) PDBGFTRACERINSRC;
     523
     524#ifdef VBOX_WITH_LOTS_OF_DBGF_BPS
     525/** A cross context DBGF breakpoint owner handle. */
     526typedef uint32_t                DBGFBPOWNER;
     527/** Pointer to a cross context DBGF breakpoint owner handle. */
     528typedef DBGFBPOWNER             *PDBGFBPOWNER;
     529/** A NIL DBGF breakpoint owner handle. */
     530#define NIL_DBGFBPOWNER         ((uint32_t)UINT32_MAX)
     531
     532/** A cross context DBGF breakpoint handle. */
     533typedef uint32_t                DBGFBP;
     534/** Pointer to a cross context DBGF breakpoint handle. */
     535typedef DBGFBP                  *PDBGFBP;
     536/** A NIL DBGF breakpoint handle. */
     537#define NIL_DBGFBP              ((uint32_t)UINT32_MAX)
     538#endif
    523539/** @} */
    524540
  • trunk/include/VBox/vmm/dbgf.h

    r86361 r86666  
    529529        struct DBGFEVENTBP
    530530        {
     531#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    531532            /** The identifier of the breakpoint which was hit. */
    532533            RTUINT                  iBp;
     534#else
     535            /** The handle of the breakpoint which was hit. */
     536            DBGFBP                  hBp;
     537#endif
    533538        } Bp;
    534539
     
    744749typedef enum DBGFBPTYPE
    745750{
     751#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    746752    /** Free breakpoint entry. */
    747753    DBGFBPTYPE_FREE = 0,
     754#else
     755    /** Invalid breakpoint type. */
     756    DBGFBPTYPE_INVALID = 0,
     757#endif
    748758    /** Debug register. */
    749759    DBGFBPTYPE_REG,
    750760    /** INT 3 instruction. */
    751761    DBGFBPTYPE_INT3,
     762#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    752763    /** Recompiler. */
    753764    DBGFBPTYPE_REM,
     765#endif
    754766    /** Port I/O breakpoint. */
    755767    DBGFBPTYPE_PORT_IO,
     
    798810/** @} */
    799811
     812#ifdef VBOX_WITH_LOTS_OF_DBGF_BPS
     813/**
     814 * The visible breakpoint state (read-only).
     815 */
     816typedef struct DBGFBPPUB
     817{
     818    /** The number of breakpoint hits. */
     819    uint64_t        cHits;
     820    /** The hit number which starts to trigger the breakpoint. */
     821    uint64_t        iHitTrigger;
     822    /** The hit number which stops triggering the breakpoint (disables it).
     823     * Use ~(uint64_t)0 if it should never stop. */
     824    uint64_t        iHitDisable;
     825    /** The breakpoint owner handle (a nil owner defers the breakpoint to the
     826     * debugger). */
     827    DBGFBPOWNER     hOwner;
     828    /** The breakpoint type. */
     829    DBGFBPTYPE      enmType;
     830    /** The breakpoint handle this state belongs to. */
     831    DBGFBP          hBp;
     832    /** Breakpoint flags, see DBGF_BP_F_XXX. */
     833    uint32_t        fFlags;
     834
     835    /** Union of type specific data. */
     836    union
     837    {
     838        /** The flat GC address breakpoint address for REG and INT3 breakpoints. */
     839        RTGCUINTPTR         GCPtr;
     840
     841        /** Debug register data. */
     842        struct DBGFBPREG
     843        {
     844            /** The flat GC address of the breakpoint. */
     845            RTGCUINTPTR     GCPtr;
     846            /** The debug register number. */
     847            uint8_t         iReg;
     848            /** The access type (one of the X86_DR7_RW_* value). */
     849            uint8_t         fType;
     850            /** The access size. */
     851            uint8_t         cb;
     852        } Reg;
     853
     854        /** INT3 breakpoint data. */
     855        struct DBGFBPINT3
     856        {
     857            /** The flat GC address of the breakpoint. */
     858            RTGCUINTPTR     GCPtr;
     859            /** The physical address of the breakpoint. */
     860            RTGCPHYS        PhysAddr;
     861            /** The byte value we replaced by the INT 3 instruction. */
     862            uint8_t         bOrg;
     863        } Int3;
     864
     865        /** I/O port breakpoint data.   */
     866        struct DBGFBPPORTIO
     867        {
     868            /** The first port. */
     869            RTIOPORT        uPort;
     870            /** The number of ports. */
     871            RTIOPORT        cPorts;
     872            /** Valid DBGFBPIOACCESS_XXX selection, max DWORD size. */
     873            uint32_t        fAccess;
     874        } PortIo;
     875
     876        /** Memory mapped I/O breakpoint data. */
     877        struct DBGFBPMMIO
     878        {
     879            /** The first MMIO address. */
     880            RTGCPHYS        PhysAddr;
     881            /** The size of the MMIO range in bytes. */
     882            uint32_t        cb;
     883            /** Valid DBGFBPIOACCESS_XXX selection, max QWORD size. */
     884            uint32_t        fAccess;
     885        } Mmio;
     886
     887        /** Padding to the anticipated size. */
     888        uint64_t    u64Padding[3];
     889    } u;
     890} DBGFBPPUB;
     891AssertCompileSize(DBGFBPPUB, 64);
     892AssertCompileMembersAtSameOffset(DBGFBPPUB, u.GCPtr, DBGFBPPUB, u.Reg.GCPtr);
     893AssertCompileMembersAtSameOffset(DBGFBPPUB, u.GCPtr, DBGFBPPUB, u.Int3.GCPtr);
     894
     895/** Pointer to the visible breakpoint state. */
     896typedef DBGFBPPUB *PDBGFBPPUB;
     897/** Pointer to a const visible breakpoint state. */
     898typedef const DBGFBPPUB *PCDBGFBPPUB;
     899
     900/** @name Possible DBGFBPPUB::fFlags flags.
     901 * @{ */
     902/** Flag whether the breakpoint is enabled currently. */
     903#define DBGF_BP_F_ENABLED                   RT_BIT_32(0)
     904/** @} */
     905
     906/**
     907 * Breakpoint hit handler.
     908 *
     909 * @returns Strict VBox status code.
     910 * @retval  VINF_SUCCESS if the breakpoint was handled and guest execution can resume.
     911 * @retval  VINF_DBGF_BP_HALT if guest execution should be stopped and the debugger should be invoked.
     912 *
     913 * @param   pVM         The cross-context VM structure pointer.
     914 * @param   idCpu       ID of the vCPU triggering the breakpoint.
     915 * @param   pvUser      User argument of the set breakpoint.
     916 * @param   pBpPub      Pointer to the readonly public state of the breakpoint.
     917 *
     918 * @remarks The handler is called on the EMT of vCPU triggering the breakpoint and no locks are held.
     919 * @remarks Any status code returned other than the ones mentioned will send the VM straight into a
     920 *          guru meditation.
     921 */
     922typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNDBGFBPHIT,(PVM pVM, VMCPUID idCpu, void *pvUserBp, PCDBGFBPPUB pBpPub));
     923/** Pointer to a FNDBGFBPHIT(). */
     924typedef FNDBGFBPHIT *PFNDBGFBPHIT;
     925
     926
     927#ifdef IN_RING3
     928/** @defgroup grp_dbgf_bp_r3    The DBGF Breakpoint Host Context Ring-3 API
     929 * @{ */
     930VMMR3DECL(int) DBGFR3BpOwnerCreate(PUVM pUVM, PFNDBGFBPHIT pfnBpHit, PDBGFBPOWNER phBpOwner);
     931VMMR3DECL(int) DBGFR3BpOwnerDestroy(PUVM pUVM, DBGFBPOWNER hBpOwner);
     932
     933VMMR3DECL(int) DBGFR3BpSetInt3(PUVM pUVM, VMCPUID idSrcCpu, PCDBGFADDRESS pAddress,
     934                               uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp);
     935VMMR3DECL(int) DBGFR3BpSetInt3Ex(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser,
     936                                 VMCPUID idSrcCpu, PCDBGFADDRESS pAddress,
     937                                 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp);
     938VMMR3DECL(int) DBGFR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger,
     939                              uint64_t iHitDisable, uint8_t fType, uint8_t cb, PDBGFBP phBp);
     940VMMR3DECL(int) DBGFR3BpSetRegEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser,
     941                                PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable,
     942                                uint8_t fType, uint8_t cb, PDBGFBP phBp);
     943VMMR3DECL(int) DBGFR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger,
     944                              uint64_t iHitDisable, PDBGFBP phBp);
     945VMMR3DECL(int) DBGFR3BpSetPortIo(PUVM pUVM, RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess,
     946                                 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp);
     947VMMR3DECL(int) DBGFR3BpSetPortIoEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser,
     948                                   RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess,
     949                                   uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp);
     950VMMR3DECL(int) DBGFR3BpSetMmio(PUVM pUVM, RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess,
     951                               uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp);
     952VMMR3DECL(int) DBGFR3BpSetMmioEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser,
     953                                 RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess,
     954                                 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp);
     955VMMR3DECL(int) DBGFR3BpClear(PUVM pUVM, DBGFBP hBp);
     956VMMR3DECL(int) DBGFR3BpEnable(PUVM pUVM, DBGFBP hBp);
     957VMMR3DECL(int) DBGFR3BpDisable(PUVM pUVM, DBGFBP hBp);
     958
     959/**
     960 * Breakpoint enumeration callback function.
     961 *
     962 * @returns VBox status code.
     963 *          The enumeration stops on failure status and VINF_CALLBACK_RETURN.
     964 * @param   pUVM        The user mode VM handle.
     965 * @param   pvUser      The user argument.
     966 * @param   pBp         Pointer to the breakpoint information. (readonly)
     967 */
     968typedef DECLCALLBACKTYPE(int, FNDBGFBPENUM,(PUVM pUVM, PCDBGFBPPUB pBpPub));
     969/** Pointer to a breakpoint enumeration callback function. */
     970typedef FNDBGFBPENUM *PFNDBGFBPENUM;
     971
     972VMMR3DECL(int) DBGFR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser);
     973/** @} */
     974#endif /* !IN_RING3 */
     975
     976
     977#if defined(IN_RING0) || defined(DOXYGEN_RUNNING)
     978/** @defgroup grp_dbgf_bp_r0    The DBGF Breakpoint Host Context Ring-0 API
     979 * @{ */
     980VMMR0_INT_DECL(void) DBGFR0InitPerVMData(PGVM pGVM);
     981VMMR0_INT_DECL(void) DBGFR0CleanupVM(PGVM pGVM);
     982
     983VMMR0_INT_DECL(int)  DBGFR0BpOwnerSetUpContext(PGVM pGVM, DBGFBPOWNER hBpOwner, PFNDBGFBPHIT pfnBpHit);
     984VMMR0_INT_DECL(int)  DBGFR0BpOwnerDestroyContext(PGVM pGVM, DBGFBPOWNER hBpOwner);
     985
     986VMMR0_INT_DECL(int)  DBGFR0BpSetUpContext(PGVM pGVM, DBGFBP hBp, void *pvUser);
     987VMMR0_INT_DECL(int)  DBGFR0BpDestroyContext(PGVM pGVM, DBGFBP hBp);
     988/** @} */
     989#endif /* IN_RING0 || DOXYGEN_RUNNING */
     990
     991#else /* !VBOX_WITH_LOTS_OF_DBGF_BPS */
    800992/**
    801993 * A Breakpoint.
     
    8901082typedef const DBGFBP *PCDBGFBP;
    8911083
    892 #ifdef IN_RING3 /* The breakpoint management API is only available in ring-3. */
     1084# ifdef IN_RING3 /* The breakpoint management API is only available in ring-3. */
    8931085VMMR3DECL(int)  DBGFR3BpSetInt3(PUVM pUVM, VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp);
    8941086VMMR3DECL(int)  DBGFR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable,
     
    9171109
    9181110VMMR3DECL(int)              DBGFR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser);
    919 #endif /* IN_RING3 */
     1111# endif /* IN_RING3 */
     1112#endif /* !VBOX_WITH_LOTS_OF_DBGF_BPS */
    9201113
    9211114VMM_INT_DECL(RTGCUINTREG)   DBGFBpGetDR7(PVM pVM);
  • trunk/src/VBox/VMM/Makefile.kmk

    r86121 r86666  
    7171ifdef VBOX_WITH_DBGF_TRACING
    7272VBoxVMM_DEFS    += VBOX_WITH_DBGF_TRACING
     73endif
     74ifdef VBOX_WITH_LOTS_OF_DBGF_BPS
     75VBoxVMM_DEFS    += VBOX_WITH_LOTS_OF_DBGF_BPS
    7376endif
    7477ifdef VBOX_WITH_VMM_R0_SWITCH_STACK
     
    9699        VMMR3/DBGFAddr.cpp \
    97100        VMMR3/DBGFAddrSpace.cpp \
    98         VMMR3/DBGFBp.cpp \
     101        $(if-expr defined(VBOX_WITH_LOTS_OF_DBGF_BPS), VMMR3/DBGFR3Bp.cpp, VMMR3/DBGFBp.cpp) \
    99102        VMMR3/DBGFR3BugCheck.cpp \
    100103        VMMR3/DBGFCoreWrite.cpp \
  • trunk/src/VBox/VMM/VMMAll/DBGFAll.cpp

    r82968 r86666  
    5050{
    5151    RTGCUINTREG uDr7 = X86_DR7_GD | X86_DR7_GE | X86_DR7_LE | X86_DR7_RA1_MASK;
     52#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    5253    PDBGFBP     pBp = &pVM->dbgf.s.aHwBreakpoints[0];
    5354    unsigned    cLeft = RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
     
    6869        pBp++;
    6970    }
     71#else
     72    for (uint32_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
     73    {
     74        PCDBGFBPHW  pBp = &pVM->dbgf.s.aHwBreakpoints[i];
     75
     76        if (    pBp->hBp != NIL_DBGFBP
     77            &&  pBp->fEnabled)
     78        {
     79            static const uint8_t s_au8Sizes[8] =
     80            {
     81                X86_DR7_LEN_BYTE, X86_DR7_LEN_BYTE, X86_DR7_LEN_WORD, X86_DR7_LEN_BYTE,
     82                X86_DR7_LEN_DWORD,X86_DR7_LEN_BYTE, X86_DR7_LEN_BYTE, X86_DR7_LEN_QWORD
     83            };
     84            uDr7 |= X86_DR7_G(i)
     85                 |  X86_DR7_RW(i, pBp->fType)
     86                 |  X86_DR7_LEN(i, s_au8Sizes[pBp->cb]);
     87        }
     88        pBp++;
     89    }
     90#endif
    7091    return uDr7;
    7192}
     
    80101VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR0(PVM pVM)
    81102{
     103#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    82104    PCDBGFBP    pBp = &pVM->dbgf.s.aHwBreakpoints[0];
    83105    Assert(pBp->u.Reg.iReg == 0);
    84106    return pBp->u.Reg.GCPtr;
     107#else
     108    PCDBGFBPHW pBp = &pVM->dbgf.s.aHwBreakpoints[0];
     109    return pBp->GCPtr;
     110#endif
    85111}
    86112
     
    94120VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR1(PVM pVM)
    95121{
     122#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    96123    PCDBGFBP    pBp = &pVM->dbgf.s.aHwBreakpoints[1];
    97124    Assert(pBp->u.Reg.iReg == 1);
    98125    return pBp->u.Reg.GCPtr;
     126#else
     127    PCDBGFBPHW pBp = &pVM->dbgf.s.aHwBreakpoints[1];
     128    return pBp->GCPtr;
     129#endif
    99130}
    100131
     
    108139VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR2(PVM pVM)
    109140{
     141#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    110142    PCDBGFBP    pBp = &pVM->dbgf.s.aHwBreakpoints[2];
    111143    Assert(pBp->u.Reg.iReg == 2);
    112144    return pBp->u.Reg.GCPtr;
     145#else
     146    PCDBGFBPHW pBp = &pVM->dbgf.s.aHwBreakpoints[2];
     147    return pBp->GCPtr;
     148#endif
    113149}
    114150
     
    122158VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR3(PVM pVM)
    123159{
     160#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    124161    PCDBGFBP    pBp = &pVM->dbgf.s.aHwBreakpoints[3];
    125162    Assert(pBp->u.Reg.iReg == 3);
    126163    return pBp->u.Reg.GCPtr;
     164#else
     165    PCDBGFBPHW pBp = &pVM->dbgf.s.aHwBreakpoints[3];
     166    return pBp->GCPtr;
     167#endif
    127168}
    128169
     
    163204VMM_INT_DECL(bool) DBGFBpIsInt3Armed(PVM pVM)
    164205{
     206#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    165207    return pVM->dbgf.s.cEnabledInt3Breakpoints > 0;
     208#else
     209    RT_NOREF(pVM);
     210    return false; /** @todo */
     211#endif
    166212}
    167213
     
    186232    uint32_t const uIoPortFirst = uIoPort;
    187233    uint32_t const uIoPortLast  = uIoPortFirst + cbValue - 1;
    188 
    189 
     234 
    190235    /*
    191236     * Check hyper breakpoints first as the VMM debugger has priority over
     
    196241        for (unsigned iBp = 0; iBp < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); iBp++)
    197242        {
     243#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    198244            if (   pVM->dbgf.s.aHwBreakpoints[iBp].u.Reg.fType == X86_DR7_RW_IO
    199245                && pVM->dbgf.s.aHwBreakpoints[iBp].fEnabled
     
    214260                }
    215261            }
     262#else
     263            PCDBGFBPHW  pBp = &pVM->dbgf.s.aHwBreakpoints[iBp];
     264
     265            if (   pBp->fType == X86_DR7_RW_IO
     266                && pBp->hBp == NIL_DBGFBP
     267                && pBp->fEnabled)
     268            {
     269                uint8_t  cbReg      = pBp->cb; Assert(RT_IS_POWER_OF_TWO(cbReg));
     270                uint64_t uDrXFirst  = pBp->GCPtr & ~(uint64_t)(cbReg - 1);
     271                uint64_t uDrXLast   = uDrXFirst + cbReg - 1;
     272                if (uDrXFirst <= uIoPortLast && uDrXLast >= uIoPortFirst)
     273                {
     274                    /* (See also DBGFRZTrap01Handler.) */
     275                    pVCpu->dbgf.s.hBpActive = pBp->hBp;
     276                    pVCpu->dbgf.s.fSingleSteppingRaw = false;
     277
     278                    LogFlow(("DBGFBpCheckIo: hit hw breakpoint %d at %04x:%RGv (iop %#x)\n",
     279                             iBp, pCtx->cs.Sel, pCtx->rip, uIoPort));
     280                    return VINF_EM_DBG_BREAKPOINT;
     281                }
     282            }
     283#endif
    216284        }
    217285    }
     
    254322                    pCtx->dr[7] &= ~X86_DR7_GD;
    255323                    LogFlow(("DBGFBpCheckIo: hit hw breakpoint %d at %04x:%RGv (iop %#x)\n",
    256                              pVM->dbgf.s.aHwBreakpoints[iBp].iBp, pCtx->cs.Sel, pCtx->rip, uIoPort));
     324                             iBp, pCtx->cs.Sel, pCtx->rip, uIoPort));
    257325                    return VINF_EM_RAW_GUEST_TRAP;
    258326                }
  • trunk/src/VBox/VMM/VMMR3/DBGF.cpp

    r86392 r86666  
    174174                            dbgfR3OSTermPart2(pUVM);
    175175                        }
     176#ifdef VBOX_WITH_LOTS_OF_DBGF_BPS
     177                        dbgfR3BpTerm(pVM);
     178#endif
    176179                    }
    177180                    dbgfR3AsTerm(pUVM);
     
    203206    dbgfR3PlugInTerm(pUVM);
    204207    dbgfR3OSTermPart2(pUVM);
     208#ifdef VBOX_WITH_LOTS_OF_DBGF_BPS
     209    dbgfR3BpTerm(pVM);
     210#endif
    205211    dbgfR3AsTerm(pUVM);
    206212    dbgfR3RegTerm(pUVM);
     
    775781     */
    776782    DBGFEVENT DbgEvent;
     783#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    777784    RTUINT iBp = DbgEvent.u.Bp.iBp = pVCpu->dbgf.s.iActiveBp;
    778785    pVCpu->dbgf.s.iActiveBp = ~0U;
     
    782789        return dbgfR3SendEventWaitEx(pVM, pVCpu, enmEvent, DBGFEVENTCTX_RAW, &DbgEvent.u, sizeof(DbgEvent.u.Bp));
    783790    }
    784 
     791#else
     792    DbgEvent.u.Bp.hBp = pVCpu->dbgf.s.hBpActive;
     793    pVCpu->dbgf.s.hBpActive = NIL_DBGFBP;
     794    if (DbgEvent.u.Bp.hBp != NIL_DBGFBP)
     795    {
     796        DbgEvent.enmCtx = DBGFEVENTCTX_RAW;
     797        return dbgfR3SendEventWaitEx(pVM, pVCpu, enmEvent, DBGFEVENTCTX_RAW, &DbgEvent.u, sizeof(DbgEvent.u.Bp));
     798    }
     799#endif
     800
     801#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    785802    AssertFailed(); /** @todo this should be obsolete now...   */
    786803
     
    801818    AssertMsg(DbgEvent.u.Bp.iBp != ~0U, ("eip=%08x\n", eip));
    802819    return dbgfR3SendEventWaitEx(pVM, pVCpu, enmEvent, DBGFEVENTCTX_REM, &DbgEvent.u, sizeof(DbgEvent.u.Bp));
     820#else
     821    return VERR_DBGF_IPE_1;
     822#endif
    803823}
    804824
  • trunk/src/VBox/VMM/VMMR3/DBGFR3Bp.cpp

    r86660 r86666  
    1414 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
    1515 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
     16 */
     17
     18
     19/** @page pg_dbgf_bp            DBGF - The Debugger Facility, Breakpoint Management
     20 *
     21 * The debugger facilities breakpoint managers purpose is to efficiently manage
     22 * large amounts of breakpoints for various use cases like dtrace like operations
     23 * or execution flow tracing for instance. Especially execution flow tracing can
     24 * require thousands of breakpoints which need to be managed efficiently to not slow
     25 * down guest operation too much. Before the rewrite starting end of 2020, DBGF could
     26 * only handle 32 breakpoints (+ 4 hardware assisted breakpoints). The new
     27 * manager is supposed to be able to handle up to one million breakpoints.
     28 *
     29 * @see grp_dbgf
     30 *
     31 *
     32 * @section sec_dbgf_bp_owner   Breakpoint owners
     33 *
     34 * A single breakpoint owner has a mandatory ring-3 callback and an optional ring-0
     35 * callback assigned which is called whenever a breakpoint with the owner assigned is hit.
     36 * The common part of the owner is managed by a single table mapped into both ring-0
     37 * and ring-3 and the handle being the index into the table. This allows resolving
     38 * the handle to the internal structure efficiently. Searching for a free entry is
     39 * done using a bitmap indicating free and occupied entries. For the optional
     40 * ring-0 owner part there is a separate ring-0 only table for security reasons.
     41 *
     42 * The callback of the owner can be used to gather and log guest state information
     43 * and decide whether to continue guest execution or stop and drop into the debugger.
     44 * Breakpoints which don't have an owner assigned will always drop the VM right into
     45 * the debugger.
     46 *
     47 *
     48 * @section sec_dbgf_bp_bps     Breakpoints
     49 *
     50 * Breakpoints are referenced by an opaque handle which acts as an index into a global table
     51 * mapped into ring-3 and ring-0. Each entry contains the necessary state to manage the breakpoint
     52 * like trigger conditions, type, owner, etc. If an owner is given an optional opaque user argument
     53 * can be supplied which is passed in the respective owner callback. For owners with ring-0 callbacks
     54 * a dedicated ring-0 table is held saving possible ring-0 user arguments.
     55 *
     56 * To keep memory consumption under control and still support large amounts of
     57 * breakpoints the table is split into fixed sized chunks and the chunk index and index
     58 * into the chunk can be derived from the handle with only a few logical operations.
     59 *
     60 *
     61 * @section sec_dbgf_bp_resolv  Resolving breakpoint addresses
     62 *
     63 * Whenever a \#BP(0) event is triggered DBGF needs to decide whether the event originated
     64 * from within the guest or whether a DBGF breakpoint caused it. This has to happen as fast
     65 * as possible. The following scheme is employed to achieve this:
     66 *
     67 * @verbatim
     68 *                       7   6   5   4   3   2   1   0
     69 *                     +---+---+---+---+---+---+---+---+
     70 *                     |   |   |   |   |   |   |   |   | BP address
     71 *                     +---+---+---+---+---+---+---+---+
     72 *                      \_____________________/ \_____/
     73 *                                 |               |
     74 *                                 |               +---------------+
     75 *                                 |                               |
     76 *    BP table                     |                               v
     77 * +------------+                  |                         +-----------+
     78 * |   hBp 0    |                  |                    X <- | 0 | xxxxx |
     79 * |   hBp 1    | <----------------+------------------------ | 1 | hBp 1 |
     80 * |            |                  |                    +--- | 2 | idxL2 |
     81 * |   hBp <m>  | <---+            v                    |    |...|  ...  |
     82 * |            |     |      +-----------+              |    |...|  ...  |
     83 * |            |     |      |           |              |    |...|  ...  |
     84 * |   hBp <n>  | <-+ +----- | +> leaf   |              |    |     .     |
     85 * |            |   |        | |         |              |    |     .     |
     86 * |            |   |        | + root +  | <------------+    |     .     |
     87 * |            |   |        |        |  |                   +-----------+
     88 * |            |   +------- |   leaf<+  |                     L1: 65536
     89 * |     .      |            |     .     |
     90 * |     .      |            |     .     |
     91 * |     .      |            |     .     |
     92 * +------------+            +-----------+
     93 *                            L2 idx AVL
     94 * @endverbatim
     95 *
     96 *     -# Take the lowest 16 bits of the breakpoint address and use it as an direct index
     97 *        into the L1 table. The L1 table is contiguous and consists of 4 byte entries
     98 *        resulting in 256KiB of memory used. The topmost 4 bits indicate how to proceed
     99 *        and the meaning of the remaining 28bits depends on the topmost 4 bits:
     100 *            - A 0 type entry means no breakpoint is registered with the matching lowest 16bits,
     101 *              so forward the event to the guest.
     102 *            - A 1 in the topmost 4 bits means that the remaining 28bits directly denote a breakpoint
     103 *              handle which can be resolved by extracting the chunk index and index into the chunk
     104 *              of the global breakpoint table. If the address matches the breakpoint is processed
     105 *              according to the configuration. Otherwise the breakpoint is again forwarded to the guest.
     106 *            - A 2 in the topmost 4 bits means that there are multiple breakpoints registered
     107 *              matching the lowest 16bits and the search must continue in the L2 table with the
     108 *              remaining 28bits acting as an index into the L2 table indicating the search root.
     109 *     -# The L2 table consists of multiple index based AVL trees, there is one for each reference
     110 *        from the L1 table. The key for the table are the upper 6 bytes of the breakpoint address
     111 *        used for searching. This tree is traversed until either a matching address is found and
     112 *        the breakpoint is being processed or again forwardedto the guest if it isn't successful.
     113 *        Each entry in the L2 table is 16 bytes big and densly packed to avoid excessive memory usage.
     114 *
     115 *
     116 * @section sec_dbgf_bp_note    Random thoughts and notes for the implementation
     117 *
     118 * - The assumption for this approach is that the lowest 16bits of the breakpoint address are
     119 *   hopefully the ones being the most varying ones across breakpoints so the traversal
     120 *   can skip the L2 table in most of the cases. Even if the L2 table must be taken the
     121 *   individual trees should be quite shallow resulting in low overhead when walking it
     122 *   (though only real world testing can assert this assumption).
     123 * - Index based tables and trees are used instead of pointers because the tables
     124 *   are always mapped into ring-0 and ring-3 with different base addresses.
     125 * - Efficent breakpoint allocation is done by having a global bitmap indicating free
     126 *   and occupied breakpoint entries. Same applies for the L2 AVL table.
     127 * - Special care must be taken when modifying the L1 and L2 tables as other EMTs
     128 *   might still access it (want to try a lockless approach first using
     129 *   atomic updates, have to resort to locking if that turns out to be too difficult).
     130 * - Each BP entry is supposed to be 64 byte big and each chunk should contain 65536
     131 *   breakpoints which results in 4MiB for each chunk plus the allocation bitmap.
     132 * - ring-0 has to take special care when traversing the L2 AVL tree to not run into cycles
     133 *   and do strict bounds checking before accessing anything. The L1 and L2 table
     134 *   are written to from ring-3 only. Same goes for the breakpoint table with the
     135 *   exception being the opaque user argument for ring-0 which is stored in ring-0 only
     136 *   memory.
    16137 */
    17138
     
    40161*   Structures and Typedefs                                                                                                      *
    41162*********************************************************************************************************************************/
    42 /**
    43  * DBGF INT3-breakpoint set callback arguments.
    44  */
    45 typedef struct DBGFBPINT3ARGS
    46 {
    47     /** The source virtual CPU ID (used for breakpoint address resolution). */
    48     VMCPUID         idSrcCpu;
    49     /** The breakpoint address. */
    50     PCDBGFADDRESS   pAddress;
    51     /** The hit count at which the breakpoint starts triggering. */
    52     uint64_t        iHitTrigger;
    53     /** The hit count at which disables the breakpoint. */
    54     uint64_t        iHitDisable;
    55     /** Where to store the breakpoint Id (optional). */
    56     uint32_t       *piBp;
    57 } DBGFBPINT3ARGS;
    58 /** Pointer to a DBGF INT3 breakpoint set callback argument. */
    59 typedef DBGFBPINT3ARGS *PDBGFBPINT3ARGS;
    60163
    61164
     
    64167*********************************************************************************************************************************/
    65168RT_C_DECLS_BEGIN
    66 static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp);
    67 static int dbgfR3BpInt3Arm(PVM pVM, PDBGFBP pBp);
    68169RT_C_DECLS_END
    69170
     
    71172
    72173/**
    73  * Initialize the breakpoint stuff.
    74  *
    75  * @returns VINF_SUCCESS
    76  * @param   pVM     The cross context VM structure.
    77  */
    78 int dbgfR3BpInit(PVM pVM)
     174 * Initialize the breakpoint mangement.
     175 *
     176 * @returns VBox status code.
     177 * @param   pVM                 The cross context VM structure.
     178 */
     179DECLHIDDEN(int) dbgfR3BpInit(PVM pVM)
     180{
     181    RT_NOREF(pVM);
     182    return VINF_SUCCESS;
     183}
     184
     185
     186/**
     187 * Terminates the breakpoint mangement.
     188 *
     189 * @returns VBox status code.
     190 * @param   pVM                 The cross context VM structure.
     191 */
     192DECLHIDDEN(int) dbgfR3BpTerm(PVM pVM)
     193{
     194    RT_NOREF(pVM);
     195    return VINF_SUCCESS;
     196}
     197
     198
     199/**
     200 * Creates a new breakpoint owner returning a handle which can be used when setting breakpoints.
     201 *
     202 * @returns VBox status code.
     203 * @param   pUVM                The user mode VM handle.
     204 * @param   pfnBpHit            The R3 callback which is called when a breakpoint with the owner handle is hit.
     205 * @param   phBpOwner           Where to store the owner handle on success.
     206 */
     207VMMR3DECL(int) DBGFR3BpOwnerCreate(PUVM pUVM, PFNDBGFBPHIT pfnBpHit, PDBGFBPOWNER phBpOwner)
    79208{
    80209    /*
    81      * Init structures.
     210     * Validate the input.
    82211     */
    83     unsigned i;
    84     for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
    85     {
    86         pVM->dbgf.s.aHwBreakpoints[i].iBp = i;
    87         pVM->dbgf.s.aHwBreakpoints[i].enmType = DBGFBPTYPE_FREE;
    88         pVM->dbgf.s.aHwBreakpoints[i].u.Reg.iReg = i;
    89     }
    90 
    91     for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
    92     {
    93         pVM->dbgf.s.aBreakpoints[i].iBp = i + RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
    94         pVM->dbgf.s.aBreakpoints[i].enmType = DBGFBPTYPE_FREE;
    95     }
    96 
    97     for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
    98     {
    99         PVMCPU pVCpu = pVM->apCpusR3[idCpu];
    100         pVCpu->dbgf.s.iActiveBp = ~0U;
    101     }
    102 
     212    UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
     213    AssertPtrReturn(pfnBpHit, VERR_INVALID_PARAMETER);
     214    AssertPtrReturn(phBpOwner, VERR_INVALID_POINTER);
     215
     216    return VERR_NOT_IMPLEMENTED;
     217}
     218
     219
     220/**
     221 * Destroys the owner identified by the given handle.
     222 *
     223 * @returns VBox status code.
     224 * @retval  VERR_DBGF_OWNER_BUSY if there are still breakpoints set with the given owner handle.
     225 * @param   pUVM                The user mode VM handle.
     226 * @param   hBpOwner            The breakpoint owner handle to destroy.
     227 */
     228VMMR3DECL(int) DBGFR3BpOwnerDestroy(PUVM pUVM, DBGFBPOWNER hBpOwner)
     229{
    103230    /*
    104      * Register saved state.
     231     * Validate the input.
    105232     */
    106     /** @todo */
    107 
    108     return VINF_SUCCESS;
    109 }
    110 
    111 
    112 
    113 /**
    114  * Allocate a breakpoint.
    115  *
    116  * @returns Pointer to the allocated breakpoint.
    117  * @returns NULL if we're out of breakpoints.
    118  * @param   pVM     The cross context VM structure.
    119  * @param   enmType The type to allocate.
    120  */
    121 static PDBGFBP dbgfR3BpAlloc(PVM pVM, DBGFBPTYPE enmType)
    122 {
    123     /*
    124      * Determine which array to search and where in the array to start
    125      * searching (latter for grouping similar BPs, reducing runtime overhead).
    126      */
    127     unsigned    iStart;
    128     unsigned    cBps;
    129     PDBGFBP     paBps;
    130     switch (enmType)
    131     {
    132         case DBGFBPTYPE_REG:
    133             cBps = RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
    134             paBps = &pVM->dbgf.s.aHwBreakpoints[0];
    135             iStart = 0;
    136             break;
    137 
    138         case DBGFBPTYPE_INT3:
    139         case DBGFBPTYPE_REM:
    140         case DBGFBPTYPE_PORT_IO:
    141         case DBGFBPTYPE_MMIO:
    142             cBps = RT_ELEMENTS(pVM->dbgf.s.aBreakpoints);
    143             paBps = &pVM->dbgf.s.aBreakpoints[0];
    144             if (enmType == DBGFBPTYPE_PORT_IO)
    145                 iStart = cBps / 4 * 2;
    146             else if (enmType == DBGFBPTYPE_MMIO)
    147                 iStart = cBps / 4 * 1;
    148             else if (enmType == DBGFBPTYPE_REM)
    149                 iStart = cBps / 4 * 3;
    150             else
    151                 iStart = 0;
    152             break;
    153 
    154         default:
    155             AssertMsgFailed(("enmType=%d\n", enmType));
    156             return NULL;
    157     }
    158 
    159     /*
    160      * Search for a free breakpoint entry.
    161      */
    162     unsigned iBp;
    163     for (iBp = iStart; iBp < cBps; iBp++)
    164         if (paBps[iBp].enmType == DBGFBPTYPE_FREE)
    165             break;
    166     if (iBp >= cBps && iStart != 0)
    167         for (iBp = 0; iBp < cBps; iBp++)
    168             if (paBps[iBp].enmType == DBGFBPTYPE_FREE)
    169                 break;
    170     if (iBp < cBps)
    171     {
    172         /*
    173          * Return what we found.
    174          */
    175         paBps[iBp].fEnabled = false;
    176         paBps[iBp].cHits    = 0;
    177         paBps[iBp].enmType  = enmType;
    178         return &paBps[iBp];
    179     }
    180 
    181     LogFlow(("dbgfR3BpAlloc: returns NULL - we're out of breakpoint slots! cBps=%u\n", cBps));
    182     return NULL;
    183 }
    184 
    185 
    186 /**
    187  * Updates the search optimization structure for enabled breakpoints of the
    188  * specified type.
    189  *
    190  * @returns VINF_SUCCESS.
    191  * @param   pVM         The cross context VM structure.
    192  * @param   enmType     The breakpoint type.
    193  * @param   pOpt        The breakpoint optimization structure to update.
    194  */
    195 static int dbgfR3BpUpdateSearchOptimizations(PVM pVM, DBGFBPTYPE enmType, PDBGFBPSEARCHOPT pOpt)
    196 {
    197     DBGFBPSEARCHOPT Opt  = { UINT32_MAX, 0 };
    198 
    199     for (uint32_t iBp = 0; iBp < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); iBp++)
    200         if (   pVM->dbgf.s.aBreakpoints[iBp].enmType == enmType
    201             && pVM->dbgf.s.aBreakpoints[iBp].fEnabled)
    202         {
    203             if (Opt.iStartSearch > iBp)
    204                 Opt.iStartSearch = iBp;
    205             Opt.cToSearch = iBp - Opt.iStartSearch + 1;
    206         }
    207 
    208     *pOpt = Opt;
    209     return VINF_SUCCESS;
    210 }
    211 
    212 
    213 /**
    214  * Get a breakpoint give by breakpoint id.
    215  *
    216  * @returns Pointer to the allocated breakpoint.
    217  * @returns NULL if the breakpoint is invalid.
    218  * @param   pVM     The cross context VM structure.
    219  * @param   iBp     The breakpoint id.
    220  */
    221 static PDBGFBP dbgfR3BpGet(PVM pVM, uint32_t iBp)
    222 {
    223     /* Find it. */
    224     PDBGFBP pBp;
    225     if (iBp < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints))
    226         pBp = &pVM->dbgf.s.aHwBreakpoints[iBp];
    227     else
    228     {
    229         iBp -= RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
    230         if (iBp >= RT_ELEMENTS(pVM->dbgf.s.aBreakpoints))
    231             return NULL;
    232         pBp = &pVM->dbgf.s.aBreakpoints[iBp];
    233     }
    234 
    235     /* check if it's valid. */
    236     switch (pBp->enmType)
    237     {
    238         case DBGFBPTYPE_FREE:
    239             return NULL;
    240 
    241         case DBGFBPTYPE_REG:
    242         case DBGFBPTYPE_INT3:
    243         case DBGFBPTYPE_REM:
    244         case DBGFBPTYPE_PORT_IO:
    245         case DBGFBPTYPE_MMIO:
    246             break;
    247 
    248         default:
    249             AssertMsgFailed(("Invalid enmType=%d!\n", pBp->enmType));
    250             return NULL;
    251     }
    252 
    253     return pBp;
    254 }
    255 
    256 
    257 /**
    258  * Get a breakpoint give by address.
    259  *
    260  * @returns Pointer to the allocated breakpoint.
    261  * @returns NULL if the breakpoint is invalid.
    262  * @param   pVM     The cross context VM structure.
    263  * @param   enmType The breakpoint type.
    264  * @param   GCPtr   The breakpoint address.
    265  */
    266 static PDBGFBP dbgfR3BpGetByAddr(PVM pVM, DBGFBPTYPE enmType, RTGCUINTPTR GCPtr)
    267 {
    268     /*
    269      * Determine which array to search.
    270      */
    271     unsigned cBps;
    272     PDBGFBP  paBps;
    273     switch (enmType)
    274     {
    275         case DBGFBPTYPE_REG:
    276             cBps = RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
    277             paBps = &pVM->dbgf.s.aHwBreakpoints[0];
    278             break;
    279 
    280         case DBGFBPTYPE_INT3:
    281         case DBGFBPTYPE_REM:
    282             cBps = RT_ELEMENTS(pVM->dbgf.s.aBreakpoints);
    283             paBps = &pVM->dbgf.s.aBreakpoints[0];
    284             break;
    285 
    286         default:
    287             AssertMsgFailed(("enmType=%d\n", enmType));
    288             return NULL;
    289     }
    290 
    291     /*
    292      * Search.
    293      */
    294     for (unsigned iBp = 0; iBp < cBps; iBp++)
    295         if (   paBps[iBp].enmType == enmType
    296             && paBps[iBp].u.GCPtr == GCPtr)
    297             return &paBps[iBp];
    298 
    299     return NULL;
    300 }
    301 
    302 
    303 /**
    304  * Frees a breakpoint.
    305  *
    306  * @param   pVM     The cross context VM structure.
    307  * @param   pBp     The breakpoint to free.
    308  */
    309 static void dbgfR3BpFree(PVM pVM, PDBGFBP pBp)
    310 {
    311     switch (pBp->enmType)
    312     {
    313         case DBGFBPTYPE_FREE:
    314             AssertMsgFailed(("Already freed!\n"));
    315             return;
    316 
    317         case DBGFBPTYPE_REG:
    318             Assert((uintptr_t)(pBp - &pVM->dbgf.s.aHwBreakpoints[0]) < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints));
    319             break;
    320 
    321         case DBGFBPTYPE_INT3:
    322         case DBGFBPTYPE_REM:
    323         case DBGFBPTYPE_PORT_IO:
    324         case DBGFBPTYPE_MMIO:
    325             Assert((uintptr_t)(pBp - &pVM->dbgf.s.aBreakpoints[0]) < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints));
    326             break;
    327 
    328         default:
    329             AssertMsgFailed(("Invalid enmType=%d!\n", pBp->enmType));
    330             return;
    331 
    332     }
    333     pBp->enmType = DBGFBPTYPE_FREE;
    334     NOREF(pVM);
    335 }
    336 
    337 
    338 /**
    339  * @callback_method_impl{FNVMMEMTRENDEZVOUS}
    340  */
    341 static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpEnableInt3OnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
    342 {
    343     /*
    344      * Validate input.
    345      */
    346     PDBGFBP pBp = (PDBGFBP)pvUser;
    347     AssertReturn(pBp, VERR_INVALID_PARAMETER);
    348     Assert(pBp->enmType == DBGFBPTYPE_INT3);
    349     VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu);
    350     VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
    351 
    352     /*
    353      * Arm the breakpoint.
    354      */
    355     return dbgfR3BpInt3Arm(pVM, pBp);
    356 }
    357 
    358 
    359 /**
    360  * @callback_method_impl{FNVMMEMTRENDEZVOUS}
    361  */
    362 static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpSetInt3OnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
    363 {
    364     /*
    365      * Validate input.
    366      */
    367     PDBGFBPINT3ARGS pBpArgs = (PDBGFBPINT3ARGS)pvUser;
    368     AssertReturn(pBpArgs, VERR_INVALID_PARAMETER);
    369     VMCPU_ASSERT_EMT(pVCpu);
    370     VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
    371 
    372     AssertMsgReturn(!pBpArgs->piBp || VALID_PTR(pBpArgs->piBp), ("piBp=%p\n", pBpArgs->piBp), VERR_INVALID_POINTER);
    373     PCDBGFADDRESS pAddress = pBpArgs->pAddress;
    374     if (!DBGFR3AddrIsValid(pVM->pUVM, pAddress))
    375         return VERR_INVALID_PARAMETER;
    376 
    377     if (pBpArgs->iHitTrigger > pBpArgs->iHitDisable)
    378         return VERR_INVALID_PARAMETER;
    379 
    380     /*
    381      * Check if we're on the source CPU where we can resolve the breakpoint address.
    382      */
    383     if (pVCpu->idCpu == pBpArgs->idSrcCpu)
    384     {
    385         if (pBpArgs->piBp)
    386             *pBpArgs->piBp = UINT32_MAX;
    387 
    388         /*
    389          * Check if the breakpoint already exists.
    390          */
    391         PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_INT3, pAddress->FlatPtr);
    392         if (pBp)
    393         {
    394             int rc = VINF_SUCCESS;
    395             if (!pBp->fEnabled)
    396                 rc = dbgfR3BpInt3Arm(pVM, pBp);
    397             if (RT_SUCCESS(rc))
    398             {
    399                 if (pBpArgs->piBp)
    400                     *pBpArgs->piBp = pBp->iBp;
    401 
    402                 /*
    403                  * Returning VINF_DBGF_BP_ALREADY_EXIST here causes a VBOXSTRICTRC out-of-range assertion
    404                  * in VMMR3EmtRendezvous(). Re-setting of an existing breakpoint shouldn't cause an assertion
    405                  * killing the VM (and debugging session), so for now we'll pretend success.
    406                  */
    407 #if 0
    408                 rc = VINF_DBGF_BP_ALREADY_EXIST;
    409 #endif
    410             }
    411             else
    412                 dbgfR3BpFree(pVM, pBp);
    413             return rc;
    414         }
    415 
    416         /*
    417          * Allocate the breakpoint.
    418          */
    419         pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_INT3);
    420         if (!pBp)
    421             return VERR_DBGF_NO_MORE_BP_SLOTS;
    422 
    423         /*
    424          * Translate & save the breakpoint address into a guest-physical address.
    425          */
    426         int rc = DBGFR3AddrToPhys(pVM->pUVM, pBpArgs->idSrcCpu, pAddress, &pBp->u.Int3.PhysAddr);
    427         if (RT_SUCCESS(rc))
    428         {
    429             /* The physical address from DBGFR3AddrToPhys() is the start of the page,
    430                we need the exact byte offset into the page while writing to it in dbgfR3BpInt3Arm(). */
    431             pBp->u.Int3.PhysAddr |= (pAddress->FlatPtr & X86_PAGE_OFFSET_MASK);
    432             pBp->u.Int3.GCPtr = pAddress->FlatPtr;
    433             pBp->iHitTrigger  = pBpArgs->iHitTrigger;
    434             pBp->iHitDisable  = pBpArgs->iHitDisable;
    435 
    436             /*
    437              * Now set the breakpoint in guest memory.
    438              */
    439             rc = dbgfR3BpInt3Arm(pVM, pBp);
    440             if (RT_SUCCESS(rc))
    441             {
    442                 if (pBpArgs->piBp)
    443                     *pBpArgs->piBp = pBp->iBp;
    444                 return VINF_SUCCESS;
    445             }
    446         }
    447 
    448         dbgfR3BpFree(pVM, pBp);
    449         return rc;
    450     }
    451 
    452     return VINF_SUCCESS;
     233    UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
     234    AssertReturn(hBpOwner != NIL_DBGFBPOWNER, VERR_INVALID_HANDLE);
     235
     236    return VERR_NOT_IMPLEMENTED;
    453237}
    454238
     
    466250 * @param   iHitDisable The hit count which disables the breakpoint.
    467251 *                      Use ~(uint64_t) if it's never gonna be disabled.
    468  * @param   piBp        Where to store the breakpoint id. (optional)
    469  * @thread  Any thread.
    470  */
    471 VMMR3DECL(int) DBGFR3BpSetInt3(PUVM pUVM, VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable,
    472                                uint32_t *piBp)
    473 {
    474     AssertReturn(idSrcCpu <= pUVM->cCpus, VERR_INVALID_CPU_ID);
    475 
    476     DBGFBPINT3ARGS BpArgs;
    477     RT_ZERO(BpArgs);
    478     BpArgs.idSrcCpu    = idSrcCpu;
    479     BpArgs.iHitTrigger = iHitTrigger;
    480     BpArgs.iHitDisable = iHitDisable;
    481     BpArgs.pAddress    = pAddress;
    482     BpArgs.piBp        = piBp;
    483 
    484     int rc = VMMR3EmtRendezvous(pUVM->pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpSetInt3OnCpu, &BpArgs);
    485     LogFlow(("DBGFR3BpSet: returns %Rrc\n", rc));
    486     return rc;
    487 }
    488 
    489 
    490 /**
    491  * Arms an int 3 breakpoint.
    492  *
    493  * This is used to implement both DBGFR3BpSetInt3() and
    494  * DBGFR3BpEnable().
    495  *
    496  * @returns VBox status code.
    497  * @param   pVM         The cross context VM structure.
    498  * @param   pBp         The breakpoint.
    499  */
    500 static int dbgfR3BpInt3Arm(PVM pVM, PDBGFBP pBp)
    501 {
    502     VM_ASSERT_EMT(pVM);
    503 
    504     /*
    505      * Save current byte and write the int3 instruction byte.
    506      */
    507     int rc = PGMPhysSimpleReadGCPhys(pVM, &pBp->u.Int3.bOrg, pBp->u.Int3.PhysAddr, sizeof(pBp->u.Int3.bOrg));
    508     if (RT_SUCCESS(rc))
    509     {
    510         static const uint8_t s_bInt3 = 0xcc;
    511         rc = PGMPhysSimpleWriteGCPhys(pVM, pBp->u.Int3.PhysAddr, &s_bInt3, sizeof(s_bInt3));
    512         if (RT_SUCCESS(rc))
    513         {
    514             pBp->fEnabled = true;
    515             dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_INT3, &pVM->dbgf.s.Int3);
    516             pVM->dbgf.s.cEnabledInt3Breakpoints = pVM->dbgf.s.Int3.cToSearch;
    517             Log(("DBGF: Set breakpoint at %RGv (Phys %RGp) cEnabledInt3Breakpoints=%u\n", pBp->u.Int3.GCPtr,
    518                  pBp->u.Int3.PhysAddr, pVM->dbgf.s.cEnabledInt3Breakpoints));
    519         }
    520     }
    521     return rc;
    522 }
    523 
    524 
    525 /**
    526  * Disarms an int 3 breakpoint.
    527  *
    528  * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable().
    529  *
    530  * @returns VBox status code.
    531  * @param   pVM         The cross context VM structure.
    532  * @param   pBp         The breakpoint.
    533  */
    534 static int dbgfR3BpInt3Disarm(PVM pVM, PDBGFBP pBp)
    535 {
    536     VM_ASSERT_EMT(pVM);
    537 
    538     /*
    539      * Check that the current byte is the int3 instruction, and restore the original one.
    540      * We currently ignore invalid bytes.
    541      */
    542     uint8_t bCurrent = 0;
    543     int rc = PGMPhysSimpleReadGCPhys(pVM, &bCurrent, pBp->u.Int3.PhysAddr, sizeof(bCurrent));
    544     if (   RT_SUCCESS(rc)
    545         && bCurrent == 0xcc)
    546     {
    547         rc = PGMPhysSimpleWriteGCPhys(pVM, pBp->u.Int3.PhysAddr, &pBp->u.Int3.bOrg, sizeof(pBp->u.Int3.bOrg));
    548         if (RT_SUCCESS(rc))
    549         {
    550             pBp->fEnabled = false;
    551             dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_INT3, &pVM->dbgf.s.Int3);
    552             pVM->dbgf.s.cEnabledInt3Breakpoints = pVM->dbgf.s.Int3.cToSearch;
    553             Log(("DBGF: Removed breakpoint at %RGv (Phys %RGp) cEnabledInt3Breakpoints=%u\n", pBp->u.Int3.GCPtr,
    554                  pBp->u.Int3.PhysAddr, pVM->dbgf.s.cEnabledInt3Breakpoints));
    555         }
    556     }
    557     return rc;
    558 }
    559 
    560 
    561 /**
    562  * @callback_method_impl{FNVMMEMTRENDEZVOUS}
    563  */
    564 static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpDisableInt3OnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
    565 {
    566     /*
    567      * Validate input.
    568      */
    569     PDBGFBP pBp = (PDBGFBP)pvUser;
    570     AssertReturn(pBp, VERR_INVALID_PARAMETER);
    571     Assert(pBp->enmType == DBGFBPTYPE_INT3);
    572     VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu);
    573     VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
    574 
    575     /*
    576      * Disarm the breakpoint.
    577      */
    578     return dbgfR3BpInt3Disarm(pVM, pBp);
     252 * @param   phBp        Where to store the breakpoint handle on success.
     253 *
     254 * @thread  Any thread.
     255 */
     256VMMR3DECL(int) DBGFR3BpSetInt3(PUVM pUVM, VMCPUID idSrcCpu, PCDBGFADDRESS pAddress,
     257                               uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp)
     258{
     259    return DBGFR3BpSetInt3Ex(pUVM, NIL_DBGFBPOWNER, NULL /*pvUser*/, idSrcCpu, pAddress,
     260                             iHitTrigger, iHitDisable, phBp);
     261}
     262
     263
     264/**
     265 * Sets a breakpoint (int 3 based) - extended version.
     266 *
     267 * @returns VBox status code.
     268 * @param   pUVM            The user mode VM handle.
     269 * @param   hOwner          The owner handle, use NIL_DBGFBPOWNER if no special owner attached.
     270 * @param   pvUser          Opaque user data to pass in the owner callback.
     271 * @param   idSrcCpu        The ID of the virtual CPU used for the
     272 *                          breakpoint address resolution.
     273 * @param   pAddress        The address of the breakpoint.
     274 * @param   iHitTrigger     The hit count at which the breakpoint start triggering.
     275 *                          Use 0 (or 1) if it's gonna trigger at once.
     276 * @param   iHitDisable     The hit count which disables the breakpoint.
     277 *                          Use ~(uint64_t) if it's never gonna be disabled.
     278 * @param   phBp            Where to store the breakpoint handle on success.
     279 *
     280 * @thread  Any thread.
     281 */
     282VMMR3DECL(int) DBGFR3BpSetInt3Ex(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser,
     283                                 VMCPUID idSrcCpu, PCDBGFADDRESS pAddress,
     284                                 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp)
     285{
     286    UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
     287    AssertReturn(hOwner != NIL_DBGFBPOWNER || pvUser != NULL, VERR_INVALID_PARAMETER);
     288    AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER);
     289    AssertReturn(iHitTrigger <= iHitDisable, VERR_INVALID_PARAMETER);
     290    AssertPtrReturn(phBp, VERR_INVALID_POINTER);
     291
     292    RT_NOREF(idSrcCpu);
     293
     294    return VERR_NOT_IMPLEMENTED;
    579295}
    580296
     
    586302 * @param   pUVM            The user mode VM handle.
    587303 * @param   pAddress        The address of the breakpoint.
    588  * @param   piHitTrigger    The hit count at which the breakpoint start triggering.
     304 * @param   iHitTrigger     The hit count at which the breakpoint start triggering.
    589305 *                          Use 0 (or 1) if it's gonna trigger at once.
    590  * @param   piHitDisable    The hit count which disables the breakpoint.
     306 * @param   iHitDisable     The hit count which disables the breakpoint.
    591307 *                          Use ~(uint64_t) if it's never gonna be disabled.
    592308 * @param   fType           The access type (one of the X86_DR7_RW_* defines).
    593309 * @param   cb              The access size - 1,2,4 or 8 (the latter is AMD64 long mode only.
    594310 *                          Must be 1 if fType is X86_DR7_RW_EO.
    595  * @param   piBp            Where to store the breakpoint id. (optional)
    596  * @thread  EMT
    597  * @internal
    598  */
    599 static DECLCALLBACK(int) dbgfR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable,
    600                                         uint8_t fType, uint8_t cb, uint32_t *piBp)
    601 {
    602     /*
    603      * Validate input.
    604      */
    605     PVM pVM = pUVM->pVM;
    606     VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
    607     if (!DBGFR3AddrIsValid(pUVM, pAddress))
    608         return VERR_INVALID_PARAMETER;
    609     if (*piHitTrigger > *piHitDisable)
    610         return VERR_INVALID_PARAMETER;
    611     AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
    612     if (piBp)
    613         *piBp = UINT32_MAX;
     311 * @param   phBp            Where to store the breakpoint handle.
     312 *
     313 * @thread  Any thread.
     314 */
     315VMMR3DECL(int) DBGFR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger,
     316                              uint64_t iHitDisable, uint8_t fType, uint8_t cb, PDBGFBP phBp)
     317{
     318    return DBGFR3BpSetRegEx(pUVM, NIL_DBGFBPOWNER, NULL /*pvUser*/, pAddress,
     319                            iHitTrigger, iHitDisable, fType, cb, phBp);
     320}
     321
     322
     323/**
     324 * Sets a register breakpoint - extended version.
     325 *
     326 * @returns VBox status code.
     327 * @param   pUVM            The user mode VM handle.
     328 * @param   hOwner          The owner handle, use NIL_DBGFBPOWNER if no special owner attached.
     329 * @param   pvUser          Opaque user data to pass in the owner callback.
     330 * @param   pAddress        The address of the breakpoint.
     331 * @param   iHitTrigger     The hit count at which the breakpoint start triggering.
     332 *                          Use 0 (or 1) if it's gonna trigger at once.
     333 * @param   iHitDisable     The hit count which disables the breakpoint.
     334 *                          Use ~(uint64_t) if it's never gonna be disabled.
     335 * @param   fType           The access type (one of the X86_DR7_RW_* defines).
     336 * @param   cb              The access size - 1,2,4 or 8 (the latter is AMD64 long mode only.
     337 *                          Must be 1 if fType is X86_DR7_RW_EO.
     338 * @param   phBp            Where to store the breakpoint handle.
     339 *
     340 * @thread  Any thread.
     341 */
     342VMMR3DECL(int) DBGFR3BpSetRegEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser,
     343                                PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable,
     344                                uint8_t fType, uint8_t cb, PDBGFBP phBp)
     345{
     346    UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
     347    AssertReturn(hOwner != NIL_DBGFBPOWNER || pvUser != NULL, VERR_INVALID_PARAMETER);
     348    AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER);
     349    AssertReturn(iHitTrigger <= iHitDisable, VERR_INVALID_PARAMETER);
     350    AssertReturn(cb > 0 && cb <= 8 && RT_IS_POWER_OF_TWO(cb), VERR_INVALID_PARAMETER);
     351    AssertPtrReturn(phBp, VERR_INVALID_POINTER);
    614352    switch (fType)
    615353    {
     
    617355            if (cb == 1)
    618356                break;
    619             AssertMsgFailed(("fType=%#x cb=%d != 1\n", fType, cb));
    620             return VERR_INVALID_PARAMETER;
     357            AssertMsgFailedReturn(("fType=%#x cb=%d != 1\n", fType, cb), VERR_INVALID_PARAMETER);
    621358        case X86_DR7_RW_IO:
    622359        case X86_DR7_RW_RW:
     
    624361            break;
    625362        default:
    626             AssertMsgFailed(("fType=%#x\n", fType));
    627             return VERR_INVALID_PARAMETER;
     363            AssertMsgFailedReturn(("fType=%#x\n", fType), VERR_INVALID_PARAMETER);
    628364    }
    629     switch (cb)
    630     {
    631         case 1:
    632         case 2:
    633         case 4:
    634             break;
    635         default:
    636             AssertMsgFailed(("cb=%#x\n", cb));
    637             return VERR_INVALID_PARAMETER;
    638     }
    639 
    640     /*
    641      * Check if the breakpoint already exists.
    642      */
    643     PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REG, pAddress->FlatPtr);
    644     if (    pBp
    645         &&  pBp->u.Reg.cb == cb
    646         &&  pBp->u.Reg.fType == fType)
    647     {
    648         int rc = VINF_SUCCESS;
    649         if (!pBp->fEnabled)
    650             rc = dbgfR3BpRegArm(pVM, pBp);
    651         if (RT_SUCCESS(rc))
    652         {
    653             rc = VINF_DBGF_BP_ALREADY_EXIST;
    654             if (piBp)
    655                 *piBp = pBp->iBp;
    656         }
    657         return rc;
    658     }
    659 
    660     /*
    661      * Allocate and initialize the bp.
    662      */
    663     pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REG);
    664     if (!pBp)
    665         return VERR_DBGF_NO_MORE_BP_SLOTS;
    666     pBp->iHitTrigger = *piHitTrigger;
    667     pBp->iHitDisable = *piHitDisable;
    668     Assert(pBp->iBp == pBp->u.Reg.iReg);
    669     pBp->u.Reg.GCPtr = pAddress->FlatPtr;
    670     pBp->u.Reg.fType = fType;
    671     pBp->u.Reg.cb    = cb;
    672     ASMCompilerBarrier();
    673     pBp->fEnabled    = true;
    674 
    675     /*
    676      * Arm the breakpoint.
    677      */
    678     int rc = dbgfR3BpRegArm(pVM, pBp);
    679     if (RT_SUCCESS(rc))
    680     {
    681         if (piBp)
    682             *piBp = pBp->iBp;
    683     }
    684     else
    685         dbgfR3BpFree(pVM, pBp);
    686 
    687     return rc;
    688 }
    689 
    690 
    691 /**
    692  * Sets a register breakpoint.
    693  *
    694  * @returns VBox status code.
    695  * @param   pUVM        The user mode VM handle.
    696  * @param   pAddress    The address of the breakpoint.
    697  * @param   iHitTrigger The hit count at which the breakpoint start triggering.
    698  *                      Use 0 (or 1) if it's gonna trigger at once.
    699  * @param   iHitDisable The hit count which disables the breakpoint.
    700  *                      Use ~(uint64_t) if it's never gonna be disabled.
    701  * @param   fType       The access type (one of the X86_DR7_RW_* defines).
    702  * @param   cb          The access size - 1,2,4 or 8 (the latter is AMD64 long mode only.
    703  *                      Must be 1 if fType is X86_DR7_RW_EO.
    704  * @param   piBp        Where to store the breakpoint id. (optional)
    705  * @thread  Any thread.
    706  */
    707 VMMR3DECL(int) DBGFR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable,
    708                               uint8_t fType, uint8_t cb, uint32_t *piBp)
    709 {
    710     /*
    711      * This must be done on EMT.
    712      */
    713     int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetReg, 7,
    714                               pUVM, pAddress, &iHitTrigger, &iHitDisable, fType, cb, piBp);
    715     LogFlow(("DBGFR3BpSetReg: returns %Rrc\n", rc));
    716     return rc;
    717 
    718 }
    719 
    720 
    721 /**
    722  * @callback_method_impl{FNVMMEMTRENDEZVOUS}
    723  */
    724 static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpRegRecalcOnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
    725 {
    726     NOREF(pVM); NOREF(pvUser);
    727 
    728     /*
    729      * CPU 0 updates the enabled hardware breakpoint counts.
    730      */
    731     if (pVCpu->idCpu == 0)
    732     {
    733         pVM->dbgf.s.cEnabledHwBreakpoints   = 0;
    734         pVM->dbgf.s.cEnabledHwIoBreakpoints = 0;
    735 
    736         for (uint32_t iBp = 0; iBp < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); iBp++)
    737             if (   pVM->dbgf.s.aHwBreakpoints[iBp].fEnabled
    738                 && pVM->dbgf.s.aHwBreakpoints[iBp].enmType == DBGFBPTYPE_REG)
    739             {
    740                 pVM->dbgf.s.cEnabledHwBreakpoints   += 1;
    741                 pVM->dbgf.s.cEnabledHwIoBreakpoints += pVM->dbgf.s.aHwBreakpoints[iBp].u.Reg.fType == X86_DR7_RW_IO;
    742             }
    743     }
    744 
    745     return CPUMRecalcHyperDRx(pVCpu, UINT8_MAX, false);
    746 }
    747 
    748 
    749 /**
    750  * Arms a debug register breakpoint.
    751  *
    752  * This is used to implement both DBGFR3BpSetReg() and DBGFR3BpEnable().
    753  *
    754  * @returns VBox status code.
    755  * @param   pVM         The cross context VM structure.
    756  * @param   pBp         The breakpoint.
    757  * @thread  EMT(0)
    758  */
    759 static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp)
    760 {
    761     RT_NOREF_PV(pBp);
    762     Assert(pBp->fEnabled);
    763     return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpRegRecalcOnCpu, NULL);
    764 }
    765 
    766 
    767 /**
    768  * Disarms a debug register breakpoint.
    769  *
    770  * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable().
    771  *
    772  * @returns VBox status code.
    773  * @param   pVM         The cross context VM structure.
    774  * @param   pBp         The breakpoint.
    775  * @thread  EMT(0)
    776  */
    777 static int dbgfR3BpRegDisarm(PVM pVM, PDBGFBP pBp)
    778 {
    779     RT_NOREF_PV(pBp);
    780     Assert(!pBp->fEnabled);
    781     return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpRegRecalcOnCpu, NULL);
    782 }
    783 
    784 
    785 /**
    786  * EMT worker for DBGFR3BpSetREM().
    787  *
    788  * @returns VBox status code.
    789  * @param   pUVM            The user mode VM handle.
    790  * @param   pAddress        The address of the breakpoint.
    791  * @param   piHitTrigger    The hit count at which the breakpoint start triggering.
    792  *                          Use 0 (or 1) if it's gonna trigger at once.
    793  * @param   piHitDisable    The hit count which disables the breakpoint.
    794  *                          Use ~(uint64_t) if it's never gonna be disabled.
    795  * @param   piBp            Where to store the breakpoint id. (optional)
    796  * @thread  EMT(0)
    797  * @internal
    798  */
    799 static DECLCALLBACK(int) dbgfR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger,
    800                                         uint64_t *piHitDisable, uint32_t *piBp)
    801 {
    802     /*
    803      * Validate input.
    804      */
    805     PVM pVM = pUVM->pVM;
    806     VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
    807     if (!DBGFR3AddrIsValid(pUVM, pAddress))
    808         return VERR_INVALID_PARAMETER;
    809     if (*piHitTrigger > *piHitDisable)
    810         return VERR_INVALID_PARAMETER;
    811     AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
    812     if (piBp)
    813         *piBp = UINT32_MAX;
    814 
    815     /*
    816      * Check if the breakpoint already exists.
    817      */
    818     PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REM, pAddress->FlatPtr);
    819     if (pBp)
    820     {
    821         int rc = VINF_SUCCESS;
    822         if (!pBp->fEnabled)
    823             rc = IEMBreakpointSet(pVM, pBp->u.Rem.GCPtr);
    824         if (RT_SUCCESS(rc))
    825         {
    826             rc = VINF_DBGF_BP_ALREADY_EXIST;
    827             if (piBp)
    828                 *piBp = pBp->iBp;
    829         }
    830         return rc;
    831     }
    832 
    833     /*
    834      * Allocate and initialize the bp.
    835      */
    836     pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REM);
    837     if (!pBp)
    838         return VERR_DBGF_NO_MORE_BP_SLOTS;
    839     pBp->u.Rem.GCPtr = pAddress->FlatPtr;
    840     pBp->iHitTrigger = *piHitTrigger;
    841     pBp->iHitDisable = *piHitDisable;
    842     ASMCompilerBarrier();
    843     pBp->fEnabled    = true;
    844 
    845     /*
    846      * Now ask REM to set the breakpoint.
    847      */
    848     int rc = IEMBreakpointSet(pVM, pAddress->FlatPtr);
    849     if (RT_SUCCESS(rc))
    850     {
    851         if (piBp)
    852             *piBp = pBp->iBp;
    853     }
    854     else
    855         dbgfR3BpFree(pVM, pBp);
    856 
    857     return rc;
    858 }
    859 
    860 
    861 /**
    862  * Sets a recompiler breakpoint.
    863  *
    864  * @returns VBox status code.
    865  * @param   pUVM        The user mode VM handle.
    866  * @param   pAddress    The address of the breakpoint.
    867  * @param   iHitTrigger The hit count at which the breakpoint start triggering.
    868  *                      Use 0 (or 1) if it's gonna trigger at once.
    869  * @param   iHitDisable The hit count which disables the breakpoint.
    870  *                      Use ~(uint64_t) if it's never gonna be disabled.
    871  * @param   piBp        Where to store the breakpoint id. (optional)
    872  * @thread  Any thread.
    873  */
    874 VMMR3DECL(int) DBGFR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp)
    875 {
    876     /*
    877      * This must be done on EMT.
    878      */
    879     int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetREM, 5,
    880                               pUVM, pAddress, &iHitTrigger, &iHitDisable, piBp);
    881     LogFlow(("DBGFR3BpSetREM: returns %Rrc\n", rc));
    882     return rc;
    883 }
    884 
    885 
    886 /**
    887  * Updates IOM on whether we've got any armed I/O port or MMIO breakpoints.
    888  *
    889  * @returns VINF_SUCCESS
    890  * @param   pVM         The cross context VM structure.
    891  * @thread  EMT(0)
    892  */
    893 static int dbgfR3BpUpdateIom(PVM pVM)
    894 {
    895     dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_PORT_IO, &pVM->dbgf.s.PortIo);
    896     if (pVM->dbgf.s.PortIo.cToSearch)
    897         ASMAtomicBitSet(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_BREAKPOINT_IO);
    898     else
    899         ASMAtomicBitClear(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_BREAKPOINT_IO);
    900 
    901     dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_MMIO, &pVM->dbgf.s.Mmio);
    902     if (pVM->dbgf.s.Mmio.cToSearch)
    903         ASMAtomicBitSet(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_BREAKPOINT_MMIO);
    904     else
    905         ASMAtomicBitClear(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_BREAKPOINT_MMIO);
    906 
    907     IOMR3NotifyBreakpointCountChange(pVM, pVM->dbgf.s.PortIo.cToSearch != 0, pVM->dbgf.s.Mmio.cToSearch != 0);
    908     return VINF_SUCCESS;
    909 }
    910 
    911 
    912 /**
    913  * EMT worker for DBGFR3BpSetPortIo.
    914  *
    915  * @returns VBox status code.
    916  * @param   pUVM            The user mode VM handle.
    917  * @param   uPort           The first I/O port.
    918  * @param   cPorts          The number of I/O ports.
    919  * @param   fAccess         The access we want to break on.
    920  * @param   piHitTrigger    The hit count at which the breakpoint start triggering.
    921  *                          Use 0 (or 1) if it's gonna trigger at once.
    922  * @param   piHitDisable    The hit count which disables the breakpoint.
    923  *                          Use ~(uint64_t) if it's never gonna be disabled.
    924  * @param   piBp            Where to store the breakpoint ID.
    925  * @thread  EMT(0)
    926  */
    927 static DECLCALLBACK(int) dbgfR3BpSetPortIo(PUVM pUVM, RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess,
    928                                            uint64_t const *piHitTrigger, uint64_t const *piHitDisable, uint32_t *piBp)
    929 {
    930     /*
    931      * Validate input.
    932      */
    933     PVM pVM = pUVM->pVM;
    934     VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
    935     *piBp = UINT32_MAX;
    936 
    937     /*
    938      * Check if the breakpoint already exists.
    939      */
    940     for (uint32_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
    941         if (   pVM->dbgf.s.aBreakpoints[i].enmType == DBGFBPTYPE_PORT_IO
    942             && pVM->dbgf.s.aBreakpoints[i].u.PortIo.uPort == uPort
    943             && pVM->dbgf.s.aBreakpoints[i].u.PortIo.cPorts == cPorts
    944             && pVM->dbgf.s.aBreakpoints[i].u.PortIo.fAccess == fAccess)
    945         {
    946             if (!pVM->dbgf.s.aBreakpoints[i].fEnabled)
    947             {
    948                 pVM->dbgf.s.aBreakpoints[i].fEnabled = true;
    949                 dbgfR3BpUpdateIom(pVM);
    950             }
    951             *piBp = pVM->dbgf.s.aBreakpoints[i].iBp;
    952             return VINF_DBGF_BP_ALREADY_EXIST;
    953         }
    954 
    955     /*
    956      * Allocate and initialize the breakpoint.
    957      */
    958     PDBGFBP pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_PORT_IO);
    959     if (!pBp)
    960         return VERR_DBGF_NO_MORE_BP_SLOTS;
    961     pBp->iHitTrigger        = *piHitTrigger;
    962     pBp->iHitDisable        = *piHitDisable;
    963     pBp->u.PortIo.uPort     = uPort;
    964     pBp->u.PortIo.cPorts    = cPorts;
    965     pBp->u.PortIo.fAccess   = fAccess;
    966     ASMCompilerBarrier();
    967     pBp->fEnabled           = true;
    968 
    969     /*
    970      * Tell IOM.
    971      */
    972     dbgfR3BpUpdateIom(pVM);
    973     *piBp = pBp->iBp;
    974     return VINF_SUCCESS;
     365
     366    return VERR_NOT_IMPLEMENTED;
     367}
     368
     369
     370/**
     371 * This is only kept for now to not mess with the debugger implementation at this point,
     372 * recompiler breakpoints are not supported anymore (IEM has some API but it isn't implemented
     373 * and should probably be merged with the DBGF breakpoints).
     374 */
     375VMMR3DECL(int) DBGFR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger,
     376                              uint64_t iHitDisable, PDBGFBP phBp)
     377{
     378    RT_NOREF(pUVM, pAddress, iHitTrigger, iHitDisable, phBp);
     379    return VERR_NOT_SUPPORTED;
    975380}
    976381
     
    989394 * @param   iHitDisable     The hit count which disables the breakpoint.
    990395 *                          Use ~(uint64_t) if it's never gonna be disabled.
    991  * @param   piBp            Where to store the breakpoint ID. Optional.
    992  * @thread  Any thread.
    993  */
    994 VMMR3DECL(int)  DBGFR3BpSetPortIo(PUVM pUVM, RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess,
    995                                   uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp)
    996 {
     396 * @param   phBp            Where to store the breakpoint handle.
     397 *
     398 * @thread  Any thread.
     399 */
     400VMMR3DECL(int) DBGFR3BpSetPortIo(PUVM pUVM, RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess,
     401                                 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp)
     402{
     403    return DBGFR3BpSetPortIoEx(pUVM, NIL_DBGFBPOWNER, NULL /*pvUser*/, uPort, cPorts,
     404                               fAccess, iHitTrigger, iHitDisable, phBp);
     405}
     406
     407
     408/**
     409 * Sets an I/O port breakpoint - extended version.
     410 *
     411 * @returns VBox status code.
     412 * @param   pUVM            The user mode VM handle.
     413 * @param   hOwner          The owner handle, use NIL_DBGFBPOWNER if no special owner attached.
     414 * @param   pvUser          Opaque user data to pass in the owner callback.
     415 * @param   uPort           The first I/O port.
     416 * @param   cPorts          The number of I/O ports, see DBGFBPIOACCESS_XXX.
     417 * @param   fAccess         The access we want to break on.
     418 * @param   iHitTrigger     The hit count at which the breakpoint start
     419 *                          triggering. Use 0 (or 1) if it's gonna trigger at
     420 *                          once.
     421 * @param   iHitDisable     The hit count which disables the breakpoint.
     422 *                          Use ~(uint64_t) if it's never gonna be disabled.
     423 * @param   phBp            Where to store the breakpoint handle.
     424 *
     425 * @thread  Any thread.
     426 */
     427VMMR3DECL(int) DBGFR3BpSetPortIoEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser,
     428                                   RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess,
     429                                   uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp)
     430{
     431    UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
     432    AssertReturn(hOwner != NIL_DBGFBPOWNER || pvUser != NULL, VERR_INVALID_PARAMETER);
    997433    AssertReturn(!(fAccess & ~DBGFBPIOACCESS_VALID_MASK_PORT_IO), VERR_INVALID_FLAGS);
    998434    AssertReturn(fAccess, VERR_INVALID_FLAGS);
    999     if (iHitTrigger > iHitDisable)
    1000         return VERR_INVALID_PARAMETER;
    1001     AssertPtrNullReturn(piBp, VERR_INVALID_POINTER);
     435    AssertReturn(iHitTrigger <= iHitDisable, VERR_INVALID_PARAMETER);
     436    AssertPtrReturn(phBp, VERR_INVALID_POINTER);
    1002437    AssertReturn(cPorts > 0, VERR_OUT_OF_RANGE);
    1003438    AssertReturn((RTIOPORT)(uPort + cPorts) < uPort, VERR_OUT_OF_RANGE);
    1004439
    1005     /*
    1006      * This must be done on EMT.
    1007      */
    1008     uint32_t iBp = UINT32_MAX;
    1009     int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetPortIo, 7,
    1010                               pUVM, uPort, cPorts, fAccess, &iHitTrigger, &iHitDisable, piBp);
    1011     if (piBp)
    1012         *piBp = iBp;
    1013     LogFlow(("DBGFR3BpSetPortIo: returns %Rrc iBp=%d\n", rc, iBp));
    1014     return rc;
    1015 }
    1016 
    1017 
    1018 /**
    1019  * EMT worker for DBGFR3BpSetMmio.
    1020  *
    1021  * @returns VBox status code.
    1022  * @param   pUVM            The user mode VM handle.
    1023  * @param   pGCPhys         The start of the MMIO range to break on.
    1024  * @param   cb              The size of the MMIO range.
    1025  * @param   fAccess         The access we want to break on.
    1026  * @param   piHitTrigger    The hit count at which the breakpoint start triggering.
    1027  *                          Use 0 (or 1) if it's gonna trigger at once.
    1028  * @param   piHitDisable    The hit count which disables the breakpoint.
    1029  *                          Use ~(uint64_t) if it's never gonna be disabled.
    1030  * @param   piBp            Where to store the breakpoint ID.
    1031  * @thread  EMT(0)
    1032  */
    1033 static DECLCALLBACK(int) dbgfR3BpSetMmio(PUVM pUVM, PCRTGCPHYS pGCPhys, uint32_t cb, uint32_t fAccess,
    1034                                          uint64_t const *piHitTrigger, uint64_t const *piHitDisable, uint32_t *piBp)
    1035 {
    1036     RTGCPHYS const GCPhys = *pGCPhys;
    1037 
    1038     /*
    1039      * Validate input.
    1040      */
    1041     PVM pVM = pUVM->pVM;
    1042     VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
    1043     *piBp = UINT32_MAX;
    1044 
    1045     /*
    1046      * Check if the breakpoint already exists.
    1047      */
    1048     for (uint32_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
    1049         if (   pVM->dbgf.s.aBreakpoints[i].enmType == DBGFBPTYPE_MMIO
    1050             && pVM->dbgf.s.aBreakpoints[i].u.Mmio.PhysAddr == GCPhys
    1051             && pVM->dbgf.s.aBreakpoints[i].u.Mmio.cb == cb
    1052             && pVM->dbgf.s.aBreakpoints[i].u.Mmio.fAccess == fAccess)
    1053         {
    1054             if (!pVM->dbgf.s.aBreakpoints[i].fEnabled)
    1055             {
    1056                 pVM->dbgf.s.aBreakpoints[i].fEnabled = true;
    1057                 dbgfR3BpUpdateIom(pVM);
    1058             }
    1059             *piBp = pVM->dbgf.s.aBreakpoints[i].iBp;
    1060             return VINF_DBGF_BP_ALREADY_EXIST;
    1061         }
    1062 
    1063     /*
    1064      * Allocate and initialize the breakpoint.
    1065      */
    1066     PDBGFBP pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_MMIO);
    1067     if (!pBp)
    1068         return VERR_DBGF_NO_MORE_BP_SLOTS;
    1069     pBp->iHitTrigger        = *piHitTrigger;
    1070     pBp->iHitDisable        = *piHitDisable;
    1071     pBp->u.Mmio.PhysAddr    = GCPhys;
    1072     pBp->u.Mmio.cb          = cb;
    1073     pBp->u.Mmio.fAccess     = fAccess;
    1074     ASMCompilerBarrier();
    1075     pBp->fEnabled           = true;
    1076 
    1077     /*
    1078      * Tell IOM.
    1079      */
    1080     dbgfR3BpUpdateIom(pVM);
    1081     *piBp = pBp->iBp;
    1082     return VINF_SUCCESS;
     440    return VERR_NOT_IMPLEMENTED;
    1083441}
    1084442
     
    1097455 * @param   iHitDisable     The hit count which disables the breakpoint.
    1098456 *                          Use ~(uint64_t) if it's never gonna be disabled.
    1099  * @param   piBp            Where to store the breakpoint ID. Optional.
    1100  * @thread  Any thread.
    1101  */
    1102 VMMR3DECL(int)  DBGFR3BpSetMmio(PUVM pUVM, RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess,
    1103                                 uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp)
    1104 {
     457 * @param   phBp            Where to store the breakpoint handle.
     458 *
     459 * @thread  Any thread.
     460 */
     461VMMR3DECL(int) DBGFR3BpSetMmio(PUVM pUVM, RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess,
     462                               uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp)
     463{
     464    return DBGFR3BpSetMmioEx(pUVM, NIL_DBGFBPOWNER, NULL /*pvUser*/, GCPhys, cb, fAccess,
     465                             iHitTrigger, iHitDisable, phBp);
     466}
     467
     468
     469/**
     470 * Sets a memory mapped I/O breakpoint - extended version.
     471 *
     472 * @returns VBox status code.
     473 * @param   pUVM            The user mode VM handle.
     474 * @param   hOwner          The owner handle, use NIL_DBGFBPOWNER if no special owner attached.
     475 * @param   pvUser          Opaque user data to pass in the owner callback.
     476 * @param   GCPhys          The first MMIO address.
     477 * @param   cb              The size of the MMIO range to break on.
     478 * @param   fAccess         The access we want to break on.
     479 * @param   iHitTrigger     The hit count at which the breakpoint start
     480 *                          triggering. Use 0 (or 1) if it's gonna trigger at
     481 *                          once.
     482 * @param   iHitDisable     The hit count which disables the breakpoint.
     483 *                          Use ~(uint64_t) if it's never gonna be disabled.
     484 * @param   phBp            Where to store the breakpoint handle.
     485 *
     486 * @thread  Any thread.
     487 */
     488VMMR3DECL(int) DBGFR3BpSetMmioEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser,
     489                                 RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess,
     490                                 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp)
     491{
     492    UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
     493    AssertReturn(hOwner != NIL_DBGFBPOWNER || pvUser != NULL, VERR_INVALID_PARAMETER);
    1105494    AssertReturn(!(fAccess & ~DBGFBPIOACCESS_VALID_MASK_MMIO), VERR_INVALID_FLAGS);
    1106495    AssertReturn(fAccess, VERR_INVALID_FLAGS);
    1107     if (iHitTrigger > iHitDisable)
    1108         return VERR_INVALID_PARAMETER;
    1109     AssertPtrNullReturn(piBp, VERR_INVALID_POINTER);
     496    AssertReturn(iHitTrigger <= iHitDisable, VERR_INVALID_PARAMETER);
     497    AssertPtrReturn(phBp, VERR_INVALID_POINTER);
    1110498    AssertReturn(cb, VERR_OUT_OF_RANGE);
    1111499    AssertReturn(GCPhys + cb < GCPhys, VERR_OUT_OF_RANGE);
    1112500
     501    return VERR_NOT_IMPLEMENTED;
     502}
     503
     504
     505/**
     506 * Clears a breakpoint.
     507 *
     508 * @returns VBox status code.
     509 * @param   pUVM        The user mode VM handle.
     510 * @param   hBp         The handle of the breakpoint which should be removed (cleared).
     511 *
     512 * @thread  Any thread.
     513 */
     514VMMR3DECL(int) DBGFR3BpClear(PUVM pUVM, DBGFBP hBp)
     515{
     516    UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
     517    AssertReturn(hBp != NIL_DBGFBPOWNER, VERR_INVALID_HANDLE);
     518
     519    return VERR_NOT_IMPLEMENTED;
     520}
     521
     522
     523/**
     524 * Enables a breakpoint.
     525 *
     526 * @returns VBox status code.
     527 * @param   pUVM        The user mode VM handle.
     528 * @param   hBp         The handle of the breakpoint which should be enabled.
     529 *
     530 * @thread  Any thread.
     531 */
     532VMMR3DECL(int) DBGFR3BpEnable(PUVM pUVM, DBGFBP hBp)
     533{
     534    UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
     535    AssertReturn(hBp != NIL_DBGFBPOWNER, VERR_INVALID_HANDLE);
     536
     537    return VERR_NOT_IMPLEMENTED;
     538}
     539
     540
     541/**
     542 * Disables a breakpoint.
     543 *
     544 * @returns VBox status code.
     545 * @param   pUVM        The user mode VM handle.
     546 * @param   hBp         The handle of the breakpoint which should be disabled.
     547 *
     548 * @thread  Any thread.
     549 */
     550VMMR3DECL(int) DBGFR3BpDisable(PUVM pUVM, DBGFBP hBp)
     551{
    1113552    /*
    1114      * This must be done on EMT.
     553     * Validate the input.
    1115554     */
    1116     uint32_t iBp = UINT32_MAX;
    1117     int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetMmio, 7,
    1118                               pUVM, &GCPhys, cb, fAccess, &iHitTrigger, &iHitDisable, piBp);
    1119     if (piBp)
    1120         *piBp = iBp;
    1121     LogFlow(("DBGFR3BpSetMmio: returns %Rrc iBp=%d\n", rc, iBp));
    1122     return rc;
    1123 }
    1124 
    1125 
    1126 /**
    1127  * EMT worker for DBGFR3BpClear().
    1128  *
    1129  * @returns VBox status code.
    1130  * @param   pUVM        The user mode VM handle.
    1131  * @param   iBp         The id of the breakpoint which should be removed (cleared).
    1132  * @thread  EMT(0)
    1133  * @internal
    1134  */
    1135 static DECLCALLBACK(int) dbgfR3BpClear(PUVM pUVM, uint32_t iBp)
    1136 {
    1137     /*
    1138      * Validate input.
    1139      */
    1140     PVM pVM = pUVM->pVM;
    1141     VM_ASSERT_EMT(pVM);
    1142     VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
    1143     PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
    1144     if (!pBp)
    1145         return VERR_DBGF_BP_NOT_FOUND;
    1146 
    1147     /*
    1148      * Disarm the breakpoint if it's enabled.
    1149      */
    1150     if (pBp->fEnabled)
    1151     {
    1152         pBp->fEnabled = false;
    1153         int rc;
    1154         switch (pBp->enmType)
    1155         {
    1156             case DBGFBPTYPE_REG:
    1157                 rc = dbgfR3BpRegDisarm(pVM, pBp);
    1158                 break;
    1159 
    1160             case DBGFBPTYPE_INT3:
    1161                 rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3BpDisableInt3OnCpu, pBp);
    1162                 break;
    1163 
    1164             case DBGFBPTYPE_REM:
    1165                 rc = IEMBreakpointClear(pVM, pBp->u.Rem.GCPtr);
    1166                 break;
    1167 
    1168             case DBGFBPTYPE_PORT_IO:
    1169             case DBGFBPTYPE_MMIO:
    1170                 rc = dbgfR3BpUpdateIom(pVM);
    1171                 break;
    1172 
    1173             default:
    1174                 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
    1175         }
    1176         AssertRCReturn(rc, rc);
    1177     }
    1178 
    1179     /*
    1180      * Free the breakpoint.
    1181      */
    1182     dbgfR3BpFree(pVM, pBp);
    1183     return VINF_SUCCESS;
    1184 }
    1185 
    1186 
    1187 /**
    1188  * Clears a breakpoint.
    1189  *
    1190  * @returns VBox status code.
    1191  * @param   pUVM        The user mode VM handle.
    1192  * @param   iBp         The id of the breakpoint which should be removed (cleared).
    1193  * @thread  Any thread.
    1194  */
    1195 VMMR3DECL(int) DBGFR3BpClear(PUVM pUVM, uint32_t iBp)
    1196 {
    1197     /*
    1198      * This must be done on EMT.
    1199      */
    1200     int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpClear, 2, pUVM, iBp);
    1201     LogFlow(("DBGFR3BpClear: returns %Rrc\n", rc));
    1202     return rc;
    1203 }
    1204 
    1205 
    1206 /**
    1207  * EMT worker for DBGFR3BpEnable().
    1208  *
    1209  * @returns VBox status code.
    1210  * @param   pUVM        The user mode VM handle.
    1211  * @param   iBp         The id of the breakpoint which should be enabled.
    1212  * @thread  EMT(0)
    1213  * @internal
    1214  */
    1215 static DECLCALLBACK(int) dbgfR3BpEnable(PUVM pUVM, uint32_t iBp)
    1216 {
    1217     /*
    1218      * Validate input.
    1219      */
    1220     PVM pVM = pUVM->pVM;
    1221     VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
    1222     PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
    1223     if (!pBp)
    1224         return VERR_DBGF_BP_NOT_FOUND;
    1225 
    1226     /*
    1227      * Already enabled?
    1228      */
    1229     if (pBp->fEnabled)
    1230         return VINF_DBGF_BP_ALREADY_ENABLED;
    1231 
    1232     /*
    1233      * Arm the breakpoint.
    1234      */
    1235     int rc;
    1236     pBp->fEnabled = true;
    1237     switch (pBp->enmType)
    1238     {
    1239         case DBGFBPTYPE_REG:
    1240             rc = dbgfR3BpRegArm(pVM, pBp);
    1241             break;
    1242 
    1243         case DBGFBPTYPE_INT3:
    1244             rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3BpEnableInt3OnCpu, pBp);
    1245             break;
    1246 
    1247         case DBGFBPTYPE_REM:
    1248             rc = IEMBreakpointSet(pVM, pBp->u.Rem.GCPtr);
    1249             break;
    1250 
    1251         case DBGFBPTYPE_PORT_IO:
    1252         case DBGFBPTYPE_MMIO:
    1253             rc = dbgfR3BpUpdateIom(pVM);
    1254             break;
    1255 
    1256         default:
    1257             AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
    1258     }
    1259     if (RT_FAILURE(rc))
    1260         pBp->fEnabled = false;
    1261 
    1262     return rc;
    1263 }
    1264 
    1265 
    1266 /**
    1267  * Enables a breakpoint.
    1268  *
    1269  * @returns VBox status code.
    1270  * @param   pUVM        The user mode VM handle.
    1271  * @param   iBp         The id of the breakpoint which should be enabled.
    1272  * @thread  Any thread.
    1273  */
    1274 VMMR3DECL(int) DBGFR3BpEnable(PUVM pUVM, uint32_t iBp)
    1275 {
    1276     /*
    1277      * This must be done on EMT.
    1278      */
    1279     int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpEnable, 2, pUVM, iBp);
    1280     LogFlow(("DBGFR3BpEnable: returns %Rrc\n", rc));
    1281     return rc;
    1282 }
    1283 
    1284 
    1285 /**
    1286  * EMT worker for DBGFR3BpDisable().
    1287  *
    1288  * @returns VBox status code.
    1289  * @param   pUVM        The user mode VM handle.
    1290  * @param   iBp         The id of the breakpoint which should be disabled.
    1291  * @thread  EMT(0)
    1292  * @internal
    1293  */
    1294 static DECLCALLBACK(int) dbgfR3BpDisable(PUVM pUVM, uint32_t iBp)
    1295 {
    1296     /*
    1297      * Validate input.
    1298      */
    1299     PVM pVM = pUVM->pVM;
    1300     VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
    1301     PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
    1302     if (!pBp)
    1303         return VERR_DBGF_BP_NOT_FOUND;
    1304 
    1305     /*
    1306      * Already enabled?
    1307      */
    1308     if (!pBp->fEnabled)
    1309         return VINF_DBGF_BP_ALREADY_DISABLED;
    1310 
    1311     /*
    1312      * Remove the breakpoint.
    1313      */
    1314     pBp->fEnabled = false;
    1315     int rc;
    1316     switch (pBp->enmType)
    1317     {
    1318         case DBGFBPTYPE_REG:
    1319             rc = dbgfR3BpRegDisarm(pVM, pBp);
    1320             break;
    1321 
    1322         case DBGFBPTYPE_INT3:
    1323             rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3BpDisableInt3OnCpu, pBp);
    1324             break;
    1325 
    1326         case DBGFBPTYPE_REM:
    1327             rc = IEMBreakpointClear(pVM, pBp->u.Rem.GCPtr);
    1328             break;
    1329 
    1330         case DBGFBPTYPE_PORT_IO:
    1331         case DBGFBPTYPE_MMIO:
    1332             rc = dbgfR3BpUpdateIom(pVM);
    1333             break;
    1334 
    1335         default:
    1336             AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
    1337     }
    1338 
    1339     return rc;
    1340 }
    1341 
    1342 
    1343 /**
    1344  * Disables a breakpoint.
    1345  *
    1346  * @returns VBox status code.
    1347  * @param   pUVM        The user mode VM handle.
    1348  * @param   iBp         The id of the breakpoint which should be disabled.
    1349  * @thread  Any thread.
    1350  */
    1351 VMMR3DECL(int) DBGFR3BpDisable(PUVM pUVM, uint32_t iBp)
    1352 {
    1353     /*
    1354      * This must be done on EMT.
    1355      */
    1356     int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpDisable, 2, pUVM, iBp);
    1357     LogFlow(("DBGFR3BpDisable: returns %Rrc\n", rc));
    1358     return rc;
     555    UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
     556    AssertReturn(hBp != NIL_DBGFBPOWNER, VERR_INVALID_HANDLE);
     557
     558    return VERR_NOT_IMPLEMENTED;
    1359559}
    1360560
     
    1367567 * @param   pfnCallback The callback function.
    1368568 * @param   pvUser      The user argument to pass to the callback.
     569 *
    1369570 * @thread  EMT
    1370571 * @internal
     
    1379580    AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
    1380581
    1381     /*
    1382      * Enumerate the hardware breakpoints.
    1383      */
    1384     unsigned i;
    1385     for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
    1386         if (pVM->dbgf.s.aHwBreakpoints[i].enmType != DBGFBPTYPE_FREE)
    1387         {
    1388             int rc = pfnCallback(pUVM, pvUser, &pVM->dbgf.s.aHwBreakpoints[i]);
    1389             if (RT_FAILURE(rc) || rc == VINF_CALLBACK_RETURN)
    1390                 return rc;
    1391         }
    1392 
    1393     /*
    1394      * Enumerate the other breakpoints.
    1395      */
    1396     for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
    1397         if (pVM->dbgf.s.aBreakpoints[i].enmType != DBGFBPTYPE_FREE)
    1398         {
    1399             int rc = pfnCallback(pUVM, pvUser, &pVM->dbgf.s.aBreakpoints[i]);
    1400             if (RT_FAILURE(rc) || rc == VINF_CALLBACK_RETURN)
    1401                 return rc;
    1402         }
    1403 
    1404     return VINF_SUCCESS;
     582    RT_NOREF(pvUser);
     583
     584    return VERR_NOT_IMPLEMENTED;
    1405585}
    1406586
     
    1413593 * @param   pfnCallback The callback function.
    1414594 * @param   pvUser      The user argument to pass to the callback.
     595 *
    1415596 * @thread  Any thread but the callback will be called from EMT.
    1416597 */
  • trunk/src/VBox/VMM/VMMRZ/DBGFRZ.cpp

    r82968 r86666  
    6969        for (unsigned iBp = 0; iBp < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); iBp++)
    7070        {
     71#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    7172            if (    ((uint32_t)uDr6 & RT_BIT_32(iBp))
    7273                &&  pVM->dbgf.s.aHwBreakpoints[iBp].enmType == DBGFBPTYPE_REG)
     
    7980                return fInHyper ? VINF_EM_DBG_HYPER_BREAKPOINT : VINF_EM_DBG_BREAKPOINT;
    8081            }
     82#else
     83            if (    ((uint32_t)uDr6 & RT_BIT_32(iBp))
     84                &&  pVM->dbgf.s.aHwBreakpoints[iBp].hBp != NIL_DBGFBP)
     85            {
     86                pVCpu->dbgf.s.hBpActive = pVM->dbgf.s.aHwBreakpoints[iBp].hBp;
     87                pVCpu->dbgf.s.fSingleSteppingRaw = false;
     88                LogFlow(("DBGFRZTrap03Handler: hit hw breakpoint %x at %04x:%RGv\n",
     89                         pVM->dbgf.s.aHwBreakpoints[iBp].hBp, pRegFrame->cs.Sel, pRegFrame->rip));
     90
     91                return fInHyper ? VINF_EM_DBG_HYPER_BREAKPOINT : VINF_EM_DBG_BREAKPOINT;
     92            }
     93#endif
    8194        }
    8295    }
     
    197210#endif
    198211
     212#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    199213    /*
    200214     * Get the trap address and look it up in the breakpoint table.
     
    206220        RTGCPTR pPc;
    207221        int rc = SELMValidateAndConvertCSAddr(pVCpu, pRegFrame->eflags, pRegFrame->ss.Sel, pRegFrame->cs.Sel, &pRegFrame->cs,
    208 #ifdef IN_RC
     222# ifdef IN_RC
    209223                                              pRegFrame->eip - 1,
    210 #else
     224# else
    211225                                              pRegFrame->rip /* no -1 in R0 */,
    212 #endif
     226# endif
    213227                                              &pPc);
    214228        AssertRCReturn(rc, rc);
     
    233247        }
    234248    }
     249#endif /* !VBOX_WITH_LOTS_OF_DBGF_BPS */
    235250
    236251    return fInHyper
  • trunk/src/VBox/VMM/include/DBGFInternal.h

    r86098 r86666  
    747747
    748748
     749#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    749750/**
    750751 * Breakpoint search optimization.
     
    761762/** Pointer to a breakpoint search optimziation structure. */
    762763typedef DBGFBPSEARCHOPT *PDBGFBPSEARCHOPT;
     764#else
     765/**
     766 * Hardware breakpoint state.
     767 */
     768typedef struct DBGFBPHW
     769{
     770    /** The flat GC address of the breakpoint. */
     771    RTGCUINTPTR     GCPtr;
     772    /** The breakpoint handle if active, NIL_DBGFBP if disabled. */
     773    DBGFBP          hBp;
     774    /** The access type (one of the X86_DR7_RW_* value). */
     775    uint8_t         fType;
     776    /** The access size. */
     777    uint8_t         cb;
     778    /** Flag whether the breakpoint is currently enabled. */
     779    bool            fEnabled;
     780    /** Padding. */
     781    uint8_t         bPad;
     782} DBGFBPHW;
     783AssertCompileSize(DBGFBPHW, 16);
     784/** Pointer to a hardware breakpoint state. */
     785typedef DBGFBPHW *PDBGFBPHW;
     786/** Pointer to a const hardware breakpoint state. */
     787typedef const DBGFBPHW *PCDBGFBPHW;
     788#endif
    763789
    764790
     
    790816    /** The number of enabled hardware I/O breakpoints. */
    791817    uint8_t                     cEnabledHwIoBreakpoints;
     818#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    792819    /** The number of enabled INT3 breakpoints. */
    793820    uint8_t                     cEnabledInt3Breakpoints;
    794821    uint8_t                     abPadding; /**< Unused padding space up for grabs. */
     822#else
     823    uint16_t                    u16Pad;
     824#endif
    795825    uint32_t                    uPadding;
    796826
     
    830860    uint32_t                    u32Padding[2]; /**< Alignment padding. */
    831861
     862#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    832863    /** Array of hardware breakpoints. (0..3)
    833864     * This is shared among all the CPUs because life is much simpler that way. */
     
    843874    /** INT3 breakpoint search optimizations. */
    844875    DBGFBPSEARCHOPT             Int3;
     876#else
     877    /** Array of hardware breakpoints (0..3).
     878     * This is shared among all the CPUs because life is much simpler that way. */
     879    DBGFBPHW                    aHwBreakpoints[4];
     880#endif
    845881
    846882    /**
     
    907943    uint32_t                offVM;
    908944
     945#ifndef VBOX_WITH_LOTS_OF_DBGF_BPS
    909946    /** Current active breakpoint (id).
    910947     * This is ~0U if not active. It is set when a execution engine
     
    915952     * @todo drop this in favor of aEvents!  */
    916953    uint32_t                iActiveBp;
     954#else
     955    /** Current active breakpoint handle.
     956     * This is NIL_DBGFBP if not active. It is set when a execution engine
     957     * encounters a breakpoint and returns VINF_EM_DBG_BREAKPOINT.
     958     *
     959     * @todo drop this in favor of aEvents!  */
     960    DBGFBP                  hBpActive;
     961#endif
    917962    /** Set if we're singlestepping in raw mode.
    918963     * This is checked and cleared in the \#DB handler. */
     
    10921137void dbgfR3AsTerm(PUVM pUVM);
    10931138void dbgfR3AsRelocate(PUVM pUVM, RTGCUINTPTR offDelta);
     1139#ifdef VBOX_WITH_LOTS_OF_DBGF_BPS
     1140DECLHIDDEN(int) dbgfR3BpInit(PVM pVM);
     1141DECLHIDDEN(int) dbgfR3BpTerm(PVM pVM);
     1142#else
    10941143int  dbgfR3BpInit(PVM pVM);
     1144#endif
    10951145int  dbgfR3InfoInit(PUVM pUVM);
    10961146int  dbgfR3InfoTerm(PUVM pUVM);
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