VirtualBox

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

Last change on this file since 38838 was 38838, checked in by vboxsync, 13 years ago

VMM,++: Try fix the async reset, suspend and power-off problems in PDM wrt conflicting VMM requests. Split them into priority requests and normal requests. The priority requests can safely be processed when PDM is doing async state change waits, the normal ones cannot. (The problem I bumped into was a unmap-chunk request from PGM being processed during PDMR3Reset, causing a recursive VMMR3EmtRendezvous deadlock.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 26.2 KB
Line 
1/* $Id: DBGFBp.cpp 38838 2011-09-23 11:21:55Z 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/vmm/dbgf.h>
24#include <VBox/vmm/selm.h>
25#include <VBox/vmm/rem.h>
26#include "DBGFInternal.h"
27#include <VBox/vmm/vm.h>
28#include <VBox/vmm/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, uint32_t *piBp);
41static DECLCALLBACK(int) dbgfR3BpSetInt3(PVM pVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable, uint32_t *piBp);
42static DECLCALLBACK(int) dbgfR3BpSetREM(PVM pVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable, uint32_t *piBp);
43static DECLCALLBACK(int) dbgfR3BpClear(PVM pVM, uint32_t iBp);
44static DECLCALLBACK(int) dbgfR3BpEnable(PVM pVM, uint32_t iBp);
45static DECLCALLBACK(int) dbgfR3BpDisable(PVM pVM, uint32_t 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 * Determine which array to search.
102 */
103 unsigned cBps;
104 uint32_t *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, uint32_t 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 * Determine 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, uint32_t *piBp)
281{
282 /*
283 * This must be done on EMT.
284 */
285 /** @todo SMP? */
286 int rc = VMR3ReqPriorityCallWait(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, uint32_t *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, uint32_t *piBp)
438{
439 /** @todo SMP - broadcast, VT-x/AMD-V. */
440 /*
441 * This must be done on EMT.
442 */
443 int rc = VMR3ReqPriorityCallWait(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, uint32_t *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, uint32_t *piBp)
606{
607 /*
608 * This must be done on EMT.
609 */
610 int rc = VMR3ReqPriorityCallWait(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, uint32_t *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, uint32_t iBp)
698{
699 /*
700 * This must be done on EMT.
701 */
702 int rc = VMR3ReqPriorityCallWait(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, uint32_t 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, uint32_t iBp)
771{
772 /*
773 * This must be done on EMT.
774 */
775 int rc = VMR3ReqPriorityCallWait(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, uint32_t 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, uint32_t iBp)
844{
845 /*
846 * This must be done on EMT.
847 */
848 int rc = VMR3ReqPriorityCallWait(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, uint32_t 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 on EMT.
919 */
920 int rc = VMR3ReqPriorityCallWait(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.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette