154 lines
4.4 KiB
C
154 lines
4.4 KiB
C
|
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
// found in the LICENSE file.
|
||
|
//
|
||
|
// Static class for hooking Win32 API routines. For now,
|
||
|
// we only add one watcher at a time.
|
||
|
//
|
||
|
// TODO(mbelshe): Support multiple watchers.
|
||
|
|
||
|
#ifndef MEMORY_WATCHER_MEMORY_HOOK_
|
||
|
#define MEMORY_WATCHER_MEMORY_HOOK_
|
||
|
|
||
|
#include "base/logging.h"
|
||
|
|
||
|
// When allocating memory for internal use with the MemoryHook,
|
||
|
// we must always use the MemoryHook's heap; otherwise, the memory
|
||
|
// gets tracked, and it becomes an infinite loop (allocation() calls
|
||
|
// MemoryHook() which calls allocation(), etc).
|
||
|
//
|
||
|
// PrivateHookAllocator is an STL-friendly Allocator so that STL lists,
|
||
|
// maps, etc can be used on the global MemoryHook's heap.
|
||
|
template <class T>
|
||
|
class PrivateHookAllocator {
|
||
|
public:
|
||
|
// These type definitions are needed for stl allocators.
|
||
|
typedef size_t size_type;
|
||
|
typedef ptrdiff_t difference_type;
|
||
|
typedef T* pointer;
|
||
|
typedef const T* const_pointer;
|
||
|
typedef T& reference;
|
||
|
typedef const T& const_reference;
|
||
|
typedef T value_type;
|
||
|
|
||
|
PrivateHookAllocator() {}
|
||
|
|
||
|
// Allocate memory for STL.
|
||
|
pointer allocate(size_type n, const void * = 0) {
|
||
|
return reinterpret_cast<T*>(MemoryHook::Alloc(n * sizeof(T)));
|
||
|
}
|
||
|
|
||
|
// Deallocate memory for STL.
|
||
|
void deallocate(void* p, size_type) {
|
||
|
if (p)
|
||
|
MemoryHook::Free(p);
|
||
|
}
|
||
|
|
||
|
// Construct the object
|
||
|
void construct(pointer p, const T& val) {
|
||
|
new (reinterpret_cast<T*>(p))T(val);
|
||
|
}
|
||
|
|
||
|
// Destruct an object
|
||
|
void destroy(pointer p) { p->~T(); }
|
||
|
|
||
|
size_type max_size() const { return size_t(-1); }
|
||
|
|
||
|
template <class U>
|
||
|
struct rebind { typedef PrivateHookAllocator<U> other; };
|
||
|
|
||
|
template <class U>
|
||
|
PrivateHookAllocator(const PrivateHookAllocator<U>&) {}
|
||
|
};
|
||
|
|
||
|
template<class T, class U> inline
|
||
|
bool operator==(const PrivateHookAllocator<T>&,
|
||
|
const PrivateHookAllocator<U>&) {
|
||
|
return (true);
|
||
|
}
|
||
|
|
||
|
template<class T, class U> inline
|
||
|
bool operator!=(const PrivateHookAllocator<T>& left,
|
||
|
const PrivateHookAllocator<U>& right) {
|
||
|
return (!(left == right));
|
||
|
}
|
||
|
|
||
|
|
||
|
// Classes which monitor memory from these hooks implement
|
||
|
// the MemoryObserver interface.
|
||
|
class MemoryObserver {
|
||
|
public:
|
||
|
virtual ~MemoryObserver() {}
|
||
|
|
||
|
// Track a pointer. Will capture the current StackTrace.
|
||
|
virtual void OnTrack(HANDLE heap, int32 id, int32 size) = 0;
|
||
|
|
||
|
// Untrack a pointer, removing it from our list.
|
||
|
virtual void OnUntrack(HANDLE heap, int32 id, int32 size) = 0;
|
||
|
};
|
||
|
|
||
|
class MemoryHook : MemoryObserver {
|
||
|
public:
|
||
|
// Initialize the MemoryHook. Must be called before
|
||
|
// registering watchers. This can be called repeatedly,
|
||
|
// but is not thread safe.
|
||
|
static bool Initialize();
|
||
|
|
||
|
// Returns true is memory allocations and deallocations
|
||
|
// are being traced.
|
||
|
static bool hooked() { return hooked_ != NULL; }
|
||
|
|
||
|
// Register a class to receive memory allocation & deallocation
|
||
|
// callbacks. If we haven't hooked memory yet, this call will
|
||
|
// force memory hooking to start.
|
||
|
static bool RegisterWatcher(MemoryObserver* watcher);
|
||
|
|
||
|
// Register a class to stop receiving callbacks. If there are
|
||
|
// no more watchers, this call will unhook memory.
|
||
|
static bool UnregisterWatcher(MemoryObserver* watcher);
|
||
|
|
||
|
// MemoryHook provides a private heap for allocating
|
||
|
// unwatched memory.
|
||
|
static void* Alloc(size_t size) {
|
||
|
DCHECK(global_hook_ && global_hook_->heap_);
|
||
|
return HeapAlloc(global_hook_->heap_, 0, size);
|
||
|
}
|
||
|
static void Free(void* ptr) {
|
||
|
DCHECK(global_hook_ && global_hook_->heap_);
|
||
|
HeapFree(global_hook_->heap_, 0, ptr);
|
||
|
}
|
||
|
|
||
|
// Access the global hook. For internal use only from static "C"
|
||
|
// hooks.
|
||
|
static MemoryHook* hook() { return global_hook_; }
|
||
|
|
||
|
// MemoryObserver interface.
|
||
|
virtual void OnTrack(HANDLE hHeap, int32 id, int32 size);
|
||
|
virtual void OnUntrack(HANDLE hHeap, int32 id, int32 size);
|
||
|
|
||
|
private:
|
||
|
MemoryHook();
|
||
|
~MemoryHook();
|
||
|
|
||
|
// Enable memory tracing. When memory is 'hooked',
|
||
|
// MemoryWatchers which have registered will be called
|
||
|
// as memory is allocated and deallocated.
|
||
|
static bool Hook();
|
||
|
|
||
|
// Disables memory tracing.
|
||
|
static bool Unhook();
|
||
|
|
||
|
// Create our private heap
|
||
|
bool CreateHeap();
|
||
|
|
||
|
// Close our private heap.
|
||
|
bool CloseHeap();
|
||
|
|
||
|
MemoryObserver* watcher_;
|
||
|
HANDLE heap_; // An internal accounting heap.
|
||
|
static bool hooked_;
|
||
|
static MemoryHook* global_hook_;
|
||
|
};
|
||
|
|
||
|
#endif // MEMORY_WATCHER_MEMORY_HOOK_
|