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