VirtualBox

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

Last change on this file since 50653 was 47714, checked in by vboxsync, 11 years ago

CPUMRecalcHyperDRx: Host single stepping in HM-mode fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 27.1 KB
Line 
1/* $Id: DBGFBp.cpp 47714 2013-08-13 23:43:24Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Breakpoint Management.
4 */
5
6/*
7 * Copyright (C) 2006-2013 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#ifdef VBOX_WITH_REM
26# include <VBox/vmm/rem.h>
27#else
28# include <VBox/vmm/iem.h>
29#endif
30#include <VBox/vmm/mm.h>
31#include "DBGFInternal.h"
32#include <VBox/vmm/vm.h>
33#include <VBox/vmm/uvm.h>
34
35#include <VBox/err.h>
36#include <VBox/log.h>
37#include <iprt/assert.h>
38#include <iprt/string.h>
39
40
41/*******************************************************************************
42* Internal Functions *
43*******************************************************************************/
44RT_C_DECLS_BEGIN
45static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp);
46static int dbgfR3BpInt3Arm(PUVM pUVM, PDBGFBP pBp);
47RT_C_DECLS_END
48
49
50
51/**
52 * Initialize the breakpoint stuff.
53 *
54 * @returns VINF_SUCCESS
55 * @param pVM Pointer to the VM.
56 */
57int dbgfR3BpInit(PVM pVM)
58{
59 /*
60 * Init structures.
61 */
62 unsigned i;
63 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
64 {
65 pVM->dbgf.s.aHwBreakpoints[i].iBp = i;
66 pVM->dbgf.s.aHwBreakpoints[i].enmType = DBGFBPTYPE_FREE;
67 pVM->dbgf.s.aHwBreakpoints[i].u.Reg.iReg = i;
68 }
69
70 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
71 {
72 pVM->dbgf.s.aBreakpoints[i].iBp = i + RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
73 pVM->dbgf.s.aBreakpoints[i].enmType = DBGFBPTYPE_FREE;
74 }
75
76 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
77 {
78 PVMCPU pVCpu = &pVM->aCpus[idCpu];
79 pVCpu->dbgf.s.iActiveBp = ~0U;
80 }
81
82 /*
83 * Register saved state.
84 */
85 /** @todo */
86
87 return VINF_SUCCESS;
88}
89
90
91
92/**
93 * Allocate a breakpoint.
94 *
95 * @returns Pointer to the allocated breakpoint.
96 * @returns NULL if we're out of breakpoints.
97 * @param pVM Pointer to the VM.
98 * @param enmType The type to allocate.
99 */
100static PDBGFBP dbgfR3BpAlloc(PVM pVM, DBGFBPTYPE enmType)
101{
102 /*
103 * Determine which array to search.
104 */
105 unsigned cBps;
106 uint32_t *pcBpsCur;
107 PDBGFBP paBps;
108 switch (enmType)
109 {
110 case DBGFBPTYPE_REG:
111 cBps = RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
112 paBps = &pVM->dbgf.s.aHwBreakpoints[0];
113 pcBpsCur = &pVM->dbgf.s.cHwBreakpoints;
114 break;
115
116 case DBGFBPTYPE_INT3:
117 case DBGFBPTYPE_REM:
118 cBps = RT_ELEMENTS(pVM->dbgf.s.aBreakpoints);
119 paBps = &pVM->dbgf.s.aBreakpoints[0];
120 pcBpsCur = &pVM->dbgf.s.cBreakpoints;
121 break;
122
123 default:
124 AssertMsgFailed(("enmType=%d\n", enmType));
125 return NULL;
126 }
127
128 /*
129 * Search.
130 */
131 for (unsigned iBp = 0; iBp < cBps; iBp++)
132 if (paBps[iBp].enmType == DBGFBPTYPE_FREE)
133 {
134 ++*pcBpsCur;
135 paBps[iBp].cHits = 0;
136 paBps[iBp].enmType = enmType;
137 return &paBps[iBp];
138 }
139
140 LogFlow(("dbgfR3BpAlloc: returns NULL - we're out of breakpoint slots! %u/%u\n", *pcBpsCur, cBps));
141 return NULL;
142}
143
144
145/**
146 * Get a breakpoint give by breakpoint id.
147 *
148 * @returns Pointer to the allocated breakpoint.
149 * @returns NULL if the breakpoint is invalid.
150 * @param pVM Pointer to the VM.
151 * @param iBp The breakpoint id.
152 */
153static PDBGFBP dbgfR3BpGet(PVM pVM, uint32_t iBp)
154{
155 /* Find it. */
156 PDBGFBP pBp;
157 if (iBp < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints))
158 pBp = &pVM->dbgf.s.aHwBreakpoints[iBp];
159 else
160 {
161 iBp -= RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
162 if (iBp >= RT_ELEMENTS(pVM->dbgf.s.aBreakpoints))
163 return NULL;
164 pBp = &pVM->dbgf.s.aBreakpoints[iBp];
165 }
166
167 /* check if it's valid. */
168 switch (pBp->enmType)
169 {
170 case DBGFBPTYPE_FREE:
171 return NULL;
172
173 case DBGFBPTYPE_REG:
174 case DBGFBPTYPE_INT3:
175 case DBGFBPTYPE_REM:
176 break;
177
178 default:
179 AssertMsgFailed(("Invalid enmType=%d!\n", pBp->enmType));
180 return NULL;
181 }
182
183 return pBp;
184}
185
186
187/**
188 * Get a breakpoint give by address.
189 *
190 * @returns Pointer to the allocated breakpoint.
191 * @returns NULL if the breakpoint is invalid.
192 * @param pVM Pointer to the VM.
193 * @param enmType The breakpoint type.
194 * @param GCPtr The breakpoint address.
195 */
196static PDBGFBP dbgfR3BpGetByAddr(PVM pVM, DBGFBPTYPE enmType, RTGCUINTPTR GCPtr)
197{
198 /*
199 * Determine which array to search.
200 */
201 unsigned cBps;
202 PDBGFBP paBps;
203 switch (enmType)
204 {
205 case DBGFBPTYPE_REG:
206 cBps = RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
207 paBps = &pVM->dbgf.s.aHwBreakpoints[0];
208 break;
209
210 case DBGFBPTYPE_INT3:
211 case DBGFBPTYPE_REM:
212 cBps = RT_ELEMENTS(pVM->dbgf.s.aBreakpoints);
213 paBps = &pVM->dbgf.s.aBreakpoints[0];
214 break;
215
216 default:
217 AssertMsgFailed(("enmType=%d\n", enmType));
218 return NULL;
219 }
220
221 /*
222 * Search.
223 */
224 for (unsigned iBp = 0; iBp < cBps; iBp++)
225 {
226 if ( paBps[iBp].enmType == enmType
227 && paBps[iBp].GCPtr == GCPtr)
228 return &paBps[iBp];
229 }
230
231 return NULL;
232}
233
234
235/**
236 * Frees a breakpoint.
237 *
238 * @param pVM Pointer to the VM.
239 * @param pBp The breakpoint to free.
240 */
241static void dbgfR3BpFree(PVM pVM, PDBGFBP pBp)
242{
243 switch (pBp->enmType)
244 {
245 case DBGFBPTYPE_FREE:
246 AssertMsgFailed(("Already freed!\n"));
247 return;
248
249 case DBGFBPTYPE_REG:
250 Assert(pVM->dbgf.s.cHwBreakpoints > 0);
251 pVM->dbgf.s.cHwBreakpoints--;
252 break;
253
254 case DBGFBPTYPE_INT3:
255 case DBGFBPTYPE_REM:
256 Assert(pVM->dbgf.s.cBreakpoints > 0);
257 pVM->dbgf.s.cBreakpoints--;
258 break;
259
260 default:
261 AssertMsgFailed(("Invalid enmType=%d!\n", pBp->enmType));
262 return;
263
264 }
265 pBp->enmType = DBGFBPTYPE_FREE;
266}
267
268
269/**
270 * Sets a breakpoint (int 3 based).
271 *
272 * @returns VBox status code.
273 * @param pUVM The user mode VM handle.
274 * @param pAddress The address of the breakpoint.
275 * @param piHitTrigger The hit count at which the breakpoint start triggering.
276 * Use 0 (or 1) if it's gonna trigger at once.
277 * @param piHitDisable The hit count which disables the breakpoint.
278 * Use ~(uint64_t) if it's never gonna be disabled.
279 * @param piBp Where to store the breakpoint id. (optional)
280 * @thread Any thread.
281 */
282static DECLCALLBACK(int) dbgfR3BpSetInt3(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger,
283 uint64_t *piHitDisable, uint32_t *piBp)
284{
285 /*
286 * Validate input.
287 */
288 PVM pVM = pUVM->pVM;
289 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
290 if (!DBGFR3AddrIsValid(pUVM, pAddress))
291 return VERR_INVALID_PARAMETER;
292 if (*piHitTrigger > *piHitDisable)
293 return VERR_INVALID_PARAMETER;
294 AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
295 if (piBp)
296 *piBp = ~0;
297
298 /*
299 * Check if the breakpoint already exists.
300 */
301 PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_INT3, pAddress->FlatPtr);
302 if (pBp)
303 {
304 int rc = VINF_SUCCESS;
305 if (!pBp->fEnabled)
306 rc = dbgfR3BpInt3Arm(pUVM, pBp);
307 if (RT_SUCCESS(rc))
308 {
309 rc = VINF_DBGF_BP_ALREADY_EXIST;
310 if (piBp)
311 *piBp = pBp->iBp;
312 }
313 return rc;
314 }
315
316 /*
317 * Allocate and initialize the bp.
318 */
319 pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_INT3);
320 if (!pBp)
321 return VERR_DBGF_NO_MORE_BP_SLOTS;
322 pBp->GCPtr = pAddress->FlatPtr;
323 pBp->iHitTrigger = *piHitTrigger;
324 pBp->iHitDisable = *piHitDisable;
325 pBp->fEnabled = true;
326
327 /*
328 * Now ask REM to set the breakpoint.
329 */
330 int rc = dbgfR3BpInt3Arm(pUVM, pBp);
331 if (RT_SUCCESS(rc))
332 {
333 if (piBp)
334 *piBp = pBp->iBp;
335 }
336 else
337 dbgfR3BpFree(pVM, pBp);
338
339 return rc;
340}
341
342
343/**
344 * Sets a breakpoint (int 3 based).
345 *
346 * @returns VBox status code.
347 * @param pUVM The user mode VM handle.
348 * @param pAddress The address of the breakpoint.
349 * @param iHitTrigger The hit count at which the breakpoint start triggering.
350 * Use 0 (or 1) if it's gonna trigger at once.
351 * @param iHitDisable The hit count which disables the breakpoint.
352 * Use ~(uint64_t) if it's never gonna be disabled.
353 * @param piBp Where to store the breakpoint id. (optional)
354 * @thread Any thread.
355 */
356VMMR3DECL(int) DBGFR3BpSet(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp)
357{
358 /*
359 * This must be done on EMT.
360 */
361 /** @todo SMP? */
362 int rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3BpSetInt3, 5,
363 pUVM, pAddress, &iHitTrigger, &iHitDisable, piBp);
364 LogFlow(("DBGFR3BpSet: returns %Rrc\n", rc));
365 return rc;
366}
367
368
369/**
370 * Arms an int 3 breakpoint.
371 * This is used to implement both DBGFR3BpSetReg() and DBGFR3BpEnable().
372 *
373 * @returns VBox status code.
374 * @param pUVM The user mode VM handle.
375 * @param pBp The breakpoint.
376 */
377static int dbgfR3BpInt3Arm(PUVM pUVM, PDBGFBP pBp)
378{
379 /** @todo should actually use physical address here! */
380
381 /** @todo SMP support! */
382 VMCPUID idCpu = 0;
383
384 /*
385 * Save current byte and write int3 instruction.
386 */
387 DBGFADDRESS Addr;
388 DBGFR3AddrFromFlat(pUVM, &Addr, pBp->GCPtr);
389 int rc = DBGFR3MemRead(pUVM, idCpu, &Addr, &pBp->u.Int3.bOrg, 1);
390 if (RT_SUCCESS(rc))
391 {
392 static const uint8_t s_bInt3 = 0xcc;
393 rc = DBGFR3MemWrite(pUVM, idCpu, &Addr, &s_bInt3, 1);
394 }
395 return rc;
396}
397
398
399/**
400 * Disarms an int 3 breakpoint.
401 * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable().
402 *
403 * @returns VBox status code.
404 * @param pUVM The user mode VM handle.
405 * @param pBp The breakpoint.
406 */
407static int dbgfR3BpInt3Disarm(PUVM pUVM, PDBGFBP pBp)
408{
409 /* @todo SMP support! */
410 VMCPUID idCpu = 0;
411
412 /*
413 * Check that the current byte is the int3 instruction, and restore the original one.
414 * We currently ignore invalid bytes.
415 */
416 DBGFADDRESS Addr;
417 DBGFR3AddrFromFlat(pUVM, &Addr, pBp->GCPtr);
418 uint8_t bCurrent;
419 int rc = DBGFR3MemRead(pUVM, idCpu, &Addr, &bCurrent, 1);
420 if (bCurrent == 0xcc)
421 rc = DBGFR3MemWrite(pUVM, idCpu, &Addr, &pBp->u.Int3.bOrg, 1);
422 return rc;
423}
424
425
426/**
427 * Sets a register breakpoint.
428 *
429 * @returns VBox status code.
430 * @param pUVM The user mode VM handle.
431 * @param pAddress The address of the breakpoint.
432 * @param piHitTrigger The hit count at which the breakpoint start triggering.
433 * Use 0 (or 1) if it's gonna trigger at once.
434 * @param piHitDisable The hit count which disables the breakpoint.
435 * Use ~(uint64_t) if it's never gonna be disabled.
436 * @param fType The access type (one of the X86_DR7_RW_* defines).
437 * @param cb The access size - 1,2,4 or 8 (the latter is AMD64 long mode only.
438 * Must be 1 if fType is X86_DR7_RW_EO.
439 * @param piBp Where to store the breakpoint id. (optional)
440 * @thread EMT
441 * @internal
442 */
443static DECLCALLBACK(int) dbgfR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable,
444 uint8_t fType, uint8_t cb, uint32_t *piBp)
445{
446 /*
447 * Validate input.
448 */
449 PVM pVM = pUVM->pVM;
450 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
451 if (!DBGFR3AddrIsValid(pUVM, pAddress))
452 return VERR_INVALID_PARAMETER;
453 if (*piHitTrigger > *piHitDisable)
454 return VERR_INVALID_PARAMETER;
455 AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
456 if (piBp)
457 *piBp = ~0;
458 switch (fType)
459 {
460 case X86_DR7_RW_EO:
461 if (cb == 1)
462 break;
463 AssertMsgFailed(("fType=%#x cb=%d != 1\n", fType, cb));
464 return VERR_INVALID_PARAMETER;
465 case X86_DR7_RW_IO:
466 case X86_DR7_RW_RW:
467 case X86_DR7_RW_WO:
468 break;
469 default:
470 AssertMsgFailed(("fType=%#x\n", fType));
471 return VERR_INVALID_PARAMETER;
472 }
473 switch (cb)
474 {
475 case 1:
476 case 2:
477 case 4:
478 break;
479 default:
480 AssertMsgFailed(("cb=%#x\n", cb));
481 return VERR_INVALID_PARAMETER;
482 }
483
484 /*
485 * Check if the breakpoint already exists.
486 */
487 PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REG, pAddress->FlatPtr);
488 if ( pBp
489 && pBp->u.Reg.cb == cb
490 && pBp->u.Reg.fType == fType)
491 {
492 int rc = VINF_SUCCESS;
493 if (!pBp->fEnabled)
494 rc = dbgfR3BpRegArm(pVM, pBp);
495 if (RT_SUCCESS(rc))
496 {
497 rc = VINF_DBGF_BP_ALREADY_EXIST;
498 if (piBp)
499 *piBp = pBp->iBp;
500 }
501 return rc;
502 }
503
504 /*
505 * Allocate and initialize the bp.
506 */
507 pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REG);
508 if (!pBp)
509 return VERR_DBGF_NO_MORE_BP_SLOTS;
510 pBp->GCPtr = pAddress->FlatPtr;
511 pBp->iHitTrigger = *piHitTrigger;
512 pBp->iHitDisable = *piHitDisable;
513 pBp->fEnabled = true;
514 Assert(pBp->iBp == pBp->u.Reg.iReg);
515 pBp->u.Reg.fType = fType;
516 pBp->u.Reg.cb = cb;
517
518 /*
519 * Arm the breakpoint.
520 */
521 int rc = dbgfR3BpRegArm(pVM, pBp);
522 if (RT_SUCCESS(rc))
523 {
524 if (piBp)
525 *piBp = pBp->iBp;
526 }
527 else
528 dbgfR3BpFree(pVM, pBp);
529
530 return rc;
531}
532
533
534/**
535 * Sets a register breakpoint.
536 *
537 * @returns VBox status code.
538 * @param pUVM The user mode VM handle.
539 * @param pAddress The address of the breakpoint.
540 * @param iHitTrigger The hit count at which the breakpoint start triggering.
541 * Use 0 (or 1) if it's gonna trigger at once.
542 * @param iHitDisable The hit count which disables the breakpoint.
543 * Use ~(uint64_t) if it's never gonna be disabled.
544 * @param fType The access type (one of the X86_DR7_RW_* defines).
545 * @param cb The access size - 1,2,4 or 8 (the latter is AMD64 long mode only.
546 * Must be 1 if fType is X86_DR7_RW_EO.
547 * @param piBp Where to store the breakpoint id. (optional)
548 * @thread Any thread.
549 */
550VMMR3DECL(int) DBGFR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable,
551 uint8_t fType, uint8_t cb, uint32_t *piBp)
552{
553 /*
554 * This must be done on EMT.
555 */
556 int rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3BpSetReg, 7,
557 pUVM, pAddress, &iHitTrigger, &iHitDisable, fType, cb, piBp);
558 LogFlow(("DBGFR3BpSetReg: returns %Rrc\n", rc));
559 return rc;
560
561}
562
563
564/** @callback_method_impl{FNVMMEMTRENDEZVOUS} */
565DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpRegRecalcOnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
566{
567 NOREF(pVM); NOREF(pvUser);
568 return CPUMRecalcHyperDRx(pVCpu, UINT8_MAX, false);
569}
570
571
572/**
573 * Arms a debug register breakpoint.
574 * This is used to implement both DBGFR3BpSetReg() and DBGFR3BpEnable().
575 *
576 * @returns VBox status code.
577 * @param pUVM The user mode VM handle.
578 * @param pBp The breakpoint.
579 */
580static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp)
581{
582 Assert(pBp->fEnabled);
583 return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpRegRecalcOnCpu, NULL);
584}
585
586
587/**
588 * Disarms a debug register breakpoint.
589 * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable().
590 *
591 * @returns VBox status code.
592 * @param pUVM The user mode VM handle.
593 * @param pBp The breakpoint.
594 */
595static int dbgfR3BpRegDisarm(PVM pVM, PDBGFBP pBp)
596{
597 Assert(!pBp->fEnabled);
598 return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpRegRecalcOnCpu, NULL);
599}
600
601
602/**
603 * EMT worker for DBGFR3BpSetREM().
604 *
605 * @returns VBox status code.
606 * @param pUVM The user mode VM handle.
607 * @param pAddress The address of the breakpoint.
608 * @param piHitTrigger The hit count at which the breakpoint start triggering.
609 * Use 0 (or 1) if it's gonna trigger at once.
610 * @param piHitDisable The hit count which disables the breakpoint.
611 * Use ~(uint64_t) if it's never gonna be disabled.
612 * @param piBp Where to store the breakpoint id. (optional)
613 * @thread EMT
614 * @internal
615 */
616static DECLCALLBACK(int) dbgfR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger,
617 uint64_t *piHitDisable, uint32_t *piBp)
618{
619 /*
620 * Validate input.
621 */
622 PVM pVM = pUVM->pVM;
623 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
624 if (!DBGFR3AddrIsValid(pUVM, pAddress))
625 return VERR_INVALID_PARAMETER;
626 if (*piHitTrigger > *piHitDisable)
627 return VERR_INVALID_PARAMETER;
628 AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
629 if (piBp)
630 *piBp = ~0;
631
632
633 /*
634 * Check if the breakpoint already exists.
635 */
636 PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REM, pAddress->FlatPtr);
637 if (pBp)
638 {
639 int rc = VINF_SUCCESS;
640 if (!pBp->fEnabled)
641#ifdef VBOX_WITH_REM
642 rc = REMR3BreakpointSet(pVM, pBp->GCPtr);
643#else
644 rc = IEMBreakpointSet(pVM, pBp->GCPtr);
645#endif
646 if (RT_SUCCESS(rc))
647 {
648 rc = VINF_DBGF_BP_ALREADY_EXIST;
649 if (piBp)
650 *piBp = pBp->iBp;
651 }
652 return rc;
653 }
654
655 /*
656 * Allocate and initialize the bp.
657 */
658 pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REM);
659 if (!pBp)
660 return VERR_DBGF_NO_MORE_BP_SLOTS;
661 pBp->GCPtr = pAddress->FlatPtr;
662 pBp->iHitTrigger = *piHitTrigger;
663 pBp->iHitDisable = *piHitDisable;
664 pBp->fEnabled = true;
665
666 /*
667 * Now ask REM to set the breakpoint.
668 */
669#ifdef VBOX_WITH_REM
670 int rc = REMR3BreakpointSet(pVM, pAddress->FlatPtr);
671#else
672 int rc = IEMBreakpointSet(pVM, pAddress->FlatPtr);
673#endif
674 if (RT_SUCCESS(rc))
675 {
676 if (piBp)
677 *piBp = pBp->iBp;
678 }
679 else
680 dbgfR3BpFree(pVM, pBp);
681
682 return rc;
683}
684
685
686/**
687 * Sets a recompiler breakpoint.
688 *
689 * @returns VBox status code.
690 * @param pUVM The user mode VM handle.
691 * @param pAddress The address of the breakpoint.
692 * @param iHitTrigger The hit count at which the breakpoint start triggering.
693 * Use 0 (or 1) if it's gonna trigger at once.
694 * @param iHitDisable The hit count which disables the breakpoint.
695 * Use ~(uint64_t) if it's never gonna be disabled.
696 * @param piBp Where to store the breakpoint id. (optional)
697 * @thread Any thread.
698 */
699VMMR3DECL(int) DBGFR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp)
700{
701 /*
702 * This must be done on EMT.
703 */
704 int rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3BpSetREM, 5,
705 pUVM, pAddress, &iHitTrigger, &iHitDisable, piBp);
706 LogFlow(("DBGFR3BpSetREM: returns %Rrc\n", rc));
707 return rc;
708}
709
710
711/**
712 * EMT worker for DBGFR3BpClear().
713 *
714 * @returns VBox status code.
715 * @param pUVM The user mode VM handle.
716 * @param iBp The id of the breakpoint which should be removed (cleared).
717 * @thread EMT
718 * @internal
719 */
720static DECLCALLBACK(int) dbgfR3BpClear(PUVM pUVM, uint32_t iBp)
721{
722 /*
723 * Validate input.
724 */
725 PVM pVM = pUVM->pVM;
726 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
727 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
728 if (!pBp)
729 return VERR_DBGF_BP_NOT_FOUND;
730
731 /*
732 * Disarm the breakpoint if it's enabled.
733 */
734 if (pBp->fEnabled)
735 {
736 pBp->fEnabled = false;
737 int rc;
738 switch (pBp->enmType)
739 {
740 case DBGFBPTYPE_REG:
741 rc = dbgfR3BpRegDisarm(pVM, pBp);
742 break;
743
744 case DBGFBPTYPE_INT3:
745 rc = dbgfR3BpInt3Disarm(pUVM, pBp);
746 break;
747
748 case DBGFBPTYPE_REM:
749#ifdef VBOX_WITH_REM
750 rc = REMR3BreakpointClear(pVM, pBp->GCPtr);
751#else
752 rc = IEMBreakpointClear(pVM, pBp->GCPtr);
753#endif
754 break;
755
756 default:
757 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
758 }
759 AssertRCReturn(rc, rc);
760 }
761
762 /*
763 * Free the breakpoint.
764 */
765 dbgfR3BpFree(pVM, pBp);
766 return VINF_SUCCESS;
767}
768
769
770/**
771 * Clears a breakpoint.
772 *
773 * @returns VBox status code.
774 * @param pUVM The user mode VM handle.
775 * @param iBp The id of the breakpoint which should be removed (cleared).
776 * @thread Any thread.
777 */
778VMMR3DECL(int) DBGFR3BpClear(PUVM pUVM, uint32_t iBp)
779{
780 /*
781 * This must be done on EMT.
782 */
783 int rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3BpClear, 2, pUVM, iBp);
784 LogFlow(("DBGFR3BpClear: returns %Rrc\n", rc));
785 return rc;
786}
787
788
789/**
790 * EMT worker for DBGFR3BpEnable().
791 *
792 * @returns VBox status code.
793 * @param pUVM The user mode VM handle.
794 * @param iBp The id of the breakpoint which should be enabled.
795 * @thread EMT
796 * @internal
797 */
798static DECLCALLBACK(int) dbgfR3BpEnable(PUVM pUVM, uint32_t iBp)
799{
800 /*
801 * Validate input.
802 */
803 PVM pVM = pUVM->pVM;
804 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
805 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
806 if (!pBp)
807 return VERR_DBGF_BP_NOT_FOUND;
808
809 /*
810 * Already enabled?
811 */
812 if (pBp->fEnabled)
813 return VINF_DBGF_BP_ALREADY_ENABLED;
814
815 /*
816 * Remove the breakpoint.
817 */
818 int rc;
819 pBp->fEnabled = true;
820 switch (pBp->enmType)
821 {
822 case DBGFBPTYPE_REG:
823 rc = dbgfR3BpRegArm(pVM, pBp);
824 break;
825
826 case DBGFBPTYPE_INT3:
827 rc = dbgfR3BpInt3Arm(pUVM, pBp);
828 break;
829
830 case DBGFBPTYPE_REM:
831#ifdef VBOX_WITH_REM
832 rc = REMR3BreakpointSet(pVM, pBp->GCPtr);
833#else
834 rc = IEMBreakpointSet(pVM, pBp->GCPtr);
835#endif
836 break;
837
838 default:
839 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
840 }
841 if (RT_FAILURE(rc))
842 pBp->fEnabled = false;
843
844 return rc;
845}
846
847
848/**
849 * Enables a breakpoint.
850 *
851 * @returns VBox status code.
852 * @param pUVM The user mode VM handle.
853 * @param iBp The id of the breakpoint which should be enabled.
854 * @thread Any thread.
855 */
856VMMR3DECL(int) DBGFR3BpEnable(PUVM pUVM, uint32_t iBp)
857{
858 /*
859 * This must be done on EMT.
860 */
861 int rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3BpEnable, 2, pUVM, iBp);
862 LogFlow(("DBGFR3BpEnable: returns %Rrc\n", rc));
863 return rc;
864}
865
866
867/**
868 * EMT worker for DBGFR3BpDisable().
869 *
870 * @returns VBox status code.
871 * @param pUVM The user mode VM handle.
872 * @param iBp The id of the breakpoint which should be disabled.
873 * @thread EMT
874 * @internal
875 */
876static DECLCALLBACK(int) dbgfR3BpDisable(PUVM pUVM, uint32_t iBp)
877{
878 /*
879 * Validate input.
880 */
881 PVM pVM = pUVM->pVM;
882 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
883 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
884 if (!pBp)
885 return VERR_DBGF_BP_NOT_FOUND;
886
887 /*
888 * Already enabled?
889 */
890 if (!pBp->fEnabled)
891 return VINF_DBGF_BP_ALREADY_DISABLED;
892
893 /*
894 * Remove the breakpoint.
895 */
896 pBp->fEnabled = false;
897 int rc;
898 switch (pBp->enmType)
899 {
900 case DBGFBPTYPE_REG:
901 rc = dbgfR3BpRegDisarm(pVM, pBp);
902 break;
903
904 case DBGFBPTYPE_INT3:
905 rc = dbgfR3BpInt3Disarm(pUVM, pBp);
906 break;
907
908 case DBGFBPTYPE_REM:
909#ifdef VBOX_WITH_REM
910 rc = REMR3BreakpointClear(pVM, pBp->GCPtr);
911#else
912 rc = IEMBreakpointClear(pVM, pBp->GCPtr);
913#endif
914 break;
915
916 default:
917 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
918 }
919
920 return rc;
921}
922
923
924/**
925 * Disables a breakpoint.
926 *
927 * @returns VBox status code.
928 * @param pUVM The user mode VM handle.
929 * @param iBp The id of the breakpoint which should be disabled.
930 * @thread Any thread.
931 */
932VMMR3DECL(int) DBGFR3BpDisable(PUVM pUVM, uint32_t iBp)
933{
934 /*
935 * This must be done on EMT.
936 */
937 int rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3BpDisable, 2, pUVM, iBp);
938 LogFlow(("DBGFR3BpDisable: returns %Rrc\n", rc));
939 return rc;
940}
941
942
943/**
944 * EMT worker for DBGFR3BpEnum().
945 *
946 * @returns VBox status code.
947 * @param pUVM The user mode VM handle.
948 * @param pfnCallback The callback function.
949 * @param pvUser The user argument to pass to the callback.
950 * @thread EMT
951 * @internal
952 */
953static DECLCALLBACK(int) dbgfR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
954{
955 /*
956 * Validate input.
957 */
958 PVM pVM = pUVM->pVM;
959 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
960 AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
961
962 /*
963 * Enumerate the hardware breakpoints.
964 */
965 unsigned i;
966 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
967 if (pVM->dbgf.s.aHwBreakpoints[i].enmType != DBGFBPTYPE_FREE)
968 {
969 int rc = pfnCallback(pUVM, pvUser, &pVM->dbgf.s.aHwBreakpoints[i]);
970 if (RT_FAILURE(rc))
971 return rc;
972 }
973
974 /*
975 * Enumerate the other breakpoints.
976 */
977 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
978 if (pVM->dbgf.s.aBreakpoints[i].enmType != DBGFBPTYPE_FREE)
979 {
980 int rc = pfnCallback(pUVM, pvUser, &pVM->dbgf.s.aBreakpoints[i]);
981 if (RT_FAILURE(rc))
982 return rc;
983 }
984
985 return VINF_SUCCESS;
986}
987
988
989/**
990 * Enumerate the breakpoints.
991 *
992 * @returns VBox status code.
993 * @param pUVM The user mode VM handle.
994 * @param pfnCallback The callback function.
995 * @param pvUser The user argument to pass to the callback.
996 * @thread Any thread but the callback will be called from EMT.
997 */
998VMMR3DECL(int) DBGFR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
999{
1000 /*
1001 * This must be done on EMT.
1002 */
1003 int rc = VMR3ReqPriorityCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3BpEnum, 3, pUVM, pfnCallback, pvUser);
1004 LogFlow(("DBGFR3BpClear: returns %Rrc\n", rc));
1005 return rc;
1006}
1007
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use