Index: /trunk/src/VBox/Additions/common/testcase/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Additions/common/testcase/Makefile.kmk	(revision 30063)
+++ /trunk/src/VBox/Additions/common/testcase/Makefile.kmk	(revision 30063)
@@ -0,0 +1,41 @@
+# $Id: Makefile.kmk 61727 2010-05-17 19:41:27Z fmehnert $
+## @file
+# Sub-Makefile for the Cross Platform Guest Addition test cases.
+#
+
+#
+# Copyright (C) 2007-2010 Oracle Corporation
+#
+# 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.
+#
+
+SUB_DEPTH = ../../../../..
+include	$(KBUILD_PATH)/subheader.kmk
+
+#
+# Target lists.
+#
+PROGRAMS += tstPageFusion
+
+#
+# tstPageFusion
+#
+tstPageFusion_TEMPLATE      = VBOXGUESTR3EXE
+tstPageFusion_DEFS.win     += _WIN32_WINNT=0x0501
+
+tstPageFusion_SOURCES       = \
+	tstPageFusion.cpp
+
+tstPageFusion_LIBS          = \
+	$(VBOX_LIB_IPRT_GUEST_R3) \
+	$(VBOX_LIB_VBGL_R3) \
+	$(VBOX_LIB_IPRT_GUEST_R3)
+
+include	$(KBUILD_PATH)/subfooter.kmk
+
Index: /trunk/src/VBox/Additions/common/testcase/tstPageFusion.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/testcase/tstPageFusion.cpp	(revision 30063)
+++ /trunk/src/VBox/Additions/common/testcase/tstPageFusion.cpp	(revision 30063)
@@ -0,0 +1,366 @@
+/* $Id: VBoxServicePageSharing.cpp 62335 2010-06-03 14:40:59Z bird $ */
+/** @file
+ * VBoxService - Guest page sharing testcase
+ */
+
+/*
+ * Copyright (C) 2006-2010 Oracle Corporation
+ *
+ * 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.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#include <iprt/mem.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/initterm.h>
+#include <VBox/VBoxGuestLib.h>
+#include <VBox/x86.h>
+#include <stdio.h>
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+
+#ifdef RT_OS_WINDOWS
+#include <Windows.h>
+#include <process.h> /* Needed for file version information. */
+#include <tlhelp32.h>
+#include <psapi.h>
+#include <winternl.h>
+
+#define SystemModuleInformation     11
+
+typedef struct _RTL_PROCESS_MODULE_INFORMATION
+{
+    ULONG Section;
+    PVOID MappedBase;
+    PVOID ImageBase;
+    ULONG ImageSize;
+    ULONG Flags;
+    USHORT LoadOrderIndex;
+    USHORT InitOrderIndex;
+    USHORT LoadCount;
+    USHORT OffsetToFileName;
+    CHAR FullPathName[256];
+} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;
+
+typedef struct _RTL_PROCESS_MODULES
+{
+    ULONG NumberOfModules;
+    RTL_PROCESS_MODULE_INFORMATION Modules[1];
+} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;
+
+typedef NTSTATUS (WINAPI *PFNZWQUERYSYSTEMINFORMATION)(ULONG, PVOID, ULONG, PULONG);
+static PFNZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = NULL;
+static HMODULE hNtdll = 0;
+
+#define PAGE_STATE_INVALID           0
+#define PAGE_STATE_SHARED            1
+#define PAGE_STATE_READ_WRITE        2
+#define PAGE_STATE_READ_ONLY         3
+#define PAGE_STATE_NOT_PRESENT       4
+
+/* Page counters. */
+static unsigned cNotPresentPages = 0;
+static unsigned cWritablePages   = 0;
+static unsigned cSharedPages     = 0;
+static unsigned cPrivatePages    = 0;
+
+/**
+ * Registers a new module with the VMM
+ * @param   pModule         Module ptr
+ */
+void VBoxServicePageSharingCheckModule(MODULEENTRY32 *pModule)
+{
+    DWORD       dwModuleSize = pModule->modBaseSize;
+    BYTE       *pBaseAddress = pModule->modBaseAddr;
+    bool        fFirstLine = true;
+    unsigned    uPageState, uLastPageState;
+    bool        fLastWritable = false;
+    BYTE       *pLastBaseAddress = pBaseAddress;
+
+    uPageState = uLastPageState = PAGE_STATE_INVALID;
+
+    printf("Check module %s base %p size %x\n", pModule->szModule, pBaseAddress, dwModuleSize);
+    do
+    {
+        bool     fShared;
+        uint64_t uPageFlags;
+
+#ifdef RT_ARCH_X86
+        int rc = VbglR3PageIsShared((uint32_t)pLastBaseAddress, &fShared, &uPageFlags);
+#else
+        int rc = VbglR3PageIsShared((RTGCPTR)pLastBaseAddress, &fShared, &uPageFlags);
+#endif
+        if (RT_FAILURE(rc))
+            printf("VbglR3PageIsShared %p failed with %d\n", pLastBaseAddress, rc);
+
+        if (RT_SUCCESS(rc))
+        {
+            if (uPageFlags & X86_PTE_P)
+            {
+                if (uPageFlags & X86_PTE_RW)
+                {
+                    cWritablePages++;
+                    uPageState = PAGE_STATE_READ_WRITE;
+                }
+                else
+                if (fShared)
+                {
+                    cSharedPages++;
+                    uPageState = PAGE_STATE_SHARED;
+                }
+                else
+                {
+                    cPrivatePages++;
+                    uPageState = PAGE_STATE_READ_ONLY;
+                }
+            }
+            else
+            {
+                cNotPresentPages++;
+                uPageState = PAGE_STATE_NOT_PRESENT;
+            }
+
+            if (    !fFirstLine
+                &&  uPageState != uLastPageState)
+            {
+                printf("0x%p\n", pLastBaseAddress + 0xfff);
+            }
+
+            if (uPageState != uLastPageState)
+            {
+                switch (uPageState)
+                {
+                case PAGE_STATE_READ_WRITE:
+                    printf("%s RW     0x%p - ", pModule->szModule, pBaseAddress);
+                    break;
+                case PAGE_STATE_SHARED:
+                    printf("%s SHARED 0x%p - ", pModule->szModule, pBaseAddress);
+                    break;
+                case PAGE_STATE_READ_ONLY:
+                    printf("%s PRIV   0x%p - ", pModule->szModule, pBaseAddress);
+                    break;
+                case PAGE_STATE_NOT_PRESENT:
+                    printf("%s NP     0x%p - ", pModule->szModule, pBaseAddress);
+                    break;
+                }
+
+                fFirstLine       = false;
+            }
+            uLastPageState = uPageState;
+        }
+        else
+        if (!fFirstLine)
+        {
+            printf("0x%p\n", pLastBaseAddress + 0xfff);
+            fFirstLine = true;
+        }
+
+        if (dwModuleSize > PAGE_SIZE)
+            dwModuleSize -= PAGE_SIZE;
+        else
+            dwModuleSize = 0;
+
+        pLastBaseAddress  = pBaseAddress;
+        pBaseAddress     += PAGE_SIZE;
+    }
+    while (dwModuleSize);
+
+    printf("0x%p\n", pLastBaseAddress + 0xfff);
+    return;
+}
+
+/**
+ * Inspect all loaded modules for the specified process
+ * @param   dwProcessId     Process id
+ */
+void VBoxServicePageSharingInspectModules(DWORD dwProcessId)
+{
+    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
+    if (hSnapshot == INVALID_HANDLE_VALUE)
+    {
+        printf("VBoxServicePageSharingInspectModules: CreateToolhelp32Snapshot failed with %d\n", GetLastError());
+        return;
+    }
+
+    printf("VBoxServicePageSharingInspectModules\n");
+
+    MODULEENTRY32 ModuleInfo;
+    BOOL          bRet;
+
+    ModuleInfo.dwSize = sizeof(ModuleInfo);
+    bRet = Module32First(hSnapshot, &ModuleInfo);
+    do
+    {
+        /** todo when changing this make sure VBoxService.exe is excluded! */
+        char *pszDot = strrchr(ModuleInfo.szModule, '.');
+        if (    pszDot
+            &&  (pszDot[1] == 'e' || pszDot[1] == 'E'))
+            continue;   /* ignore executables for now. */
+
+        VBoxServicePageSharingCheckModule(&ModuleInfo);
+    }
+    while (Module32Next(hSnapshot, &ModuleInfo));
+
+    CloseHandle(hSnapshot);
+}
+
+/**
+ * Inspect all running processes for executables and dlls that might be worth sharing
+ * with other VMs.
+ *
+ */
+void VBoxServicePageSharingInspectGuest()
+{
+    VBoxServicePageSharingInspectModules(GetCurrentProcessId());
+
+    /* Check all loaded kernel modules. */
+    if (ZwQuerySystemInformation)
+    {
+        ULONG                cbBuffer = 0;
+        PVOID                pBuffer = NULL;
+        PRTL_PROCESS_MODULES pSystemModules;
+
+        NTSTATUS ret = ZwQuerySystemInformation(SystemModuleInformation, (PVOID)&cbBuffer, 0, &cbBuffer);
+        if (!cbBuffer)
+        {
+            printf("ZwQuerySystemInformation returned length 0\n");
+            goto skipkernelmodules;
+        }
+
+        pBuffer = RTMemAllocZ(cbBuffer);
+        if (!pBuffer)
+            goto skipkernelmodules;
+
+        ret = ZwQuerySystemInformation(SystemModuleInformation, pBuffer, cbBuffer, &cbBuffer);
+        if (ret != 0)
+        {
+            printf("ZwQuerySystemInformation returned %x (1)\n", ret);
+            goto skipkernelmodules;
+        }
+
+        pSystemModules = (PRTL_PROCESS_MODULES)pBuffer;
+        for (unsigned i = 0; i < pSystemModules->NumberOfModules; i++)
+        {
+            /* User-mode modules seem to have no flags set; skip them as we detected them above. */
+            if (pSystemModules->Modules[i].Flags == 0)
+                continue;
+
+            /* New module; register it. */
+            char          szFullFilePath[512];
+            MODULEENTRY32 ModuleInfo;
+
+            strcpy(ModuleInfo.szModule, &pSystemModules->Modules[i].FullPathName[pSystemModules->Modules[i].OffsetToFileName]);
+            GetSystemDirectoryA(szFullFilePath, sizeof(szFullFilePath));
+
+            /* skip \Systemroot\system32 */
+            char *lpPath = strchr(&pSystemModules->Modules[i].FullPathName[1], '\\');
+            if (!lpPath)
+            {
+                printf("Unexpected kernel module name %s\n", pSystemModules->Modules[i].FullPathName);
+                break;
+            }
+
+            lpPath = strchr(lpPath+1, '\\');
+            if (!lpPath)
+            {
+                printf("Unexpected kernel module name %s\n", pSystemModules->Modules[i].FullPathName);
+                break;
+            }
+
+            strcat(szFullFilePath, lpPath);
+            strcpy(ModuleInfo.szExePath, szFullFilePath);
+            ModuleInfo.modBaseAddr = (BYTE *)pSystemModules->Modules[i].ImageBase;
+            ModuleInfo.modBaseSize = pSystemModules->Modules[i].ImageSize;
+
+            VBoxServicePageSharingCheckModule(&ModuleInfo);
+        }
+skipkernelmodules:
+        if (pBuffer)
+            RTMemFree(pBuffer);
+    }
+}
+#else
+void VBoxServicePageSharingInspectGuest()
+{
+    /* @todo other platforms */
+}
+#endif
+
+
+/** @copydoc VBOXSERVICE::pfnInit */
+static DECLCALLBACK(int) VBoxServicePageSharingInit(void)
+{
+    printf("VBoxServicePageSharingInit\n");
+
+#ifdef RT_OS_WINDOWS
+    hNtdll = LoadLibrary("ntdll.dll");
+
+    if (hNtdll)
+        ZwQuerySystemInformation = (PFNZWQUERYSYSTEMINFORMATION)GetProcAddress(hNtdll, "ZwQuerySystemInformation");
+#endif
+
+    /* @todo report system name and version */
+    /* Never fail here. */
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(void) VBoxServicePageSharingTerm(void)
+{
+    printf("VBoxServicePageSharingTerm\n");
+
+    printf("\n\nRESULT\n");
+    printf("cNotPresentPages = %d\n", cNotPresentPages);
+    printf("cWritablePages   = %d\n", cNotPresentPages);
+    printf("cPrivatePages    = %d\n", cNotPresentPages);
+    printf("cSharedPages     = %d\n", cNotPresentPages);
+
+#ifdef RT_OS_WINDOWS
+    if (hNtdll)
+        FreeLibrary(hNtdll);
+#endif
+    return;
+}
+
+int main(int argc, char **argv)
+{
+    int rc = VINF_SUCCESS;
+    /*
+     * Init globals and such.
+     */
+    RTR3Init();
+
+    /*
+     * Connect to the kernel part before daemonizing so we can fail
+     * and complain if there is some kind of problem. We need to initialize
+     * the guest lib *before* we do the pre-init just in case one of services
+     * needs do to some initial stuff with it.
+     */
+    printf("Calling VbgR3Init()\n");
+    rc = VbglR3Init();
+    if (RT_FAILURE(rc))
+    {
+        printf("VbglR3Init failed with rc=%Rrc.\n", rc);
+        return -1;
+    }
+    VBoxServicePageSharingInit();
+
+    VBoxServicePageSharingInspectGuest();
+
+    VBoxServicePageSharingTerm();
+    return 0;
+}
+
