VirtualBox

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

Last change on this file since 58591 was 58126, checked in by vboxsync, 9 years ago

VMM: Fixed almost all the Doxygen warnings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 27.5 KB
Line 
1/* $Id: DBGFBp.cpp 58126 2015-10-08 20:59:48Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Breakpoint Management.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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 The cross context VM structure.
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 The cross context VM structure.
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 The cross context VM structure.
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 The cross context VM structure.
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 The cross context VM structure.
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/**
565 * @callback_method_impl{FNVMMEMTRENDEZVOUS}
566 */
567DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpRegRecalcOnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
568{
569 NOREF(pVM); NOREF(pvUser);
570 return CPUMRecalcHyperDRx(pVCpu, UINT8_MAX, false);
571}
572
573
574/**
575 * Arms a debug register breakpoint.
576 * This is used to implement both DBGFR3BpSetReg() and DBGFR3BpEnable().
577 *
578 * @returns VBox status code.
579 * @param pVM The cross context VM structure.
580 * @param pBp The breakpoint.
581 */
582static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp)
583{
584 Assert(pBp->fEnabled);
585 return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpRegRecalcOnCpu, NULL);
586}
587
588
589/**
590 * Disarms a debug register breakpoint.
591 * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable().
592 *
593 * @returns VBox status code.
594 * @param pVM The cross context VM structure.
595 * @param pBp The breakpoint.
596 */
597static int dbgfR3BpRegDisarm(PVM pVM, PDBGFBP pBp)
598{
599 Assert(!pBp->fEnabled);
600 return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpRegRecalcOnCpu, NULL);
601}
602
603
604/**
605 * EMT worker for DBGFR3BpSetREM().
606 *
607 * @returns VBox status code.
608 * @param pUVM The user mode VM handle.
609 * @param pAddress The address of the breakpoint.
610 * @param piHitTrigger The hit count at which the breakpoint start triggering.
611 * Use 0 (or 1) if it's gonna trigger at once.
612 * @param piHitDisable The hit count which disables the breakpoint.
613 * Use ~(uint64_t) if it's never gonna be disabled.
614 * @param piBp Where to store the breakpoint id. (optional)
615 * @thread EMT
616 * @internal
617 */
618static DECLCALLBACK(int) dbgfR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger,
619 uint64_t *piHitDisable, uint32_t *piBp)
620{
621 /*
622 * Validate input.
623 */
624 PVM pVM = pUVM->pVM;
625 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
626 if (!DBGFR3AddrIsValid(pUVM, pAddress))
627 return VERR_INVALID_PARAMETER;
628 if (*piHitTrigger > *piHitDisable)
629 return VERR_INVALID_PARAMETER;
630 AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
631 if (piBp)
632 *piBp = ~0;
633
634
635 /*
636 * Check if the breakpoint already exists.
637 */
638 PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REM, pAddress->FlatPtr);
639 if (pBp)
640 {
641 int rc = VINF_SUCCESS;
642 if (!pBp->fEnabled)
643#ifdef VBOX_WITH_REM
644 rc = REMR3BreakpointSet(pVM, pBp->GCPtr);
645#else
646 rc = IEMBreakpointSet(pVM, pBp->GCPtr);
647#endif
648 if (RT_SUCCESS(rc))
649 {
650 rc = VINF_DBGF_BP_ALREADY_EXIST;
651 if (piBp)
652 *piBp = pBp->iBp;
653 }
654 return rc;
655 }
656
657 /*
658 * Allocate and initialize the bp.
659 */
660 pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REM);
661 if (!pBp)
662 return VERR_DBGF_NO_MORE_BP_SLOTS;
663 pBp->GCPtr = pAddress->FlatPtr;
664 pBp->iHitTrigger = *piHitTrigger;
665 pBp->iHitDisable = *piHitDisable;
666 pBp->fEnabled = true;
667
668 /*
669 * Now ask REM to set the breakpoint.
670 */
671#ifdef VBOX_WITH_REM
672 int rc = REMR3BreakpointSet(pVM, pAddress->FlatPtr);
673#else
674 int rc = IEMBreakpointSet(pVM, pAddress->FlatPtr);
675#endif
676 if (RT_SUCCESS(rc))
677 {
678 if (piBp)
679 *piBp = pBp->iBp;
680 }
681 else
682 dbgfR3BpFree(pVM, pBp);
683
684 return rc;
685}
686
687
688/**
689 * Sets a recompiler breakpoint.
690 *
691 * @returns VBox status code.
692 * @param pUVM The user mode VM handle.
693 * @param pAddress The address of the breakpoint.
694 * @param iHitTrigger The hit count at which the breakpoint start triggering.
695 * Use 0 (or 1) if it's gonna trigger at once.
696 * @param iHitDisable The hit count which disables the breakpoint.
697 * Use ~(uint64_t) if it's never gonna be disabled.
698 * @param piBp Where to store the breakpoint id. (optional)
699 * @thread Any thread.
700 */
701VMMR3DECL(int) DBGFR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp)
702{
703 /*
704 * This must be done on EMT.
705 */
706 int rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3BpSetREM, 5,
707 pUVM, pAddress, &iHitTrigger, &iHitDisable, piBp);
708 LogFlow(("DBGFR3BpSetREM: returns %Rrc\n", rc));
709 return rc;
710}
711
712
713/**
714 * EMT worker for DBGFR3BpClear().
715 *
716 * @returns VBox status code.
717 * @param pUVM The user mode VM handle.
718 * @param iBp The id of the breakpoint which should be removed (cleared).
719 * @thread EMT
720 * @internal
721 */
722static DECLCALLBACK(int) dbgfR3BpClear(PUVM pUVM, uint32_t iBp)
723{
724 /*
725 * Validate input.
726 */
727 PVM pVM = pUVM->pVM;
728 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
729 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
730 if (!pBp)
731 return VERR_DBGF_BP_NOT_FOUND;
732
733 /*
734 * Disarm the breakpoint if it's enabled.
735 */
736 if (pBp->fEnabled)
737 {
738 pBp->fEnabled = false;
739 int rc;
740 switch (pBp->enmType)
741 {
742 case DBGFBPTYPE_REG:
743 rc = dbgfR3BpRegDisarm(pVM, pBp);
744 break;
745
746 case DBGFBPTYPE_INT3:
747 rc = dbgfR3BpInt3Disarm(pUVM, pBp);
748 break;
749
750 case DBGFBPTYPE_REM:
751#ifdef VBOX_WITH_REM
752 rc = REMR3BreakpointClear(pVM, pBp->GCPtr);
753#else
754 rc = IEMBreakpointClear(pVM, pBp->GCPtr);
755#endif
756 break;
757
758 default:
759 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
760 }
761 AssertRCReturn(rc, rc);
762 }
763
764 /*
765 * Free the breakpoint.
766 */
767 dbgfR3BpFree(pVM, pBp);
768 return VINF_SUCCESS;
769}
770
771
772/**
773 * Clears a breakpoint.
774 *
775 * @returns VBox status code.
776 * @param pUVM The user mode VM handle.
777 * @param iBp The id of the breakpoint which should be removed (cleared).
778 * @thread Any thread.
779 */
780VMMR3DECL(int) DBGFR3BpClear(PUVM pUVM, uint32_t iBp)
781{
782 /*
783 * This must be done on EMT.
784 */
785 int rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3BpClear, 2, pUVM, iBp);
786 LogFlow(("DBGFR3BpClear: returns %Rrc\n", rc));
787 return rc;
788}
789
790
791/**
792 * EMT worker for DBGFR3BpEnable().
793 *
794 * @returns VBox status code.
795 * @param pUVM The user mode VM handle.
796 * @param iBp The id of the breakpoint which should be enabled.
797 * @thread EMT
798 * @internal
799 */
800static DECLCALLBACK(int) dbgfR3BpEnable(PUVM pUVM, uint32_t iBp)
801{
802 /*
803 * Validate input.
804 */
805 PVM pVM = pUVM->pVM;
806 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
807 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
808 if (!pBp)
809 return VERR_DBGF_BP_NOT_FOUND;
810
811 /*
812 * Already enabled?
813 */
814 if (pBp->fEnabled)
815 return VINF_DBGF_BP_ALREADY_ENABLED;
816
817 /*
818 * Remove the breakpoint.
819 */
820 int rc;
821 pBp->fEnabled = true;
822 switch (pBp->enmType)
823 {
824 case DBGFBPTYPE_REG:
825 rc = dbgfR3BpRegArm(pVM, pBp);
826 break;
827
828 case DBGFBPTYPE_INT3:
829 rc = dbgfR3BpInt3Arm(pUVM, pBp);
830 break;
831
832 case DBGFBPTYPE_REM:
833#ifdef VBOX_WITH_REM
834 rc = REMR3BreakpointSet(pVM, pBp->GCPtr);
835#else
836 rc = IEMBreakpointSet(pVM, pBp->GCPtr);
837#endif
838 break;
839
840 default:
841 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
842 }
843 if (RT_FAILURE(rc))
844 pBp->fEnabled = false;
845
846 return rc;
847}
848
849
850/**
851 * Enables a breakpoint.
852 *
853 * @returns VBox status code.
854 * @param pUVM The user mode VM handle.
855 * @param iBp The id of the breakpoint which should be enabled.
856 * @thread Any thread.
857 */
858VMMR3DECL(int) DBGFR3BpEnable(PUVM pUVM, uint32_t iBp)
859{
860 /*
861 * This must be done on EMT.
862 */
863 int rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3BpEnable, 2, pUVM, iBp);
864 LogFlow(("DBGFR3BpEnable: returns %Rrc\n", rc));
865 return rc;
866}
867
868
869/**
870 * EMT worker for DBGFR3BpDisable().
871 *
872 * @returns VBox status code.
873 * @param pUVM The user mode VM handle.
874 * @param iBp The id of the breakpoint which should be disabled.
875 * @thread EMT
876 * @internal
877 */
878static DECLCALLBACK(int) dbgfR3BpDisable(PUVM pUVM, uint32_t iBp)
879{
880 /*
881 * Validate input.
882 */
883 PVM pVM = pUVM->pVM;
884 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
885 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
886 if (!pBp)
887 return VERR_DBGF_BP_NOT_FOUND;
888
889 /*
890 * Already enabled?
891 */
892 if (!pBp->fEnabled)
893 return VINF_DBGF_BP_ALREADY_DISABLED;
894
895 /*
896 * Remove the breakpoint.
897 */
898 pBp->fEnabled = false;
899 int rc;
900 switch (pBp->enmType)
901 {
902 case DBGFBPTYPE_REG:
903 rc = dbgfR3BpRegDisarm(pVM, pBp);
904 break;
905
906 case DBGFBPTYPE_INT3:
907 rc = dbgfR3BpInt3Disarm(pUVM, pBp);
908 break;
909
910 case DBGFBPTYPE_REM:
911#ifdef VBOX_WITH_REM
912 rc = REMR3BreakpointClear(pVM, pBp->GCPtr);
913#else
914 rc = IEMBreakpointClear(pVM, pBp->GCPtr);
915#endif
916 break;
917
918 default:
919 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
920 }
921
922 return rc;
923}
924
925
926/**
927 * Disables a breakpoint.
928 *
929 * @returns VBox status code.
930 * @param pUVM The user mode VM handle.
931 * @param iBp The id of the breakpoint which should be disabled.
932 * @thread Any thread.
933 */
934VMMR3DECL(int) DBGFR3BpDisable(PUVM pUVM, uint32_t iBp)
935{
936 /*
937 * This must be done on EMT.
938 */
939 int rc = VMR3ReqCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3BpDisable, 2, pUVM, iBp);
940 LogFlow(("DBGFR3BpDisable: returns %Rrc\n", rc));
941 return rc;
942}
943
944
945/**
946 * EMT worker for DBGFR3BpEnum().
947 *
948 * @returns VBox status code.
949 * @param pUVM The user mode VM handle.
950 * @param pfnCallback The callback function.
951 * @param pvUser The user argument to pass to the callback.
952 * @thread EMT
953 * @internal
954 */
955static DECLCALLBACK(int) dbgfR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
956{
957 /*
958 * Validate input.
959 */
960 PVM pVM = pUVM->pVM;
961 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
962 AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
963
964 /*
965 * Enumerate the hardware breakpoints.
966 */
967 unsigned i;
968 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
969 if (pVM->dbgf.s.aHwBreakpoints[i].enmType != DBGFBPTYPE_FREE)
970 {
971 int rc = pfnCallback(pUVM, pvUser, &pVM->dbgf.s.aHwBreakpoints[i]);
972 if (RT_FAILURE(rc))
973 return rc;
974 }
975
976 /*
977 * Enumerate the other breakpoints.
978 */
979 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
980 if (pVM->dbgf.s.aBreakpoints[i].enmType != DBGFBPTYPE_FREE)
981 {
982 int rc = pfnCallback(pUVM, pvUser, &pVM->dbgf.s.aBreakpoints[i]);
983 if (RT_FAILURE(rc))
984 return rc;
985 }
986
987 return VINF_SUCCESS;
988}
989
990
991/**
992 * Enumerate the breakpoints.
993 *
994 * @returns VBox status code.
995 * @param pUVM The user mode VM handle.
996 * @param pfnCallback The callback function.
997 * @param pvUser The user argument to pass to the callback.
998 * @thread Any thread but the callback will be called from EMT.
999 */
1000VMMR3DECL(int) DBGFR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
1001{
1002 /*
1003 * This must be done on EMT.
1004 */
1005 int rc = VMR3ReqPriorityCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3BpEnum, 3, pUVM, pfnCallback, pvUser);
1006 LogFlow(("DBGFR3BpClear: returns %Rrc\n", rc));
1007 return rc;
1008}
1009
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