Index: /trunk/include/VBox/cpum.h
===================================================================
--- /trunk/include/VBox/cpum.h	(revision 24060)
+++ /trunk/include/VBox/cpum.h	(revision 24061)
@@ -963,21 +963,5 @@
 VMMDECL(uint32_t)       CPUMGetGuestCPL(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore);
 VMMDECL(bool)           CPUMAreHiddenSelRegsValid(PVM pVM);
-
-/**
- * CPU modes.
- */
-typedef enum CPUMMODE
-{
-    /** The usual invalid zero entry. */
-    CPUMMODE_INVALID = 0,
-    /** Real mode. */
-    CPUMMODE_REAL,
-    /** Protected mode (32-bit). */
-    CPUMMODE_PROTECTED,
-    /** Long mode (64-bit). */
-    CPUMMODE_LONG
-} CPUMMODE;
-
-VMMDECL(CPUMMODE)  CPUMGetGuestMode(PVMCPU pVCpu);
+VMMDECL(CPUMMODE)       CPUMGetGuestMode(PVMCPU pVCpu);
 
 
Index: /trunk/include/VBox/dbgf.h
===================================================================
--- /trunk/include/VBox/dbgf.h	(revision 24060)
+++ /trunk/include/VBox/dbgf.h	(revision 24061)
@@ -410,4 +410,8 @@
 VMMDECL(RTGCUINTREG)    DBGFBpGetDR3(PVM pVM);
 VMMDECL(bool)           DBGFIsStepping(PVMCPU pVCpu);
+
+
+
+VMMR3DECL(CPUMMODE)     DBGFR3CpuGetMode(PVM pVM, VMCPUID idCpu);
 
 
@@ -885,5 +889,6 @@
 
 
-VMMR3DECL(int) DBGFR3MemScan(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, RTGCUINTPTR cbRange, const uint8_t *pabNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress);
+VMMR3DECL(int) DBGFR3MemScan(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, RTGCUINTPTR cbRange, RTGCUINTPTR uAlign,
+                             const void *pvNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress);
 VMMR3DECL(int) DBGFR3MemRead(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void *pvBuf, size_t cbRead);
 VMMR3DECL(int) DBGFR3MemReadString(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, char *pszBuf, size_t cbBuf);
Index: /trunk/include/VBox/pgm.h
===================================================================
--- /trunk/include/VBox/pgm.h	(revision 24060)
+++ /trunk/include/VBox/pgm.h	(revision 24061)
@@ -545,6 +545,6 @@
 VMMR3DECL(int)      PGMR3DbgReadGCPtr(PVM pVM, void *pvDst, RTGCPTR GCPtrSrc, size_t cb, uint32_t fFlags, size_t *pcbRead);
 VMMR3DECL(int)      PGMR3DbgWriteGCPtr(PVM pVM, RTGCPTR GCPtrDst, void const *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten);
-VMMR3DECL(int)      PGMR3DbgScanPhysical(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cbRange, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCPHYS pGCPhysHit);
-VMMR3DECL(int)      PGMR3DbgScanVirtual(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, RTGCPTR cbRange, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCUINTPTR pGCPhysHit);
+VMMR3DECL(int)      PGMR3DbgScanPhysical(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cbRange, RTGCPHYS GCPhysAlign, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCPHYS pGCPhysHit);
+VMMR3DECL(int)      PGMR3DbgScanVirtual(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, RTGCPTR cbRange, RTGCPTR GCPtrAlign, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCUINTPTR pGCPhysHit);
 /** @} */
 #endif /* IN_RING3 */
Index: /trunk/include/VBox/types.h
===================================================================
--- /trunk/include/VBox/types.h	(revision 24060)
+++ /trunk/include/VBox/types.h	(revision 24061)
@@ -795,4 +795,18 @@
 typedef struct CFGMLEAF *PCFGMLEAF;
 
