VirtualBox

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

Last change on this file since 22898 was 20947, checked in by vboxsync, 15 years ago

PGMR3DbgScanVirtual: Chop the range so we don't end up above 4GB on a 32-bit guest.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 21.4 KB
Line 
1/* $Id: PGMDbg.cpp 20947 2009-06-25 15:37:20Z 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 *pGCPhys = NIL_RTGCPHYS;
58 return VERR_NOT_IMPLEMENTED;
59}
60
61
62/**
63 * Converts a R3 pointer to a HC physical address.
64 *
65 * Only for the debugger.
66 *
67 * @returns VBox status code.
68 * @retval VINF_SUCCESS on success, *pHCPhys is set.
69 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid GC physical page but has no physical backing.
70 * @retval VERR_INVALID_POINTER if the pointer is not within the GC physical memory.
71 *
72 * @param pVM The VM handle.
73 * @param R3Ptr The R3 pointer to convert.
74 * @param pHCPhys Where to store the HC physical address on success.
75 */
76VMMR3DECL(int) PGMR3DbgR3Ptr2HCPhys(PVM pVM, RTR3PTR R3Ptr, PRTHCPHYS pHCPhys)
77{
78 *pHCPhys = NIL_RTHCPHYS;
79 return VERR_NOT_IMPLEMENTED;
80}
81
82
83/**
84 * Converts a HC physical address to a GC physical address.
85 *
86 * Only for the debugger.
87 *
88 * @returns VBox status code
89 * @retval VINF_SUCCESS on success, *pGCPhys is set.
90 * @retval VERR_INVALID_POINTER if the HC physical address is not within the GC physical memory.
91 *
92 * @param pVM The VM handle.
93 * @param HCPhys The HC physical address to convert.
94 * @param pGCPhys Where to store the GC physical address on success.
95 */
96VMMR3DECL(int) PGMR3DbgHCPhys2GCPhys(PVM pVM, RTHCPHYS HCPhys, PRTGCPHYS pGCPhys)
97{
98 /*
99 * Validate and adjust the input a bit.
100 */
101 if (HCPhys == NIL_RTHCPHYS)
102 return VERR_INVALID_POINTER;
103 unsigned off = HCPhys & PAGE_OFFSET_MASK;
104 HCPhys &= X86_PTE_PAE_PG_MASK;
105 if (HCPhys == 0)
106 return VERR_INVALID_POINTER;
107
108 for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
109 pRam;
110 pRam = pRam->CTX_SUFF(pNext))
111 {
112 uint32_t iPage = pRam->cb >> PAGE_SHIFT;
113 while (iPage-- > 0)
114 if (PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]) == HCPhys)
115 {
116 *pGCPhys = pRam->GCPhys + (iPage << PAGE_SHIFT) + off;
117 return VINF_SUCCESS;
118 }
119 }
120 return VERR_INVALID_POINTER;
121}
122
123
124/**
125 * Read physical memory API for the debugger, similar to
126 * PGMPhysSimpleReadGCPhys.
127 *
128 * @returns VBox status code.
129 *
130 * @param pVM The VM handle.
131 * @param pvDst Where to store what's read.
132 * @param GCPhysDst Where to start reading from.
133 * @param cb The number of bytes to attempt reading.
134 * @param fFlags Flags, MBZ.
135 * @param pcbRead For store the actual number of bytes read, pass NULL if
136 * partial reads are unwanted.
137 * @todo Unused?
138 */
139VMMR3DECL(int) PGMR3DbgReadGCPhys(PVM pVM, void *pvDst, RTGCPHYS GCPhysSrc, size_t cb, uint32_t fFlags, size_t *pcbRead)
140{
141 /* validate */
142 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
143 AssertReturn(pVM, VERR_INVALID_PARAMETER);
144
145 /* try simple first. */
146 int rc = PGMPhysSimpleReadGCPhys(pVM, pvDst, GCPhysSrc, cb);
147 if (RT_SUCCESS(rc) || !pcbRead)
148 return rc;
149
150 /* partial read that failed, chop it up in pages. */
151 *pcbRead = 0;
152 size_t const cbReq = cb;
153 rc = VINF_SUCCESS;
154 while (cb > 0)
155 {
156 size_t cbChunk = PAGE_SIZE;
157 cbChunk -= GCPhysSrc & PAGE_OFFSET_MASK;
158 if (cbChunk > cb)
159 cbChunk = cb;
160
161 rc = PGMPhysSimpleReadGCPhys(pVM, pvDst, GCPhysSrc, cbChunk);
162
163 /* advance */
164 if (RT_FAILURE(rc))
165 break;
166 *pcbRead += cbChunk;
167 cb -= cbChunk;
168 GCPhysSrc += cbChunk;
169 pvDst = (uint8_t *)pvDst + cbChunk;
170 }
171
172 return *pcbRead && RT_FAILURE(rc) ? -rc : rc;
173}
174
175
176/**
177 * Write physical memory API for the debugger, similar to
178 * PGMPhysSimpleWriteGCPhys.
179 *
180 * @returns VBox status code.
181 *
182 * @param pVM The VM handle.
183 * @param GCPhysDst Where to start writing.
184 * @param pvSrc What to write.
185 * @param cb The number of bytes to attempt writing.
186 * @param fFlags Flags, MBZ.
187 * @param pcbWritten For store the actual number of bytes written, pass NULL
188 * if partial writes are unwanted.
189 * @todo Unused?
190 */
191VMMR3DECL(int) PGMR3DbgWriteGCPhys(PVM pVM, RTGCPHYS GCPhysDst, const void *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten)
192{
193 /* validate */
194 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
195 AssertReturn(pVM, VERR_INVALID_PARAMETER);
196
197 /* try simple first. */
198 int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysDst, pvSrc, cb);
199 if (RT_SUCCESS(rc) || !pcbWritten)
200 return rc;
201
202 /* partial write that failed, chop it up in pages. */
203 *pcbWritten = 0;
204 rc = VINF_SUCCESS;
205 while (cb > 0)
206 {
207 size_t cbChunk = PAGE_SIZE;
208 cbChunk -= GCPhysDst & PAGE_OFFSET_MASK;
209 if (cbChunk > cb)
210 cbChunk = cb;
211
212 rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysDst, pvSrc, cbChunk);
213
214 /* advance */
215 if (RT_FAILURE(rc))
216 break;
217 *pcbWritten += cbChunk;
218 cb -= cbChunk;
219 GCPhysDst += cbChunk;
220 pvSrc = (uint8_t const *)pvSrc + cbChunk;
221 }
222
223 return *pcbWritten && RT_FAILURE(rc) ? -rc : rc;
224
225}
226
227
228/**
229 * Read virtual memory API for the debugger, similar to PGMPhysSimpleReadGCPtr.
230 *
231 * @returns VBox status code.
232 *
233 * @param pVM The VM handle.
234 * @param pvDst Where to store what's read.
235 * @param GCPtrDst Where to start reading from.
236 * @param cb The number of bytes to attempt reading.
237 * @param fFlags Flags, MBZ.
238 * @param pcbRead For store the actual number of bytes read, pass NULL if
239 * partial reads are unwanted.
240 * @todo Unused?
241 */
242VMMR3DECL(int) PGMR3DbgReadGCPtr(PVM pVM, void *pvDst, RTGCPTR GCPtrSrc, size_t cb, uint32_t fFlags, size_t *pcbRead)
243{
244 /* validate */
245 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
246 AssertReturn(pVM, VERR_INVALID_PARAMETER);
247
248 /* @todo SMP support! */
249 PVMCPU pVCpu = &pVM->aCpus[0];
250
251/** @todo deal with HMA */
252 /* try simple first. */
253 int rc = PGMPhysSimpleReadGCPtr(pVCpu, pvDst, GCPtrSrc, cb);
254 if (RT_SUCCESS(rc) || !pcbRead)
255 return rc;
256
257 /* partial read that failed, chop it up in pages. */
258 *pcbRead = 0;
259 rc = VINF_SUCCESS;
260 while (cb > 0)
261 {
262 size_t cbChunk = PAGE_SIZE;
263 cbChunk -= GCPtrSrc & PAGE_OFFSET_MASK;
264 if (cbChunk > cb)
265 cbChunk = cb;
266
267 rc = PGMPhysSimpleReadGCPtr(pVCpu, pvDst, GCPtrSrc, cbChunk);
268
269 /* advance */
270 if (RT_FAILURE(rc))
271 break;
272 *pcbRead += cbChunk;
273 cb -= cbChunk;
274 GCPtrSrc += cbChunk;
275 pvDst = (uint8_t *)pvDst + cbChunk;
276 }
277
278 return *pcbRead && RT_FAILURE(rc) ? -rc : rc;
279
280}
281
282
283/**
284 * Write virtual memory API for the debugger, similar to
285 * PGMPhysSimpleWriteGCPtr.
286 *
287 * @returns VBox status code.
288 *
289 * @param pVM The VM handle.
290 * @param GCPtrDst Where to start writing.
291 * @param pvSrc What to write.
292 * @param cb The number of bytes to attempt writing.
293 * @param fFlags Flags, MBZ.
294 * @param pcbWritten For store the actual number of bytes written, pass NULL
295 * if partial writes are unwanted.
296 * @todo Unused?
297 */
298VMMR3DECL(int) PGMR3DbgWriteGCPtr(PVM pVM, RTGCPTR GCPtrDst, void const *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten)
299{
300 /* validate */
301 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
302 AssertReturn(pVM, VERR_INVALID_PARAMETER);
303
304 /* @todo SMP support! */
305 PVMCPU pVCpu = &pVM->aCpus[0];
306
307/** @todo deal with HMA */
308 /* try simple first. */
309 int rc = PGMPhysSimpleWriteGCPtr(pVCpu, GCPtrDst, pvSrc, cb);
310 if (RT_SUCCESS(rc) || !pcbWritten)
311 return rc;
312
313 /* partial write that failed, chop it up in pages. */
314 *pcbWritten = 0;
315 rc = VINF_SUCCESS;
316 while (cb > 0)
317 {
318 size_t cbChunk = PAGE_SIZE;
319 cbChunk -= GCPtrDst & PAGE_OFFSET_MASK;
320 if (cbChunk > cb)
321 cbChunk = cb;
322
323 rc = PGMPhysSimpleWriteGCPtr(pVCpu, GCPtrDst, pvSrc, cbChunk);
324
325 /* advance */
326 if (RT_FAILURE(rc))
327 break;
328 *pcbWritten += cbChunk;
329 cb -= cbChunk;
330 GCPtrDst += cbChunk;
331 pvSrc = (uint8_t const *)pvSrc + cbChunk;
332 }
333
334 return *pcbWritten && RT_FAILURE(rc) ? -rc : rc;
335
336}
337
338
339
340/**
341 * Scans a page for a byte string, keeping track of potential
342 * cross page matches.
343 *
344 * @returns true and *poff on match.
345 * false on mismatch.
346 * @param pbPage Pointer to the current page.
347 * @param poff Input: The offset into the page.
348 * Output: The page offset of the match on success.
349 * @param cb The number of bytes to search, starting of *poff.
350 * @param pabNeedle The byte string to search for.
351 * @param cbNeedle The length of the byte string.
352 * @param pabPrev The buffer that keeps track of a partial match that we
353 * bring over from the previous page. This buffer must be
354 * at least cbNeedle - 1 big.
355 * @param pcbPrev Input: The number of partial matching bytes from the previous page.
356 * Output: The number of partial matching bytes from this page.
357 * Initialize to 0 before the first call to this function.
358 */
359static bool pgmR3DbgScanPage(const uint8_t *pbPage, int32_t *poff, uint32_t cb,
360 const uint8_t *pabNeedle, size_t cbNeedle,
361 uint8_t *pabPrev, size_t *pcbPrev)
362{
363 /*
364 * Try complete any partial match from the previous page.
365 */
366 if (*pcbPrev > 0)
367 {
368 size_t cbPrev = *pcbPrev;
369 Assert(!*poff);
370 Assert(cbPrev < cbNeedle);
371 if (!memcmp(pbPage, pabNeedle + cbPrev, cbNeedle - cbPrev))
372 {
373 if (cbNeedle - cbPrev > cb)
374 return false;
375 *poff = -(int32_t)cbPrev;
376 return true;
377 }
378
379 /* check out the remainder of the previous page. */
380 const uint8_t *pb = pabPrev;
381 while (cbPrev-- > 0)
382 {
383 pb = (const uint8_t *)memchr(pb + 1, *pabNeedle, cbPrev);
384 if (!pb)
385 break;
386 cbPrev = *pcbPrev - (pb - pabPrev);
387 if ( !memcmp(pb + 1, &pabNeedle[1], cbPrev - 1)
388 && !memcmp(pbPage, pabNeedle + cbPrev, cbNeedle - cbPrev))
389 {
390 if (cbNeedle - cbPrev > cb)
391 return false;
392 *poff = -(int32_t)cbPrev;
393 return true;
394 }
395 }
396
397 *pcbPrev = 0;
398 }
399
400 /*
401 * Match the body of the page.
402 */
403 const uint8_t *pb = pbPage + *poff;
404 const uint8_t *pbEnd = pb + cb;
405 for (;;)
406 {
407 pb = (const uint8_t *)memchr(pb, *pabNeedle, cb);
408 if (!pb)
409 break;
410 cb = pbEnd - pb;
411 if (cb >= cbNeedle)
412 {
413 /* match? */
414 if (!memcmp(pb + 1, &pabNeedle[1], cbNeedle - 1))
415 {
416 *poff = pb - pbPage;
417 return true;
418 }
419 }
420 else
421 {
422 /* paritial match at the end of the page? */
423 if (!memcmp(pb + 1, &pabNeedle[1], cb - 1))
424 {
425 /* We're copying one byte more that we really need here, but wtf. */
426 memcpy(pabPrev, pb, cb);
427 *pcbPrev = cb;
428 return false;
429 }
430 }
431
432 /* no match, skip a byte ahead. */
433 if (cb <= 1)
434 break;
435 pb++;
436 cb--;
437 }
438
439 return false;
440}
441
442
443/**
444 * Scans guest physical memory for a byte string.
445 *
446 * @returns VBox status codes:
447 * @retval VINF_SUCCESS and *pGCPtrHit on success.
448 * @retval VERR_DBGF_MEM_NOT_FOUND if not found.
449 * @retval VERR_INVALID_POINTER if any of the pointer arguments are invalid.
450 * @retval VERR_INVALID_ARGUMENT if any other arguments are invalid.
451 *
452 * @param pVM Pointer to the shared VM structure.
453 * @param GCPhys Where to start searching.
454 * @param cbRange The number of bytes to search.
455 * @param pabNeedle The byte string to search for.
456 * @param cbNeedle The length of the byte string. Max 256 bytes.
457 * @param pGCPhysHit Where to store the address of the first occurence on success.
458 */
459VMMR3DECL(int) PGMR3DbgScanPhysical(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cbRange, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCPHYS pGCPhysHit)
460{
461 /*
462 * Validate and adjust the input a bit.
463 */
464 if (!VALID_PTR(pGCPhysHit))
465 return VERR_INVALID_POINTER;
466 *pGCPhysHit = NIL_RTGCPHYS;
467
468 if ( !VALID_PTR(pabNeedle)
469 || GCPhys == NIL_RTGCPHYS)
470 return VERR_INVALID_POINTER;
471 if (!cbNeedle)
472 return VERR_INVALID_PARAMETER;
473 if (cbNeedle > MAX_NEEDLE_SIZE)
474 return VERR_INVALID_PARAMETER;
475
476 if (!cbRange)
477 return VERR_DBGF_MEM_NOT_FOUND;
478 if (GCPhys + cbNeedle - 1 < GCPhys)
479 return VERR_DBGF_MEM_NOT_FOUND;
480
481 const RTGCPHYS GCPhysLast = GCPhys + cbRange - 1 >= GCPhys
482 ? GCPhys + cbRange - 1
483 : ~(RTGCPHYS)0;
484
485 /*
486 * Search the memory - ignore MMIO and zero pages, also don't
487 * bother to match across ranges.
488 */
489 pgmLock(pVM);
490 for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
491 pRam;
492 pRam = pRam->CTX_SUFF(pNext))
493 {
494 /*
495 * If the search range starts prior to the current ram range record,
496 * adjust the search range and possibly conclude the search.
497 */
498 RTGCPHYS off;
499 if (GCPhys < pRam->GCPhys)
500 {
501 if (GCPhysLast < pRam->GCPhys)
502 break;
503 GCPhys = pRam->GCPhys;
504 off = 0;
505 }
506 else
507 off = GCPhys - pRam->GCPhys;
508 if (off < pRam->cb)
509 {
510 /*
511 * Iterate the relevant pages.
512 */
513 uint8_t abPrev[MAX_NEEDLE_SIZE];
514 size_t cbPrev = 0;
515 const uint32_t cPages = pRam->cb >> PAGE_SHIFT;
516 for (uint32_t iPage = off >> PAGE_SHIFT; iPage < cPages; iPage++)
517 {
518 PPGMPAGE pPage = &pRam->aPages[iPage];
519 if ( !PGM_PAGE_IS_ZERO(pPage)
520 && !PGM_PAGE_IS_MMIO(pPage))
521 {
522 void const *pvPage;
523 PGMPAGEMAPLOCK Lock;
524 int rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK, &pvPage, &Lock);
525 if (RT_SUCCESS(rc))
526 {
527 int32_t offPage = (GCPhys & PAGE_OFFSET_MASK);
528 uint32_t cbSearch = (GCPhys ^ GCPhysLast) & ~(RTGCPHYS)PAGE_OFFSET_MASK
529 ? PAGE_SIZE - (uint32_t)offPage
530 : (GCPhysLast & PAGE_OFFSET_MASK) + 1 - (uint32_t)offPage;
531 bool fRc = pgmR3DbgScanPage((uint8_t const *)pvPage, &offPage, cbSearch,
532 pabNeedle, cbNeedle, &abPrev[0], &cbPrev);
533 PGMPhysReleasePageMappingLock(pVM, &Lock);
534 if (fRc)
535 {
536 *pGCPhysHit = (GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK) + offPage;
537 pgmUnlock(pVM);
538 return VINF_SUCCESS;
539 }
540 }
541 else
542 cbPrev = 0; /* ignore error. */
543 }
544 else
545 cbPrev = 0;
546
547 /* advance to the next page. */
548 GCPhys |= PAGE_OFFSET_MASK;
549 if (GCPhys++ >= GCPhysLast)
550 {
551 pgmUnlock(pVM);
552 return VERR_DBGF_MEM_NOT_FOUND;
553 }
554 }
555 }
556 }
557 pgmUnlock(pVM);
558 return VERR_DBGF_MEM_NOT_FOUND;
559}
560
561
562/**
563 * Scans (guest) virtual memory for a byte string.
564 *
565 * @returns VBox status codes:
566 * @retval VINF_SUCCESS and *pGCPtrHit on success.
567 * @retval VERR_DBGF_MEM_NOT_FOUND if not found.
568 * @retval VERR_INVALID_POINTER if any of the pointer arguments are invalid.
569 * @retval VERR_INVALID_ARGUMENT if any other arguments are invalid.
570 *
571 * @param pVM Pointer to the shared VM structure.
572 * @param pVCpu The CPU context to search in.
573 * @param GCPtr Where to start searching.
574 * @param cbRange The number of bytes to search. Max 256 bytes.
575 * @param pabNeedle The byte string to search for.
576 * @param cbNeedle The length of the byte string.
577 * @param pGCPtrHit Where to store the address of the first occurence on success.
578 */
579VMMR3DECL(int) PGMR3DbgScanVirtual(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, RTGCPTR cbRange, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCUINTPTR pGCPtrHit)
580{
581 VMCPU_ASSERT_EMT(pVCpu);
582
583 /*
584 * Validate and adjust the input a bit.
585 */
586 if (!VALID_PTR(pGCPtrHit))
587 return VERR_INVALID_POINTER;
588 *pGCPtrHit = 0;
589
590 if (!VALID_PTR(pabNeedle))
591 return VERR_INVALID_POINTER;
592 if (!cbNeedle)
593 return VERR_INVALID_PARAMETER;
594 if (cbNeedle > MAX_NEEDLE_SIZE)
595 return VERR_INVALID_PARAMETER;
596
597 if (!cbRange)
598 return VERR_DBGF_MEM_NOT_FOUND;
599 if (GCPtr + cbNeedle - 1 < GCPtr)
600 return VERR_DBGF_MEM_NOT_FOUND;
601
602 /*
603 * Search the memory - ignore MMIO, zero and not-present pages.
604 */
605 PGMMODE enmMode = PGMGetGuestMode(pVCpu);
606 RTGCPTR GCPtrMask = PGMMODE_IS_LONG_MODE(enmMode) ? UINT64_MAX : UINT32_MAX;
607 uint8_t abPrev[MAX_NEEDLE_SIZE];
608 size_t cbPrev = 0;
609 const RTGCPTR GCPtrLast = GCPtr + cbRange - 1 >= GCPtr
610 ? (GCPtr + cbRange - 1) & GCPtrMask
611 : GCPtrMask;
612 RTGCPTR cPages = (((GCPtrLast - GCPtr) + (GCPtr & PAGE_OFFSET_MASK)) >> PAGE_SHIFT) + 1;
613 while (cPages-- > 0)
614 {
615 RTGCPHYS GCPhys;
616 int rc = PGMPhysGCPtr2GCPhys(pVCpu, GCPtr, &GCPhys);
617 if (RT_SUCCESS(rc))
618 {
619 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);
620 if ( pPage
621 && !PGM_PAGE_IS_ZERO(pPage) /** @todo handle all zero needle. */
622 && !PGM_PAGE_IS_MMIO(pPage))
623 {
624 void const *pvPage;
625 PGMPAGEMAPLOCK Lock;
626 rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys & ~(RTGCPTR)PAGE_OFFSET_MASK, &pvPage, &Lock);
627 if (RT_SUCCESS(rc))
628 {
629 int32_t offPage = (GCPtr & PAGE_OFFSET_MASK);
630 uint32_t cbSearch = cPages > 0
631 ? PAGE_SIZE - (uint32_t)offPage
632 : (GCPtrLast & PAGE_OFFSET_MASK) + 1 - (uint32_t)offPage;
633 bool fRc = pgmR3DbgScanPage((uint8_t const *)pvPage, &offPage, cbSearch,
634 pabNeedle, cbNeedle, &abPrev[0], &cbPrev);
635 PGMPhysReleasePageMappingLock(pVM, &Lock);
636 if (fRc)
637 {
638 *pGCPtrHit = (GCPtr & ~(RTGCPTR)PAGE_OFFSET_MASK) + offPage;
639 return VINF_SUCCESS;
640 }
641 }
642 else
643 cbPrev = 0; /* ignore error. */
644 }
645 else
646 cbPrev = 0;
647 }
648 else
649 cbPrev = 0; /* ignore error. */
650
651 /* advance to the next page. */
652 GCPtr |= PAGE_OFFSET_MASK;
653 GCPtr++;
654 GCPtr &= GCPtrMask;
655 }
656 return VERR_DBGF_MEM_NOT_FOUND;
657}
658
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