15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2007, Google Inc. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Redistribution and use in source and binary forms, with or without 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modification, are permitted provided that the following conditions are 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// met: 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Redistributions of source code must retain the above copyright 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notice, this list of conditions and the following disclaimer. 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Redistributions in binary form must reproduce the above 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// copyright notice, this list of conditions and the following disclaimer 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the documentation and/or other materials provided with the 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// distribution. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Neither the name of Google Inc. nor the names of its 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// contributors may be used to endorse or promote products derived from 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this software without specific prior written permission. 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// --- 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Author: Craig Silverstein 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The main purpose of this file is to patch the libc allocation 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// routines (malloc and friends, but also _msize and other 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// windows-specific libc-style routines). However, we also patch 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// windows routines to do accounting. We do better at the former than 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the latter. Here are some comments from Paul Pluzhnikov about what 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// it might take to do a really good job patching windows routines to 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// keep track of memory usage: 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "You should intercept at least the following: 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HeapCreate HeapDestroy HeapAlloc HeapReAlloc HeapFree 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// RtlCreateHeap RtlDestroyHeap RtlAllocateHeap RtlFreeHeap 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// malloc calloc realloc free 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// malloc_dbg calloc_dbg realloc_dbg free_dbg 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Some of these call the other ones (but not always), sometimes 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// recursively (i.e. HeapCreate may call HeapAlloc on a different 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// heap, IIRC)." 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Since Paul didn't mention VirtualAllocEx, he may not have even been 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// considering all the mmap-like functions that windows has (or he may 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// just be ignoring it because he's seen we already patch it). Of the 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// above, we do not patch the *_dbg functions, and of the windows 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// functions, we only patch HeapAlloc and HeapFree. 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The *_dbg functions come into play with /MDd, /MTd, and /MLd, 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// probably. It may be ok to just turn off tcmalloc in those cases -- 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// if the user wants the windows debug malloc, they probably don't 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// want tcmalloc! We should also test with all of /MD, /MT, and /ML, 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// which we're not currently doing. 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(csilvers): try to do better here? Paul does conclude: 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "Keeping track of all of this was a nightmare." 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef _WIN32 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# error You should only be including windows/patch_functions.cc in a windows environment! 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <config.h> 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef WIN32_OVERRIDE_ALLOCATORS 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#error This file is intended for patching allocators - use override_functions.cc instead. 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We use psapi. Non-MSVC systems will have to link this in themselves. 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef _MSC_VER 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma comment(lib, "Psapi.lib") 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Make sure we always use the 'old' names of the psapi functions. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef PSAPI_VERSION 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define PSAPI_VERSION 1 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h> 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <malloc.h> // for _msize and _expand 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <Psapi.h> // for EnumProcessModules, GetModuleInformation, etc. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set> 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map> 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <base/logging.h> 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/spinlock.h" 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "gperftools/malloc_hook.h" 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "malloc_hook-inl.h" 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "preamble_patcher.h" 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The maximum number of modules we allow to be in one executable 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMaxModules = 8182; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// These are hard-coded, unfortunately. :-( They are also probably 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// compiler specific. See get_mangled_names.cc, in this directory, 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for instructions on how to update these names for your compiler. 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kMangledNew[] = "??2@YAPAXI@Z"; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kMangledNewArray[] = "??_U@YAPAXI@Z"; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kMangledDelete[] = "??3@YAXPAX@Z"; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kMangledDeleteArray[] = "??_V@YAXPAX@Z"; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kMangledNewNothrow[] = "??2@YAPAXIABUnothrow_t@std@@@Z"; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kMangledNewArrayNothrow[] = "??_U@YAPAXIABUnothrow_t@std@@@Z"; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kMangledDeleteNothrow[] = "??3@YAXPAXABUnothrow_t@std@@@Z"; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kMangledDeleteArrayNothrow[] = "??_V@YAXPAXABUnothrow_t@std@@@Z"; 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is an unused but exported symbol that we can use to tell the 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MSVC linker to bring in libtcmalloc, via the /INCLUDE linker flag. 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Without this, the linker will likely decide that libtcmalloc.dll 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// doesn't add anything to the executable (since it does all its work 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// through patching, which the linker can't see), and ignore it 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// entirely. (The name 'tcmalloc' is already reserved for a 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// namespace. I'd rather export a variable named "_tcmalloc", but I 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// couldn't figure out how to get that to work. This function exports 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the symbol "__tcmalloc".) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" PERFTOOLS_DLL_DECL void _tcmalloc(); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void _tcmalloc() { } 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is the version needed for windows x64, which has a different 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// decoration scheme which doesn't auto-add a leading underscore. 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" PERFTOOLS_DLL_DECL void __tcmalloc(); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void __tcmalloc() { } 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { // most everything here is in an unnamed namespace 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef void (*GenericFnPtr)(); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using sidestep::PreamblePatcher; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct ModuleEntryCopy; // defined below 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// These functions are how we override the memory allocation 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// functions, just like tcmalloc.cc and malloc_hook.cc do. 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is information about the routines we're patching, for a given 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// module that implements libc memory routines. A single executable 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// can have several libc implementations running about (in different 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// .dll's), and we need to patch/unpatch them all. This defines 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// everything except the new functions we're patching in, which 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// are defined in LibcFunctions, below. 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class LibcInfo { 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LibcInfo() { 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(this, 0, sizeof(*this)); // easiest way to initialize the array 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool patched() const { return is_valid(); } 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void set_is_valid(bool b) { is_valid_ = b; } 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // According to http://msdn.microsoft.com/en-us/library/ms684229(VS.85).aspx: 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "The load address of a module (lpBaseOfDll) is the same as the HMODULE 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // value." 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HMODULE hmodule() const { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return reinterpret_cast<HMODULE>(const_cast<void*>(module_base_address_)); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Populates all the windows_fn_[] vars based on our module info. 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns false if windows_fn_ is all NULL's, because there's 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // nothing to patch. Also populates the rest of the module_entry 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // info, such as the module's name. 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool PopulateWindowsFn(const ModuleEntryCopy& module_entry); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected: 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CopyFrom(const LibcInfo& that) { 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this == &that) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this->is_valid_ = that.is_valid_; 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(this->windows_fn_, that.windows_fn_, sizeof(windows_fn_)); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this->module_base_address_ = that.module_base_address_; 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this->module_base_size_ = that.module_base_size_; 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum { 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kMalloc, kFree, kRealloc, kCalloc, 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kNew, kNewArray, kDelete, kDeleteArray, 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kNewNothrow, kNewArrayNothrow, kDeleteNothrow, kDeleteArrayNothrow, 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // These are windows-only functions from malloc.h 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) k_Msize, k_Expand, 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A MS CRT "internal" function, implemented using _calloc_impl 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) k_CallocCrt, 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kNumFunctions 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // I'd like to put these together in a struct (perhaps in the 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // subclass, so we can put in perftools_fn_ as well), but vc8 seems 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to have a bug where it doesn't initialize the struct properly if 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we try to take the address of a function that's not yet loaded 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // from a dll, as is the common case for static_fn_. So we need 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // each to be in its own array. :-( 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char* const function_name_[kNumFunctions]; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This function is only used when statically linking the binary. 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In that case, loading malloc/etc from the dll (via 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // PatchOneModule) won't work, since there are no dlls. Instead, 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // you just want to be taking the address of malloc/etc directly. 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In the common, non-static-link case, these pointers will all be 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NULL, since this initializer runs before msvcrt.dll is loaded. 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const GenericFnPtr static_fn_[kNumFunctions]; 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is the address of the function we are going to patch 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (malloc, etc). Other info about the function is in the 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // patch-specific subclasses, below. 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GenericFnPtr windows_fn_[kNumFunctions]; 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is set to true when this structure is initialized (because 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we're patching a new library) and set to false when it's 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // uninitialized (because we've freed that library). 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_valid_; 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void *module_base_address_; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t module_base_size_; 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // These shouldn't have to be public, since only subclasses of 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // LibcInfo need it, but they do. Maybe something to do with 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // templates. Shrug. I hide them down here so users won't see 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // them. :-) (OK, I also need to define ctrgProcAddress late.) 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_valid() const { return is_valid_; } 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GenericFnPtr windows_fn(int ifunction) const { 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return windows_fn_[ifunction]; 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // These three are needed by ModuleEntryCopy. 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int ctrgProcAddress = kNumFunctions; 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static GenericFnPtr static_fn(int ifunction) { 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return static_fn_[ifunction]; 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char* const function_name(int ifunction) { 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return function_name_[ifunction]; 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Template trickiness: logically, a LibcInfo would include 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Windows_malloc_, origstub_malloc_, and Perftools_malloc_: for a 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// given module, these three go together. And in fact, 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Perftools_malloc_ may need to call origstub_malloc_, which means we 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// either need to change Perftools_malloc_ to take origstub_malloc_ as 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// an arugment -- unfortunately impossible since it needs to keep the 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// same API as normal malloc -- or we need to write a different 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// version of Perftools_malloc_ for each LibcInfo instance we create. 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We choose the second route, and use templates to implement it (we 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// could have also used macros). So to get multiple versions 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of the struct, we say "struct<1> var1; struct<2> var2;". The price 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we pay is some code duplication, and more annoying, each instance 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of this var is a separate type. 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int> class LibcInfoWithPatchFunctions : public LibcInfo { 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // me_info should have had PopulateWindowsFn() called on it, so the 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // module_* vars and windows_fn_ are set up. 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool Patch(const LibcInfo& me_info); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Unpatch(); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This holds the original function contents after we patch the function. 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This has to be defined static in the subclass, because the perftools_fns 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // reference origstub_fn_. 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static GenericFnPtr origstub_fn_[kNumFunctions]; 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is the function we want to patch in 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const GenericFnPtr perftools_fn_[kNumFunctions]; 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void* Perftools_malloc(size_t size) __THROW; 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void Perftools_free(void* ptr) __THROW; 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void* Perftools_realloc(void* ptr, size_t size) __THROW; 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void* Perftools_calloc(size_t nmemb, size_t size) __THROW; 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void* Perftools_new(size_t size); 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void* Perftools_newarray(size_t size); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void Perftools_delete(void *ptr); 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void Perftools_deletearray(void *ptr); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void* Perftools_new_nothrow(size_t size, 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::nothrow_t&) __THROW; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void* Perftools_newarray_nothrow(size_t size, 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::nothrow_t&) __THROW; 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void Perftools_delete_nothrow(void *ptr, 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::nothrow_t&) __THROW; 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void Perftools_deletearray_nothrow(void *ptr, 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::nothrow_t&) __THROW; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static size_t Perftools__msize(void *ptr) __THROW; 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void* Perftools__expand(void *ptr, size_t size) __THROW; 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // malloc.h also defines these functions: 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // _aligned_malloc, _aligned_free, 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // _recalloc, _aligned_offset_malloc, _aligned_realloc, _aligned_recalloc 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // _aligned_offset_realloc, _aligned_offset_recalloc, _malloca, _freea 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // But they seem pretty obscure, and I'm fine not overriding them for now. 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It may be they all call into malloc/free anyway. 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is a subset of MODDULEENTRY32, that we need for patching. 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct ModuleEntryCopy { 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID modBaseAddr; // the same as hmodule 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD modBaseSize; 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is not part of MODDULEENTRY32, but is needed to avoid making 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // windows syscalls while we're holding patch_all_modules_lock (see 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // lock-inversion comments at patch_all_modules_lock definition, below). 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GenericFnPtr rgProcAddresses[LibcInfo::ctrgProcAddress]; 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ModuleEntryCopy() { 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modBaseAddr = NULL; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modBaseSize = 0; 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < sizeof(rgProcAddresses)/sizeof(*rgProcAddresses); i++) 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rgProcAddresses[i] = LibcInfo::static_fn(i); 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ModuleEntryCopy(const MODULEINFO& mi) { 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this->modBaseAddr = mi.lpBaseOfDll; 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this->modBaseSize = mi.SizeOfImage; 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID modEndAddr = (char*)mi.lpBaseOfDll + mi.SizeOfImage; 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < sizeof(rgProcAddresses)/sizeof(*rgProcAddresses); i++) { 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FARPROC target = ::GetProcAddress( 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<const HMODULE>(mi.lpBaseOfDll), 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LibcInfo::function_name(i)); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sometimes a DLL forwards a function to a function in another 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // DLL. We don't want to patch those forwarded functions -- 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // they'll get patched when the other DLL is processed. 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (target >= modBaseAddr && target < modEndAddr) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rgProcAddresses[i] = (GenericFnPtr)target; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rgProcAddresses[i] = (GenericFnPtr)NULL; 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class is easier because there's only one of them. 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class WindowsInfo { 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Patch(); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Unpatch(); 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(csilvers): should we be patching GlobalAlloc/LocalAlloc instead, 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for pre-XP systems? 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum { 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kHeapAlloc, kHeapFree, kVirtualAllocEx, kVirtualFreeEx, 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kMapViewOfFileEx, kUnmapViewOfFile, kLoadLibraryExW, kFreeLibrary, 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kNumFunctions 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct FunctionInfo { 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* const name; // name of fn in a module (eg "malloc") 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GenericFnPtr windows_fn; // the fn whose name we call (&malloc) 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GenericFnPtr origstub_fn; // original fn contents after we patch 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GenericFnPtr perftools_fn; // fn we want to patch in 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static FunctionInfo function_info_[kNumFunctions]; 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A Windows-API equivalent of malloc and free 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static LPVOID WINAPI Perftools_HeapAlloc(HANDLE hHeap, DWORD dwFlags, 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD_PTR dwBytes); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static BOOL WINAPI Perftools_HeapFree(HANDLE hHeap, DWORD dwFlags, 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID lpMem); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A Windows-API equivalent of mmap and munmap, for "anonymous regions" 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static LPVOID WINAPI Perftools_VirtualAllocEx(HANDLE process, LPVOID address, 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZE_T size, DWORD type, 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD protect); 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static BOOL WINAPI Perftools_VirtualFreeEx(HANDLE process, LPVOID address, 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZE_T size, DWORD type); 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A Windows-API equivalent of mmap and munmap, for actual files 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static LPVOID WINAPI Perftools_MapViewOfFileEx(HANDLE hFileMappingObject, 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dwDesiredAccess, 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dwFileOffsetHigh, 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dwFileOffsetLow, 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZE_T dwNumberOfBytesToMap, 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID lpBaseAddress); 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static BOOL WINAPI Perftools_UnmapViewOfFile(LPCVOID lpBaseAddress); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We don't need the other 3 variants because they all call this one. */ 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static HMODULE WINAPI Perftools_LoadLibraryExW(LPCWSTR lpFileName, 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HANDLE hFile, 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dwFlags); 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static BOOL WINAPI Perftools_FreeLibrary(HMODULE hLibModule); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If you run out, just add a few more to the array. You'll also need 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to update the switch statement in PatchOneModule(), and the list in 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// UnpatchWindowsFunctions(). 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// main_executable and main_executable_windows are two windows into 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the same executable. One is responsible for patching the libc 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// routines that live in the main executable (if any) to use tcmalloc; 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the other is responsible for patching the windows routines like 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HeapAlloc/etc to use tcmalloc. 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static LibcInfoWithPatchFunctions<0> main_executable; 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static LibcInfoWithPatchFunctions<1> libc1; 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static LibcInfoWithPatchFunctions<2> libc2; 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static LibcInfoWithPatchFunctions<3> libc3; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static LibcInfoWithPatchFunctions<4> libc4; 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static LibcInfoWithPatchFunctions<5> libc5; 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static LibcInfoWithPatchFunctions<6> libc6; 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static LibcInfoWithPatchFunctions<7> libc7; 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static LibcInfoWithPatchFunctions<8> libc8; 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static LibcInfo* g_module_libcs[] = { 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &libc1, &libc2, &libc3, &libc4, &libc5, &libc6, &libc7, &libc8 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static WindowsInfo main_executable_windows; 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* const LibcInfo::function_name_[] = { 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "malloc", "free", "realloc", "calloc", 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kMangledNew, kMangledNewArray, kMangledDelete, kMangledDeleteArray, 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ideally we should patch the nothrow versions of new/delete, but 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // at least in msvcrt, nothrow-new machine-code is of a type we 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // can't patch. Since these are relatively rare, I'm hoping it's ok 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // not to patch them. (NULL name turns off patching.) 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, // kMangledNewNothrow, 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, // kMangledNewArrayNothrow, 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, // kMangledDeleteNothrow, 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, // kMangledDeleteArrayNothrow, 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "_msize", "_expand", "_calloc_crt", 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For mingw, I can't patch the new/delete here, because the 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// instructions are too small to patch. Luckily, they're so small 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// because all they do is call into malloc/free, so they still end up 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// calling tcmalloc routines, and we don't actually lose anything 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (except maybe some stacktrace goodness) by not patching. 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const GenericFnPtr LibcInfo::static_fn_[] = { 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&::malloc, 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&::free, 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&::realloc, 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&::calloc, 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef __MINGW32__ 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)(void*(*)(size_t))&::operator new, 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)(void*(*)(size_t))&::operator new[], 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)(void(*)(void*))&::operator delete, 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)(void(*)(void*))&::operator delete[], 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr) 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void*(*)(size_t, struct std::nothrow_t const &))&::operator new, 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr) 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void*(*)(size_t, struct std::nothrow_t const &))&::operator new[], 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr) 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void(*)(void*, struct std::nothrow_t const &))&::operator delete, 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr) 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void(*)(void*, struct std::nothrow_t const &))&::operator delete[], 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&::_msize, 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&::_expand, 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&::calloc, 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int T> GenericFnPtr LibcInfoWithPatchFunctions<T>::origstub_fn_[] = { 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This will get filled in at run-time, as patching is done. 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int T> 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const GenericFnPtr LibcInfoWithPatchFunctions<T>::perftools_fn_[] = { 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&Perftools_malloc, 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&Perftools_free, 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&Perftools_realloc, 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&Perftools_calloc, 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&Perftools_new, 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&Perftools_newarray, 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&Perftools_delete, 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&Perftools_deletearray, 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&Perftools_new_nothrow, 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&Perftools_newarray_nothrow, 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&Perftools_delete_nothrow, 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&Perftools_deletearray_nothrow, 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&Perftools__msize, 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&Perftools__expand, 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GenericFnPtr)&Perftools_calloc, 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*static*/ WindowsInfo::FunctionInfo WindowsInfo::function_info_[] = { 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "HeapAlloc", NULL, NULL, (GenericFnPtr)&Perftools_HeapAlloc }, 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "HeapFree", NULL, NULL, (GenericFnPtr)&Perftools_HeapFree }, 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "VirtualAllocEx", NULL, NULL, (GenericFnPtr)&Perftools_VirtualAllocEx }, 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "VirtualFreeEx", NULL, NULL, (GenericFnPtr)&Perftools_VirtualFreeEx }, 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "MapViewOfFileEx", NULL, NULL, (GenericFnPtr)&Perftools_MapViewOfFileEx }, 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "UnmapViewOfFile", NULL, NULL, (GenericFnPtr)&Perftools_UnmapViewOfFile }, 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "LoadLibraryExW", NULL, NULL, (GenericFnPtr)&Perftools_LoadLibraryExW }, 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "FreeLibrary", NULL, NULL, (GenericFnPtr)&Perftools_FreeLibrary }, 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool LibcInfo::PopulateWindowsFn(const ModuleEntryCopy& module_entry) { 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // First, store the location of the function to patch before 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // patching it. If none of these functions are found in the module, 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // then this module has no libc in it, and we just return false. 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < kNumFunctions; i++) { 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!function_name_[i]) // we can turn off patching by unsetting name 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The ::GetProcAddress calls were done in the ModuleEntryCopy 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // constructor, so we don't have to make any windows calls here. 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GenericFnPtr fn = module_entry.rgProcAddresses[i]; 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fn) { 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) windows_fn_[i] = PreamblePatcher::ResolveTarget(fn); 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Some modules use the same function pointer for new and new[]. If 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we find that, set one of the pointers to NULL so we don't double- 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // patch. Same may happen with new and nothrow-new, or even new[] 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and nothrow-new. It's easiest just to check each fn-ptr against 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // every other. 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < kNumFunctions; i++) { 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int j = i+1; j < kNumFunctions; j++) { 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (windows_fn_[i] == windows_fn_[j]) { 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We NULL the later one (j), so as to minimize the chances we 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NULL kFree and kRealloc. See comments below. This is fragile! 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) windows_fn_[j] = NULL; 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There's always a chance that our module uses the same function 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as another module that we've already loaded. In that case, we 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // need to set our windows_fn to NULL, to avoid double-patching. 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int ifn = 0; ifn < kNumFunctions; ifn++) { 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int imod = 0; 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) imod < sizeof(g_module_libcs)/sizeof(*g_module_libcs); imod++) { 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (g_module_libcs[imod]->is_valid() && 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this->windows_fn(ifn) == g_module_libcs[imod]->windows_fn(ifn)) { 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) windows_fn_[ifn] = NULL; 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool found_non_null = false; 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < kNumFunctions; i++) { 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (windows_fn_[i]) 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) found_non_null = true; 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!found_non_null) 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It's important we didn't NULL out windows_fn_[kFree] or [kRealloc]. 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The reason is, if those are NULL-ed out, we'll never patch them 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and thus never get an origstub_fn_ value for them, and when we 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // try to call origstub_fn_[kFree/kRealloc] in Perftools_free and 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Perftools_realloc, below, it will fail. We could work around 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that by adding a pointer from one patch-unit to the other, but we 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // haven't needed to yet. 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(windows_fn_[kFree]); 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(windows_fn_[kRealloc]); 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // OK, we successfully populated. Let's store our member information. 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) module_base_address_ = module_entry.modBaseAddr; 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) module_base_size_ = module_entry.modBaseSize; 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int T> 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool LibcInfoWithPatchFunctions<T>::Patch(const LibcInfo& me_info) { 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CopyFrom(me_info); // copies the module_entry and the windows_fn_ array 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < kNumFunctions; i++) { 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (windows_fn_[i] && windows_fn_[i] != perftools_fn_[i]) { 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // if origstub_fn_ is not NULL, it's left around from a previous 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // patch. We need to set it to NULL for the new Patch call. 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since we've patched Unpatch() not to delete origstub_fn_ (it 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // causes problems in some contexts, though obviously not this 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // one), we should delete it now, before setting it to NULL. 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NOTE: casting from a function to a pointer is contra the C++ 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // spec. It's not safe on IA64, but is on i386. We use 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a C-style cast here to emphasize this is not legal C++. 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete[] (char*)(origstub_fn_[i]); 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) origstub_fn_[i] = NULL; // Patch() will fill this in 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(sidestep::SIDESTEP_SUCCESS, 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PreamblePatcher::Patch(windows_fn_[i], perftools_fn_[i], 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &origstub_fn_[i])); 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_is_valid(true); 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int T> 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LibcInfoWithPatchFunctions<T>::Unpatch() { 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have to cast our GenericFnPtrs to void* for unpatch. This is 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // contra the C++ spec; we use C-style casts to empahsize that. 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < kNumFunctions; i++) { 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (windows_fn_[i]) 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(sidestep::SIDESTEP_SUCCESS, 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PreamblePatcher::Unpatch((void*)windows_fn_[i], 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void*)perftools_fn_[i], 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void*)origstub_fn_[i])); 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_is_valid(false); 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WindowsInfo::Patch() { 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HMODULE hkernel32 = ::GetModuleHandleA("kernel32"); 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_NE(hkernel32, NULL); 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Unlike for libc, we know these exist in our module, so we can get 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and patch at the same time. 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < kNumFunctions; i++) { 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function_info_[i].windows_fn = (GenericFnPtr) 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ::GetProcAddress(hkernel32, function_info_[i].name); 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If origstub_fn is not NULL, it's left around from a previous 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // patch. We need to set it to NULL for the new Patch call. 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since we've patched Unpatch() not to delete origstub_fn_ (it 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // causes problems in some contexts, though obviously not this 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // one), we should delete it now, before setting it to NULL. 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NOTE: casting from a function to a pointer is contra the C++ 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // spec. It's not safe on IA64, but is on i386. We use 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a C-style cast here to emphasize this is not legal C++. 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete[] (char*)(function_info_[i].origstub_fn); 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function_info_[i].origstub_fn = NULL; // Patch() will fill this in 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(sidestep::SIDESTEP_SUCCESS, 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PreamblePatcher::Patch(function_info_[i].windows_fn, 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function_info_[i].perftools_fn, 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &function_info_[i].origstub_fn)); 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WindowsInfo::Unpatch() { 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have to cast our GenericFnPtrs to void* for unpatch. This is 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // contra the C++ spec; we use C-style casts to empahsize that. 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < kNumFunctions; i++) { 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(sidestep::SIDESTEP_SUCCESS, 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PreamblePatcher::Unpatch((void*)function_info_[i].windows_fn, 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void*)function_info_[i].perftools_fn, 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void*)function_info_[i].origstub_fn)); 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// You should hold the patch_all_modules_lock when calling this. 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PatchOneModuleLocked(const LibcInfo& me_info) { 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we don't already have info on this module, let's add it. This 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is where we're sad that each libcX has a different type, so we 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // can't use an array; instead, we have to use a switch statement. 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Patch() returns false if there were no libc functions in the module. 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < sizeof(g_module_libcs)/sizeof(*g_module_libcs); i++) { 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!g_module_libcs[i]->is_valid()) { // found an empty spot to add! 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (i) { 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 0: libc1.Patch(me_info); return; 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 1: libc2.Patch(me_info); return; 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 2: libc3.Patch(me_info); return; 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 3: libc4.Patch(me_info); return; 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 4: libc5.Patch(me_info); return; 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 5: libc6.Patch(me_info); return; 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 6: libc7.Patch(me_info); return; 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 7: libc8.Patch(me_info); return; 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("PERFTOOLS ERROR: Too many modules containing libc in this executable\n"); 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PatchMainExecutableLocked() { 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (main_executable.patched()) 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // main executable has already been patched 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ModuleEntryCopy fake_module_entry; // make a fake one to pass into Patch() 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No need to call PopulateModuleEntryProcAddresses on the main executable. 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) main_executable.PopulateWindowsFn(fake_module_entry); 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) main_executable.Patch(main_executable); 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This lock is subject to a subtle and annoying lock inversion 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// problem: it may interact badly with unknown internal windows locks. 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In particular, windows may be holding a lock when it calls 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LoadLibraryExW and FreeLibrary, which we've patched. We have those 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// routines call PatchAllModules, which acquires this lock. If we 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// make windows system calls while holding this lock, those system 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// calls may need the internal windows locks that are being held in 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the call to LoadLibraryExW, resulting in deadlock. The solution is 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to be very careful not to call *any* windows routines while holding 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// patch_all_modules_lock, inside PatchAllModules(). 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static SpinLock patch_all_modules_lock(SpinLock::LINKER_INITIALIZED); 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// last_loaded: The set of modules that were loaded the last time 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PatchAllModules was called. This is an optimization for only 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// looking at modules that were added or removed from the last call. 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static std::set<HMODULE> *g_last_loaded; 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Iterates over all the modules currently loaded by the executable, 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// according to windows, and makes sure they're all patched. Most 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modules will already be in loaded_modules, meaning we have already 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// loaded and either patched them or determined they did not need to 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be patched. Others will not, which means we need to patch them 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (if necessary). Finally, we have to go through the existing 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// g_module_libcs and see if any of those are *not* in the modules 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// currently loaded by the executable. If so, we need to invalidate 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// them. Returns true if we did any work (patching or invalidating), 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// false if we were a noop. May update loaded_modules as well. 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NOTE: you must hold the patch_all_modules_lock to access loaded_modules. 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PatchAllModules() { 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<ModuleEntryCopy> modules; 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool made_changes = false; 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const HANDLE hCurrentProcess = GetCurrentProcess(); 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD num_modules = 0; 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HMODULE hModules[kMaxModules]; // max # of modules we support in one process 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!::EnumProcessModules(hCurrentProcess, hModules, sizeof(hModules), 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &num_modules)) { 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_modules = 0; 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // EnumProcessModules actually set the bytes written into hModules, 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so we need to divide to make num_modules actually be a module-count. 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_modules /= sizeof(*hModules); 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num_modules >= kMaxModules) { 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("PERFTOOLS ERROR: Too many modules in this executable to try" 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) " to patch them all (if you need to, raise kMaxModules in" 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) " patch_functions.cc).\n"); 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_modules = kMaxModules; 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now we handle the unpatching of modules we have in g_module_libcs 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but that were not found in EnumProcessModules. We need to 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // invalidate them. To speed that up, we store the EnumProcessModules 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // output in a set. 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // At the same time, we prepare for the adding of new modules, by 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // removing from hModules all the modules we know we've already 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // patched (or decided don't need to be patched). At the end, 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // hModules will hold only the modules that we need to consider patching. 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::set<HMODULE> currently_loaded_modules; 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpinLockHolder h(&patch_all_modules_lock); 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!g_last_loaded) g_last_loaded = new std::set<HMODULE>; 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // At the end of this loop, currently_loaded_modules contains the 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // full list of EnumProcessModules, and hModules just the ones we 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // haven't handled yet. 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < num_modules; ) { 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) currently_loaded_modules.insert(hModules[i]); 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (g_last_loaded->count(hModules[i]) > 0) { 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hModules[i] = hModules[--num_modules]; // replace element i with tail 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i++; // keep element i 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now we do the unpatching/invalidation. 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < sizeof(g_module_libcs)/sizeof(*g_module_libcs); i++) { 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (g_module_libcs[i]->patched() && 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) currently_loaded_modules.count(g_module_libcs[i]->hmodule()) == 0) { 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Means g_module_libcs[i] is no longer loaded (no me32 matched). 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We could call Unpatch() here, but why bother? The module 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // has gone away, so nobody is going to call into it anyway. 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_module_libcs[i]->set_is_valid(false); 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) made_changes = true; 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Update the loaded module cache. 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_last_loaded->swap(currently_loaded_modules); 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now that we know what modules are new, let's get the info we'll 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // need to patch them. Note this *cannot* be done while holding the 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // lock, since it needs to make windows calls (see the lock-inversion 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // comments before the definition of patch_all_modules_lock). 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MODULEINFO mi; 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < num_modules; i++) { 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (::GetModuleInformation(hCurrentProcess, hModules[i], &mi, sizeof(mi))) 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modules.push_back(ModuleEntryCopy(mi)); 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now we can do the patching of new modules. 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpinLockHolder h(&patch_all_modules_lock); 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::vector<ModuleEntryCopy>::iterator it = modules.begin(); 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != modules.end(); ++it) { 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LibcInfo libc_info; 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (libc_info.PopulateWindowsFn(*it)) { // true==module has libc routines 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PatchOneModuleLocked(libc_info); 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) made_changes = true; 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now that we've dealt with the modules (dlls), update the main 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // executable. We do this last because PatchMainExecutableLocked 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // wants to look at how other modules were patched. 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!main_executable.patched()) { 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PatchMainExecutableLocked(); 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) made_changes = true; 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(csilvers): for this to be reliable, we need to also take 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // into account if we *would* have patched any modules had they not 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // already been loaded. (That is, made_changes should ignore 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // g_last_loaded.) 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return made_changes; 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // end unnamed namespace 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// --------------------------------------------------------------------- 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Now that we've done all the patching machinery, let's actually 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// define the functions we're patching in. Mostly these are 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// simple wrappers around the do_* routines in tcmalloc.cc. 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In fact, we #include tcmalloc.cc to get at the tcmalloc internal 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// do_* functions, the better to write our own hook functions. 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// U-G-L-Y, I know. But the alternatives are, perhaps, worse. This 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// also lets us define _msize(), _expand(), and other windows-specific 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// functions here, using tcmalloc internals, without polluting 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// tcmalloc.cc. 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ------------------------------------------------------------------- 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(csilvers): refactor tcmalloc.cc into two files, so I can link 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// against the file with do_malloc, and ignore the one with malloc. 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "tcmalloc.cc" 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int T> 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* LibcInfoWithPatchFunctions<T>::Perftools_malloc(size_t size) __THROW { 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* result = do_malloc_or_cpp_alloc(size); 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeNewHook(result, size); 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int T> 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LibcInfoWithPatchFunctions<T>::Perftools_free(void* ptr) __THROW { 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeDeleteHook(ptr); 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This calls the windows free if do_free decides ptr was not 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // allocated by tcmalloc. Note it calls the origstub_free from 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // *this* templatized instance of LibcInfo. See "template 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // trickiness" above. 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do_free_with_callback(ptr, (void (*)(void*))origstub_fn_[kFree]); 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int T> 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* LibcInfoWithPatchFunctions<T>::Perftools_realloc( 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* old_ptr, size_t new_size) __THROW { 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (old_ptr == NULL) { 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* result = do_malloc_or_cpp_alloc(new_size); 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeNewHook(result, new_size); 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (new_size == 0) { 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeDeleteHook(old_ptr); 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do_free_with_callback(old_ptr, 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void (*)(void*))origstub_fn_[kFree]); 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return do_realloc_with_callback( 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_ptr, new_size, 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void (*)(void*))origstub_fn_[kFree], 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (size_t (*)(const void*))origstub_fn_[k_Msize]); 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int T> 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* LibcInfoWithPatchFunctions<T>::Perftools_calloc( 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t n, size_t elem_size) __THROW { 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* result = do_calloc(n, elem_size); 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeNewHook(result, n * elem_size); 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int T> 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* LibcInfoWithPatchFunctions<T>::Perftools_new(size_t size) { 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* p = cpp_alloc(size, false); 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeNewHook(p, size); 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return p; 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int T> 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* LibcInfoWithPatchFunctions<T>::Perftools_newarray(size_t size) { 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* p = cpp_alloc(size, false); 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeNewHook(p, size); 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return p; 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int T> 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LibcInfoWithPatchFunctions<T>::Perftools_delete(void *p) { 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeDeleteHook(p); 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do_free_with_callback(p, (void (*)(void*))origstub_fn_[kFree]); 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int T> 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LibcInfoWithPatchFunctions<T>::Perftools_deletearray(void *p) { 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeDeleteHook(p); 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do_free_with_callback(p, (void (*)(void*))origstub_fn_[kFree]); 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int T> 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* LibcInfoWithPatchFunctions<T>::Perftools_new_nothrow( 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t size, const std::nothrow_t&) __THROW { 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* p = cpp_alloc(size, true); 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeNewHook(p, size); 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return p; 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int T> 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* LibcInfoWithPatchFunctions<T>::Perftools_newarray_nothrow( 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t size, const std::nothrow_t&) __THROW { 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* p = cpp_alloc(size, true); 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeNewHook(p, size); 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return p; 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int T> 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LibcInfoWithPatchFunctions<T>::Perftools_delete_nothrow( 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *p, const std::nothrow_t&) __THROW { 8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeDeleteHook(p); 8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do_free_with_callback(p, (void (*)(void*))origstub_fn_[kFree]); 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int T> 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LibcInfoWithPatchFunctions<T>::Perftools_deletearray_nothrow( 8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *p, const std::nothrow_t&) __THROW { 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeDeleteHook(p); 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do_free_with_callback(p, (void (*)(void*))origstub_fn_[kFree]); 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// _msize() lets you figure out how much space is reserved for a 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// pointer, in Windows. Even if applications don't call it, any DLL 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// with global constructors will call (transitively) something called 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// __dllonexit_lk in order to make sure the destructors get called 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// when the dll unloads. And that will call msize -- horrible things 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// can ensue if this is not hooked. Other parts of libc may also call 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this internally. 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int T> 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t LibcInfoWithPatchFunctions<T>::Perftools__msize(void* ptr) __THROW { 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetSizeWithCallback(ptr, (size_t (*)(const void*))origstub_fn_[k_Msize]); 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We need to define this because internal windows functions like to 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// call into it(?). _expand() is like realloc but doesn't move the 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// pointer. We punt, which will cause callers to fall back on realloc. 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<int T> 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* LibcInfoWithPatchFunctions<T>::Perftools__expand(void *ptr, 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t size) __THROW { 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LPVOID WINAPI WindowsInfo::Perftools_HeapAlloc(HANDLE hHeap, DWORD dwFlags, 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD_PTR dwBytes) { 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID result = ((LPVOID (WINAPI *)(HANDLE, DWORD, DWORD_PTR)) 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function_info_[kHeapAlloc].origstub_fn)( 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hHeap, dwFlags, dwBytes); 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeNewHook(result, dwBytes); 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL WINAPI WindowsInfo::Perftools_HeapFree(HANDLE hHeap, DWORD dwFlags, 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID lpMem) { 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeDeleteHook(lpMem); 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ((BOOL (WINAPI *)(HANDLE, DWORD, LPVOID)) 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function_info_[kHeapFree].origstub_fn)( 9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hHeap, dwFlags, lpMem); 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LPVOID WINAPI WindowsInfo::Perftools_VirtualAllocEx(HANDLE process, 9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID address, 9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZE_T size, DWORD type, 9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD protect) { 9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID result = ((LPVOID (WINAPI *)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD)) 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function_info_[kVirtualAllocEx].origstub_fn)( 9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) process, address, size, type, protect); 9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // VirtualAllocEx() seems to be the Windows equivalent of mmap() 9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeMmapHook(result, address, size, protect, type, -1, 0); 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL WINAPI WindowsInfo::Perftools_VirtualFreeEx(HANDLE process, LPVOID address, 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZE_T size, DWORD type) { 9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeMunmapHook(address, size); 9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ((BOOL (WINAPI *)(HANDLE, LPVOID, SIZE_T, DWORD)) 9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function_info_[kVirtualFreeEx].origstub_fn)( 9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) process, address, size, type); 9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LPVOID WINAPI WindowsInfo::Perftools_MapViewOfFileEx( 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, 9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap, LPVOID lpBaseAddress) { 9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For this function pair, you always deallocate the full block of 9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // data that you allocate, so NewHook/DeleteHook is the right API. 9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID result = ((LPVOID (WINAPI *)(HANDLE, DWORD, DWORD, DWORD, 9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZE_T, LPVOID)) 9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function_info_[kMapViewOfFileEx].origstub_fn)( 9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, 9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dwFileOffsetLow, dwNumberOfBytesToMap, lpBaseAddress); 9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeNewHook(result, dwNumberOfBytesToMap); 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL WINAPI WindowsInfo::Perftools_UnmapViewOfFile(LPCVOID lpBaseAddress) { 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MallocHook::InvokeDeleteHook(lpBaseAddress); 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ((BOOL (WINAPI *)(LPCVOID)) 9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function_info_[kUnmapViewOfFile].origstub_fn)( 9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lpBaseAddress); 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// g_load_map holds a copy of windows' refcount for how many times 9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// each currently loaded module has been loaded and unloaded. We use 9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// it as an optimization when the same module is loaded more than 9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// once: as long as the refcount stays above 1, we don't need to worry 9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// about patching because it's already patched. Likewise, we don't 9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// need to unpatch until the refcount drops to 0. load_map is 9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// maintained in LoadLibraryExW and FreeLibrary, and only covers 9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modules explicitly loaded/freed via those interfaces. 9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static std::map<HMODULE, int>* g_load_map = NULL; 9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HMODULE WINAPI WindowsInfo::Perftools_LoadLibraryExW(LPCWSTR lpFileName, 9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HANDLE hFile, 9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dwFlags) { 9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HMODULE rv; 9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check to see if the modules is already loaded, flag 0 gets a 9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // reference if it was loaded. If it was loaded no need to call 9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // PatchAllModules, just increase the reference count to match 9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // what GetModuleHandleExW does internally inside windows. 9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (::GetModuleHandleExW(0, lpFileName, &rv)) { 9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Not already loaded, so load it. 9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ((HMODULE (WINAPI *)(LPCWSTR, HANDLE, DWORD)) 10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function_info_[kLoadLibraryExW].origstub_fn)( 10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lpFileName, hFile, dwFlags); 10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This will patch any newly loaded libraries, if patching needs 10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to be done. 10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PatchAllModules(); 10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL WINAPI WindowsInfo::Perftools_FreeLibrary(HMODULE hLibModule) { 10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL rv = ((BOOL (WINAPI *)(HMODULE)) 10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function_info_[kFreeLibrary].origstub_fn)(hLibModule); 10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check to see if the module is still loaded by passing the base 10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // address and seeing if it comes back with the same address. If it 10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is the same address it's still loaded, so the FreeLibrary() call 10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // was a noop, and there's no need to redo the patching. 10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HMODULE owner = NULL; 10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL result = ::GetModuleHandleExW( 10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | 10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT), 10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (LPCWSTR)hLibModule, 10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &owner); 10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result && owner == hLibModule) 10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PatchAllModules(); // this will fix up the list of patched libraries 10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// --------------------------------------------------------------------- 10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PatchWindowsFunctions() 10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is the function that is exposed to the outside world. 10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It should be called before the program becomes multi-threaded, 10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// since main_executable_windows.Patch() is not thread-safe. 10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// --------------------------------------------------------------------- 10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PatchWindowsFunctions() { 10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This does the libc patching in every module, and the main executable. 10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PatchAllModules(); 10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) main_executable_windows.Patch(); 10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if 0 10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It's possible to unpatch all the functions when we are exiting. 10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The idea is to handle properly windows-internal data that is 10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// allocated before PatchWindowsFunctions is called. If all 10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// destruction happened in reverse order from construction, then we 10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// could call UnpatchWindowsFunctions at just the right time, so that 10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that early-allocated data would be freed using the windows 10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// allocation functions rather than tcmalloc. The problem is that 10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// windows allocates some structures lazily, so it would allocate them 10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// late (using tcmalloc) and then try to deallocate them late as well. 10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// So instead of unpatching, we just modify all the tcmalloc routines 10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// so they call through to the libc rountines if the memory in 10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// question doesn't seem to have been allocated with tcmalloc. I keep 10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this unpatch code around for reference. 10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UnpatchWindowsFunctions() { 10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We need to go back to the system malloc/etc at global destruct time, 10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so objects that were constructed before tcmalloc, using the system 10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // malloc, can destroy themselves using the system free. This depends 10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // on DLLs unloading in the reverse order in which they load! 10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We also go back to the default HeapAlloc/etc, just for consistency. 10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Who knows, it may help avoid weird bugs in some situations. 10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) main_executable_windows.Unpatch(); 10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) main_executable.Unpatch(); 10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (libc1.is_valid()) libc1.Unpatch(); 10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (libc2.is_valid()) libc2.Unpatch(); 10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (libc3.is_valid()) libc3.Unpatch(); 10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (libc4.is_valid()) libc4.Unpatch(); 10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (libc5.is_valid()) libc5.Unpatch(); 10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (libc6.is_valid()) libc6.Unpatch(); 10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (libc7.is_valid()) libc7.Unpatch(); 10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (libc8.is_valid()) libc8.Unpatch(); 10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1081