+/**
+ * CPU modes.
+ */
+typedef enum CPUMMODE
+{
+    /** The usual invalid zero entry. */
+    CPUMMODE_INVALID = 0,
+    /** Real mode. */
+    CPUMMODE_REAL,
+    /** Protected mode (32-bit). */
+    CPUMMODE_PROTECTED,
+    /** Long mode (64-bit). */
+    CPUMMODE_LONG
+} CPUMMODE;
 
 /** @} */
Index: /trunk/include/iprt/err.h
===================================================================
--- /trunk/include/iprt/err.h	(revision 24060)
+++ /trunk/include/iprt/err.h	(revision 24061)
@@ -605,4 +605,6 @@
 /** Authentication failure. */
 #define VERR_AUTHENTICATION_FAILURE         (-89)
+/** Not a power of two. */
+#define VERR_NOT_POWER_OF_TWO               (-90)
 /** @} */
 
Index: /trunk/src/VBox/VMM/DBGFCpu.cpp
===================================================================
--- /trunk/src/VBox/VMM/DBGFCpu.cpp	(revision 24061)
+++ /trunk/src/VBox/VMM/DBGFCpu.cpp	(revision 24061)
@@ -0,0 +1,72 @@
+/* $Id$ */
+/** @file
+ * DBGF - Debugger Facility, CPU State Accessors.
+ */
+
+/*
+ * Copyright (C) 2009 Sun Microsystems, Inc.
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_DBGF
+#include <VBox/dbgf.h>
+#include <VBox/cpum.h>
+#include "DBGFInternal.h"
+#include <VBox/vm.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+#include <VBox/param.h>
+#include <iprt/assert.h>
+
+
+/**
+ * Wrapper around CPUMGetGuestMode.
+ *
+ * @returns VINF_SUCCESS.
+ * @param   pVM                 The VM handle.
+ * @param   idCpu               The current CPU ID.
+ * @param   penmMode            Where to return the mode.
+ */
+static DECLCALLBACK(int) dbgfR3CpuGetMode(PVM pVM, VMCPUID idCpu, CPUMMODE *penmMode)
+{
+    Assert(idCpu == VMMGetCpuId(pVM));
+    PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
+    *penmMode = CPUMGetGuestMode(pVCpu);
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Get the current CPU mode.
+ *
+ * @returns The CPU mode on success, CPUMMODE_INVALID on failure.
+ * @param   pVM                 The VM handle.
+ * @param   idCpu               The target CPU ID.
+ */
+VMMR3DECL(CPUMMODE) DBGFR3CpuGetMode(PVM pVM, VMCPUID idCpu)
+{
+    VM_ASSERT_VALID_EXT_RETURN(pVM, CPUMMODE_INVALID);
+    AssertReturn(idCpu < pVM->cCpus, CPUMMODE_INVALID);
+
+    CPUMMODE enmMode;
+    int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3CpuGetMode, 3, pVM, idCpu, &enmMode);
+    if (RT_FAILURE(rc))
+        return CPUMMODE_INVALID;
+    return enmMode;
+}
+
Index: /trunk/src/VBox/VMM/DBGFMem.cpp
===================================================================
--- /trunk/src/VBox/VMM/DBGFMem.cpp	(revision 24060)
+++ /trunk/src/VBox/VMM/DBGFMem.cpp	(revision 24061)
@@ -44,4 +44,5 @@
  * @param   idCpu       The ID of the CPU context to search in.
  * @param   pAddress    Where to store the mixed address.
+ * @param   pu64Align   The alignment restriction imposed on the search result.
  * @param   pcbRange    The number of bytes to scan. Passed as a pointer because
  *                      it may be 64-bit.
@@ -50,5 +51,5 @@
  * @param   pHitAddress Where to put the address of the first hit.
  */
