VirtualBox

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

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

VMM/DBGFOS: Add preliminary WinNT specific interface to let the KD remote stub communicate with the OS digger plugin

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 24.5 KB
Line 
1/* $Id: DBGFOS.cpp 86102 2020-09-13 08:26:02Z 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{
542 PDBGFOSEMTWRAPPER pWrapper = RT_FROM_MEMBER(pThis, DBGFOSEMTWRAPPER, uWrapper.WinNt);
543 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
544 AssertReturn(pUVM == pWrapper->pUVM, VERR_INVALID_VM_HANDLE);
545
546 return VMR3ReqPriorityCallWaitU(pWrapper->pUVM, 0 /*idDstCpu*/,
547 (PFNRT)pWrapper->uDigger.pWinNt->pfnQueryVersion, 4,
548 pWrapper->uDigger.pWinNt, pUVM, puVersMajor, puVersMinor);
549}
550
551
552/**
553 * @interface_method_impl{DBGFOSIWINNT,pfnQueryVersion, Generic EMT wrapper.}
554 */
555static DECLCALLBACK(int) dbgfR3OSEmtIWinNt_QueryKernelPtrs(PDBGFOSIWINNT pThis, PUVM pUVM,
556 PRTGCUINTPTR pGCPtrKernBase, PRTGCUINTPTR pGCPtrPsLoadedModuleList)
557{
558 PDBGFOSEMTWRAPPER pWrapper = RT_FROM_MEMBER(pThis, DBGFOSEMTWRAPPER, uWrapper.WinNt);
559 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
560 AssertReturn(pUVM == pWrapper->pUVM, VERR_INVALID_VM_HANDLE);
561
562 return VMR3ReqPriorityCallWaitU(pWrapper->pUVM, 0 /*idDstCpu*/,
563 (PFNRT)pWrapper->uDigger.pWinNt->pfnQueryKernelPtrs, 4,
564 pWrapper->uDigger.pWinNt, pUVM, pGCPtrKernBase, pGCPtrPsLoadedModuleList);
565}
566
567
568/**
569 * @interface_method_impl{DBGFOSIWINNT,pfnQueryKpcrForVCpu, Generic EMT wrapper.}
570 */
571static DECLCALLBACK(int) dbgfR3OSEmtIWinNt_QueryKpcrForVCpu(struct DBGFOSIWINNT *pThis, PUVM pUVM, VMCPUID idCpu,
572 PRTGCUINTPTR pKpcr, PRTGCUINTPTR pKpcrb)
573{
574 PDBGFOSEMTWRAPPER pWrapper = RT_FROM_MEMBER(pThis, DBGFOSEMTWRAPPER, uWrapper.WinNt);
575 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
576 AssertReturn(pUVM == pWrapper->pUVM, VERR_INVALID_VM_HANDLE);
577
578 return VMR3ReqPriorityCallWaitU(pWrapper->pUVM, 0 /*idDstCpu*/,
579 (PFNRT)pWrapper->uDigger.pWinNt->pfnQueryKpcrForVCpu, 5,
580 pWrapper->uDigger.pWinNt, pUVM, idCpu, pKpcr, pKpcrb);
581}
582
583
584/**
585 * @interface_method_impl{DBGFOSIWINNT,pfnQueryCurThrdForVCpu, Generic EMT wrapper.}
586 */
587static DECLCALLBACK(int) dbgfR3OSEmtIWinNt_QueryCurThrdForVCpu(struct DBGFOSIWINNT *pThis, PUVM pUVM, VMCPUID idCpu,
588 PRTGCUINTPTR pCurThrd)
589{
590 PDBGFOSEMTWRAPPER pWrapper = RT_FROM_MEMBER(pThis, DBGFOSEMTWRAPPER, uWrapper.WinNt);
591 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
592 AssertReturn(pUVM == pWrapper->pUVM, VERR_INVALID_VM_HANDLE);
593
594 return VMR3ReqPriorityCallWaitU(pWrapper->pUVM, 0 /*idDstCpu*/,
595 (PFNRT)pWrapper->uDigger.pWinNt->pfnQueryCurThrdForVCpu, 4,
596 pWrapper->uDigger.pWinNt, pUVM, idCpu, pCurThrd);
597}
598
599
600/**
601 * EMT worker for DBGFR3OSQueryInterface.
602 *
603 * @param pUVM The user mode VM handle.
604 * @param enmIf The interface identifier.
605 * @param ppvIf Where to store the interface pointer on success.
606 */
607static DECLCALLBACK(void) dbgfR3OSQueryInterface(PUVM pUVM, DBGFOSINTERFACE enmIf, void **ppvIf)
608{
609 AssertPtrReturnVoid(ppvIf);
610 *ppvIf = NULL;
611 AssertReturnVoid(enmIf > DBGFOSINTERFACE_INVALID && enmIf < DBGFOSINTERFACE_END);
612 UVM_ASSERT_VALID_EXT_RETURN_VOID(pUVM);
613
614 /*
615 * Forward the query to the current OS.
616 */
617 DBGF_OS_READ_LOCK(pUVM);
618 PDBGFOS pOS = pUVM->dbgf.s.pCurOS;
619 if (pOS)
620 {
621 void *pvDiggerIf;
622 pvDiggerIf = pOS->pReg->pfnQueryInterface(pUVM, pUVM->dbgf.s.pCurOS->abData, enmIf);
623 if (pvDiggerIf)
624 {
625 /*
626 * Do we have an EMT wrapper for this interface already?
627 *
628 * We ASSUME the interfaces are static and not dynamically allocated
629 * for each QueryInterface call.
630 */
631 PDBGFOSEMTWRAPPER pWrapper = pOS->pWrapperHead;
632 while ( pWrapper != NULL
633 && ( pWrapper->uDigger.pv != pvDiggerIf
634 && pWrapper->enmIf != enmIf) )
635 pWrapper = pWrapper->pNext;
636 if (pWrapper)
637 {
638 *ppvIf = &pWrapper->uWrapper;
639 DBGF_OS_READ_UNLOCK(pUVM);
640 return;
641 }
642 DBGF_OS_READ_UNLOCK(pUVM);
643
644 /*
645 * Create a wrapper.
646 */
647 int rc = MMR3HeapAllocExU(pUVM, MM_TAG_DBGF_OS, sizeof(*pWrapper), (void **)&pWrapper);
648 if (RT_FAILURE(rc))
649 return;
650 pWrapper->uDigger.pv = pvDiggerIf;
651 pWrapper->pUVM = pUVM;
652 pWrapper->enmIf = enmIf;
653 switch (enmIf)
654 {
655 case DBGFOSINTERFACE_DMESG:
656 pWrapper->uWrapper.Dmesg.u32Magic = DBGFOSIDMESG_MAGIC;
657 pWrapper->uWrapper.Dmesg.pfnQueryKernelLog = dbgfR3OSEmtIDmesg_QueryKernelLog;
658 pWrapper->uWrapper.Dmesg.u32EndMagic = DBGFOSIDMESG_MAGIC;
659 break;
660 case DBGFOSINTERFACE_WINNT:
661 pWrapper->uWrapper.WinNt.u32Magic = DBGFOSIWINNT_MAGIC;
662 pWrapper->uWrapper.WinNt.pfnQueryVersion = dbgfR3OSEmtIWinNt_QueryVersion;
663 pWrapper->uWrapper.WinNt.pfnQueryKernelPtrs = dbgfR3OSEmtIWinNt_QueryKernelPtrs;
664 pWrapper->uWrapper.WinNt.pfnQueryKpcrForVCpu = dbgfR3OSEmtIWinNt_QueryKpcrForVCpu;
665 pWrapper->uWrapper.WinNt.pfnQueryCurThrdForVCpu = dbgfR3OSEmtIWinNt_QueryCurThrdForVCpu;
666 pWrapper->uWrapper.WinNt.u32EndMagic = DBGFOSIWINNT_MAGIC;
667 break;
668 default:
669 AssertFailed();
670 MMR3HeapFree(pWrapper);
671 return;
672 }
673
674 DBGF_OS_WRITE_LOCK(pUVM);
675 if (pUVM->dbgf.s.pCurOS == pOS)
676 {
677 pWrapper->pNext = pOS->pWrapperHead;
678 pOS->pWrapperHead = pWrapper;
679 *ppvIf = &pWrapper->uWrapper;
680 DBGF_OS_WRITE_UNLOCK(pUVM);
681 }
682 else
683 {
684 DBGF_OS_WRITE_UNLOCK(pUVM);
685 MMR3HeapFree(pWrapper);
686 }
687 return;
688 }
689 }
690 DBGF_OS_READ_UNLOCK(pUVM);
691}
692
693
694/**
695 * Query an optional digger interface.
696 *
697 * @returns Pointer to the digger interface on success, NULL if the interfaces isn't
698 * available or no active guest OS digger.
699 * @param pUVM The user mode VM handle.
700 * @param enmIf The interface identifier.
701 * @thread Any.
702 */
703VMMR3DECL(void *) DBGFR3OSQueryInterface(PUVM pUVM, DBGFOSINTERFACE enmIf)
704{
705 AssertMsgReturn(enmIf > DBGFOSINTERFACE_INVALID && enmIf < DBGFOSINTERFACE_END, ("%d\n", enmIf), NULL);
706
707 /*
708 * Pass it on to an EMT.
709 */
710 void *pvIf = NULL;
711 VMR3ReqPriorityCallVoidWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3OSQueryInterface, 3, pUVM, enmIf, &pvIf);
712 return pvIf;
713}
714
715
716
717/**
718 * Internal wrapper for calling DBGFOSREG::pfnStackUnwindAssist.
719 */
720int dbgfR3OSStackUnwindAssist(PUVM pUVM, VMCPUID idCpu, PDBGFSTACKFRAME pFrame, PRTDBGUNWINDSTATE pState,
721 PCCPUMCTX pInitialCtx, RTDBGAS hAs, uint64_t *puScratch)
722{
723 int rc = VINF_SUCCESS;
724 if (pUVM->dbgf.s.pCurOS)
725 {
726 ASMCompilerBarrier();
727 DBGF_OS_READ_LOCK(pUVM);
728 PDBGFOS pOS = pUVM->dbgf.s.pCurOS;
729 if (pOS)
730 rc = pOS->pReg->pfnStackUnwindAssist(pUVM, pUVM->dbgf.s.pCurOS->abData, idCpu, pFrame,
731 pState, pInitialCtx, hAs, puScratch);
732 DBGF_OS_READ_UNLOCK(pUVM);
733 }
734 return rc;
735}
736
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