VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGFOS.cpp@ 93554

Last change on this file since 93554 was 93470, checked in by vboxsync, 3 years ago

DbgPlugInDiggers,VMM,Main: Refactored the diggers and related interfaces to work via the VMM function table. Removed non-working tstVBoxDbg (needs proper COM now). bugref:10072

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 25.1 KB
Line 
1/* $Id: DBGFOS.cpp 93470 2022-01-27 23:51:28Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Guest OS Diggers.
4 */
5
6/*
7 * Copyright (C) 2008-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DBGF
23#include <VBox/vmm/dbgf.h>
24#include <VBox/vmm/mm.h>
25#include <VBox/vmm/vmm.h>
26#include "DBGFInternal.h"
27#include <VBox/vmm/uvm.h>
28#include <VBox/err.h>
29#include <VBox/log.h>
30
31#include <iprt/assert.h>
32#include <iprt/thread.h>
33#include <iprt/param.h>
34
35
36/*********************************************************************************************************************************
37* Defined Constants And Macros *
38*********************************************************************************************************************************/
39
40#define DBGF_OS_READ_LOCK(pUVM) \
41 do { int rcLock = RTCritSectRwEnterShared(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
42#define DBGF_OS_READ_UNLOCK(pUVM) \
43 do { int rcLock = RTCritSectRwLeaveShared(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
44
45#define DBGF_OS_WRITE_LOCK(pUVM) \
46 do { int rcLock = RTCritSectRwEnterExcl(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
47#define DBGF_OS_WRITE_UNLOCK(pUVM) \
48 do { int rcLock = RTCritSectRwLeaveExcl(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
49
50
51/*********************************************************************************************************************************
52* Structures and Typedefs *
53*********************************************************************************************************************************/
54/**
55 * EMT interface wrappers.
56 *
57 * The diggers expects to be called on an EMT. To avoid the debugger+Main having
58 *
59 * Since the user (debugger/Main) shouldn't be calling directly into the digger code, but rather
60 */
61typedef struct DBGFOSEMTWRAPPER
62{
63 /** Pointer to the next list entry. */
64 struct DBGFOSEMTWRAPPER *pNext;
65 /** The interface type. */
66 DBGFOSINTERFACE enmIf;
67 /** The digger interface pointer. */
68 union
69 {
70 /** Generic void pointer. */
71 void *pv;
72 /** DBGFOSINTERFACE_DMESG.*/
73 PDBGFOSIDMESG pDmesg;
74 /** DBGFOSINTERFACE_WINNT.*/
75 PDBGFOSIWINNT pWinNt;
76 } uDigger;
77 /** The user mode VM handle. */
78 PUVM pUVM;
79 /** The wrapper interface union (consult enmIf). */
80 union
81 {
82 /** DBGFOSINTERFACE_DMESG.*/
83 DBGFOSIDMESG Dmesg;
84 /** DBGFOSINTERFACE_WINNT.*/
85 DBGFOSIWINNT WinNt;
86 } uWrapper;
87} DBGFOSEMTWRAPPER;
88/** Pointer to an EMT interface wrapper. */
89typedef DBGFOSEMTWRAPPER *PDBGFOSEMTWRAPPER;
90
91
92/**
93 * Internal init routine called by DBGFR3Init().
94 *
95 * @returns VBox status code.
96 * @param pUVM The user mode VM handle.
97 */
98int dbgfR3OSInit(PUVM pUVM)
99{
100 RT_NOREF_PV(pUVM);
101 return VINF_SUCCESS;
102}
103
104
105/**
106 * Internal cleanup routine called by DBGFR3Term(), part 1.
107 *
108 * @param pUVM The user mode VM handle.
109 */
110void dbgfR3OSTermPart1(PUVM pUVM)
111{
112 DBGF_OS_WRITE_LOCK(pUVM);
113
114 /*
115 * Terminate the current one.
116 */
117 if (pUVM->dbgf.s.pCurOS)
118 {
119 pUVM->dbgf.s.pCurOS->pReg->pfnTerm(pUVM, VMMR3GetVTable(), pUVM->dbgf.s.pCurOS->abData);
120 pUVM->dbgf.s.pCurOS = NULL;
121 }
122
123 DBGF_OS_WRITE_UNLOCK(pUVM);
124}
125
126
127/**
128 * Internal cleanup routine called by DBGFR3Term(), part 2.
129 *
130 * @param pUVM The user mode VM handle.
131 */
132void dbgfR3OSTermPart2(PUVM pUVM)
133{
134 DBGF_OS_WRITE_LOCK(pUVM);
135
136 /* This shouldn't happen. */
137 AssertStmt(!pUVM->dbgf.s.pCurOS, dbgfR3OSTermPart1(pUVM));
138
139 /*
140 * Destroy all the instances.
141 */
142 while (pUVM->dbgf.s.pOSHead)
143 {
144 PDBGFOS pOS = pUVM->dbgf.s.pOSHead;
145 pUVM->dbgf.s.pOSHead = pOS->pNext;
146 if (pOS->pReg->pfnDestruct)
147 pOS->pReg->pfnDestruct(pUVM, VMMR3GetVTable(), pOS->abData);
148
149 PDBGFOSEMTWRAPPER pFree = pOS->pWrapperHead;
150 while ((pFree = pOS->pWrapperHead) != NULL)
151 {
152 pOS->pWrapperHead = pFree->pNext;
153 pFree->pNext = NULL;
154 MMR3HeapFree(pFree);
155 }
156
157 MMR3HeapFree(pOS);
158 }
159
160 DBGF_OS_WRITE_UNLOCK(pUVM);
161}
162
163
164/**
165 * EMT worker function for DBGFR3OSRegister.
166 *
167 * @returns VBox status code.
168 * @param pUVM The user mode VM handle.
169 * @param pReg The registration structure.
170 */
171static DECLCALLBACK(int) dbgfR3OSRegister(PUVM pUVM, PDBGFOSREG pReg)
172{
173 /* more validations. */
174 DBGF_OS_READ_LOCK(pUVM);
175 PDBGFOS pOS;
176 for (pOS = pUVM->dbgf.s.pOSHead; pOS; pOS = pOS->pNext)
177 if (!strcmp(pOS->pReg->szName, pReg->szName))
178 {
179 DBGF_OS_READ_UNLOCK(pUVM);
180 Log(("dbgfR3OSRegister: %s -> VERR_ALREADY_LOADED\n", pReg->szName));
181 return VERR_ALREADY_LOADED;
182 }
183 DBGF_OS_READ_UNLOCK(pUVM);
184
185 /*
186 * Allocate a new structure, call the constructor and link it into the list.
187 */
188 pOS = (PDBGFOS)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF_OS, RT_UOFFSETOF_DYN(DBGFOS, abData[pReg->cbData]));
189 AssertReturn(pOS, VERR_NO_MEMORY);
190 pOS->pReg = pReg;
191
192 int rc = pOS->pReg->pfnConstruct(pUVM, VMMR3GetVTable(), pOS->abData);
193 if (RT_SUCCESS(rc))
194 {
195 DBGF_OS_WRITE_LOCK(pUVM);
196 pOS->pNext = pUVM->dbgf.s.pOSHead;
197 pUVM->dbgf.s.pOSHead = pOS;
198 DBGF_OS_WRITE_UNLOCK(pUVM);
199 }
200 else
201 {
202 if (pOS->pReg->pfnDestruct)
203 pOS->pReg->pfnDestruct(pUVM, VMMR3GetVTable(), pOS->abData);
204 MMR3HeapFree(pOS);
205 }
206
207 return VINF_SUCCESS;
208}
209
210
211/**
212 * Registers a guest OS digger.
213 *
214 * This will instantiate an instance of the digger and add it
215 * to the list for us in the next call to DBGFR3OSDetect().
216 *
217 * @returns VBox status code.
218 * @param pUVM The user mode VM handle.
219 * @param pReg The registration structure.
220 * @thread Any.
221 */
222VMMR3DECL(int) DBGFR3OSRegister(PUVM pUVM, PCDBGFOSREG pReg)
223{
224 /*
225 * Validate intput.
226 */
227 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
228
229 AssertPtrReturn(pReg, VERR_INVALID_POINTER);
230 AssertReturn(pReg->u32Magic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC);
231 AssertReturn(pReg->u32EndMagic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC);
232 AssertReturn(!pReg->fFlags, VERR_INVALID_PARAMETER);
233 AssertReturn(pReg->cbData < _2G, VERR_INVALID_PARAMETER);
234 AssertReturn(pReg->szName[0], VERR_INVALID_NAME);
235 AssertReturn(RTStrEnd(&pReg->szName[0], sizeof(pReg->szName)), VERR_INVALID_NAME);
236 AssertPtrReturn(pReg->pfnConstruct, VERR_INVALID_POINTER);
237 AssertPtrNullReturn(pReg->pfnDestruct, VERR_INVALID_POINTER);
238 AssertPtrReturn(pReg->pfnProbe, VERR_INVALID_POINTER);
239 AssertPtrReturn(pReg->pfnInit, VERR_INVALID_POINTER);
240 AssertPtrReturn(pReg->pfnRefresh, VERR_INVALID_POINTER);
241 AssertPtrReturn(pReg->pfnTerm, VERR_INVALID_POINTER);
242 AssertPtrReturn(pReg->pfnQueryVersion, VERR_INVALID_POINTER);
243 AssertPtrReturn(pReg->pfnQueryInterface, VERR_INVALID_POINTER);
244
245 /*
246 * Pass it on to EMT(0).
247 */
248 return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSRegister, 2, pUVM, pReg);
249}
250
251
252/**
253 * EMT worker function for DBGFR3OSDeregister.
254 *
255 * @returns VBox status code.
256 * @param pUVM The user mode VM handle.
257 * @param pReg The registration structure.
258 */
259static DECLCALLBACK(int) dbgfR3OSDeregister(PUVM pUVM, PDBGFOSREG pReg)
260{
261 /*
262 * Unlink it.
263 */
264 bool fWasCurOS = false;
265 PDBGFOS pOSPrev = NULL;
266 PDBGFOS pOS;
267 DBGF_OS_WRITE_LOCK(pUVM);
268 for (pOS = pUVM->dbgf.s.pOSHead; pOS; pOSPrev = pOS, pOS = pOS->pNext)
269 if (pOS->pReg == pReg)
270 {
271 if (pOSPrev)
272 pOSPrev->pNext = pOS->pNext;
273 else
274 pUVM->dbgf.s.pOSHead = pOS->pNext;
275 if (pUVM->dbgf.s.pCurOS == pOS)
276 {
277 pUVM->dbgf.s.pCurOS = NULL;
278 fWasCurOS = true;
279 }
280 break;
281 }
282 DBGF_OS_WRITE_UNLOCK(pUVM);
283 if (!pOS)
284 {
285 Log(("DBGFR3OSDeregister: %s -> VERR_NOT_FOUND\n", pReg->szName));
286 return VERR_NOT_FOUND;
287 }
288
289 /*
290 * Terminate it if it was the current OS, then invoke the
291 * destructor and clean up.
292 */
293 if (fWasCurOS)
294 pOS->pReg->pfnTerm(pUVM, VMMR3GetVTable(), pOS->abData);
295 if (pOS->pReg->pfnDestruct)
296 pOS->pReg->pfnDestruct(pUVM, VMMR3GetVTable(), pOS->abData);
297
298 PDBGFOSEMTWRAPPER pFree = pOS->pWrapperHead;
299 while ((pFree = pOS->pWrapperHead) != NULL)
300 {
301 pOS->pWrapperHead = pFree->pNext;
302 pFree->pNext = NULL;
303 MMR3HeapFree(pFree);
304 }
305
306 MMR3HeapFree(pOS);
307
308 return VINF_SUCCESS;
309}
310
311
312/**
313 * Deregisters a guest OS digger previously registered by DBGFR3OSRegister.
314 *
315 * @returns VBox status code.
316 *
317 * @param pUVM The user mode VM handle.
318 * @param pReg The registration structure.
319 * @thread Any.
320 */
321VMMR3DECL(int) DBGFR3OSDeregister(PUVM pUVM, PCDBGFOSREG pReg)
322{
323 /*
324 * Validate input.
325 */
326 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
327 AssertPtrReturn(pReg, VERR_INVALID_POINTER);
328 AssertReturn(pReg->u32Magic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC);
329 AssertReturn(pReg->u32EndMagic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC);
330 AssertReturn(RTStrEnd(&pReg->szName[0], sizeof(pReg->szName)), VERR_INVALID_NAME);
331
332 DBGF_OS_READ_LOCK(pUVM);
333 PDBGFOS pOS;
334 for (pOS = pUVM->dbgf.s.pOSHead; pOS; pOS = pOS->pNext)
335 if (pOS->pReg == pReg)
336 break;
337 DBGF_OS_READ_UNLOCK(pUVM);
338
339 if (!pOS)
340 {
341 Log(("DBGFR3OSDeregister: %s -> VERR_NOT_FOUND\n", pReg->szName));
342 return VERR_NOT_FOUND;
343 }
344
345 /*
346 * Pass it on to EMT(0).
347 */
348 return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSDeregister, 2, pUVM, pReg);
349}
350
351
352/**
353 * EMT worker function for DBGFR3OSDetect.
354 *
355 * @returns VBox status code.
356 * @retval VINF_SUCCESS if successfully detected.
357 * @retval VINF_DBGF_OS_NOT_DETCTED if we cannot figure it out.
358 *
359 * @param pUVM The user mode VM handle.
360 * @param pszName Where to store the OS name. Empty string if not detected.
361 * @param cchName Size of the buffer.
362 */
363static DECLCALLBACK(int) dbgfR3OSDetect(PUVM pUVM, char *pszName, size_t cchName)
364{
365 /*
366 * Cycle thru the detection routines.
367 */
368 DBGF_OS_WRITE_LOCK(pUVM);
369
370 PDBGFOS const pOldOS = pUVM->dbgf.s.pCurOS;
371 pUVM->dbgf.s.pCurOS = NULL;
372
373 for (PDBGFOS pNewOS = pUVM->dbgf.s.pOSHead; pNewOS; pNewOS = pNewOS->pNext)
374 if (pNewOS->pReg->pfnProbe(pUVM, VMMR3GetVTable(), pNewOS->abData))
375 {
376 int rc;
377 pUVM->dbgf.s.pCurOS = pNewOS;
378 if (pOldOS == pNewOS)
379 rc = pNewOS->pReg->pfnRefresh(pUVM, VMMR3GetVTable(), pNewOS->abData);
380 else
381 {
382 if (pOldOS)
383 pOldOS->pReg->pfnTerm(pUVM, VMMR3GetVTable(), pNewOS->abData);
384 rc = pNewOS->pReg->pfnInit(pUVM, VMMR3GetVTable(), pNewOS->abData);
385 }
386 if (pszName && cchName)
387 strncat(pszName, pNewOS->pReg->szName, cchName);
388
389 DBGF_OS_WRITE_UNLOCK(pUVM);
390 return rc;
391 }
392
393 /* not found */
394 if (pOldOS)
395 pOldOS->pReg->pfnTerm(pUVM, VMMR3GetVTable(), pOldOS->abData);
396
397 DBGF_OS_WRITE_UNLOCK(pUVM);
398 return VINF_DBGF_OS_NOT_DETCTED;
399}
400
401
402/**
403 * Detects the guest OS and try dig out symbols and useful stuff.
404 *
405 * When called the 2nd time, symbols will be updated that if the OS
406 * is the same.
407 *
408 * @returns VBox status code.
409 * @retval VINF_SUCCESS if successfully detected.
410 * @retval VINF_DBGF_OS_NOT_DETCTED if we cannot figure it out.
411 *
412 * @param pUVM The user mode VM handle.
413 * @param pszName Where to store the OS name. Empty string if not detected.
414 * @param cchName Size of the buffer.
415 * @thread Any.
416 */
417VMMR3DECL(int) DBGFR3OSDetect(PUVM pUVM, char *pszName, size_t cchName)
418{
419 AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
420 if (pszName && cchName)
421 *pszName = '\0';
422 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
423
424 /*
425 * Pass it on to EMT(0).
426 */
427 return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSDetect, 3, pUVM, pszName, cchName);
428}
429
430
431/**
432 * EMT worker function for DBGFR3OSQueryNameAndVersion
433 *
434 * @returns VBox status code.
435 * @param pUVM The user mode VM handle.
436 * @param pszName Where to store the OS name. Optional.
437 * @param cchName The size of the name buffer.
438 * @param pszVersion Where to store the version string. Optional.
439 * @param cchVersion The size of the version buffer.
440 */
441static DECLCALLBACK(int) dbgfR3OSQueryNameAndVersion(PUVM pUVM, char *pszName, size_t cchName, char *pszVersion, size_t cchVersion)
442{
443 /*
444 * Any known OS?
445 */
446 DBGF_OS_READ_LOCK(pUVM);
447
448 if (pUVM->dbgf.s.pCurOS)
449 {
450 int rc = VINF_SUCCESS;
451 if (pszName && cchName)
452 {
453 size_t cch = strlen(pUVM->dbgf.s.pCurOS->pReg->szName);
454 if (cchName > cch)
455 memcpy(pszName, pUVM->dbgf.s.pCurOS->pReg->szName, cch + 1);
456 else
457 {
458 memcpy(pszName, pUVM->dbgf.s.pCurOS->pReg->szName, cchName - 1);
459 pszName[cchName - 1] = '\0';
460 rc = VINF_BUFFER_OVERFLOW;
461 }
462 }
463
464 if (pszVersion && cchVersion)
465 {
466 int rc2 = pUVM->dbgf.s.pCurOS->pReg->pfnQueryVersion(pUVM, VMMR3GetVTable(), pUVM->dbgf.s.pCurOS->abData,
467 pszVersion, cchVersion);
468 if (RT_FAILURE(rc2) || rc == VINF_SUCCESS)
469 rc = rc2;
470 }
471
472 DBGF_OS_READ_UNLOCK(pUVM);
473 return rc;
474 }
475
476 DBGF_OS_READ_UNLOCK(pUVM);
477 return VERR_DBGF_OS_NOT_DETCTED;
478}
479
480
481/**
482 * Queries the name and/or version string for the guest OS.
483 *
484 * It goes without saying that this querying is done using the current
485 * guest OS digger and not additions or user configuration.
486 *
487 * @returns VBox status code.
488 * @param pUVM The user mode VM handle.
489 * @param pszName Where to store the OS name. Optional.
490 * @param cchName The size of the name buffer.
491 * @param pszVersion Where to store the version string. Optional.
492 * @param cchVersion The size of the version buffer.
493 * @thread Any.
494 */
495VMMR3DECL(int) DBGFR3OSQueryNameAndVersion(PUVM pUVM, char *pszName, size_t cchName, char *pszVersion, size_t cchVersion)
496{
497 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
498 AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
499 AssertPtrNullReturn(pszVersion, VERR_INVALID_POINTER);
500
501 /*
502 * Initialize the output up front.
503 */
504 if (pszName && cchName)
505 *pszName = '\0';
506 if (pszVersion && cchVersion)
507 *pszVersion = '\0';
508
509 /*
510 * Pass it on to EMT(0).
511 */
512 return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/,
513 (PFNRT)dbgfR3OSQueryNameAndVersion, 5, pUVM, pszName, cchName, pszVersion, cchVersion);
514}
515
516
517/**
518 * @interface_method_impl{DBGFOSIDMESG,pfnQueryKernelLog, Generic EMT wrapper.}
519 */
520static DECLCALLBACK(int) dbgfR3OSEmtIDmesg_QueryKernelLog(PDBGFOSIDMESG pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, uint32_t fFlags,
521 uint32_t cMessages, char *pszBuf, size_t cbBuf, size_t *pcbActual)
522{
523 PDBGFOSEMTWRAPPER pWrapper = RT_FROM_MEMBER(pThis, DBGFOSEMTWRAPPER, uWrapper.Dmesg);
524 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
525 AssertReturn(pUVM == pWrapper->pUVM, VERR_INVALID_VM_HANDLE);
526 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
527 AssertReturn(cMessages > 0, VERR_INVALID_PARAMETER);
528 if (cbBuf)
529 AssertPtrReturn(pszBuf, VERR_INVALID_POINTER);
530 AssertPtrNullReturn(pcbActual, VERR_INVALID_POINTER);
531
532 return VMR3ReqPriorityCallWaitU(pWrapper->pUVM, 0 /*idDstCpu*/,
533 (PFNRT)pWrapper->uDigger.pDmesg->pfnQueryKernelLog, 8,
534 pWrapper->uDigger.pDmesg, pUVM, pVMM, fFlags, cMessages, pszBuf, cbBuf, pcbActual);
535
536}
537
538
539/**
540 * @interface_method_impl{DBGFOSIWINNT,pfnQueryVersion, Generic EMT wrapper.}
541 */
542static DECLCALLBACK(int) dbgfR3OSEmtIWinNt_QueryVersion(PDBGFOSIWINNT pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, uint32_t *puVersMajor,
543 uint32_t *puVersMinor, uint32_t *puBuildNumber, bool *pf32Bit)
544{
545 PDBGFOSEMTWRAPPER pWrapper = RT_FROM_MEMBER(pThis, DBGFOSEMTWRAPPER, uWrapper.WinNt);
546 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
547 AssertReturn(pUVM == pWrapper->pUVM, VERR_INVALID_VM_HANDLE);
548
549 return VMR3ReqPriorityCallWaitU(pWrapper->pUVM, 0 /*idDstCpu*/,
550 (PFNRT)pWrapper->uDigger.pWinNt->pfnQueryVersion, 7,
551 pWrapper->uDigger.pWinNt, pUVM, pVMM, puVersMajor, puVersMinor,
552 puBuildNumber, pf32Bit);
553}
554
555
556/**
557 * @interface_method_impl{DBGFOSIWINNT,pfnQueryKernelPtrs, Generic EMT wrapper.}
558 */
559static DECLCALLBACK(int) dbgfR3OSEmtIWinNt_QueryKernelPtrs(PDBGFOSIWINNT pThis, PUVM pUVM, PCVMMR3VTABLE pVMM,
560 PRTGCUINTPTR pGCPtrKernBase, PRTGCUINTPTR pGCPtrPsLoadedModuleList)
561{
562 PDBGFOSEMTWRAPPER pWrapper = RT_FROM_MEMBER(pThis, DBGFOSEMTWRAPPER, uWrapper.WinNt);
563 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
564 AssertReturn(pUVM == pWrapper->pUVM, VERR_INVALID_VM_HANDLE);
565
566 return VMR3ReqPriorityCallWaitU(pWrapper->pUVM, 0 /*idDstCpu*/,
567 (PFNRT)pWrapper->uDigger.pWinNt->pfnQueryKernelPtrs, 5,
568 pWrapper->uDigger.pWinNt, pUVM, pVMM, pGCPtrKernBase, pGCPtrPsLoadedModuleList);
569}
570
571
572/**
573 * @interface_method_impl{DBGFOSIWINNT,pfnQueryKpcrForVCpu, Generic EMT wrapper.}
574 */
575static DECLCALLBACK(int) dbgfR3OSEmtIWinNt_QueryKpcrForVCpu(struct DBGFOSIWINNT *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM,
576 VMCPUID idCpu, PRTGCUINTPTR pKpcr, PRTGCUINTPTR pKpcrb)
577{
578 PDBGFOSEMTWRAPPER pWrapper = RT_FROM_MEMBER(pThis, DBGFOSEMTWRAPPER, uWrapper.WinNt);
579 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
580 AssertReturn(pUVM == pWrapper->pUVM, VERR_INVALID_VM_HANDLE);
581
582 return VMR3ReqPriorityCallWaitU(pWrapper->pUVM, 0 /*idDstCpu*/,
583 (PFNRT)pWrapper->uDigger.pWinNt->pfnQueryKpcrForVCpu, 6,
584 pWrapper->uDigger.pWinNt, pUVM, pVMM, idCpu, pKpcr, pKpcrb);
585}
586
587
588/**
589 * @interface_method_impl{DBGFOSIWINNT,pfnQueryCurThrdForVCpu, Generic EMT wrapper.}
590 */
591static DECLCALLBACK(int) dbgfR3OSEmtIWinNt_QueryCurThrdForVCpu(struct DBGFOSIWINNT *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM,
592 VMCPUID idCpu, PRTGCUINTPTR pCurThrd)
593{
594 PDBGFOSEMTWRAPPER pWrapper = RT_FROM_MEMBER(pThis, DBGFOSEMTWRAPPER, uWrapper.WinNt);
595 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
596 AssertReturn(pUVM == pWrapper->pUVM, VERR_INVALID_VM_HANDLE);
597
598 return VMR3ReqPriorityCallWaitU(pWrapper->pUVM, 0 /*idDstCpu*/,
599 (PFNRT)pWrapper->uDigger.pWinNt->pfnQueryCurThrdForVCpu, 5,
600 pWrapper->uDigger.pWinNt, pUVM, pVMM, idCpu, pCurThrd);
601}
602
603
604/**
605 * EMT worker for DBGFR3OSQueryInterface.
606 *
607 * @param pUVM The user mode VM handle.
608 * @param enmIf The interface identifier.
609 * @param ppvIf Where to store the interface pointer on success.
610 */
611static DECLCALLBACK(void) dbgfR3OSQueryInterface(PUVM pUVM, DBGFOSINTERFACE enmIf, void **ppvIf)
612{
613 AssertPtrReturnVoid(ppvIf);
614 *ppvIf = NULL;
615 AssertReturnVoid(enmIf > DBGFOSINTERFACE_INVALID && enmIf < DBGFOSINTERFACE_END);
616 UVM_ASSERT_VALID_EXT_RETURN_VOID(pUVM);
617
618 /*
619 * Forward the query to the current OS.
620 */
621 DBGF_OS_READ_LOCK(pUVM);
622 PDBGFOS pOS = pUVM->dbgf.s.pCurOS;
623 if (pOS)
624 {
625 void *pvDiggerIf;
626 pvDiggerIf = pOS->pReg->pfnQueryInterface(pUVM, VMMR3GetVTable(), pUVM->dbgf.s.pCurOS->abData, enmIf);
627 if (pvDiggerIf)
628 {
629 /*
630 * Do we have an EMT wrapper for this interface already?
631 *
632 * We ASSUME the interfaces are static and not dynamically allocated
633 * for each QueryInterface call.
634 */
635 PDBGFOSEMTWRAPPER pWrapper = pOS->pWrapperHead;
636 while ( pWrapper != NULL
637 && ( pWrapper->uDigger.pv != pvDiggerIf
638 && pWrapper->enmIf != enmIf) )
639 pWrapper = pWrapper->pNext;
640 if (pWrapper)
641 {
642 *ppvIf = &pWrapper->uWrapper;
643 DBGF_OS_READ_UNLOCK(pUVM);
644 return;
645 }
646 DBGF_OS_READ_UNLOCK(pUVM);
647
648 /*
649 * Create a wrapper.
650 */
651 int rc = MMR3HeapAllocExU(pUVM, MM_TAG_DBGF_OS, sizeof(*pWrapper), (void **)&pWrapper);
652 if (RT_FAILURE(rc))
653 return;
654 pWrapper->uDigger.pv = pvDiggerIf;
655 pWrapper->pUVM = pUVM;
656 pWrapper->enmIf = enmIf;
657 switch (enmIf)
658 {
659 case DBGFOSINTERFACE_DMESG:
660 pWrapper->uWrapper.Dmesg.u32Magic = DBGFOSIDMESG_MAGIC;
661 pWrapper->uWrapper.Dmesg.pfnQueryKernelLog = dbgfR3OSEmtIDmesg_QueryKernelLog;
662 pWrapper->uWrapper.Dmesg.u32EndMagic = DBGFOSIDMESG_MAGIC;
663 break;
664 case DBGFOSINTERFACE_WINNT:
665 pWrapper->uWrapper.WinNt.u32Magic = DBGFOSIWINNT_MAGIC;
666 pWrapper->uWrapper.WinNt.pfnQueryVersion = dbgfR3OSEmtIWinNt_QueryVersion;
667 pWrapper->uWrapper.WinNt.pfnQueryKernelPtrs = dbgfR3OSEmtIWinNt_QueryKernelPtrs;
668 pWrapper->uWrapper.WinNt.pfnQueryKpcrForVCpu = dbgfR3OSEmtIWinNt_QueryKpcrForVCpu;
669 pWrapper->uWrapper.WinNt.pfnQueryCurThrdForVCpu = dbgfR3OSEmtIWinNt_QueryCurThrdForVCpu;
670 pWrapper->uWrapper.WinNt.u32EndMagic = DBGFOSIWINNT_MAGIC;
671 break;
672 default:
673 AssertFailed();
674 MMR3HeapFree(pWrapper);
675 return;
676 }
677
678 DBGF_OS_WRITE_LOCK(pUVM);
679 if (pUVM->dbgf.s.pCurOS == pOS)
680 {
681 pWrapper->pNext = pOS->pWrapperHead;
682 pOS->pWrapperHead = pWrapper;
683 *ppvIf = &pWrapper->uWrapper;
684 DBGF_OS_WRITE_UNLOCK(pUVM);
685 }
686 else
687 {
688 DBGF_OS_WRITE_UNLOCK(pUVM);
689 MMR3HeapFree(pWrapper);
690 }
691 return;
692 }
693 }
694 DBGF_OS_READ_UNLOCK(pUVM);
695}
696
697
698/**
699 * Query an optional digger interface.
700 *
701 * @returns Pointer to the digger interface on success, NULL if the interfaces isn't
702 * available or no active guest OS digger.
703 * @param pUVM The user mode VM handle.
704 * @param enmIf The interface identifier.
705 * @thread Any.
706 */
707VMMR3DECL(void *) DBGFR3OSQueryInterface(PUVM pUVM, DBGFOSINTERFACE enmIf)
708{
709 AssertMsgReturn(enmIf > DBGFOSINTERFACE_INVALID && enmIf < DBGFOSINTERFACE_END, ("%d\n", enmIf), NULL);
710
711 /*
712 * Pass it on to an EMT.
713 */
714 void *pvIf = NULL;
715 VMR3ReqPriorityCallVoidWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3OSQueryInterface, 3, pUVM, enmIf, &pvIf);
716 return pvIf;
717}
718
719
720
721/**
722 * Internal wrapper for calling DBGFOSREG::pfnStackUnwindAssist.
723 */
724int dbgfR3OSStackUnwindAssist(PUVM pUVM, VMCPUID idCpu, PDBGFSTACKFRAME pFrame, PRTDBGUNWINDSTATE pState,
725 PCCPUMCTX pInitialCtx, RTDBGAS hAs, uint64_t *puScratch)
726{
727 int rc = VINF_SUCCESS;
728 if (pUVM->dbgf.s.pCurOS)
729 {
730 ASMCompilerBarrier();
731 DBGF_OS_READ_LOCK(pUVM);
732 PDBGFOS pOS = pUVM->dbgf.s.pCurOS;
733 if (pOS)
734 rc = pOS->pReg->pfnStackUnwindAssist(pUVM, VMMR3GetVTable(), pUVM->dbgf.s.pCurOS->abData, idCpu, pFrame,
735 pState, pInitialCtx, hAs, puScratch);
736 DBGF_OS_READ_UNLOCK(pUVM);
737 }
738 return rc;
739}
740
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette