VirtualBox

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

Last change on this file since 20543 was 20374, checked in by vboxsync, 15 years ago

*: s/RT_\(BEGIN|END\)_DECLS/RT_C_DECLS_\1/g

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