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

     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/. */
     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
    23 /***************************************************************************/
    26 PRLock*           DHWImportHooker::gLock  = nullptr;
    27 DHWImportHooker*  DHWImportHooker::gHooks = nullptr;
    28 decltype(GetProcAddress)* DHWImportHooker::gRealGetProcAddress = nullptr;
    31 static bool
    32 dhwEnsureImageHlpInitialized()
    33 {
    34   static bool gInitialized = false;
    35   static bool gTried       = false;
    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     }
    49 #define INIT_PROC(typename_, name_) \
    50     dhw##name_ = (decltype(name_)*) ::GetProcAddress(module, #name_); \
    51     if(!dhw##name_) return false;
    53 #ifdef _WIN64
    54     INIT_PROC(ENUMERATELOADEDMODULES64, EnumerateLoadedModules64);
    55 #else
    56     INIT_PROC(ENUMERATELOADEDMODULES, EnumerateLoadedModules);
    57 #endif
    58     INIT_PROC(IMAGEDIRECTORYENTRYTODATA, ImageDirectoryEntryToData);
    60 #undef INIT_PROC
    62     gInitialized = true;
    63   }
    65   return gInitialized;
    66 } 
    69 DHWImportHooker&
    70 DHWImportHooker::getGetProcAddressHooker()
    71 {
    72   static DHWImportHooker gGetProcAddress("Kernel32.dll", "GetProcAddress",
    73                                            (PROC)DHWImportHooker::GetProcAddress);
    74   return gGetProcAddress;
    75 }
    78 DHWImportHooker&
    79 DHWImportHooker::getLoadLibraryWHooker()
    80 {
    81   static DHWImportHooker gLoadLibraryW("Kernel32.dll", "LoadLibraryW",
    82                                          (PROC)DHWImportHooker::LoadLibraryW);
    83   return gLoadLibraryW;
    84 }
    86 DHWImportHooker&
    87 DHWImportHooker::getLoadLibraryExWHooker()
    88 {
    89   static DHWImportHooker gLoadLibraryExW("Kernel32.dll", "LoadLibraryExW",
    90                                          (PROC)DHWImportHooker::LoadLibraryExW);
    91   return gLoadLibraryExW;
    92 }
    94 DHWImportHooker&
    95 DHWImportHooker::getLoadLibraryAHooker()
    96 {
    97   static DHWImportHooker gLoadLibraryA("Kernel32.dll", "LoadLibraryA",
    98                                          (PROC)DHWImportHooker::LoadLibraryA);
    99   return gLoadLibraryA;
   100 }
   102 DHWImportHooker&
   103 DHWImportHooker::getLoadLibraryExAHooker()
   104 {
   105   static DHWImportHooker gLoadLibraryExA("Kernel32.dll", "LoadLibraryExA",
   106                                            (PROC)DHWImportHooker::LoadLibraryExA);
   107   return gLoadLibraryExA;
   108 }
   111 static HMODULE ThisModule()
   112 {
   113     MEMORY_BASIC_INFORMATION info;
   114     return VirtualQuery(ThisModule, &info, sizeof(info)) ? 
   115                             (HMODULE) info.AllocationBase : nullptr;
   116 }
   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);
   132     if(!gLock)
   133         gLock = PR_NewLock();
   134     PR_Lock(gLock);
   136     dhwEnsureImageHlpInitialized(); // for the extra ones we care about.
   138     if(!gRealGetProcAddress)
   139         gRealGetProcAddress = ::GetProcAddress;
   141     mOriginal = gRealGetProcAddress(::GetModuleHandleA(aModuleName), 
   142                                     aFunctionName),
   144     mNext = gHooks;
   145     gHooks = this;
   147     PatchAllModules();
   149     PR_Unlock(gLock);
   150 }   
   152 DHWImportHooker::~DHWImportHooker()
   153 {
   154     PR_Lock(gLock);
   156     mHooking = false;
   157     PatchAllModules();
   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     }
   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 }    
   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 }
   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 }    
   215 bool 
   216 DHWImportHooker::PatchOneModule(HMODULE aModule, const char* name)
   217 {
   218     if(aModule == mIgnoreModule)
   219     {
   220         return true;
   221     }
   223     // do the fun stuff...
   225     PIMAGE_IMPORT_DESCRIPTOR desc;
   226     ULONG size;
   228     desc = (PIMAGE_IMPORT_DESCRIPTOR) 
   229         dhwImageDirectoryEntryToData(aModule, true, 
   230                                      IMAGE_DIRECTORY_ENTRY_IMPORT, &size);
   232     if(!desc)
   233     {
   234         return true;
   235     }
   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     }
   245     if(!desc->Name)
   246     {
   247         return true;
   248     }
   250     PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)
   251         ((char*) aModule + desc->FirstThunk);
   253     for(; thunk->u1.Function; thunk++)
   254     {
   255         PROC original;
   256         PROC replacement;
   258         if(mHooking)
   259         {
   260             original = mOriginal;
   261             replacement = mHook;  
   262         } 
   263         else
   264         {
   265             original = mHook;  
   266             replacement = mOriginal;
   267         }   
   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         }
   290     }
   291     return true;
   292 }
   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 }
   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 }
   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 }    
   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 }
   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);
   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 }

mercurial