VirtualBox

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

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