VirtualBox

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

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

Doxygen, comment typos.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.4 KB
Line 
1/* $Id: DBGFMem.cpp 41783 2012-06-16 19:24:15Z 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 Pointer to the VM.
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 Pointer to the VM.
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 VM.
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 VM.
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 VM.
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 VM.
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 VM.
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 VM.
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 Pointer to the VM.
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 Pointer to the VM.
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