tools/trace-malloc/lib/nsDebugHelpWin32.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:e61034ab34dc
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
7 #if defined(_WIN32) && (defined(_M_IX86) || defined(_M_X64))
8 // This is the .cpp file where the globals live
9 #define DHW_IMPLEMENT_GLOBALS
10 #include <stdio.h>
11 #include "prprf.h"
12 #include "prlog.h"
13 #include "plstr.h"
14 #include "prlock.h"
15 #include "nscore.h"
16 #include "nsDebugHelpWin32.h"
17 #else
18 #error "nsDebugHelpWin32.cpp should only be built in Win32 x86/x64 builds"
19 #endif
20
21
22
23 /***************************************************************************/
24
25
26 PRLock* DHWImportHooker::gLock = nullptr;
27 DHWImportHooker* DHWImportHooker::gHooks = nullptr;
28 decltype(GetProcAddress)* DHWImportHooker::gRealGetProcAddress = nullptr;
29
30
31 static bool
32 dhwEnsureImageHlpInitialized()
33 {
34 static bool gInitialized = false;
35 static bool gTried = false;
36
37 if (!gInitialized && !gTried) {
38 gTried = true;
39 HMODULE module = ::LoadLibrary("DBGHELP.DLL");
40 if (!module) {
41 DWORD dw = GetLastError();
42 printf("DumpStack Error: DBGHELP.DLL wasn't found. GetLastError() returned 0x%8.8X\n"
43 " This DLL is needed for succeessfully implementing trace-malloc.\n"
44 " This dll ships by default on Win2k. Disabling trace-malloc functionality.\n"
45 , dw);
46 return false;
47 }
48
49 #define INIT_PROC(typename_, name_) \
50 dhw##name_ = (decltype(name_)*) ::GetProcAddress(module, #name_); \
51 if(!dhw##name_) return false;
52
53 #ifdef _WIN64
54 INIT_PROC(ENUMERATELOADEDMODULES64, EnumerateLoadedModules64);
55 #else
56 INIT_PROC(ENUMERATELOADEDMODULES, EnumerateLoadedModules);
57 #endif
58 INIT_PROC(IMAGEDIRECTORYENTRYTODATA, ImageDirectoryEntryToData);
59
60 #undef INIT_PROC
61
62 gInitialized = true;
63 }
64
65 return gInitialized;
66 }
67
68
69 DHWImportHooker&
70 DHWImportHooker::getGetProcAddressHooker()
71 {
72 static DHWImportHooker gGetProcAddress("Kernel32.dll", "GetProcAddress",
73 (PROC)DHWImportHooker::GetProcAddress);
74 return gGetProcAddress;
75 }
76
77
78 DHWImportHooker&
79 DHWImportHooker::getLoadLibraryWHooker()
80 {
81 static DHWImportHooker gLoadLibraryW("Kernel32.dll", "LoadLibraryW",
82 (PROC)DHWImportHooker::LoadLibraryW);
83 return gLoadLibraryW;
84 }
85
86 DHWImportHooker&
87 DHWImportHooker::getLoadLibraryExWHooker()
88 {
89 static DHWImportHooker gLoadLibraryExW("Kernel32.dll", "LoadLibraryExW",
90 (PROC)DHWImportHooker::LoadLibraryExW);
91 return gLoadLibraryExW;
92 }
93
94 DHWImportHooker&
95 DHWImportHooker::getLoadLibraryAHooker()
96 {
97 static DHWImportHooker gLoadLibraryA("Kernel32.dll", "LoadLibraryA",
98 (PROC)DHWImportHooker::LoadLibraryA);
99 return gLoadLibraryA;
100 }
101
102 DHWImportHooker&
103 DHWImportHooker::getLoadLibraryExAHooker()
104 {
105 static DHWImportHooker gLoadLibraryExA("Kernel32.dll", "LoadLibraryExA",
106 (PROC)DHWImportHooker::LoadLibraryExA);
107 return gLoadLibraryExA;
108 }
109
110
111 static HMODULE ThisModule()
112 {
113 MEMORY_BASIC_INFORMATION info;
114 return VirtualQuery(ThisModule, &info, sizeof(info)) ?
115 (HMODULE) info.AllocationBase : nullptr;
116 }
117
118 DHWImportHooker::DHWImportHooker(const char* aModuleName,
119 const char* aFunctionName,
120 PROC aHook,
121 bool aExcludeOurModule /* = false */)
122 : mNext(nullptr),
123 mModuleName(aModuleName),
124 mFunctionName(aFunctionName),
125 mOriginal(nullptr),
126 mHook(aHook),
127 mIgnoreModule(aExcludeOurModule ? ThisModule() : nullptr),
128 mHooking(true)
129 {
130 //printf("DHWImportHooker hooking %s, function %s\n",aModuleName, aFunctionName);
131
132 if(!gLock)
133 gLock = PR_NewLock();
134 PR_Lock(gLock);
135
136 dhwEnsureImageHlpInitialized(); // for the extra ones we care about.
137
138 if(!gRealGetProcAddress)
139 gRealGetProcAddress = ::GetProcAddress;
140
141 mOriginal = gRealGetProcAddress(::GetModuleHandleA(aModuleName),
142 aFunctionName),
143
144 mNext = gHooks;
145 gHooks = this;
146
147 PatchAllModules();
148
149 PR_Unlock(gLock);
150 }
151
152 DHWImportHooker::~DHWImportHooker()
153 {
154 PR_Lock(gLock);
155
156 mHooking = false;
157 PatchAllModules();
158
159 for (DHWImportHooker **cur = &gHooks;
160 (PR_ASSERT(*cur), *cur); /* assert that we find this */
161 cur = &(*cur)->mNext)
162 {
163 if (*cur == this)
164 {
165 *cur = mNext;
166 break;
167 }
168 }
169
170 if(!gHooks)
171 {
172 PRLock* theLock = gLock;
173 gLock = nullptr;
174 PR_Unlock(theLock);
175 PR_DestroyLock(theLock);
176 }
177 if (gLock)
178 PR_Unlock(gLock);
179 }
180
181 #ifdef _WIN64
182 static BOOL CALLBACK ModuleEnumCallback(PCSTR ModuleName,
183 DWORD64 ModuleBase,
184 ULONG ModuleSize,
185 PVOID UserContext)
186 #else
187 static BOOL CALLBACK ModuleEnumCallback(PCSTR ModuleName,
188 ULONG ModuleBase,
189 ULONG ModuleSize,
190 PVOID UserContext)
191 #endif
192 {
193 //printf("Module Name %s\n",ModuleName);
194 DHWImportHooker* self = (DHWImportHooker*) UserContext;
195 HMODULE aModule = (HMODULE) ModuleBase;
196 return self->PatchOneModule(aModule, ModuleName);
197 }
198
199 bool
200 DHWImportHooker::PatchAllModules()
201 {
202 // Need to cast to PENUMLOADED_MODULES_CALLBACK because the
203 // constness of the first parameter of PENUMLOADED_MODULES_CALLBACK
204 // varies over SDK versions (from non-const to const over time).
205 // See bug 391848 and bug 415426.
206 #ifdef _WIN64
207 return dhwEnumerateLoadedModules64(::GetCurrentProcess(),
208 (PENUMLOADED_MODULES_CALLBACK64)ModuleEnumCallback, this);
209 #else
210 return dhwEnumerateLoadedModules(::GetCurrentProcess(),
211 (PENUMLOADED_MODULES_CALLBACK)ModuleEnumCallback, this);
212 #endif
213 }
214
215 bool
216 DHWImportHooker::PatchOneModule(HMODULE aModule, const char* name)
217 {
218 if(aModule == mIgnoreModule)
219 {
220 return true;
221 }
222
223 // do the fun stuff...
224
225 PIMAGE_IMPORT_DESCRIPTOR desc;
226 ULONG size;
227
228 desc = (PIMAGE_IMPORT_DESCRIPTOR)
229 dhwImageDirectoryEntryToData(aModule, true,
230 IMAGE_DIRECTORY_ENTRY_IMPORT, &size);
231
232 if(!desc)
233 {
234 return true;
235 }
236
237 for(; desc->Name; desc++)
238 {
239 const char* entryModuleName = (const char*)
240 ((char*)aModule + desc->Name);
241 if(!lstrcmpi(entryModuleName, mModuleName))
242 break;
243 }
244
245 if(!desc->Name)
246 {
247 return true;
248 }
249
250 PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)
251 ((char*) aModule + desc->FirstThunk);
252
253 for(; thunk->u1.Function; thunk++)
254 {
255 PROC original;
256 PROC replacement;
257
258 if(mHooking)
259 {
260 original = mOriginal;
261 replacement = mHook;
262 }
263 else
264 {
265 original = mHook;
266 replacement = mOriginal;
267 }
268
269 PROC* ppfn = (PROC*) &thunk->u1.Function;
270 if(*ppfn == original)
271 {
272 DWORD dwDummy;
273 VirtualProtect(ppfn, sizeof(ppfn), PAGE_EXECUTE_READWRITE, &dwDummy);
274 BOOL result = WriteProcessMemory(GetCurrentProcess(),
275 ppfn, &replacement, sizeof(replacement), nullptr);
276 if (!result) //failure
277 {
278 printf("failure name %s func %x\n",name,*ppfn);
279 DWORD error = GetLastError();
280 return true;
281 }
282 else
283 {
284 // printf("success name %s func %x\n",name,*ppfn);
285 DWORD filler = result+1;
286 return result;
287 }
288 }
289
290 }
291 return true;
292 }
293
294 bool
295 DHWImportHooker::ModuleLoaded(HMODULE aModule, DWORD flags)
296 {
297 //printf("ModuleLoaded\n");
298 if(aModule && !(flags & LOAD_LIBRARY_AS_DATAFILE))
299 {
300 PR_Lock(gLock);
301 // We don't know that the newly loaded module didn't drag in implicitly
302 // linked modules, so we patch everything in sight.
303 for(DHWImportHooker* cur = gHooks; cur; cur = cur->mNext)
304 cur->PatchAllModules();
305 PR_Unlock(gLock);
306 }
307 return true;
308 }
309
310 // static
311 HMODULE WINAPI
312 DHWImportHooker::LoadLibraryW(PCWSTR path)
313 {
314 //wprintf(L"LoadLibraryW %s\n",path);
315 HMODULE hmod = DHW_ORIGINAL(::LoadLibraryW, getLoadLibraryWHooker())(path);
316 ModuleLoaded(hmod, 0);
317 return hmod;
318 }
319
320
321 // static
322 HMODULE WINAPI
323 DHWImportHooker::LoadLibraryExW(PCWSTR path, HANDLE file, DWORD flags)
324 {
325 //wprintf(L"LoadLibraryExW %s\n",path);
326 HMODULE hmod = DHW_ORIGINAL(::LoadLibraryExW, getLoadLibraryExWHooker())(path, file, flags);
327 ModuleLoaded(hmod, flags);
328 return hmod;
329 }
330
331 // static
332 HMODULE WINAPI
333 DHWImportHooker::LoadLibraryA(PCSTR path)
334 {
335 //printf("LoadLibraryA %s\n",path);
336 HMODULE hmod = DHW_ORIGINAL(::LoadLibraryA, getLoadLibraryAHooker())(path);
337 ModuleLoaded(hmod, 0);
338 return hmod;
339 }
340
341 // static
342 HMODULE WINAPI
343 DHWImportHooker::LoadLibraryExA(PCSTR path, HANDLE file, DWORD flags)
344 {
345 //printf("LoadLibraryExA %s\n",path);
346 HMODULE hmod = DHW_ORIGINAL(::LoadLibraryExA, getLoadLibraryExAHooker())(path, file, flags);
347 ModuleLoaded(hmod, flags);
348 return hmod;
349 }
350 // static
351 FARPROC WINAPI
352 DHWImportHooker::GetProcAddress(HMODULE aModule, PCSTR aFunctionName)
353 {
354 FARPROC pfn = gRealGetProcAddress(aModule, aFunctionName);
355
356 if(pfn)
357 {
358 PR_Lock(gLock);
359 for(DHWImportHooker* cur = gHooks; cur; cur = cur->mNext)
360 {
361 if(pfn == cur->mOriginal)
362 {
363 pfn = cur->mHook;
364 break;
365 }
366 }
367 PR_Unlock(gLock);
368 }
369 return pfn;
370 }
371
372

mercurial