VirtualBox

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

Last change on this file since 43858 was 42834, checked in by vboxsync, 12 years ago

dbgfR3BpInit: initialize DBGFCPU::iActiveBp to ~0U for all cpus. This
ensures that when we hit our first non-hardware breakpoint
DBGFR3EventBreakpoint will be on the right track.

XXX: I'm not sure if here is the right place to do it, but it looks
most suitable.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 26.9 KB
Line 
1/* $Id: DBGFBp.cpp 42834 2012-08-16 00:23:20Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Breakpoint Management.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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 "DBGFInternal.h"
31#include <VBox/vmm/vm.h>
32#include <VBox/vmm/mm.h>
33#include <VBox/err.h>
34#include <VBox/log.h>
35#include <iprt/assert.h>
36#include <iprt/string.h>
37
38
39/*******************************************************************************
40* Internal Functions *
41*******************************************************************************/
42RT_C_DECLS_BEGIN
43static DECLCALLBACK(int) dbgfR3BpSetReg(PVM pVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable,
44 uint8_t u8Type, uint8_t cb, uint32_t *piBp);
45static DECLCALLBACK(int) dbgfR3BpSetInt3(PVM pVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable, uint32_t *piBp);
46static DECLCALLBACK(int) dbgfR3BpSetREM(PVM pVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable, uint32_t *piBp);
47static DECLCALLBACK(int) dbgfR3BpClear(PVM pVM, uint32_t iBp);
48static DECLCALLBACK(int) dbgfR3BpEnable(PVM pVM, uint32_t iBp);
49static DECLCALLBACK(int) dbgfR3BpDisable(PVM pVM, uint32_t iBp);
50static DECLCALLBACK(int) dbgfR3BpEnum(PVM pVM, PFNDBGFBPENUM pfnCallback, void *pvUser);
51static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp);
52static int dbgfR3BpRegDisarm(PVM pVM, PDBGFBP pBp);
53static int dbgfR3BpInt3Arm(PVM pVM, PDBGFBP pBp);
54static int dbgfR3BpInt3Disarm(PVM pVM, PDBGFBP pBp);
55RT_C_DECLS_END
56
57
58
59/**
60 * Initialize the breakpoint stuff.
61 *
62 * @returns VINF_SUCCESS
63 * @param pVM Pointer to the VM.
64 */
65int dbgfR3BpInit(PVM pVM)
66{
67 /*
68 * Init structures.
69 */
70 unsigned i;
71 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
72 {
73 pVM->dbgf.s.aHwBreakpoints[i].iBp = i;
74 pVM->dbgf.s.aHwBreakpoints[i].enmType = DBGFBPTYPE_FREE;
75 pVM->dbgf.s.aHwBreakpoints[i].u.Reg.iReg = i;
76 }
77
78 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
79 {
80 pVM->dbgf.s.aBreakpoints[i].iBp = i + RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
81 pVM->dbgf.s.aBreakpoints[i].enmType = DBGFBPTYPE_FREE;
82 }
83
84 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
85 {
86 PVMCPU pVCpu = &pVM->aCpus[idCpu];
87 pVCpu->dbgf.s.iActiveBp = ~0U;
88 }
89
90 /*
91 * Register saved state.
92 */
93 /** @todo */
94
95 return VINF_SUCCESS;
96}
97
98
99
100/**
101 * Allocate a breakpoint.
102 *
103 * @returns Pointer to the allocated breakpoint.
104 * @returns NULL if we're out of breakpoints.
105 * @param pVM Pointer to the VM.
106 * @param enmType The type to allocate.
107 */
108static PDBGFBP dbgfR3BpAlloc(PVM pVM, DBGFBPTYPE enmType)
109{
110 /*
111 * Determine which array to search.
112 */
113 unsigned cBps;
114 uint32_t *pcBpsCur;
115 PDBGFBP paBps;
116 switch (enmType)
117 {
118 case DBGFBPTYPE_REG:
119 cBps = RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
120 paBps = &pVM->dbgf.s.aHwBreakpoints[0];
121 pcBpsCur = &pVM->dbgf.s.cHwBreakpoints;
122 break;
123
124 case DBGFBPTYPE_INT3:
125 case DBGFBPTYPE_REM:
126 cBps = RT_ELEMENTS(pVM->dbgf.s.aBreakpoints);
127 paBps = &pVM->dbgf.s.aBreakpoints[0];
128 pcBpsCur = &pVM->dbgf.s.cBreakpoints;
129 break;
130
131 default:
132 AssertMsgFailed(("enmType=%d\n", enmType));
133 return NULL;
134 }
135
136 /*
137 * Search.
138 */
139 for (unsigned iBp = 0; iBp < cBps; iBp++)
140 if (paBps[iBp].enmType == DBGFBPTYPE_FREE)
141 {
142 ++*pcBpsCur;
143 paBps[iBp].cHits = 0;
144 paBps[iBp].enmType = enmType;
145 return &paBps[iBp];
146 }
147
148 LogFlow(("dbgfR3BpAlloc: returns NULL - we're out of breakpoint slots! %u/%u\n", *pcBpsCur, cBps));
149 return NULL;
150}
151
152
153/**
154 * Get a breakpoint give by breakpoint id.
155 *
156 * @returns Pointer to the allocated breakpoint.
157 * @returns NULL if the breakpoint is invalid.
158 * @param pVM Pointer to the VM.
159 * @param iBp The breakpoint id.
160 */
161static PDBGFBP dbgfR3BpGet(PVM pVM, uint32_t iBp)
162{
163 /* Find it. */
164 PDBGFBP pBp;
165 if (iBp < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints))
166 pBp = &pVM->dbgf.s.aHwBreakpoints[iBp];
167 else
168 {
169 iBp -= RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
170 if (iBp >= RT_ELEMENTS(pVM->dbgf.s.aBreakpoints))
171 return NULL;
172 pBp = &pVM->dbgf.s.aBreakpoints[iBp];
173 }
174
175 /* check if it's valid. */
176 switch (pBp->enmType)
177 {
178 case DBGFBPTYPE_FREE:
179 return NULL;
180
181 case DBGFBPTYPE_REG:
182 case DBGFBPTYPE_INT3:
183 case DBGFBPTYPE_REM:
184 break;
185
186 default:
187 AssertMsgFailed(("Invalid enmType=%d!\n", pBp->enmType));
188 return NULL;
189 }
190
191 return pBp;
192}
193
194
195/**
196 * Get a breakpoint give by address.
197 *
198 * @returns Pointer to the allocated breakpoint.
199 * @returns NULL if the breakpoint is invalid.
200 * @param pVM Pointer to the VM.
201 * @param enmType The breakpoint type.
202 * @param GCPtr The breakpoint address.
203 */
204static PDBGFBP dbgfR3BpGetByAddr(PVM pVM, DBGFBPTYPE enmType, RTGCUINTPTR GCPtr)
205{
206 /*
207 * Determine which array to search.
208 */
209 unsigned cBps;
210 PDBGFBP paBps;
211 switch (enmType)
212 {
213 case DBGFBPTYPE_REG:
214 cBps = RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
215 paBps = &pVM->dbgf.s.aHwBreakpoints[0];
216 break;
217
218 case DBGFBPTYPE_INT3:
219 case DBGFBPTYPE_REM:
220 cBps = RT_ELEMENTS(pVM->dbgf.s.aBreakpoints);
221 paBps = &pVM->dbgf.s.aBreakpoints[0];
222 break;
223
224 default:
225 AssertMsgFailed(("enmType=%d\n", enmType));
226 return NULL;
227 }
228
229 /*
230 * Search.
231 */
232 for (unsigned iBp = 0; iBp < cBps; iBp++)
233 {
234 if ( paBps[iBp].enmType == enmType
235 && paBps[iBp].GCPtr == GCPtr)
236 return &paBps[iBp];
237 }
238
239 return NULL;
240}
241
242
243/**
244 * Frees a breakpoint.
245 *
246 * @param pVM Pointer to the VM.
247 * @param pBp The breakpoint to free.
248 */
249static void dbgfR3BpFree(PVM pVM, PDBGFBP pBp)
250{
251 switch (pBp->enmType)
252 {
253 case DBGFBPTYPE_FREE:
254 AssertMsgFailed(("Already freed!\n"));
255 return;
256
257 case DBGFBPTYPE_REG:
258 Assert(pVM->dbgf.s.cHwBreakpoints > 0);
259 pVM->dbgf.s.cHwBreakpoints--;
260 break;
261
262 case DBGFBPTYPE_INT3:
263 case DBGFBPTYPE_REM:
264 Assert(pVM->dbgf.s.cBreakpoints > 0);
265 pVM->dbgf.s.cBreakpoints--;
266 break;
267
268 default:
269 AssertMsgFailed(("Invalid enmType=%d!\n", pBp->enmType));
270 return;
271
272 }
273 pBp->enmType = DBGFBPTYPE_FREE;
274}
275
276
277/**
278 * Sets a breakpoint (int 3 based).
279 *
280 * @returns VBox status code.
281 * @param pVM Pointer to the VM.
282 * @param pAddress The address of the breakpoint.
283 * @param iHitTrigger The hit count at which the breakpoint start triggering.
284 * Use 0 (or 1) if it's gonna trigger at once.
285 * @param iHitDisable The hit count which disables the breakpoint.
286 * Use ~(uint64_t) if it's never gonna be disabled.
287 * @param piBp Where to store the breakpoint id. (optional)
288 * @thread Any thread.
289 */
290VMMR3DECL(int) DBGFR3BpSet(PVM pVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp)
291{
292 /*
293 * This must be done on EMT.
294 */
295 /** @todo SMP? */
296 int rc = VMR3ReqPriorityCallWait(pVM, VMCPUID_ANY, (PFNRT)dbgfR3BpSetInt3, 5, pVM, pAddress, &iHitTrigger, &iHitDisable, piBp);
297 LogFlow(("DBGFR3BpSet: returns %Rrc\n", rc));
298 return rc;
299}
300
301
302/**
303 * Sets a breakpoint (int 3 based).
304 *
305 * @returns VBox status code.
306 * @param pVM Pointer to the VM.
307 * @param pAddress The address of the breakpoint.
308 * @param piHitTrigger The hit count at which the breakpoint start triggering.
309 * Use 0 (or 1) if it's gonna trigger at once.
310 * @param piHitDisable The hit count which disables the breakpoint.
311 * Use ~(uint64_t) if it's never gonna be disabled.
312 * @param piBp Where to store the breakpoint id. (optional)
313 * @thread Any thread.
314 */
315static DECLCALLBACK(int) dbgfR3BpSetInt3(PVM pVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable, uint32_t *piBp)
316{
317 /*
318 * Validate input.
319 */
320 if (!DBGFR3AddrIsValid(pVM, pAddress))
321 return VERR_INVALID_PARAMETER;
322 if (*piHitTrigger > *piHitDisable)
323 return VERR_INVALID_PARAMETER;
324 AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
325 if (piBp)
326 *piBp = ~0;
327
328 /*
329 * Check if the breakpoint already exists.
330 */
331 PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_INT3, pAddress->FlatPtr);
332 if (pBp)
333 {
334 int rc = VINF_SUCCESS;
335 if (!pBp->fEnabled)
336 rc = dbgfR3BpInt3Arm(pVM, pBp);
337 if (RT_SUCCESS(rc))
338 {
339 rc = VINF_DBGF_BP_ALREADY_EXIST;
340 if (piBp)
341 *piBp = pBp->iBp;
342 }
343 return rc;
344 }
345
346 /*
347 * Allocate and initialize the bp.
348 */
349 pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_INT3);
350 if (!pBp)
351 return VERR_DBGF_NO_MORE_BP_SLOTS;
352 pBp->GCPtr = pAddress->FlatPtr;
353 pBp->iHitTrigger = *piHitTrigger;
354 pBp->iHitDisable = *piHitDisable;
355 pBp->fEnabled = true;
356
357 /*
358 * Now ask REM to set the breakpoint.
359 */
360 int rc = dbgfR3BpInt3Arm(pVM, pBp);
361 if (RT_SUCCESS(rc))
362 {
363 if (piBp)
364 *piBp = pBp->iBp;
365 }
366 else
367 dbgfR3BpFree(pVM, pBp);
368
369 return rc;
370}
371
372
373/**
374 * Arms an int 3 breakpoint.
375 * This is used to implement both DBGFR3BpSetReg() and DBGFR3BpEnable().
376 *
377 * @returns VBox status code.
378 * @param pVM Pointer to the VM.
379 * @param pBp The breakpoint.
380 */
381static int dbgfR3BpInt3Arm(PVM pVM, PDBGFBP pBp)
382{
383 /** @todo should actually use physical address here! */
384
385 /* @todo SMP support! */
386 VMCPUID idCpu = 0;
387
388 /*
389 * Save current byte and write int3 instruction.
390 */
391 DBGFADDRESS Addr;
392 DBGFR3AddrFromFlat(pVM, &Addr, pBp->GCPtr);
393 int rc = DBGFR3MemRead(pVM, idCpu, &Addr, &pBp->u.Int3.bOrg, 1);
394 if (RT_SUCCESS(rc))
395 {
396 static const uint8_t s_bInt3 = 0xcc;
397 rc = DBGFR3MemWrite(pVM, idCpu, &Addr, &s_bInt3, 1);
398 }
399 return rc;
400}
401
402
403/**
404 * Disarms an int 3 breakpoint.
405 * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable().
406 *
407 * @returns VBox status code.
408 * @param pVM Pointer to the VM.
409 * @param pBp The breakpoint.
410 */
411static int dbgfR3BpInt3Disarm(PVM pVM, PDBGFBP pBp)
412{
413 /* @todo SMP support! */
414 VMCPUID idCpu = 0;
415
416 /*
417 * Check that the current byte is the int3 instruction, and restore the original one.
418 * We currently ignore invalid bytes.
419 */
420 DBGFADDRESS Addr;
421 DBGFR3AddrFromFlat(pVM, &Addr, pBp->GCPtr);
422 uint8_t bCurrent;
423 int rc = DBGFR3MemRead(pVM, idCpu, &Addr, &bCurrent, 1);
424 if (bCurrent == 0xcc)
425 rc = DBGFR3MemWrite(pVM, idCpu, &Addr, &pBp->u.Int3.bOrg, 1);
426 return rc;
427}
428
429
430/**
431 * Sets a register breakpoint.
432 *
433 * @returns VBox status code.
434 * @param pVM Pointer to the VM.
435 * @param pAddress The address of the breakpoint.
436 * @param iHitTrigger The hit count at which the breakpoint start triggering.
437 * Use 0 (or 1) if it's gonna trigger at once.
438 * @param iHitDisable The hit count which disables the breakpoint.
439 * Use ~(uint64_t) if it's never gonna be disabled.
440 * @param fType The access type (one of the X86_DR7_RW_* defines).
441 * @param cb The access size - 1,2,4 or 8 (the latter is AMD64 long mode only.
442 * Must be 1 if fType is X86_DR7_RW_EO.
443 * @param piBp Where to store the breakpoint id. (optional)
444 * @thread Any thread.
445 */
446VMMR3DECL(int) DBGFR3BpSetReg(PVM pVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable,
447 uint8_t fType, uint8_t cb, uint32_t *piBp)
448{
449 /** @todo SMP - broadcast, VT-x/AMD-V. */
450 /*
451 * This must be done on EMT.
452 */
453 int rc = VMR3ReqPriorityCallWait(pVM, VMCPUID_ANY, (PFNRT)dbgfR3BpSetReg, 7, pVM, pAddress, &iHitTrigger, &iHitDisable, fType, cb, piBp);
454 LogFlow(("DBGFR3BpSetReg: returns %Rrc\n", rc));
455 return rc;
456
457}
458
459
460/**
461 * Sets a register breakpoint.
462 *
463 * @returns VBox status code.
464 * @param pVM Pointer to the VM.
465 * @param pAddress The address of the breakpoint.
466 * @param piHitTrigger The hit count at which the breakpoint start triggering.
467 * Use 0 (or 1) if it's gonna trigger at once.
468 * @param piHitDisable The hit count which disables the breakpoint.
469 * Use ~(uint64_t) if it's never gonna be disabled.
470 * @param fType The access type (one of the X86_DR7_RW_* defines).
471 * @param cb The access size - 1,2,4 or 8 (the latter is AMD64 long mode only.
472 * Must be 1 if fType is X86_DR7_RW_EO.
473 * @param piBp Where to store the breakpoint id. (optional)
474 * @thread EMT
475 * @internal
476 */
477static DECLCALLBACK(int) dbgfR3BpSetReg(PVM pVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable,
478 uint8_t fType, uint8_t cb, uint32_t *piBp)
479{
480 /*
481 * Validate input.
482 */
483 if (!DBGFR3AddrIsValid(pVM, pAddress))
484 return VERR_INVALID_PARAMETER;
485 if (*piHitTrigger > *piHitDisable)
486 return VERR_INVALID_PARAMETER;
487 AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
488 if (piBp)
489 *piBp = ~0;
490 switch (fType)
491 {
492 case X86_DR7_RW_EO:
493 if (cb == 1)
494 break;
495 AssertMsgFailed(("fType=%#x cb=%d != 1\n", fType, cb));
496 return VERR_INVALID_PARAMETER;
497 case X86_DR7_RW_IO:
498 case X86_DR7_RW_RW:
499 case X86_DR7_RW_WO:
500 break;
501 default:
502 AssertMsgFailed(("fType=%#x\n", fType));
503 return VERR_INVALID_PARAMETER;
504 }
505 switch (cb)
506 {
507 case 1:
508 case 2:
509 case 4:
510 break;
511 default:
512 AssertMsgFailed(("cb=%#x\n", cb));
513 return VERR_INVALID_PARAMETER;
514 }
515
516 /*
517 * Check if the breakpoint already exists.
518 */
519 PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REG, pAddress->FlatPtr);
520 if ( pBp
521 && pBp->u.Reg.cb == cb
522 && pBp->u.Reg.fType == fType)
523 {
524 int rc = VINF_SUCCESS;
525 if (!pBp->fEnabled)
526 rc = dbgfR3BpRegArm(pVM, pBp);
527 if (RT_SUCCESS(rc))
528 {
529 rc = VINF_DBGF_BP_ALREADY_EXIST;
530 if (piBp)
531 *piBp = pBp->iBp;
532 }
533 return rc;
534 }
535
536 /*
537 * Allocate and initialize the bp.
538 */
539 pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REG);
540 if (!pBp)
541 return VERR_DBGF_NO_MORE_BP_SLOTS;
542 pBp->GCPtr = pAddress->FlatPtr;
543 pBp->iHitTrigger = *piHitTrigger;
544 pBp->iHitDisable = *piHitDisable;
545 pBp->fEnabled = true;
546 Assert(pBp->iBp == pBp->u.Reg.iReg);
547 pBp->u.Reg.fType = fType;
548 pBp->u.Reg.cb = cb;
549
550 /*
551 * Arm the breakpoint.
552 */
553 int rc = dbgfR3BpRegArm(pVM, pBp);
554 if (RT_SUCCESS(rc))
555 {
556 if (piBp)
557 *piBp = pBp->iBp;
558 }
559 else
560 dbgfR3BpFree(pVM, pBp);
561
562 return rc;
563}
564
565
566/**
567 * Arms a debug register breakpoint.
568 * This is used to implement both DBGFR3BpSetReg() and DBGFR3BpEnable().
569 *
570 * @returns VBox status code.
571 * @param pVM Pointer to the VM.
572 * @param pBp The breakpoint.
573 */
574static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp)
575{
576 /* @todo SMP support! */
577 PVMCPU pVCpu = &pVM->aCpus[0];
578
579 Assert(pBp->fEnabled);
580 return CPUMRecalcHyperDRx(pVCpu);
581}
582
583
584/**
585 * Disarms a debug register breakpoint.
586 * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable().
587 *
588 * @returns VBox status code.
589 * @param pVM Pointer to the VM.
590 * @param pBp The breakpoint.
591 */
592static int dbgfR3BpRegDisarm(PVM pVM, PDBGFBP pBp)
593{
594 /** @todo SMP support! */
595 PVMCPU pVCpu = &pVM->aCpus[0];
596
597 Assert(!pBp->fEnabled);
598 return CPUMRecalcHyperDRx(pVCpu);
599}
600
601
602/**
603 * Sets a recompiler breakpoint.
604 *
605 * @returns VBox status code.
606 * @param pVM Pointer to the VM.
607 * @param pAddress The address of the breakpoint.
608 * @param iHitTrigger The hit count at which the breakpoint start triggering.
609 * Use 0 (or 1) if it's gonna trigger at once.
610 * @param iHitDisable The hit count which disables the breakpoint.
611 * Use ~(uint64_t) if it's never gonna be disabled.
612 * @param piBp Where to store the breakpoint id. (optional)
613 * @thread Any thread.
614 */
615VMMR3DECL(int) DBGFR3BpSetREM(PVM pVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp)
616{
617 /*
618 * This must be done on EMT.
619 */
620 int rc = VMR3ReqPriorityCallWait(pVM, VMCPUID_ANY, (PFNRT)dbgfR3BpSetREM, 5, pVM, pAddress, &iHitTrigger, &iHitDisable, piBp);
621 LogFlow(("DBGFR3BpSetREM: returns %Rrc\n", rc));
622 return rc;
623}
624
625
626/**
627 * EMT worker for DBGFR3BpSetREM().
628 *
629 * @returns VBox status code.
630 * @param pVM Pointer to the VM.
631 * @param pAddress The address of the breakpoint.
632 * @param piHitTrigger The hit count at which the breakpoint start triggering.
633 * Use 0 (or 1) if it's gonna trigger at once.
634 * @param piHitDisable The hit count which disables the breakpoint.
635 * Use ~(uint64_t) if it's never gonna be disabled.
636 * @param piBp Where to store the breakpoint id. (optional)
637 * @thread EMT
638 * @internal
639 */
640static DECLCALLBACK(int) dbgfR3BpSetREM(PVM pVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable, uint32_t *piBp)
641{
642 /*
643 * Validate input.
644 */
645 if (!DBGFR3AddrIsValid(pVM, pAddress))
646 return VERR_INVALID_PARAMETER;
647 if (*piHitTrigger > *piHitDisable)
648 return VERR_INVALID_PARAMETER;
649 AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
650 if (piBp)
651 *piBp = ~0;
652
653
654 /*
655 * Check if the breakpoint already exists.
656 */
657 PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REM, pAddress->FlatPtr);
658 if (pBp)
659 {
660 int rc = VINF_SUCCESS;
661 if (!pBp->fEnabled)
662#ifdef VBOX_WITH_REM
663 rc = REMR3BreakpointSet(pVM, pBp->GCPtr);
664#else
665 rc = IEMBreakpointSet(pVM, pBp->GCPtr);
666#endif
667 if (RT_SUCCESS(rc))
668 {
669 rc = VINF_DBGF_BP_ALREADY_EXIST;
670 if (piBp)
671 *piBp = pBp->iBp;
672 }
673 return rc;
674 }
675
676 /*
677 * Allocate and initialize the bp.
678 */
679 pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REM);
680 if (!pBp)
681 return VERR_DBGF_NO_MORE_BP_SLOTS;
682 pBp->GCPtr = pAddress->FlatPtr;
683 pBp->iHitTrigger = *piHitTrigger;
684 pBp->iHitDisable = *piHitDisable;
685 pBp->fEnabled = true;
686
687 /*
688 * Now ask REM to set the breakpoint.
689 */
690#ifdef VBOX_WITH_REM
691 int rc = REMR3BreakpointSet(pVM, pAddress->FlatPtr);
692#else
693 int rc = IEMBreakpointSet(pVM, pAddress->FlatPtr);
694#endif
695 if (RT_SUCCESS(rc))
696 {
697 if (piBp)
698 *piBp = pBp->iBp;
699 }
700 else
701 dbgfR3BpFree(pVM, pBp);
702
703 return rc;
704}
705
706
707/**
708 * Clears a breakpoint.
709 *
710 * @returns VBox status code.
711 * @param pVM Pointer to the VM.
712 * @param iBp The id of the breakpoint which should be removed (cleared).
713 * @thread Any thread.
714 */
715VMMR3DECL(int) DBGFR3BpClear(PVM pVM, uint32_t iBp)
716{
717 /*
718 * This must be done on EMT.
719 */
720 int rc = VMR3ReqPriorityCallWait(pVM, VMCPUID_ANY, (PFNRT)dbgfR3BpClear, 2, pVM, iBp);
721 LogFlow(("DBGFR3BpClear: returns %Rrc\n", rc));
722 return rc;
723}
724
725
726/**
727 * EMT worker for DBGFR3BpClear().
728 *
729 * @returns VBox status code.
730 * @param pVM Pointer to the VM.
731 * @param iBp The id of the breakpoint which should be removed (cleared).
732 * @thread EMT
733 * @internal
734 */
735static DECLCALLBACK(int) dbgfR3BpClear(PVM pVM, uint32_t iBp)
736{
737 /*
738 * Validate input.
739 */
740 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
741 if (!pBp)
742 return VERR_DBGF_BP_NOT_FOUND;
743
744 /*
745 * Disarm the breakpoint if it's enabled.
746 */
747 if (pBp->fEnabled)
748 {
749 pBp->fEnabled = false;
750 int rc;
751 switch (pBp->enmType)
752 {
753 case DBGFBPTYPE_REG:
754 rc = dbgfR3BpRegDisarm(pVM, pBp);
755 break;
756
757 case DBGFBPTYPE_INT3:
758 rc = dbgfR3BpInt3Disarm(pVM, pBp);
759 break;
760
761 case DBGFBPTYPE_REM:
762#ifdef VBOX_WITH_REM
763 rc = REMR3BreakpointClear(pVM, pBp->GCPtr);
764#else
765 rc = IEMBreakpointClear(pVM, pBp->GCPtr);
766#endif
767 break;
768
769 default:
770 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
771 }
772 AssertRCReturn(rc, rc);
773 }
774
775 /*
776 * Free the breakpoint.
777 */
778 dbgfR3BpFree(pVM, pBp);
779 return VINF_SUCCESS;
780}
781
782
783/**
784 * Enables a breakpoint.
785 *
786 * @returns VBox status code.
787 * @param pVM Pointer to the VM.
788 * @param iBp The id of the breakpoint which should be enabled.
789 * @thread Any thread.
790 */
791VMMR3DECL(int) DBGFR3BpEnable(PVM pVM, uint32_t iBp)
792{
793 /*
794 * This must be done on EMT.
795 */
796 int rc = VMR3ReqPriorityCallWait(pVM, VMCPUID_ANY, (PFNRT)dbgfR3BpEnable, 2, pVM, iBp);
797 LogFlow(("DBGFR3BpEnable: returns %Rrc\n", rc));
798 return rc;
799}
800
801
802/**
803 * EMT worker for DBGFR3BpEnable().
804 *
805 * @returns VBox status code.
806 * @param pVM Pointer to the VM.
807 * @param iBp The id of the breakpoint which should be enabled.
808 * @thread EMT
809 * @internal
810 */
811static DECLCALLBACK(int) dbgfR3BpEnable(PVM pVM, uint32_t iBp)
812{
813 /*
814 * Validate input.
815 */
816 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
817 if (!pBp)
818 return VERR_DBGF_BP_NOT_FOUND;
819
820 /*
821 * Already enabled?
822 */
823 if (pBp->fEnabled)
824 return VINF_DBGF_BP_ALREADY_ENABLED;
825
826 /*
827 * Remove the breakpoint.
828 */
829 int rc;
830 pBp->fEnabled = true;
831 switch (pBp->enmType)
832 {
833 case DBGFBPTYPE_REG:
834 rc = dbgfR3BpRegArm(pVM, pBp);
835 break;
836
837 case DBGFBPTYPE_INT3:
838 rc = dbgfR3BpInt3Arm(pVM, pBp);
839 break;
840
841 case DBGFBPTYPE_REM:
842#ifdef VBOX_WITH_REM
843 rc = REMR3BreakpointSet(pVM, pBp->GCPtr);
844#else
845 rc = IEMBreakpointSet(pVM, pBp->GCPtr);
846#endif
847 break;
848
849 default:
850 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
851 }
852 if (RT_FAILURE(rc))
853 pBp->fEnabled = false;
854
855 return rc;
856}
857
858
859/**
860 * Disables a breakpoint.
861 *
862 * @returns VBox status code.
863 * @param pVM Pointer to the VM.
864 * @param iBp The id of the breakpoint which should be disabled.
865 * @thread Any thread.
866 */
867VMMR3DECL(int) DBGFR3BpDisable(PVM pVM, uint32_t iBp)
868{
869 /*
870 * This must be done on EMT.
871 */
872 int rc = VMR3ReqPriorityCallWait(pVM, VMCPUID_ANY, (PFNRT)dbgfR3BpDisable, 2, pVM, iBp);
873 LogFlow(("DBGFR3BpDisable: returns %Rrc\n", rc));
874 return rc;
875}
876
877
878/**
879 * EMT worker for DBGFR3BpDisable().
880 *
881 * @returns VBox status code.
882 * @param pVM Pointer to the VM.
883 * @param iBp The id of the breakpoint which should be disabled.
884 * @thread EMT
885 * @internal
886 */
887static DECLCALLBACK(int) dbgfR3BpDisable(PVM pVM, uint32_t iBp)
888{
889 /*
890 * Validate input.
891 */
892 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
893 if (!pBp)
894 return VERR_DBGF_BP_NOT_FOUND;
895
896 /*
897 * Already enabled?
898 */
899 if (!pBp->fEnabled)
900 return VINF_DBGF_BP_ALREADY_DISABLED;
901
902 /*
903 * Remove the breakpoint.
904 */
905 pBp->fEnabled = false;
906 int rc;
907 switch (pBp->enmType)
908 {
909 case DBGFBPTYPE_REG:
910 rc = dbgfR3BpRegDisarm(pVM, pBp);
911 break;
912
913 case DBGFBPTYPE_INT3:
914 rc = dbgfR3BpInt3Disarm(pVM, pBp);
915 break;
916
917 case DBGFBPTYPE_REM:
918#ifdef VBOX_WITH_REM
919 rc = REMR3BreakpointClear(pVM, pBp->GCPtr);
920#else
921 rc = IEMBreakpointClear(pVM, pBp->GCPtr);
922#endif
923 break;
924
925 default:
926 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
927 }
928
929 return rc;
930}
931
932
933/**
934 * Enumerate the breakpoints.
935 *
936 * @returns VBox status code.
937 * @param pVM Pointer to the VM.
938 * @param pfnCallback The callback function.
939 * @param pvUser The user argument to pass to the callback.
940 * @thread Any thread but the callback will be called from EMT.
941 */
942VMMR3DECL(int) DBGFR3BpEnum(PVM pVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
943{
944 /*
945 * This must be done on EMT.
946 */
947 int rc = VMR3ReqPriorityCallWait(pVM, VMCPUID_ANY, (PFNRT)dbgfR3BpEnum, 3, pVM, pfnCallback, pvUser);
948 LogFlow(("DBGFR3BpClear: returns %Rrc\n", rc));
949 return rc;
950}
951
952
953/**
954 * EMT worker for DBGFR3BpEnum().
955 *
956 * @returns VBox status code.
957 * @param pVM Pointer to the VM.
958 * @param pfnCallback The callback function.
959 * @param pvUser The user argument to pass to the callback.
960 * @thread EMT
961 * @internal
962 */
963static DECLCALLBACK(int) dbgfR3BpEnum(PVM pVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
964{
965 /*
966 * Validate input.
967 */
968 AssertMsgReturn(VALID_PTR(pfnCallback), ("pfnCallback=%p\n", pfnCallback), VERR_INVALID_POINTER);
969
970 /*
971 * Enumerate the hardware breakpoints.
972 */
973 unsigned i;
974 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
975 if (pVM->dbgf.s.aHwBreakpoints[i].enmType != DBGFBPTYPE_FREE)
976 {
977 int rc = pfnCallback(pVM, pvUser, &pVM->dbgf.s.aHwBreakpoints[i]);
978 if (RT_FAILURE(rc))
979 return rc;
980 }
981
982 /*
983 * Enumerate the other breakpoints.
984 */
985 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
986 if (pVM->dbgf.s.aBreakpoints[i].enmType != DBGFBPTYPE_FREE)
987 {
988 int rc = pfnCallback(pVM, pvUser, &pVM->dbgf.s.aBreakpoints[i]);
989 if (RT_FAILURE(rc))
990 return rc;
991 }
992
993 return VINF_SUCCESS;
994}
995
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