| OLD | NEW |
| 1 // Copyright (c) 2007, Google Inc. | 1 // Copyright (c) 2007, Google Inc. |
| 2 // All rights reserved. | 2 // All rights reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // met: |
| 7 // | 7 // |
| 8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
| 9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
| 10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 115 // Without this, the linker will likely decide that libtcmalloc.dll | 115 // Without this, the linker will likely decide that libtcmalloc.dll |
| 116 // doesn't add anything to the executable (since it does all its work | 116 // doesn't add anything to the executable (since it does all its work |
| 117 // through patching, which the linker can't see), and ignore it | 117 // through patching, which the linker can't see), and ignore it |
| 118 // entirely. (The name 'tcmalloc' is already reserved for a | 118 // entirely. (The name 'tcmalloc' is already reserved for a |
| 119 // namespace. I'd rather export a variable named "_tcmalloc", but I | 119 // namespace. I'd rather export a variable named "_tcmalloc", but I |
| 120 // couldn't figure out how to get that to work. This function exports | 120 // couldn't figure out how to get that to work. This function exports |
| 121 // the symbol "__tcmalloc".) | 121 // the symbol "__tcmalloc".) |
| 122 extern "C" PERFTOOLS_DLL_DECL void _tcmalloc(); | 122 extern "C" PERFTOOLS_DLL_DECL void _tcmalloc(); |
| 123 void _tcmalloc() { } | 123 void _tcmalloc() { } |
| 124 | 124 |
| 125 // This is the version needed for windows x64, which has a different |
| 126 // decoration scheme which doesn't auto-add a leading underscore. |
| 127 extern "C" PERFTOOLS_DLL_DECL void __tcmalloc(); |
| 128 void __tcmalloc() { } |
| 129 |
| 125 namespace { // most everything here is in an unnamed namespace | 130 namespace { // most everything here is in an unnamed namespace |
| 126 | 131 |
| 127 typedef void (*GenericFnPtr)(); | 132 typedef void (*GenericFnPtr)(); |
| 128 | 133 |
| 129 using sidestep::PreamblePatcher; | 134 using sidestep::PreamblePatcher; |
| 130 | 135 |
| 131 struct ModuleEntryCopy; // defined below | 136 struct ModuleEntryCopy; // defined below |
| 132 | 137 |
| 133 // These functions are how we override the memory allocation | 138 // These functions are how we override the memory allocation |
| 134 // functions, just like tcmalloc.cc and malloc_hook.cc do. | 139 // functions, just like tcmalloc.cc and malloc_hook.cc do. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 memcpy(this->windows_fn_, that.windows_fn_, sizeof(windows_fn_)); | 173 memcpy(this->windows_fn_, that.windows_fn_, sizeof(windows_fn_)); |
| 169 this->module_base_address_ = that.module_base_address_; | 174 this->module_base_address_ = that.module_base_address_; |
| 170 this->module_base_size_ = that.module_base_size_; | 175 this->module_base_size_ = that.module_base_size_; |
| 171 } | 176 } |
| 172 | 177 |
| 173 enum { | 178 enum { |
| 174 kMalloc, kFree, kRealloc, kCalloc, | 179 kMalloc, kFree, kRealloc, kCalloc, |
| 175 kNew, kNewArray, kDelete, kDeleteArray, | 180 kNew, kNewArray, kDelete, kDeleteArray, |
| 176 kNewNothrow, kNewArrayNothrow, kDeleteNothrow, kDeleteArrayNothrow, | 181 kNewNothrow, kNewArrayNothrow, kDeleteNothrow, kDeleteArrayNothrow, |
| 177 // These are windows-only functions from malloc.h | 182 // These are windows-only functions from malloc.h |
| 178 k_Msize, k_Expand, k_Aligned_malloc, k_Aligned_free, | 183 k_Msize, k_Expand, |
| 179 kNumFunctions | 184 kNumFunctions |
| 180 }; | 185 }; |
| 181 | 186 |
| 182 // I'd like to put these together in a struct (perhaps in the | 187 // I'd like to put these together in a struct (perhaps in the |
| 183 // subclass, so we can put in perftools_fn_ as well), but vc8 seems | 188 // subclass, so we can put in perftools_fn_ as well), but vc8 seems |
| 184 // to have a bug where it doesn't initialize the struct properly if | 189 // to have a bug where it doesn't initialize the struct properly if |
| 185 // we try to take the address of a function that's not yet loaded | 190 // we try to take the address of a function that's not yet loaded |
| 186 // from a dll, as is the common case for static_fn_. So we need | 191 // from a dll, as is the common case for static_fn_. So we need |
| 187 // each to be in its own array. :-( | 192 // each to be in its own array. :-( |
| 188 static const char* const function_name_[kNumFunctions]; | 193 static const char* const function_name_[kNumFunctions]; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 static void* Perftools_new_nothrow(size_t size, | 272 static void* Perftools_new_nothrow(size_t size, |
| 268 const std::nothrow_t&) __THROW; | 273 const std::nothrow_t&) __THROW; |
| 269 static void* Perftools_newarray_nothrow(size_t size, | 274 static void* Perftools_newarray_nothrow(size_t size, |
| 270 const std::nothrow_t&) __THROW; | 275 const std::nothrow_t&) __THROW; |
| 271 static void Perftools_delete_nothrow(void *ptr, | 276 static void Perftools_delete_nothrow(void *ptr, |
| 272 const std::nothrow_t&) __THROW; | 277 const std::nothrow_t&) __THROW; |
| 273 static void Perftools_deletearray_nothrow(void *ptr, | 278 static void Perftools_deletearray_nothrow(void *ptr, |
| 274 const std::nothrow_t&) __THROW; | 279 const std::nothrow_t&) __THROW; |
| 275 static size_t Perftools__msize(void *ptr) __THROW; | 280 static size_t Perftools__msize(void *ptr) __THROW; |
| 276 static void* Perftools__expand(void *ptr, size_t size) __THROW; | 281 static void* Perftools__expand(void *ptr, size_t size) __THROW; |
| 277 static void* Perftools__aligned_malloc(size_t size, size_t alignment) __THROW; | |
| 278 static void Perftools__aligned_free(void *ptr) __THROW; | |
| 279 // malloc.h also defines these functions: | 282 // malloc.h also defines these functions: |
| 283 // _aligned_malloc, _aligned_free, |
| 280 // _recalloc, _aligned_offset_malloc, _aligned_realloc, _aligned_recalloc | 284 // _recalloc, _aligned_offset_malloc, _aligned_realloc, _aligned_recalloc |
| 281 // _aligned_offset_realloc, _aligned_offset_recalloc, _malloca, _freea | 285 // _aligned_offset_realloc, _aligned_offset_recalloc, _malloca, _freea |
| 282 // But they seem pretty obscure, and I'm fine not overriding them for now. | 286 // But they seem pretty obscure, and I'm fine not overriding them for now. |
| 287 // It may be they all call into malloc/free anyway. |
| 283 }; | 288 }; |
| 284 | 289 |
| 285 // This is a subset of MODDULEENTRY32, that we need for patching. | 290 // This is a subset of MODDULEENTRY32, that we need for patching. |
| 286 struct ModuleEntryCopy { | 291 struct ModuleEntryCopy { |
| 287 LPVOID modBaseAddr; // the same as hmodule | 292 LPVOID modBaseAddr; // the same as hmodule |
| 288 DWORD modBaseSize; | 293 DWORD modBaseSize; |
| 289 // This is not part of MODDULEENTRY32, but is needed to avoid making | 294 // This is not part of MODDULEENTRY32, but is needed to avoid making |
| 290 // windows syscalls while we're holding patch_all_modules_lock (see | 295 // windows syscalls while we're holding patch_all_modules_lock (see |
| 291 // lock-inversion comments at patch_all_modules_lock definition, below). | 296 // lock-inversion comments at patch_all_modules_lock definition, below). |
| 292 GenericFnPtr rgProcAddresses[LibcInfo::ctrgProcAddress]; | 297 GenericFnPtr rgProcAddresses[LibcInfo::ctrgProcAddress]; |
| 293 | 298 |
| 294 ModuleEntryCopy() { | 299 ModuleEntryCopy() { |
| 295 modBaseAddr = NULL; | 300 modBaseAddr = NULL; |
| 296 modBaseSize = 0; | 301 modBaseSize = 0; |
| 297 for (int i = 0; i < sizeof(rgProcAddresses)/sizeof(*rgProcAddresses); i++) | 302 for (int i = 0; i < sizeof(rgProcAddresses)/sizeof(*rgProcAddresses); i++) |
| 298 rgProcAddresses[i] = LibcInfo::static_fn(i); | 303 rgProcAddresses[i] = LibcInfo::static_fn(i); |
| 299 } | 304 } |
| 300 ModuleEntryCopy(const MODULEINFO& mi) { | 305 ModuleEntryCopy(const MODULEINFO& mi) { |
| 301 this->modBaseAddr = mi.lpBaseOfDll; | 306 this->modBaseAddr = mi.lpBaseOfDll; |
| 302 this->modBaseSize = mi.SizeOfImage; | 307 this->modBaseSize = mi.SizeOfImage; |
| 303 for (int i = 0; i < sizeof(rgProcAddresses)/sizeof(*rgProcAddresses); i++) | 308 LPVOID modEndAddr = (char*)mi.lpBaseOfDll + mi.SizeOfImage; |
| 304 rgProcAddresses[i] = (GenericFnPtr)::GetProcAddress( | 309 for (int i = 0; i < sizeof(rgProcAddresses)/sizeof(*rgProcAddresses); i++) { |
| 310 FARPROC target = ::GetProcAddress( |
| 305 reinterpret_cast<const HMODULE>(mi.lpBaseOfDll), | 311 reinterpret_cast<const HMODULE>(mi.lpBaseOfDll), |
| 306 LibcInfo::function_name(i)); | 312 LibcInfo::function_name(i)); |
| 313 // Sometimes a DLL forwards a function to a function in another |
| 314 // DLL. We don't want to patch those forwarded functions -- |
| 315 // they'll get patched when the other DLL is processed. |
| 316 if (target >= modBaseAddr && target < modEndAddr) |
| 317 rgProcAddresses[i] = (GenericFnPtr)target; |
| 318 else |
| 319 rgProcAddresses[i] = (GenericFnPtr)NULL; |
| 320 } |
| 307 } | 321 } |
| 308 }; | 322 }; |
| 309 | 323 |
| 310 // This class is easier because there's only one of them. | 324 // This class is easier because there's only one of them. |
| 311 class WindowsInfo { | 325 class WindowsInfo { |
| 312 public: | 326 public: |
| 313 void Patch(); | 327 void Patch(); |
| 314 void Unpatch(); | 328 void Unpatch(); |
| 315 | 329 |
| 316 private: | 330 private: |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 "malloc", "free", "realloc", "calloc", | 397 "malloc", "free", "realloc", "calloc", |
| 384 kMangledNew, kMangledNewArray, kMangledDelete, kMangledDeleteArray, | 398 kMangledNew, kMangledNewArray, kMangledDelete, kMangledDeleteArray, |
| 385 // Ideally we should patch the nothrow versions of new/delete, but | 399 // Ideally we should patch the nothrow versions of new/delete, but |
| 386 // at least in msvcrt, nothrow-new machine-code is of a type we | 400 // at least in msvcrt, nothrow-new machine-code is of a type we |
| 387 // can't patch. Since these are relatively rare, I'm hoping it's ok | 401 // can't patch. Since these are relatively rare, I'm hoping it's ok |
| 388 // not to patch them. (NULL name turns off patching.) | 402 // not to patch them. (NULL name turns off patching.) |
| 389 NULL, // kMangledNewNothrow, | 403 NULL, // kMangledNewNothrow, |
| 390 NULL, // kMangledNewArrayNothrow, | 404 NULL, // kMangledNewArrayNothrow, |
| 391 NULL, // kMangledDeleteNothrow, | 405 NULL, // kMangledDeleteNothrow, |
| 392 NULL, // kMangledDeleteArrayNothrow, | 406 NULL, // kMangledDeleteArrayNothrow, |
| 393 "_msize", "_expand", "_aligned_malloc", "_aligned_free", | 407 "_msize", "_expand", |
| 394 }; | 408 }; |
| 395 | 409 |
| 396 // For mingw, I can't patch the new/delete here, because the | 410 // For mingw, I can't patch the new/delete here, because the |
| 397 // instructions are too small to patch. Luckily, they're so small | 411 // instructions are too small to patch. Luckily, they're so small |
| 398 // because all they do is call into malloc/free, so they still end up | 412 // because all they do is call into malloc/free, so they still end up |
| 399 // calling tcmalloc routines, and we don't actually lose anything | 413 // calling tcmalloc routines, and we don't actually lose anything |
| 400 // (except maybe some stacktrace goodness) by not patching. | 414 // (except maybe some stacktrace goodness) by not patching. |
| 401 const GenericFnPtr LibcInfo::static_fn_[] = { | 415 const GenericFnPtr LibcInfo::static_fn_[] = { |
| 402 (GenericFnPtr)&::malloc, | 416 (GenericFnPtr)&::malloc, |
| 403 (GenericFnPtr)&::free, | 417 (GenericFnPtr)&::free, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 414 (void*(*)(size_t, struct std::nothrow_t const &))&::operator new, | 428 (void*(*)(size_t, struct std::nothrow_t const &))&::operator new, |
| 415 (GenericFnPtr) | 429 (GenericFnPtr) |
| 416 (void*(*)(size_t, struct std::nothrow_t const &))&::operator new[], | 430 (void*(*)(size_t, struct std::nothrow_t const &))&::operator new[], |
| 417 (GenericFnPtr) | 431 (GenericFnPtr) |
| 418 (void(*)(void*, struct std::nothrow_t const &))&::operator delete, | 432 (void(*)(void*, struct std::nothrow_t const &))&::operator delete, |
| 419 (GenericFnPtr) | 433 (GenericFnPtr) |
| 420 (void(*)(void*, struct std::nothrow_t const &))&::operator delete[], | 434 (void(*)(void*, struct std::nothrow_t const &))&::operator delete[], |
| 421 #endif | 435 #endif |
| 422 (GenericFnPtr)&::_msize, | 436 (GenericFnPtr)&::_msize, |
| 423 (GenericFnPtr)&::_expand, | 437 (GenericFnPtr)&::_expand, |
| 424 #ifdef PERFTOOLS_NO_ALIGNED_MALLOC // for older versions of mingw | |
| 425 // _aligned_malloc isn't always available in mingw, so don't try to patch. | |
| 426 (GenericFnPtr)NULL, | |
| 427 (GenericFnPtr)NULL, | |
| 428 #else | |
| 429 (GenericFnPtr)&::_aligned_malloc, | |
| 430 (GenericFnPtr)&::_aligned_free, | |
| 431 #endif | |
| 432 }; | 438 }; |
| 433 | 439 |
| 434 template<int T> GenericFnPtr LibcInfoWithPatchFunctions<T>::origstub_fn_[] = { | 440 template<int T> GenericFnPtr LibcInfoWithPatchFunctions<T>::origstub_fn_[] = { |
| 435 // This will get filled in at run-time, as patching is done. | 441 // This will get filled in at run-time, as patching is done. |
| 436 }; | 442 }; |
| 437 | 443 |
| 438 template<int T> | 444 template<int T> |
| 439 const GenericFnPtr LibcInfoWithPatchFunctions<T>::perftools_fn_[] = { | 445 const GenericFnPtr LibcInfoWithPatchFunctions<T>::perftools_fn_[] = { |
| 440 (GenericFnPtr)&Perftools_malloc, | 446 (GenericFnPtr)&Perftools_malloc, |
| 441 (GenericFnPtr)&Perftools_free, | 447 (GenericFnPtr)&Perftools_free, |
| 442 (GenericFnPtr)&Perftools_realloc, | 448 (GenericFnPtr)&Perftools_realloc, |
| 443 (GenericFnPtr)&Perftools_calloc, | 449 (GenericFnPtr)&Perftools_calloc, |
| 444 (GenericFnPtr)&Perftools_new, | 450 (GenericFnPtr)&Perftools_new, |
| 445 (GenericFnPtr)&Perftools_newarray, | 451 (GenericFnPtr)&Perftools_newarray, |
| 446 (GenericFnPtr)&Perftools_delete, | 452 (GenericFnPtr)&Perftools_delete, |
| 447 (GenericFnPtr)&Perftools_deletearray, | 453 (GenericFnPtr)&Perftools_deletearray, |
| 448 (GenericFnPtr)&Perftools_new_nothrow, | 454 (GenericFnPtr)&Perftools_new_nothrow, |
| 449 (GenericFnPtr)&Perftools_newarray_nothrow, | 455 (GenericFnPtr)&Perftools_newarray_nothrow, |
| 450 (GenericFnPtr)&Perftools_delete_nothrow, | 456 (GenericFnPtr)&Perftools_delete_nothrow, |
| 451 (GenericFnPtr)&Perftools_deletearray_nothrow, | 457 (GenericFnPtr)&Perftools_deletearray_nothrow, |
| 452 (GenericFnPtr)&Perftools__msize, | 458 (GenericFnPtr)&Perftools__msize, |
| 453 (GenericFnPtr)&Perftools__expand, | 459 (GenericFnPtr)&Perftools__expand, |
| 454 (GenericFnPtr)&Perftools__aligned_malloc, | |
| 455 (GenericFnPtr)&Perftools__aligned_free, | |
| 456 }; | 460 }; |
| 457 | 461 |
| 458 /*static*/ WindowsInfo::FunctionInfo WindowsInfo::function_info_[] = { | 462 /*static*/ WindowsInfo::FunctionInfo WindowsInfo::function_info_[] = { |
| 459 { "HeapAlloc", NULL, NULL, (GenericFnPtr)&Perftools_HeapAlloc }, | 463 { "HeapAlloc", NULL, NULL, (GenericFnPtr)&Perftools_HeapAlloc }, |
| 460 { "HeapFree", NULL, NULL, (GenericFnPtr)&Perftools_HeapFree }, | 464 { "HeapFree", NULL, NULL, (GenericFnPtr)&Perftools_HeapFree }, |
| 461 { "VirtualAllocEx", NULL, NULL, (GenericFnPtr)&Perftools_VirtualAllocEx }, | 465 { "VirtualAllocEx", NULL, NULL, (GenericFnPtr)&Perftools_VirtualAllocEx }, |
| 462 { "VirtualFreeEx", NULL, NULL, (GenericFnPtr)&Perftools_VirtualFreeEx }, | 466 { "VirtualFreeEx", NULL, NULL, (GenericFnPtr)&Perftools_VirtualFreeEx }, |
| 463 { "MapViewOfFileEx", NULL, NULL, (GenericFnPtr)&Perftools_MapViewOfFileEx }, | 467 { "MapViewOfFileEx", NULL, NULL, (GenericFnPtr)&Perftools_MapViewOfFileEx }, |
| 464 { "UnmapViewOfFile", NULL, NULL, (GenericFnPtr)&Perftools_UnmapViewOfFile }, | 468 { "UnmapViewOfFile", NULL, NULL, (GenericFnPtr)&Perftools_UnmapViewOfFile }, |
| 465 { "LoadLibraryExW", NULL, NULL, (GenericFnPtr)&Perftools_LoadLibraryExW }, | 469 { "LoadLibraryExW", NULL, NULL, (GenericFnPtr)&Perftools_LoadLibraryExW }, |
| (...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 901 | 905 |
| 902 // We need to define this because internal windows functions like to | 906 // We need to define this because internal windows functions like to |
| 903 // call into it(?). _expand() is like realloc but doesn't move the | 907 // call into it(?). _expand() is like realloc but doesn't move the |
| 904 // pointer. We punt, which will cause callers to fall back on realloc. | 908 // pointer. We punt, which will cause callers to fall back on realloc. |
| 905 template<int T> | 909 template<int T> |
| 906 void* LibcInfoWithPatchFunctions<T>::Perftools__expand(void *ptr, | 910 void* LibcInfoWithPatchFunctions<T>::Perftools__expand(void *ptr, |
| 907 size_t size) __THROW { | 911 size_t size) __THROW { |
| 908 return NULL; | 912 return NULL; |
| 909 } | 913 } |
| 910 | 914 |
| 911 template<int T> | |
| 912 void* LibcInfoWithPatchFunctions<T>::Perftools__aligned_malloc(size_t size, | |
| 913 size_t alignment) | |
| 914 __THROW { | |
| 915 void* result = do_memalign_or_cpp_memalign(alignment, size); | |
| 916 MallocHook::InvokeNewHook(result, size); | |
| 917 return result; | |
| 918 } | |
| 919 | |
| 920 template<int T> | |
| 921 void LibcInfoWithPatchFunctions<T>::Perftools__aligned_free(void *ptr) __THROW { | |
| 922 MallocHook::InvokeDeleteHook(ptr); | |
| 923 do_free_with_callback(ptr, (void (*)(void*))origstub_fn_[k_Aligned_free]); | |
| 924 } | |
| 925 | |
| 926 LPVOID WINAPI WindowsInfo::Perftools_HeapAlloc(HANDLE hHeap, DWORD dwFlags, | 915 LPVOID WINAPI WindowsInfo::Perftools_HeapAlloc(HANDLE hHeap, DWORD dwFlags, |
| 927 DWORD_PTR dwBytes) { | 916 DWORD_PTR dwBytes) { |
| 928 LPVOID result = ((LPVOID (WINAPI *)(HANDLE, DWORD, DWORD_PTR)) | 917 LPVOID result = ((LPVOID (WINAPI *)(HANDLE, DWORD, DWORD_PTR)) |
| 929 function_info_[kHeapAlloc].origstub_fn)( | 918 function_info_[kHeapAlloc].origstub_fn)( |
| 930 hHeap, dwFlags, dwBytes); | 919 hHeap, dwFlags, dwBytes); |
| 931 MallocHook::InvokeNewHook(result, dwBytes); | 920 MallocHook::InvokeNewHook(result, dwBytes); |
| 932 return result; | 921 return result; |
| 933 } | 922 } |
| 934 | 923 |
| 935 BOOL WINAPI WindowsInfo::Perftools_HeapFree(HANDLE hHeap, DWORD dwFlags, | 924 BOOL WINAPI WindowsInfo::Perftools_HeapFree(HANDLE hHeap, DWORD dwFlags, |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1078 if (libc1.is_valid()) libc1.Unpatch(); | 1067 if (libc1.is_valid()) libc1.Unpatch(); |
| 1079 if (libc2.is_valid()) libc2.Unpatch(); | 1068 if (libc2.is_valid()) libc2.Unpatch(); |
| 1080 if (libc3.is_valid()) libc3.Unpatch(); | 1069 if (libc3.is_valid()) libc3.Unpatch(); |
| 1081 if (libc4.is_valid()) libc4.Unpatch(); | 1070 if (libc4.is_valid()) libc4.Unpatch(); |
| 1082 if (libc5.is_valid()) libc5.Unpatch(); | 1071 if (libc5.is_valid()) libc5.Unpatch(); |
| 1083 if (libc6.is_valid()) libc6.Unpatch(); | 1072 if (libc6.is_valid()) libc6.Unpatch(); |
| 1084 if (libc7.is_valid()) libc7.Unpatch(); | 1073 if (libc7.is_valid()) libc7.Unpatch(); |
| 1085 if (libc8.is_valid()) libc8.Unpatch(); | 1074 if (libc8.is_valid()) libc8.Unpatch(); |
| 1086 } | 1075 } |
| 1087 #endif | 1076 #endif |
| OLD | NEW |