VirtualBox

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

Last change on this file since 19015 was 18927, checked in by vboxsync, 16 years ago

Big step to separate VMM data structures for guest SMP. (pgm, em)

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