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