[23] | 1 | /* $Id: DBGFBp.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
|
---|
[1] | 2 | /** @file
|
---|
[12677] | 3 | * DBGF - Debugger Facility, Breakpoint Management.
|
---|
[1] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[76553] | 7 | * Copyright (C) 2006-2019 Oracle Corporation
|
---|
[1] | 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
|
---|
[5999] | 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.
|
---|
[1] | 16 | */
|
---|
| 17 |
|
---|
| 18 |
|
---|
[57358] | 19 | /*********************************************************************************************************************************
|
---|
| 20 | * Header Files *
|
---|
| 21 | *********************************************************************************************************************************/
|
---|
[1] | 22 | #define LOG_GROUP LOG_GROUP_DBGF
|
---|
[35346] | 23 | #include <VBox/vmm/dbgf.h>
|
---|
| 24 | #include <VBox/vmm/selm.h>
|
---|
[40274] | 25 | #ifdef VBOX_WITH_REM
|
---|
| 26 | # include <VBox/vmm/rem.h>
|
---|
| 27 | #else
|
---|
| 28 | # include <VBox/vmm/iem.h>
|
---|
| 29 | #endif
|
---|
[44399] | 30 | #include <VBox/vmm/mm.h>
|
---|
[58903] | 31 | #include <VBox/vmm/iom.h>
|
---|
| 32 | #include <VBox/vmm/hm.h>
|
---|
[1] | 33 | #include "DBGFInternal.h"
|
---|
[35346] | 34 | #include <VBox/vmm/vm.h>
|
---|
[44399] | 35 | #include <VBox/vmm/uvm.h>
|
---|
| 36 |
|
---|
[1] | 37 | #include <VBox/err.h>
|
---|
| 38 | #include <VBox/log.h>
|
---|
| 39 | #include <iprt/assert.h>
|
---|
[23] | 40 | #include <iprt/string.h>
|
---|
[1] | 41 |
|
---|
| 42 |
|
---|
[57358] | 43 | /*********************************************************************************************************************************
|
---|
[64770] | 44 | * Structures and Typedefs *
|
---|
| 45 | *********************************************************************************************************************************/
|
---|
| 46 | /**
|
---|
| 47 | * DBGF INT3-breakpoint set callback arguments.
|
---|
| 48 | */
|
---|
| 49 | typedef struct DBGFBPINT3ARGS
|
---|
| 50 | {
|
---|
| 51 | /** The source virtual CPU ID (used for breakpoint address resolution). */
|
---|
| 52 | VMCPUID idSrcCpu;
|
---|
| 53 | /** The breakpoint address. */
|
---|
| 54 | PCDBGFADDRESS pAddress;
|
---|
| 55 | /** The hit count at which the breakpoint starts triggering. */
|
---|
| 56 | uint64_t iHitTrigger;
|
---|
| 57 | /** The hit count at which disables the breakpoint. */
|
---|
| 58 | uint64_t iHitDisable;
|
---|
| 59 | /** Where to store the breakpoint Id (optional). */
|
---|
| 60 | uint32_t *piBp;
|
---|
| 61 | } DBGFBPINT3ARGS;
|
---|
| 62 | /** Pointer to a DBGF INT3 breakpoint set callback argument. */
|
---|
| 63 | typedef DBGFBPINT3ARGS *PDBGFBPINT3ARGS;
|
---|
| 64 |
|
---|
| 65 |
|
---|
| 66 | /*********************************************************************************************************************************
|
---|
[57358] | 67 | * Internal Functions *
|
---|
| 68 | *********************************************************************************************************************************/
|
---|
[20374] | 69 | RT_C_DECLS_BEGIN
|
---|
[1] | 70 | static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp);
|
---|
[64770] | 71 | static int dbgfR3BpInt3Arm(PVM pVM, PDBGFBP pBp);
|
---|
[20374] | 72 | RT_C_DECLS_END
|
---|
[1] | 73 |
|
---|
| 74 |
|
---|
[12663] | 75 |
|
---|
[1] | 76 | /**
|
---|
| 77 | * Initialize the breakpoint stuff.
|
---|
| 78 | *
|
---|
| 79 | * @returns VINF_SUCCESS
|
---|
[58122] | 80 | * @param pVM The cross context VM structure.
|
---|
[1] | 81 | */
|
---|
| 82 | int dbgfR3BpInit(PVM pVM)
|
---|
| 83 | {
|
---|
| 84 | /*
|
---|
| 85 | * Init structures.
|
---|
| 86 | */
|
---|
| 87 | unsigned i;
|
---|
[11311] | 88 | for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
|
---|
[1] | 89 | {
|
---|
| 90 | pVM->dbgf.s.aHwBreakpoints[i].iBp = i;
|
---|
| 91 | pVM->dbgf.s.aHwBreakpoints[i].enmType = DBGFBPTYPE_FREE;
|
---|
| 92 | pVM->dbgf.s.aHwBreakpoints[i].u.Reg.iReg = i;
|
---|
| 93 | }
|
---|
| 94 |
|
---|
[11311] | 95 | for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
|
---|
[1] | 96 | {
|
---|
[11311] | 97 | pVM->dbgf.s.aBreakpoints[i].iBp = i + RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
|
---|
[1] | 98 | pVM->dbgf.s.aBreakpoints[i].enmType = DBGFBPTYPE_FREE;
|
---|
| 99 | }
|
---|
| 100 |
|
---|
[42834] | 101 | for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
|
---|
| 102 | {
|
---|
| 103 | PVMCPU pVCpu = &pVM->aCpus[idCpu];
|
---|
| 104 | pVCpu->dbgf.s.iActiveBp = ~0U;
|
---|
| 105 | }
|
---|
| 106 |
|
---|
[1] | 107 | /*
|
---|
| 108 | * Register saved state.
|
---|
| 109 | */
|
---|
| 110 | /** @todo */
|
---|
| 111 |
|
---|
| 112 | return VINF_SUCCESS;
|
---|
| 113 | }
|
---|
| 114 |
|
---|
| 115 |
|
---|
| 116 |
|
---|
| 117 | /**
|
---|
| 118 | * Allocate a breakpoint.
|
---|
| 119 | *
|
---|
| 120 | * @returns Pointer to the allocated breakpoint.
|
---|
| 121 | * @returns NULL if we're out of breakpoints.
|
---|
[58122] | 122 | * @param pVM The cross context VM structure.
|
---|
[1] | 123 | * @param enmType The type to allocate.
|
---|
| 124 | */
|
---|
| 125 | static PDBGFBP dbgfR3BpAlloc(PVM pVM, DBGFBPTYPE enmType)
|
---|
| 126 | {
|
---|
| 127 | /*
|
---|
[58909] | 128 | * Determine which array to search and where in the array to start
|
---|
| 129 | * searching (latter for grouping similar BPs, reducing runtime overhead).
|
---|
[1] | 130 | */
|
---|
[58909] | 131 | unsigned iStart;
|
---|
[35694] | 132 | unsigned cBps;
|
---|
| 133 | PDBGFBP paBps;
|
---|
[1] | 134 | switch (enmType)
|
---|
| 135 | {
|
---|
| 136 | case DBGFBPTYPE_REG:
|
---|
[11311] | 137 | cBps = RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
|
---|
[1] | 138 | paBps = &pVM->dbgf.s.aHwBreakpoints[0];
|
---|
[58909] | 139 | iStart = 0;
|
---|
[1] | 140 | break;
|
---|
| 141 |
|
---|
| 142 | case DBGFBPTYPE_INT3:
|
---|
| 143 | case DBGFBPTYPE_REM:
|
---|
[58909] | 144 | case DBGFBPTYPE_PORT_IO:
|
---|
| 145 | case DBGFBPTYPE_MMIO:
|
---|
[11311] | 146 | cBps = RT_ELEMENTS(pVM->dbgf.s.aBreakpoints);
|
---|
[1] | 147 | paBps = &pVM->dbgf.s.aBreakpoints[0];
|
---|
[58909] | 148 | if (enmType == DBGFBPTYPE_PORT_IO)
|
---|
| 149 | iStart = cBps / 4 * 2;
|
---|
| 150 | else if (enmType == DBGFBPTYPE_MMIO)
|
---|
| 151 | iStart = cBps / 4 * 1;
|
---|
| 152 | else if (enmType == DBGFBPTYPE_REM)
|
---|
| 153 | iStart = cBps / 4 * 3;
|
---|
| 154 | else
|
---|
| 155 | iStart = 0;
|
---|
[1] | 156 | break;
|
---|
| 157 |
|
---|
| 158 | default:
|
---|
| 159 | AssertMsgFailed(("enmType=%d\n", enmType));
|
---|
| 160 | return NULL;
|
---|
| 161 | }
|
---|
| 162 |
|
---|
| 163 | /*
|
---|
[58909] | 164 | * Search for a free breakpoint entry.
|
---|
[1] | 165 | */
|
---|
[58909] | 166 | unsigned iBp;
|
---|
| 167 | for (iBp = iStart; iBp < cBps; iBp++)
|
---|
[1] | 168 | if (paBps[iBp].enmType == DBGFBPTYPE_FREE)
|
---|
[58909] | 169 | break;
|
---|
| 170 | if (iBp >= cBps && iStart != 0)
|
---|
| 171 | for (iBp = 0; iBp < cBps; iBp++)
|
---|
| 172 | if (paBps[iBp].enmType == DBGFBPTYPE_FREE)
|
---|
| 173 | break;
|
---|
| 174 | if (iBp < cBps)
|
---|
| 175 | {
|
---|
| 176 | /*
|
---|
| 177 | * Return what we found.
|
---|
| 178 | */
|
---|
| 179 | paBps[iBp].fEnabled = false;
|
---|
| 180 | paBps[iBp].cHits = 0;
|
---|
| 181 | paBps[iBp].enmType = enmType;
|
---|
| 182 | return &paBps[iBp];
|
---|
| 183 | }
|
---|
| 184 |
|
---|
| 185 | LogFlow(("dbgfR3BpAlloc: returns NULL - we're out of breakpoint slots! cBps=%u\n", cBps));
|
---|
| 186 | return NULL;
|
---|
| 187 | }
|
---|
| 188 |
|
---|
| 189 |
|
---|
| 190 | /**
|
---|
[64770] | 191 | * Updates the search optimization structure for enabled breakpoints of the
|
---|
| 192 | * specified type.
|
---|
[58909] | 193 | *
|
---|
[64770] | 194 | * @returns VINF_SUCCESS.
|
---|
[58909] | 195 | * @param pVM The cross context VM structure.
|
---|
| 196 | * @param enmType The breakpoint type.
|
---|
| 197 | * @param pOpt The breakpoint optimization structure to update.
|
---|
| 198 | */
|
---|
| 199 | static int dbgfR3BpUpdateSearchOptimizations(PVM pVM, DBGFBPTYPE enmType, PDBGFBPSEARCHOPT pOpt)
|
---|
| 200 | {
|
---|
| 201 | DBGFBPSEARCHOPT Opt = { UINT32_MAX, 0 };
|
---|
| 202 |
|
---|
| 203 | for (uint32_t iBp = 0; iBp < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); iBp++)
|
---|
| 204 | if ( pVM->dbgf.s.aBreakpoints[iBp].enmType == enmType
|
---|
| 205 | && pVM->dbgf.s.aBreakpoints[iBp].fEnabled)
|
---|
[1] | 206 | {
|
---|
[58909] | 207 | if (Opt.iStartSearch > iBp)
|
---|
| 208 | Opt.iStartSearch = iBp;
|
---|
| 209 | Opt.cToSearch = iBp - Opt.iStartSearch + 1;
|
---|
[1] | 210 | }
|
---|
| 211 |
|
---|
[58909] | 212 | *pOpt = Opt;
|
---|
| 213 | return VINF_SUCCESS;
|
---|
[1] | 214 | }
|
---|
| 215 |
|
---|
| 216 |
|
---|
| 217 | /**
|
---|
| 218 | * Get a breakpoint give by breakpoint id.
|
---|
| 219 | *
|
---|
| 220 | * @returns Pointer to the allocated breakpoint.
|
---|
| 221 | * @returns NULL if the breakpoint is invalid.
|
---|
[58122] | 222 | * @param pVM The cross context VM structure.
|
---|
[1] | 223 | * @param iBp The breakpoint id.
|
---|
| 224 | */
|
---|
[35694] | 225 | static PDBGFBP dbgfR3BpGet(PVM pVM, uint32_t iBp)
|
---|
[1] | 226 | {
|
---|
| 227 | /* Find it. */
|
---|
| 228 | PDBGFBP pBp;
|
---|
[11311] | 229 | if (iBp < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints))
|
---|
[1] | 230 | pBp = &pVM->dbgf.s.aHwBreakpoints[iBp];
|
---|
| 231 | else
|
---|
| 232 | {
|
---|
[11311] | 233 | iBp -= RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
|
---|
| 234 | if (iBp >= RT_ELEMENTS(pVM->dbgf.s.aBreakpoints))
|
---|
[1] | 235 | return NULL;
|
---|
| 236 | pBp = &pVM->dbgf.s.aBreakpoints[iBp];
|
---|
| 237 | }
|
---|
| 238 |
|
---|
| 239 | /* check if it's valid. */
|
---|
| 240 | switch (pBp->enmType)
|
---|
| 241 | {
|
---|
| 242 | case DBGFBPTYPE_FREE:
|
---|
| 243 | return NULL;
|
---|
| 244 |
|
---|
| 245 | case DBGFBPTYPE_REG:
|
---|
| 246 | case DBGFBPTYPE_INT3:
|
---|
| 247 | case DBGFBPTYPE_REM:
|
---|
[58909] | 248 | case DBGFBPTYPE_PORT_IO:
|
---|
| 249 | case DBGFBPTYPE_MMIO:
|
---|
[1] | 250 | break;
|
---|
| 251 |
|
---|
| 252 | default:
|
---|
| 253 | AssertMsgFailed(("Invalid enmType=%d!\n", pBp->enmType));
|
---|
| 254 | return NULL;
|
---|
| 255 | }
|
---|
| 256 |
|
---|
| 257 | return pBp;
|
---|
| 258 | }
|
---|
| 259 |
|
---|
| 260 |
|
---|
| 261 | /**
|
---|
| 262 | * Get a breakpoint give by address.
|
---|
| 263 | *
|
---|
| 264 | * @returns Pointer to the allocated breakpoint.
|
---|
| 265 | * @returns NULL if the breakpoint is invalid.
|
---|
[58122] | 266 | * @param pVM The cross context VM structure.
|
---|
[1] | 267 | * @param enmType The breakpoint type.
|
---|
| 268 | * @param GCPtr The breakpoint address.
|
---|
| 269 | */
|
---|
| 270 | static PDBGFBP dbgfR3BpGetByAddr(PVM pVM, DBGFBPTYPE enmType, RTGCUINTPTR GCPtr)
|
---|
| 271 | {
|
---|
| 272 | /*
|
---|
[33540] | 273 | * Determine which array to search.
|
---|
[1] | 274 | */
|
---|
| 275 | unsigned cBps;
|
---|
| 276 | PDBGFBP paBps;
|
---|
| 277 | switch (enmType)
|
---|
| 278 | {
|
---|
| 279 | case DBGFBPTYPE_REG:
|
---|
[11311] | 280 | cBps = RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints);
|
---|
[1] | 281 | paBps = &pVM->dbgf.s.aHwBreakpoints[0];
|
---|
| 282 | break;
|
---|
| 283 |
|
---|
| 284 | case DBGFBPTYPE_INT3:
|
---|
| 285 | case DBGFBPTYPE_REM:
|
---|
[11311] | 286 | cBps = RT_ELEMENTS(pVM->dbgf.s.aBreakpoints);
|
---|
[1] | 287 | paBps = &pVM->dbgf.s.aBreakpoints[0];
|
---|
| 288 | break;
|
---|
| 289 |
|
---|
| 290 | default:
|
---|
| 291 | AssertMsgFailed(("enmType=%d\n", enmType));
|
---|
| 292 | return NULL;
|
---|
| 293 | }
|
---|
| 294 |
|
---|
| 295 | /*
|
---|
| 296 | * Search.
|
---|
| 297 | */
|
---|
| 298 | for (unsigned iBp = 0; iBp < cBps; iBp++)
|
---|
[58903] | 299 | if ( paBps[iBp].enmType == enmType
|
---|
| 300 | && paBps[iBp].u.GCPtr == GCPtr)
|
---|
[1] | 301 | return &paBps[iBp];
|
---|
| 302 |
|
---|
| 303 | return NULL;
|
---|
| 304 | }
|
---|
| 305 |
|
---|
| 306 |
|
---|
| 307 | /**
|
---|
| 308 | * Frees a breakpoint.
|
---|
| 309 | *
|
---|
[58122] | 310 | * @param pVM The cross context VM structure.
|
---|
[1] | 311 | * @param pBp The breakpoint to free.
|
---|
| 312 | */
|
---|
| 313 | static void dbgfR3BpFree(PVM pVM, PDBGFBP pBp)
|
---|
| 314 | {
|
---|
| 315 | switch (pBp->enmType)
|
---|
| 316 | {
|
---|
| 317 | case DBGFBPTYPE_FREE:
|
---|
| 318 | AssertMsgFailed(("Already freed!\n"));
|
---|
| 319 | return;
|
---|
| 320 |
|
---|
| 321 | case DBGFBPTYPE_REG:
|
---|
[58911] | 322 | Assert((uintptr_t)(pBp - &pVM->dbgf.s.aHwBreakpoints[0]) < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints));
|
---|
[1] | 323 | break;
|
---|
| 324 |
|
---|
| 325 | case DBGFBPTYPE_INT3:
|
---|
| 326 | case DBGFBPTYPE_REM:
|
---|
[58909] | 327 | case DBGFBPTYPE_PORT_IO:
|
---|
| 328 | case DBGFBPTYPE_MMIO:
|
---|
[58911] | 329 | Assert((uintptr_t)(pBp - &pVM->dbgf.s.aBreakpoints[0]) < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints));
|
---|
[1] | 330 | break;
|
---|
| 331 |
|
---|
| 332 | default:
|
---|
| 333 | AssertMsgFailed(("Invalid enmType=%d!\n", pBp->enmType));
|
---|
| 334 | return;
|
---|
| 335 |
|
---|
| 336 | }
|
---|
| 337 | pBp->enmType = DBGFBPTYPE_FREE;
|
---|
[58909] | 338 | NOREF(pVM);
|
---|
[1] | 339 | }
|
---|
| 340 |
|
---|
| 341 |
|
---|
| 342 | /**
|
---|
[64770] | 343 | * @callback_method_impl{FNVMMEMTRENDEZVOUS}
|
---|
[1] | 344 | */
|
---|
[64770] | 345 | static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpEnableInt3OnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
|
---|
[1] | 346 | {
|
---|
| 347 | /*
|
---|
| 348 | * Validate input.
|
---|
| 349 | */
|
---|
[64770] | 350 | PDBGFBP pBp = (PDBGFBP)pvUser;
|
---|
| 351 | AssertReturn(pBp, VERR_INVALID_PARAMETER);
|
---|
| 352 | Assert(pBp->enmType == DBGFBPTYPE_INT3);
|
---|
| 353 | VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu);
|
---|
[44399] | 354 | VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
|
---|
[64770] | 355 |
|
---|
| 356 | /*
|
---|
| 357 | * Arm the breakpoint.
|
---|
| 358 | */
|
---|
| 359 | return dbgfR3BpInt3Arm(pVM, pBp);
|
---|
| 360 | }
|
---|
| 361 |
|
---|
| 362 |
|
---|
| 363 | /**
|
---|
| 364 | * @callback_method_impl{FNVMMEMTRENDEZVOUS}
|
---|
| 365 | */
|
---|
| 366 | static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpSetInt3OnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
|
---|
| 367 | {
|
---|
| 368 | /*
|
---|
| 369 | * Validate input.
|
---|
| 370 | */
|
---|
| 371 | PDBGFBPINT3ARGS pBpArgs = (PDBGFBPINT3ARGS)pvUser;
|
---|
| 372 | AssertReturn(pBpArgs, VERR_INVALID_PARAMETER);
|
---|
| 373 | VMCPU_ASSERT_EMT(pVCpu);
|
---|
| 374 | VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
|
---|
| 375 |
|
---|
| 376 | AssertMsgReturn(!pBpArgs->piBp || VALID_PTR(pBpArgs->piBp), ("piBp=%p\n", pBpArgs->piBp), VERR_INVALID_POINTER);
|
---|
| 377 | PCDBGFADDRESS pAddress = pBpArgs->pAddress;
|
---|
| 378 | if (!DBGFR3AddrIsValid(pVM->pUVM, pAddress))
|
---|
[1] | 379 | return VERR_INVALID_PARAMETER;
|
---|
[64770] | 380 |
|
---|
| 381 | if (pBpArgs->iHitTrigger > pBpArgs->iHitDisable)
|
---|
[1] | 382 | return VERR_INVALID_PARAMETER;
|
---|
| 383 |
|
---|
| 384 | /*
|
---|
[64770] | 385 | * Check if we're on the source CPU where we can resolve the breakpoint address.
|
---|
[1] | 386 | */
|
---|
[64770] | 387 | if (pVCpu->idCpu == pBpArgs->idSrcCpu)
|
---|
[1] | 388 | {
|
---|
[64770] | 389 | if (pBpArgs->piBp)
|
---|
| 390 | *pBpArgs->piBp = UINT32_MAX;
|
---|
| 391 |
|
---|
| 392 | /*
|
---|
| 393 | * Check if the breakpoint already exists.
|
---|
| 394 | */
|
---|
| 395 | PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_INT3, pAddress->FlatPtr);
|
---|
| 396 | if (pBp)
|
---|
| 397 | {
|
---|
| 398 | int rc = VINF_SUCCESS;
|
---|
| 399 | if (!pBp->fEnabled)
|
---|
| 400 | rc = dbgfR3BpInt3Arm(pVM, pBp);
|
---|
| 401 | if (RT_SUCCESS(rc))
|
---|
| 402 | {
|
---|
| 403 | if (pBpArgs->piBp)
|
---|
| 404 | *pBpArgs->piBp = pBp->iBp;
|
---|
| 405 |
|
---|
| 406 | /*
|
---|
| 407 | * Returning VINF_DBGF_BP_ALREADY_EXIST here causes a VBOXSTRICTRC out-of-range assertion
|
---|
| 408 | * in VMMR3EmtRendezvous(). Re-setting of an existing breakpoint shouldn't cause an assertion
|
---|
| 409 | * killing the VM (and debugging session), so for now we'll pretend success.
|
---|
| 410 | */
|
---|
| 411 | #if 0
|
---|
| 412 | rc = VINF_DBGF_BP_ALREADY_EXIST;
|
---|
| 413 | #endif
|
---|
| 414 | }
|
---|
| 415 | else
|
---|
| 416 | dbgfR3BpFree(pVM, pBp);
|
---|
| 417 | return rc;
|
---|
| 418 | }
|
---|
| 419 |
|
---|
| 420 | /*
|
---|
| 421 | * Allocate the breakpoint.
|
---|
| 422 | */
|
---|
| 423 | pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_INT3);
|
---|
| 424 | if (!pBp)
|
---|
| 425 | return VERR_DBGF_NO_MORE_BP_SLOTS;
|
---|
| 426 |
|
---|
| 427 | /*
|
---|
| 428 | * Translate & save the breakpoint address into a guest-physical address.
|
---|
| 429 | */
|
---|
| 430 | int rc = DBGFR3AddrToPhys(pVM->pUVM, pBpArgs->idSrcCpu, pAddress, &pBp->u.Int3.PhysAddr);
|
---|
[13816] | 431 | if (RT_SUCCESS(rc))
|
---|
[1] | 432 | {
|
---|
[64770] | 433 | /* The physical address from DBGFR3AddrToPhys() is the start of the page,
|
---|
| 434 | we need the exact byte offset into the page while writing to it in dbgfR3BpInt3Arm(). */
|
---|
| 435 | pBp->u.Int3.PhysAddr |= (pAddress->FlatPtr & X86_PAGE_OFFSET_MASK);
|
---|
| 436 | pBp->u.Int3.GCPtr = pAddress->FlatPtr;
|
---|
| 437 | pBp->iHitTrigger = pBpArgs->iHitTrigger;
|
---|
| 438 | pBp->iHitDisable = pBpArgs->iHitDisable;
|
---|
| 439 |
|
---|
| 440 | /*
|
---|
| 441 | * Now set the breakpoint in guest memory.
|
---|
| 442 | */
|
---|
| 443 | rc = dbgfR3BpInt3Arm(pVM, pBp);
|
---|
| 444 | if (RT_SUCCESS(rc))
|
---|
| 445 | {
|
---|
| 446 | if (pBpArgs->piBp)
|
---|
| 447 | *pBpArgs->piBp = pBp->iBp;
|
---|
| 448 | return VINF_SUCCESS;
|
---|
| 449 | }
|
---|
[1] | 450 | }
|
---|
[64770] | 451 |
|
---|
| 452 | dbgfR3BpFree(pVM, pBp);
|
---|
[1] | 453 | return rc;
|
---|
| 454 | }
|
---|
| 455 |
|
---|
[64770] | 456 | return VINF_SUCCESS;
|
---|
[1] | 457 | }
|
---|
| 458 |
|
---|
| 459 |
|
---|
| 460 | /**
|
---|
[44399] | 461 | * Sets a breakpoint (int 3 based).
|
---|
| 462 | *
|
---|
| 463 | * @returns VBox status code.
|
---|
| 464 | * @param pUVM The user mode VM handle.
|
---|
[64770] | 465 | * @param idSrcCpu The ID of the virtual CPU used for the
|
---|
| 466 | * breakpoint address resolution.
|
---|
[44399] | 467 | * @param pAddress The address of the breakpoint.
|
---|
| 468 | * @param iHitTrigger The hit count at which the breakpoint start triggering.
|
---|
| 469 | * Use 0 (or 1) if it's gonna trigger at once.
|
---|
| 470 | * @param iHitDisable The hit count which disables the breakpoint.
|
---|
| 471 | * Use ~(uint64_t) if it's never gonna be disabled.
|
---|
| 472 | * @param piBp Where to store the breakpoint id. (optional)
|
---|
| 473 | * @thread Any thread.
|
---|
| 474 | */
|
---|
[64770] | 475 | VMMR3DECL(int) DBGFR3BpSetInt3(PUVM pUVM, VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable,
|
---|
| 476 | uint32_t *piBp)
|
---|
[44399] | 477 | {
|
---|
[64770] | 478 | AssertReturn(idSrcCpu <= pUVM->cCpus, VERR_INVALID_CPU_ID);
|
---|
| 479 |
|
---|
| 480 | DBGFBPINT3ARGS BpArgs;
|
---|
| 481 | RT_ZERO(BpArgs);
|
---|
| 482 | BpArgs.idSrcCpu = idSrcCpu;
|
---|
| 483 | BpArgs.iHitTrigger = iHitTrigger;
|
---|
| 484 | BpArgs.iHitDisable = iHitDisable;
|
---|
| 485 | BpArgs.pAddress = pAddress;
|
---|
| 486 | BpArgs.piBp = piBp;
|
---|
| 487 |
|
---|
| 488 | int rc = VMMR3EmtRendezvous(pUVM->pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpSetInt3OnCpu, &BpArgs);
|
---|
[44399] | 489 | LogFlow(("DBGFR3BpSet: returns %Rrc\n", rc));
|
---|
| 490 | return rc;
|
---|
| 491 | }
|
---|
| 492 |
|
---|
| 493 |
|
---|
| 494 | /**
|
---|
[1] | 495 | * Arms an int 3 breakpoint.
|
---|
| 496 | *
|
---|
[64770] | 497 | * This is used to implement both DBGFR3BpSetInt3() and
|
---|
| 498 | * DBGFR3BpEnable().
|
---|
| 499 | *
|
---|
[1] | 500 | * @returns VBox status code.
|
---|
[64770] | 501 | * @param pVM The cross context VM structure.
|
---|
[1] | 502 | * @param pBp The breakpoint.
|
---|
| 503 | */
|
---|
[64770] | 504 | static int dbgfR3BpInt3Arm(PVM pVM, PDBGFBP pBp)
|
---|
[1] | 505 | {
|
---|
[64770] | 506 | VM_ASSERT_EMT(pVM);
|
---|
[18927] | 507 |
|
---|
[1] | 508 | /*
|
---|
[64770] | 509 | * Save current byte and write the int3 instruction byte.
|
---|
[1] | 510 | */
|
---|
[64770] | 511 | int rc = PGMPhysSimpleReadGCPhys(pVM, &pBp->u.Int3.bOrg, pBp->u.Int3.PhysAddr, sizeof(pBp->u.Int3.bOrg));
|
---|
[13816] | 512 | if (RT_SUCCESS(rc))
|
---|
[1] | 513 | {
|
---|
| 514 | static const uint8_t s_bInt3 = 0xcc;
|
---|
[64770] | 515 | rc = PGMPhysSimpleWriteGCPhys(pVM, pBp->u.Int3.PhysAddr, &s_bInt3, sizeof(s_bInt3));
|
---|
| 516 | if (RT_SUCCESS(rc))
|
---|
| 517 | {
|
---|
| 518 | pBp->fEnabled = true;
|
---|
| 519 | dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_INT3, &pVM->dbgf.s.Int3);
|
---|
| 520 | pVM->dbgf.s.cEnabledInt3Breakpoints = pVM->dbgf.s.Int3.cToSearch;
|
---|
| 521 | Log(("DBGF: Set breakpoint at %RGv (Phys %RGp) cEnabledInt3Breakpoints=%u\n", pBp->u.Int3.GCPtr,
|
---|
| 522 | pBp->u.Int3.PhysAddr, pVM->dbgf.s.cEnabledInt3Breakpoints));
|
---|
| 523 | }
|
---|
[1] | 524 | }
|
---|
| 525 | return rc;
|
---|
| 526 | }
|
---|
| 527 |
|
---|
| 528 |
|
---|
| 529 | /**
|
---|
| 530 | * Disarms an int 3 breakpoint.
|
---|
[64770] | 531 | *
|
---|
[1] | 532 | * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable().
|
---|
| 533 | *
|
---|
| 534 | * @returns VBox status code.
|
---|
[64770] | 535 | * @param pVM The cross context VM structure.
|
---|
[1] | 536 | * @param pBp The breakpoint.
|
---|
| 537 | */
|
---|
[64770] | 538 | static int dbgfR3BpInt3Disarm(PVM pVM, PDBGFBP pBp)
|
---|
[1] | 539 | {
|
---|
[64770] | 540 | VM_ASSERT_EMT(pVM);
|
---|
[18927] | 541 |
|
---|
[1] | 542 | /*
|
---|
| 543 | * Check that the current byte is the int3 instruction, and restore the original one.
|
---|
| 544 | * We currently ignore invalid bytes.
|
---|
| 545 | */
|
---|
[64770] | 546 | uint8_t bCurrent = 0;
|
---|
| 547 | int rc = PGMPhysSimpleReadGCPhys(pVM, &bCurrent, pBp->u.Int3.PhysAddr, sizeof(bCurrent));
|
---|
| 548 | if ( RT_SUCCESS(rc)
|
---|
| 549 | && bCurrent == 0xcc)
|
---|
| 550 | {
|
---|
| 551 | rc = PGMPhysSimpleWriteGCPhys(pVM, pBp->u.Int3.PhysAddr, &pBp->u.Int3.bOrg, sizeof(pBp->u.Int3.bOrg));
|
---|
| 552 | if (RT_SUCCESS(rc))
|
---|
| 553 | {
|
---|
| 554 | pBp->fEnabled = false;
|
---|
| 555 | dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_INT3, &pVM->dbgf.s.Int3);
|
---|
| 556 | pVM->dbgf.s.cEnabledInt3Breakpoints = pVM->dbgf.s.Int3.cToSearch;
|
---|
| 557 | Log(("DBGF: Removed breakpoint at %RGv (Phys %RGp) cEnabledInt3Breakpoints=%u\n", pBp->u.Int3.GCPtr,
|
---|
| 558 | pBp->u.Int3.PhysAddr, pVM->dbgf.s.cEnabledInt3Breakpoints));
|
---|
| 559 | }
|
---|
| 560 | }
|
---|
[1] | 561 | return rc;
|
---|
| 562 | }
|
---|
| 563 |
|
---|
| 564 |
|
---|
| 565 | /**
|
---|
[64770] | 566 | * @callback_method_impl{FNVMMEMTRENDEZVOUS}
|
---|
| 567 | */
|
---|
| 568 | static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpDisableInt3OnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
|
---|
| 569 | {
|
---|
| 570 | /*
|
---|
| 571 | * Validate input.
|
---|
| 572 | */
|
---|
| 573 | PDBGFBP pBp = (PDBGFBP)pvUser;
|
---|
| 574 | AssertReturn(pBp, VERR_INVALID_PARAMETER);
|
---|
| 575 | Assert(pBp->enmType == DBGFBPTYPE_INT3);
|
---|
| 576 | VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu);
|
---|
| 577 | VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
|
---|
| 578 |
|
---|
| 579 | /*
|
---|
| 580 | * Disarm the breakpoint.
|
---|
| 581 | */
|
---|
| 582 | return dbgfR3BpInt3Disarm(pVM, pBp);
|
---|
| 583 | }
|
---|
| 584 |
|
---|
| 585 |
|
---|
| 586 | /**
|
---|
[1] | 587 | * Sets a register breakpoint.
|
---|
| 588 | *
|
---|
| 589 | * @returns VBox status code.
|
---|
[44399] | 590 | * @param pUVM The user mode VM handle.
|
---|
[1] | 591 | * @param pAddress The address of the breakpoint.
|
---|
| 592 | * @param piHitTrigger The hit count at which the breakpoint start triggering.
|
---|
| 593 | * Use 0 (or 1) if it's gonna trigger at once.
|
---|
| 594 | * @param piHitDisable The hit count which disables the breakpoint.
|
---|
| 595 | * Use ~(uint64_t) if it's never gonna be disabled.
|
---|
| 596 | * @param fType The access type (one of the X86_DR7_RW_* defines).
|
---|
| 597 | * @param cb The access size - 1,2,4 or 8 (the latter is AMD64 long mode only.
|
---|
| 598 | * Must be 1 if fType is X86_DR7_RW_EO.
|
---|
| 599 | * @param piBp Where to store the breakpoint id. (optional)
|
---|
| 600 | * @thread EMT
|
---|
| 601 | * @internal
|
---|
| 602 | */
|
---|
[44399] | 603 | static DECLCALLBACK(int) dbgfR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable,
|
---|
[35694] | 604 | uint8_t fType, uint8_t cb, uint32_t *piBp)
|
---|
[1] | 605 | {
|
---|
| 606 | /*
|
---|
| 607 | * Validate input.
|
---|
| 608 | */
|
---|
[44399] | 609 | PVM pVM = pUVM->pVM;
|
---|
| 610 | VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
|
---|
| 611 | if (!DBGFR3AddrIsValid(pUVM, pAddress))
|
---|
[1] | 612 | return VERR_INVALID_PARAMETER;
|
---|
| 613 | if (*piHitTrigger > *piHitDisable)
|
---|
| 614 | return VERR_INVALID_PARAMETER;
|
---|
| 615 | AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
|
---|
| 616 | if (piBp)
|
---|
[62637] | 617 | *piBp = UINT32_MAX;
|
---|
[1] | 618 | switch (fType)
|
---|
| 619 | {
|
---|
| 620 | case X86_DR7_RW_EO:
|
---|
| 621 | if (cb == 1)
|
---|
| 622 | break;
|
---|
| 623 | AssertMsgFailed(("fType=%#x cb=%d != 1\n", fType, cb));
|
---|
| 624 | return VERR_INVALID_PARAMETER;
|
---|
| 625 | case X86_DR7_RW_IO:
|
---|
| 626 | case X86_DR7_RW_RW:
|
---|
| 627 | case X86_DR7_RW_WO:
|
---|
| 628 | break;
|
---|
| 629 | default:
|
---|
| 630 | AssertMsgFailed(("fType=%#x\n", fType));
|
---|
| 631 | return VERR_INVALID_PARAMETER;
|
---|
| 632 | }
|
---|
| 633 | switch (cb)
|
---|
| 634 | {
|
---|
| 635 | case 1:
|
---|
| 636 | case 2:
|
---|
| 637 | case 4:
|
---|
| 638 | break;
|
---|
| 639 | default:
|
---|
| 640 | AssertMsgFailed(("cb=%#x\n", cb));
|
---|
| 641 | return VERR_INVALID_PARAMETER;
|
---|
| 642 | }
|
---|
| 643 |
|
---|
| 644 | /*
|
---|
| 645 | * Check if the breakpoint already exists.
|
---|
| 646 | */
|
---|
| 647 | PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REG, pAddress->FlatPtr);
|
---|
| 648 | if ( pBp
|
---|
| 649 | && pBp->u.Reg.cb == cb
|
---|
| 650 | && pBp->u.Reg.fType == fType)
|
---|
| 651 | {
|
---|
| 652 | int rc = VINF_SUCCESS;
|
---|
| 653 | if (!pBp->fEnabled)
|
---|
| 654 | rc = dbgfR3BpRegArm(pVM, pBp);
|
---|
[13816] | 655 | if (RT_SUCCESS(rc))
|
---|
[1] | 656 | {
|
---|
| 657 | rc = VINF_DBGF_BP_ALREADY_EXIST;
|
---|
| 658 | if (piBp)
|
---|
| 659 | *piBp = pBp->iBp;
|
---|
| 660 | }
|
---|
| 661 | return rc;
|
---|
| 662 | }
|
---|
| 663 |
|
---|
| 664 | /*
|
---|
| 665 | * Allocate and initialize the bp.
|
---|
| 666 | */
|
---|
| 667 | pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REG);
|
---|
| 668 | if (!pBp)
|
---|
| 669 | return VERR_DBGF_NO_MORE_BP_SLOTS;
|
---|
| 670 | pBp->iHitTrigger = *piHitTrigger;
|
---|
| 671 | pBp->iHitDisable = *piHitDisable;
|
---|
| 672 | Assert(pBp->iBp == pBp->u.Reg.iReg);
|
---|
[58903] | 673 | pBp->u.Reg.GCPtr = pAddress->FlatPtr;
|
---|
[1] | 674 | pBp->u.Reg.fType = fType;
|
---|
| 675 | pBp->u.Reg.cb = cb;
|
---|
[58903] | 676 | ASMCompilerBarrier();
|
---|
| 677 | pBp->fEnabled = true;
|
---|
[1] | 678 |
|
---|
| 679 | /*
|
---|
| 680 | * Arm the breakpoint.
|
---|
| 681 | */
|
---|
| 682 | int rc = dbgfR3BpRegArm(pVM, pBp);
|
---|
[13816] | 683 | if (RT_SUCCESS(rc))
|
---|
[1] | 684 | {
|
---|
| 685 | if (piBp)
|
---|
| 686 | *piBp = pBp->iBp;
|
---|
| 687 | }
|
---|
| 688 | else
|
---|
| 689 | dbgfR3BpFree(pVM, pBp);
|
---|
| 690 |
|
---|
| 691 | return rc;
|
---|
| 692 | }
|
---|
| 693 |
|
---|
| 694 |
|
---|
| 695 | /**
|
---|
[44399] | 696 | * Sets a register breakpoint.
|
---|
[1] | 697 | *
|
---|
| 698 | * @returns VBox status code.
|
---|
[44399] | 699 | * @param pUVM The user mode VM handle.
|
---|
| 700 | * @param pAddress The address of the breakpoint.
|
---|
| 701 | * @param iHitTrigger The hit count at which the breakpoint start triggering.
|
---|
| 702 | * Use 0 (or 1) if it's gonna trigger at once.
|
---|
| 703 | * @param iHitDisable The hit count which disables the breakpoint.
|
---|
| 704 | * Use ~(uint64_t) if it's never gonna be disabled.
|
---|
| 705 | * @param fType The access type (one of the X86_DR7_RW_* defines).
|
---|
| 706 | * @param cb The access size - 1,2,4 or 8 (the latter is AMD64 long mode only.
|
---|
| 707 | * Must be 1 if fType is X86_DR7_RW_EO.
|
---|
| 708 | * @param piBp Where to store the breakpoint id. (optional)
|
---|
| 709 | * @thread Any thread.
|
---|
[1] | 710 | */
|
---|
[44399] | 711 | VMMR3DECL(int) DBGFR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable,
|
---|
| 712 | uint8_t fType, uint8_t cb, uint32_t *piBp)
|
---|
[1] | 713 | {
|
---|
[44399] | 714 | /*
|
---|
| 715 | * This must be done on EMT.
|
---|
| 716 | */
|
---|
[58909] | 717 | int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetReg, 7,
|
---|
[44517] | 718 | pUVM, pAddress, &iHitTrigger, &iHitDisable, fType, cb, piBp);
|
---|
[44399] | 719 | LogFlow(("DBGFR3BpSetReg: returns %Rrc\n", rc));
|
---|
| 720 | return rc;
|
---|
[18927] | 721 |
|
---|
[44399] | 722 | }
|
---|
| 723 |
|
---|
| 724 |
|
---|
[58126] | 725 | /**
|
---|
| 726 | * @callback_method_impl{FNVMMEMTRENDEZVOUS}
|
---|
| 727 | */
|
---|
[58909] | 728 | static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpRegRecalcOnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
|
---|
[44399] | 729 | {
|
---|
| 730 | NOREF(pVM); NOREF(pvUser);
|
---|
[58909] | 731 |
|
---|
| 732 | /*
|
---|
| 733 | * CPU 0 updates the enabled hardware breakpoint counts.
|
---|
| 734 | */
|
---|
| 735 | if (pVCpu->idCpu == 0)
|
---|
| 736 | {
|
---|
| 737 | pVM->dbgf.s.cEnabledHwBreakpoints = 0;
|
---|
| 738 | pVM->dbgf.s.cEnabledHwIoBreakpoints = 0;
|
---|
| 739 |
|
---|
| 740 | for (uint32_t iBp = 0; iBp < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); iBp++)
|
---|
| 741 | if ( pVM->dbgf.s.aHwBreakpoints[iBp].fEnabled
|
---|
| 742 | && pVM->dbgf.s.aHwBreakpoints[iBp].enmType == DBGFBPTYPE_REG)
|
---|
| 743 | {
|
---|
| 744 | pVM->dbgf.s.cEnabledHwBreakpoints += 1;
|
---|
| 745 | pVM->dbgf.s.cEnabledHwIoBreakpoints += pVM->dbgf.s.aHwBreakpoints[iBp].u.Reg.fType == X86_DR7_RW_IO;
|
---|
| 746 | }
|
---|
| 747 | }
|
---|
| 748 |
|
---|
[47714] | 749 | return CPUMRecalcHyperDRx(pVCpu, UINT8_MAX, false);
|
---|
[1] | 750 | }
|
---|
| 751 |
|
---|
| 752 |
|
---|
| 753 | /**
|
---|
[44399] | 754 | * Arms a debug register breakpoint.
|
---|
[58909] | 755 | *
|
---|
[44399] | 756 | * This is used to implement both DBGFR3BpSetReg() and DBGFR3BpEnable().
|
---|
[1] | 757 | *
|
---|
| 758 | * @returns VBox status code.
|
---|
[58122] | 759 | * @param pVM The cross context VM structure.
|
---|
[1] | 760 | * @param pBp The breakpoint.
|
---|
[58909] | 761 | * @thread EMT(0)
|
---|
[1] | 762 | */
|
---|
[44399] | 763 | static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp)
|
---|
[1] | 764 | {
|
---|
[62637] | 765 | RT_NOREF_PV(pBp);
|
---|
[44399] | 766 | Assert(pBp->fEnabled);
|
---|
| 767 | return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpRegRecalcOnCpu, NULL);
|
---|
[1] | 768 | }
|
---|
| 769 |
|
---|
| 770 |
|
---|
| 771 | /**
|
---|
[44399] | 772 | * Disarms a debug register breakpoint.
|
---|
[58909] | 773 | *
|
---|
[44399] | 774 | * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable().
|
---|
[1] | 775 | *
|
---|
| 776 | * @returns VBox status code.
|
---|
[58122] | 777 | * @param pVM The cross context VM structure.
|
---|
[44399] | 778 | * @param pBp The breakpoint.
|
---|
[58909] | 779 | * @thread EMT(0)
|
---|
[1] | 780 | */
|
---|
[44399] | 781 | static int dbgfR3BpRegDisarm(PVM pVM, PDBGFBP pBp)
|
---|
[1] | 782 | {
|
---|
[62637] | 783 | RT_NOREF_PV(pBp);
|
---|
[44399] | 784 | Assert(!pBp->fEnabled);
|
---|
| 785 | return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpRegRecalcOnCpu, NULL);
|
---|
[1] | 786 | }
|
---|
| 787 |
|
---|
| 788 |
|
---|
| 789 | /**
|
---|
| 790 | * EMT worker for DBGFR3BpSetREM().
|
---|
| 791 | *
|
---|
| 792 | * @returns VBox status code.
|
---|
[44399] | 793 | * @param pUVM The user mode VM handle.
|
---|
[1] | 794 | * @param pAddress The address of the breakpoint.
|
---|
| 795 | * @param piHitTrigger The hit count at which the breakpoint start triggering.
|
---|
| 796 | * Use 0 (or 1) if it's gonna trigger at once.
|
---|
| 797 | * @param piHitDisable The hit count which disables the breakpoint.
|
---|
| 798 | * Use ~(uint64_t) if it's never gonna be disabled.
|
---|
| 799 | * @param piBp Where to store the breakpoint id. (optional)
|
---|
[58909] | 800 | * @thread EMT(0)
|
---|
[1] | 801 | * @internal
|
---|
| 802 | */
|
---|
[44399] | 803 | static DECLCALLBACK(int) dbgfR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger,
|
---|
| 804 | uint64_t *piHitDisable, uint32_t *piBp)
|
---|
[1] | 805 | {
|
---|
| 806 | /*
|
---|
| 807 | * Validate input.
|
---|
| 808 | */
|
---|
[44399] | 809 | PVM pVM = pUVM->pVM;
|
---|
| 810 | VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
|
---|
| 811 | if (!DBGFR3AddrIsValid(pUVM, pAddress))
|
---|
[1] | 812 | return VERR_INVALID_PARAMETER;
|
---|
| 813 | if (*piHitTrigger > *piHitDisable)
|
---|
| 814 | return VERR_INVALID_PARAMETER;
|
---|
| 815 | AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
|
---|
| 816 | if (piBp)
|
---|
[62637] | 817 | *piBp = UINT32_MAX;
|
---|
[1] | 818 |
|
---|
| 819 | /*
|
---|
| 820 | * Check if the breakpoint already exists.
|
---|
| 821 | */
|
---|
| 822 | PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REM, pAddress->FlatPtr);
|
---|
| 823 | if (pBp)
|
---|
| 824 | {
|
---|
| 825 | int rc = VINF_SUCCESS;
|
---|
| 826 | if (!pBp->fEnabled)
|
---|
[40274] | 827 | #ifdef VBOX_WITH_REM
|
---|
[58903] | 828 | rc = REMR3BreakpointSet(pVM, pBp->u.Rem.GCPtr);
|
---|
[40274] | 829 | #else
|
---|
[58903] | 830 | rc = IEMBreakpointSet(pVM, pBp->u.Rem.GCPtr);
|
---|
[40274] | 831 | #endif
|
---|
[13816] | 832 | if (RT_SUCCESS(rc))
|
---|
[1] | 833 | {
|
---|
| 834 | rc = VINF_DBGF_BP_ALREADY_EXIST;
|
---|
| 835 | if (piBp)
|
---|
| 836 | *piBp = pBp->iBp;
|
---|
| 837 | }
|
---|
| 838 | return rc;
|
---|
| 839 | }
|
---|
| 840 |
|
---|
| 841 | /*
|
---|
| 842 | * Allocate and initialize the bp.
|
---|
| 843 | */
|
---|
| 844 | pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REM);
|
---|
| 845 | if (!pBp)
|
---|
| 846 | return VERR_DBGF_NO_MORE_BP_SLOTS;
|
---|
[58903] | 847 | pBp->u.Rem.GCPtr = pAddress->FlatPtr;
|
---|
[1] | 848 | pBp->iHitTrigger = *piHitTrigger;
|
---|
| 849 | pBp->iHitDisable = *piHitDisable;
|
---|
[58903] | 850 | ASMCompilerBarrier();
|
---|
[1] | 851 | pBp->fEnabled = true;
|
---|
| 852 |
|
---|
| 853 | /*
|
---|
| 854 | * Now ask REM to set the breakpoint.
|
---|
| 855 | */
|
---|
[40274] | 856 | #ifdef VBOX_WITH_REM
|
---|
[1] | 857 | int rc = REMR3BreakpointSet(pVM, pAddress->FlatPtr);
|
---|
[40274] | 858 | #else
|
---|
| 859 | int rc = IEMBreakpointSet(pVM, pAddress->FlatPtr);
|
---|
| 860 | #endif
|
---|
[13816] | 861 | if (RT_SUCCESS(rc))
|
---|
[1] | 862 | {
|
---|
| 863 | if (piBp)
|
---|
| 864 | *piBp = pBp->iBp;
|
---|
| 865 | }
|
---|
| 866 | else
|
---|
| 867 | dbgfR3BpFree(pVM, pBp);
|
---|
| 868 |
|
---|
| 869 | return rc;
|
---|
| 870 | }
|
---|
| 871 |
|
---|
| 872 |
|
---|
| 873 | /**
|
---|
[44399] | 874 | * Sets a recompiler breakpoint.
|
---|
[1] | 875 | *
|
---|
| 876 | * @returns VBox status code.
|
---|
[44399] | 877 | * @param pUVM The user mode VM handle.
|
---|
| 878 | * @param pAddress The address of the breakpoint.
|
---|
| 879 | * @param iHitTrigger The hit count at which the breakpoint start triggering.
|
---|
| 880 | * Use 0 (or 1) if it's gonna trigger at once.
|
---|
| 881 | * @param iHitDisable The hit count which disables the breakpoint.
|
---|
| 882 | * Use ~(uint64_t) if it's never gonna be disabled.
|
---|
| 883 | * @param piBp Where to store the breakpoint id. (optional)
|
---|
[1] | 884 | * @thread Any thread.
|
---|
| 885 | */
|
---|
[44399] | 886 | VMMR3DECL(int) DBGFR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp)
|
---|
[1] | 887 | {
|
---|
| 888 | /*
|
---|
[38838] | 889 | * This must be done on EMT.
|
---|
[1] | 890 | */
|
---|
[58909] | 891 | int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetREM, 5,
|
---|
[44517] | 892 | pUVM, pAddress, &iHitTrigger, &iHitDisable, piBp);
|
---|
[44399] | 893 | LogFlow(("DBGFR3BpSetREM: returns %Rrc\n", rc));
|
---|
[1] | 894 | return rc;
|
---|
| 895 | }
|
---|
| 896 |
|
---|
| 897 |
|
---|
| 898 | /**
|
---|
[58903] | 899 | * Updates IOM on whether we've got any armed I/O port or MMIO breakpoints.
|
---|
| 900 | *
|
---|
| 901 | * @returns VINF_SUCCESS
|
---|
| 902 | * @param pVM The cross context VM structure.
|
---|
[58909] | 903 | * @thread EMT(0)
|
---|
[58903] | 904 | */
|
---|
| 905 | static int dbgfR3BpUpdateIom(PVM pVM)
|
---|
| 906 | {
|
---|
[58909] | 907 | dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_PORT_IO, &pVM->dbgf.s.PortIo);
|
---|
| 908 | if (pVM->dbgf.s.PortIo.cToSearch)
|
---|
| 909 | ASMAtomicBitSet(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_BREAKPOINT_IO);
|
---|
| 910 | else
|
---|
| 911 | ASMAtomicBitClear(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_BREAKPOINT_IO);
|
---|
[58903] | 912 |
|
---|
[58909] | 913 | dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_MMIO, &pVM->dbgf.s.Mmio);
|
---|
| 914 | if (pVM->dbgf.s.Mmio.cToSearch)
|
---|
| 915 | ASMAtomicBitSet(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_BREAKPOINT_MMIO);
|
---|
| 916 | else
|
---|
| 917 | ASMAtomicBitClear(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_BREAKPOINT_MMIO);
|
---|
[58903] | 918 |
|
---|
[58909] | 919 | IOMR3NotifyBreakpointCountChange(pVM, pVM->dbgf.s.PortIo.cToSearch != 0, pVM->dbgf.s.Mmio.cToSearch != 0);
|
---|
[58903] | 920 | return VINF_SUCCESS;
|
---|
| 921 | }
|
---|
| 922 |
|
---|
| 923 |
|
---|
| 924 | /**
|
---|
| 925 | * EMT worker for DBGFR3BpSetPortIo.
|
---|
| 926 | *
|
---|
| 927 | * @returns VBox status code.
|
---|
| 928 | * @param pUVM The user mode VM handle.
|
---|
| 929 | * @param uPort The first I/O port.
|
---|
| 930 | * @param cPorts The number of I/O ports.
|
---|
| 931 | * @param fAccess The access we want to break on.
|
---|
| 932 | * @param piHitTrigger The hit count at which the breakpoint start triggering.
|
---|
| 933 | * Use 0 (or 1) if it's gonna trigger at once.
|
---|
| 934 | * @param piHitDisable The hit count which disables the breakpoint.
|
---|
| 935 | * Use ~(uint64_t) if it's never gonna be disabled.
|
---|
| 936 | * @param piBp Where to store the breakpoint ID.
|
---|
[58909] | 937 | * @thread EMT(0)
|
---|
[58903] | 938 | */
|
---|
| 939 | static DECLCALLBACK(int) dbgfR3BpSetPortIo(PUVM pUVM, RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess,
|
---|
| 940 | uint64_t const *piHitTrigger, uint64_t const *piHitDisable, uint32_t *piBp)
|
---|
| 941 | {
|
---|
| 942 | /*
|
---|
| 943 | * Validate input.
|
---|
| 944 | */
|
---|
| 945 | PVM pVM = pUVM->pVM;
|
---|
| 946 | VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
|
---|
[62637] | 947 | *piBp = UINT32_MAX;
|
---|
[58903] | 948 |
|
---|
| 949 | /*
|
---|
| 950 | * Check if the breakpoint already exists.
|
---|
| 951 | */
|
---|
| 952 | for (uint32_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
|
---|
| 953 | if ( pVM->dbgf.s.aBreakpoints[i].enmType == DBGFBPTYPE_PORT_IO
|
---|
| 954 | && pVM->dbgf.s.aBreakpoints[i].u.PortIo.uPort == uPort
|
---|
| 955 | && pVM->dbgf.s.aBreakpoints[i].u.PortIo.cPorts == cPorts
|
---|
| 956 | && pVM->dbgf.s.aBreakpoints[i].u.PortIo.fAccess == fAccess)
|
---|
| 957 | {
|
---|
| 958 | if (!pVM->dbgf.s.aBreakpoints[i].fEnabled)
|
---|
| 959 | {
|
---|
| 960 | pVM->dbgf.s.aBreakpoints[i].fEnabled = true;
|
---|
| 961 | dbgfR3BpUpdateIom(pVM);
|
---|
| 962 | }
|
---|
| 963 | *piBp = pVM->dbgf.s.aBreakpoints[i].iBp;
|
---|
| 964 | return VINF_DBGF_BP_ALREADY_EXIST;
|
---|
| 965 | }
|
---|
| 966 |
|
---|
| 967 | /*
|
---|
| 968 | * Allocate and initialize the breakpoint.
|
---|
| 969 | */
|
---|
| 970 | PDBGFBP pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_PORT_IO);
|
---|
| 971 | if (!pBp)
|
---|
| 972 | return VERR_DBGF_NO_MORE_BP_SLOTS;
|
---|
| 973 | pBp->iHitTrigger = *piHitTrigger;
|
---|
| 974 | pBp->iHitDisable = *piHitDisable;
|
---|
| 975 | pBp->u.PortIo.uPort = uPort;
|
---|
| 976 | pBp->u.PortIo.cPorts = cPorts;
|
---|
| 977 | pBp->u.PortIo.fAccess = fAccess;
|
---|
| 978 | ASMCompilerBarrier();
|
---|
| 979 | pBp->fEnabled = true;
|
---|
| 980 |
|
---|
| 981 | /*
|
---|
| 982 | * Tell IOM.
|
---|
| 983 | */
|
---|
| 984 | dbgfR3BpUpdateIom(pVM);
|
---|
| 985 | *piBp = pBp->iBp;
|
---|
| 986 | return VINF_SUCCESS;
|
---|
| 987 | }
|
---|
| 988 |
|
---|
| 989 |
|
---|
| 990 | /**
|
---|
| 991 | * Sets an I/O port breakpoint.
|
---|
| 992 | *
|
---|
| 993 | * @returns VBox status code.
|
---|
[58916] | 994 | * @param pUVM The user mode VM handle.
|
---|
[58903] | 995 | * @param uPort The first I/O port.
|
---|
| 996 | * @param cPorts The number of I/O ports, see DBGFBPIOACCESS_XXX.
|
---|
| 997 | * @param fAccess The access we want to break on.
|
---|
| 998 | * @param iHitTrigger The hit count at which the breakpoint start
|
---|
| 999 | * triggering. Use 0 (or 1) if it's gonna trigger at
|
---|
| 1000 | * once.
|
---|
| 1001 | * @param iHitDisable The hit count which disables the breakpoint.
|
---|
| 1002 | * Use ~(uint64_t) if it's never gonna be disabled.
|
---|
| 1003 | * @param piBp Where to store the breakpoint ID. Optional.
|
---|
[58909] | 1004 | * @thread Any thread.
|
---|
[58903] | 1005 | */
|
---|
| 1006 | VMMR3DECL(int) DBGFR3BpSetPortIo(PUVM pUVM, RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess,
|
---|
| 1007 | uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp)
|
---|
| 1008 | {
|
---|
| 1009 | AssertReturn(!(fAccess & ~DBGFBPIOACCESS_VALID_MASK_PORT_IO), VERR_INVALID_FLAGS);
|
---|
| 1010 | AssertReturn(fAccess, VERR_INVALID_FLAGS);
|
---|
| 1011 | if (iHitTrigger > iHitDisable)
|
---|
| 1012 | return VERR_INVALID_PARAMETER;
|
---|
| 1013 | AssertPtrNullReturn(piBp, VERR_INVALID_POINTER);
|
---|
| 1014 | AssertReturn(cPorts > 0, VERR_OUT_OF_RANGE);
|
---|
| 1015 | AssertReturn((RTIOPORT)(uPort + cPorts) < uPort, VERR_OUT_OF_RANGE);
|
---|
| 1016 |
|
---|
| 1017 | /*
|
---|
| 1018 | * This must be done on EMT.
|
---|
| 1019 | */
|
---|
[62637] | 1020 | uint32_t iBp = UINT32_MAX;
|
---|
[58909] | 1021 | int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetPortIo, 7,
|
---|
[58903] | 1022 | pUVM, uPort, cPorts, fAccess, &iHitTrigger, &iHitDisable, piBp);
|
---|
| 1023 | if (piBp)
|
---|
| 1024 | *piBp = iBp;
|
---|
[58909] | 1025 | LogFlow(("DBGFR3BpSetPortIo: returns %Rrc iBp=%d\n", rc, iBp));
|
---|
[58903] | 1026 | return rc;
|
---|
| 1027 | }
|
---|
| 1028 |
|
---|
| 1029 |
|
---|
| 1030 | /**
|
---|
| 1031 | * EMT worker for DBGFR3BpSetMmio.
|
---|
| 1032 | *
|
---|
| 1033 | * @returns VBox status code.
|
---|
| 1034 | * @param pUVM The user mode VM handle.
|
---|
| 1035 | * @param pGCPhys The start of the MMIO range to break on.
|
---|
[64530] | 1036 | * @param cb The size of the MMIO range.
|
---|
[58903] | 1037 | * @param fAccess The access we want to break on.
|
---|
| 1038 | * @param piHitTrigger The hit count at which the breakpoint start triggering.
|
---|
| 1039 | * Use 0 (or 1) if it's gonna trigger at once.
|
---|
| 1040 | * @param piHitDisable The hit count which disables the breakpoint.
|
---|
| 1041 | * Use ~(uint64_t) if it's never gonna be disabled.
|
---|
| 1042 | * @param piBp Where to store the breakpoint ID.
|
---|
[58909] | 1043 | * @thread EMT(0)
|
---|
[58903] | 1044 | */
|
---|
| 1045 | static DECLCALLBACK(int) dbgfR3BpSetMmio(PUVM pUVM, PCRTGCPHYS pGCPhys, uint32_t cb, uint32_t fAccess,
|
---|
| 1046 | uint64_t const *piHitTrigger, uint64_t const *piHitDisable, uint32_t *piBp)
|
---|
| 1047 | {
|
---|
| 1048 | RTGCPHYS const GCPhys = *pGCPhys;
|
---|
| 1049 |
|
---|
| 1050 | /*
|
---|
| 1051 | * Validate input.
|
---|
| 1052 | */
|
---|
| 1053 | PVM pVM = pUVM->pVM;
|
---|
| 1054 | VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
|
---|
[62637] | 1055 | *piBp = UINT32_MAX;
|
---|
[58903] | 1056 |
|
---|
| 1057 | /*
|
---|
| 1058 | * Check if the breakpoint already exists.
|
---|
| 1059 | */
|
---|
| 1060 | for (uint32_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
|
---|
| 1061 | if ( pVM->dbgf.s.aBreakpoints[i].enmType == DBGFBPTYPE_MMIO
|
---|
| 1062 | && pVM->dbgf.s.aBreakpoints[i].u.Mmio.PhysAddr == GCPhys
|
---|
| 1063 | && pVM->dbgf.s.aBreakpoints[i].u.Mmio.cb == cb
|
---|
| 1064 | && pVM->dbgf.s.aBreakpoints[i].u.Mmio.fAccess == fAccess)
|
---|
| 1065 | {
|
---|
| 1066 | if (!pVM->dbgf.s.aBreakpoints[i].fEnabled)
|
---|
| 1067 | {
|
---|
| 1068 | pVM->dbgf.s.aBreakpoints[i].fEnabled = true;
|
---|
| 1069 | dbgfR3BpUpdateIom(pVM);
|
---|
| 1070 | }
|
---|
| 1071 | *piBp = pVM->dbgf.s.aBreakpoints[i].iBp;
|
---|
| 1072 | return VINF_DBGF_BP_ALREADY_EXIST;
|
---|
| 1073 | }
|
---|
| 1074 |
|
---|
| 1075 | /*
|
---|
| 1076 | * Allocate and initialize the breakpoint.
|
---|
| 1077 | */
|
---|
[64770] | 1078 | PDBGFBP pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_MMIO);
|
---|
[58903] | 1079 | if (!pBp)
|
---|
| 1080 | return VERR_DBGF_NO_MORE_BP_SLOTS;
|
---|
| 1081 | pBp->iHitTrigger = *piHitTrigger;
|
---|
| 1082 | pBp->iHitDisable = *piHitDisable;
|
---|
| 1083 | pBp->u.Mmio.PhysAddr = GCPhys;
|
---|
| 1084 | pBp->u.Mmio.cb = cb;
|
---|
| 1085 | pBp->u.Mmio.fAccess = fAccess;
|
---|
| 1086 | ASMCompilerBarrier();
|
---|
| 1087 | pBp->fEnabled = true;
|
---|
| 1088 |
|
---|
| 1089 | /*
|
---|
| 1090 | * Tell IOM.
|
---|
| 1091 | */
|
---|
| 1092 | dbgfR3BpUpdateIom(pVM);
|
---|
| 1093 | *piBp = pBp->iBp;
|
---|
| 1094 | return VINF_SUCCESS;
|
---|
| 1095 | }
|
---|
| 1096 |
|
---|
| 1097 |
|
---|
| 1098 | /**
|
---|
| 1099 | * Sets a memory mapped I/O breakpoint.
|
---|
| 1100 | *
|
---|
| 1101 | * @returns VBox status code.
|
---|
[58916] | 1102 | * @param pUVM The user mode VM handle.
|
---|
[58903] | 1103 | * @param GCPhys The first MMIO address.
|
---|
| 1104 | * @param cb The size of the MMIO range to break on.
|
---|
| 1105 | * @param fAccess The access we want to break on.
|
---|
| 1106 | * @param iHitTrigger The hit count at which the breakpoint start
|
---|
| 1107 | * triggering. Use 0 (or 1) if it's gonna trigger at
|
---|
| 1108 | * once.
|
---|
| 1109 | * @param iHitDisable The hit count which disables the breakpoint.
|
---|
| 1110 | * Use ~(uint64_t) if it's never gonna be disabled.
|
---|
| 1111 | * @param piBp Where to store the breakpoint ID. Optional.
|
---|
[58909] | 1112 | * @thread Any thread.
|
---|
[58903] | 1113 | */
|
---|
| 1114 | VMMR3DECL(int) DBGFR3BpSetMmio(PUVM pUVM, RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess,
|
---|
| 1115 | uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp)
|
---|
| 1116 | {
|
---|
| 1117 | AssertReturn(!(fAccess & ~DBGFBPIOACCESS_VALID_MASK_MMIO), VERR_INVALID_FLAGS);
|
---|
| 1118 | AssertReturn(fAccess, VERR_INVALID_FLAGS);
|
---|
| 1119 | if (iHitTrigger > iHitDisable)
|
---|
| 1120 | return VERR_INVALID_PARAMETER;
|
---|
| 1121 | AssertPtrNullReturn(piBp, VERR_INVALID_POINTER);
|
---|
| 1122 | AssertReturn(cb, VERR_OUT_OF_RANGE);
|
---|
| 1123 | AssertReturn(GCPhys + cb < GCPhys, VERR_OUT_OF_RANGE);
|
---|
| 1124 |
|
---|
| 1125 | /*
|
---|
| 1126 | * This must be done on EMT.
|
---|
| 1127 | */
|
---|
[62637] | 1128 | uint32_t iBp = UINT32_MAX;
|
---|
[58909] | 1129 | int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetMmio, 7,
|
---|
[58903] | 1130 | pUVM, &GCPhys, cb, fAccess, &iHitTrigger, &iHitDisable, piBp);
|
---|
| 1131 | if (piBp)
|
---|
| 1132 | *piBp = iBp;
|
---|
[58909] | 1133 | LogFlow(("DBGFR3BpSetMmio: returns %Rrc iBp=%d\n", rc, iBp));
|
---|
[58903] | 1134 | return rc;
|
---|
| 1135 | }
|
---|
| 1136 |
|
---|
| 1137 |
|
---|
| 1138 | /**
|
---|
[1] | 1139 | * EMT worker for DBGFR3BpClear().
|
---|
| 1140 | *
|
---|
| 1141 | * @returns VBox status code.
|
---|
[44399] | 1142 | * @param pUVM The user mode VM handle.
|
---|
[1] | 1143 | * @param iBp The id of the breakpoint which should be removed (cleared).
|
---|
[58909] | 1144 | * @thread EMT(0)
|
---|
[1] | 1145 | * @internal
|
---|
| 1146 | */
|
---|
[44399] | 1147 | static DECLCALLBACK(int) dbgfR3BpClear(PUVM pUVM, uint32_t iBp)
|
---|
[1] | 1148 | {
|
---|
| 1149 | /*
|
---|
| 1150 | * Validate input.
|
---|
| 1151 | */
|
---|
[44399] | 1152 | PVM pVM = pUVM->pVM;
|
---|
[64770] | 1153 | VM_ASSERT_EMT(pVM);
|
---|
[44399] | 1154 | VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
|
---|
[1] | 1155 | PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
|
---|
| 1156 | if (!pBp)
|
---|
| 1157 | return VERR_DBGF_BP_NOT_FOUND;
|
---|
| 1158 |
|
---|
| 1159 | /*
|
---|
| 1160 | * Disarm the breakpoint if it's enabled.
|
---|
| 1161 | */
|
---|
| 1162 | if (pBp->fEnabled)
|
---|
| 1163 | {
|
---|
| 1164 | pBp->fEnabled = false;
|
---|
| 1165 | int rc;
|
---|
| 1166 | switch (pBp->enmType)
|
---|
| 1167 | {
|
---|
| 1168 | case DBGFBPTYPE_REG:
|
---|
| 1169 | rc = dbgfR3BpRegDisarm(pVM, pBp);
|
---|
| 1170 | break;
|
---|
| 1171 |
|
---|
| 1172 | case DBGFBPTYPE_INT3:
|
---|
[64770] | 1173 | rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3BpDisableInt3OnCpu, pBp);
|
---|
[1] | 1174 | break;
|
---|
| 1175 |
|
---|
| 1176 | case DBGFBPTYPE_REM:
|
---|
[40274] | 1177 | #ifdef VBOX_WITH_REM
|
---|
[58903] | 1178 | rc = REMR3BreakpointClear(pVM, pBp->u.Rem.GCPtr);
|
---|
[40274] | 1179 | #else
|
---|
[58903] | 1180 | rc = IEMBreakpointClear(pVM, pBp->u.Rem.GCPtr);
|
---|
[40274] | 1181 | #endif
|
---|
[1] | 1182 | break;
|
---|
| 1183 |
|
---|
[58903] | 1184 | case DBGFBPTYPE_PORT_IO:
|
---|
| 1185 | case DBGFBPTYPE_MMIO:
|
---|
| 1186 | rc = dbgfR3BpUpdateIom(pVM);
|
---|
| 1187 | break;
|
---|
| 1188 |
|
---|
[1] | 1189 | default:
|
---|
[39405] | 1190 | AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
|
---|
[1] | 1191 | }
|
---|
| 1192 | AssertRCReturn(rc, rc);
|
---|
| 1193 | }
|
---|
| 1194 |
|
---|
| 1195 | /*
|
---|
| 1196 | * Free the breakpoint.
|
---|
| 1197 | */
|
---|
| 1198 | dbgfR3BpFree(pVM, pBp);
|
---|
| 1199 | return VINF_SUCCESS;
|
---|
| 1200 | }
|
---|
| 1201 |
|
---|
| 1202 |
|
---|
| 1203 | /**
|
---|
[44399] | 1204 | * Clears a breakpoint.
|
---|
[1] | 1205 | *
|
---|
| 1206 | * @returns VBox status code.
|
---|
[44399] | 1207 | * @param pUVM The user mode VM handle.
|
---|
| 1208 | * @param iBp The id of the breakpoint which should be removed (cleared).
|
---|
[1] | 1209 | * @thread Any thread.
|
---|
| 1210 | */
|
---|
[44399] | 1211 | VMMR3DECL(int) DBGFR3BpClear(PUVM pUVM, uint32_t iBp)
|
---|
[1] | 1212 | {
|
---|
| 1213 | /*
|
---|
[38838] | 1214 | * This must be done on EMT.
|
---|
[1] | 1215 | */
|
---|
[58909] | 1216 | int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpClear, 2, pUVM, iBp);
|
---|
[44399] | 1217 | LogFlow(("DBGFR3BpClear: returns %Rrc\n", rc));
|
---|
[1] | 1218 | return rc;
|
---|
| 1219 | }
|
---|
| 1220 |
|
---|
| 1221 |
|
---|
| 1222 | /**
|
---|
| 1223 | * EMT worker for DBGFR3BpEnable().
|
---|
| 1224 | *
|
---|
| 1225 | * @returns VBox status code.
|
---|
[44399] | 1226 | * @param pUVM The user mode VM handle.
|
---|
[1] | 1227 | * @param iBp The id of the breakpoint which should be enabled.
|
---|
[58909] | 1228 | * @thread EMT(0)
|
---|
[1] | 1229 | * @internal
|
---|
| 1230 | */
|
---|
[44399] | 1231 | static DECLCALLBACK(int) dbgfR3BpEnable(PUVM pUVM, uint32_t iBp)
|
---|
[1] | 1232 | {
|
---|
| 1233 | /*
|
---|
| 1234 | * Validate input.
|
---|
| 1235 | */
|
---|
[44399] | 1236 | PVM pVM = pUVM->pVM;
|
---|
| 1237 | VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
|
---|
[1] | 1238 | PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
|
---|
| 1239 | if (!pBp)
|
---|
| 1240 | return VERR_DBGF_BP_NOT_FOUND;
|
---|
| 1241 |
|
---|
| 1242 | /*
|
---|
| 1243 | * Already enabled?
|
---|
| 1244 | */
|
---|
| 1245 | if (pBp->fEnabled)
|
---|
| 1246 | return VINF_DBGF_BP_ALREADY_ENABLED;
|
---|
| 1247 |
|
---|
| 1248 | /*
|
---|
[64770] | 1249 | * Arm the breakpoint.
|
---|
[1] | 1250 | */
|
---|
| 1251 | int rc;
|
---|
| 1252 | pBp->fEnabled = true;
|
---|
| 1253 | switch (pBp->enmType)
|
---|
| 1254 | {
|
---|
| 1255 | case DBGFBPTYPE_REG:
|
---|
| 1256 | rc = dbgfR3BpRegArm(pVM, pBp);
|
---|
| 1257 | break;
|
---|
| 1258 |
|
---|
| 1259 | case DBGFBPTYPE_INT3:
|
---|
[64770] | 1260 | rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3BpEnableInt3OnCpu, pBp);
|
---|
[1] | 1261 | break;
|
---|
| 1262 |
|
---|
| 1263 | case DBGFBPTYPE_REM:
|
---|
[40274] | 1264 | #ifdef VBOX_WITH_REM
|
---|
[58903] | 1265 | rc = REMR3BreakpointSet(pVM, pBp->u.Rem.GCPtr);
|
---|
[40274] | 1266 | #else
|
---|
[58903] | 1267 | rc = IEMBreakpointSet(pVM, pBp->u.Rem.GCPtr);
|
---|
[40274] | 1268 | #endif
|
---|
[1] | 1269 | break;
|
---|
| 1270 |
|
---|
[58903] | 1271 | case DBGFBPTYPE_PORT_IO:
|
---|
| 1272 | case DBGFBPTYPE_MMIO:
|
---|
| 1273 | rc = dbgfR3BpUpdateIom(pVM);
|
---|
| 1274 | break;
|
---|
| 1275 |
|
---|
[1] | 1276 | default:
|
---|
[39405] | 1277 | AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
|
---|
[1] | 1278 | }
|
---|
[13816] | 1279 | if (RT_FAILURE(rc))
|
---|
[1] | 1280 | pBp->fEnabled = false;
|
---|
| 1281 |
|
---|
| 1282 | return rc;
|
---|
| 1283 | }
|
---|
| 1284 |
|
---|
| 1285 |
|
---|
| 1286 | /**
|
---|
[44399] | 1287 | * Enables a breakpoint.
|
---|
[1] | 1288 | *
|
---|
| 1289 | * @returns VBox status code.
|
---|
[44399] | 1290 | * @param pUVM The user mode VM handle.
|
---|
| 1291 | * @param iBp The id of the breakpoint which should be enabled.
|
---|
[1] | 1292 | * @thread Any thread.
|
---|
| 1293 | */
|
---|
[44399] | 1294 | VMMR3DECL(int) DBGFR3BpEnable(PUVM pUVM, uint32_t iBp)
|
---|
[1] | 1295 | {
|
---|
| 1296 | /*
|
---|
[38838] | 1297 | * This must be done on EMT.
|
---|
[1] | 1298 | */
|
---|
[58909] | 1299 | int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpEnable, 2, pUVM, iBp);
|
---|
[44399] | 1300 | LogFlow(("DBGFR3BpEnable: returns %Rrc\n", rc));
|
---|
[1] | 1301 | return rc;
|
---|
| 1302 | }
|
---|
| 1303 |
|
---|
| 1304 |
|
---|
| 1305 | /**
|
---|
| 1306 | * EMT worker for DBGFR3BpDisable().
|
---|
| 1307 | *
|
---|
| 1308 | * @returns VBox status code.
|
---|
[44399] | 1309 | * @param pUVM The user mode VM handle.
|
---|
[1] | 1310 | * @param iBp The id of the breakpoint which should be disabled.
|
---|
[58909] | 1311 | * @thread EMT(0)
|
---|
[1] | 1312 | * @internal
|
---|
| 1313 | */
|
---|
[44399] | 1314 | static DECLCALLBACK(int) dbgfR3BpDisable(PUVM pUVM, uint32_t iBp)
|
---|
[1] | 1315 | {
|
---|
| 1316 | /*
|
---|
| 1317 | * Validate input.
|
---|
| 1318 | */
|
---|
[44399] | 1319 | PVM pVM = pUVM->pVM;
|
---|
| 1320 | VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
|
---|
[1] | 1321 | PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
|
---|
| 1322 | if (!pBp)
|
---|
| 1323 | return VERR_DBGF_BP_NOT_FOUND;
|
---|
| 1324 |
|
---|
| 1325 | /*
|
---|
| 1326 | * Already enabled?
|
---|
| 1327 | */
|
---|
| 1328 | if (!pBp->fEnabled)
|
---|
| 1329 | return VINF_DBGF_BP_ALREADY_DISABLED;
|
---|
| 1330 |
|
---|
| 1331 | /*
|
---|
| 1332 | * Remove the breakpoint.
|
---|
| 1333 | */
|
---|
| 1334 | pBp->fEnabled = false;
|
---|
| 1335 | int rc;
|
---|
| 1336 | switch (pBp->enmType)
|
---|
| 1337 | {
|
---|
| 1338 | case DBGFBPTYPE_REG:
|
---|
| 1339 | rc = dbgfR3BpRegDisarm(pVM, pBp);
|
---|
| 1340 | break;
|
---|
| 1341 |
|
---|
| 1342 | case DBGFBPTYPE_INT3:
|
---|
[64770] | 1343 | rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3BpDisableInt3OnCpu, pBp);
|
---|
[1] | 1344 | break;
|
---|
| 1345 |
|
---|
| 1346 | case DBGFBPTYPE_REM:
|
---|
[40274] | 1347 | #ifdef VBOX_WITH_REM
|
---|
[58903] | 1348 | rc = REMR3BreakpointClear(pVM, pBp->u.Rem.GCPtr);
|
---|
[40274] | 1349 | #else
|
---|
[58903] | 1350 | rc = IEMBreakpointClear(pVM, pBp->u.Rem.GCPtr);
|
---|
[40274] | 1351 | #endif
|
---|
[1] | 1352 | break;
|
---|
| 1353 |
|
---|
[58903] | 1354 | case DBGFBPTYPE_PORT_IO:
|
---|
| 1355 | case DBGFBPTYPE_MMIO:
|
---|
| 1356 | rc = dbgfR3BpUpdateIom(pVM);
|
---|
| 1357 | break;
|
---|
| 1358 |
|
---|
[1] | 1359 | default:
|
---|
[39405] | 1360 | AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
|
---|
[1] | 1361 | }
|
---|
| 1362 |
|
---|
| 1363 | return rc;
|
---|
| 1364 | }
|
---|
| 1365 |
|
---|
| 1366 |
|
---|
| 1367 | /**
|
---|
[44399] | 1368 | * Disables a breakpoint.
|
---|
[1] | 1369 | *
|
---|
| 1370 | * @returns VBox status code.
|
---|
[44399] | 1371 | * @param pUVM The user mode VM handle.
|
---|
| 1372 | * @param iBp The id of the breakpoint which should be disabled.
|
---|
| 1373 | * @thread Any thread.
|
---|
[1] | 1374 | */
|
---|
[44399] | 1375 | VMMR3DECL(int) DBGFR3BpDisable(PUVM pUVM, uint32_t iBp)
|
---|
[1] | 1376 | {
|
---|
| 1377 | /*
|
---|
[38838] | 1378 | * This must be done on EMT.
|
---|
[1] | 1379 | */
|
---|
[58909] | 1380 | int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpDisable, 2, pUVM, iBp);
|
---|
[44399] | 1381 | LogFlow(("DBGFR3BpDisable: returns %Rrc\n", rc));
|
---|
[1] | 1382 | return rc;
|
---|
| 1383 | }
|
---|
| 1384 |
|
---|
| 1385 |
|
---|
| 1386 | /**
|
---|
| 1387 | * EMT worker for DBGFR3BpEnum().
|
---|
| 1388 | *
|
---|
| 1389 | * @returns VBox status code.
|
---|
[44399] | 1390 | * @param pUVM The user mode VM handle.
|
---|
[1] | 1391 | * @param pfnCallback The callback function.
|
---|
| 1392 | * @param pvUser The user argument to pass to the callback.
|
---|
| 1393 | * @thread EMT
|
---|
| 1394 | * @internal
|
---|
| 1395 | */
|
---|
[44399] | 1396 | static DECLCALLBACK(int) dbgfR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
|
---|
[1] | 1397 | {
|
---|
| 1398 | /*
|
---|
| 1399 | * Validate input.
|
---|
| 1400 | */
|
---|
[44399] | 1401 | PVM pVM = pUVM->pVM;
|
---|
| 1402 | VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
|
---|
| 1403 | AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
|
---|
[1] | 1404 |
|
---|
| 1405 | /*
|
---|
| 1406 | * Enumerate the hardware breakpoints.
|
---|
| 1407 | */
|
---|
| 1408 | unsigned i;
|
---|
[11311] | 1409 | for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
|
---|
[1] | 1410 | if (pVM->dbgf.s.aHwBreakpoints[i].enmType != DBGFBPTYPE_FREE)
|
---|
| 1411 | {
|
---|
[44399] | 1412 | int rc = pfnCallback(pUVM, pvUser, &pVM->dbgf.s.aHwBreakpoints[i]);
|
---|
[58909] | 1413 | if (RT_FAILURE(rc) || rc == VINF_CALLBACK_RETURN)
|
---|
[1] | 1414 | return rc;
|
---|
| 1415 | }
|
---|
| 1416 |
|
---|
| 1417 | /*
|
---|
| 1418 | * Enumerate the other breakpoints.
|
---|
| 1419 | */
|
---|
[11311] | 1420 | for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
|
---|
[1] | 1421 | if (pVM->dbgf.s.aBreakpoints[i].enmType != DBGFBPTYPE_FREE)
|
---|
| 1422 | {
|
---|
[44399] | 1423 | int rc = pfnCallback(pUVM, pvUser, &pVM->dbgf.s.aBreakpoints[i]);
|
---|
[58909] | 1424 | if (RT_FAILURE(rc) || rc == VINF_CALLBACK_RETURN)
|
---|
[1] | 1425 | return rc;
|
---|
| 1426 | }
|
---|
| 1427 |
|
---|
| 1428 | return VINF_SUCCESS;
|
---|
| 1429 | }
|
---|
| 1430 |
|
---|
[44399] | 1431 |
|
---|
| 1432 | /**
|
---|
| 1433 | * Enumerate the breakpoints.
|
---|
| 1434 | *
|
---|
| 1435 | * @returns VBox status code.
|
---|
| 1436 | * @param pUVM The user mode VM handle.
|
---|
| 1437 | * @param pfnCallback The callback function.
|
---|
| 1438 | * @param pvUser The user argument to pass to the callback.
|
---|
| 1439 | * @thread Any thread but the callback will be called from EMT.
|
---|
| 1440 | */
|
---|
| 1441 | VMMR3DECL(int) DBGFR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser)
|
---|
| 1442 | {
|
---|
| 1443 | /*
|
---|
| 1444 | * This must be done on EMT.
|
---|
| 1445 | */
|
---|
[58909] | 1446 | int rc = VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpEnum, 3, pUVM, pfnCallback, pvUser);
|
---|
[64770] | 1447 | LogFlow(("DBGFR3BpEnum: returns %Rrc\n", rc));
|
---|
[44399] | 1448 | return rc;
|
---|
| 1449 | }
|
---|
| 1450 |
|
---|