VirtualBox

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

Last change on this file since 18499 was 17370, checked in by vboxsync, 15 years ago

PGMDbg: new phys code.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use