VirtualBox

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

Last change on this file since 28800 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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

© 2023 Oracle
ContactPrivacy policyTerms of Use