VirtualBox

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

Last change on this file since 10700 was 8155, checked in by vboxsync, 17 years ago

The Big Sun Rebranding Header Change

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