-static DECLCALLBACK(int) dbgfR3MemScan(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, PCRTGCUINTPTR pcbRange,
+static DECLCALLBACK(int) dbgfR3MemScan(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, PCRTGCUINTPTR pcbRange, RTGCUINTPTR *puAlign,
                                        const uint8_t *pabNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress)
 {
@@ -77,6 +78,9 @@
         )
     {
+        RTGCPHYS GCPhysAlign = *puAlign;
+        if (GCPhysAlign != *puAlign)
+            return VERR_OUT_OF_RANGE;
         RTGCPHYS PhysHit;
-        rc = PGMR3DbgScanPhysical(pVM, pAddress->FlatPtr, cbRange, pabNeedle, cbNeedle, &PhysHit);
+        rc = PGMR3DbgScanPhysical(pVM, pAddress->FlatPtr, cbRange, GCPhysAlign, pabNeedle, cbNeedle, &PhysHit);
         if (RT_SUCCESS(rc))
             DBGFR3AddrFromPhys(pVM, pHitAddress, PhysHit);
@@ -92,5 +96,5 @@
 #endif
         RTGCUINTPTR GCPtrHit;
-        rc = PGMR3DbgScanVirtual(pVM, pVCpu, pAddress->FlatPtr, cbRange, pabNeedle, cbNeedle, &GCPtrHit);
+        rc = PGMR3DbgScanVirtual(pVM, pVCpu, pAddress->FlatPtr, cbRange, *puAlign, pabNeedle, cbNeedle, &GCPtrHit);
         if (RT_SUCCESS(rc))
             DBGFR3AddrFromFlat(pVM, pHitAddress, GCPtrHit);
@@ -114,5 +118,7 @@
  * @param   pAddress    Where to store the mixed address.
  * @param   cbRange     The number of bytes to scan.
- * @param   pabNeedle   What to search for - exact search.
+ * @param   uAlign      The alignment restriction imposed on the result.
+ *                      Usually set to 1.
+ * @param   pvNeedle    What to search for - exact search.
  * @param   cbNeedle    Size of the search byte string.
  * @param   pHitAddress Where to put the address of the first hit.
@@ -120,9 +126,10 @@
  * @thread  Any thread.
  */
-VMMR3DECL(int) DBGFR3MemScan(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, RTGCUINTPTR cbRange, const uint8_t *pabNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress)
+VMMR3DECL(int) DBGFR3MemScan(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, RTGCUINTPTR cbRange, RTGCUINTPTR uAlign,
+                             const void *pvNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress)
 {
     AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER);
-    return VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3MemScan, 7,
-                           pVM, idCpu, pAddress, &cbRange, pabNeedle, cbNeedle, pHitAddress);
+    return VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3MemScan, 8,
+                           pVM, idCpu, pAddress, &cbRange, &uAlign, pvNeedle, cbNeedle, pHitAddress);
 
 }
Index: /trunk/src/VBox/VMM/Makefile.kmk
===================================================================
--- /trunk/src/VBox/VMM/Makefile.kmk	(revision 24060)
+++ /trunk/src/VBox/VMM/Makefile.kmk	(revision 24061)
@@ -78,4 +78,5 @@
 	DBGFAddrSpace.cpp \
 	DBGFBp.cpp \
+	DBGFCpu.cpp \
 	DBGFDisas.cpp \
 	DBGFInfo.cpp \
