1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/tools/trace-malloc/lib/nsDebugHelpWin32.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,372 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 + 1.10 +#if defined(_WIN32) && (defined(_M_IX86) || defined(_M_X64)) 1.11 +// This is the .cpp file where the globals live 1.12 +#define DHW_IMPLEMENT_GLOBALS 1.13 +#include <stdio.h> 1.14 +#include "prprf.h" 1.15 +#include "prlog.h" 1.16 +#include "plstr.h" 1.17 +#include "prlock.h" 1.18 +#include "nscore.h" 1.19 +#include "nsDebugHelpWin32.h" 1.20 +#else 1.21 +#error "nsDebugHelpWin32.cpp should only be built in Win32 x86/x64 builds" 1.22 +#endif 1.23 + 1.24 + 1.25 + 1.26 +/***************************************************************************/ 1.27 + 1.28 + 1.29 +PRLock* DHWImportHooker::gLock = nullptr; 1.30 +DHWImportHooker* DHWImportHooker::gHooks = nullptr; 1.31 +decltype(GetProcAddress)* DHWImportHooker::gRealGetProcAddress = nullptr; 1.32 + 1.33 + 1.34 +static bool 1.35 +dhwEnsureImageHlpInitialized() 1.36 +{ 1.37 + static bool gInitialized = false; 1.38 + static bool gTried = false; 1.39 + 1.40 + if (!gInitialized && !gTried) { 1.41 + gTried = true; 1.42 + HMODULE module = ::LoadLibrary("DBGHELP.DLL"); 1.43 + if (!module) { 1.44 + DWORD dw = GetLastError(); 1.45 + printf("DumpStack Error: DBGHELP.DLL wasn't found. GetLastError() returned 0x%8.8X\n" 1.46 + " This DLL is needed for succeessfully implementing trace-malloc.\n" 1.47 + " This dll ships by default on Win2k. Disabling trace-malloc functionality.\n" 1.48 + , dw); 1.49 + return false; 1.50 + } 1.51 + 1.52 +#define INIT_PROC(typename_, name_) \ 1.53 + dhw##name_ = (decltype(name_)*) ::GetProcAddress(module, #name_); \ 1.54 + if(!dhw##name_) return false; 1.55 + 1.56 +#ifdef _WIN64 1.57 + INIT_PROC(ENUMERATELOADEDMODULES64, EnumerateLoadedModules64); 1.58 +#else 1.59 + INIT_PROC(ENUMERATELOADEDMODULES, EnumerateLoadedModules); 1.60 +#endif 1.61 + INIT_PROC(IMAGEDIRECTORYENTRYTODATA, ImageDirectoryEntryToData); 1.62 + 1.63 +#undef INIT_PROC 1.64 + 1.65 + gInitialized = true; 1.66 + } 1.67 + 1.68 + return gInitialized; 1.69 +} 1.70 + 1.71 + 1.72 +DHWImportHooker& 1.73 +DHWImportHooker::getGetProcAddressHooker() 1.74 +{ 1.75 + static DHWImportHooker gGetProcAddress("Kernel32.dll", "GetProcAddress", 1.76 + (PROC)DHWImportHooker::GetProcAddress); 1.77 + return gGetProcAddress; 1.78 +} 1.79 + 1.80 + 1.81 +DHWImportHooker& 1.82 +DHWImportHooker::getLoadLibraryWHooker() 1.83 +{ 1.84 + static DHWImportHooker gLoadLibraryW("Kernel32.dll", "LoadLibraryW", 1.85 + (PROC)DHWImportHooker::LoadLibraryW); 1.86 + return gLoadLibraryW; 1.87 +} 1.88 + 1.89 +DHWImportHooker& 1.90 +DHWImportHooker::getLoadLibraryExWHooker() 1.91 +{ 1.92 + static DHWImportHooker gLoadLibraryExW("Kernel32.dll", "LoadLibraryExW", 1.93 + (PROC)DHWImportHooker::LoadLibraryExW); 1.94 + return gLoadLibraryExW; 1.95 +} 1.96 + 1.97 +DHWImportHooker& 1.98 +DHWImportHooker::getLoadLibraryAHooker() 1.99 +{ 1.100 + static DHWImportHooker gLoadLibraryA("Kernel32.dll", "LoadLibraryA", 1.101 + (PROC)DHWImportHooker::LoadLibraryA); 1.102 + return gLoadLibraryA; 1.103 +} 1.104 + 1.105 +DHWImportHooker& 1.106 +DHWImportHooker::getLoadLibraryExAHooker() 1.107 +{ 1.108 + static DHWImportHooker gLoadLibraryExA("Kernel32.dll", "LoadLibraryExA", 1.109 + (PROC)DHWImportHooker::LoadLibraryExA); 1.110 + return gLoadLibraryExA; 1.111 +} 1.112 + 1.113 + 1.114 +static HMODULE ThisModule() 1.115 +{ 1.116 + MEMORY_BASIC_INFORMATION info; 1.117 + return VirtualQuery(ThisModule, &info, sizeof(info)) ? 1.118 + (HMODULE) info.AllocationBase : nullptr; 1.119 +} 1.120 + 1.121 +DHWImportHooker::DHWImportHooker(const char* aModuleName, 1.122 + const char* aFunctionName, 1.123 + PROC aHook, 1.124 + bool aExcludeOurModule /* = false */) 1.125 + : mNext(nullptr), 1.126 + mModuleName(aModuleName), 1.127 + mFunctionName(aFunctionName), 1.128 + mOriginal(nullptr), 1.129 + mHook(aHook), 1.130 + mIgnoreModule(aExcludeOurModule ? ThisModule() : nullptr), 1.131 + mHooking(true) 1.132 +{ 1.133 + //printf("DHWImportHooker hooking %s, function %s\n",aModuleName, aFunctionName); 1.134 + 1.135 + if(!gLock) 1.136 + gLock = PR_NewLock(); 1.137 + PR_Lock(gLock); 1.138 + 1.139 + dhwEnsureImageHlpInitialized(); // for the extra ones we care about. 1.140 + 1.141 + if(!gRealGetProcAddress) 1.142 + gRealGetProcAddress = ::GetProcAddress; 1.143 + 1.144 + mOriginal = gRealGetProcAddress(::GetModuleHandleA(aModuleName), 1.145 + aFunctionName), 1.146 + 1.147 + mNext = gHooks; 1.148 + gHooks = this; 1.149 + 1.150 + PatchAllModules(); 1.151 + 1.152 + PR_Unlock(gLock); 1.153 +} 1.154 + 1.155 +DHWImportHooker::~DHWImportHooker() 1.156 +{ 1.157 + PR_Lock(gLock); 1.158 + 1.159 + mHooking = false; 1.160 + PatchAllModules(); 1.161 + 1.162 + for (DHWImportHooker **cur = &gHooks; 1.163 + (PR_ASSERT(*cur), *cur); /* assert that we find this */ 1.164 + cur = &(*cur)->mNext) 1.165 + { 1.166 + if (*cur == this) 1.167 + { 1.168 + *cur = mNext; 1.169 + break; 1.170 + } 1.171 + } 1.172 + 1.173 + if(!gHooks) 1.174 + { 1.175 + PRLock* theLock = gLock; 1.176 + gLock = nullptr; 1.177 + PR_Unlock(theLock); 1.178 + PR_DestroyLock(theLock); 1.179 + } 1.180 + if (gLock) 1.181 + PR_Unlock(gLock); 1.182 +} 1.183 + 1.184 +#ifdef _WIN64 1.185 +static BOOL CALLBACK ModuleEnumCallback(PCSTR ModuleName, 1.186 + DWORD64 ModuleBase, 1.187 + ULONG ModuleSize, 1.188 + PVOID UserContext) 1.189 +#else 1.190 +static BOOL CALLBACK ModuleEnumCallback(PCSTR ModuleName, 1.191 + ULONG ModuleBase, 1.192 + ULONG ModuleSize, 1.193 + PVOID UserContext) 1.194 +#endif 1.195 +{ 1.196 + //printf("Module Name %s\n",ModuleName); 1.197 + DHWImportHooker* self = (DHWImportHooker*) UserContext; 1.198 + HMODULE aModule = (HMODULE) ModuleBase; 1.199 + return self->PatchOneModule(aModule, ModuleName); 1.200 +} 1.201 + 1.202 +bool 1.203 +DHWImportHooker::PatchAllModules() 1.204 +{ 1.205 + // Need to cast to PENUMLOADED_MODULES_CALLBACK because the 1.206 + // constness of the first parameter of PENUMLOADED_MODULES_CALLBACK 1.207 + // varies over SDK versions (from non-const to const over time). 1.208 + // See bug 391848 and bug 415426. 1.209 +#ifdef _WIN64 1.210 + return dhwEnumerateLoadedModules64(::GetCurrentProcess(), 1.211 + (PENUMLOADED_MODULES_CALLBACK64)ModuleEnumCallback, this); 1.212 +#else 1.213 + return dhwEnumerateLoadedModules(::GetCurrentProcess(), 1.214 + (PENUMLOADED_MODULES_CALLBACK)ModuleEnumCallback, this); 1.215 +#endif 1.216 +} 1.217 + 1.218 +bool 1.219 +DHWImportHooker::PatchOneModule(HMODULE aModule, const char* name) 1.220 +{ 1.221 + if(aModule == mIgnoreModule) 1.222 + { 1.223 + return true; 1.224 + } 1.225 + 1.226 + // do the fun stuff... 1.227 + 1.228 + PIMAGE_IMPORT_DESCRIPTOR desc; 1.229 + ULONG size; 1.230 + 1.231 + desc = (PIMAGE_IMPORT_DESCRIPTOR) 1.232 + dhwImageDirectoryEntryToData(aModule, true, 1.233 + IMAGE_DIRECTORY_ENTRY_IMPORT, &size); 1.234 + 1.235 + if(!desc) 1.236 + { 1.237 + return true; 1.238 + } 1.239 + 1.240 + for(; desc->Name; desc++) 1.241 + { 1.242 + const char* entryModuleName = (const char*) 1.243 + ((char*)aModule + desc->Name); 1.244 + if(!lstrcmpi(entryModuleName, mModuleName)) 1.245 + break; 1.246 + } 1.247 + 1.248 + if(!desc->Name) 1.249 + { 1.250 + return true; 1.251 + } 1.252 + 1.253 + PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA) 1.254 + ((char*) aModule + desc->FirstThunk); 1.255 + 1.256 + for(; thunk->u1.Function; thunk++) 1.257 + { 1.258 + PROC original; 1.259 + PROC replacement; 1.260 + 1.261 + if(mHooking) 1.262 + { 1.263 + original = mOriginal; 1.264 + replacement = mHook; 1.265 + } 1.266 + else 1.267 + { 1.268 + original = mHook; 1.269 + replacement = mOriginal; 1.270 + } 1.271 + 1.272 + PROC* ppfn = (PROC*) &thunk->u1.Function; 1.273 + if(*ppfn == original) 1.274 + { 1.275 + DWORD dwDummy; 1.276 + VirtualProtect(ppfn, sizeof(ppfn), PAGE_EXECUTE_READWRITE, &dwDummy); 1.277 + BOOL result = WriteProcessMemory(GetCurrentProcess(), 1.278 + ppfn, &replacement, sizeof(replacement), nullptr); 1.279 + if (!result) //failure 1.280 + { 1.281 + printf("failure name %s func %x\n",name,*ppfn); 1.282 + DWORD error = GetLastError(); 1.283 + return true; 1.284 + } 1.285 + else 1.286 + { 1.287 + // printf("success name %s func %x\n",name,*ppfn); 1.288 + DWORD filler = result+1; 1.289 + return result; 1.290 + } 1.291 + } 1.292 + 1.293 + } 1.294 + return true; 1.295 +} 1.296 + 1.297 +bool 1.298 +DHWImportHooker::ModuleLoaded(HMODULE aModule, DWORD flags) 1.299 +{ 1.300 + //printf("ModuleLoaded\n"); 1.301 + if(aModule && !(flags & LOAD_LIBRARY_AS_DATAFILE)) 1.302 + { 1.303 + PR_Lock(gLock); 1.304 + // We don't know that the newly loaded module didn't drag in implicitly 1.305 + // linked modules, so we patch everything in sight. 1.306 + for(DHWImportHooker* cur = gHooks; cur; cur = cur->mNext) 1.307 + cur->PatchAllModules(); 1.308 + PR_Unlock(gLock); 1.309 + } 1.310 + return true; 1.311 +} 1.312 + 1.313 +// static 1.314 +HMODULE WINAPI 1.315 +DHWImportHooker::LoadLibraryW(PCWSTR path) 1.316 +{ 1.317 + //wprintf(L"LoadLibraryW %s\n",path); 1.318 + HMODULE hmod = DHW_ORIGINAL(::LoadLibraryW, getLoadLibraryWHooker())(path); 1.319 + ModuleLoaded(hmod, 0); 1.320 + return hmod; 1.321 +} 1.322 + 1.323 + 1.324 +// static 1.325 +HMODULE WINAPI 1.326 +DHWImportHooker::LoadLibraryExW(PCWSTR path, HANDLE file, DWORD flags) 1.327 +{ 1.328 + //wprintf(L"LoadLibraryExW %s\n",path); 1.329 + HMODULE hmod = DHW_ORIGINAL(::LoadLibraryExW, getLoadLibraryExWHooker())(path, file, flags); 1.330 + ModuleLoaded(hmod, flags); 1.331 + return hmod; 1.332 +} 1.333 + 1.334 +// static 1.335 +HMODULE WINAPI 1.336 +DHWImportHooker::LoadLibraryA(PCSTR path) 1.337 +{ 1.338 + //printf("LoadLibraryA %s\n",path); 1.339 + HMODULE hmod = DHW_ORIGINAL(::LoadLibraryA, getLoadLibraryAHooker())(path); 1.340 + ModuleLoaded(hmod, 0); 1.341 + return hmod; 1.342 +} 1.343 + 1.344 +// static 1.345 +HMODULE WINAPI 1.346 +DHWImportHooker::LoadLibraryExA(PCSTR path, HANDLE file, DWORD flags) 1.347 +{ 1.348 + //printf("LoadLibraryExA %s\n",path); 1.349 + HMODULE hmod = DHW_ORIGINAL(::LoadLibraryExA, getLoadLibraryExAHooker())(path, file, flags); 1.350 + ModuleLoaded(hmod, flags); 1.351 + return hmod; 1.352 +} 1.353 +// static 1.354 +FARPROC WINAPI 1.355 +DHWImportHooker::GetProcAddress(HMODULE aModule, PCSTR aFunctionName) 1.356 +{ 1.357 + FARPROC pfn = gRealGetProcAddress(aModule, aFunctionName); 1.358 + 1.359 + if(pfn) 1.360 + { 1.361 + PR_Lock(gLock); 1.362 + for(DHWImportHooker* cur = gHooks; cur; cur = cur->mNext) 1.363 + { 1.364 + if(pfn == cur->mOriginal) 1.365 + { 1.366 + pfn = cur->mHook; 1.367 + break; 1.368 + } 1.369 + } 1.370 + PR_Unlock(gLock); 1.371 + } 1.372 + return pfn; 1.373 +} 1.374 + 1.375 +