VirtualBox

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

Last change on this file since 50653 was 44528, checked in by vboxsync, 11 years ago

header (C) fixes

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

© 2023 Oracle
ContactPrivacy policyTerms of Use