tools/trace-malloc/lib/nsDebugHelpWin32.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial