/** * EMT worker for DBGFR3BpEnable(). * * @returns VBox status code. * @param pVM Pointer to the VM. * @param iBp The id of the breakpoint which should be enabled. * @thread EMT * @internal */ static DECLCALLBACK(int) dbgfR3BpEnable(PVM pVM, uint32_t iBp) { /* * Validate input. */ PDBGFBP pBp = dbgfR3BpGet(pVM, iBp); if (!pBp) return VERR_DBGF_BP_NOT_FOUND; /* * Already enabled? */ if (pBp->fEnabled) return VINF_DBGF_BP_ALREADY_ENABLED; /* * Remove the breakpoint. */ int rc; pBp->fEnabled = true; switch (pBp->enmType) { case DBGFBPTYPE_REG: rc = dbgfR3BpRegArm(pVM, pBp); break; case DBGFBPTYPE_INT3: rc = dbgfR3BpInt3Arm(pVM, pBp); break; case DBGFBPTYPE_REM: #ifdef VBOX_WITH_REM rc = REMR3BreakpointSet(pVM, pBp->GCPtr); #else rc = IEMBreakpointSet(pVM, pBp->GCPtr); #endif break; default: AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE); } if (RT_FAILURE(rc)) pBp->fEnabled = false; return rc; }
/** * Sets a register breakpoint. * * @returns VBox status code. * @param pVM The VM handle. * @param pAddress The address of the breakpoint. * @param piHitTrigger The hit count at which the breakpoint start triggering. * Use 0 (or 1) if it's gonna trigger at once. * @param piHitDisable The hit count which disables the breakpoint. * Use ~(uint64_t) if it's never gonna be disabled. * @param fType The access type (one of the X86_DR7_RW_* defines). * @param cb The access size - 1,2,4 or 8 (the latter is AMD64 long mode only. * Must be 1 if fType is X86_DR7_RW_EO. * @param piBp Where to store the breakpoint id. (optional) * @thread EMT * @internal */ static DECLCALLBACK(int) dbgfR3BpSetReg(PVM pVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable, uint8_t fType, uint8_t cb, uint32_t *piBp) { /* * Validate input. */ if (!DBGFR3AddrIsValid(pVM, pAddress)) return VERR_INVALID_PARAMETER; if (*piHitTrigger > *piHitDisable) return VERR_INVALID_PARAMETER; AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER); if (piBp) *piBp = ~0; switch (fType) { case X86_DR7_RW_EO: if (cb == 1) break; AssertMsgFailed(("fType=%#x cb=%d != 1\n", fType, cb)); return VERR_INVALID_PARAMETER; case X86_DR7_RW_IO: case X86_DR7_RW_RW: case X86_DR7_RW_WO: break; default: AssertMsgFailed(("fType=%#x\n", fType)); return VERR_INVALID_PARAMETER; } switch (cb) { case 1: case 2: case 4: break; default: AssertMsgFailed(("cb=%#x\n", cb)); return VERR_INVALID_PARAMETER; } /* * Check if the breakpoint already exists. */ PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REG, pAddress->FlatPtr); if ( pBp && pBp->u.Reg.cb == cb && pBp->u.Reg.fType == fType) { int rc = VINF_SUCCESS; if (!pBp->fEnabled) rc = dbgfR3BpRegArm(pVM, pBp); if (RT_SUCCESS(rc)) { rc = VINF_DBGF_BP_ALREADY_EXIST; if (piBp) *piBp = pBp->iBp; } return rc; } /* * Allocate and initialize the bp. */ pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REG); if (!pBp) return VERR_DBGF_NO_MORE_BP_SLOTS; pBp->GCPtr = pAddress->FlatPtr; pBp->iHitTrigger = *piHitTrigger; pBp->iHitDisable = *piHitDisable; pBp->fEnabled = true; Assert(pBp->iBp == pBp->u.Reg.iReg); pBp->u.Reg.fType = fType; pBp->u.Reg.cb = cb; /* * Arm the breakpoint. */ int rc = dbgfR3BpRegArm(pVM, pBp); if (RT_SUCCESS(rc)) { if (piBp) *piBp = pBp->iBp; } else dbgfR3BpFree(pVM, pBp); return rc; }