Index: /trunk/src/VBox/VMM/PGMDbg.cpp
===================================================================
--- /trunk/src/VBox/VMM/PGMDbg.cpp	(revision 24060)
+++ /trunk/src/VBox/VMM/PGMDbg.cpp	(revision 24061)
@@ -337,4 +337,56 @@
 
 
+/**
+ * memchr() with alignment considerations.
+ *
+ * @returns Pointer to matching byte, NULL if none found.
+ * @param   pb                  Where to search. Aligned.
+ * @param   b                   What to search for.
+ * @param   cb                  How much to search .
+ * @param   uAlign              The alignment restriction of the result.
+ */
+static const uint8_t *pgmR3DbgAlignedMemChr(const uint8_t *pb, uint8_t b, size_t cb, uint32_t uAlign)
+{
+    const uint8_t *pbRet;
+    if (uAlign <= 32)
+    {
+        pbRet = (const uint8_t *)memchr(pb, b, cb);
+        if ((uintptr_t)pbRet & (uAlign - 1))
+        {
+            do
+            {
+                pbRet++;
+                size_t cbLeft = cb - (pbRet - pb);
+                if (!cbLeft)
+                {
+                    pbRet = NULL;
+                    break;
+                }
+                pbRet = (const uint8_t *)memchr(pbRet, b, cbLeft);
+            } while ((uintptr_t)pbRet & (uAlign - 1));
+        }
+    }
+    else
+    {
+        pbRet = NULL;
+        if (cb)
+        {
+            for (;;)
+            {
+                if (*pb == b)
+                {
+                    pbRet = pb;
+                    break;
+                }
+                if (cb <= uAlign)
+                    break;
+                cb -= uAlign;
+                pb += uAlign;
+            }
+        }
+    }
+    return pbRet;
+}
+
 
 /**
@@ -345,7 +397,8 @@
  *          false on mismatch.
  * @param   pbPage          Pointer to the current page.
- * @param   poff            Input: The offset into the page.
+ * @param   poff            Input: The offset into the page (aligned).
  *                          Output: The page offset of the match on success.
  * @param   cb              The number of bytes to search, starting of *poff.
+ * @param   uAlign          The needle alignment. This is of course less than a page.
  * @param   pabNeedle       The byte string to search for.
  * @param   cbNeedle        The length of the byte string.
@@ -357,5 +410,5 @@
  *                          Initialize to 0 before the first call to this function.
  */
