VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxServicePageSharing.cpp@ 29531

Last change on this file since 29531 was 29514, checked in by vboxsync, 15 years ago

Skip our own process

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.5 KB
Line 
1/* $Id: VBoxServicePageSharing.cpp 29514 2010-05-17 09:35:20Z vboxsync $ */
2/** @file
3 * VBoxService - Guest page sharing.
4 */
5
6/*
7 * Copyright (C) 2006-2010 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/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include <iprt/assert.h>
23#include <iprt/avl.h>
24#include <iprt/mem.h>
25#include <iprt/stream.h>
26#include <iprt/string.h>
27#include <iprt/semaphore.h>
28#include <iprt/system.h>
29#include <iprt/thread.h>
30#include <iprt/time.h>
31#include <VBox/VBoxGuestLib.h>
32#include "VBoxServiceInternal.h"
33#include "VBoxServiceUtils.h"
34
35
36/*******************************************************************************
37* Global Variables *
38*******************************************************************************/
39
40/** The semaphore we're blocking on. */
41static RTSEMEVENTMULTI g_PageSharingEvent = NIL_RTSEMEVENTMULTI;
42
43#if defined(RT_OS_WINDOWS) && !defined(TARGET_NT4)
44#include <tlhelp32.h>
45#include <psapi.h>
46
47typedef struct
48{
49 AVLPVNODECORE Core;
50 HMODULE hModule;
51 char szFileVersion[16];
52 MODULEENTRY32 Info;
53} KNOWN_MODULE, *PKNOWN_MODULE;
54
55static DECLCALLBACK(int) VBoxServicePageSharingEmptyTreeCallback(PAVLPVNODECORE pNode, void *);
56
57static PAVLPVNODECORE pKnownModuleTree = NULL;
58
59/**
60 * Registers a new module with the VMM
61 * @param pModule Module ptr
62 */
63void VBoxServicePageSharingRegisterModule(PKNOWN_MODULE pModule)
64{
65 VMMDEVSHAREDREGIONDESC aRegions[VMMDEVSHAREDREGIONDESC_MAX];
66 DWORD dwModuleSize = pModule->Info.modBaseSize;
67 BYTE *pBaseAddress = pModule->Info.modBaseAddr;
68 DWORD cbVersionSize, dummy;
69 BYTE *pVersionInfo;
70
71 VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule\n");
72
73 cbVersionSize = GetFileVersionInfoSize(pModule->Info.szExePath, &dummy);
74 if (!cbVersionSize)
75 {
76 VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule: GetFileVersionInfoSize failed with %d\n", GetLastError());
77 return;
78 }
79 pVersionInfo = (BYTE *)RTMemAlloc(cbVersionSize);
80 if (!pVersionInfo)
81 return;
82
83 if (!GetFileVersionInfo(pModule->Info.szExePath, 0, cbVersionSize, pVersionInfo))
84 {
85 VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule: GetFileVersionInfo failed with %d\n", GetLastError());
86 goto end;
87 }
88
89 /* Fetch default code page. */
90 struct LANGANDCODEPAGE {
91 WORD wLanguage;
92 WORD wCodePage;
93 } *lpTranslate;
94
95 UINT cbTranslate;
96 BOOL ret = VerQueryValue(pVersionInfo, TEXT("\\VarFileInfo\\Translation"), (LPVOID *)&lpTranslate, &cbTranslate);
97 if ( !ret
98 || cbTranslate < 4)
99 {
100 VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule: VerQueryValue failed with %d (cb=%d)\n", GetLastError(), cbTranslate);
101 goto end;
102 }
103
104 unsigned i;
105 UINT cbFileVersion;
106 char *lpszFileVersion;
107 unsigned cTranslationBlocks = cbTranslate/sizeof(struct LANGANDCODEPAGE);
108
109 for(i = 0; i < cTranslationBlocks; i++)
110 {
111 /* Fetch file version string. */
112 char szFileVersionLocation[256];
113
114 sprintf(szFileVersionLocation, TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"), lpTranslate[i].wLanguage, lpTranslate[i].wCodePage);
115 ret = VerQueryValue(pVersionInfo, szFileVersionLocation, (LPVOID *)&lpszFileVersion, &cbFileVersion);
116 if (ret)
117 break;
118 }
119 if (i == cTranslationBlocks)
120 {
121 VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule: no file version found!\n");
122 goto end;
123 }
124
125 _snprintf(pModule->szFileVersion, sizeof(pModule->szFileVersion), "%s", lpszFileVersion);
126 pModule->szFileVersion[RT_ELEMENTS(pModule->szFileVersion) - 1] = 0;
127
128 unsigned idxRegion = 0;
129 do
130 {
131 MEMORY_BASIC_INFORMATION MemInfo;
132
133 SIZE_T ret = VirtualQuery(pBaseAddress, &MemInfo, sizeof(MemInfo));
134 Assert(ret);
135 if (!ret)
136 {
137 VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule: VirtualQueryEx failed with %d\n", GetLastError());
138 break;
139 }
140
141 if ( MemInfo.State == MEM_COMMIT
142 && MemInfo.Type == MEM_IMAGE)
143 {
144 switch (MemInfo.Protect)
145 {
146 case PAGE_EXECUTE:
147 case PAGE_EXECUTE_READ:
148 case PAGE_READONLY:
149 {
150 char *pRegion = (char *)MemInfo.BaseAddress;
151
152 /* Skip the first region as it only contains the image file header. */
153 if (pRegion != (char *)pModule->Info.modBaseAddr)
154 {
155 /* Touch all pages. */
156 while (pRegion < (char *)MemInfo.BaseAddress + MemInfo.RegionSize)
157 {
158 char dummy;
159
160 memcpy(&dummy, pRegion, 1);
161 pRegion += PAGE_SIZE;
162 }
163 }
164 aRegions[idxRegion].GCRegionAddr = (RTGCPTR64)MemInfo.BaseAddress;
165 aRegions[idxRegion].cbRegion = MemInfo.RegionSize;
166 idxRegion++;
167
168 break;
169 }
170
171 default:
172 break; /* ignore */
173 }
174 }
175
176 pBaseAddress = (BYTE *)MemInfo.BaseAddress + MemInfo.RegionSize;
177 if (dwModuleSize > MemInfo.RegionSize)
178 {
179 dwModuleSize -= MemInfo.RegionSize;
180 }
181 else
182 {
183 dwModuleSize = 0;
184 break;
185 }
186
187 if (idxRegion >= RT_ELEMENTS(aRegions))
188 break; /* out of room */
189 }
190 while (dwModuleSize);
191
192 VBoxServiceVerbose(3, "VbglR3RegisterSharedModule %s %s base=%p size=%x cregions=%d\n", pModule->Info.szModule, pModule->szFileVersion, pModule->Info.modBaseAddr, pModule->Info.modBaseSize, idxRegion);
193 int rc = VbglR3RegisterSharedModule(pModule->Info.szModule, pModule->szFileVersion, (RTGCPTR64)pModule->Info.modBaseAddr,
194 pModule->Info.modBaseSize, idxRegion, aRegions);
195// AssertRC(rc);
196 if (RT_FAILURE(rc))
197 VBoxServiceVerbose(3, "VbglR3RegisterSharedModule failed with %d\n", rc);
198
199
200end:
201 RTMemFree(pVersionInfo);
202 return;
203}
204
205/**
206 * Inspect all loaded modules for the specified process
207 * @param dwProcessId Process id
208 */
209void VBoxServicePageSharingInspectModules(DWORD dwProcessId, PAVLPVNODECORE *ppNewTree)
210{
211 HANDLE hProcess, hSnapshot;
212
213 /* Get a list of all the modules in this process. */
214 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,
215 FALSE /* no child process handle inheritance */, dwProcessId);
216 if (hProcess == NULL)
217 {
218 VBoxServiceVerbose(3, "VBoxServicePageSharingInspectModules: OpenProcess %x failed with %d\n", dwProcessId, GetLastError());
219 return;
220 }
221
222 hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
223 if (hSnapshot == INVALID_HANDLE_VALUE)
224 {
225 VBoxServiceVerbose(3, "VBoxServicePageSharingInspectModules: CreateToolhelp32Snapshot failed with %d\n", GetLastError());
226 CloseHandle(hProcess);
227 return;
228 }
229
230 VBoxServiceVerbose(3, "VBoxServicePageSharingInspectModules\n");
231
232 MODULEENTRY32 ModuleInfo;
233 BOOL bRet;
234
235 ModuleInfo.dwSize = sizeof(ModuleInfo);
236 bRet = Module32First(hSnapshot, &ModuleInfo);
237 do
238 {
239 /** todo when changing this make sure VBoxService.exe is excluded! */
240 char *pszDot = strrchr(ModuleInfo.szModule, '.');
241 if ( pszDot
242 && (pszDot[1] == 'e' || pszDot[1] == 'E'))
243 continue; /* ignore executables for now. */
244
245 /* Found it before? */
246 PAVLPVNODECORE pRec = RTAvlPVGet(ppNewTree, ModuleInfo.modBaseAddr);
247 if (!pRec)
248 {
249 pRec = RTAvlPVRemove(&pKnownModuleTree, ModuleInfo.modBaseAddr);
250 if (!pRec)
251 {
252 /* New module; register it. */
253 PKNOWN_MODULE pModule = (PKNOWN_MODULE)RTMemAllocZ(sizeof(*pModule));
254 Assert(pModule);
255 if (!pModule)
256 break;
257
258 pModule->Info = ModuleInfo;
259 pModule->Core.Key = ModuleInfo.modBaseAddr;
260 pModule->hModule = LoadLibraryEx(ModuleInfo.szExePath, 0, DONT_RESOLVE_DLL_REFERENCES);
261 if (pModule->hModule)
262 VBoxServicePageSharingRegisterModule(pModule);
263
264 pRec = &pModule->Core;
265 }
266 bool ret = RTAvlPVInsert(ppNewTree, pRec);
267 Assert(ret); NOREF(ret);
268
269 VBoxServiceVerbose(3, "\n\n MODULE NAME: %s", ModuleInfo.szModule );
270 VBoxServiceVerbose(3, "\n executable = %s", ModuleInfo.szExePath );
271 VBoxServiceVerbose(3, "\n process ID = 0x%08X", ModuleInfo.th32ProcessID );
272 VBoxServiceVerbose(3, "\n base address = 0x%08X", (DWORD) ModuleInfo.modBaseAddr );
273 VBoxServiceVerbose(3, "\n base size = %d", ModuleInfo.modBaseSize );
274 }
275 }
276 while (Module32Next(hSnapshot, &ModuleInfo));
277
278 CloseHandle(hSnapshot);
279 CloseHandle(hProcess);
280}
281
282/**
283 * Inspect all running processes for executables and dlls that might be worth sharing
284 * with other VMs.
285 *
286 */
287void VBoxServicePageSharingInspectGuest()
288{
289 HANDLE hSnapshot;
290 PAVLPVNODECORE pNewTree = NULL;
291 DWORD dwProcessId = GetCurrentProcessId();
292
293 VBoxServiceVerbose(3, "VBoxServicePageSharingInspectGuest\n");
294
295 hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
296 if (hSnapshot == INVALID_HANDLE_VALUE)
297 {
298 VBoxServiceVerbose(3, "CreateToolhelp32Snapshot failed with %d\n", GetLastError());
299 return;
300 }
301
302 /* Check loaded modules for all running processes. */
303 PROCESSENTRY32 ProcessInfo;
304
305 ProcessInfo.dwSize = sizeof(ProcessInfo);
306 Process32First(hSnapshot, &ProcessInfo);
307
308 do
309 {
310 /* Skip our own process. */
311 if (ProcessInfo.th32ProcessID != dwProcessId)
312 VBoxServicePageSharingInspectModules(ProcessInfo.th32ProcessID, &pNewTree);
313 }
314 while (Process32Next(hSnapshot, &ProcessInfo));
315
316 CloseHandle(hSnapshot);
317
318 /* Delete leftover modules in the old tree. */
319 RTAvlPVDestroy(&pKnownModuleTree, VBoxServicePageSharingEmptyTreeCallback, NULL);
320
321 /* Check all registered modules. */
322 VbglR3CheckSharedModules();
323
324 /* Activate new module tree. */
325 pKnownModuleTree = pNewTree;
326}
327
328/**
329 * RTAvlPVDestroy callback.
330 */
331static DECLCALLBACK(int) VBoxServicePageSharingEmptyTreeCallback(PAVLPVNODECORE pNode, void *)
332{
333 PKNOWN_MODULE pModule = (PKNOWN_MODULE)pNode;
334
335 VBoxServiceVerbose(3, "VBoxServicePageSharingEmptyTreeCallback %s %s\n", pModule->Info.szModule, pModule->szFileVersion);
336
337 /* Defererence module in the hypervisor. */
338 int rc = VbglR3UnregisterSharedModule(pModule->Info.szModule, pModule->szFileVersion, (RTGCPTR64)pModule->Info.modBaseAddr, pModule->Info.modBaseSize);
339 AssertRC(rc);
340
341 if (pModule->hModule)
342 FreeLibrary(pModule->hModule);
343 RTMemFree(pNode);
344 return 0;
345}
346
347
348#elif TARGET_NT4
349void VBoxServicePageSharingInspectGuest()
350{
351 /* not implemented */
352}
353#else
354void VBoxServicePageSharingInspectGuest()
355{
356 /* @todo other platforms */
357}
358#endif
359
360/** @copydoc VBOXSERVICE::pfnPreInit */
361static DECLCALLBACK(int) VBoxServicePageSharingPreInit(void)
362{
363 return VINF_SUCCESS;
364}
365
366
367/** @copydoc VBOXSERVICE::pfnOption */
368static DECLCALLBACK(int) VBoxServicePageSharingOption(const char **ppszShort, int argc, char **argv, int *pi)
369{
370 NOREF(ppszShort);
371 NOREF(argc);
372 NOREF(argv);
373 NOREF(pi);
374 return VINF_SUCCESS;
375}
376
377
378/** @copydoc VBOXSERVICE::pfnInit */
379static DECLCALLBACK(int) VBoxServicePageSharingInit(void)
380{
381 VBoxServiceVerbose(3, "VBoxServicePageSharingInit\n");
382
383 int rc = RTSemEventMultiCreate(&g_PageSharingEvent);
384 AssertRCReturn(rc, rc);
385
386 /* @todo report system name and version */
387 /* Never fail here. */
388 return VINF_SUCCESS;
389}
390
391/** @copydoc VBOXSERVICE::pfnWorker */
392DECLCALLBACK(int) VBoxServicePageSharingWorker(bool volatile *pfShutdown)
393{
394 /*
395 * Tell the control thread that it can continue
396 * spawning services.
397 */
398 RTThreadUserSignal(RTThreadSelf());
399
400 /*
401 * Now enter the loop retrieving runtime data continuously.
402 */
403 for (;;)
404 {
405 VBoxServiceVerbose(3, "VBoxServicePageSharingWorker: enabled=%d\n", VbglR3PageSharingIsEnabled());
406
407 if (VbglR3PageSharingIsEnabled())
408 VBoxServicePageSharingInspectGuest();
409
410 /*
411 * Block for a minute.
412 *
413 * The event semaphore takes care of ignoring interruptions and it
414 * allows us to implement service wakeup later.
415 */
416 if (*pfShutdown)
417 break;
418 int rc = RTSemEventMultiWait(g_PageSharingEvent, 60000);
419 if (*pfShutdown)
420 break;
421 if (rc != VERR_TIMEOUT && RT_FAILURE(rc))
422 {
423 VBoxServiceError("RTSemEventMultiWait failed; rc=%Rrc\n", rc);
424 break;
425 }
426 }
427
428 RTSemEventMultiDestroy(g_PageSharingEvent);
429 g_PageSharingEvent = NIL_RTSEMEVENTMULTI;
430
431 VBoxServiceVerbose(3, "VBoxServicePageSharingWorker: finished thread\n");
432 return 0;
433}
434
435/** @copydoc VBOXSERVICE::pfnTerm */
436static DECLCALLBACK(void) VBoxServicePageSharingTerm(void)
437{
438 VBoxServiceVerbose(3, "VBoxServicePageSharingTerm\n");
439 return;
440}
441
442
443/** @copydoc VBOXSERVICE::pfnStop */
444static DECLCALLBACK(void) VBoxServicePageSharingStop(void)
445{
446 RTSemEventMultiSignal(g_PageSharingEvent);
447}
448
449
450/**
451 * The 'pagesharing' service description.
452 */
453VBOXSERVICE g_PageSharing =
454{
455 /* pszName. */
456 "pagesharing",
457 /* pszDescription. */
458 "Page Sharing",
459 /* pszUsage. */
460 NULL,
461 /* pszOptions. */
462 NULL,
463 /* methods */
464 VBoxServicePageSharingPreInit,
465 VBoxServicePageSharingOption,
466 VBoxServicePageSharingInit,
467 VBoxServicePageSharingWorker,
468 VBoxServicePageSharingStop,
469 VBoxServicePageSharingTerm
470};
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette