VirtualBox

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

Last change on this file since 16281 was 13818, checked in by vboxsync, 16 years ago

VMM: %Vrc -> %Rrc, %Vra -> %Rra.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 26.6 KB
Line 
1/* $Id: DBGFBp.cpp 13818 2008-11-04 22:59:47Z 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 * Save current byte and write int3 instruction.
383 */
384 int rc = MMR3ReadGCVirt(pVM, &pBp->u.Int3.bOrg, pBp->GCPtr, 1);
385 if (RT_SUCCESS(rc))
386 {
387 static const uint8_t s_bInt3 = 0xcc;
388 rc = MMR3WriteGCVirt(pVM, pBp->GCPtr, &s_bInt3, 1);
389 }
390 return rc;
391}
392
393
394/**
395 * Disarms an int 3 breakpoint.
396 * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable().
397 *
398 * @returns VBox status code.
399 * @param pVM The VM handle.
400 * @param pBp The breakpoint.
401 */
402static int dbgfR3BpInt3Disarm(PVM pVM, PDBGFBP pBp)
403{
404 /*
405 * Check that the current byte is the int3 instruction, and restore the original one.
406 * We currently ignore invalid bytes.
407 */
408 uint8_t bCurrent;
409 int rc = MMR3ReadGCVirt(pVM, &bCurrent, pBp->GCPtr, 1);
410 if (bCurrent == 0xcc)
411 rc = MMR3WriteGCVirt(pVM, pBp->GCPtr, &pBp->u.Int3.bOrg, 1);
412 return rc;
413}
414
415
416/**
417 * Sets a register breakpoint.
418 *
419 * @returns VBox status code.
420 * @param pVM The VM handle.
421 * @param pAddress The address of the breakpoint.
422 * @param iHitTrigger The hit count at which the breakpoint start triggering.
423 * Use 0 (or 1) if it's gonna trigger at once.
424 * @param iHitDisable The hit count which disables the breakpoint.
425 * Use ~(uint64_t) if it's never gonna be disabled.
426 * @param fType The access type (one of the X86_DR7_RW_* defines).
427 * @param cb The access size - 1,2,4 or 8 (the latter is AMD64 long mode only.
428 * Must be 1 if fType is X86_DR7_RW_EO.
429 * @param piBp Where to store the breakpoint id. (optional)
430 * @thread Any thread.
431 */
432VMMR3DECL(int) DBGFR3BpSetReg(PVM pVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable,
433 uint8_t fType, uint8_t cb, PRTUINT piBp)
434{
435 /*
436 * This must be done in EMT.
437 */
438 PVMREQ pReq;
439 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)dbgfR3BpSetReg, 7, pVM, pAddress, &iHitTrigger, &iHitDisable, fType, cb, piBp);
440 if (RT_SUCCESS(rc))
441 rc = pReq->iStatus;
442 VMR3ReqFree(pReq);
443 LogFlow(("DBGFR3BpSetReg: returns %Rrc\n", rc));
444 return rc;
445
446}
447
448
449/**
450 * Sets a register breakpoint.
451 *
452 * @returns VBox status code.
453 * @param pVM The VM handle.
454 * @param pAddress The address of the breakpoint.
455 * @param piHitTrigger The hit count at which the breakpoint start triggering.
456 * Use 0 (or 1) if it's gonna trigger at once.
457 * @param piHitDisable The hit count which disables the breakpoint.
458 * Use ~(uint64_t) if it's never gonna be disabled.
459 * @param fType The access type (one of the X86_DR7_RW_* defines).
460 * @param cb The access size - 1,2,4 or 8 (the latter is AMD64 long mode only.
461 * Must be 1 if fType is X86_DR7_RW_EO.
462 * @param piBp Where to store the breakpoint id. (optional)
463 * @thread EMT
464 * @internal
465 */
466static DECLCALLBACK(int) dbgfR3BpSetReg(PVM pVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable,
467 uint8_t fType, uint8_t cb, PRTUINT piBp)
468{
469 /*
470 * Validate input.
471 */
472 if (!DBGFR3AddrIsValid(pVM, pAddress))
473 return VERR_INVALID_PARAMETER;
474 if (*piHitTrigger > *piHitDisable)
475 return VERR_INVALID_PARAMETER;
476 AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
477 if (piBp)
478 *piBp = ~0;
479 switch (fType)
480 {
481 case X86_DR7_RW_EO:
482 if (cb == 1)
483 break;
484 AssertMsgFailed(("fType=%#x cb=%d != 1\n", fType, cb));
485 return VERR_INVALID_PARAMETER;
486 case X86_DR7_RW_IO:
487 case X86_DR7_RW_RW:
488 case X86_DR7_RW_WO:
489 break;
490 default:
491 AssertMsgFailed(("fType=%#x\n", fType));
492 return VERR_INVALID_PARAMETER;
493 }
494 switch (cb)
495 {
496 case 1:
497 case 2:
498 case 4:
499 break;
500 default:
501 AssertMsgFailed(("cb=%#x\n", cb));
502 return VERR_INVALID_PARAMETER;
503 }
504
505 /*
506 * Check if the breakpoint already exists.
507 */
508 PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REG, pAddress->FlatPtr);
509 if ( pBp
510 && pBp->u.Reg.cb == cb
511 && pBp->u.Reg.fType == fType)
512 {
513 int rc = VINF_SUCCESS;
514 if (!pBp->fEnabled)
515 rc = dbgfR3BpRegArm(pVM, pBp);
516 if (RT_SUCCESS(rc))
517 {
518 rc = VINF_DBGF_BP_ALREADY_EXIST;
519 if (piBp)
520 *piBp = pBp->iBp;
521 }
522 return rc;
523 }
524
525 /*
526 * Allocate and initialize the bp.
527 */
528 pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REG);
529 if (!pBp)
530 return VERR_DBGF_NO_MORE_BP_SLOTS;
531 pBp->GCPtr = pAddress->FlatPtr;
532 pBp->iHitTrigger = *piHitTrigger;
533 pBp->iHitDisable = *piHitDisable;
534 pBp->fEnabled = true;
535 Assert(pBp->iBp == pBp->u.Reg.iReg);
536 pBp->u.Reg.fType = fType;
537 pBp->u.Reg.cb = cb;
538
539 /*
540 * Arm the breakpoint.
541 */
542 int rc = dbgfR3BpRegArm(pVM, pBp);
543 if (RT_SUCCESS(rc))
544 {
545 if (piBp)
546 *piBp = pBp->iBp;
547 }
548 else
549 dbgfR3BpFree(pVM, pBp);
550
551 return rc;
552}
553
554
555/**
556 * Arms a debug register breakpoint.
557 * This is used to implement both DBGFR3BpSetReg() and DBGFR3BpEnable().
558 *
559 * @returns VBox status code.
560 * @param pVM The VM handle.
561 * @param pBp The breakpoint.
562 */
563static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp)
564{
565 Assert(pBp->fEnabled);
566 return CPUMRecalcHyperDRx(pVM);
567}
568
569
570/**
571 * Disarms a debug register breakpoint.
572 * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable().
573 *
574 * @returns VBox status code.
575 * @param pVM The VM handle.
576 * @param pBp The breakpoint.
577 */
578static int dbgfR3BpRegDisarm(PVM pVM, PDBGFBP pBp)
579{
580 Assert(!pBp->fEnabled);
581 return CPUMRecalcHyperDRx(pVM);
582}
583
584
585/**
586 * Sets a recompiler breakpoint.
587 *
588 * @returns VBox status code.
589 * @param pVM The VM handle.
590 * @param pAddress The address of the breakpoint.
591 * @param iHitTrigger The hit count at which the breakpoint start triggering.
592 * Use 0 (or 1) if it's gonna trigger at once.
593 * @param iHitDisable The hit count which disables the breakpoint.
594 * Use ~(uint64_t) if it's never gonna be disabled.
595 * @param piBp Where to store the breakpoint id. (optional)
596 * @thread Any thread.
597 */
598VMMR3DECL(int) DBGFR3BpSetREM(PVM pVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, PRTUINT piBp)
599{
600 /*
601 * This must be done in EMT.
602 */
603 PVMREQ pReq;
604 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)dbgfR3BpSetREM, 5, pVM, pAddress, &iHitTrigger, &iHitDisable, piBp);
605 if (RT_SUCCESS(rc))
606 rc = pReq->iStatus;
607 VMR3ReqFree(pReq);
608 LogFlow(("DBGFR3BpSetREM: returns %Rrc\n", rc));
609 return rc;
610}
611
612
613/**
614 * EMT worker for DBGFR3BpSetREM().
615 *
616 * @returns VBox status code.
617 * @param pVM The VM handle.
618 * @param pAddress The address of the breakpoint.
619 * @param piHitTrigger The hit count at which the breakpoint start triggering.
620 * Use 0 (or 1) if it's gonna trigger at once.
621 * @param piHitDisable The hit count which disables the breakpoint.
622 * Use ~(uint64_t) if it's never gonna be disabled.
623 * @param piBp Where to store the breakpoint id. (optional)
624 * @thread EMT
625 * @internal
626 */
627static DECLCALLBACK(int) dbgfR3BpSetREM(PVM pVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable, PRTUINT piBp)
628{
629 /*
630 * Validate input.
631 */
632 if (!DBGFR3AddrIsValid(pVM, pAddress))
633 return VERR_INVALID_PARAMETER;
634 if (*piHitTrigger > *piHitDisable)
635 return VERR_INVALID_PARAMETER;
636 AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
637 if (piBp)
638 *piBp = ~0;
639
640
641 /*
642 * Check if the breakpoint already exists.
643 */
644 PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REM, pAddress->FlatPtr);
645 if (pBp)
646 {
647 int rc = VINF_SUCCESS;
648 if (!pBp->fEnabled)
649 rc = REMR3BreakpointSet(pVM, pBp->GCPtr);
650 if (RT_SUCCESS(rc))
651 {
652 rc = VINF_DBGF_BP_ALREADY_EXIST;
653 if (piBp)
654 *piBp = pBp->iBp;
655 }
656 return rc;
657 }
658
659 /*
660 * Allocate and initialize the bp.
661 */
662 pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REM);
663 if (!pBp)
664 return VERR_DBGF_NO_MORE_BP_SLOTS;
665 pBp->GCPtr = pAddress->FlatPtr;
666 pBp->iHitTrigger = *piHitTrigger;
667 pBp->iHitDisable = *piHitDisable;
668 pBp->fEnabled = true;
669
670 /*
671 * Now ask REM to set the breakpoint.
672 */
673 int rc = REMR3BreakpointSet(pVM, pAddress->FlatPtr);
674 if (RT_SUCCESS(rc))
675 {
676 if (piBp)
677 *piBp = pBp->iBp;
678 }
679 else
680 dbgfR3BpFree(pVM, pBp);
681
682 return rc;
683}
684
685
686/**
687 * Clears a breakpoint.
688 *
689 * @returns VBox status code.
690 * @param pVM The VM handle.
691 * @param iBp The id of the breakpoint which should be removed (cleared).
692 * @thread Any thread.
693 */
694VMMR3DECL(int) DBGFR3BpClear(PVM pVM, RTUINT iBp)
695{
696 /*
697 * This must be done in EMT.
698 */
699 PVMREQ pReq;
700 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)dbgfR3BpClear, 2, pVM, iBp);
701 if (RT_SUCCESS(rc))
702 rc = pReq->iStatus;
703 VMR3ReqFree(pReq);
704 LogFlow(("DBGFR3BpClear: returns %Rrc\n", rc));
705 return rc;
706}
707
708
709/**
710 * EMT worker for DBGFR3BpClear().
711 *
712 * @returns VBox status code.
713 * @param pVM The VM handle.
714 * @param iBp The id of the breakpoint which should be removed (cleared).
715 * @thread EMT
716 * @internal
717 */
718static DECLCALLBACK(int) dbgfR3BpClear(PVM pVM, RTUINT iBp)
719{
720 /*
721 * Validate input.
722 */
723 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
724 if (!pBp)
725 return VERR_DBGF_BP_NOT_FOUND;
726
727 /*
728 * Disarm the breakpoint if it's enabled.
729 */
730 if (pBp->fEnabled)
731 {
732 pBp->fEnabled = false;
733 int rc;
734 switch (pBp->enmType)
735 {
736 case DBGFBPTYPE_REG:
737 rc = dbgfR3BpRegDisarm(pVM, pBp);
738 break;
739
740 case DBGFBPTYPE_INT3:
741 rc = dbgfR3BpInt3Disarm(pVM, pBp);
742 break;
743
744 case DBGFBPTYPE_REM:
745 rc = REMR3BreakpointClear(pVM, pBp->GCPtr);
746 break;
747
748 default:
749 AssertMsgFailed(("Invalid enmType=%d!\n", pBp->enmType));
750 return VERR_INTERNAL_ERROR;
751 }
752 AssertRCReturn(rc, rc);
753 }
754
755 /*
756 * Free the breakpoint.
757 */
758 dbgfR3BpFree(pVM, pBp);
759 return VINF_SUCCESS;
760}
761
762
763/**
764 * Enables a breakpoint.
765 *
766 * @returns VBox status code.
767 * @param pVM The VM handle.
768 * @param iBp The id of the breakpoint which should be enabled.
769 * @thread Any thread.
770 */
771VMMR3DECL(int) DBGFR3BpEnable(PVM pVM, RTUINT iBp)
772{
773 /*
774 * This must be done in EMT.
775 */
776 PVMREQ pReq;
777 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)dbgfR3BpEnable, 2, pVM, iBp);
778 if (RT_SUCCESS(rc))
779 rc = pReq->iStatus;
780 VMR3ReqFree(pReq);
781 LogFlow(("DBGFR3BpEnable: returns %Rrc\n", rc));
782 return rc;
783}
784
785
786/**
787 * EMT worker for DBGFR3BpEnable().
788 *
789 * @returns VBox status code.
790 * @param pVM The VM handle.
791 * @param iBp The id of the breakpoint which should be enabled.
792 * @thread EMT
793 * @internal
794 */
795static DECLCALLBACK(int) dbgfR3BpEnable(PVM pVM, RTUINT iBp)
796{
797 /*
798 * Validate input.
799 */
800 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
801 if (!pBp)
802 return VERR_DBGF_BP_NOT_FOUND;
803
804 /*
805 * Already enabled?
806 */
807 if (pBp->fEnabled)
808 return VINF_DBGF_BP_ALREADY_ENABLED;
809
810 /*
811 * Remove the breakpoint.
812 */
813 int rc;
814 pBp->fEnabled = true;
815 switch (pBp->enmType)
816 {
817 case DBGFBPTYPE_REG:
818 rc = dbgfR3BpRegArm(pVM, pBp);
819 break;
820
821 case DBGFBPTYPE_INT3:
822 rc = dbgfR3BpInt3Arm(pVM, pBp);
823 break;
824
825 case DBGFBPTYPE_REM:
826 rc = REMR3BreakpointSet(pVM, pBp->GCPtr);
827 break;
828
829 default:
830 AssertMsgFailed(("Invalid enmType=%d!\n", pBp->enmType));
831 return VERR_INTERNAL_ERROR;
832 }
833 if (RT_FAILURE(rc))
834 pBp->fEnabled = false;
835
836 return rc;
837}
838
839
840/**
841 * Disables a breakpoint.
842 *
843 * @returns VBox status code.
844 * @param pVM The VM handle.
845 * @param iBp The id of the breakpoint which should be disabled.
846 * @thread Any thread.
847 */
848VMMR3DECL(int) DBGFR3BpDisable(PVM pVM, RTUINT iBp)
849{
850 /*
851 * This must be done in EMT.
852 */
853 PVMREQ pReq;
854 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)dbgfR3BpDisable, 2, pVM, iBp);
855 if (RT_SUCCESS(rc))
856 rc = pReq->iStatus;
857 VMR3ReqFree(pReq);
858 LogFlow(("DBGFR3BpDisable: returns %Rrc\n", rc));
859 return rc;
860}
861
862
863/**
864 * EMT worker for DBGFR3BpDisable().
865 *
866 * @returns VBox status code.
867 * @param pVM The VM handle.
868 * @param iBp The id of the breakpoint which should be disabled.
869 * @thread EMT
870 * @internal
871 */
872static DECLCALLBACK(int) dbgfR3BpDisable(PVM pVM, RTUINT iBp)
873{
874 /*
875 * Validate input.
876 */
877 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
878 if (!pBp)
879 return VERR_DBGF_BP_NOT_FOUND;
880
881 /*
882 * Already enabled?
883 */
884 if (!pBp->fEnabled)
885 return VINF_DBGF_BP_ALREADY_DISABLED;
886
887 /*
888 * Remove the breakpoint.
889 */
890 pBp->fEnabled = false;
891 int rc;
892 switch (pBp->enmType)
893 {
894 case DBGFBPTYPE_REG:
895 rc = dbgfR3BpRegDisarm(pVM, pBp);
896 break;
897
898 case DBGFBPTYPE_INT3:
899 rc = dbgfR3BpInt3Disarm(pVM, pBp);
900 break;
901
902 case DBGFBPTYPE_REM:
903 rc = REMR3BreakpointClear(pVM, pBp->GCPtr);
904 break;
905
906 default:
907 AssertMsgFailed(("Invalid enmType=%d!\n", pBp->enmType));
908 return VERR_INTERNAL_ERROR;
909 }
910
911 return rc;
912}
913
914
915/**
916 * Enumerate the breakpoints.
917 *
918 * @returns VBox status code.
919 * @param pVM The VM handle.
920 * @param pfnCallback The callback function.
921 * @param pvUser The user argument to pass to the callback.
922 * @thread Any thread but the callback will be called from EMT.
923 */
924VMMR3DECL(int) DBGFR3BpEnum(PVM pVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
925{
926 /*
927 * This must be done in EMT.
928 */
929 PVMREQ pReq;
930 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)dbgfR3BpEnum, 3, pVM, pfnCallback, pvUser);
931 if (RT_SUCCESS(rc))
932 rc = pReq->iStatus;
933 VMR3ReqFree(pReq);
934 LogFlow(("DBGFR3BpClear: returns %Rrc\n", rc));
935 return rc;
936}
937
938
939/**
940 * EMT worker for DBGFR3BpEnum().
941 *
942 * @returns VBox status code.
943 * @param pVM The VM handle.
944 * @param pfnCallback The callback function.
945 * @param pvUser The user argument to pass to the callback.
946 * @thread EMT
947 * @internal
948 */
949static DECLCALLBACK(int) dbgfR3BpEnum(PVM pVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
950{
951 /*
952 * Validate input.
953 */
954 AssertMsgReturn(VALID_PTR(pfnCallback), ("pfnCallback=%p\n", pfnCallback), VERR_INVALID_POINTER);
955
956 /*
957 * Enumerate the hardware breakpoints.
958 */
959 unsigned i;
960 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
961 if (pVM->dbgf.s.aHwBreakpoints[i].enmType != DBGFBPTYPE_FREE)
962 {
963 int rc = pfnCallback(pVM, pvUser, &pVM->dbgf.s.aHwBreakpoints[i]);
964 if (RT_FAILURE(rc))
965 return rc;
966 }
967
968 /*
969 * Enumerate the other breakpoints.
970 */
971 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
972 if (pVM->dbgf.s.aBreakpoints[i].enmType != DBGFBPTYPE_FREE)
973 {
974 int rc = pfnCallback(pVM, pvUser, &pVM->dbgf.s.aBreakpoints[i]);
975 if (RT_FAILURE(rc))
976 return rc;
977 }
978
979 return VINF_SUCCESS;
980}
981
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