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 |