VirtualBox

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

Last change on this file since 74795 was 69111, checked in by vboxsync, 7 years ago

(C) year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 43.6 KB
Line 
1/* $Id: DBGFBp.cpp 69111 2017-10-17 14:26:02Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Breakpoint Management.
4 */
5
6/*
7 * Copyright (C) 2006-2017 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#ifdef VBOX_WITH_REM
26# include <VBox/vmm/rem.h>
27#else
28# include <VBox/vmm/iem.h>
29#endif
30#include <VBox/vmm/mm.h>
31#include <VBox/vmm/iom.h>
32#include <VBox/vmm/hm.h>
33#include "DBGFInternal.h"
34#include <VBox/vmm/vm.h>
35#include <VBox/vmm/uvm.h>
36
37#include <VBox/err.h>
38#include <VBox/log.h>
39#include <iprt/assert.h>
40#include <iprt/string.h>
41
42
43/*********************************************************************************************************************************
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/*********************************************************************************************************************************
67* Internal Functions *
68*********************************************************************************************************************************/
69RT_C_DECLS_BEGIN
70static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp);
71static int dbgfR3BpInt3Arm(PVM pVM, PDBGFBP pBp);
72RT_C_DECLS_END
73
74
75
76/**
77 * Initialize the breakpoint stuff.
78 *
79 * @returns VINF_SUCCESS
80 * @param pVM The cross context VM structure.
81 */
82int dbgfR3BpInit(PVM pVM)
83{
84 /*
85 * Init structures.
86 */
87 unsigned i;
88 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
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
95 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
96 {
97 pVM->dbgf.s.aBreakpoints[i].iBp = i + RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
98 pVM->dbgf.s.aBreakpoints[i].enmType = DBGFBPTYPE_FREE;
99 }
100
101 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
102 {
103 PVMCPU pVCpu = &pVM->aCpus[idCpu];
104 pVCpu->dbgf.s.iActiveBp = ~0U;
105 }
106
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.
122 * @param pVM The cross context VM structure.
123 * @param enmType The type to allocate.
124 */
125static PDBGFBP dbgfR3BpAlloc(PVM pVM, DBGFBPTYPE enmType)
126{
127 /*
128 * Determine which array to search and where in the array to start
129 * searching (latter for grouping similar BPs, reducing runtime overhead).
130 */
131 unsigned iStart;
132 unsigned cBps;
133 PDBGFBP paBps;
134 switch (enmType)
135 {
136 case DBGFBPTYPE_REG:
137 cBps = RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
138 paBps = &pVM->dbgf.s.aHwBreakpoints[0];
139 iStart = 0;
140 break;
141
142 case DBGFBPTYPE_INT3:
143 case DBGFBPTYPE_REM:
144 case DBGFBPTYPE_PORT_IO:
145 case DBGFBPTYPE_MMIO:
146 cBps = RT_ELEMENTS(pVM->dbgf.s.aBreakpoints);
147 paBps = &pVM->dbgf.s.aBreakpoints[0];
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;
156 break;
157
158 default:
159 AssertMsgFailed(("enmType=%d\n", enmType));
160 return NULL;
161 }
162
163 /*
164 * Search for a free breakpoint entry.
165 */
166 unsigned iBp;
167 for (iBp = iStart; iBp < cBps; iBp++)
168 if (paBps[iBp].enmType == DBGFBPTYPE_FREE)
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/**
191 * Updates the search optimization structure for enabled breakpoints of the
192 * specified type.
193 *
194 * @returns VINF_SUCCESS.
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)
206 {
207 if (Opt.iStartSearch > iBp)
208 Opt.iStartSearch = iBp;
209 Opt.cToSearch = iBp - Opt.iStartSearch + 1;
210 }
211
212 *pOpt = Opt;
213 return VINF_SUCCESS;
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.
222 * @param pVM The cross context VM structure.
223 * @param iBp The breakpoint id.
224 */
225static PDBGFBP dbgfR3BpGet(PVM pVM, uint32_t iBp)
226{
227 /* Find it. */
228 PDBGFBP pBp;
229 if (iBp < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints))
230 pBp = &pVM->dbgf.s.aHwBreakpoints[iBp];
231 else
232 {
233 iBp -= RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
234 if (iBp >= RT_ELEMENTS(pVM->dbgf.s.aBreakpoints))
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:
248 case DBGFBPTYPE_PORT_IO:
249 case DBGFBPTYPE_MMIO:
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.
266 * @param pVM The cross context VM structure.
267 * @param enmType The breakpoint type.
268 * @param GCPtr The breakpoint address.
269 */
270static PDBGFBP dbgfR3BpGetByAddr(PVM pVM, DBGFBPTYPE enmType, RTGCUINTPTR GCPtr)
271{
272 /*
273 * Determine which array to search.
274 */
275 unsigned cBps;
276 PDBGFBP paBps;
277 switch (enmType)
278 {
279 case DBGFBPTYPE_REG:
280 cBps = RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
281 paBps = &pVM->dbgf.s.aHwBreakpoints[0];
282 break;
283
284 case DBGFBPTYPE_INT3:
285 case DBGFBPTYPE_REM:
286 cBps = RT_ELEMENTS(pVM->dbgf.s.aBreakpoints);
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++)
299 if ( paBps[iBp].enmType == enmType
300 && paBps[iBp].u.GCPtr == GCPtr)
301 return &paBps[iBp];
302
303 return NULL;
304}
305
306
307/**
308 * Frees a breakpoint.
309 *
310 * @param pVM The cross context VM structure.
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:
322 Assert((uintptr_t)(pBp - &pVM->dbgf.s.aHwBreakpoints[0]) < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints));
323 break;
324
325 case DBGFBPTYPE_INT3:
326 case DBGFBPTYPE_REM:
327 case DBGFBPTYPE_PORT_IO:
328 case DBGFBPTYPE_MMIO:
329 Assert((uintptr_t)(pBp - &pVM->dbgf.s.aBreakpoints[0]) < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints));
330 break;
331
332 default:
333 AssertMsgFailed(("Invalid enmType=%d!\n", pBp->enmType));
334 return;
335
336 }
337 pBp->enmType = DBGFBPTYPE_FREE;
338 NOREF(pVM);
339}
340
341
342/**
343 * @callback_method_impl{FNVMMEMTRENDEZVOUS}
344 */
345static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpEnableInt3OnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
346{
347 /*
348 * Validate input.
349 */
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);
354 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
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))
379 return VERR_INVALID_PARAMETER;
380
381 if (pBpArgs->iHitTrigger > pBpArgs->iHitDisable)
382 return VERR_INVALID_PARAMETER;
383
384 /*
385 * Check if we're on the source CPU where we can resolve the breakpoint address.
386 */
387 if (pVCpu->idCpu == pBpArgs->idSrcCpu)
388 {
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);
431 if (RT_SUCCESS(rc))
432 {
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 }
450 }
451
452 dbgfR3BpFree(pVM, pBp);
453 return rc;
454 }
455
456 return VINF_SUCCESS;
457}
458
459
460/**
461 * Sets a breakpoint (int 3 based).
462 *
463 * @returns VBox status code.
464 * @param pUVM The user mode VM handle.
465 * @param idSrcCpu The ID of the virtual CPU used for the
466 * breakpoint address resolution.
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 */
475VMMR3DECL(int) DBGFR3BpSetInt3(PUVM pUVM, VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable,
476 uint32_t *piBp)
477{
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);
489 LogFlow(("DBGFR3BpSet: returns %Rrc\n", rc));
490 return rc;
491}
492
493
494/**
495 * Arms an int 3 breakpoint.
496 *
497 * This is used to implement both DBGFR3BpSetInt3() and
498 * DBGFR3BpEnable().
499 *
500 * @returns VBox status code.
501 * @param pVM The cross context VM structure.
502 * @param pBp The breakpoint.
503 */
504static int dbgfR3BpInt3Arm(PVM pVM, PDBGFBP pBp)
505{
506 VM_ASSERT_EMT(pVM);
507
508 /*
509 * Save current byte and write the int3 instruction byte.
510 */
511 int rc = PGMPhysSimpleReadGCPhys(pVM, &pBp->u.Int3.bOrg, pBp->u.Int3.PhysAddr, sizeof(pBp->u.Int3.bOrg));
512 if (RT_SUCCESS(rc))
513 {
514 static const uint8_t s_bInt3 = 0xcc;
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 }
524 }
525 return rc;
526}
527
528
529/**
530 * Disarms an int 3 breakpoint.
531 *
532 * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable().
533 *
534 * @returns VBox status code.
535 * @param pVM The cross context VM structure.
536 * @param pBp The breakpoint.
537 */
538static int dbgfR3BpInt3Disarm(PVM pVM, PDBGFBP pBp)
539{
540 VM_ASSERT_EMT(pVM);
541
542 /*
543 * Check that the current byte is the int3 instruction, and restore the original one.
544 * We currently ignore invalid bytes.
545 */
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 }
561 return rc;
562}
563
564
565/**
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/**
587 * Sets a register breakpoint.
588 *
589 * @returns VBox status code.
590 * @param pUVM The user mode VM handle.
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 */
603static DECLCALLBACK(int) dbgfR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable,
604 uint8_t fType, uint8_t cb, uint32_t *piBp)
605{
606 /*
607 * Validate input.
608 */
609 PVM pVM = pUVM->pVM;
610 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
611 if (!DBGFR3AddrIsValid(pUVM, pAddress))
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)
617 *piBp = UINT32_MAX;
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);
655 if (RT_SUCCESS(rc))
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);
673 pBp->u.Reg.GCPtr = pAddress->FlatPtr;
674 pBp->u.Reg.fType = fType;
675 pBp->u.Reg.cb = cb;
676 ASMCompilerBarrier();
677 pBp->fEnabled = true;
678
679 /*
680 * Arm the breakpoint.
681 */
682 int rc = dbgfR3BpRegArm(pVM, pBp);
683 if (RT_SUCCESS(rc))
684 {
685 if (piBp)
686 *piBp = pBp->iBp;
687 }
688 else
689 dbgfR3BpFree(pVM, pBp);
690
691 return rc;
692}
693
694
695/**
696 * Sets a register breakpoint.
697 *
698 * @returns VBox status code.
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.
710 */
711VMMR3DECL(int) DBGFR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable,
712 uint8_t fType, uint8_t cb, uint32_t *piBp)
713{
714 /*
715 * This must be done on EMT.
716 */
717 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetReg, 7,
718 pUVM, pAddress, &iHitTrigger, &iHitDisable, fType, cb, piBp);
719 LogFlow(("DBGFR3BpSetReg: returns %Rrc\n", rc));
720 return rc;
721
722}
723
724
725/**
726 * @callback_method_impl{FNVMMEMTRENDEZVOUS}
727 */
728static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpRegRecalcOnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
729{
730 NOREF(pVM); NOREF(pvUser);
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
749 return CPUMRecalcHyperDRx(pVCpu, UINT8_MAX, false);
750}
751
752
753/**
754 * Arms a debug register breakpoint.
755 *
756 * This is used to implement both DBGFR3BpSetReg() and DBGFR3BpEnable().
757 *
758 * @returns VBox status code.
759 * @param pVM The cross context VM structure.
760 * @param pBp The breakpoint.
761 * @thread EMT(0)
762 */
763static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp)
764{
765 RT_NOREF_PV(pBp);
766 Assert(pBp->fEnabled);
767 return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpRegRecalcOnCpu, NULL);
768}
769
770
771/**
772 * Disarms a debug register breakpoint.
773 *
774 * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable().
775 *
776 * @returns VBox status code.
777 * @param pVM The cross context VM structure.
778 * @param pBp The breakpoint.
779 * @thread EMT(0)
780 */
781static int dbgfR3BpRegDisarm(PVM pVM, PDBGFBP pBp)
782{
783 RT_NOREF_PV(pBp);
784 Assert(!pBp->fEnabled);
785 return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpRegRecalcOnCpu, NULL);
786}
787
788
789/**
790 * EMT worker for DBGFR3BpSetREM().
791 *
792 * @returns VBox status code.
793 * @param pUVM The user mode VM handle.
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)
800 * @thread EMT(0)
801 * @internal
802 */
803static DECLCALLBACK(int) dbgfR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger,
804 uint64_t *piHitDisable, uint32_t *piBp)
805{
806 /*
807 * Validate input.
808 */
809 PVM pVM = pUVM->pVM;
810 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
811 if (!DBGFR3AddrIsValid(pUVM, pAddress))
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)
817 *piBp = UINT32_MAX;
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)
827#ifdef VBOX_WITH_REM
828 rc = REMR3BreakpointSet(pVM, pBp->u.Rem.GCPtr);
829#else
830 rc = IEMBreakpointSet(pVM, pBp->u.Rem.GCPtr);
831#endif
832 if (RT_SUCCESS(rc))
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;
847 pBp->u.Rem.GCPtr = pAddress->FlatPtr;
848 pBp->iHitTrigger = *piHitTrigger;
849 pBp->iHitDisable = *piHitDisable;
850 ASMCompilerBarrier();
851 pBp->fEnabled = true;
852
853 /*
854 * Now ask REM to set the breakpoint.
855 */
856#ifdef VBOX_WITH_REM
857 int rc = REMR3BreakpointSet(pVM, pAddress->FlatPtr);
858#else
859 int rc = IEMBreakpointSet(pVM, pAddress->FlatPtr);
860#endif
861 if (RT_SUCCESS(rc))
862 {
863 if (piBp)
864 *piBp = pBp->iBp;
865 }
866 else
867 dbgfR3BpFree(pVM, pBp);
868
869 return rc;
870}
871
872
873/**
874 * Sets a recompiler breakpoint.
875 *
876 * @returns VBox status code.
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)
884 * @thread Any thread.
885 */
886VMMR3DECL(int) DBGFR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp)
887{
888 /*
889 * This must be done on EMT.
890 */
891 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetREM, 5,
892 pUVM, pAddress, &iHitTrigger, &iHitDisable, piBp);
893 LogFlow(("DBGFR3BpSetREM: returns %Rrc\n", rc));
894 return rc;
895}
896
897
898/**
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.
903 * @thread EMT(0)
904 */
905static int dbgfR3BpUpdateIom(PVM pVM)
906{
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);
912
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);
918
919 IOMR3NotifyBreakpointCountChange(pVM, pVM->dbgf.s.PortIo.cToSearch != 0, pVM->dbgf.s.Mmio.cToSearch != 0);
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.
937 * @thread EMT(0)
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);
947 *piBp = UINT32_MAX;
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.
994 * @param pUVM The user mode VM handle.
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.
1004 * @thread Any thread.
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 */
1020 uint32_t iBp = UINT32_MAX;
1021 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetPortIo, 7,
1022 pUVM, uPort, cPorts, fAccess, &iHitTrigger, &iHitDisable, piBp);
1023 if (piBp)
1024 *piBp = iBp;
1025 LogFlow(("DBGFR3BpSetPortIo: returns %Rrc iBp=%d\n", rc, iBp));
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.
1036 * @param cb The size of the MMIO range.
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.
1043 * @thread EMT(0)
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);
1055 *piBp = UINT32_MAX;
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 */
1078 PDBGFBP pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_MMIO);
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.
1102 * @param pUVM The user mode VM handle.
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.
1112 * @thread Any thread.
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 */
1128 uint32_t iBp = UINT32_MAX;
1129 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetMmio, 7,
1130 pUVM, &GCPhys, cb, fAccess, &iHitTrigger, &iHitDisable, piBp);
1131 if (piBp)
1132 *piBp = iBp;
1133 LogFlow(("DBGFR3BpSetMmio: returns %Rrc iBp=%d\n", rc, iBp));
1134 return rc;
1135}
1136
1137
1138/**
1139 * EMT worker for DBGFR3BpClear().
1140 *
1141 * @returns VBox status code.
1142 * @param pUVM The user mode VM handle.
1143 * @param iBp The id of the breakpoint which should be removed (cleared).
1144 * @thread EMT(0)
1145 * @internal
1146 */
1147static DECLCALLBACK(int) dbgfR3BpClear(PUVM pUVM, uint32_t iBp)
1148{
1149 /*
1150 * Validate input.
1151 */
1152 PVM pVM = pUVM->pVM;
1153 VM_ASSERT_EMT(pVM);
1154 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
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:
1173 rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3BpDisableInt3OnCpu, pBp);
1174 break;
1175
1176 case DBGFBPTYPE_REM:
1177#ifdef VBOX_WITH_REM
1178 rc = REMR3BreakpointClear(pVM, pBp->u.Rem.GCPtr);
1179#else
1180 rc = IEMBreakpointClear(pVM, pBp->u.Rem.GCPtr);
1181#endif
1182 break;
1183
1184 case DBGFBPTYPE_PORT_IO:
1185 case DBGFBPTYPE_MMIO:
1186 rc = dbgfR3BpUpdateIom(pVM);
1187 break;
1188
1189 default:
1190 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
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/**
1204 * Clears a breakpoint.
1205 *
1206 * @returns VBox status code.
1207 * @param pUVM The user mode VM handle.
1208 * @param iBp The id of the breakpoint which should be removed (cleared).
1209 * @thread Any thread.
1210 */
1211VMMR3DECL(int) DBGFR3BpClear(PUVM pUVM, uint32_t iBp)
1212{
1213 /*
1214 * This must be done on EMT.
1215 */
1216 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpClear, 2, pUVM, iBp);
1217 LogFlow(("DBGFR3BpClear: returns %Rrc\n", rc));
1218 return rc;
1219}
1220
1221
1222/**
1223 * EMT worker for DBGFR3BpEnable().
1224 *
1225 * @returns VBox status code.
1226 * @param pUVM The user mode VM handle.
1227 * @param iBp The id of the breakpoint which should be enabled.
1228 * @thread EMT(0)
1229 * @internal
1230 */
1231static DECLCALLBACK(int) dbgfR3BpEnable(PUVM pUVM, uint32_t iBp)
1232{
1233 /*
1234 * Validate input.
1235 */
1236 PVM pVM = pUVM->pVM;
1237 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
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 /*
1249 * Arm the breakpoint.
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:
1260 rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3BpEnableInt3OnCpu, pBp);
1261 break;
1262
1263 case DBGFBPTYPE_REM:
1264#ifdef VBOX_WITH_REM
1265 rc = REMR3BreakpointSet(pVM, pBp->u.Rem.GCPtr);
1266#else
1267 rc = IEMBreakpointSet(pVM, pBp->u.Rem.GCPtr);
1268#endif
1269 break;
1270
1271 case DBGFBPTYPE_PORT_IO:
1272 case DBGFBPTYPE_MMIO:
1273 rc = dbgfR3BpUpdateIom(pVM);
1274 break;
1275
1276 default:
1277 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
1278 }
1279 if (RT_FAILURE(rc))
1280 pBp->fEnabled = false;
1281
1282 return rc;
1283}
1284
1285
1286/**
1287 * Enables a breakpoint.
1288 *
1289 * @returns VBox status code.
1290 * @param pUVM The user mode VM handle.
1291 * @param iBp The id of the breakpoint which should be enabled.
1292 * @thread Any thread.
1293 */
1294VMMR3DECL(int) DBGFR3BpEnable(PUVM pUVM, uint32_t iBp)
1295{
1296 /*
1297 * This must be done on EMT.
1298 */
1299 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpEnable, 2, pUVM, iBp);
1300 LogFlow(("DBGFR3BpEnable: returns %Rrc\n", rc));
1301 return rc;
1302}
1303
1304
1305/**
1306 * EMT worker for DBGFR3BpDisable().
1307 *
1308 * @returns VBox status code.
1309 * @param pUVM The user mode VM handle.
1310 * @param iBp The id of the breakpoint which should be disabled.
1311 * @thread EMT(0)
1312 * @internal
1313 */
1314static DECLCALLBACK(int) dbgfR3BpDisable(PUVM pUVM, uint32_t iBp)
1315{
1316 /*
1317 * Validate input.
1318 */
1319 PVM pVM = pUVM->pVM;
1320 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
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:
1343 rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3BpDisableInt3OnCpu, pBp);
1344 break;
1345
1346 case DBGFBPTYPE_REM:
1347#ifdef VBOX_WITH_REM
1348 rc = REMR3BreakpointClear(pVM, pBp->u.Rem.GCPtr);
1349#else
1350 rc = IEMBreakpointClear(pVM, pBp->u.Rem.GCPtr);
1351#endif
1352 break;
1353
1354 case DBGFBPTYPE_PORT_IO:
1355 case DBGFBPTYPE_MMIO:
1356 rc = dbgfR3BpUpdateIom(pVM);
1357 break;
1358
1359 default:
1360 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
1361 }
1362
1363 return rc;
1364}
1365
1366
1367/**
1368 * Disables a breakpoint.
1369 *
1370 * @returns VBox status code.
1371 * @param pUVM The user mode VM handle.
1372 * @param iBp The id of the breakpoint which should be disabled.
1373 * @thread Any thread.
1374 */
1375VMMR3DECL(int) DBGFR3BpDisable(PUVM pUVM, uint32_t iBp)
1376{
1377 /*
1378 * This must be done on EMT.
1379 */
1380 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpDisable, 2, pUVM, iBp);
1381 LogFlow(("DBGFR3BpDisable: returns %Rrc\n", rc));
1382 return rc;
1383}
1384
1385
1386/**
1387 * EMT worker for DBGFR3BpEnum().
1388 *
1389 * @returns VBox status code.
1390 * @param pUVM The user mode VM handle.
1391 * @param pfnCallback The callback function.
1392 * @param pvUser The user argument to pass to the callback.
1393 * @thread EMT
1394 * @internal
1395 */
1396static DECLCALLBACK(int) dbgfR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
1397{
1398 /*
1399 * Validate input.
1400 */
1401 PVM pVM = pUVM->pVM;
1402 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1403 AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
1404
1405 /*
1406 * Enumerate the hardware breakpoints.
1407 */
1408 unsigned i;
1409 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
1410 if (pVM->dbgf.s.aHwBreakpoints[i].enmType != DBGFBPTYPE_FREE)
1411 {
1412 int rc = pfnCallback(pUVM, pvUser, &pVM->dbgf.s.aHwBreakpoints[i]);
1413 if (RT_FAILURE(rc) || rc == VINF_CALLBACK_RETURN)
1414 return rc;
1415 }
1416
1417 /*
1418 * Enumerate the other breakpoints.
1419 */
1420 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
1421 if (pVM->dbgf.s.aBreakpoints[i].enmType != DBGFBPTYPE_FREE)
1422 {
1423 int rc = pfnCallback(pUVM, pvUser, &pVM->dbgf.s.aBreakpoints[i]);
1424 if (RT_FAILURE(rc) || rc == VINF_CALLBACK_RETURN)
1425 return rc;
1426 }
1427
1428 return VINF_SUCCESS;
1429}
1430
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 */
1446 int rc = VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpEnum, 3, pUVM, pfnCallback, pvUser);
1447 LogFlow(("DBGFR3BpEnum: returns %Rrc\n", rc));
1448 return rc;
1449}
1450
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use