-static bool pgmR3DbgScanPage(const uint8_t *pbPage, int32_t *poff, uint32_t cb,
+static bool pgmR3DbgScanPage(const uint8_t *pbPage, int32_t *poff, uint32_t cb, uint32_t uAlign,
                              const uint8_t *pabNeedle, size_t cbNeedle,
                              uint8_t *pabPrev, size_t *pcbPrev)
@@ -379,7 +432,10 @@
         /* check out the remainder of the previous page. */
         const uint8_t *pb = pabPrev;
-        while (cbPrev-- > 0)
-        {
-            pb = (const uint8_t *)memchr(pb + 1, *pabNeedle, cbPrev);
+        for (;;)
+        {
+            if (cbPrev <= uAlign)
+                break;
+            cbPrev -= uAlign;
+            pb = pgmR3DbgAlignedMemChr(pb + uAlign, *pabNeedle, cbPrev, uAlign);
             if (!pb)
                 break;
@@ -405,5 +461,5 @@
     for (;;)
     {
-        pb = (const uint8_t *)memchr(pb, *pabNeedle, cb);
+        pb = pgmR3DbgAlignedMemChr(pb, *pabNeedle, cb, uAlign);
         if (!pb)
             break;
@@ -430,9 +486,9 @@
         }
 
-        /* no match, skip a byte ahead. */
-        if (cb <= 1)
+        /* no match, skip ahead. */
+        if (cb <= uAlign)
             break;
-        pb++;
-        cb--;
+        pb += uAlign;
+        cb -= uAlign;
     }
 
@@ -453,9 +509,12 @@
  * @param   GCPhys          Where to start searching.
  * @param   cbRange         The number of bytes to search.
+ * @param   GCPhysAlign     The alignment of the needle. Must be a power of two
+ *                          and less or equal to 4GB.
  * @param   pabNeedle       The byte string to search for.
  * @param   cbNeedle        The length of the byte string. Max 256 bytes.
  * @param   pGCPhysHit      Where to store the address of the first occurence on success.
  */
-VMMR3DECL(int) PGMR3DbgScanPhysical(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cbRange, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCPHYS pGCPhysHit)
+VMMR3DECL(int) PGMR3DbgScanPhysical(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cbRange, RTGCPHYS GCPhysAlign,
+                                    const uint8_t *pabNeedle, size_t cbNeedle, PRTGCPHYS pGCPhysHit)
 {
     /*
@@ -479,7 +538,28 @@
         return VERR_DBGF_MEM_NOT_FOUND;
 
-    const RTGCPHYS GCPhysLast = GCPhys + cbRange - 1 >= GCPhys
-                              ? GCPhys + cbRange - 1
-                              : ~(RTGCPHYS)0;
+    if (!GCPhysAlign)
+        return VERR_INVALID_PARAMETER;
+    if (GCPhysAlign > UINT32_MAX)
+        return VERR_NOT_POWER_OF_TWO;
+    if (GCPhysAlign & (GCPhysAlign - 1))
+        return VERR_INVALID_PARAMETER;
+
+    if (GCPhys & (GCPhysAlign - 1))
+    {
+        RTGCPHYS Adj = GCPhysAlign - (GCPhys & (GCPhysAlign - 1));
+        if (    cbRange <= Adj
+            ||  GCPhys + Adj < GCPhys)
+            return VERR_DBGF_MEM_NOT_FOUND;
+        GCPhys  += Adj;
+        cbRange -= Adj;
+    }
+
+    const bool      fAllZero   = ASMMemIsAll8(pabNeedle, cbNeedle, 0) == NULL;
+    const uint32_t  cIncPages  = GCPhysAlign <= PAGE_SIZE
+                               ? 1
+                               : GCPhysAlign >> PAGE_SHIFT;
+    const RTGCPHYS  GCPhysLast = GCPhys + cbRange - 1 >= GCPhys
+                               ? GCPhys + cbRange - 1
+                               : ~(RTGCPHYS)0;
 
     /*
@@ -511,28 +591,39 @@
              * Iterate the relevant pages.
              */
-            uint8_t abPrev[MAX_NEEDLE_SIZE];
-            size_t  cbPrev = 0;
-            const uint32_t cPages = pRam->cb >> PAGE_SHIFT;
-            for (uint32_t iPage = off >> PAGE_SHIFT; iPage < cPages; iPage++)
+            uint8_t         abPrev[MAX_NEEDLE_SIZE];
+            size_t          cbPrev   = 0;
+            const uint32_t  cPages   = pRam->cb >> PAGE_SHIFT;
+            uint32_t        iPage    = off >> PAGE_SHIFT;
+            uint32_t        offPage  = GCPhys & PAGE_OFFSET_MASK;
+            GCPhys &= ~(RTGCPHYS)PAGE_OFFSET_MASK;
+            for (;; offPage = 0)
             {
                 PPGMPAGE pPage = &pRam->aPages[iPage];
-                if (    !PGM_PAGE_IS_ZERO(pPage)
+                if (    (   !PGM_PAGE_IS_ZERO(pPage)
+                         || fAllZero)
                     &&  !PGM_PAGE_IS_MMIO(pPage))
                 {
-                    void const *pvPage;
-                    PGMPAGEMAPLOCK Lock;
-                    int rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK, &pvPage, &Lock);
+                    void const     *pvPage;
+                    PGMPAGEMAPLOCK  Lock;
+                    int rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys, &pvPage, &Lock);
                     if (RT_SUCCESS(rc))
                     {
-                        int32_t  offPage = (GCPhys & PAGE_OFFSET_MASK);
-                        uint32_t cbSearch = (GCPhys ^ GCPhysLast) & ~(RTGCPHYS)PAGE_OFFSET_MASK
-                                          ? PAGE_SIZE                           - (uint32_t)offPage
-                                          : (GCPhysLast & PAGE_OFFSET_MASK) + 1 - (uint32_t)offPage;
-                        bool fRc = pgmR3DbgScanPage((uint8_t const *)pvPage, &offPage, cbSearch,
-                                                    pabNeedle, cbNeedle, &abPrev[0], &cbPrev);
+                        int32_t     offHit = offPage;
+                        bool        fRc;
+                        if (GCPhysAlign < PAGE_SIZE)
+                        {
+                            uint32_t cbSearch = (GCPhys ^ GCPhysLast) & ~(RTGCPHYS)PAGE_OFFSET_MASK
+                                              ? PAGE_SIZE                           - (uint32_t)offPage
+                                              : (GCPhysLast & PAGE_OFFSET_MASK) + 1 - (uint32_t)offPage;
+                            fRc = pgmR3DbgScanPage((uint8_t const *)pvPage, &offHit, cbSearch, (uint32_t)GCPhysAlign,
+                                                   pabNeedle, cbNeedle, &abPrev[0], &cbPrev);
+                        }
+                        else
+                            fRc = memcmp(pvPage, pabNeedle, cbNeedle) == 0
+                               && (GCPhysLast - GCPhys) >= cbNeedle;
                         PGMPhysReleasePageMappingLock(pVM, &Lock);
                         if (fRc)
                         {
-                            *pGCPhysHit = (GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK) + offPage;
+                            *pGCPhysHit = GCPhys + offHit;
                             pgmUnlock(pVM);
                             return VINF_SUCCESS;
@@ -546,10 +637,14 @@
 
                 /* advance to the next page. */
-                GCPhys |= PAGE_OFFSET_MASK;
-                if (GCPhys++ >= GCPhysLast)
+                GCPhys += (RTGCPHYS)cIncPages << PAGE_SHIFT;
+                if (GCPhys >= GCPhysLast) /* (may not always hit, but we're run out of ranges.) */
                 {
                     pgmUnlock(pVM);
                     return VERR_DBGF_MEM_NOT_FOUND;
                 }
+                iPage += cIncPages;
+                if (    iPage < cIncPages
+                    ||  iPage >= cPages)
+                    break;
             }
         }
@@ -572,4 +667,6 @@
  * @param   pVCpu           The CPU context to search in.
  * @param   GCPtr           Where to start searching.
+ * @param   GCPtrAlign      The alignment of the needle. Must be a power of two
+ *                          and less or equal to 4GB.
  * @param   cbRange         The number of bytes to search. Max 256 bytes.
  * @param   pabNeedle       The byte string to search for.
@@ -577,5 +674,6 @@
  * @param   pGCPtrHit       Where to store the address of the first occurence on success.
  */
-VMMR3DECL(int) PGMR3DbgScanVirtual(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, RTGCPTR cbRange, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCUINTPTR pGCPtrHit)
+VMMR3DECL(int) PGMR3DbgScanVirtual(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, RTGCPTR cbRange, RTGCPTR GCPtrAlign,
+                                   const uint8_t *pabNeedle, size_t cbNeedle, PRTGCUINTPTR pGCPtrHit)
 {
     VMCPU_ASSERT_EMT(pVCpu);
@@ -600,16 +698,39 @@
         return VERR_DBGF_MEM_NOT_FOUND;
 
+    if (!GCPtrAlign)
+        return VERR_INVALID_PARAMETER;
+    if (GCPtrAlign > UINT32_MAX)
+        return VERR_NOT_POWER_OF_TWO;
+    if (GCPtrAlign & (GCPtrAlign - 1))
+        return VERR_INVALID_PARAMETER;
+
+    if (GCPtr & (GCPtrAlign - 1))
+    {
+        RTGCPTR Adj = GCPtrAlign - (GCPtr & (GCPtrAlign - 1));
+        if (    cbRange <= Adj
+            ||  GCPtr + Adj < GCPtr)
+            return VERR_DBGF_MEM_NOT_FOUND;
+        GCPtr   += Adj;
+        cbRange -= Adj;
+    }
+
     /*
      * Search the memory - ignore MMIO, zero and not-present pages.
      */
+    const bool      fAllZero  = ASMMemIsAll8(pabNeedle, cbNeedle, 0) == NULL;
     PGMMODE         enmMode   = PGMGetGuestMode(pVCpu);
     RTGCPTR         GCPtrMask = PGMMODE_IS_LONG_MODE(enmMode) ? UINT64_MAX : UINT32_MAX;
     uint8_t         abPrev[MAX_NEEDLE_SIZE];
     size_t          cbPrev    = 0;
+    const uint32_t  cIncPages = GCPtrAlign <= PAGE_SIZE
+                              ? 1
+                              : GCPtrAlign >> PAGE_SHIFT;
     const RTGCPTR   GCPtrLast = GCPtr + cbRange - 1 >= GCPtr
                               ? (GCPtr + cbRange - 1) & GCPtrMask
                               : GCPtrMask;
     RTGCPTR         cPages    = (((GCPtrLast - GCPtr) + (GCPtr & PAGE_OFFSET_MASK)) >> PAGE_SHIFT) + 1;
-    while (cPages-- > 0)
+    uint32_t        offPage   = GCPtr & PAGE_OFFSET_MASK;
+    GCPtr &= ~(RTGCPTR)PAGE_OFFSET_MASK;
+    for (;; offPage = 0)
     {
         RTGCPHYS GCPhys;
@@ -619,22 +740,30 @@
             PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);
             if (    pPage
-                &&  !PGM_PAGE_IS_ZERO(pPage) /** @todo handle all zero needle. */
+                &&  (   !PGM_PAGE_IS_ZERO(pPage)
+                     || fAllZero)
                 &&  !PGM_PAGE_IS_MMIO(pPage))
             {
                 void const *pvPage;
                 PGMPAGEMAPLOCK Lock;
-                rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys & ~(RTGCPTR)PAGE_OFFSET_MASK, &pvPage, &Lock);
+                rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys, &pvPage, &Lock);
                 if (RT_SUCCESS(rc))
                 {
-                    int32_t  offPage = (GCPtr & PAGE_OFFSET_MASK);
-                    uint32_t cbSearch = cPages > 0
-                                      ? PAGE_SIZE                          - (uint32_t)offPage
-                                      : (GCPtrLast & PAGE_OFFSET_MASK) + 1 - (uint32_t)offPage;
-                    bool fRc = pgmR3DbgScanPage((uint8_t const *)pvPage, &offPage, cbSearch,
-                                                pabNeedle, cbNeedle, &abPrev[0], &cbPrev);
+                    int32_t offHit = offPage;
+                    bool    fRc;
+                    if (GCPtrAlign < PAGE_SIZE)
+                    {
+                        uint32_t cbSearch = cPages > 0
+                                          ? PAGE_SIZE                          - (uint32_t)offPage
+                                          : (GCPtrLast & PAGE_OFFSET_MASK) + 1 - (uint32_t)offPage;
+                        fRc = pgmR3DbgScanPage((uint8_t const *)pvPage, &offHit, cbSearch, (uint32_t)GCPtrAlign,
+                                               pabNeedle, cbNeedle, &abPrev[0], &cbPrev);
+                    }
+                    else
+                        fRc = memcmp(pvPage, pabNeedle, cbNeedle) == 0
+                           && (GCPtrLast - GCPtr) >= cbNeedle;
                     PGMPhysReleasePageMappingLock(pVM, &Lock);
                     if (fRc)
                     {
-                        *pGCPtrHit = (GCPtr & ~(RTGCPTR)PAGE_OFFSET_MASK) + offPage;
+                        *pGCPtrHit = GCPtr + offHit;
                         return VINF_SUCCESS;
                     }
@@ -650,7 +779,8 @@
 
         /* advance to the next page. */
-        GCPtr |= PAGE_OFFSET_MASK;
-        GCPtr++;
-        GCPtr &= GCPtrMask;
+        if (cPages <= cIncPages)
+            break;
+        cPages -= cIncPages;
+        GCPtr += (RTGCPTR)cIncPages << PAGE_SHIFT;
     }
     return VERR_DBGF_MEM_NOT_FOUND;
Index: /trunk/src/VBox/VMM/VBoxVMMDeps.cpp
===================================================================
--- /trunk/src/VBox/VMM/VBoxVMMDeps.cpp	(revision 24060)
+++ /trunk/src/VBox/VMM/VBoxVMMDeps.cpp	(revision 24061)
@@ -43,4 +43,5 @@
     (PFNRT)DBGFR3StackWalkEnd,
     (PFNRT)DBGFR3AsSymbolByAddr,
+    (PFNRT)DBGFR3CpuGetMode,
     (PFNRT)DBGFR3MemScan,
     (PFNRT)EMInterpretInstruction,
