VirtualBox

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

Last change on this file since 26550 was 26150, checked in by vboxsync, 15 years ago

PGM: Split out the inlined code from PGMInternal.h and into PGMInline.h so we can drop all the &pVM->pgm.s and &pVCpu->pgm.s stuff.

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