VirtualBox

source: vbox/trunk/src/VBox/Additions/common/testcase/tstPageFusion.cpp

Last change on this file was 106061, checked in by vboxsync, 7 weeks ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.9 KB
Line 
1/* $Id: tstPageFusion.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBoxService - Guest page sharing testcase
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <iprt/assert.h>
33#include <iprt/asm.h>
34#include <iprt/mem.h>
35#include <iprt/messages.h>
36#include <iprt/stream.h>
37#include <iprt/string.h>
38#include <iprt/initterm.h>
39#include <VBox/VBoxGuestLib.h>
40#include <iprt/x86.h>
41#include <stdio.h>
42
43
44/*********************************************************************************************************************************
45* Global Variables *
46*********************************************************************************************************************************/
47
48#ifdef RT_OS_WINDOWS
49#include <iprt/win/windows.h>
50#include <process.h> /* Needed for file version information. */
51#include <tlhelp32.h>
52#include <psapi.h>
53#include <winternl.h>
54
55#define SystemModuleInformation 11
56
57typedef struct _RTL_PROCESS_MODULE_INFORMATION
58{
59 ULONG Section;
60 PVOID MappedBase;
61 PVOID ImageBase;
62 ULONG ImageSize;
63 ULONG Flags;
64 USHORT LoadOrderIndex;
65 USHORT InitOrderIndex;
66 USHORT LoadCount;
67 USHORT OffsetToFileName;
68 CHAR FullPathName[256];
69} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;
70
71typedef struct _RTL_PROCESS_MODULES
72{
73 ULONG NumberOfModules;
74 RTL_PROCESS_MODULE_INFORMATION Modules[1];
75} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;
76
77typedef NTSTATUS (WINAPI *PFNZWQUERYSYSTEMINFORMATION)(ULONG, PVOID, ULONG, PULONG);
78static PFNZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = NULL;
79static HMODULE hNtdll = 0;
80
81#define PAGE_STATE_INVALID 0
82#define PAGE_STATE_SHARED 1
83#define PAGE_STATE_READ_WRITE 2
84#define PAGE_STATE_READ_ONLY 3
85#define PAGE_STATE_NOT_PRESENT 4
86
87/* Page counters. */
88static unsigned cNotPresentPages = 0;
89static unsigned cWritablePages = 0;
90static unsigned cSharedPages = 0;
91static unsigned cPrivatePages = 0;
92
93/**
94 * Registers a new module with the VMM
95 * @param pModule Module ptr
96 */
97void VBoxServicePageSharingCheckModule(MODULEENTRY32 *pModule)
98{
99 DWORD dwModuleSize = pModule->modBaseSize;
100 BYTE *pBaseAddress = pModule->modBaseAddr;
101 bool fFirstLine = true;
102 unsigned uPageState, uLastPageState;
103 bool fLastWritable = false;
104 BYTE *pLastBaseAddress = pBaseAddress;
105
106 uPageState = uLastPageState = PAGE_STATE_INVALID;
107
108 printf("Check module %s base %p size %x\n", pModule->szModule, pBaseAddress, dwModuleSize);
109 do
110 {
111 bool fShared;
112 uint64_t uPageFlags;
113
114#ifdef RT_ARCH_X86
115 int rc = VbglR3PageIsShared((uint32_t)pLastBaseAddress, &fShared, &uPageFlags);
116#else
117 int rc = VbglR3PageIsShared((RTGCPTR)pLastBaseAddress, &fShared, &uPageFlags);
118#endif
119 if (RT_FAILURE(rc))
120 printf("VbglR3PageIsShared %p failed with %d\n", pLastBaseAddress, rc);
121
122 if (RT_SUCCESS(rc))
123 {
124 if (uPageFlags & X86_PTE_P)
125 {
126 if (uPageFlags & X86_PTE_RW)
127 {
128 cWritablePages++;
129 uPageState = PAGE_STATE_READ_WRITE;
130 }
131 else
132 if (fShared)
133 {
134 cSharedPages++;
135 uPageState = PAGE_STATE_SHARED;
136 }
137 else
138 {
139 cPrivatePages++;
140 uPageState = PAGE_STATE_READ_ONLY;
141 }
142 }
143 else
144 {
145 cNotPresentPages++;
146 uPageState = PAGE_STATE_NOT_PRESENT;
147 }
148
149 if ( !fFirstLine
150 && uPageState != uLastPageState)
151 {
152 printf("0x%p\n", pLastBaseAddress + 0xfff);
153 }
154
155 if (uPageState != uLastPageState)
156 {
157 switch (uPageState)
158 {
159 case PAGE_STATE_READ_WRITE:
160 printf("%s RW 0x%p - ", pModule->szModule, pBaseAddress);
161 break;
162 case PAGE_STATE_SHARED:
163 printf("%s SHARED 0x%p - ", pModule->szModule, pBaseAddress);
164 break;
165 case PAGE_STATE_READ_ONLY:
166 printf("%s PRIV 0x%p - ", pModule->szModule, pBaseAddress);
167 break;
168 case PAGE_STATE_NOT_PRESENT:
169 printf("%s NP 0x%p - ", pModule->szModule, pBaseAddress);
170 break;
171 }
172
173 fFirstLine = false;
174 }
175 uLastPageState = uPageState;
176 }
177 else
178 if (!fFirstLine)
179 {
180 printf("0x%p\n", pLastBaseAddress + 0xfff);
181 fFirstLine = true;
182 }
183
184 if (dwModuleSize > PAGE_SIZE)
185 dwModuleSize -= PAGE_SIZE;
186 else
187 dwModuleSize = 0;
188
189 pLastBaseAddress = pBaseAddress;
190 pBaseAddress += PAGE_SIZE;
191 }
192 while (dwModuleSize);
193
194 printf("0x%p\n", pLastBaseAddress + 0xfff);
195 return;
196}
197
198/**
199 * Inspect all loaded modules for the specified process
200 * @param dwProcessId Process id
201 */
202void VBoxServicePageSharingInspectModules(DWORD dwProcessId)
203{
204 HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
205 if (hSnapshot == INVALID_HANDLE_VALUE)
206 {
207 printf("VBoxServicePageSharingInspectModules: CreateToolhelp32Snapshot failed with %d\n", GetLastError());
208 return;
209 }
210
211 printf("VBoxServicePageSharingInspectModules\n");
212
213 MODULEENTRY32 ModuleInfo;
214 BOOL bRet;
215
216 ModuleInfo.dwSize = sizeof(ModuleInfo);
217 bRet = Module32First(hSnapshot, &ModuleInfo);
218 do
219 {
220 /** @todo when changing this make sure VBoxService.exe is excluded! */
221 char *pszDot = strrchr(ModuleInfo.szModule, '.');
222 if ( pszDot
223 && (pszDot[1] == 'e' || pszDot[1] == 'E'))
224 continue; /* ignore executables for now. */
225
226 VBoxServicePageSharingCheckModule(&ModuleInfo);
227 }
228 while (Module32Next(hSnapshot, &ModuleInfo));
229
230 CloseHandle(hSnapshot);
231}
232
233/**
234 * Inspect all running processes for executables and dlls that might be worth sharing
235 * with other VMs.
236 *
237 */
238void VBoxServicePageSharingInspectGuest()
239{
240 VBoxServicePageSharingInspectModules(GetCurrentProcessId());
241
242 printf("\n\nUSER RESULTS\n");
243 printf("cNotPresentPages = %d\n", cNotPresentPages);
244 printf("cWritablePages = %d\n", cWritablePages);
245 printf("cPrivatePages = %d\n", cPrivatePages);
246 printf("cSharedPages = %d\n", cSharedPages);
247
248 cNotPresentPages = 0;
249 cWritablePages = 0;
250 cPrivatePages = 0;
251 cSharedPages = 0;
252
253 /* Check all loaded kernel modules. */
254 if (ZwQuerySystemInformation)
255 {
256 ULONG cbBuffer = 0;
257 PVOID pBuffer = NULL;
258 PRTL_PROCESS_MODULES pSystemModules;
259
260 NTSTATUS ret = ZwQuerySystemInformation(SystemModuleInformation, (PVOID)&cbBuffer, 0, &cbBuffer);
261 if (!cbBuffer)
262 {
263 printf("ZwQuerySystemInformation returned length 0\n");
264 goto skipkernelmodules;
265 }
266
267 pBuffer = RTMemAllocZ(cbBuffer);
268 if (!pBuffer)
269 goto skipkernelmodules;
270
271 ret = ZwQuerySystemInformation(SystemModuleInformation, pBuffer, cbBuffer, &cbBuffer);
272 if (ret != 0)
273 {
274 printf("ZwQuerySystemInformation returned %x (1)\n", ret);
275 goto skipkernelmodules;
276 }
277
278 pSystemModules = (PRTL_PROCESS_MODULES)pBuffer;
279 for (unsigned i = 0; i < pSystemModules->NumberOfModules; i++)
280 {
281 /* User-mode modules seem to have no flags set; skip them as we detected them above. */
282 if (pSystemModules->Modules[i].Flags == 0)
283 continue;
284
285 /* New module; register it. */
286 char szFullFilePath[512];
287 MODULEENTRY32 ModuleInfo;
288
289 strcpy(ModuleInfo.szModule, &pSystemModules->Modules[i].FullPathName[pSystemModules->Modules[i].OffsetToFileName]);
290 GetSystemDirectoryA(szFullFilePath, sizeof(szFullFilePath));
291
292 /* skip \Systemroot\system32 */
293 char *lpPath = strchr(&pSystemModules->Modules[i].FullPathName[1], '\\');
294 if (!lpPath)
295 {
296 printf("Unexpected kernel module name %s\n", pSystemModules->Modules[i].FullPathName);
297 break;
298 }
299
300 lpPath = strchr(lpPath+1, '\\');
301 if (!lpPath)
302 {
303 printf("Unexpected kernel module name %s\n", pSystemModules->Modules[i].FullPathName);
304 break;
305 }
306
307 strcat(szFullFilePath, lpPath);
308 strcpy(ModuleInfo.szExePath, szFullFilePath);
309 ModuleInfo.modBaseAddr = (BYTE *)pSystemModules->Modules[i].ImageBase;
310 ModuleInfo.modBaseSize = pSystemModules->Modules[i].ImageSize;
311
312 VBoxServicePageSharingCheckModule(&ModuleInfo);
313 }
314skipkernelmodules:
315 if (pBuffer)
316 RTMemFree(pBuffer);
317 }
318 printf("\n\nKERNEL RESULTS\n");
319 printf("cNotPresentPages = %d\n", cNotPresentPages);
320 printf("cWritablePages = %d\n", cWritablePages);
321 printf("cPrivatePages = %d\n", cPrivatePages);
322 printf("cSharedPages = %d\n", cSharedPages);
323}
324#else
325void VBoxServicePageSharingInspectGuest()
326{
327 /** @todo other platforms */
328}
329#endif
330
331
332/** @copydoc VBOXSERVICE::pfnInit */
333static DECLCALLBACK(int) VBoxServicePageSharingInit(void)
334{
335 printf("VBoxServicePageSharingInit\n");
336
337#ifdef RT_OS_WINDOWS
338 hNtdll = LoadLibrary("ntdll.dll");
339
340 if (hNtdll)
341 ZwQuerySystemInformation = (PFNZWQUERYSYSTEMINFORMATION)GetProcAddress(hNtdll, "ZwQuerySystemInformation");
342#endif
343
344 /** @todo report system name and version */
345 /* Never fail here. */
346 return VINF_SUCCESS;
347}
348
349static DECLCALLBACK(void) VBoxServicePageSharingTerm(void)
350{
351 printf("VBoxServicePageSharingTerm\n");
352
353#ifdef RT_OS_WINDOWS
354 if (hNtdll)
355 FreeLibrary(hNtdll);
356#endif
357 return;
358}
359
360int main(int argc, char **argv)
361{
362 /*
363 * Init globals and such.
364 */
365 int rc = RTR3InitExe(argc, &argv, 0);
366 if (RT_FAILURE(rc))
367 return RTMsgInitFailure(rc);
368
369 /*
370 * Connect to the kernel part before daemonizing so we can fail
371 * and complain if there is some kind of problem. We need to initialize
372 * the guest lib *before* we do the pre-init just in case one of services
373 * needs do to some initial stuff with it.
374 */
375 printf("Calling VbgR3Init()\n");
376 rc = VbglR3Init();
377 if (RT_FAILURE(rc))
378 {
379 printf("VbglR3Init failed with rc=%Rrc.\n", rc);
380 return -1;
381 }
382 VBoxServicePageSharingInit();
383
384 VBoxServicePageSharingInspectGuest();
385
386 VBoxServicePageSharingTerm();
387 return 0;
388}
389
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