1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
|
/* $Id: DBGFInternal.h $ */
/** @file
* DBGF - Internal header file.
*/
/*
* Copyright (C) 2006-2019 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#ifndef VMM_INCLUDED_SRC_include_DBGFInternal_h
#define VMM_INCLUDED_SRC_include_DBGFInternal_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif
#include <VBox/cdefs.h>
#ifdef IN_RING3
# include <VBox/dis.h>
#endif
#include <VBox/types.h>
#include <iprt/semaphore.h>
#include <iprt/critsect.h>
#include <iprt/string.h>
#include <iprt/avl.h>
#include <iprt/dbg.h>
#include <VBox/vmm/dbgf.h>
/** @defgroup grp_dbgf_int Internals
* @ingroup grp_dbgf
* @internal
* @{
*/
/** VMM Debugger Command. */
typedef enum DBGFCMD
{
/** No command.
* This is assigned to the field by the emulation thread after
* a command has been completed. */
DBGFCMD_NO_COMMAND = 0,
/** Halt the VM. */
DBGFCMD_HALT,
/** Resume execution. */
DBGFCMD_GO,
/** Single step execution - stepping into calls. */
DBGFCMD_SINGLE_STEP,
/** Detaches the debugger.
* Disabling all breakpoints, watch points and the like. */
DBGFCMD_DETACH_DEBUGGER,
/** Detached the debugger.
* The isn't a command as such, it's just that it's necessary for the
* detaching protocol to be racefree. */
DBGFCMD_DETACHED_DEBUGGER
} DBGFCMD;
/**
* VMM Debugger Command.
*/
typedef union DBGFCMDDATA
{
uint32_t uDummy;
} DBGFCMDDATA;
/** Pointer to DBGF Command Data. */
typedef DBGFCMDDATA *PDBGFCMDDATA;
/**
* Info type.
*/
typedef enum DBGFINFOTYPE
{
/** Invalid. */
DBGFINFOTYPE_INVALID = 0,
/** Device owner. */
DBGFINFOTYPE_DEV,
/** Driver owner. */
DBGFINFOTYPE_DRV,
/** Internal owner. */
DBGFINFOTYPE_INT,
/** External owner. */
DBGFINFOTYPE_EXT
} DBGFINFOTYPE;
/** Pointer to info structure. */
typedef struct DBGFINFO *PDBGFINFO;
#ifdef IN_RING3
/**
* Info structure.
*/
typedef struct DBGFINFO
{
/** The flags. */
uint32_t fFlags;
/** Owner type. */
DBGFINFOTYPE enmType;
/** Per type data. */
union
{
/** DBGFINFOTYPE_DEV */
struct
{
/** Device info handler function. */
PFNDBGFHANDLERDEV pfnHandler;
/** The device instance. */
PPDMDEVINS pDevIns;
} Dev;
/** DBGFINFOTYPE_DRV */
struct
{
/** Driver info handler function. */
PFNDBGFHANDLERDRV pfnHandler;
/** The driver instance. */
PPDMDRVINS pDrvIns;
} Drv;
/** DBGFINFOTYPE_INT */
struct
{
/** Internal info handler function. */
PFNDBGFHANDLERINT pfnHandler;
} Int;
/** DBGFINFOTYPE_EXT */
struct
{
/** External info handler function. */
PFNDBGFHANDLEREXT pfnHandler;
/** The user argument. */
void *pvUser;
} Ext;
} u;
/** Pointer to the description. */
const char *pszDesc;
/** Pointer to the next info structure. */
PDBGFINFO pNext;
/** The identifier name length. */
size_t cchName;
/** The identifier name. (Extends 'beyond' the struct as usual.) */
char szName[1];
} DBGFINFO;
#endif /* IN_RING3 */
#ifdef IN_RING3
/**
* Guest OS digger instance.
*/
typedef struct DBGFOS
{
/** Pointer to the registration record. */
PCDBGFOSREG pReg;
/** Pointer to the next OS we've registered. */
struct DBGFOS *pNext;
/** List of EMT interface wrappers. */
struct DBGFOSEMTWRAPPER *pWrapperHead;
/** The instance data (variable size). */
uint8_t abData[16];
} DBGFOS;
#endif
/** Pointer to guest OS digger instance. */
typedef struct DBGFOS *PDBGFOS;
/** Pointer to const guest OS digger instance. */
typedef struct DBGFOS const *PCDBGFOS;
/**
* Breakpoint search optimization.
*/
typedef struct DBGFBPSEARCHOPT
{
/** Where to start searching for hits.
* (First enabled is #DBGF::aBreakpoints[iStartSearch]). */
uint32_t volatile iStartSearch;
/** The number of aBreakpoints entries to search.
* (Last enabled is #DBGF::aBreakpoints[iStartSearch + cToSearch - 1]) */
uint32_t volatile cToSearch;
} DBGFBPSEARCHOPT;
/** Pointer to a breakpoint search optimziation structure. */
typedef DBGFBPSEARCHOPT *PDBGFBPSEARCHOPT;
/**
* DBGF Data (part of VM)
*/
typedef struct DBGF
{
/** Bitmap of enabled hardware interrupt breakpoints. */
uint32_t bmHardIntBreakpoints[256 / 32];
/** Bitmap of enabled software interrupt breakpoints. */
uint32_t bmSoftIntBreakpoints[256 / 32];
/** Bitmap of selected events.
* This includes non-selectable events too for simplicity, we maintain the
* state for some of these, as it may come in handy. */
uint64_t bmSelectedEvents[(DBGFEVENT_END + 63) / 64];
/** Enabled hardware interrupt breakpoints. */
uint32_t cHardIntBreakpoints;
/** Enabled software interrupt breakpoints. */
uint32_t cSoftIntBreakpoints;
/** The number of selected events. */
uint32_t cSelectedEvents;
/** The number of enabled hardware breakpoints. */
uint8_t cEnabledHwBreakpoints;
/** The number of enabled hardware I/O breakpoints. */
uint8_t cEnabledHwIoBreakpoints;
/** The number of enabled INT3 breakpoints. */
uint8_t cEnabledInt3Breakpoints;
uint8_t abPadding; /**< Unused padding space up for grabs. */
uint32_t uPadding;
/** Debugger Attached flag.
* Set if a debugger is attached, elsewise it's clear.
*/
bool volatile fAttached;
/** Stopped in the Hypervisor.
* Set if we're stopped on a trace, breakpoint or assertion inside
* the hypervisor and have to restrict the available operations.
*/
bool volatile fStoppedInHyper;
/**
* Ping-Pong construct where the Ping side is the VMM and the Pong side
* the Debugger.
*/
RTPINGPONG PingPong;
RTHCUINTPTR uPtrPadding; /**< Alignment padding. */
/** The Event to the debugger.
* The VMM will ping the debugger when the event is ready. The event is
* either a response to a command or to a break/watch point issued
* previously.
*/
DBGFEVENT DbgEvent;
/** The Command to the VMM.
* Operated in an atomic fashion since the VMM will poll on this.
* This means that a the command data must be written before this member
* is set. The VMM will reset this member to the no-command state
* when it have processed it.
*/
DBGFCMD volatile enmVMMCmd;
/** The Command data.
* Not all commands take data. */
DBGFCMDDATA VMMCmdData;
/** Stepping filtering. */
struct
{
/** The CPU doing the stepping.
* Set to NIL_VMCPUID when filtering is inactive */
VMCPUID idCpu;
/** The specified flags. */
uint32_t fFlags;
/** The effective PC address to stop at, if given. */
RTGCPTR AddrPc;
/** The lowest effective stack address to stop at.
* Together with cbStackPop, this forms a range of effective stack pointer
* addresses that we stop for. */
RTGCPTR AddrStackPop;
/** The size of the stack stop area starting at AddrStackPop. */
RTGCPTR cbStackPop;
/** Maximum number of steps. */
uint32_t cMaxSteps;
/** Number of steps made thus far. */
uint32_t cSteps;
/** Current call counting balance for step-over handling. */
uint32_t uCallDepth;
uint32_t u32Padding; /**< Alignment padding. */
} SteppingFilter;
uint32_t u32Padding[2]; /**< Alignment padding. */
/** Array of hardware breakpoints. (0..3)
* This is shared among all the CPUs because life is much simpler that way. */
DBGFBP aHwBreakpoints[4];
/** Array of int 3 and REM breakpoints. (4..)
* @remark This is currently a fixed size array for reasons of simplicity. */
DBGFBP aBreakpoints[32];
/** MMIO breakpoint search optimizations. */
DBGFBPSEARCHOPT Mmio;
/** I/O port breakpoint search optimizations. */
DBGFBPSEARCHOPT PortIo;
/** INT3 breakpoint search optimizations. */
DBGFBPSEARCHOPT Int3;
/**
* Bug check data.
* @note This will not be reset on reset.
*/
struct
{
/** The ID of the CPU reporting it. */
VMCPUID idCpu;
/** The event associated with the bug check (gives source).
* This is set to DBGFEVENT_END if no BSOD data here. */
DBGFEVENTTYPE enmEvent;
/** The total reset count at the time (VMGetResetCount). */
uint32_t uResetNo;
/** Explicit padding. */
uint32_t uPadding;
/** When it was reported (TMVirtualGet). */
uint64_t uTimestamp;
/** The bug check number.
* @note This is really just 32-bit wide, see KeBugCheckEx. */
uint64_t uBugCheck;
/** The bug check parameters. */
uint64_t auParameters[4];
} BugCheck;
} DBGF;
AssertCompileMemberAlignment(DBGF, DbgEvent, 8);
AssertCompileMemberAlignment(DBGF, aHwBreakpoints, 8);
AssertCompileMemberAlignment(DBGF, bmHardIntBreakpoints, 8);
/** Pointer to DBGF Data. */
typedef DBGF *PDBGF;
/**
* Event state (for DBGFCPU::aEvents).
*/
typedef enum DBGFEVENTSTATE
{
/** Invalid event stack entry. */
DBGFEVENTSTATE_INVALID = 0,
/** The current event stack entry. */
DBGFEVENTSTATE_CURRENT,
/** Event that should be ignored but hasn't yet actually been ignored. */
DBGFEVENTSTATE_IGNORE,
/** Event that has been ignored but may be restored to IGNORE should another
* debug event fire before the instruction is completed. */
DBGFEVENTSTATE_RESTORABLE,
/** End of valid events. */
DBGFEVENTSTATE_END,
/** Make sure we've got a 32-bit type. */
DBGFEVENTSTATE_32BIT_HACK = 0x7fffffff
} DBGFEVENTSTATE;
/** Converts a DBGFCPU pointer into a VM pointer. */
#define DBGFCPU_2_VM(pDbgfCpu) ((PVM)((uint8_t *)(pDbgfCpu) + (pDbgfCpu)->offVM))
/**
* The per CPU data for DBGF.
*/
typedef struct DBGFCPU
{
/** The offset into the VM structure.
* @see DBGFCPU_2_VM(). */
uint32_t offVM;
/** Current active breakpoint (id).
* This is ~0U if not active. It is set when a execution engine
* encounters a breakpoint and returns VINF_EM_DBG_BREAKPOINT. This is
* currently not used for REM breakpoints because of the lazy coupling
* between VBox and REM.
*
* @todo drop this in favor of aEvents! */
uint32_t iActiveBp;
/** Set if we're singlestepping in raw mode.
* This is checked and cleared in the \#DB handler. */
bool fSingleSteppingRaw;
/** Alignment padding. */
bool afPadding[3];
/** The number of events on the stack (aEvents).
* The pending event is the last one (aEvents[cEvents - 1]), but only when
* enmState is DBGFEVENTSTATE_CURRENT. */
uint32_t cEvents;
/** Events - current, ignoring and ignored.
*
* We maintain a stack of events in order to try avoid ending up in an infinit
* loop when resuming after an event fired. There are cases where we may end
* generating additional events before the instruction can be executed
* successfully. Like for instance an XCHG on MMIO with separate read and write
* breakpoints, or a MOVSB instruction working on breakpointed MMIO as both
* source and destination.
*
* So, when resuming after dropping into the debugger for an event, we convert
* the DBGFEVENTSTATE_CURRENT event into a DBGFEVENTSTATE_IGNORE event, leaving
* cEvents unchanged. If the event is reported again, we will ignore it and
* tell the reporter to continue executing. The event change to the
* DBGFEVENTSTATE_RESTORABLE state.
*
* Currently, the event reporter has to figure out that it is a nested event and
* tell DBGF to restore DBGFEVENTSTATE_RESTORABLE events (and keep
* DBGFEVENTSTATE_IGNORE, should they happen out of order for some weird
* reason).
*/
struct
{
/** The event details. */
DBGFEVENT Event;
/** The RIP at which this happend (for validating ignoring). */
uint64_t rip;
/** The event state. */
DBGFEVENTSTATE enmState;
/** Alignment padding. */
uint32_t u32Alignment;
} aEvents[3];
} DBGFCPU;
AssertCompileMemberAlignment(DBGFCPU, aEvents, 8);
AssertCompileMemberSizeAlignment(DBGFCPU, aEvents[0], 8);
/** Pointer to DBGFCPU data. */
typedef DBGFCPU *PDBGFCPU;
struct DBGFOSEMTWRAPPER;
/**
* The DBGF data kept in the UVM.
*/
typedef struct DBGFUSERPERVM
{
/** The address space database lock. */
RTSEMRW hAsDbLock;
/** The address space handle database. (Protected by hAsDbLock.) */
R3PTRTYPE(AVLPVTREE) AsHandleTree;
/** The address space process id database. (Protected by hAsDbLock.) */
R3PTRTYPE(AVLU32TREE) AsPidTree;
/** The address space name database. (Protected by hAsDbLock.) */
R3PTRTYPE(RTSTRSPACE) AsNameSpace;
/** Special address space aliases. (Protected by hAsDbLock.) */
RTDBGAS volatile ahAsAliases[DBGF_AS_COUNT];
/** For lazily populating the aliased address spaces. */
bool volatile afAsAliasPopuplated[DBGF_AS_COUNT];
/** Alignment padding. */
bool afAlignment1[2];
/** Debug configuration. */
R3PTRTYPE(RTDBGCFG) hDbgCfg;
/** The register database lock. */
RTSEMRW hRegDbLock;
/** String space for looking up registers. (Protected by hRegDbLock.) */
R3PTRTYPE(RTSTRSPACE) RegSpace;
/** String space holding the register sets. (Protected by hRegDbLock.) */
R3PTRTYPE(RTSTRSPACE) RegSetSpace;
/** The number of registers (aliases, sub-fields and the special CPU
* register aliases (eg AH) are not counted). */
uint32_t cRegs;
/** For early initialization by . */
bool volatile fRegDbInitialized;
/** Alignment padding. */
bool afAlignment2[3];
/** Critical section protecting the Guest OS Digger data, the info handlers
* and the plugins. These share to give the best possible plugin unload
* race protection. */
RTCRITSECTRW CritSect;
/** Head of the LIFO of loaded DBGF plugins. */
R3PTRTYPE(struct DBGFPLUGIN *) pPlugInHead;
/** The current Guest OS digger. */
R3PTRTYPE(PDBGFOS) pCurOS;
/** The head of the Guest OS digger instances. */
R3PTRTYPE(PDBGFOS) pOSHead;
/** List of registered info handlers. */
R3PTRTYPE(PDBGFINFO) pInfoFirst;
/** The type database lock. */
RTSEMRW hTypeDbLock;
/** String space for looking up types. (Protected by hTypeDbLock.) */
R3PTRTYPE(RTSTRSPACE) TypeSpace;
/** For early initialization by . */
bool volatile fTypeDbInitialized;
/** Alignment padding. */
bool afAlignment3[3];
} DBGFUSERPERVM;
typedef DBGFUSERPERVM *PDBGFUSERPERVM;
typedef DBGFUSERPERVM const *PCDBGFUSERPERVM;
/**
* The per-CPU DBGF data kept in the UVM.
*/
typedef struct DBGFUSERPERVMCPU
{
/** The guest register set for this CPU. Can be NULL. */
R3PTRTYPE(struct DBGFREGSET *) pGuestRegSet;
/** The hypervisor register set for this CPU. Can be NULL. */
R3PTRTYPE(struct DBGFREGSET *) pHyperRegSet;
} DBGFUSERPERVMCPU;
#ifdef IN_RING3
int dbgfR3AsInit(PUVM pUVM);
void dbgfR3AsTerm(PUVM pUVM);
void dbgfR3AsRelocate(PUVM pUVM, RTGCUINTPTR offDelta);
int dbgfR3BpInit(PVM pVM);
int dbgfR3InfoInit(PUVM pUVM);
int dbgfR3InfoTerm(PUVM pUVM);
int dbgfR3OSInit(PUVM pUVM);
void dbgfR3OSTermPart1(PUVM pUVM);
void dbgfR3OSTermPart2(PUVM pUVM);
int dbgfR3OSStackUnwindAssist(PUVM pUVM, VMCPUID idCpu, PDBGFSTACKFRAME pFrame, PRTDBGUNWINDSTATE pState,
PCCPUMCTX pInitialCtx, RTDBGAS hAs, uint64_t *puScratch);
int dbgfR3RegInit(PUVM pUVM);
void dbgfR3RegTerm(PUVM pUVM);
int dbgfR3TraceInit(PVM pVM);
void dbgfR3TraceRelocate(PVM pVM);
void dbgfR3TraceTerm(PVM pVM);
DECLHIDDEN(int) dbgfR3TypeInit(PUVM pUVM);
DECLHIDDEN(void) dbgfR3TypeTerm(PUVM pUVM);
int dbgfR3PlugInInit(PUVM pUVM);
void dbgfR3PlugInTerm(PUVM pUVM);
int dbgfR3BugCheckInit(PVM pVM);
/**
* DBGF disassembler state (substate of DISSTATE).
*/
typedef struct DBGFDISSTATE
{
/** Pointer to the current instruction. */
PCDISOPCODE pCurInstr;
/** Size of the instruction in bytes. */
uint32_t cbInstr;
/** Parameters. */
DISOPPARAM Param1;
DISOPPARAM Param2;
DISOPPARAM Param3;
DISOPPARAM Param4;
} DBGFDISSTATE;
/** Pointer to a DBGF disassembler state. */
typedef DBGFDISSTATE *PDBGFDISSTATE;
DECLHIDDEN(int) dbgfR3DisasInstrStateEx(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddr, uint32_t fFlags,
char *pszOutput, uint32_t cbOutput, PDBGFDISSTATE pDisState);
#endif /* IN_RING3 */
/** @} */
#endif /* !VMM_INCLUDED_SRC_include_DBGFInternal_h */
|