~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/VMM/DBGFBp.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

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