VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGFBp.cpp@ 76553

Last change on this file since 76553 was 76553, checked in by vboxsync, 5 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 43.6 KB
RevLine 
[23]1/* $Id: DBGFBp.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
[1]2/** @file
[12677]3 * DBGF - Debugger Facility, Breakpoint Management.
[1]4 */
5
6/*
[76553]7 * Copyright (C) 2006-2019 Oracle Corporation
[1]8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
[5999]12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
[1]16 */
17
18
[57358]19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
[1]22#define LOG_GROUP LOG_GROUP_DBGF
[35346]23#include <VBox/vmm/dbgf.h>
24#include <VBox/vmm/selm.h>
[40274]25#ifdef VBOX_WITH_REM
26# include <VBox/vmm/rem.h>
27#else
28# include <VBox/vmm/iem.h>
29#endif
[44399]30#include <VBox/vmm/mm.h>
[58903]31#include <VBox/vmm/iom.h>
32#include <VBox/vmm/hm.h>
[1]33#include "DBGFInternal.h"
[35346]34#include <VBox/vmm/vm.h>
[44399]35#include <VBox/vmm/uvm.h>
36
[1]37#include <VBox/err.h>
38#include <VBox/log.h>
39#include <iprt/assert.h>
[23]40#include <iprt/string.h>
[1]41
42
[57358]43/*********************************************************************************************************************************
[64770]44* Structures and Typedefs *
45*********************************************************************************************************************************/
46/**
47 * DBGF INT3-breakpoint set callback arguments.
48 */
49typedef struct DBGFBPINT3ARGS
50{
51 /** The source virtual CPU ID (used for breakpoint address resolution). */
52 VMCPUID idSrcCpu;
53 /** The breakpoint address. */
54 PCDBGFADDRESS pAddress;
55 /** The hit count at which the breakpoint starts triggering. */
56 uint64_t iHitTrigger;
57 /** The hit count at which disables the breakpoint. */
58 uint64_t iHitDisable;
59 /** Where to store the breakpoint Id (optional). */
60 uint32_t *piBp;
61} DBGFBPINT3ARGS;
62/** Pointer to a DBGF INT3 breakpoint set callback argument. */
63typedef DBGFBPINT3ARGS *PDBGFBPINT3ARGS;
64
65
66/*********************************************************************************************************************************
[57358]67* Internal Functions *
68*********************************************************************************************************************************/
[20374]69RT_C_DECLS_BEGIN
[1]70static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp);
[64770]71static int dbgfR3BpInt3Arm(PVM pVM, PDBGFBP pBp);
[20374]72RT_C_DECLS_END
[1]73
74
[12663]75
[1]76/**
77 * Initialize the breakpoint stuff.
78 *
79 * @returns VINF_SUCCESS
[58122]80 * @param pVM The cross context VM structure.
[1]81 */
82int dbgfR3BpInit(PVM pVM)
83{
84 /*
85 * Init structures.
86 */
87 unsigned i;
[11311]88 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
[1]89 {
90 pVM->dbgf.s.aHwBreakpoints[i].iBp = i;
91 pVM->dbgf.s.aHwBreakpoints[i].enmType = DBGFBPTYPE_FREE;
92 pVM->dbgf.s.aHwBreakpoints[i].u.Reg.iReg = i;
93 }
94
[11311]95 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
[1]96 {
[11311]97 pVM->dbgf.s.aBreakpoints[i].iBp = i + RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
[1]98 pVM->dbgf.s.aBreakpoints[i].enmType = DBGFBPTYPE_FREE;
99 }
100
[42834]101 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
102 {
103 PVMCPU pVCpu = &pVM->aCpus[idCpu];
104 pVCpu->dbgf.s.iActiveBp = ~0U;
105 }
106
[1]107 /*
108 * Register saved state.
109 */
110 /** @todo */
111
112 return VINF_SUCCESS;
113}
114
115
116
117/**
118 * Allocate a breakpoint.
119 *
120 * @returns Pointer to the allocated breakpoint.
121 * @returns NULL if we're out of breakpoints.
[58122]122 * @param pVM The cross context VM structure.
[1]123 * @param enmType The type to allocate.
124 */
125static PDBGFBP dbgfR3BpAlloc(PVM pVM, DBGFBPTYPE enmType)
126{
127 /*
[58909]128 * Determine which array to search and where in the array to start
129 * searching (latter for grouping similar BPs, reducing runtime overhead).
[1]130 */
[58909]131 unsigned iStart;
[35694]132 unsigned cBps;
133 PDBGFBP paBps;
[1]134 switch (enmType)
135 {
136 case DBGFBPTYPE_REG:
[11311]137 cBps = RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
[1]138 paBps = &pVM->dbgf.s.aHwBreakpoints[0];
[58909]139 iStart = 0;
[1]140 break;
141
142 case DBGFBPTYPE_INT3:
143 case DBGFBPTYPE_REM:
[58909]144 case DBGFBPTYPE_PORT_IO:
145 case DBGFBPTYPE_MMIO:
[11311]146 cBps = RT_ELEMENTS(pVM->dbgf.s.aBreakpoints);
[1]147 paBps = &pVM->dbgf.s.aBreakpoints[0];
[58909]148 if (enmType == DBGFBPTYPE_PORT_IO)
149 iStart = cBps / 4 * 2;
150 else if (enmType == DBGFBPTYPE_MMIO)
151 iStart = cBps / 4 * 1;
152 else if (enmType == DBGFBPTYPE_REM)
153 iStart = cBps / 4 * 3;
154 else
155 iStart = 0;
[1]156 break;
157
158 default:
159 AssertMsgFailed(("enmType=%d\n", enmType));
160 return NULL;
161 }
162
163 /*
[58909]164 * Search for a free breakpoint entry.
[1]165 */
[58909]166 unsigned iBp;
167 for (iBp = iStart; iBp < cBps; iBp++)
[1]168 if (paBps[iBp].enmType == DBGFBPTYPE_FREE)
[58909]169 break;
170 if (iBp >= cBps && iStart != 0)
171 for (iBp = 0; iBp < cBps; iBp++)
172 if (paBps[iBp].enmType == DBGFBPTYPE_FREE)
173 break;
174 if (iBp < cBps)
175 {
176 /*
177 * Return what we found.
178 */
179 paBps[iBp].fEnabled = false;
180 paBps[iBp].cHits = 0;
181 paBps[iBp].enmType = enmType;
182 return &paBps[iBp];
183 }
184
185 LogFlow(("dbgfR3BpAlloc: returns NULL - we're out of breakpoint slots! cBps=%u\n", cBps));
186 return NULL;
187}
188
189
190/**
[64770]191 * Updates the search optimization structure for enabled breakpoints of the
192 * specified type.
[58909]193 *
[64770]194 * @returns VINF_SUCCESS.
[58909]195 * @param pVM The cross context VM structure.
196 * @param enmType The breakpoint type.
197 * @param pOpt The breakpoint optimization structure to update.
198 */
199static int dbgfR3BpUpdateSearchOptimizations(PVM pVM, DBGFBPTYPE enmType, PDBGFBPSEARCHOPT pOpt)
200{
201 DBGFBPSEARCHOPT Opt = { UINT32_MAX, 0 };
202
203 for (uint32_t iBp = 0; iBp < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); iBp++)
204 if ( pVM->dbgf.s.aBreakpoints[iBp].enmType == enmType
205 && pVM->dbgf.s.aBreakpoints[iBp].fEnabled)
[1]206 {
[58909]207 if (Opt.iStartSearch > iBp)
208 Opt.iStartSearch = iBp;
209 Opt.cToSearch = iBp - Opt.iStartSearch + 1;
[1]210 }
211
[58909]212 *pOpt = Opt;
213 return VINF_SUCCESS;
[1]214}
215
216
217/**
218 * Get a breakpoint give by breakpoint id.
219 *
220 * @returns Pointer to the allocated breakpoint.
221 * @returns NULL if the breakpoint is invalid.
[58122]222 * @param pVM The cross context VM structure.
[1]223 * @param iBp The breakpoint id.
224 */
[35694]225static PDBGFBP dbgfR3BpGet(PVM pVM, uint32_t iBp)
[1]226{
227 /* Find it. */
228 PDBGFBP pBp;
[11311]229 if (iBp < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints))
[1]230 pBp = &pVM->dbgf.s.aHwBreakpoints[iBp];
231 else
232 {
[11311]233 iBp -= RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
234 if (iBp >= RT_ELEMENTS(pVM->dbgf.s.aBreakpoints))
[1]235 return NULL;
236 pBp = &pVM->dbgf.s.aBreakpoints[iBp];
237 }
238
239 /* check if it's valid. */
240 switch (pBp->enmType)
241 {
242 case DBGFBPTYPE_FREE:
243 return NULL;
244
245 case DBGFBPTYPE_REG:
246 case DBGFBPTYPE_INT3:
247 case DBGFBPTYPE_REM:
[58909]248 case DBGFBPTYPE_PORT_IO:
249 case DBGFBPTYPE_MMIO:
[1]250 break;
251
252 default:
253 AssertMsgFailed(("Invalid enmType=%d!\n", pBp->enmType));
254 return NULL;
255 }
256
257 return pBp;
258}
259
260
261/**
262 * Get a breakpoint give by address.
263 *
264 * @returns Pointer to the allocated breakpoint.
265 * @returns NULL if the breakpoint is invalid.
[58122]266 * @param pVM The cross context VM structure.
[1]267 * @param enmType The breakpoint type.
268 * @param GCPtr The breakpoint address.
269 */
270static PDBGFBP dbgfR3BpGetByAddr(PVM pVM, DBGFBPTYPE enmType, RTGCUINTPTR GCPtr)
271{
272 /*
[33540]273 * Determine which array to search.
[1]274 */
275 unsigned cBps;
276 PDBGFBP paBps;
277 switch (enmType)
278 {
279 case DBGFBPTYPE_REG:
[11311]280 cBps = RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
[1]281 paBps = &pVM->dbgf.s.aHwBreakpoints[0];
282 break;
283
284 case DBGFBPTYPE_INT3:
285 case DBGFBPTYPE_REM:
[11311]286 cBps = RT_ELEMENTS(pVM->dbgf.s.aBreakpoints);
[1]287 paBps = &pVM->dbgf.s.aBreakpoints[0];
288 break;
289
290 default:
291 AssertMsgFailed(("enmType=%d\n", enmType));
292 return NULL;
293 }
294
295 /*
296 * Search.
297 */
298 for (unsigned iBp = 0; iBp < cBps; iBp++)
[58903]299 if ( paBps[iBp].enmType == enmType
300 && paBps[iBp].u.GCPtr == GCPtr)
[1]301 return &paBps[iBp];
302
303 return NULL;
304}
305
306
307/**
308 * Frees a breakpoint.
309 *
[58122]310 * @param pVM The cross context VM structure.
[1]311 * @param pBp The breakpoint to free.
312 */
313static void dbgfR3BpFree(PVM pVM, PDBGFBP pBp)
314{
315 switch (pBp->enmType)
316 {
317 case DBGFBPTYPE_FREE:
318 AssertMsgFailed(("Already freed!\n"));
319 return;
320
321 case DBGFBPTYPE_REG:
[58911]322 Assert((uintptr_t)(pBp - &pVM->dbgf.s.aHwBreakpoints[0]) < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints));
[1]323 break;
324
325 case DBGFBPTYPE_INT3:
326 case DBGFBPTYPE_REM:
[58909]327 case DBGFBPTYPE_PORT_IO:
328 case DBGFBPTYPE_MMIO:
[58911]329 Assert((uintptr_t)(pBp - &pVM->dbgf.s.aBreakpoints[0]) < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints));
[1]330 break;
331
332 default:
333 AssertMsgFailed(("Invalid enmType=%d!\n", pBp->enmType));
334 return;
335
336 }
337 pBp->enmType = DBGFBPTYPE_FREE;
[58909]338 NOREF(pVM);
[1]339}
340
341
342/**
[64770]343 * @callback_method_impl{FNVMMEMTRENDEZVOUS}
[1]344 */
[64770]345static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpEnableInt3OnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
[1]346{
347 /*
348 * Validate input.
349 */
[64770]350 PDBGFBP pBp = (PDBGFBP)pvUser;
351 AssertReturn(pBp, VERR_INVALID_PARAMETER);
352 Assert(pBp->enmType == DBGFBPTYPE_INT3);
353 VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu);
[44399]354 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
[64770]355
356 /*
357 * Arm the breakpoint.
358 */
359 return dbgfR3BpInt3Arm(pVM, pBp);
360}
361
362
363/**
364 * @callback_method_impl{FNVMMEMTRENDEZVOUS}
365 */
366static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpSetInt3OnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
367{
368 /*
369 * Validate input.
370 */
371 PDBGFBPINT3ARGS pBpArgs = (PDBGFBPINT3ARGS)pvUser;
372 AssertReturn(pBpArgs, VERR_INVALID_PARAMETER);
373 VMCPU_ASSERT_EMT(pVCpu);
374 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
375
376 AssertMsgReturn(!pBpArgs->piBp || VALID_PTR(pBpArgs->piBp), ("piBp=%p\n", pBpArgs->piBp), VERR_INVALID_POINTER);
377 PCDBGFADDRESS pAddress = pBpArgs->pAddress;
378 if (!DBGFR3AddrIsValid(pVM->pUVM, pAddress))
[1]379 return VERR_INVALID_PARAMETER;
[64770]380
381 if (pBpArgs->iHitTrigger > pBpArgs->iHitDisable)
[1]382 return VERR_INVALID_PARAMETER;
383
384 /*
[64770]385 * Check if we're on the source CPU where we can resolve the breakpoint address.
[1]386 */
[64770]387 if (pVCpu->idCpu == pBpArgs->idSrcCpu)
[1]388 {
[64770]389 if (pBpArgs->piBp)
390 *pBpArgs->piBp = UINT32_MAX;
391
392 /*
393 * Check if the breakpoint already exists.
394 */
395 PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_INT3, pAddress->FlatPtr);
396 if (pBp)
397 {
398 int rc = VINF_SUCCESS;
399 if (!pBp->fEnabled)
400 rc = dbgfR3BpInt3Arm(pVM, pBp);
401 if (RT_SUCCESS(rc))
402 {
403 if (pBpArgs->piBp)
404 *pBpArgs->piBp = pBp->iBp;
405
406 /*
407 * Returning VINF_DBGF_BP_ALREADY_EXIST here causes a VBOXSTRICTRC out-of-range assertion
408 * in VMMR3EmtRendezvous(). Re-setting of an existing breakpoint shouldn't cause an assertion
409 * killing the VM (and debugging session), so for now we'll pretend success.
410 */
411#if 0
412 rc = VINF_DBGF_BP_ALREADY_EXIST;
413#endif
414 }
415 else
416 dbgfR3BpFree(pVM, pBp);
417 return rc;
418 }
419
420 /*
421 * Allocate the breakpoint.
422 */
423 pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_INT3);
424 if (!pBp)
425 return VERR_DBGF_NO_MORE_BP_SLOTS;
426
427 /*
428 * Translate & save the breakpoint address into a guest-physical address.
429 */
430 int rc = DBGFR3AddrToPhys(pVM->pUVM, pBpArgs->idSrcCpu, pAddress, &pBp->u.Int3.PhysAddr);
[13816]431 if (RT_SUCCESS(rc))
[1]432 {
[64770]433 /* The physical address from DBGFR3AddrToPhys() is the start of the page,
434 we need the exact byte offset into the page while writing to it in dbgfR3BpInt3Arm(). */
435 pBp->u.Int3.PhysAddr |= (pAddress->FlatPtr & X86_PAGE_OFFSET_MASK);
436 pBp->u.Int3.GCPtr = pAddress->FlatPtr;
437 pBp->iHitTrigger = pBpArgs->iHitTrigger;
438 pBp->iHitDisable = pBpArgs->iHitDisable;
439
440 /*
441 * Now set the breakpoint in guest memory.
442 */
443 rc = dbgfR3BpInt3Arm(pVM, pBp);
444 if (RT_SUCCESS(rc))
445 {
446 if (pBpArgs->piBp)
447 *pBpArgs->piBp = pBp->iBp;
448 return VINF_SUCCESS;
449 }
[1]450 }
[64770]451
452 dbgfR3BpFree(pVM, pBp);
[1]453 return rc;
454 }
455
[64770]456 return VINF_SUCCESS;
[1]457}
458
459
460/**
[44399]461 * Sets a breakpoint (int 3 based).
462 *
463 * @returns VBox status code.
464 * @param pUVM The user mode VM handle.
[64770]465 * @param idSrcCpu The ID of the virtual CPU used for the
466 * breakpoint address resolution.
[44399]467 * @param pAddress The address of the breakpoint.
468 * @param iHitTrigger The hit count at which the breakpoint start triggering.
469 * Use 0 (or 1) if it's gonna trigger at once.
470 * @param iHitDisable The hit count which disables the breakpoint.
471 * Use ~(uint64_t) if it's never gonna be disabled.
472 * @param piBp Where to store the breakpoint id. (optional)
473 * @thread Any thread.
474 */
[64770]475VMMR3DECL(int) DBGFR3BpSetInt3(PUVM pUVM, VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable,
476 uint32_t *piBp)
[44399]477{
[64770]478 AssertReturn(idSrcCpu <= pUVM->cCpus, VERR_INVALID_CPU_ID);
479
480 DBGFBPINT3ARGS BpArgs;
481 RT_ZERO(BpArgs);
482 BpArgs.idSrcCpu = idSrcCpu;
483 BpArgs.iHitTrigger = iHitTrigger;
484 BpArgs.iHitDisable = iHitDisable;
485 BpArgs.pAddress = pAddress;
486 BpArgs.piBp = piBp;
487
488 int rc = VMMR3EmtRendezvous(pUVM->pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpSetInt3OnCpu, &BpArgs);
[44399]489 LogFlow(("DBGFR3BpSet: returns %Rrc\n", rc));
490 return rc;
491}
492
493
494/**
[1]495 * Arms an int 3 breakpoint.
496 *
[64770]497 * This is used to implement both DBGFR3BpSetInt3() and
498 * DBGFR3BpEnable().
499 *
[1]500 * @returns VBox status code.
[64770]501 * @param pVM The cross context VM structure.
[1]502 * @param pBp The breakpoint.
503 */
[64770]504static int dbgfR3BpInt3Arm(PVM pVM, PDBGFBP pBp)
[1]505{
[64770]506 VM_ASSERT_EMT(pVM);
[18927]507
[1]508 /*
[64770]509 * Save current byte and write the int3 instruction byte.
[1]510 */
[64770]511 int rc = PGMPhysSimpleReadGCPhys(pVM, &pBp->u.Int3.bOrg, pBp->u.Int3.PhysAddr, sizeof(pBp->u.Int3.bOrg));
[13816]512 if (RT_SUCCESS(rc))
[1]513 {
514 static const uint8_t s_bInt3 = 0xcc;
[64770]515 rc = PGMPhysSimpleWriteGCPhys(pVM, pBp->u.Int3.PhysAddr, &s_bInt3, sizeof(s_bInt3));
516 if (RT_SUCCESS(rc))
517 {
518 pBp->fEnabled = true;
519 dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_INT3, &pVM->dbgf.s.Int3);
520 pVM->dbgf.s.cEnabledInt3Breakpoints = pVM->dbgf.s.Int3.cToSearch;
521 Log(("DBGF: Set breakpoint at %RGv (Phys %RGp) cEnabledInt3Breakpoints=%u\n", pBp->u.Int3.GCPtr,
522 pBp->u.Int3.PhysAddr, pVM->dbgf.s.cEnabledInt3Breakpoints));
523 }
[1]524 }
525 return rc;
526}
527
528
529/**
530 * Disarms an int 3 breakpoint.
[64770]531 *
[1]532 * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable().
533 *
534 * @returns VBox status code.
[64770]535 * @param pVM The cross context VM structure.
[1]536 * @param pBp The breakpoint.
537 */
[64770]538static int dbgfR3BpInt3Disarm(PVM pVM, PDBGFBP pBp)
[1]539{
[64770]540 VM_ASSERT_EMT(pVM);
[18927]541
[1]542 /*
543 * Check that the current byte is the int3 instruction, and restore the original one.
544 * We currently ignore invalid bytes.
545 */
[64770]546 uint8_t bCurrent = 0;
547 int rc = PGMPhysSimpleReadGCPhys(pVM, &bCurrent, pBp->u.Int3.PhysAddr, sizeof(bCurrent));
548 if ( RT_SUCCESS(rc)
549 && bCurrent == 0xcc)
550 {
551 rc = PGMPhysSimpleWriteGCPhys(pVM, pBp->u.Int3.PhysAddr, &pBp->u.Int3.bOrg, sizeof(pBp->u.Int3.bOrg));
552 if (RT_SUCCESS(rc))
553 {
554 pBp->fEnabled = false;
555 dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_INT3, &pVM->dbgf.s.Int3);
556 pVM->dbgf.s.cEnabledInt3Breakpoints = pVM->dbgf.s.Int3.cToSearch;
557 Log(("DBGF: Removed breakpoint at %RGv (Phys %RGp) cEnabledInt3Breakpoints=%u\n", pBp->u.Int3.GCPtr,
558 pBp->u.Int3.PhysAddr, pVM->dbgf.s.cEnabledInt3Breakpoints));
559 }
560 }
[1]561 return rc;
562}
563
564
565/**
[64770]566 * @callback_method_impl{FNVMMEMTRENDEZVOUS}
567 */
568static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpDisableInt3OnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
569{
570 /*
571 * Validate input.
572 */
573 PDBGFBP pBp = (PDBGFBP)pvUser;
574 AssertReturn(pBp, VERR_INVALID_PARAMETER);
575 Assert(pBp->enmType == DBGFBPTYPE_INT3);
576 VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu);
577 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
578
579 /*
580 * Disarm the breakpoint.
581 */
582 return dbgfR3BpInt3Disarm(pVM, pBp);
583}
584
585
586/**
[1]587 * Sets a register breakpoint.
588 *
589 * @returns VBox status code.
[44399]590 * @param pUVM The user mode VM handle.
[1]591 * @param pAddress The address of the breakpoint.
592 * @param piHitTrigger The hit count at which the breakpoint start triggering.
593 * Use 0 (or 1) if it's gonna trigger at once.
594 * @param piHitDisable The hit count which disables the breakpoint.
595 * Use ~(uint64_t) if it's never gonna be disabled.
596 * @param fType The access type (one of the X86_DR7_RW_* defines).
597 * @param cb The access size - 1,2,4 or 8 (the latter is AMD64 long mode only.
598 * Must be 1 if fType is X86_DR7_RW_EO.
599 * @param piBp Where to store the breakpoint id. (optional)
600 * @thread EMT
601 * @internal
602 */
[44399]603static DECLCALLBACK(int) dbgfR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable,
[35694]604 uint8_t fType, uint8_t cb, uint32_t *piBp)
[1]605{
606 /*
607 * Validate input.
608 */
[44399]609 PVM pVM = pUVM->pVM;
610 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
611 if (!DBGFR3AddrIsValid(pUVM, pAddress))
[1]612 return VERR_INVALID_PARAMETER;
613 if (*piHitTrigger > *piHitDisable)
614 return VERR_INVALID_PARAMETER;
615 AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
616 if (piBp)
[62637]617 *piBp = UINT32_MAX;
[1]618 switch (fType)
619 {
620 case X86_DR7_RW_EO:
621 if (cb == 1)
622 break;
623 AssertMsgFailed(("fType=%#x cb=%d != 1\n", fType, cb));
624 return VERR_INVALID_PARAMETER;
625 case X86_DR7_RW_IO:
626 case X86_DR7_RW_RW:
627 case X86_DR7_RW_WO:
628 break;
629 default:
630 AssertMsgFailed(("fType=%#x\n", fType));
631 return VERR_INVALID_PARAMETER;
632 }
633 switch (cb)
634 {
635 case 1:
636 case 2:
637 case 4:
638 break;
639 default:
640 AssertMsgFailed(("cb=%#x\n", cb));
641 return VERR_INVALID_PARAMETER;
642 }
643
644 /*
645 * Check if the breakpoint already exists.
646 */
647 PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REG, pAddress->FlatPtr);
648 if ( pBp
649 && pBp->u.Reg.cb == cb
650 && pBp->u.Reg.fType == fType)
651 {
652 int rc = VINF_SUCCESS;
653 if (!pBp->fEnabled)
654 rc = dbgfR3BpRegArm(pVM, pBp);
[13816]655 if (RT_SUCCESS(rc))
[1]656 {
657 rc = VINF_DBGF_BP_ALREADY_EXIST;
658 if (piBp)
659 *piBp = pBp->iBp;
660 }
661 return rc;
662 }
663
664 /*
665 * Allocate and initialize the bp.
666 */
667 pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REG);
668 if (!pBp)
669 return VERR_DBGF_NO_MORE_BP_SLOTS;
670 pBp->iHitTrigger = *piHitTrigger;
671 pBp->iHitDisable = *piHitDisable;
672 Assert(pBp->iBp == pBp->u.Reg.iReg);
[58903]673 pBp->u.Reg.GCPtr = pAddress->FlatPtr;
[1]674 pBp->u.Reg.fType = fType;
675 pBp->u.Reg.cb = cb;
[58903]676 ASMCompilerBarrier();
677 pBp->fEnabled = true;
[1]678
679 /*
680 * Arm the breakpoint.
681 */
682 int rc = dbgfR3BpRegArm(pVM, pBp);
[13816]683 if (RT_SUCCESS(rc))
[1]684 {
685 if (piBp)
686 *piBp = pBp->iBp;
687 }
688 else
689 dbgfR3BpFree(pVM, pBp);
690
691 return rc;
692}
693
694
695/**
[44399]696 * Sets a register breakpoint.
[1]697 *
698 * @returns VBox status code.
[44399]699 * @param pUVM The user mode VM handle.
700 * @param pAddress The address of the breakpoint.
701 * @param iHitTrigger The hit count at which the breakpoint start triggering.
702 * Use 0 (or 1) if it's gonna trigger at once.
703 * @param iHitDisable The hit count which disables the breakpoint.
704 * Use ~(uint64_t) if it's never gonna be disabled.
705 * @param fType The access type (one of the X86_DR7_RW_* defines).
706 * @param cb The access size - 1,2,4 or 8 (the latter is AMD64 long mode only.
707 * Must be 1 if fType is X86_DR7_RW_EO.
708 * @param piBp Where to store the breakpoint id. (optional)
709 * @thread Any thread.
[1]710 */
[44399]711VMMR3DECL(int) DBGFR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable,
712 uint8_t fType, uint8_t cb, uint32_t *piBp)
[1]713{
[44399]714 /*
715 * This must be done on EMT.
716 */
[58909]717 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetReg, 7,
[44517]718 pUVM, pAddress, &iHitTrigger, &iHitDisable, fType, cb, piBp);
[44399]719 LogFlow(("DBGFR3BpSetReg: returns %Rrc\n", rc));
720 return rc;
[18927]721
[44399]722}
723
724
[58126]725/**
726 * @callback_method_impl{FNVMMEMTRENDEZVOUS}
727 */
[58909]728static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpRegRecalcOnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
[44399]729{
730 NOREF(pVM); NOREF(pvUser);
[58909]731
732 /*
733 * CPU 0 updates the enabled hardware breakpoint counts.
734 */
735 if (pVCpu->idCpu == 0)
736 {
737 pVM->dbgf.s.cEnabledHwBreakpoints = 0;
738 pVM->dbgf.s.cEnabledHwIoBreakpoints = 0;
739
740 for (uint32_t iBp = 0; iBp < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); iBp++)
741 if ( pVM->dbgf.s.aHwBreakpoints[iBp].fEnabled
742 && pVM->dbgf.s.aHwBreakpoints[iBp].enmType == DBGFBPTYPE_REG)
743 {
744 pVM->dbgf.s.cEnabledHwBreakpoints += 1;
745 pVM->dbgf.s.cEnabledHwIoBreakpoints += pVM->dbgf.s.aHwBreakpoints[iBp].u.Reg.fType == X86_DR7_RW_IO;
746 }
747 }
748
[47714]749 return CPUMRecalcHyperDRx(pVCpu, UINT8_MAX, false);
[1]750}
751
752
753/**
[44399]754 * Arms a debug register breakpoint.
[58909]755 *
[44399]756 * This is used to implement both DBGFR3BpSetReg() and DBGFR3BpEnable().
[1]757 *
758 * @returns VBox status code.
[58122]759 * @param pVM The cross context VM structure.
[1]760 * @param pBp The breakpoint.
[58909]761 * @thread EMT(0)
[1]762 */
[44399]763static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp)
[1]764{
[62637]765 RT_NOREF_PV(pBp);
[44399]766 Assert(pBp->fEnabled);
767 return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpRegRecalcOnCpu, NULL);
[1]768}
769
770
771/**
[44399]772 * Disarms a debug register breakpoint.
[58909]773 *
[44399]774 * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable().
[1]775 *
776 * @returns VBox status code.
[58122]777 * @param pVM The cross context VM structure.
[44399]778 * @param pBp The breakpoint.
[58909]779 * @thread EMT(0)
[1]780 */
[44399]781static int dbgfR3BpRegDisarm(PVM pVM, PDBGFBP pBp)
[1]782{
[62637]783 RT_NOREF_PV(pBp);
[44399]784 Assert(!pBp->fEnabled);
785 return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpRegRecalcOnCpu, NULL);
[1]786}
787
788
789/**
790 * EMT worker for DBGFR3BpSetREM().
791 *
792 * @returns VBox status code.
[44399]793 * @param pUVM The user mode VM handle.
[1]794 * @param pAddress The address of the breakpoint.
795 * @param piHitTrigger The hit count at which the breakpoint start triggering.
796 * Use 0 (or 1) if it's gonna trigger at once.
797 * @param piHitDisable The hit count which disables the breakpoint.
798 * Use ~(uint64_t) if it's never gonna be disabled.
799 * @param piBp Where to store the breakpoint id. (optional)
[58909]800 * @thread EMT(0)
[1]801 * @internal
802 */
[44399]803static DECLCALLBACK(int) dbgfR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger,
804 uint64_t *piHitDisable, uint32_t *piBp)
[1]805{
806 /*
807 * Validate input.
808 */
[44399]809 PVM pVM = pUVM->pVM;
810 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
811 if (!DBGFR3AddrIsValid(pUVM, pAddress))
[1]812 return VERR_INVALID_PARAMETER;
813 if (*piHitTrigger > *piHitDisable)
814 return VERR_INVALID_PARAMETER;
815 AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
816 if (piBp)
[62637]817 *piBp = UINT32_MAX;
[1]818
819 /*
820 * Check if the breakpoint already exists.
821 */
822 PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REM, pAddress->FlatPtr);
823 if (pBp)
824 {
825 int rc = VINF_SUCCESS;
826 if (!pBp->fEnabled)
[40274]827#ifdef VBOX_WITH_REM
[58903]828 rc = REMR3BreakpointSet(pVM, pBp->u.Rem.GCPtr);
[40274]829#else
[58903]830 rc = IEMBreakpointSet(pVM, pBp->u.Rem.GCPtr);
[40274]831#endif
[13816]832 if (RT_SUCCESS(rc))
[1]833 {
834 rc = VINF_DBGF_BP_ALREADY_EXIST;
835 if (piBp)
836 *piBp = pBp->iBp;
837 }
838 return rc;
839 }
840
841 /*
842 * Allocate and initialize the bp.
843 */
844 pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REM);
845 if (!pBp)
846 return VERR_DBGF_NO_MORE_BP_SLOTS;
[58903]847 pBp->u.Rem.GCPtr = pAddress->FlatPtr;
[1]848 pBp->iHitTrigger = *piHitTrigger;
849 pBp->iHitDisable = *piHitDisable;
[58903]850 ASMCompilerBarrier();
[1]851 pBp->fEnabled = true;
852
853 /*
854 * Now ask REM to set the breakpoint.
855 */
[40274]856#ifdef VBOX_WITH_REM
[1]857 int rc = REMR3BreakpointSet(pVM, pAddress->FlatPtr);
[40274]858#else
859 int rc = IEMBreakpointSet(pVM, pAddress->FlatPtr);
860#endif
[13816]861 if (RT_SUCCESS(rc))
[1]862 {
863 if (piBp)
864 *piBp = pBp->iBp;
865 }
866 else
867 dbgfR3BpFree(pVM, pBp);
868
869 return rc;
870}
871
872
873/**
[44399]874 * Sets a recompiler breakpoint.
[1]875 *
876 * @returns VBox status code.
[44399]877 * @param pUVM The user mode VM handle.
878 * @param pAddress The address of the breakpoint.
879 * @param iHitTrigger The hit count at which the breakpoint start triggering.
880 * Use 0 (or 1) if it's gonna trigger at once.
881 * @param iHitDisable The hit count which disables the breakpoint.
882 * Use ~(uint64_t) if it's never gonna be disabled.
883 * @param piBp Where to store the breakpoint id. (optional)
[1]884 * @thread Any thread.
885 */
[44399]886VMMR3DECL(int) DBGFR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp)
[1]887{
888 /*
[38838]889 * This must be done on EMT.
[1]890 */
[58909]891 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetREM, 5,
[44517]892 pUVM, pAddress, &iHitTrigger, &iHitDisable, piBp);
[44399]893 LogFlow(("DBGFR3BpSetREM: returns %Rrc\n", rc));
[1]894 return rc;
895}
896
897
898/**
[58903]899 * Updates IOM on whether we've got any armed I/O port or MMIO breakpoints.
900 *
901 * @returns VINF_SUCCESS
902 * @param pVM The cross context VM structure.
[58909]903 * @thread EMT(0)
[58903]904 */
905static int dbgfR3BpUpdateIom(PVM pVM)
906{
[58909]907 dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_PORT_IO, &pVM->dbgf.s.PortIo);
908 if (pVM->dbgf.s.PortIo.cToSearch)
909 ASMAtomicBitSet(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_BREAKPOINT_IO);
910 else
911 ASMAtomicBitClear(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_BREAKPOINT_IO);
[58903]912
[58909]913 dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_MMIO, &pVM->dbgf.s.Mmio);
914 if (pVM->dbgf.s.Mmio.cToSearch)
915 ASMAtomicBitSet(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_BREAKPOINT_MMIO);
916 else
917 ASMAtomicBitClear(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_BREAKPOINT_MMIO);
[58903]918
[58909]919 IOMR3NotifyBreakpointCountChange(pVM, pVM->dbgf.s.PortIo.cToSearch != 0, pVM->dbgf.s.Mmio.cToSearch != 0);
[58903]920 return VINF_SUCCESS;
921}
922
923
924/**
925 * EMT worker for DBGFR3BpSetPortIo.
926 *
927 * @returns VBox status code.
928 * @param pUVM The user mode VM handle.
929 * @param uPort The first I/O port.
930 * @param cPorts The number of I/O ports.
931 * @param fAccess The access we want to break on.
932 * @param piHitTrigger The hit count at which the breakpoint start triggering.
933 * Use 0 (or 1) if it's gonna trigger at once.
934 * @param piHitDisable The hit count which disables the breakpoint.
935 * Use ~(uint64_t) if it's never gonna be disabled.
936 * @param piBp Where to store the breakpoint ID.
[58909]937 * @thread EMT(0)
[58903]938 */
939static DECLCALLBACK(int) dbgfR3BpSetPortIo(PUVM pUVM, RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess,
940 uint64_t const *piHitTrigger, uint64_t const *piHitDisable, uint32_t *piBp)
941{
942 /*
943 * Validate input.
944 */
945 PVM pVM = pUVM->pVM;
946 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
[62637]947 *piBp = UINT32_MAX;
[58903]948
949 /*
950 * Check if the breakpoint already exists.
951 */
952 for (uint32_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
953 if ( pVM->dbgf.s.aBreakpoints[i].enmType == DBGFBPTYPE_PORT_IO
954 && pVM->dbgf.s.aBreakpoints[i].u.PortIo.uPort == uPort
955 && pVM->dbgf.s.aBreakpoints[i].u.PortIo.cPorts == cPorts
956 && pVM->dbgf.s.aBreakpoints[i].u.PortIo.fAccess == fAccess)
957 {
958 if (!pVM->dbgf.s.aBreakpoints[i].fEnabled)
959 {
960 pVM->dbgf.s.aBreakpoints[i].fEnabled = true;
961 dbgfR3BpUpdateIom(pVM);
962 }
963 *piBp = pVM->dbgf.s.aBreakpoints[i].iBp;
964 return VINF_DBGF_BP_ALREADY_EXIST;
965 }
966
967 /*
968 * Allocate and initialize the breakpoint.
969 */
970 PDBGFBP pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_PORT_IO);
971 if (!pBp)
972 return VERR_DBGF_NO_MORE_BP_SLOTS;
973 pBp->iHitTrigger = *piHitTrigger;
974 pBp->iHitDisable = *piHitDisable;
975 pBp->u.PortIo.uPort = uPort;
976 pBp->u.PortIo.cPorts = cPorts;
977 pBp->u.PortIo.fAccess = fAccess;
978 ASMCompilerBarrier();
979 pBp->fEnabled = true;
980
981 /*
982 * Tell IOM.
983 */
984 dbgfR3BpUpdateIom(pVM);
985 *piBp = pBp->iBp;
986 return VINF_SUCCESS;
987}
988
989
990/**
991 * Sets an I/O port breakpoint.
992 *
993 * @returns VBox status code.
[58916]994 * @param pUVM The user mode VM handle.
[58903]995 * @param uPort The first I/O port.
996 * @param cPorts The number of I/O ports, see DBGFBPIOACCESS_XXX.
997 * @param fAccess The access we want to break on.
998 * @param iHitTrigger The hit count at which the breakpoint start
999 * triggering. Use 0 (or 1) if it's gonna trigger at
1000 * once.
1001 * @param iHitDisable The hit count which disables the breakpoint.
1002 * Use ~(uint64_t) if it's never gonna be disabled.
1003 * @param piBp Where to store the breakpoint ID. Optional.
[58909]1004 * @thread Any thread.
[58903]1005 */
1006VMMR3DECL(int) DBGFR3BpSetPortIo(PUVM pUVM, RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess,
1007 uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp)
1008{
1009 AssertReturn(!(fAccess & ~DBGFBPIOACCESS_VALID_MASK_PORT_IO), VERR_INVALID_FLAGS);
1010 AssertReturn(fAccess, VERR_INVALID_FLAGS);
1011 if (iHitTrigger > iHitDisable)
1012 return VERR_INVALID_PARAMETER;
1013 AssertPtrNullReturn(piBp, VERR_INVALID_POINTER);
1014 AssertReturn(cPorts > 0, VERR_OUT_OF_RANGE);
1015 AssertReturn((RTIOPORT)(uPort + cPorts) < uPort, VERR_OUT_OF_RANGE);
1016
1017 /*
1018 * This must be done on EMT.
1019 */
[62637]1020 uint32_t iBp = UINT32_MAX;
[58909]1021 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetPortIo, 7,
[58903]1022 pUVM, uPort, cPorts, fAccess, &iHitTrigger, &iHitDisable, piBp);
1023 if (piBp)
1024 *piBp = iBp;
[58909]1025 LogFlow(("DBGFR3BpSetPortIo: returns %Rrc iBp=%d\n", rc, iBp));
[58903]1026 return rc;
1027}
1028
1029
1030/**
1031 * EMT worker for DBGFR3BpSetMmio.
1032 *
1033 * @returns VBox status code.
1034 * @param pUVM The user mode VM handle.
1035 * @param pGCPhys The start of the MMIO range to break on.
[64530]1036 * @param cb The size of the MMIO range.
[58903]1037 * @param fAccess The access we want to break on.
1038 * @param piHitTrigger The hit count at which the breakpoint start triggering.
1039 * Use 0 (or 1) if it's gonna trigger at once.
1040 * @param piHitDisable The hit count which disables the breakpoint.
1041 * Use ~(uint64_t) if it's never gonna be disabled.
1042 * @param piBp Where to store the breakpoint ID.
[58909]1043 * @thread EMT(0)
[58903]1044 */
1045static DECLCALLBACK(int) dbgfR3BpSetMmio(PUVM pUVM, PCRTGCPHYS pGCPhys, uint32_t cb, uint32_t fAccess,
1046 uint64_t const *piHitTrigger, uint64_t const *piHitDisable, uint32_t *piBp)
1047{
1048 RTGCPHYS const GCPhys = *pGCPhys;
1049
1050 /*
1051 * Validate input.
1052 */
1053 PVM pVM = pUVM->pVM;
1054 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
[62637]1055 *piBp = UINT32_MAX;
[58903]1056
1057 /*
1058 * Check if the breakpoint already exists.
1059 */
1060 for (uint32_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
1061 if ( pVM->dbgf.s.aBreakpoints[i].enmType == DBGFBPTYPE_MMIO
1062 && pVM->dbgf.s.aBreakpoints[i].u.Mmio.PhysAddr == GCPhys
1063 && pVM->dbgf.s.aBreakpoints[i].u.Mmio.cb == cb
1064 && pVM->dbgf.s.aBreakpoints[i].u.Mmio.fAccess == fAccess)
1065 {
1066 if (!pVM->dbgf.s.aBreakpoints[i].fEnabled)
1067 {
1068 pVM->dbgf.s.aBreakpoints[i].fEnabled = true;
1069 dbgfR3BpUpdateIom(pVM);
1070 }
1071 *piBp = pVM->dbgf.s.aBreakpoints[i].iBp;
1072 return VINF_DBGF_BP_ALREADY_EXIST;
1073 }
1074
1075 /*
1076 * Allocate and initialize the breakpoint.
1077 */
[64770]1078 PDBGFBP pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_MMIO);
[58903]1079 if (!pBp)
1080 return VERR_DBGF_NO_MORE_BP_SLOTS;
1081 pBp->iHitTrigger = *piHitTrigger;
1082 pBp->iHitDisable = *piHitDisable;
1083 pBp->u.Mmio.PhysAddr = GCPhys;
1084 pBp->u.Mmio.cb = cb;
1085 pBp->u.Mmio.fAccess = fAccess;
1086 ASMCompilerBarrier();
1087 pBp->fEnabled = true;
1088
1089 /*
1090 * Tell IOM.
1091 */
1092 dbgfR3BpUpdateIom(pVM);
1093 *piBp = pBp->iBp;
1094 return VINF_SUCCESS;
1095}
1096
1097
1098/**
1099 * Sets a memory mapped I/O breakpoint.
1100 *
1101 * @returns VBox status code.
[58916]1102 * @param pUVM The user mode VM handle.
[58903]1103 * @param GCPhys The first MMIO address.
1104 * @param cb The size of the MMIO range to break on.
1105 * @param fAccess The access we want to break on.
1106 * @param iHitTrigger The hit count at which the breakpoint start
1107 * triggering. Use 0 (or 1) if it's gonna trigger at
1108 * once.
1109 * @param iHitDisable The hit count which disables the breakpoint.
1110 * Use ~(uint64_t) if it's never gonna be disabled.
1111 * @param piBp Where to store the breakpoint ID. Optional.
[58909]1112 * @thread Any thread.
[58903]1113 */
1114VMMR3DECL(int) DBGFR3BpSetMmio(PUVM pUVM, RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess,
1115 uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp)
1116{
1117 AssertReturn(!(fAccess & ~DBGFBPIOACCESS_VALID_MASK_MMIO), VERR_INVALID_FLAGS);
1118 AssertReturn(fAccess, VERR_INVALID_FLAGS);
1119 if (iHitTrigger > iHitDisable)
1120 return VERR_INVALID_PARAMETER;
1121 AssertPtrNullReturn(piBp, VERR_INVALID_POINTER);
1122 AssertReturn(cb, VERR_OUT_OF_RANGE);
1123 AssertReturn(GCPhys + cb < GCPhys, VERR_OUT_OF_RANGE);
1124
1125 /*
1126 * This must be done on EMT.
1127 */
[62637]1128 uint32_t iBp = UINT32_MAX;
[58909]1129 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetMmio, 7,
[58903]1130 pUVM, &GCPhys, cb, fAccess, &iHitTrigger, &iHitDisable, piBp);
1131 if (piBp)
1132 *piBp = iBp;
[58909]1133 LogFlow(("DBGFR3BpSetMmio: returns %Rrc iBp=%d\n", rc, iBp));
[58903]1134 return rc;
1135}
1136
1137
1138/**
[1]1139 * EMT worker for DBGFR3BpClear().
1140 *
1141 * @returns VBox status code.
[44399]1142 * @param pUVM The user mode VM handle.
[1]1143 * @param iBp The id of the breakpoint which should be removed (cleared).
[58909]1144 * @thread EMT(0)
[1]1145 * @internal
1146 */
[44399]1147static DECLCALLBACK(int) dbgfR3BpClear(PUVM pUVM, uint32_t iBp)
[1]1148{
1149 /*
1150 * Validate input.
1151 */
[44399]1152 PVM pVM = pUVM->pVM;
[64770]1153 VM_ASSERT_EMT(pVM);
[44399]1154 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
[1]1155 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
1156 if (!pBp)
1157 return VERR_DBGF_BP_NOT_FOUND;
1158
1159 /*
1160 * Disarm the breakpoint if it's enabled.
1161 */
1162 if (pBp->fEnabled)
1163 {
1164 pBp->fEnabled = false;
1165 int rc;
1166 switch (pBp->enmType)
1167 {
1168 case DBGFBPTYPE_REG:
1169 rc = dbgfR3BpRegDisarm(pVM, pBp);
1170 break;
1171
1172 case DBGFBPTYPE_INT3:
[64770]1173 rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3BpDisableInt3OnCpu, pBp);
[1]1174 break;
1175
1176 case DBGFBPTYPE_REM:
[40274]1177#ifdef VBOX_WITH_REM
[58903]1178 rc = REMR3BreakpointClear(pVM, pBp->u.Rem.GCPtr);
[40274]1179#else
[58903]1180 rc = IEMBreakpointClear(pVM, pBp->u.Rem.GCPtr);
[40274]1181#endif
[1]1182 break;
1183
[58903]1184 case DBGFBPTYPE_PORT_IO:
1185 case DBGFBPTYPE_MMIO:
1186 rc = dbgfR3BpUpdateIom(pVM);
1187 break;
1188
[1]1189 default:
[39405]1190 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
[1]1191 }
1192 AssertRCReturn(rc, rc);
1193 }
1194
1195 /*
1196 * Free the breakpoint.
1197 */
1198 dbgfR3BpFree(pVM, pBp);
1199 return VINF_SUCCESS;
1200}
1201
1202
1203/**
[44399]1204 * Clears a breakpoint.
[1]1205 *
1206 * @returns VBox status code.
[44399]1207 * @param pUVM The user mode VM handle.
1208 * @param iBp The id of the breakpoint which should be removed (cleared).
[1]1209 * @thread Any thread.
1210 */
[44399]1211VMMR3DECL(int) DBGFR3BpClear(PUVM pUVM, uint32_t iBp)
[1]1212{
1213 /*
[38838]1214 * This must be done on EMT.
[1]1215 */
[58909]1216 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpClear, 2, pUVM, iBp);
[44399]1217 LogFlow(("DBGFR3BpClear: returns %Rrc\n", rc));
[1]1218 return rc;
1219}
1220
1221
1222/**
1223 * EMT worker for DBGFR3BpEnable().
1224 *
1225 * @returns VBox status code.
[44399]1226 * @param pUVM The user mode VM handle.
[1]1227 * @param iBp The id of the breakpoint which should be enabled.
[58909]1228 * @thread EMT(0)
[1]1229 * @internal
1230 */
[44399]1231static DECLCALLBACK(int) dbgfR3BpEnable(PUVM pUVM, uint32_t iBp)
[1]1232{
1233 /*
1234 * Validate input.
1235 */
[44399]1236 PVM pVM = pUVM->pVM;
1237 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
[1]1238 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
1239 if (!pBp)
1240 return VERR_DBGF_BP_NOT_FOUND;
1241
1242 /*
1243 * Already enabled?
1244 */
1245 if (pBp->fEnabled)
1246 return VINF_DBGF_BP_ALREADY_ENABLED;
1247
1248 /*
[64770]1249 * Arm the breakpoint.
[1]1250 */
1251 int rc;
1252 pBp->fEnabled = true;
1253 switch (pBp->enmType)
1254 {
1255 case DBGFBPTYPE_REG:
1256 rc = dbgfR3BpRegArm(pVM, pBp);
1257 break;
1258
1259 case DBGFBPTYPE_INT3:
[64770]1260 rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3BpEnableInt3OnCpu, pBp);
[1]1261 break;
1262
1263 case DBGFBPTYPE_REM:
[40274]1264#ifdef VBOX_WITH_REM
[58903]1265 rc = REMR3BreakpointSet(pVM, pBp->u.Rem.GCPtr);
[40274]1266#else
[58903]1267 rc = IEMBreakpointSet(pVM, pBp->u.Rem.GCPtr);
[40274]1268#endif
[1]1269 break;
1270
[58903]1271 case DBGFBPTYPE_PORT_IO:
1272 case DBGFBPTYPE_MMIO:
1273 rc = dbgfR3BpUpdateIom(pVM);
1274 break;
1275
[1]1276 default:
[39405]1277 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
[1]1278 }
[13816]1279 if (RT_FAILURE(rc))
[1]1280 pBp->fEnabled = false;
1281
1282 return rc;
1283}
1284
1285
1286/**
[44399]1287 * Enables a breakpoint.
[1]1288 *
1289 * @returns VBox status code.
[44399]1290 * @param pUVM The user mode VM handle.
1291 * @param iBp The id of the breakpoint which should be enabled.
[1]1292 * @thread Any thread.
1293 */
[44399]1294VMMR3DECL(int) DBGFR3BpEnable(PUVM pUVM, uint32_t iBp)
[1]1295{
1296 /*
[38838]1297 * This must be done on EMT.
[1]1298 */
[58909]1299 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpEnable, 2, pUVM, iBp);
[44399]1300 LogFlow(("DBGFR3BpEnable: returns %Rrc\n", rc));
[1]1301 return rc;
1302}
1303
1304
1305/**
1306 * EMT worker for DBGFR3BpDisable().
1307 *
1308 * @returns VBox status code.
[44399]1309 * @param pUVM The user mode VM handle.
[1]1310 * @param iBp The id of the breakpoint which should be disabled.
[58909]1311 * @thread EMT(0)
[1]1312 * @internal
1313 */
[44399]1314static DECLCALLBACK(int) dbgfR3BpDisable(PUVM pUVM, uint32_t iBp)
[1]1315{
1316 /*
1317 * Validate input.
1318 */
[44399]1319 PVM pVM = pUVM->pVM;
1320 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
[1]1321 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
1322 if (!pBp)
1323 return VERR_DBGF_BP_NOT_FOUND;
1324
1325 /*
1326 * Already enabled?
1327 */
1328 if (!pBp->fEnabled)
1329 return VINF_DBGF_BP_ALREADY_DISABLED;
1330
1331 /*
1332 * Remove the breakpoint.
1333 */
1334 pBp->fEnabled = false;
1335 int rc;
1336 switch (pBp->enmType)
1337 {
1338 case DBGFBPTYPE_REG:
1339 rc = dbgfR3BpRegDisarm(pVM, pBp);
1340 break;
1341
1342 case DBGFBPTYPE_INT3:
[64770]1343 rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3BpDisableInt3OnCpu, pBp);
[1]1344 break;
1345
1346 case DBGFBPTYPE_REM:
[40274]1347#ifdef VBOX_WITH_REM
[58903]1348 rc = REMR3BreakpointClear(pVM, pBp->u.Rem.GCPtr);
[40274]1349#else
[58903]1350 rc = IEMBreakpointClear(pVM, pBp->u.Rem.GCPtr);
[40274]1351#endif
[1]1352 break;
1353
[58903]1354 case DBGFBPTYPE_PORT_IO:
1355 case DBGFBPTYPE_MMIO:
1356 rc = dbgfR3BpUpdateIom(pVM);
1357 break;
1358
[1]1359 default:
[39405]1360 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
[1]1361 }
1362
1363 return rc;
1364}
1365
1366
1367/**
[44399]1368 * Disables a breakpoint.
[1]1369 *
1370 * @returns VBox status code.
[44399]1371 * @param pUVM The user mode VM handle.
1372 * @param iBp The id of the breakpoint which should be disabled.
1373 * @thread Any thread.
[1]1374 */
[44399]1375VMMR3DECL(int) DBGFR3BpDisable(PUVM pUVM, uint32_t iBp)
[1]1376{
1377 /*
[38838]1378 * This must be done on EMT.
[1]1379 */
[58909]1380 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpDisable, 2, pUVM, iBp);
[44399]1381 LogFlow(("DBGFR3BpDisable: returns %Rrc\n", rc));
[1]1382 return rc;
1383}
1384
1385
1386/**
1387 * EMT worker for DBGFR3BpEnum().
1388 *
1389 * @returns VBox status code.
[44399]1390 * @param pUVM The user mode VM handle.
[1]1391 * @param pfnCallback The callback function.
1392 * @param pvUser The user argument to pass to the callback.
1393 * @thread EMT
1394 * @internal
1395 */
[44399]1396static DECLCALLBACK(int) dbgfR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
[1]1397{
1398 /*
1399 * Validate input.
1400 */
[44399]1401 PVM pVM = pUVM->pVM;
1402 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1403 AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
[1]1404
1405 /*
1406 * Enumerate the hardware breakpoints.
1407 */
1408 unsigned i;
[11311]1409 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
[1]1410 if (pVM->dbgf.s.aHwBreakpoints[i].enmType != DBGFBPTYPE_FREE)
1411 {
[44399]1412 int rc = pfnCallback(pUVM, pvUser, &pVM->dbgf.s.aHwBreakpoints[i]);
[58909]1413 if (RT_FAILURE(rc) || rc == VINF_CALLBACK_RETURN)
[1]1414 return rc;
1415 }
1416
1417 /*
1418 * Enumerate the other breakpoints.
1419 */
[11311]1420 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
[1]1421 if (pVM->dbgf.s.aBreakpoints[i].enmType != DBGFBPTYPE_FREE)
1422 {
[44399]1423 int rc = pfnCallback(pUVM, pvUser, &pVM->dbgf.s.aBreakpoints[i]);
[58909]1424 if (RT_FAILURE(rc) || rc == VINF_CALLBACK_RETURN)
[1]1425 return rc;
1426 }
1427
1428 return VINF_SUCCESS;
1429}
1430
[44399]1431
1432/**
1433 * Enumerate the breakpoints.
1434 *
1435 * @returns VBox status code.
1436 * @param pUVM The user mode VM handle.
1437 * @param pfnCallback The callback function.
1438 * @param pvUser The user argument to pass to the callback.
1439 * @thread Any thread but the callback will be called from EMT.
1440 */
1441VMMR3DECL(int) DBGFR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
1442{
1443 /*
1444 * This must be done on EMT.
1445 */
[58909]1446 int rc = VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpEnum, 3, pUVM, pfnCallback, pvUser);
[64770]1447 LogFlow(("DBGFR3BpEnum: returns %Rrc\n", rc));
[44399]1448 return rc;
1449}
1450
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use