VirtualBox

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

Last change on this file since 39405 was 38838, checked in by vboxsync, 13 years ago

VMM,++: Try fix the async reset, suspend and power-off problems in PDM wrt conflicting VMM requests. Split them into priority requests and normal requests. The priority requests can safely be processed when PDM is doing async state change waits, the normal ones cannot. (The problem I bumped into was a unmap-chunk request from PGM being processed during PDMR3Reset, causing a recursive VMMR3EmtRendezvous deadlock.)

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