VirtualBox

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

Last change on this file since 25414 was 23012, checked in by vboxsync, 15 years ago

VMM,Devices,Main: VMR3ReqCall w/ RT_INDEFINITE_WAIT -> VMR3ReqCallWait.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 26.3 KB
Line 
1/* $Id: DBGFBp.cpp 23012 2009-09-14 16:38:13Z 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 /** @todo SMP? */
290 int rc = VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)dbgfR3BpSetInt3, 5, pVM, pAddress, &iHitTrigger, &iHitDisable, piBp);
291 LogFlow(("DBGFR3BpSet: returns %Rrc\n", rc));
292 return rc;
293}
294
295
296/**
297 * Sets a breakpoint (int 3 based).
298 *
299 * @returns VBox status code.
300 * @param pVM The VM handle.
301 * @param pAddress The address of the breakpoint.
302 * @param piHitTrigger The hit count at which the breakpoint start triggering.
303 * Use 0 (or 1) if it's gonna trigger at once.
304 * @param piHitDisable The hit count which disables the breakpoint.
305 * Use ~(uint64_t) if it's never gonna be disabled.
306 * @param piBp Where to store the breakpoint id. (optional)
307 * @thread Any thread.
308 */
309static DECLCALLBACK(int) dbgfR3BpSetInt3(PVM pVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable, PRTUINT piBp)
310{
311 /*
312 * Validate input.
313 */
314 if (!DBGFR3AddrIsValid(pVM, pAddress))
315 return VERR_INVALID_PARAMETER;
316 if (*piHitTrigger > *piHitDisable)
317 return VERR_INVALID_PARAMETER;
318 AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
319 if (piBp)
320 *piBp = ~0;
321
322 /*
323 * Check if the breakpoint already exists.
324 */
325 PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_INT3, pAddress->FlatPtr);
326 if (pBp)
327 {
328 int rc = VINF_SUCCESS;
329 if (!pBp->fEnabled)
330 rc = dbgfR3BpInt3Arm(pVM, pBp);
331 if (RT_SUCCESS(rc))
332 {
333 rc = VINF_DBGF_BP_ALREADY_EXIST;
334 if (piBp)
335 *piBp = pBp->iBp;
336 }
337 return rc;
338 }
339
340 /*
341 * Allocate and initialize the bp.
342 */
343 pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_INT3);
344 if (!pBp)
345 return VERR_DBGF_NO_MORE_BP_SLOTS;
346 pBp->GCPtr = pAddress->FlatPtr;
347 pBp->iHitTrigger = *piHitTrigger;
348 pBp->iHitDisable = *piHitDisable;
349 pBp->fEnabled = true;
350
351 /*
352 * Now ask REM to set the breakpoint.
353 */
354 int rc = dbgfR3BpInt3Arm(pVM, pBp);
355 if (RT_SUCCESS(rc))
356 {
357 if (piBp)
358 *piBp = pBp->iBp;
359 }
360 else
361 dbgfR3BpFree(pVM, pBp);
362
363 return rc;
364}
365
366
367/**
368 * Arms an int 3 breakpoint.
369 * This is used to implement both DBGFR3BpSetReg() and DBGFR3BpEnable().
370 *
371 * @returns VBox status code.
372 * @param pVM The VM handle.
373 * @param pBp The breakpoint.
374 */
375static int dbgfR3BpInt3Arm(PVM pVM, PDBGFBP pBp)
376{
377 /** @todo should actually use physical address here! */
378
379 /* @todo SMP support! */
380 VMCPUID idCpu = 0;
381
382 /*
383 * Save current byte and write int3 instruction.
384 */
385 DBGFADDRESS Addr;
386 DBGFR3AddrFromFlat(pVM, &Addr, pBp->GCPtr);
387 int rc = DBGFR3MemRead(pVM, idCpu, &Addr, &pBp->u.Int3.bOrg, 1);
388 if (RT_SUCCESS(rc))
389 {
390 static const uint8_t s_bInt3 = 0xcc;
391 rc = DBGFR3MemWrite(pVM, idCpu, &Addr, &s_bInt3, 1);
392 }
393 return rc;
394}
395
396
397/**
398 * Disarms an int 3 breakpoint.
399 * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable().
400 *
401 * @returns VBox status code.
402 * @param pVM The VM handle.
403 * @param pBp The breakpoint.
404 */
405static int dbgfR3BpInt3Disarm(PVM pVM, PDBGFBP pBp)
406{
407 /* @todo SMP support! */
408 VMCPUID idCpu = 0;
409
410 /*
411 * Check that the current byte is the int3 instruction, and restore the original one.
412 * We currently ignore invalid bytes.
413 */
414 DBGFADDRESS Addr;
415 DBGFR3AddrFromFlat(pVM, &Addr, pBp->GCPtr);
416 uint8_t bCurrent;
417 int rc = DBGFR3MemRead(pVM, idCpu, &Addr, &bCurrent, 1);
418 if (bCurrent == 0xcc)
419 rc = DBGFR3MemWrite(pVM, idCpu, &Addr, &pBp->u.Int3.bOrg, 1);
420 return rc;
421}
422
423
424/**
425 * Sets a register breakpoint.
426 *
427 * @returns VBox status code.
428 * @param pVM The VM handle.
429 * @param pAddress The address of the breakpoint.
430 * @param iHitTrigger The hit count at which the breakpoint start triggering.
431 * Use 0 (or 1) if it's gonna trigger at once.
432 * @param iHitDisable The hit count which disables the breakpoint.
433 * Use ~(uint64_t) if it's never gonna be disabled.
434 * @param fType The access type (one of the X86_DR7_RW_* defines).
435 * @param cb The access size - 1,2,4 or 8 (the latter is AMD64 long mode only.
436 * Must be 1 if fType is X86_DR7_RW_EO.
437 * @param piBp Where to store the breakpoint id. (optional)
438 * @thread Any thread.
439 */
440VMMR3DECL(int) DBGFR3BpSetReg(PVM pVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable,
441 uint8_t fType, uint8_t cb, PRTUINT piBp)
442{
443 /** @todo SMP - broadcast, VT-x/AMD-V. */
444 /*
445 * This must be done in EMT.
446 */
447 int rc = VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)dbgfR3BpSetReg, 7, pVM, pAddress, &iHitTrigger, &iHitDisable, fType, cb, piBp);
448 LogFlow(("DBGFR3BpSetReg: returns %Rrc\n", rc));
449 return rc;
450
451}
452
453
454/**
455 * Sets a register breakpoint.
456 *
457 * @returns VBox status code.
458 * @param pVM The VM handle.
459 * @param pAddress The address of the breakpoint.
460 * @param piHitTrigger The hit count at which the breakpoint start triggering.
461 * Use 0 (or 1) if it's gonna trigger at once.
462 * @param piHitDisable The hit count which disables the breakpoint.
463 * Use ~(uint64_t) if it's never gonna be disabled.
464 * @param fType The access type (one of the X86_DR7_RW_* defines).
465 * @param cb The access size - 1,2,4 or 8 (the latter is AMD64 long mode only.
466 * Must be 1 if fType is X86_DR7_RW_EO.
467 * @param piBp Where to store the breakpoint id. (optional)
468 * @thread EMT
469 * @internal
470 */
471static DECLCALLBACK(int) dbgfR3BpSetReg(PVM pVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable,
472 uint8_t fType, uint8_t cb, PRTUINT piBp)
473{
474 /*
475 * Validate input.
476 */
477 if (!DBGFR3AddrIsValid(pVM, pAddress))
478 return VERR_INVALID_PARAMETER;
479 if (*piHitTrigger > *piHitDisable)
480 return VERR_INVALID_PARAMETER;
481 AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
482 if (piBp)
483 *piBp = ~0;
484 switch (fType)
485 {
486 case X86_DR7_RW_EO:
487 if (cb == 1)
488 break;
489 AssertMsgFailed(("fType=%#x cb=%d != 1\n", fType, cb));
490 return VERR_INVALID_PARAMETER;
491 case X86_DR7_RW_IO:
492 case X86_DR7_RW_RW:
493 case X86_DR7_RW_WO:
494 break;
495 default:
496 AssertMsgFailed(("fType=%#x\n", fType));
497 return VERR_INVALID_PARAMETER;
498 }
499 switch (cb)
500 {
501 case 1:
502 case 2:
503 case 4:
504 break;
505 default:
506 AssertMsgFailed(("cb=%#x\n", cb));
507 return VERR_INVALID_PARAMETER;
508 }
509
510 /*
511 * Check if the breakpoint already exists.
512 */
513 PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REG, pAddress->FlatPtr);
514 if ( pBp
515 && pBp->u.Reg.cb == cb
516 && pBp->u.Reg.fType == fType)
517 {
518 int rc = VINF_SUCCESS;
519 if (!pBp->fEnabled)
520 rc = dbgfR3BpRegArm(pVM, pBp);
521 if (RT_SUCCESS(rc))
522 {
523 rc = VINF_DBGF_BP_ALREADY_EXIST;
524 if (piBp)
525 *piBp = pBp->iBp;
526 }
527 return rc;
528 }
529
530 /*
531 * Allocate and initialize the bp.
532 */
533 pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REG);
534 if (!pBp)
535 return VERR_DBGF_NO_MORE_BP_SLOTS;
536 pBp->GCPtr = pAddress->FlatPtr;
537 pBp->iHitTrigger = *piHitTrigger;
538 pBp->iHitDisable = *piHitDisable;
539 pBp->fEnabled = true;
540 Assert(pBp->iBp == pBp->u.Reg.iReg);
541 pBp->u.Reg.fType = fType;
542 pBp->u.Reg.cb = cb;
543
544 /*
545 * Arm the breakpoint.
546 */
547 int rc = dbgfR3BpRegArm(pVM, pBp);
548 if (RT_SUCCESS(rc))
549 {
550 if (piBp)
551 *piBp = pBp->iBp;
552 }
553 else
554 dbgfR3BpFree(pVM, pBp);
555
556 return rc;
557}
558
559
560/**
561 * Arms a debug register breakpoint.
562 * This is used to implement both DBGFR3BpSetReg() and DBGFR3BpEnable().
563 *
564 * @returns VBox status code.
565 * @param pVM The VM handle.
566 * @param pBp The breakpoint.
567 */
568static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp)
569{
570 /* @todo SMP support! */
571 PVMCPU pVCpu = &pVM->aCpus[0];
572
573 Assert(pBp->fEnabled);
574 return CPUMRecalcHyperDRx(pVCpu);
575}
576
577
578/**
579 * Disarms a debug register breakpoint.
580 * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable().
581 *
582 * @returns VBox status code.
583 * @param pVM The VM handle.
584 * @param pBp The breakpoint.
585 */
586static int dbgfR3BpRegDisarm(PVM pVM, PDBGFBP pBp)
587{
588 /** @todo SMP support! */
589 PVMCPU pVCpu = &pVM->aCpus[0];
590
591 Assert(!pBp->fEnabled);
592 return CPUMRecalcHyperDRx(pVCpu);
593}
594
595
596/**
597 * Sets a recompiler breakpoint.
598 *
599 * @returns VBox status code.
600 * @param pVM The VM handle.
601 * @param pAddress The address of the breakpoint.
602 * @param iHitTrigger The hit count at which the breakpoint start triggering.
603 * Use 0 (or 1) if it's gonna trigger at once.
604 * @param iHitDisable The hit count which disables the breakpoint.
605 * Use ~(uint64_t) if it's never gonna be disabled.
606 * @param piBp Where to store the breakpoint id. (optional)
607 * @thread Any thread.
608 */
609VMMR3DECL(int) DBGFR3BpSetREM(PVM pVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, PRTUINT piBp)
610{
611 /*
612 * This must be done in EMT.
613 */
614 int rc = VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)dbgfR3BpSetREM, 5, pVM, pAddress, &iHitTrigger, &iHitDisable, piBp);
615 LogFlow(("DBGFR3BpSetREM: returns %Rrc\n", rc));
616 return rc;
617}
618
619
620/**
621 * EMT worker for DBGFR3BpSetREM().
622 *
623 * @returns VBox status code.
624 * @param pVM The VM handle.
625 * @param pAddress The address of the breakpoint.
626 * @param piHitTrigger The hit count at which the breakpoint start triggering.
627 * Use 0 (or 1) if it's gonna trigger at once.
628 * @param piHitDisable The hit count which disables the breakpoint.
629 * Use ~(uint64_t) if it's never gonna be disabled.
630 * @param piBp Where to store the breakpoint id. (optional)
631 * @thread EMT
632 * @internal
633 */
634static DECLCALLBACK(int) dbgfR3BpSetREM(PVM pVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable, PRTUINT piBp)
635{
636 /*
637 * Validate input.
638 */
639 if (!DBGFR3AddrIsValid(pVM, pAddress))
640 return VERR_INVALID_PARAMETER;
641 if (*piHitTrigger > *piHitDisable)
642 return VERR_INVALID_PARAMETER;
643 AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
644 if (piBp)
645 *piBp = ~0;
646
647
648 /*
649 * Check if the breakpoint already exists.
650 */
651 PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REM, pAddress->FlatPtr);
652 if (pBp)
653 {
654 int rc = VINF_SUCCESS;
655 if (!pBp->fEnabled)
656 rc = REMR3BreakpointSet(pVM, pBp->GCPtr);
657 if (RT_SUCCESS(rc))
658 {
659 rc = VINF_DBGF_BP_ALREADY_EXIST;
660 if (piBp)
661 *piBp = pBp->iBp;
662 }
663 return rc;
664 }
665
666 /*
667 * Allocate and initialize the bp.
668 */
669 pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REM);
670 if (!pBp)
671 return VERR_DBGF_NO_MORE_BP_SLOTS;
672 pBp->GCPtr = pAddress->FlatPtr;
673 pBp->iHitTrigger = *piHitTrigger;
674 pBp->iHitDisable = *piHitDisable;
675 pBp->fEnabled = true;
676
677 /*
678 * Now ask REM to set the breakpoint.
679 */
680 int rc = REMR3BreakpointSet(pVM, pAddress->FlatPtr);
681 if (RT_SUCCESS(rc))
682 {
683 if (piBp)
684 *piBp = pBp->iBp;
685 }
686 else
687 dbgfR3BpFree(pVM, pBp);
688
689 return rc;
690}
691
692
693/**
694 * Clears a breakpoint.
695 *
696 * @returns VBox status code.
697 * @param pVM The VM handle.
698 * @param iBp The id of the breakpoint which should be removed (cleared).
699 * @thread Any thread.
700 */
701VMMR3DECL(int) DBGFR3BpClear(PVM pVM, RTUINT iBp)
702{
703 /*
704 * This must be done in EMT.
705 */
706 int rc = VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)dbgfR3BpClear, 2, pVM, iBp);
707 LogFlow(("DBGFR3BpClear: returns %Rrc\n", rc));
708 return rc;
709}
710
711
712/**
713 * EMT worker for DBGFR3BpClear().
714 *
715 * @returns VBox status code.
716 * @param pVM The VM handle.
717 * @param iBp The id of the breakpoint which should be removed (cleared).
718 * @thread EMT
719 * @internal
720 */
721static DECLCALLBACK(int) dbgfR3BpClear(PVM pVM, RTUINT iBp)
722{
723 /*
724 * Validate input.
725 */
726 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
727 if (!pBp)
728 return VERR_DBGF_BP_NOT_FOUND;
729
730 /*
731 * Disarm the breakpoint if it's enabled.
732 */
733 if (pBp->fEnabled)
734 {
735 pBp->fEnabled = false;
736 int rc;
737 switch (pBp->enmType)
738 {
739 case DBGFBPTYPE_REG:
740 rc = dbgfR3BpRegDisarm(pVM, pBp);
741 break;
742
743 case DBGFBPTYPE_INT3:
744 rc = dbgfR3BpInt3Disarm(pVM, pBp);
745 break;
746
747 case DBGFBPTYPE_REM:
748 rc = REMR3BreakpointClear(pVM, pBp->GCPtr);
749 break;
750
751 default:
752 AssertMsgFailed(("Invalid enmType=%d!\n", pBp->enmType));
753 return VERR_INTERNAL_ERROR;
754 }
755 AssertRCReturn(rc, rc);
756 }
757
758 /*
759 * Free the breakpoint.
760 */
761 dbgfR3BpFree(pVM, pBp);
762 return VINF_SUCCESS;
763}
764
765
766/**
767 * Enables a breakpoint.
768 *
769 * @returns VBox status code.
770 * @param pVM The VM handle.
771 * @param iBp The id of the breakpoint which should be enabled.
772 * @thread Any thread.
773 */
774VMMR3DECL(int) DBGFR3BpEnable(PVM pVM, RTUINT iBp)
775{
776 /*
777 * This must be done in EMT.
778 */
779 int rc = VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)dbgfR3BpEnable, 2, pVM, iBp);
780 LogFlow(("DBGFR3BpEnable: returns %Rrc\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 (RT_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 */
847VMMR3DECL(int) DBGFR3BpDisable(PVM pVM, RTUINT iBp)
848{
849 /*
850 * This must be done in EMT.
851 */
852 int rc = VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)dbgfR3BpDisable, 2, pVM, iBp);
853 LogFlow(("DBGFR3BpDisable: returns %Rrc\n", rc));
854 return rc;
855}
856
857
858/**
859 * EMT worker for DBGFR3BpDisable().
860 *
861 * @returns VBox status code.
862 * @param pVM The VM handle.
863 * @param iBp The id of the breakpoint which should be disabled.
864 * @thread EMT
865 * @internal
866 */
867static DECLCALLBACK(int) dbgfR3BpDisable(PVM pVM, RTUINT iBp)
868{
869 /*
870 * Validate input.
871 */
872 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
873 if (!pBp)
874 return VERR_DBGF_BP_NOT_FOUND;
875
876 /*
877 * Already enabled?
878 */
879 if (!pBp->fEnabled)
880 return VINF_DBGF_BP_ALREADY_DISABLED;
881
882 /*
883 * Remove the breakpoint.
884 */
885 pBp->fEnabled = false;
886 int rc;
887 switch (pBp->enmType)
888 {
889 case DBGFBPTYPE_REG:
890 rc = dbgfR3BpRegDisarm(pVM, pBp);
891 break;
892
893 case DBGFBPTYPE_INT3:
894 rc = dbgfR3BpInt3Disarm(pVM, pBp);
895 break;
896
897 case DBGFBPTYPE_REM:
898 rc = REMR3BreakpointClear(pVM, pBp->GCPtr);
899 break;
900
901 default:
902 AssertMsgFailed(("Invalid enmType=%d!\n", pBp->enmType));
903 return VERR_INTERNAL_ERROR;
904 }
905
906 return rc;
907}
908
909
910/**
911 * Enumerate the breakpoints.
912 *
913 * @returns VBox status code.
914 * @param pVM The VM handle.
915 * @param pfnCallback The callback function.
916 * @param pvUser The user argument to pass to the callback.
917 * @thread Any thread but the callback will be called from EMT.
918 */
919VMMR3DECL(int) DBGFR3BpEnum(PVM pVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
920{
921 /*
922 * This must be done in EMT.
923 */
924 int rc = VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)dbgfR3BpEnum, 3, pVM, pfnCallback, pvUser);
925 LogFlow(("DBGFR3BpClear: returns %Rrc\n", rc));
926 return rc;
927}
928
929
930/**
931 * EMT worker for DBGFR3BpEnum().
932 *
933 * @returns VBox status code.
934 * @param pVM The VM handle.
935 * @param pfnCallback The callback function.
936 * @param pvUser The user argument to pass to the callback.
937 * @thread EMT
938 * @internal
939 */
940static DECLCALLBACK(int) dbgfR3BpEnum(PVM pVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
941{
942 /*
943 * Validate input.
944 */
945 AssertMsgReturn(VALID_PTR(pfnCallback), ("pfnCallback=%p\n", pfnCallback), VERR_INVALID_POINTER);
946
947 /*
948 * Enumerate the hardware breakpoints.
949 */
950 unsigned i;
951 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
952 if (pVM->dbgf.s.aHwBreakpoints[i].enmType != DBGFBPTYPE_FREE)
953 {
954 int rc = pfnCallback(pVM, pvUser, &pVM->dbgf.s.aHwBreakpoints[i]);
955 if (RT_FAILURE(rc))
956 return rc;
957 }
958
959 /*
960 * Enumerate the other breakpoints.
961 */
962 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
963 if (pVM->dbgf.s.aBreakpoints[i].enmType != DBGFBPTYPE_FREE)
964 {
965 int rc = pfnCallback(pVM, pvUser, &pVM->dbgf.s.aBreakpoints[i]);
966 if (RT_FAILURE(rc))
967 return rc;
968 }
969
970 return VINF_SUCCESS;
971}
972
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use