VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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