VirtualBox

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

Last change on this file since 107818 was 107742, checked in by vboxsync, 6 weeks ago

VMM/VMMR3/DBGFOS.cpp: Fix unused assignment parfait warning, bugref:3409

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