VirtualBox

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

Last change on this file since 88654 was 86159, checked in by vboxsync, 4 years ago

DBGF,DBGPlugInWinNt: Extract NtBuildNumber and make it available through the query versions callback

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