VirtualBox

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

Last change on this file since 7806 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

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