15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Static class for hooking Win32 API routines. 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Some notes about how to hook Memory Allocation Routines in Windows. 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For our purposes we do not hook the libc routines. There are two 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// reasons for this. First, the libc routines all go through HeapAlloc 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// anyway. So, it's redundant to log both HeapAlloc and malloc. 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Second, it can be tricky to hook in both static and dynamic linkages 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of libc. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h> 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "memory_hook.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "memory_watcher.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "preamble_patcher.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Calls GetProcAddress, but casts to the correct type. 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define GET_PROC_ADDRESS(hmodule, name) \ 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ( (Type_##name)(::GetProcAddress(hmodule, #name)) ) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Macro to declare Patch functions. 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define DECLARE_PATCH(name) Patch<Type_##name> patch_##name 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Macro to install Patch functions. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define INSTALL_PATCH(name) do { \ 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_##name.set_original(GET_PROC_ADDRESS(hkernel32, ##name)); \ 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_##name.Install(&Perftools_##name); \ 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} while (0) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Macro to install Patch functions. 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define INSTALL_NTDLLPATCH(name) do { \ 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_##name.set_original(GET_PROC_ADDRESS(hntdll, ##name)); \ 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_##name.Install(&Perftools_##name); \ 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} while (0) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Macro to uninstall Patch functions. 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define UNINSTALL_PATCH(name) patch_##name.Uninstall(); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Windows APIs to be hooked 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HeapAlloc routines 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef HANDLE (WINAPI *Type_HeapCreate)(DWORD flOptions, 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZE_T dwInitialSize, 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZE_T dwMaximumSize); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef BOOL (WINAPI *Type_HeapDestroy)(HANDLE hHeap); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef LPVOID (WINAPI *Type_HeapAlloc)(HANDLE hHeap, DWORD dwFlags, 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD_PTR dwBytes); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef LPVOID (WINAPI *Type_HeapReAlloc)(HANDLE hHeap, DWORD dwFlags, 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID lpMem, SIZE_T dwBytes); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef BOOL (WINAPI *Type_HeapFree)(HANDLE hHeap, DWORD dwFlags, 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID lpMem); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GlobalAlloc routines 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef HGLOBAL (WINAPI *Type_GlobalAlloc)(UINT uFlags, SIZE_T dwBytes); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef HGLOBAL (WINAPI *Type_GlobalReAlloc)(HGLOBAL hMem, SIZE_T dwBytes, 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UINT uFlags); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef HGLOBAL (WINAPI *Type_GlobalFree)(HGLOBAL hMem); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LocalAlloc routines 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef HLOCAL (WINAPI *Type_LocalAlloc)(UINT uFlags, SIZE_T uBytes); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef HLOCAL (WINAPI *Type_LocalReAlloc)(HLOCAL hMem, SIZE_T uBytes, 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UINT uFlags); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef HLOCAL (WINAPI *Type_LocalFree)(HLOCAL hMem); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A Windows-API equivalent of mmap and munmap, for "anonymous regions" 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef LPVOID (WINAPI *Type_VirtualAllocEx)(HANDLE process, LPVOID address, 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZE_T size, DWORD type, 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD protect); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef BOOL (WINAPI *Type_VirtualFreeEx)(HANDLE process, LPVOID address, 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZE_T size, DWORD type); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A Windows-API equivalent of mmap and munmap, for actual files 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef LPVOID (WINAPI *Type_MapViewOfFile)(HANDLE hFileMappingObject, 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dwDesiredAccess, 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dwFileOffsetHigh, 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dwFileOffsetLow, 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZE_T dwNumberOfBytesToMap); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef LPVOID (WINAPI *Type_MapViewOfFileEx)(HANDLE hFileMappingObject, 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dwDesiredAccess, 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dwFileOffsetHigh, 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dwFileOffsetLow, 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZE_T dwNumberOfBytesToMap, 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID lpBaseAddress); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef BOOL (WINAPI *Type_UnmapViewOfFile)(LPVOID lpBaseAddress); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef DWORD (WINAPI *Type_NtUnmapViewOfSection)(HANDLE process, 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID lpBaseAddress); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Patch is a template for keeping the pointer to the original 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// hooked routine, the function to call when hooked, and the 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// stub routine which is patched. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<class T> 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Patch { 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Constructor. Does not hook the function yet. 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Patch<T>() 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : original_function_(NULL), 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_function_(NULL), 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stub_function_(NULL) { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Destructor. Unhooks the function if it has been hooked. 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~Patch<T>() { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Uninstall(); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Patches original function with func. 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Must have called set_original to set the original function. 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Install(T func) { 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_function_ = func; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(patch_function_ != NULL); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(original_function_ != NULL); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(stub_function_ == NULL); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(sidestep::SIDESTEP_SUCCESS == 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sidestep::PreamblePatcher::Patch(original_function_, 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_function_, &stub_function_)); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Un-patches the function. 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Uninstall() { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (stub_function_) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sidestep::PreamblePatcher::Unpatch(original_function_, 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_function_, stub_function_); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stub_function_ = NULL; 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set the function to be patched. 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void set_original(T original) { original_function_ = original; } 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the original function being patched. 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) T original() { return original_function_; } 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the patched function. (e.g. the replacement function) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) T patched() { return patch_function_; } 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Access to the stub for calling the original function 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // while it is patched. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) T operator()() { 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(stub_function_); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return stub_function_; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The function that we plan to patch. 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) T original_function_; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The function to replace the original with. 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) T patch_function_; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // To unpatch, we also need to keep around a "stub" that points to the 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // pre-patched Windows function. 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) T stub_function_; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// All Windows memory-allocation routines call through to one of these. 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DECLARE_PATCH(HeapCreate); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DECLARE_PATCH(HeapDestroy); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DECLARE_PATCH(HeapAlloc); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DECLARE_PATCH(HeapReAlloc); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DECLARE_PATCH(HeapFree); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DECLARE_PATCH(VirtualAllocEx); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DECLARE_PATCH(VirtualFreeEx); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DECLARE_PATCH(MapViewOfFile); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DECLARE_PATCH(MapViewOfFileEx); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DECLARE_PATCH(UnmapViewOfFile); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DECLARE_PATCH(GlobalAlloc); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DECLARE_PATCH(GlobalReAlloc); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DECLARE_PATCH(GlobalFree); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DECLARE_PATCH(LocalAlloc); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DECLARE_PATCH(LocalReAlloc); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DECLARE_PATCH(LocalFree); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DECLARE_PATCH(NtUnmapViewOfSection); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Our replacement functions. 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static HANDLE WINAPI Perftools_HeapCreate(DWORD flOptions, 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZE_T dwInitialSize, 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZE_T dwMaximumSize) { 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dwInitialSize > 4096) 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dwInitialSize = 4096; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return patch_HeapCreate()(flOptions, dwInitialSize, dwMaximumSize); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static BOOL WINAPI Perftools_HeapDestroy(HANDLE hHeap) { 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return patch_HeapDestroy()(hHeap); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static LPVOID WINAPI Perftools_HeapAlloc(HANDLE hHeap, DWORD dwFlags, 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD_PTR dwBytes) { 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID rv = patch_HeapAlloc()(hHeap, dwFlags, dwBytes); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MemoryHook::hook()->OnTrack(hHeap, reinterpret_cast<int32>(rv), dwBytes); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static BOOL WINAPI Perftools_HeapFree(HANDLE hHeap, DWORD dwFlags, 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID lpMem) { 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t size = 0; 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (lpMem != 0) { 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size = HeapSize(hHeap, 0, lpMem); // Will crash if lpMem is 0. 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: size could be 0; HeapAlloc does allocate 0 length buffers. 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MemoryHook::hook()->OnUntrack(hHeap, reinterpret_cast<int32>(lpMem), size); 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return patch_HeapFree()(hHeap, dwFlags, lpMem); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static LPVOID WINAPI Perftools_HeapReAlloc(HANDLE hHeap, DWORD dwFlags, 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID lpMem, SIZE_T dwBytes) { 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Don't call realloc, but instead do a free/malloc. The problem is that 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the builtin realloc may either expand a buffer, or it may simply 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // just call free/malloc. If so, we will already have tracked the new 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // block via Perftools_HeapAlloc. 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID rv = Perftools_HeapAlloc(hHeap, dwFlags, dwBytes); 2200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) DCHECK_EQ((HEAP_REALLOC_IN_PLACE_ONLY & dwFlags), 0u); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If there was an old buffer, now copy the data to the new buffer. 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (lpMem != 0) { 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t size = HeapSize(hHeap, 0, lpMem); 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (size > dwBytes) 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size = dwBytes; 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: size could be 0; HeapAlloc does allocate 0 length buffers. 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(rv, lpMem, size); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Perftools_HeapFree(hHeap, dwFlags, lpMem); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static LPVOID WINAPI Perftools_VirtualAllocEx(HANDLE process, LPVOID address, 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZE_T size, DWORD type, 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD protect) { 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool already_committed = false; 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (address != NULL) { 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MEMORY_BASIC_INFORMATION info; 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(VirtualQuery(address, &info, sizeof(info))); 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (info.State & MEM_COMMIT) { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) already_committed = true; 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(size >= info.RegionSize); 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool reserving = (address == NULL) || (type & MEM_RESERVE); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool committing = !already_committed && (type & MEM_COMMIT); 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID result = patch_VirtualAllocEx()(process, address, size, type, 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protect); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MEMORY_BASIC_INFORMATION info; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(VirtualQuery(result, &info, sizeof(info))); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size = info.RegionSize; 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (committing) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MemoryHook::hook()->OnTrack(0, reinterpret_cast<int32>(result), size); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static BOOL WINAPI Perftools_VirtualFreeEx(HANDLE process, LPVOID address, 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZE_T size, DWORD type) { 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int chunk_size = size; 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MEMORY_BASIC_INFORMATION info; 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(VirtualQuery(address, &info, sizeof(info))); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (chunk_size == 0) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunk_size = info.RegionSize; 2690f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) bool decommit = (info.State & MEM_COMMIT) != 0; 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (decommit) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MemoryHook::hook()->OnUntrack(0, reinterpret_cast<int32>(address), 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunk_size); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return patch_VirtualFreeEx()(process, address, size, type); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static base::Lock known_maps_lock; 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static std::map<void*, int> known_maps; 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static LPVOID WINAPI Perftools_MapViewOfFileEx(HANDLE hFileMappingObject, 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dwDesiredAccess, 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dwFileOffsetHigh, 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dwFileOffsetLow, 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZE_T dwNumberOfBytesToMap, 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID lpBaseAddress) { 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For this function pair, you always deallocate the full block of 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // data that you allocate, so NewHook/DeleteHook is the right API. 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID result = patch_MapViewOfFileEx()(hFileMappingObject, dwDesiredAccess, 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dwFileOffsetHigh, dwFileOffsetLow, 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dwNumberOfBytesToMap, lpBaseAddress); 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock lock(known_maps_lock); 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MEMORY_BASIC_INFORMATION info; 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (known_maps.find(result) == known_maps.end()) { 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(VirtualQuery(result, &info, sizeof(info))); 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(mbelshe): THIS map uses the standard heap!!!! 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) known_maps[result] = 1; 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MemoryHook::hook()->OnTrack(0, reinterpret_cast<int32>(result), 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.RegionSize); 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) known_maps[result] = known_maps[result] + 1; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static LPVOID WINAPI Perftools_MapViewOfFile(HANDLE hFileMappingObject, 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dwDesiredAccess, 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dwFileOffsetHigh, 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dwFileOffsetLow, 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZE_T dwNumberOfBytesToMap) { 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Perftools_MapViewOfFileEx(hFileMappingObject, dwDesiredAccess, 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dwFileOffsetHigh, dwFileOffsetLow, 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dwNumberOfBytesToMap, 0); 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static BOOL WINAPI Perftools_UnmapViewOfFile(LPVOID lpBaseAddress) { 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This will call into NtUnmapViewOfSection(). 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return patch_UnmapViewOfFile()(lpBaseAddress); 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static DWORD WINAPI Perftools_NtUnmapViewOfSection(HANDLE process, 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPVOID lpBaseAddress) { 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Some windows APIs call directly into this routine rather 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // than calling UnmapViewOfFile. If we didn't trap this function, 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // then we appear to have bogus leaks. 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock lock(known_maps_lock); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MEMORY_BASIC_INFORMATION info; 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(VirtualQuery(lpBaseAddress, &info, sizeof(info))); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (known_maps.find(lpBaseAddress) != known_maps.end()) { 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (known_maps[lpBaseAddress] == 1) { 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MemoryHook::hook()->OnUntrack(0, reinterpret_cast<int32>(lpBaseAddress), 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.RegionSize); 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) known_maps.erase(lpBaseAddress); 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) known_maps[lpBaseAddress] = known_maps[lpBaseAddress] - 1; 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return patch_NtUnmapViewOfSection()(process, lpBaseAddress); 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static HGLOBAL WINAPI Perftools_GlobalAlloc(UINT uFlags, SIZE_T dwBytes) { 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GlobalAlloc is built atop HeapAlloc anyway. So we don't track these. 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GlobalAlloc will internally call into HeapAlloc and we track there. 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Force all memory to be fixed. 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uFlags &= ~GMEM_MOVEABLE; 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HGLOBAL rv = patch_GlobalAlloc()(uFlags, dwBytes); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static HGLOBAL WINAPI Perftools_GlobalFree(HGLOBAL hMem) { 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return patch_GlobalFree()(hMem); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static HGLOBAL WINAPI Perftools_GlobalReAlloc(HGLOBAL hMem, SIZE_T dwBytes, 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UINT uFlags) { 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(jar): [The following looks like a copy/paste typo from LocalRealloc.] 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GlobalDiscard is a macro which calls LocalReAlloc with size 0. 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dwBytes == 0) { 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return patch_GlobalReAlloc()(hMem, dwBytes, uFlags); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HGLOBAL rv = Perftools_GlobalAlloc(uFlags, dwBytes); 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (hMem != 0) { 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t size = GlobalSize(hMem); 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (size > dwBytes) 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size = dwBytes; 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: size could be 0; HeapAlloc does allocate 0 length buffers. 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(rv, hMem, size); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Perftools_GlobalFree(hMem); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static HLOCAL WINAPI Perftools_LocalAlloc(UINT uFlags, SIZE_T dwBytes) { 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // LocalAlloc is built atop HeapAlloc anyway. So we don't track these. 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // LocalAlloc will internally call into HeapAlloc and we track there. 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Force all memory to be fixed. 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uFlags &= ~LMEM_MOVEABLE; 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HLOCAL rv = patch_LocalAlloc()(uFlags, dwBytes); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static HLOCAL WINAPI Perftools_LocalFree(HLOCAL hMem) { 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return patch_LocalFree()(hMem); 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static HLOCAL WINAPI Perftools_LocalReAlloc(HLOCAL hMem, SIZE_T dwBytes, 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UINT uFlags) { 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // LocalDiscard is a macro which calls LocalReAlloc with size 0. 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dwBytes == 0) { 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return patch_LocalReAlloc()(hMem, dwBytes, uFlags); 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HGLOBAL rv = Perftools_LocalAlloc(uFlags, dwBytes); 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (hMem != 0) { 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t size = LocalSize(hMem); 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (size > dwBytes) 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size = dwBytes; 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: size could be 0; HeapAlloc does allocate 0 length buffers. 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(rv, hMem, size); 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Perftools_LocalFree(hMem); 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MemoryHook::hooked_ = false; 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MemoryHook* MemoryHook::global_hook_ = NULL; 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MemoryHook::MemoryHook() 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : watcher_(NULL), 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) heap_(NULL) { 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreateHeap(); 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MemoryHook::~MemoryHook() { 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It's a bit dangerous to ever close this heap; MemoryWatchers may have 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // used this heap for their tracking data. Closing the heap while any 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MemoryWatchers still exist is pretty dangerous. 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CloseHeap(); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MemoryHook::Initialize() { 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (global_hook_ == NULL) 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) global_hook_ = new MemoryHook(); 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MemoryHook::Hook() { 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!hooked_); 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!hooked_) { 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(global_hook_); 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Luckily, Patch() doesn't call malloc or windows alloc routines 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // itself -- though it does call new (we can use PatchWithStub to 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // get around that, and will need to if we need to patch new). 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HMODULE hkernel32 = ::GetModuleHandle(L"kernel32"); 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(hkernel32 != NULL); 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HMODULE hntdll = ::GetModuleHandle(L"ntdll"); 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(hntdll != NULL); 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now that we've found all the functions, patch them 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSTALL_PATCH(HeapCreate); 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSTALL_PATCH(HeapDestroy); 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSTALL_PATCH(HeapAlloc); 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSTALL_PATCH(HeapReAlloc); 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSTALL_PATCH(HeapFree); 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSTALL_PATCH(VirtualAllocEx); 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSTALL_PATCH(VirtualFreeEx); 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSTALL_PATCH(MapViewOfFileEx); 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSTALL_PATCH(MapViewOfFile); 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSTALL_PATCH(UnmapViewOfFile); 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSTALL_NTDLLPATCH(NtUnmapViewOfSection); 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSTALL_PATCH(GlobalAlloc); 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSTALL_PATCH(GlobalReAlloc); 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSTALL_PATCH(GlobalFree); 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSTALL_PATCH(LocalAlloc); 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSTALL_PATCH(LocalReAlloc); 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSTALL_PATCH(LocalFree); 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We are finally completely hooked. 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hooked_ = true; 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MemoryHook::Unhook() { 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (hooked_) { 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We need to go back to the system malloc/etc at global destruct time, 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so objects that were constructed before tcmalloc, using the system 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // malloc, can destroy themselves using the system free. This depends 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // on DLLs unloading in the reverse order in which they load! 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We also go back to the default HeapAlloc/etc, just for consistency. 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Who knows, it may help avoid weird bugs in some situations. 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNINSTALL_PATCH(HeapCreate); 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNINSTALL_PATCH(HeapDestroy); 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNINSTALL_PATCH(HeapAlloc); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNINSTALL_PATCH(HeapReAlloc); 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNINSTALL_PATCH(HeapFree); 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNINSTALL_PATCH(VirtualAllocEx); 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNINSTALL_PATCH(VirtualFreeEx); 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNINSTALL_PATCH(MapViewOfFile); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNINSTALL_PATCH(MapViewOfFileEx); 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNINSTALL_PATCH(UnmapViewOfFile); 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNINSTALL_PATCH(NtUnmapViewOfSection); 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNINSTALL_PATCH(GlobalAlloc); 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNINSTALL_PATCH(GlobalReAlloc); 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNINSTALL_PATCH(GlobalFree); 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNINSTALL_PATCH(LocalAlloc); 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNINSTALL_PATCH(LocalReAlloc); 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNINSTALL_PATCH(LocalFree); 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hooked_ = false; 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MemoryHook::RegisterWatcher(MemoryObserver* watcher) { 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(global_hook_->watcher_ == NULL); 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!hooked_) 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Hook(); 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(global_hook_); 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) global_hook_->watcher_ = watcher; 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MemoryHook::UnregisterWatcher(MemoryObserver* watcher) { 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(hooked_); 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(global_hook_->watcher_ == watcher); 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(jar): changing watcher_ here is very racy. Other threads may (without 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a lock) testing, and then calling through this value. We probably can't 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // remove this until we are single threaded. 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) global_hook_->watcher_ = NULL; 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For now, since there are no more watchers, unhook memory. 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Unhook(); 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MemoryHook::CreateHeap() { 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a heap for our own memory. 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(heap_ == NULL); 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) heap_ = HeapCreate(0, 0, 0); 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(heap_ != NULL); 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return heap_ != NULL; 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MemoryHook::CloseHeap() { 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(heap_ != NULL); 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeapDestroy(heap_); 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) heap_ = NULL; 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MemoryHook::OnTrack(HANDLE heap, int32 id, int32 size) { 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Don't notify about allocations to our internal heap. 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (heap == heap_) 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (watcher_) 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) watcher_->OnTrack(heap, id, size); 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MemoryHook::OnUntrack(HANDLE heap, int32 id, int32 size) { 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Don't notify about allocations to our internal heap. 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (heap == heap_) 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (watcher_) 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) watcher_->OnUntrack(heap, id, size); 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 563