VirtualBox

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

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

VMM/r3: Refactored VMCPU enumeration in preparation that aCpus will be replaced with a pointer array. Removed two raw-mode offset members from the CPUM and CPUMCPU sub-structures. bugref:9217 bugref:9517

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette