VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGFMem.cpp@ 97169

Last change on this file since 97169 was 96940, checked in by vboxsync, 2 years ago

VMM/PGMDbg,DBGFMem: Basic EPT dumping, both guest and shadow tables. bugref:10092

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.3 KB
Line 
1/* $Id: DBGFMem.cpp 96940 2022-09-30 00:07:38Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Memory Methods.
4 */
5
6/*
7 * Copyright (C) 2007-2022 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/pgm.h>
35#include <VBox/vmm/selm.h>
36#include <VBox/vmm/hm.h>
37#include "DBGFInternal.h"
38#include <VBox/vmm/vm.h>
39#include <VBox/vmm/uvm.h>
40#include <VBox/err.h>
41#include <VBox/log.h>
42#include <VBox/vmm/mm.h>
43
44
45
46/**
47 * Scan guest memory for an exact byte string.
48 *
49 * @returns VBox status code.
50 * @param pUVM The user mode VM handle.
51 * @param idCpu The ID of the CPU context to search in.
52 * @param pAddress Where to store the mixed address.
53 * @param puAlign The alignment restriction imposed on the search result.
54 * @param pcbRange The number of bytes to scan. Passed as a pointer because
55 * it may be 64-bit.
56 * @param pabNeedle What to search for - exact search.
57 * @param cbNeedle Size of the search byte string.
58 * @param pHitAddress Where to put the address of the first hit.
59 */
60static DECLCALLBACK(int) dbgfR3MemScan(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, PCRTGCUINTPTR pcbRange,
61 RTGCUINTPTR *puAlign, const uint8_t *pabNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress)
62{
63 PVM pVM = pUVM->pVM;
64 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
65 Assert(idCpu == VMMGetCpuId(pVM));
66
67 /*
68 * Validate the input we use, PGM does the rest.
69 */
70 RTGCUINTPTR cbRange = *pcbRange;
71 if (!DBGFR3AddrIsValid(pUVM, pAddress))
72 return VERR_INVALID_POINTER;
73 if (!RT_VALID_PTR(pHitAddress))
74 return VERR_INVALID_POINTER;
75
76 /*
77 * Select DBGF worker by addressing mode.
78 */
79 int rc;
80 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
81 PGMMODE enmMode = PGMGetGuestMode(pVCpu);
82 if ( enmMode == PGMMODE_REAL
83 || enmMode == PGMMODE_PROTECTED
84 || DBGFADDRESS_IS_PHYS(pAddress)
85 )
86 {
87 RTGCPHYS GCPhysAlign = *puAlign;
88 if (GCPhysAlign != *puAlign)
89 return VERR_OUT_OF_RANGE;
90 RTGCPHYS PhysHit;
91 rc = PGMR3DbgScanPhysical(pVM, pAddress->FlatPtr, cbRange, GCPhysAlign, pabNeedle, cbNeedle, &PhysHit);
92 if (RT_SUCCESS(rc))
93 DBGFR3AddrFromPhys(pUVM, pHitAddress, PhysHit);
94 }
95 else
96 {
97#if GC_ARCH_BITS > 32
98 if ( ( pAddress->FlatPtr >= _4G
99 || pAddress->FlatPtr + cbRange > _4G)
100 && enmMode != PGMMODE_AMD64
101 && enmMode != PGMMODE_AMD64_NX)
102 return VERR_DBGF_MEM_NOT_FOUND;
103#endif
104 RTGCUINTPTR GCPtrHit;
105 rc = PGMR3DbgScanVirtual(pVM, pVCpu, pAddress->FlatPtr, cbRange, *puAlign, pabNeedle, cbNeedle, &GCPtrHit);
106 if (RT_SUCCESS(rc))
107 DBGFR3AddrFromFlat(pUVM, pHitAddress, GCPtrHit);
108 }
109
110 return rc;
111}
112
113
114/**
115 * Scan guest memory for an exact byte string.
116 *
117 * @returns VBox status codes:
118 * @retval VINF_SUCCESS and *pGCPtrHit on success.
119 * @retval VERR_DBGF_MEM_NOT_FOUND if not found.
120 * @retval VERR_INVALID_POINTER if any of the pointer arguments are invalid.
121 * @retval VERR_INVALID_ARGUMENT if any other arguments are invalid.
122 *
123 * @param pUVM The user mode VM handle.
124 * @param idCpu The ID of the CPU context to search in.
125 * @param pAddress Where to store the mixed address.
126 * @param cbRange The number of bytes to scan.
127 * @param uAlign The alignment restriction imposed on the result.
128 * Usually set to 1.
129 * @param pvNeedle What to search for - exact search.
130 * @param cbNeedle Size of the search byte string.
131 * @param pHitAddress Where to put the address of the first hit.
132 *
133 * @thread Any thread.
134 */
135VMMR3DECL(int) DBGFR3MemScan(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, RTGCUINTPTR cbRange, RTGCUINTPTR uAlign,
136 const void *pvNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress)
137{
138 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
139 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID);
140 return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3MemScan, 8,
141 pUVM, idCpu, pAddress, &cbRange, &uAlign, pvNeedle, cbNeedle, pHitAddress);
142
143}
144
145
146/**
147 * Read guest memory.
148 *
149 * @returns VBox status code.
150 * @param pUVM The user mode VM handle.
151 * @param idCpu The ID of the CPU context to read memory from.
152 * @param pAddress Where to start reading.
153 * @param pvBuf Where to store the data we've read.
154 * @param cbRead The number of bytes to read.
155 */
156static DECLCALLBACK(int) dbgfR3MemRead(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void *pvBuf, size_t cbRead)
157{
158 PVM pVM = pUVM->pVM;
159 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
160 Assert(idCpu == VMMGetCpuId(pVM));
161
162 /*
163 * Validate the input we use, PGM does the rest.
164 */
165 if (!DBGFR3AddrIsValid(pUVM, pAddress))
166 return VERR_INVALID_POINTER;
167 if (!RT_VALID_PTR(pvBuf))
168 return VERR_INVALID_POINTER;
169
170 /*
171 * Select PGM worker by addressing mode.
172 */
173 int rc;
174 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
175 PGMMODE enmMode = PGMGetGuestMode(pVCpu);
176 if ( enmMode == PGMMODE_REAL
177 || enmMode == PGMMODE_PROTECTED
178 || DBGFADDRESS_IS_PHYS(pAddress) )
179 rc = PGMPhysSimpleReadGCPhys(pVM, pvBuf, pAddress->FlatPtr, cbRead);
180 else
181 {
182#if GC_ARCH_BITS > 32
183 if ( ( pAddress->FlatPtr >= _4G
184 || pAddress->FlatPtr + cbRead > _4G)
185 && enmMode != PGMMODE_AMD64
186 && enmMode != PGMMODE_AMD64_NX)
187 return VERR_PAGE_TABLE_NOT_PRESENT;
188#endif
189 rc = PGMPhysSimpleReadGCPtr(pVCpu, pvBuf, pAddress->FlatPtr, cbRead);
190 }
191 return rc;
192}
193
194
195/**
196 * Read guest memory.
197 *
198 * @returns VBox status code.
199 *
200 * @param pUVM The user mode VM handle.
201 * @param idCpu The ID of the source CPU context (for the address).
202 * @param pAddress Where to start reading.
203 * @param pvBuf Where to store the data we've read.
204 * @param cbRead The number of bytes to read.
205 */
206VMMR3DECL(int) DBGFR3MemRead(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void *pvBuf, size_t cbRead)
207{
208 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
209 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID);
210
211 if ((pAddress->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_RING0)
212 {
213 AssertCompile(sizeof(RTHCUINTPTR) <= sizeof(pAddress->FlatPtr));
214 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
215 return VMMR3ReadR0Stack(pUVM->pVM, idCpu, (RTHCUINTPTR)pAddress->FlatPtr, pvBuf, cbRead);
216 }
217 return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3MemRead, 5, pUVM, idCpu, pAddress, pvBuf, cbRead);
218}
219
220
221/**
222 * Read a zero terminated string from guest memory.
223 *
224 * @returns VBox status code.
225 *
226 * @param pUVM The user mode VM handle.
227 * @param idCpu The ID of the source CPU context (for the address).
228 * @param pAddress Where to start reading.
229 * @param pszBuf Where to store the string.
230 * @param cchBuf The size of the buffer.
231 */
232static DECLCALLBACK(int) dbgfR3MemReadString(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, char *pszBuf, size_t cchBuf)
233{
234 /*
235 * Validate the input we use, PGM does the rest.
236 */
237 if (!DBGFR3AddrIsValid(pUVM, pAddress))
238 return VERR_INVALID_POINTER;
239 if (!RT_VALID_PTR(pszBuf))
240 return VERR_INVALID_POINTER;
241
242 /*
243 * Let dbgfR3MemRead do the job.
244 */
245 int rc = dbgfR3MemRead(pUVM, idCpu, pAddress, pszBuf, cchBuf);
246
247 /*
248 * Make sure the result is terminated and that overflow is signaled.
249 * This may look a bit reckless with the rc but, it should be fine.
250 */
251 if (!RTStrEnd(pszBuf, cchBuf))
252 {
253 pszBuf[cchBuf - 1] = '\0';
254 rc = VINF_BUFFER_OVERFLOW;
255 }
256 /*
257 * Handle partial reads (not perfect).
258 */
259 else if (RT_FAILURE(rc))
260 {
261 if (pszBuf[0])
262 rc = VINF_SUCCESS;
263 }
264
265 return rc;
266}
267
268
269/**
270 * Read a zero terminated string from guest memory.
271 *
272 * @returns VBox status code.
273 *
274 * @param pUVM The user mode VM handle.
275 * @param idCpu The ID of the source CPU context (for the address).
276 * @param pAddress Where to start reading.
277 * @param pszBuf Where to store the string.
278 * @param cchBuf The size of the buffer.
279 */
280VMMR3DECL(int) DBGFR3MemReadString(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, char *pszBuf, size_t cchBuf)
281{
282 /*
283 * Validate and zero output.
284 */
285 if (!RT_VALID_PTR(pszBuf))
286 return VERR_INVALID_POINTER;
287 if (cchBuf <= 0)
288 return VERR_INVALID_PARAMETER;
289 memset(pszBuf, 0, cchBuf);
290 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
291 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID);
292
293 /*
294 * Pass it on to the EMT.
295 */
296 return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3MemReadString, 5, pUVM, idCpu, pAddress, pszBuf, cchBuf);
297}
298
299
300/**
301 * Writes guest memory.
302 *
303 * @returns VBox status code.
304 *
305 * @param pUVM The user mode VM handle.
306 * @param idCpu The ID of the target CPU context (for the address).
307 * @param pAddress Where to start writing.
308 * @param pvBuf The data to write.
309 * @param cbWrite The number of bytes to write.
310 */
311static DECLCALLBACK(int) dbgfR3MemWrite(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void const *pvBuf, size_t cbWrite)
312{
313 /*
314 * Validate the input we use, PGM does the rest.
315 */
316 if (!DBGFR3AddrIsValid(pUVM, pAddress))
317 return VERR_INVALID_POINTER;
318 if (!RT_VALID_PTR(pvBuf))
319 return VERR_INVALID_POINTER;
320 PVM pVM = pUVM->pVM;
321 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
322
323 /*
324 * Select PGM function by addressing mode.
325 */
326 int rc;
327 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
328 PGMMODE enmMode = PGMGetGuestMode(pVCpu);
329 if ( enmMode == PGMMODE_REAL
330 || enmMode == PGMMODE_PROTECTED
331 || DBGFADDRESS_IS_PHYS(pAddress) )
332 rc = PGMPhysSimpleWriteGCPhys(pVM, pAddress->FlatPtr, pvBuf, cbWrite);
333 else
334 {
335#if GC_ARCH_BITS > 32
336 if ( ( pAddress->FlatPtr >= _4G
337 || pAddress->FlatPtr + cbWrite > _4G)
338 && enmMode != PGMMODE_AMD64
339 && enmMode != PGMMODE_AMD64_NX)
340 return VERR_PAGE_TABLE_NOT_PRESENT;
341#endif
342 rc = PGMPhysSimpleWriteGCPtr(pVCpu, pAddress->FlatPtr, pvBuf, cbWrite);
343 }
344 return rc;
345}
346
347
348/**
349 * Read guest memory.
350 *
351 * @returns VBox status code.
352 *
353 * @param pUVM The user mode VM handle.
354 * @param idCpu The ID of the target CPU context (for the address).
355 * @param pAddress Where to start writing.
356 * @param pvBuf The data to write.
357 * @param cbWrite The number of bytes to write.
358 */
359VMMR3DECL(int) DBGFR3MemWrite(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void const *pvBuf, size_t cbWrite)
360{
361 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
362 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID);
363 return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3MemWrite, 5, pUVM, idCpu, pAddress, pvBuf, cbWrite);
364}
365
366
367/**
368 * Worker for DBGFR3SelQueryInfo that calls into SELM.
369 */
370static DECLCALLBACK(int) dbgfR3SelQueryInfo(PUVM pUVM, VMCPUID idCpu, RTSEL Sel, uint32_t fFlags, PDBGFSELINFO pSelInfo)
371{
372 PVM pVM = pUVM->pVM;
373 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
374
375 /*
376 * Make the query.
377 */
378 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
379 VMCPU_ASSERT_EMT(pVCpu);
380 int rc = SELMR3GetSelectorInfo(pVCpu, Sel, pSelInfo);
381
382 /*
383 * 64-bit mode HACKS for making data and stack selectors wide open when
384 * queried. This is voodoo magic.
385 */
386 if (fFlags & DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE)
387 {
388 /* Expand 64-bit data and stack selectors. The check is a bit bogus... */
389 if ( RT_SUCCESS(rc)
390 && (pSelInfo->fFlags & ( DBGFSELINFO_FLAGS_LONG_MODE | DBGFSELINFO_FLAGS_REAL_MODE | DBGFSELINFO_FLAGS_PROT_MODE
391 | DBGFSELINFO_FLAGS_GATE | DBGFSELINFO_FLAGS_HYPER
392 | DBGFSELINFO_FLAGS_INVALID | DBGFSELINFO_FLAGS_NOT_PRESENT))
393 == DBGFSELINFO_FLAGS_LONG_MODE
394 && pSelInfo->cbLimit != ~(RTGCPTR)0
395 && CPUMIsGuestIn64BitCode(pVCpu) )
396 {
397 pSelInfo->GCPtrBase = 0;
398 pSelInfo->cbLimit = ~(RTGCPTR)0;
399 }
400 else if ( Sel == 0
401 && CPUMIsGuestIn64BitCode(pVCpu))
402 {
403 pSelInfo->GCPtrBase = 0;
404 pSelInfo->cbLimit = ~(RTGCPTR)0;
405 pSelInfo->Sel = 0;
406 pSelInfo->SelGate = 0;
407 pSelInfo->fFlags = DBGFSELINFO_FLAGS_LONG_MODE;
408 pSelInfo->u.Raw64.Gen.u1Present = 1;
409 pSelInfo->u.Raw64.Gen.u1Long = 1;
410 pSelInfo->u.Raw64.Gen.u1DescType = 1;
411 rc = VINF_SUCCESS;
412 }
413 }
414 return rc;
415}
416
417
418/**
419 * Gets information about a selector.
420 *
421 * Intended for the debugger mostly and will prefer the guest
422 * descriptor tables over the shadow ones.
423 *
424 * @returns VBox status code, the following are the common ones.
425 * @retval VINF_SUCCESS on success.
426 * @retval VERR_INVALID_SELECTOR if the selector isn't fully inside the
427 * descriptor table.
428 * @retval VERR_SELECTOR_NOT_PRESENT if the LDT is invalid or not present. This
429 * is not returned if the selector itself isn't present, you have to
430 * check that for yourself (see DBGFSELINFO::fFlags).
431 * @retval VERR_PAGE_TABLE_NOT_PRESENT or VERR_PAGE_NOT_PRESENT if the
432 * pagetable or page backing the selector table wasn't present.
433 *
434 * @param pUVM The user mode VM handle.
435 * @param idCpu The ID of the virtual CPU context.
436 * @param Sel The selector to get info about.
437 * @param fFlags Flags, see DBGFQSEL_FLAGS_*.
438 * @param pSelInfo Where to store the information. This will always be
439 * updated.
440 *
441 * @remarks This is a wrapper around SELMR3GetSelectorInfo and
442 * SELMR3GetShadowSelectorInfo.
443 */
444VMMR3DECL(int) DBGFR3SelQueryInfo(PUVM pUVM, VMCPUID idCpu, RTSEL Sel, uint32_t fFlags, PDBGFSELINFO pSelInfo)
445{
446 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
447 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID);
448 AssertReturn(!(fFlags & ~(DBGFSELQI_FLAGS_DT_GUEST | DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE)), VERR_INVALID_PARAMETER);
449
450 /* Clear the return data here on this thread. */
451 memset(pSelInfo, 0, sizeof(*pSelInfo));
452
453 /*
454 * Dispatch the request to a worker running on the target CPU.
455 */
456 return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3SelQueryInfo, 5, pUVM, idCpu, Sel, fFlags, pSelInfo);
457}
458
459
460/**
461 * Validates a CS selector.
462 *
463 * @returns VBox status code.
464 * @param pSelInfo Pointer to the selector information for the CS selector.
465 * @param SelCPL The selector defining the CPL (SS).
466 */
467VMMDECL(int) DBGFR3SelInfoValidateCS(PCDBGFSELINFO pSelInfo, RTSEL SelCPL)
468{
469 /*
470 * Check if present.
471 */
472 if (pSelInfo->u.Raw.Gen.u1Present)
473 {
474 /*
475 * Type check.
476 */
477 if ( pSelInfo->u.Raw.Gen.u1DescType == 1
478 && (pSelInfo->u.Raw.Gen.u4Type & X86_SEL_TYPE_CODE))
479 {
480 /*
481 * Check level.
482 */
483 unsigned uLevel = RT_MAX(SelCPL & X86_SEL_RPL, pSelInfo->Sel & X86_SEL_RPL);
484 if ( !(pSelInfo->u.Raw.Gen.u4Type & X86_SEL_TYPE_CONF)
485 ? uLevel <= pSelInfo->u.Raw.Gen.u2Dpl
486 : uLevel >= pSelInfo->u.Raw.Gen.u2Dpl /* hope I got this right now... */
487 )
488 return VINF_SUCCESS;
489 return VERR_INVALID_RPL;
490 }
491 return VERR_NOT_CODE_SELECTOR;
492 }
493 return VERR_SELECTOR_NOT_PRESENT;
494}
495
496
497/**
498 * Converts a PGM paging mode to a set of DBGFPGDMP_XXX flags.
499 *
500 * @returns Flags. UINT32_MAX if the mode is invalid (asserted).
501 * @param enmMode The mode.
502 */
503static uint32_t dbgfR3PagingDumpModeToFlags(PGMMODE enmMode)
504{
505 switch (enmMode)
506 {
507 case PGMMODE_32_BIT:
508 return DBGFPGDMP_FLAGS_PSE;
509 case PGMMODE_PAE:
510 return DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE;
511 case PGMMODE_PAE_NX:
512 return DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_NXE;
513 case PGMMODE_AMD64:
514 return DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME;
515 case PGMMODE_AMD64_NX:
516 return DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME | DBGFPGDMP_FLAGS_NXE;
517 case PGMMODE_NESTED_32BIT:
518 return DBGFPGDMP_FLAGS_NP | DBGFPGDMP_FLAGS_PSE;
519 case PGMMODE_NESTED_PAE:
520 return DBGFPGDMP_FLAGS_NP | DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_NXE;
521 case PGMMODE_NESTED_AMD64:
522 return DBGFPGDMP_FLAGS_NP | DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME | DBGFPGDMP_FLAGS_NXE;
523 case PGMMODE_EPT:
524 return DBGFPGDMP_FLAGS_EPT;
525 case PGMMODE_NONE:
526 return 0;
527 default:
528 AssertFailedReturn(UINT32_MAX);
529 }
530}
531
532
533/**
534 * EMT worker for DBGFR3PagingDumpEx.
535 *
536 * @returns VBox status code.
537 * @param pUVM The shared VM handle.
538 * @param idCpu The current CPU ID.
539 * @param fFlags The flags, DBGFPGDMP_FLAGS_XXX. Valid.
540 * @param pcr3 The CR3 to use (unless we're getting the current
541 * state, see @a fFlags).
542 * @param pu64FirstAddr The first address.
543 * @param pu64LastAddr The last address.
544 * @param cMaxDepth The depth.
545 * @param pHlp The output callbacks.
546 */
547static DECLCALLBACK(int) dbgfR3PagingDumpEx(PUVM pUVM, VMCPUID idCpu, uint32_t fFlags, uint64_t *pcr3,
548 uint64_t *pu64FirstAddr, uint64_t *pu64LastAddr,
549 uint32_t cMaxDepth, PCDBGFINFOHLP pHlp)
550{
551 /*
552 * Implement dumping both context by means of recursion.
553 */
554 if ((fFlags & (DBGFPGDMP_FLAGS_GUEST | DBGFPGDMP_FLAGS_SHADOW)) == (DBGFPGDMP_FLAGS_GUEST | DBGFPGDMP_FLAGS_SHADOW))
555 {
556 int rc1 = dbgfR3PagingDumpEx(pUVM, idCpu, fFlags & ~DBGFPGDMP_FLAGS_GUEST,
557 pcr3, pu64FirstAddr, pu64LastAddr, cMaxDepth, pHlp);
558 int rc2 = dbgfR3PagingDumpEx(pUVM, idCpu, fFlags & ~DBGFPGDMP_FLAGS_SHADOW,
559 pcr3, pu64FirstAddr, pu64LastAddr, cMaxDepth, pHlp);
560 return RT_FAILURE(rc1) ? rc1 : rc2;
561 }
562
563 PVM pVM = pUVM->pVM;
564 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
565
566 /*
567 * Get the current CR3/mode if required.
568 */
569 uint64_t cr3 = *pcr3;
570 if (fFlags & (DBGFPGDMP_FLAGS_CURRENT_CR3 | DBGFPGDMP_FLAGS_CURRENT_MODE))
571 {
572 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
573 if (fFlags & DBGFPGDMP_FLAGS_SHADOW)
574 {
575 if (PGMGetShadowMode(pVCpu) == PGMMODE_NONE)
576 {
577 pHlp->pfnPrintf(pHlp, "Shadow paging mode is 'none' (NEM)\n");
578 return VINF_SUCCESS;
579 }
580
581 if (fFlags & DBGFPGDMP_FLAGS_CURRENT_CR3)
582 cr3 = PGMGetHyperCR3(pVCpu);
583 if (fFlags & DBGFPGDMP_FLAGS_CURRENT_MODE)
584 fFlags |= dbgfR3PagingDumpModeToFlags(PGMGetShadowMode(pVCpu));
585 }
586 else
587 {
588 if (fFlags & DBGFPGDMP_FLAGS_CURRENT_CR3)
589 cr3 = CPUMGetGuestCR3(pVCpu);
590 if (fFlags & DBGFPGDMP_FLAGS_CURRENT_MODE)
591 {
592 AssertCompile(DBGFPGDMP_FLAGS_PSE == X86_CR4_PSE); AssertCompile(DBGFPGDMP_FLAGS_PAE == X86_CR4_PAE);
593 fFlags |= CPUMGetGuestCR4(pVCpu) & (X86_CR4_PSE | X86_CR4_PAE);
594 AssertCompile(DBGFPGDMP_FLAGS_LME == MSR_K6_EFER_LME); AssertCompile(DBGFPGDMP_FLAGS_NXE == MSR_K6_EFER_NXE);
595 fFlags |= CPUMGetGuestEFER(pVCpu) & (MSR_K6_EFER_LME | MSR_K6_EFER_NXE);
596 }
597 }
598 }
599 fFlags &= ~(DBGFPGDMP_FLAGS_CURRENT_MODE | DBGFPGDMP_FLAGS_CURRENT_CR3);
600
601 /*
602 * Call PGM to do the real work.
603 */
604 int rc;
605 if (fFlags & DBGFPGDMP_FLAGS_SHADOW)
606 rc = PGMR3DumpHierarchyShw(pVM, cr3, fFlags, *pu64FirstAddr, *pu64LastAddr, cMaxDepth, pHlp);
607 else
608 rc = PGMR3DumpHierarchyGst(pVM, cr3, fFlags, *pu64FirstAddr, *pu64LastAddr, cMaxDepth, pHlp);
609 return rc;
610}
611
612
613/**
614 * Dump paging structures.
615 *
616 * This API can be used to dump both guest and shadow structures.
617 *
618 * @returns VBox status code.
619 * @param pUVM The user mode VM handle.
620 * @param idCpu The current CPU ID.
621 * @param fFlags The flags, DBGFPGDMP_FLAGS_XXX.
622 * @param cr3 The CR3 to use (unless we're getting the current
623 * state, see @a fFlags).
624 * @param u64FirstAddr The address to start dumping at.
625 * @param u64LastAddr The address to end dumping after.
626 * @param cMaxDepth The depth.
627 * @param pHlp The output callbacks. Defaults to the debug log if
628 * NULL.
629 */
630VMMDECL(int) DBGFR3PagingDumpEx(PUVM pUVM, VMCPUID idCpu, uint32_t fFlags, uint64_t cr3, uint64_t u64FirstAddr,
631 uint64_t u64LastAddr, uint32_t cMaxDepth, PCDBGFINFOHLP pHlp)
632{
633 /*
634 * Input validation.
635 */
636 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
637 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID);
638 AssertReturn(!(fFlags & ~DBGFPGDMP_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
639 AssertReturn(fFlags & (DBGFPGDMP_FLAGS_SHADOW | DBGFPGDMP_FLAGS_GUEST), VERR_INVALID_FLAGS);
640 AssertReturn((fFlags & DBGFPGDMP_FLAGS_CURRENT_MODE) || (fFlags & DBGFPGDMP_FLAGS_MODE_MASK), VERR_INVALID_FLAGS);
641 AssertReturn( !(fFlags & DBGFPGDMP_FLAGS_EPT)
642 || !(fFlags & (DBGFPGDMP_FLAGS_LME | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_NXE))
643 , VERR_INVALID_FLAGS);
644 AssertReturn(cMaxDepth, VERR_INVALID_PARAMETER);
645
646 /*
647 * Forward the request to the target CPU.
648 */
649 return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3PagingDumpEx, 8,
650 pUVM, idCpu, fFlags, &cr3, &u64FirstAddr, &u64LastAddr, cMaxDepth, pHlp ? pHlp : DBGFR3InfoLogHlp());
651}
652
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