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. For now, 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we only add one watcher at a time. 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(mbelshe): Support multiple watchers. 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef MEMORY_WATCHER_MEMORY_HOOK_ 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MEMORY_WATCHER_MEMORY_HOOK_ 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// When allocating memory for internal use with the MemoryHook, 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we must always use the MemoryHook's heap; otherwise, the memory 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// gets tracked, and it becomes an infinite loop (allocation() calls 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MemoryHook() which calls allocation(), etc). 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PrivateHookAllocator is an STL-friendly Allocator so that STL lists, 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// maps, etc can be used on the global MemoryHook's heap. 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class T> 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PrivateHookAllocator { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // These type definitions are needed for stl allocators. 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef size_t size_type; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef ptrdiff_t difference_type; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef T* pointer; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef const T* const_pointer; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef T& reference; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef const T& const_reference; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef T value_type; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrivateHookAllocator() {} 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Allocate memory for STL. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pointer allocate(size_type n, const void * = 0) { 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return reinterpret_cast<T*>(MemoryHook::Alloc(n * sizeof(T))); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Deallocate memory for STL. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void deallocate(void* p, size_type) { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (p) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MemoryHook::Free(p); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Construct the object 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void construct(pointer p, const T& val) { 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new (reinterpret_cast<T*>(p))T(val); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Destruct an object 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void destroy(pointer p) { p->~T(); } 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_type max_size() const { return size_t(-1); } 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) template <class U> 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct rebind { typedef PrivateHookAllocator<U> other; }; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) template <class U> 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrivateHookAllocator(const PrivateHookAllocator<U>&) {} 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<class T, class U> inline 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool operator==(const PrivateHookAllocator<T>&, 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const PrivateHookAllocator<U>&) { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (true); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<class T, class U> inline 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool operator!=(const PrivateHookAllocator<T>& left, 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const PrivateHookAllocator<U>& right) { 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (!(left == right)); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Classes which monitor memory from these hooks implement 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the MemoryObserver interface. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MemoryObserver { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~MemoryObserver() {} 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Track a pointer. Will capture the current StackTrace. 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void OnTrack(HANDLE heap, int32 id, int32 size) = 0; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Untrack a pointer, removing it from our list. 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void OnUntrack(HANDLE heap, int32 id, int32 size) = 0; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MemoryHook : MemoryObserver { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize the MemoryHook. Must be called before 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // registering watchers. This can be called repeatedly, 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but is not thread safe. 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool Initialize(); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true is memory allocations and deallocations 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // are being traced. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool hooked() { return hooked_ != NULL; } 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Register a class to receive memory allocation & deallocation 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // callbacks. If we haven't hooked memory yet, this call will 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // force memory hooking to start. 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool RegisterWatcher(MemoryObserver* watcher); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Register a class to stop receiving callbacks. If there are 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // no more watchers, this call will unhook memory. 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool UnregisterWatcher(MemoryObserver* watcher); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MemoryHook provides a private heap for allocating 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // unwatched memory. 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void* Alloc(size_t size) { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(global_hook_ && global_hook_->heap_); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return HeapAlloc(global_hook_->heap_, 0, size); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void Free(void* ptr) { 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(global_hook_ && global_hook_->heap_); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeapFree(global_hook_->heap_, 0, ptr); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Access the global hook. For internal use only from static "C" 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // hooks. 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static MemoryHook* hook() { return global_hook_; } 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MemoryObserver interface. 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void OnTrack(HANDLE hHeap, int32 id, int32 size); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void OnUntrack(HANDLE hHeap, int32 id, int32 size); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MemoryHook(); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~MemoryHook(); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Enable memory tracing. When memory is 'hooked', 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MemoryWatchers which have registered will be called 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as memory is allocated and deallocated. 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool Hook(); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Disables memory tracing. 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool Unhook(); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create our private heap 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool CreateHeap(); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Close our private heap. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool CloseHeap(); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MemoryObserver* watcher_; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HANDLE heap_; // An internal accounting heap. 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool hooked_; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static MemoryHook* global_hook_; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // MEMORY_WATCHER_MEMORY_HOOK_ 154