VirtualBox

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

Last change on this file since 16827 was 14966, checked in by vboxsync, 16 years ago

PDM, DBGC: debugger read and write APIs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 23.3 KB
Line 
1/* $Id: PGMDbg.cpp 14966 2008-12-04 01:54:38Z 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 * Read physical memory API for the debugger, similar to
203 * PGMPhysSimpleReadGCPhys.
204 *
205 * @returns VBox status code.
206 *
207 * @param pVM The VM handle.
208 * @param pvDst Where to store what's read.
209 * @param GCPhysDst Where to start reading from.
210 * @param cb The number of bytes to attempt reading.
211 * @param fFlags Flags, MBZ.
212 * @param pcbRead For store the actual number of bytes read, pass NULL if
213 * partial reads are unwanted.
214 */
215VMMR3DECL(int) PGMR3DbgReadGCPhys(PVM pVM, void *pvDst, RTGCPHYS GCPhysSrc, size_t cb, uint32_t fFlags, size_t *pcbRead)
216{
217 /* validate */
218 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
219 AssertReturn(pVM, VERR_INVALID_PARAMETER);
220
221 /* try simple first. */
222 int rc = PGMPhysSimpleReadGCPhys(pVM, pvDst, GCPhysSrc, cb);
223 if (RT_SUCCESS(rc) || !pcbRead)
224 return rc;
225
226 /* partial read that failed, chop it up in pages. */
227 *pcbRead = 0;
228 size_t const cbReq = cb;
229 rc = VINF_SUCCESS;
230 while (cb > 0)
231 {
232 size_t cbChunk = PAGE_SIZE;
233 cbChunk -= GCPhysSrc & PAGE_OFFSET_MASK;
234 if (cbChunk > cb)
235 cbChunk = cb;
236
237 rc = PGMPhysSimpleReadGCPhys(pVM, pvDst, GCPhysSrc, cbChunk);
238
239 /* advance */
240 if (RT_FAILURE(rc))
241 break;
242 *pcbRead += cbChunk;
243 cb -= cbChunk;
244 GCPhysSrc += cbChunk;
245 pvDst = (uint8_t *)pvDst + cbChunk;
246 }
247
248 return *pcbRead && RT_FAILURE(rc) ? -rc : rc;
249}
250
251
252/**
253 * Write physical memory API for the debugger, similar to
254 * PGMPhysSimpleWriteGCPhys.
255 *
256 * @returns VBox status code.
257 *
258 * @param pVM The VM handle.
259 * @param GCPhysDst Where to start writing.
260 * @param pvSrc What to write.
261 * @param cb The number of bytes to attempt writing.
262 * @param fFlags Flags, MBZ.
263 * @param pcbWritten For store the actual number of bytes written, pass NULL
264 * if partial writes are unwanted.
265 */
266VMMR3DECL(int) PGMR3DbgWriteGCPhys(PVM pVM, RTGCPHYS GCPhysDst, const void *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten)
267{
268 /* validate */
269 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
270 AssertReturn(pVM, VERR_INVALID_PARAMETER);
271
272 /* try simple first. */
273 int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysDst, pvSrc, cb);
274 if (RT_SUCCESS(rc) || !pcbWritten)
275 return rc;
276
277 /* partial write that failed, chop it up in pages. */
278 *pcbWritten = 0;
279 rc = VINF_SUCCESS;
280 while (cb > 0)
281 {
282 size_t cbChunk = PAGE_SIZE;
283 cbChunk -= GCPhysDst & PAGE_OFFSET_MASK;
284 if (cbChunk > cb)
285 cbChunk = cb;
286
287 rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysDst, pvSrc, cbChunk);
288
289 /* advance */
290 if (RT_FAILURE(rc))
291 break;
292 *pcbWritten += cbChunk;
293 cb -= cbChunk;
294 GCPhysDst += cbChunk;
295 pvSrc = (uint8_t const *)pvSrc + cbChunk;
296 }
297
298 return *pcbWritten && RT_FAILURE(rc) ? -rc : rc;
299
300}
301
302
303/**
304 * Read virtual memory API for the debugger, similar to PGMPhysSimpleReadGCPtr.
305 *
306 * @returns VBox status code.
307 *
308 * @param pVM The VM handle.
309 * @param pvDst Where to store what's read.
310 * @param GCPtrDst Where to start reading from.
311 * @param cb The number of bytes to attempt reading.
312 * @param fFlags Flags, MBZ.
313 * @param pcbRead For store the actual number of bytes read, pass NULL if
314 * partial reads are unwanted.
315 */
316VMMR3DECL(int) PGMR3DbgReadGCPtr(PVM pVM, void *pvDst, RTGCPTR GCPtrSrc, size_t cb, uint32_t fFlags, size_t *pcbRead)
317{
318 /* validate */
319 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
320 AssertReturn(pVM, VERR_INVALID_PARAMETER);
321
322/** @todo deal with HMA */
323 /* try simple first. */
324 int rc = PGMPhysSimpleReadGCPtr(pVM, pvDst, GCPtrSrc, cb);
325 if (RT_SUCCESS(rc) || !pcbRead)
326 return rc;
327
328 /* partial read that failed, chop it up in pages. */
329 *pcbRead = 0;
330 rc = VINF_SUCCESS;
331 while (cb > 0)
332 {
333 size_t cbChunk = PAGE_SIZE;
334 cbChunk -= GCPtrSrc & PAGE_OFFSET_MASK;
335 if (cbChunk > cb)
336 cbChunk = cb;
337
338 rc = PGMPhysSimpleReadGCPtr(pVM, pvDst, GCPtrSrc, cbChunk);
339
340 /* advance */
341 if (RT_FAILURE(rc))
342 break;
343 *pcbRead += cbChunk;
344 cb -= cbChunk;
345 GCPtrSrc += cbChunk;
346 pvDst = (uint8_t *)pvDst + cbChunk;
347 }
348
349 return *pcbRead && RT_FAILURE(rc) ? -rc : rc;
350
351}
352
353
354/**
355 * Write virtual memory API for the debugger, similar to
356 * PGMPhysSimpleWriteGCPtr.
357 *
358 * @returns VBox status code.
359 *
360 * @param pVM The VM handle.
361 * @param GCPtrDst Where to start writing.
362 * @param pvSrc What to write.
363 * @param cb The number of bytes to attempt writing.
364 * @param fFlags Flags, MBZ.
365 * @param pcbWritten For store the actual number of bytes written, pass NULL
366 * if partial writes are unwanted.
367 */
368VMMR3DECL(int) PGMR3DbgWriteGCPtr(PVM pVM, RTGCPTR GCPtrDst, void const *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten)
369{
370 /* validate */
371 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
372 AssertReturn(pVM, VERR_INVALID_PARAMETER);
373
374/** @todo deal with HMA */
375 /* try simple first. */
376 int rc = PGMPhysSimpleWriteGCPtr(pVM, GCPtrDst, pvSrc, cb);
377 if (RT_SUCCESS(rc) || !pcbWritten)
378 return rc;
379
380 /* partial write that failed, chop it up in pages. */
381 *pcbWritten = 0;
382 rc = VINF_SUCCESS;
383 while (cb > 0)
384 {
385 size_t cbChunk = PAGE_SIZE;
386 cbChunk -= GCPtrDst & PAGE_OFFSET_MASK;
387 if (cbChunk > cb)
388 cbChunk = cb;
389
390 rc = PGMPhysSimpleWriteGCPtr(pVM, GCPtrDst, pvSrc, cbChunk);
391
392 /* advance */
393 if (RT_FAILURE(rc))
394 break;
395 *pcbWritten += cbChunk;
396 cb -= cbChunk;
397 GCPtrDst += cbChunk;
398 pvSrc = (uint8_t const *)pvSrc + cbChunk;
399 }
400
401 return *pcbWritten && RT_FAILURE(rc) ? -rc : rc;
402
403}
404
405
406
407/**
408 * Scans a page for a byte string, keeping track of potential
409 * cross page matches.
410 *
411 * @returns true and *poff on match.
412 * false on mismatch.
413 * @param pbPage Pointer to the current page.
414 * @param poff Input: The offset into the page.
415 * Output: The page offset of the match on success.
416 * @param cb The number of bytes to search, starting of *poff.
417 * @param pabNeedle The byte string to search for.
418 * @param cbNeedle The length of the byte string.
419 * @param pabPrev The buffer that keeps track of a partial match that we
420 * bring over from the previous page. This buffer must be
421 * at least cbNeedle - 1 big.
422 * @param pcbPrev Input: The number of partial matching bytes from the previous page.
423 * Output: The number of partial matching bytes from this page.
424 * Initialize to 0 before the first call to this function.
425 */
426static bool pgmR3DbgScanPage(const uint8_t *pbPage, int32_t *poff, uint32_t cb,
427 const uint8_t *pabNeedle, size_t cbNeedle,
428 uint8_t *pabPrev, size_t *pcbPrev)
429{
430 /*
431 * Try complete any partial match from the previous page.
432 */
433 if (*pcbPrev > 0)
434 {
435 size_t cbPrev = *pcbPrev;
436 Assert(!*poff);
437 Assert(cbPrev < cbNeedle);
438 if (!memcmp(pbPage, pabNeedle + cbPrev, cbNeedle - cbPrev))
439 {
440 if (cbNeedle - cbPrev > cb)
441 return false;
442 *poff = -(int32_t)cbPrev;
443 return true;
444 }
445
446 /* check out the remainder of the previous page. */
447 const uint8_t *pb = pabPrev;
448 while (cbPrev-- > 0)
449 {
450 pb = (const uint8_t *)memchr(pb + 1, *pabNeedle, cbPrev);
451 if (!pb)
452 break;
453 cbPrev = *pcbPrev - (pb - pabPrev);
454 if ( !memcmp(pb + 1, &pabNeedle[1], cbPrev - 1)
455 && !memcmp(pbPage, pabNeedle + cbPrev, cbNeedle - cbPrev))
456 {
457 if (cbNeedle - cbPrev > cb)
458 return false;
459 *poff = -(int32_t)cbPrev;
460 return true;
461 }
462 }
463
464 *pcbPrev = 0;
465 }
466
467 /*
468 * Match the body of the page.
469 */
470 const uint8_t *pb = pbPage + *poff;
471 const uint8_t *pbEnd = pb + cb;
472 for (;;)
473 {
474 pb = (const uint8_t *)memchr(pb, *pabNeedle, cb);
475 if (!pb)
476 break;
477 cb = pbEnd - pb;
478 if (cb >= cbNeedle)
479 {
480 /* match? */
481 if (!memcmp(pb + 1, &pabNeedle[1], cbNeedle - 1))
482 {
483 *poff = pb - pbPage;
484 return true;
485 }
486 }
487 else
488 {
489 /* paritial match at the end of the page? */
490 if (!memcmp(pb + 1, &pabNeedle[1], cb - 1))
491 {
492 /* We're copying one byte more that we really need here, but wtf. */
493 memcpy(pabPrev, pb, cb);
494 *pcbPrev = cb;
495 return false;
496 }
497 }
498
499 /* no match, skip a byte ahead. */
500 if (cb <= 1)
501 break;
502 pb++;
503 cb--;
504 }
505
506 return false;
507}
508
509
510/**
511 * Scans guest physical memory for a byte string.
512 *
513 * @returns VBox status codes:
514 * @retval VINF_SUCCESS and *pGCPtrHit on success.
515 * @retval VERR_DBGF_MEM_NOT_FOUND if not found.
516 * @retval VERR_INVALID_POINTER if any of the pointer arguments are invalid.
517 * @retval VERR_INVALID_ARGUMENT if any other arguments are invalid.
518 *
519 * @param pVM Pointer to the shared VM structure.
520 * @param GCPhys Where to start searching.
521 * @param cbRange The number of bytes to search.
522 * @param pabNeedle The byte string to search for.
523 * @param cbNeedle The length of the byte string. Max 256 bytes.
524 * @param pGCPhysHit Where to store the address of the first occurence on success.
525 */
526VMMR3DECL(int) PGMR3DbgScanPhysical(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cbRange, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCPHYS pGCPhysHit)
527{
528 /*
529 * Validate and adjust the input a bit.
530 */
531 if (!VALID_PTR(pGCPhysHit))
532 return VERR_INVALID_POINTER;
533 *pGCPhysHit = NIL_RTGCPHYS;
534
535 if ( !VALID_PTR(pabNeedle)
536 || GCPhys == NIL_RTGCPHYS)
537 return VERR_INVALID_POINTER;
538 if (!cbNeedle)
539 return VERR_INVALID_PARAMETER;
540 if (cbNeedle > MAX_NEEDLE_SIZE)
541 return VERR_INVALID_PARAMETER;
542
543 if (!cbRange)
544 return VERR_DBGF_MEM_NOT_FOUND;
545 if (GCPhys + cbNeedle - 1 < GCPhys)
546 return VERR_DBGF_MEM_NOT_FOUND;
547
548 const RTGCPHYS GCPhysLast = GCPhys + cbRange - 1 >= GCPhys
549 ? GCPhys + cbRange - 1
550 : ~(RTGCPHYS)0;
551
552 /*
553 * Search the memory - ignore MMIO and zero pages, also don't
554 * bother to match across ranges.
555 */
556 for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
557 pRam;
558 pRam = pRam->CTX_SUFF(pNext))
559 {
560 /*
561 * If the search range starts prior to the current ram range record,
562 * adjust the search range and possibly conclude the search.
563 */
564 RTGCPHYS off;
565 if (GCPhys < pRam->GCPhys)
566 {
567 if (GCPhysLast < pRam->GCPhys)
568 break;
569 GCPhys = pRam->GCPhys;
570 off = 0;
571 }
572 else
573 off = GCPhys - pRam->GCPhys;
574 if (off < pRam->cb)
575 {
576 /*
577 * Iterate the relevant pages.
578 */
579 uint8_t abPrev[MAX_NEEDLE_SIZE];
580 size_t cbPrev = 0;
581 const uint32_t cPages = pRam->cb >> PAGE_SHIFT;
582 for (uint32_t iPage = off >> PAGE_SHIFT; iPage < cPages; iPage++)
583 {
584 PPGMPAGE pPage = &pRam->aPages[iPage];
585 if ( /** @todo !PGM_PAGE_IS_ZERO(pPage)
586 &&*/ !PGM_PAGE_IS_MMIO(pPage))
587 {
588 void const *pvPage;
589 PGMPAGEMAPLOCK Lock;
590 int rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK, &pvPage, &Lock);
591 if (RT_SUCCESS(rc))
592 {
593 int32_t offPage = (GCPhys & PAGE_OFFSET_MASK);
594 uint32_t cbSearch = (GCPhys ^ GCPhysLast) & ~(RTGCPHYS)PAGE_OFFSET_MASK
595 ? PAGE_SIZE - (uint32_t)offPage
596 : (GCPhysLast & PAGE_OFFSET_MASK) + 1 - (uint32_t)offPage;
597 bool fRc = pgmR3DbgScanPage((uint8_t const *)pvPage, &offPage, cbSearch,
598 pabNeedle, cbNeedle, &abPrev[0], &cbPrev);
599 PGMPhysReleasePageMappingLock(pVM, &Lock);
600 if (fRc)
601 {
602 *pGCPhysHit = (GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK) + offPage;
603 return VINF_SUCCESS;
604 }
605 }
606 else
607 cbPrev = 0; /* ignore error. */
608 }
609 else
610 cbPrev = 0;
611
612 /* advance to the next page. */
613 GCPhys |= PAGE_OFFSET_MASK;
614 if (GCPhys++ >= GCPhysLast)
615 return VERR_DBGF_MEM_NOT_FOUND;
616 }
617 }
618 }
619 return VERR_DBGF_MEM_NOT_FOUND;
620}
621
622
623/**
624 * Scans (guest) virtual memory for a byte string.
625 *
626 * @returns VBox status codes:
627 * @retval VINF_SUCCESS and *pGCPtrHit on success.
628 * @retval VERR_DBGF_MEM_NOT_FOUND if not found.
629 * @retval VERR_INVALID_POINTER if any of the pointer arguments are invalid.
630 * @retval VERR_INVALID_ARGUMENT if any other arguments are invalid.
631 *
632 * @param pVM Pointer to the shared VM structure.
633 * @param GCPtr Where to start searching.
634 * @param cbRange The number of bytes to search. Max 256 bytes.
635 * @param pabNeedle The byte string to search for.
636 * @param cbNeedle The length of the byte string.
637 * @param pGCPtrHit Where to store the address of the first occurence on success.
638 */
639VMMR3DECL(int) PGMR3DbgScanVirtual(PVM pVM, RTGCPTR GCPtr, RTGCPTR cbRange, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCUINTPTR pGCPtrHit)
640{
641 /*
642 * Validate and adjust the input a bit.
643 */
644 if (!VALID_PTR(pGCPtrHit))
645 return VERR_INVALID_POINTER;
646 *pGCPtrHit = 0;
647
648 if (!VALID_PTR(pabNeedle))
649 return VERR_INVALID_POINTER;
650 if (!cbNeedle)
651 return VERR_INVALID_PARAMETER;
652 if (cbNeedle > MAX_NEEDLE_SIZE)
653 return VERR_INVALID_PARAMETER;
654
655 if (!cbRange)
656 return VERR_DBGF_MEM_NOT_FOUND;
657 if (GCPtr + cbNeedle - 1 < GCPtr)
658 return VERR_DBGF_MEM_NOT_FOUND;
659
660 /*
661 * Search the memory - ignore MMIO, zero and not-present pages.
662 */
663 uint8_t abPrev[MAX_NEEDLE_SIZE];
664 size_t cbPrev = 0;
665 const RTGCPTR GCPtrLast = GCPtr + cbRange - 1 >= GCPtr
666 ? GCPtr + cbRange - 1
667 : ~(RTGCPTR)0;
668 RTGCPTR cPages = (((GCPtrLast - GCPtr) + (GCPtr & PAGE_OFFSET_MASK)) >> PAGE_SHIFT) + 1;
669 while (cPages-- > 0)
670 {
671 RTGCPHYS GCPhys;
672 int rc = PGMPhysGCPtr2GCPhys(pVM, GCPtr, &GCPhys);
673 if (RT_SUCCESS(rc))
674 {
675 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);
676 if ( pPage
677///@todo && !PGM_PAGE_IS_ZERO(pPage)
678 && !PGM_PAGE_IS_MMIO(pPage))
679 {
680 void const *pvPage;
681 PGMPAGEMAPLOCK Lock;
682 rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys & ~(RTGCPTR)PAGE_OFFSET_MASK, &pvPage, &Lock);
683 if (RT_SUCCESS(rc))
684 {
685 int32_t offPage = (GCPtr & PAGE_OFFSET_MASK);
686 uint32_t cbSearch = cPages > 0
687 ? PAGE_SIZE - (uint32_t)offPage
688 : (GCPtrLast & PAGE_OFFSET_MASK) + 1 - (uint32_t)offPage;
689 bool fRc = pgmR3DbgScanPage((uint8_t const *)pvPage, &offPage, cbSearch,
690 pabNeedle, cbNeedle, &abPrev[0], &cbPrev);
691 PGMPhysReleasePageMappingLock(pVM, &Lock);
692 if (fRc)
693 {
694 *pGCPtrHit = (GCPtr & ~(RTGCPTR)PAGE_OFFSET_MASK) + offPage;
695 return VINF_SUCCESS;
696 }
697 }
698 else
699 cbPrev = 0; /* ignore error. */
700 }
701 else
702 cbPrev = 0;
703 }
704 else
705 cbPrev = 0; /* ignore error. */
706
707 /* advance to the next page. */
708 GCPtr |= PAGE_OFFSET_MASK;
709 GCPtr++;
710 }
711 return VERR_DBGF_MEM_NOT_FOUND;
712}
713
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