VirtualBox

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

Last change on this file since 84044 was 82968, checked in by vboxsync, 4 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 43.1 KB
Line 
1/* $Id: DBGFBp.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Breakpoint Management.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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 LOG_GROUP LOG_GROUP_DBGF
23#include <VBox/vmm/dbgf.h>
24#include <VBox/vmm/selm.h>
25#include <VBox/vmm/iem.h>
26#include <VBox/vmm/mm.h>
27#include <VBox/vmm/iom.h>
28#include <VBox/vmm/hm.h>
29#include "DBGFInternal.h"
30#include <VBox/vmm/vm.h>
31#include <VBox/vmm/uvm.h>
32
33#include <VBox/err.h>
34#include <VBox/log.h>
35#include <iprt/assert.h>
36#include <iprt/string.h>
37
38
39/*********************************************************************************************************************************
40* Structures and Typedefs *
41*********************************************************************************************************************************/
42/**
43 * DBGF INT3-breakpoint set callback arguments.
44 */
45typedef 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. */
59typedef DBGFBPINT3ARGS *PDBGFBPINT3ARGS;
60
61
62/*********************************************************************************************************************************
63* Internal Functions *
64*********************************************************************************************************************************/
65RT_C_DECLS_BEGIN
66static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp);
67static int dbgfR3BpInt3Arm(PVM pVM, PDBGFBP pBp);
68RT_C_DECLS_END
69
70
71
72/**
73 * Initialize the breakpoint stuff.
74 *
75 * @returns VINF_SUCCESS
76 * @param pVM The cross context VM structure.
77 */
78int dbgfR3BpInit(PVM pVM)
79{
80 /*
81 * Init structures.
82 */
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
103 /*
104 * Register saved state.
105 */
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 */
121static 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 */
195static 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 */
221static 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 */
266static 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 */
309static 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 */
341static 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 */
362static 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;
453}
454
455
456/**
457 * Sets a breakpoint (int 3 based).
458 *
459 * @returns VBox status code.
460 * @param pUVM The user mode VM handle.
461 * @param idSrcCpu The ID of the virtual CPU used for the
462 * breakpoint address resolution.
463 * @param pAddress The address of the breakpoint.
464 * @param iHitTrigger The hit count at which the breakpoint start triggering.
465 * Use 0 (or 1) if it's gonna trigger at once.
466 * @param iHitDisable The hit count which disables the breakpoint.
467 * 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 */
471VMMR3DECL(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 */
500static 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 */
534static 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 */
564static 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);
579}
580
581
582/**
583 * Sets a register breakpoint.
584 *
585 * @returns VBox status code.
586 * @param pUVM The user mode VM handle.
587 * @param pAddress The address of the breakpoint.
588 * @param piHitTrigger The hit count at which the breakpoint start triggering.
589 * Use 0 (or 1) if it's gonna trigger at once.
590 * @param piHitDisable The hit count which disables the breakpoint.
591 * Use ~(uint64_t) if it's never gonna be disabled.
592 * @param fType The access type (one of the X86_DR7_RW_* defines).
593 * @param cb The access size - 1,2,4 or 8 (the latter is AMD64 long mode only.
594 * 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 */
599static 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;
614 switch (fType)
615 {
616 case X86_DR7_RW_EO:
617 if (cb == 1)
618 break;
619 AssertMsgFailed(("fType=%#x cb=%d != 1\n", fType, cb));
620 return VERR_INVALID_PARAMETER;
621 case X86_DR7_RW_IO:
622 case X86_DR7_RW_RW:
623 case X86_DR7_RW_WO:
624 break;
625 default:
626 AssertMsgFailed(("fType=%#x\n", fType));
627 return VERR_INVALID_PARAMETER;
628 }
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 */
707VMMR3DECL(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 */
724static 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 */
759static 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 */
777static 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 */
799static 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 */
874VMMR3DECL(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 */
893static 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 */
927static 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;
975}
976
977
978/**
979 * Sets an I/O port breakpoint.
980 *
981 * @returns VBox status code.
982 * @param pUVM The user mode VM handle.
983 * @param uPort The first I/O port.
984 * @param cPorts The number of I/O ports, see DBGFBPIOACCESS_XXX.
985 * @param fAccess The access we want to break on.
986 * @param iHitTrigger The hit count at which the breakpoint start
987 * triggering. Use 0 (or 1) if it's gonna trigger at
988 * once.
989 * @param iHitDisable The hit count which disables the breakpoint.
990 * 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 */
994VMMR3DECL(int) DBGFR3BpSetPortIo(PUVM pUVM, RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess,
995 uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp)
996{
997 AssertReturn(!(fAccess & ~DBGFBPIOACCESS_VALID_MASK_PORT_IO), VERR_INVALID_FLAGS);
998 AssertReturn(fAccess, VERR_INVALID_FLAGS);
999 if (iHitTrigger > iHitDisable)
1000 return VERR_INVALID_PARAMETER;
1001 AssertPtrNullReturn(piBp, VERR_INVALID_POINTER);
1002 AssertReturn(cPorts > 0, VERR_OUT_OF_RANGE);
1003 AssertReturn((RTIOPORT)(uPort + cPorts) < uPort, VERR_OUT_OF_RANGE);
1004
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 */
1033static 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;
1083}
1084
1085
1086/**
1087 * Sets a memory mapped I/O breakpoint.
1088 *
1089 * @returns VBox status code.
1090 * @param pUVM The user mode VM handle.
1091 * @param GCPhys The first MMIO address.
1092 * @param cb The size of the MMIO range to break on.
1093 * @param fAccess The access we want to break on.
1094 * @param iHitTrigger The hit count at which the breakpoint start
1095 * triggering. Use 0 (or 1) if it's gonna trigger at
1096 * once.
1097 * @param iHitDisable The hit count which disables the breakpoint.
1098 * 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 */
1102VMMR3DECL(int) DBGFR3BpSetMmio(PUVM pUVM, RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess,
1103 uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp)
1104{
1105 AssertReturn(!(fAccess & ~DBGFBPIOACCESS_VALID_MASK_MMIO), VERR_INVALID_FLAGS);
1106 AssertReturn(fAccess, VERR_INVALID_FLAGS);
1107 if (iHitTrigger > iHitDisable)
1108 return VERR_INVALID_PARAMETER;
1109 AssertPtrNullReturn(piBp, VERR_INVALID_POINTER);
1110 AssertReturn(cb, VERR_OUT_OF_RANGE);
1111 AssertReturn(GCPhys + cb < GCPhys, VERR_OUT_OF_RANGE);
1112
1113 /*
1114 * This must be done on EMT.
1115 */
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 */
1135static 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 */
1195VMMR3DECL(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 */
1215static 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 */
1274VMMR3DECL(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 */
1294static 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 */
1351VMMR3DECL(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;
1359}
1360
1361
1362/**
1363 * EMT worker for DBGFR3BpEnum().
1364 *
1365 * @returns VBox status code.
1366 * @param pUVM The user mode VM handle.
1367 * @param pfnCallback The callback function.
1368 * @param pvUser The user argument to pass to the callback.
1369 * @thread EMT
1370 * @internal
1371 */
1372static DECLCALLBACK(int) dbgfR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
1373{
1374 /*
1375 * Validate input.
1376 */
1377 PVM pVM = pUVM->pVM;
1378 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1379 AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
1380
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;
1405}
1406
1407
1408/**
1409 * Enumerate the breakpoints.
1410 *
1411 * @returns VBox status code.
1412 * @param pUVM The user mode VM handle.
1413 * @param pfnCallback The callback function.
1414 * @param pvUser The user argument to pass to the callback.
1415 * @thread Any thread but the callback will be called from EMT.
1416 */
1417VMMR3DECL(int) DBGFR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
1418{
1419 /*
1420 * This must be done on EMT.
1421 */
1422 int rc = VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpEnum, 3, pUVM, pfnCallback, pvUser);
1423 LogFlow(("DBGFR3BpEnum: returns %Rrc\n", rc));
1424 return rc;
1425}
1426
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use