VirtualBox

source: vbox/trunk/src/VBox/VMM/PGMDbg.cpp@ 13538

Last change on this file since 13538 was 13040, checked in by vboxsync, 16 years ago

#1865: More PGM changes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 17.4 KB
Line 
1/* $Id: PGMDbg.cpp 13040 2008-10-07 11:57:50Z vboxsync $ */
2/** @file
3 * PGM - Page Manager and Monitor - Debugger & Debugging APIs.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_PGM
26#include <VBox/pgm.h>
27#include <VBox/stam.h>
28#include "PGMInternal.h"
29#include <VBox/vm.h>
30#include <iprt/assert.h>
31#include <iprt/asm.h>
32#include <iprt/string.h>
33#include <VBox/log.h>
34#include <VBox/param.h>
35#include <VBox/err.h>
36
37/** The max needle size that we will bother searching for
38 * This must not be more than half a page! */
39#define MAX_NEEDLE_SIZE 256
40
41
42/**
43 * Converts a R3 pointer to a GC physical address.
44 *
45 * Only for the debugger.
46 *
47 * @returns VBox status code.
48 * @retval VINF_SUCCESS on success, *pGCPhys is set.
49 * @retval VERR_INVALID_POINTER if the pointer is not within the GC physical memory.
50 *
51 * @param pVM The VM handle.
52 * @param R3Ptr The R3 pointer to convert.
53 * @param pGCPhys Where to store the GC physical address on success.
54 */
55VMMR3DECL(int) PGMR3DbgR3Ptr2GCPhys(PVM pVM, RTR3PTR R3Ptr, PRTGCPHYS pGCPhys)
56{
57#ifdef VBOX_WITH_NEW_PHYS_CODE
58 *pGCPhys = NIL_RTGCPHYS;
59 return VERR_NOT_IMPLEMENTED;
60
61#else
62 for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
63 pRam;
64 pRam = pRam->CTX_SUFF(pNext))
65 {
66 if (pRam->fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC)
67 {
68 for (unsigned iChunk = 0; iChunk < (pRam->cb >> PGM_DYNAMIC_CHUNK_SHIFT); iChunk++)
69 {
70 if (pRam->paChunkR3Ptrs[iChunk])
71 {
72 RTR3UINTPTR off = (RTR3UINTPTR)R3Ptr - pRam->paChunkR3Ptrs[iChunk];
73 if (off < PGM_DYNAMIC_CHUNK_SIZE)
74 {
75 *pGCPhys = pRam->GCPhys + iChunk*PGM_DYNAMIC_CHUNK_SIZE + off;
76 return VINF_SUCCESS;
77 }
78 }
79 }
80 }
81 else if (pRam->pvR3)
82 {
83 RTR3UINTPTR off = (RTR3UINTPTR)R3Ptr - (RTR3UINTPTR)pRam->pvR3;
84 if (off < pRam->cb)
85 {
86 *pGCPhys = pRam->GCPhys + off;
87 return VINF_SUCCESS;
88 }
89 }
90 }
91 return VERR_INVALID_POINTER;
92#endif
93}
94
95
96/**
97 * Converts a R3 pointer to a HC physical address.
98 *
99 * Only for the debugger.
100 *
101 * @returns VBox status code.
102 * @retval VINF_SUCCESS on success, *pHCPhys is set.
103 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid GC physical page but has no physical backing.
104 * @retval VERR_INVALID_POINTER if the pointer is not within the GC physical memory.
105 *
106 * @param pVM The VM handle.
107 * @param R3Ptr The R3 pointer to convert.
108 * @param pHCPhys Where to store the HC physical address on success.
109 */
110VMMR3DECL(int) PGMR3DbgR3Ptr2HCPhys(PVM pVM, RTR3PTR R3Ptr, PRTHCPHYS pHCPhys)
111{
112#ifdef VBOX_WITH_NEW_PHYS_CODE
113 *pHCPhys = NIL_RTHCPHYS;
114 return VERR_NOT_IMPLEMENTED;
115
116#else
117 for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
118 pRam;
119 pRam = pRam->CTX_SUFF(pNext))
120 {
121 if (pRam->fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC)
122 {
123 for (unsigned iChunk = 0; iChunk < (pRam->cb >> PGM_DYNAMIC_CHUNK_SHIFT); iChunk++)
124 {
125 if (pRam->paChunkR3Ptrs[iChunk])
126 {
127 RTR3UINTPTR off = (RTR3UINTPTR)R3Ptr - pRam->paChunkR3Ptrs[iChunk];
128 if (off < PGM_DYNAMIC_CHUNK_SIZE)
129 {
130 PPGMPAGE pPage = &pRam->aPages[off >> PAGE_SHIFT];
131 if (PGM_PAGE_IS_RESERVED(pPage))
132 return VERR_PGM_PHYS_PAGE_RESERVED;
133 *pHCPhys = PGM_PAGE_GET_HCPHYS(pPage)
134 | (off & PAGE_OFFSET_MASK);
135 return VINF_SUCCESS;
136 }
137 }
138 }
139 }
140 else if (pRam->pvR3)
141 {
142 RTR3UINTPTR off = (RTR3UINTPTR)R3Ptr - (RTR3UINTPTR)pRam->pvR3;
143 if (off < pRam->cb)
144 {
145 PPGMPAGE pPage = &pRam->aPages[off >> PAGE_SHIFT];
146 if (PGM_PAGE_IS_RESERVED(pPage))
147 return VERR_PGM_PHYS_PAGE_RESERVED;
148 *pHCPhys = PGM_PAGE_GET_HCPHYS(pPage)
149 | (off & PAGE_OFFSET_MASK);
150 return VINF_SUCCESS;
151 }
152 }
153 }
154 return VERR_INVALID_POINTER;
155#endif
156}
157
158
159/**
160 * Converts a HC physical address to a GC physical address.
161 *
162 * Only for the debugger.
163 *
164 * @returns VBox status code
165 * @retval VINF_SUCCESS on success, *pGCPhys is set.
166 * @retval VERR_INVALID_POINTER if the HC physical address is not within the GC physical memory.
167 *
168 * @param pVM The VM handle.
169 * @param HCPhys The HC physical address to convert.
170 * @param pGCPhys Where to store the GC physical address on success.
171 */
172VMMR3DECL(int) PGMR3DbgHCPhys2GCPhys(PVM pVM, RTHCPHYS HCPhys, PRTGCPHYS pGCPhys)
173{
174 /*
175 * Validate and adjust the input a bit.
176 */
177 if (HCPhys == NIL_RTHCPHYS)
178 return VERR_INVALID_POINTER;
179 unsigned off = HCPhys & PAGE_OFFSET_MASK;
180 HCPhys &= X86_PTE_PAE_PG_MASK;
181 if (HCPhys == 0)
182 return VERR_INVALID_POINTER;
183
184 for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
185 pRam;
186 pRam = pRam->CTX_SUFF(pNext))
187 {
188 uint32_t iPage = pRam->cb >> PAGE_SHIFT;
189 while (iPage-- > 0)
190 if ( PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]) == HCPhys
191 && !PGM_PAGE_IS_RESERVED(&pRam->aPages[iPage]))
192 {
193 *pGCPhys = pRam->GCPhys + (iPage << PAGE_SHIFT) + off;
194 return VINF_SUCCESS;
195 }
196 }
197 return VERR_INVALID_POINTER;
198}
199
200
201/**
202 * Scans a page for a byte string, keeping track of potential
203 * cross page matches.
204 *
205 * @returns true and *poff on match.
206 * false on mismatch.
207 * @param pbPage Pointer to the current page.
208 * @param poff Input: The offset into the page.
209 * Output: The page offset of the match on success.
210 * @param cb The number of bytes to search, starting of *poff.
211 * @param pabNeedle The byte string to search for.
212 * @param cbNeedle The length of the byte string.
213 * @param pabPrev The buffer that keeps track of a partial match that we
214 * bring over from the previous page. This buffer must be
215 * at least cbNeedle - 1 big.
216 * @param pcbPrev Input: The number of partial matching bytes from the previous page.
217 * Output: The number of partial matching bytes from this page.
218 * Initialize to 0 before the first call to this function.
219 */
220static bool pgmR3DbgScanPage(const uint8_t *pbPage, int32_t *poff, uint32_t cb,
221 const uint8_t *pabNeedle, size_t cbNeedle,
222 uint8_t *pabPrev, size_t *pcbPrev)
223{
224 /*
225 * Try complete any partial match from the previous page.
226 */
227 if (*pcbPrev > 0)
228 {
229 size_t cbPrev = *pcbPrev;
230 Assert(!*poff);
231 Assert(cbPrev < cbNeedle);
232 if (!memcmp(pbPage, pabNeedle + cbPrev, cbNeedle - cbPrev))
233 {
234 if (cbNeedle - cbPrev > cb)
235 return false;
236 *poff = -(int32_t)cbPrev;
237 return true;
238 }
239
240 /* check out the remainder of the previous page. */
241 const uint8_t *pb = pabPrev;
242 while (cbPrev-- > 0)
243 {
244 pb = (const uint8_t *)memchr(pb + 1, *pabNeedle, cbPrev);
245 if (!pb)
246 break;
247 cbPrev = *pcbPrev - (pb - pabPrev);
248 if ( !memcmp(pb + 1, &pabNeedle[1], cbPrev - 1)
249 && !memcmp(pbPage, pabNeedle + cbPrev, cbNeedle - cbPrev))
250 {
251 if (cbNeedle - cbPrev > cb)
252 return false;
253 *poff = -(int32_t)cbPrev;
254 return true;
255 }
256 }
257
258 *pcbPrev = 0;
259 }
260
261 /*
262 * Match the body of the page.
263 */
264 const uint8_t *pb = pbPage + *poff;
265 const uint8_t *pbEnd = pb + cb;
266 for (;;)
267 {
268 pb = (const uint8_t *)memchr(pb, *pabNeedle, cb);
269 if (!pb)
270 break;
271 cb = pbEnd - pb;
272 if (cb >= cbNeedle)
273 {
274 /* match? */
275 if (!memcmp(pb + 1, &pabNeedle[1], cbNeedle - 1))
276 {
277 *poff = pb - pbPage;
278 return true;
279 }
280 }
281 else
282 {
283 /* paritial match at the end of the page? */
284 if (!memcmp(pb + 1, &pabNeedle[1], cb - 1))
285 {
286 /* We're copying one byte more that we really need here, but wtf. */
287 memcpy(pabPrev, pb, cb);
288 *pcbPrev = cb;
289 return false;
290 }
291 }
292
293 /* no match, skip a byte ahead. */
294 if (cb <= 1)
295 break;
296 pb++;
297 cb--;
298 }
299
300 return false;
301}
302
303
304/**
305 * Scans guest physical memory for a byte string.
306 *
307 * @returns VBox status codes:
308 * @retval VINF_SUCCESS and *pGCPtrHit on success.
309 * @retval VERR_DBGF_MEM_NOT_FOUND if not found.
310 * @retval VERR_INVALID_POINTER if any of the pointer arguments are invalid.
311 * @retval VERR_INVALID_ARGUMENT if any other arguments are invalid.
312 *
313 * @param pVM Pointer to the shared VM structure.
314 * @param GCPhys Where to start searching.
315 * @param cbRange The number of bytes to search.
316 * @param pabNeedle The byte string to search for.
317 * @param cbNeedle The length of the byte string. Max 256 bytes.
318 * @param pGCPhysHit Where to store the address of the first occurence on success.
319 */
320VMMR3DECL(int) PGMR3DbgScanPhysical(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cbRange, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCPHYS pGCPhysHit)
321{
322 /*
323 * Validate and adjust the input a bit.
324 */
325 if (!VALID_PTR(pGCPhysHit))
326 return VERR_INVALID_POINTER;
327 *pGCPhysHit = NIL_RTGCPHYS;
328
329 if ( !VALID_PTR(pabNeedle)
330 || GCPhys == NIL_RTGCPHYS)
331 return VERR_INVALID_POINTER;
332 if (!cbNeedle)
333 return VERR_INVALID_PARAMETER;
334 if (cbNeedle > MAX_NEEDLE_SIZE)
335 return VERR_INVALID_PARAMETER;
336
337 if (!cbRange)
338 return VERR_DBGF_MEM_NOT_FOUND;
339 if (GCPhys + cbNeedle - 1 < GCPhys)
340 return VERR_DBGF_MEM_NOT_FOUND;
341
342 const RTGCPHYS GCPhysLast = GCPhys + cbRange - 1 >= GCPhys
343 ? GCPhys + cbRange - 1
344 : ~(RTGCPHYS)0;
345
346 /*
347 * Search the memory - ignore MMIO and zero pages, also don't
348 * bother to match across ranges.
349 */
350 for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
351 pRam;
352 pRam = pRam->CTX_SUFF(pNext))
353 {
354 /*
355 * If the search range starts prior to the current ram range record,
356 * adjust the search range and possibly conclude the search.
357 */
358 RTGCPHYS off;
359 if (GCPhys < pRam->GCPhys)
360 {
361 if (GCPhysLast < pRam->GCPhys)
362 break;
363 GCPhys = pRam->GCPhys;
364 off = 0;
365 }
366 else
367 off = GCPhys - pRam->GCPhys;
368 if (off < pRam->cb)
369 {
370 /*
371 * Iterate the relevant pages.
372 */
373 uint8_t abPrev[MAX_NEEDLE_SIZE];
374 size_t cbPrev = 0;
375 const uint32_t cPages = pRam->cb >> PAGE_SHIFT;
376 for (uint32_t iPage = off >> PAGE_SHIFT; iPage < cPages; iPage++)
377 {
378 PPGMPAGE pPage = &pRam->aPages[iPage];
379 if ( /** @todo !PGM_PAGE_IS_ZERO(pPage)
380 &&*/ !PGM_PAGE_IS_MMIO(pPage))
381 {
382 void const *pvPage;
383 PGMPAGEMAPLOCK Lock;
384 int rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK, &pvPage, &Lock);
385 if (RT_SUCCESS(rc))
386 {
387 int32_t offPage = (GCPhys & PAGE_OFFSET_MASK);
388 uint32_t cbSearch = (GCPhys ^ GCPhysLast) & ~(RTGCPHYS)PAGE_OFFSET_MASK
389 ? PAGE_SIZE - (uint32_t)offPage
390 : (GCPhysLast & PAGE_OFFSET_MASK) + 1 - (uint32_t)offPage;
391 bool fRc = pgmR3DbgScanPage((uint8_t const *)pvPage, &offPage, cbSearch,
392 pabNeedle, cbNeedle, &abPrev[0], &cbPrev);
393 PGMPhysReleasePageMappingLock(pVM, &Lock);
394 if (fRc)
395 {
396 *pGCPhysHit = (GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK) + offPage;
397 return VINF_SUCCESS;
398 }
399 }
400 else
401 cbPrev = 0; /* ignore error. */
402 }
403 else
404 cbPrev = 0;
405
406 /* advance to the the next page. */
407 GCPhys |= PAGE_OFFSET_MASK;
408 if (GCPhys++ >= GCPhysLast)
409 return VERR_DBGF_MEM_NOT_FOUND;
410 }
411 }
412 }
413 return VERR_DBGF_MEM_NOT_FOUND;
414}
415
416
417/**
418 * Scans (guest) virtual memory for a byte string.
419 *
420 * @returns VBox status codes:
421 * @retval VINF_SUCCESS and *pGCPtrHit on success.
422 * @retval VERR_DBGF_MEM_NOT_FOUND if not found.
423 * @retval VERR_INVALID_POINTER if any of the pointer arguments are invalid.
424 * @retval VERR_INVALID_ARGUMENT if any other arguments are invalid.
425 *
426 * @param pVM Pointer to the shared VM structure.
427 * @param GCPtr Where to start searching.
428 * @param cbRange The number of bytes to search. Max 256 bytes.
429 * @param pabNeedle The byte string to search for.
430 * @param cbNeedle The length of the byte string.
431 * @param pGCPtrHit Where to store the address of the first occurence on success.
432 */
433VMMR3DECL(int) PGMR3DbgScanVirtual(PVM pVM, RTGCUINTPTR GCPtr, RTGCUINTPTR cbRange, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCUINTPTR pGCPtrHit)
434{
435 /*
436 * Validate and adjust the input a bit.
437 */
438 if (!VALID_PTR(pGCPtrHit))
439 return VERR_INVALID_POINTER;
440 *pGCPtrHit = 0;
441
442 if (!VALID_PTR(pabNeedle))
443 return VERR_INVALID_POINTER;
444 if (!cbNeedle)
445 return VERR_INVALID_PARAMETER;
446 if (cbNeedle > MAX_NEEDLE_SIZE)
447 return VERR_INVALID_PARAMETER;
448
449 if (!cbRange)
450 return VERR_DBGF_MEM_NOT_FOUND;
451 if (GCPtr + cbNeedle - 1 < GCPtr)
452 return VERR_DBGF_MEM_NOT_FOUND;
453
454 /*
455 * Search the memory - ignore MMIO, zero and not-present pages.
456 */
457 uint8_t abPrev[MAX_NEEDLE_SIZE];
458 size_t cbPrev = 0;
459 const RTGCUINTPTR GCPtrLast = GCPtr + cbRange - 1 >= GCPtr
460 ? GCPtr + cbRange - 1
461 : ~(RTGCUINTPTR)0;
462 RTGCUINTPTR cPages = (((GCPtrLast - GCPtr) + (GCPtr & PAGE_OFFSET_MASK)) >> PAGE_SHIFT) + 1;
463 while (cPages-- > 0)
464 {
465 RTGCPHYS GCPhys;
466 int rc = PGMPhysGCPtr2GCPhys(pVM, GCPtr, &GCPhys);
467 if (RT_SUCCESS(rc))
468 {
469 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);
470 if ( pPage
471///@todo && !PGM_PAGE_IS_ZERO(pPage)
472 && !PGM_PAGE_IS_MMIO(pPage))
473 {
474 void const *pvPage;
475 PGMPAGEMAPLOCK Lock;
476 rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys & ~(RTGCUINTPTR)PAGE_OFFSET_MASK, &pvPage, &Lock);
477 if (RT_SUCCESS(rc))
478 {
479 int32_t offPage = (GCPtr & PAGE_OFFSET_MASK);
480 uint32_t cbSearch = cPages > 0
481 ? PAGE_SIZE - (uint32_t)offPage
482 : (GCPtrLast & PAGE_OFFSET_MASK) + 1 - (uint32_t)offPage;
483 bool fRc = pgmR3DbgScanPage((uint8_t const *)pvPage, &offPage, cbSearch,
484 pabNeedle, cbNeedle, &abPrev[0], &cbPrev);
485 PGMPhysReleasePageMappingLock(pVM, &Lock);
486 if (fRc)
487 {
488 *pGCPtrHit = (GCPtr & ~(RTGCUINTPTR)PAGE_OFFSET_MASK) + offPage;
489 return VINF_SUCCESS;
490 }
491 }
492 else
493 cbPrev = 0; /* ignore error. */
494 }
495 else
496 cbPrev = 0;
497 }
498 else
499 cbPrev = 0; /* ignore error. */
500
501 /* advance to the the next page. */
502 GCPtr |= PAGE_OFFSET_MASK;
503 GCPtr++;
504 }
505 return VERR_DBGF_MEM_NOT_FOUND;
506}
507
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use