VirtualBox

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

Last change on this file since 7802 was 6829, checked in by vboxsync, 17 years ago

Addressed the R0/R3 issues with the PGMRAMRANGE structure.

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