VirtualBox

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

Last change on this file since 2676 was 23, checked in by vboxsync, 17 years ago

string.h & stdio.h + header cleanups.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use