VirtualBox

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

Last change on this file since 30037 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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

© 2023 Oracle
ContactPrivacy policyTerms of Use