Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Unified Diff: tools/memory_watcher/memory_hook.cc

Issue 314253003: Remove memory_watcher tool as well as --memory-profile command line flag. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix compile issue on non-ChromeOS platforms Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/memory_watcher/memory_hook.h ('k') | tools/memory_watcher/memory_watcher.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/memory_watcher/memory_hook.cc
diff --git a/tools/memory_watcher/memory_hook.cc b/tools/memory_watcher/memory_hook.cc
deleted file mode 100644
index 64df93d204150978ae7046a6f71821893266c3f3..0000000000000000000000000000000000000000
--- a/tools/memory_watcher/memory_hook.cc
+++ /dev/null
@@ -1,562 +0,0 @@
-// 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.
-
-// Some notes about how to hook Memory Allocation Routines in Windows.
-//
-// For our purposes we do not hook the libc routines. There are two
-// reasons for this. First, the libc routines all go through HeapAlloc
-// anyway. So, it's redundant to log both HeapAlloc and malloc.
-// Second, it can be tricky to hook in both static and dynamic linkages
-// of libc.
-
-#include <windows.h>
-
-#include "memory_hook.h"
-#include "memory_watcher.h"
-#include "preamble_patcher.h"
-
-// Calls GetProcAddress, but casts to the correct type.
-#define GET_PROC_ADDRESS(hmodule, name) \
- ( (Type_##name)(::GetProcAddress(hmodule, #name)) )
-
-// Macro to declare Patch functions.
-#define DECLARE_PATCH(name) Patch<Type_##name> patch_##name
-
-// Macro to install Patch functions.
-#define INSTALL_PATCH(name) do { \
- patch_##name.set_original(GET_PROC_ADDRESS(hkernel32, ##name)); \
- patch_##name.Install(&Perftools_##name); \
-} while (0)
-
-// Macro to install Patch functions.
-#define INSTALL_NTDLLPATCH(name) do { \
- patch_##name.set_original(GET_PROC_ADDRESS(hntdll, ##name)); \
- patch_##name.Install(&Perftools_##name); \
-} while (0)
-
-// Macro to uninstall Patch functions.
-#define UNINSTALL_PATCH(name) patch_##name.Uninstall();
-
-
-
-// Windows APIs to be hooked
-
-// HeapAlloc routines
-typedef HANDLE (WINAPI *Type_HeapCreate)(DWORD flOptions,
- SIZE_T dwInitialSize,
- SIZE_T dwMaximumSize);
-typedef BOOL (WINAPI *Type_HeapDestroy)(HANDLE hHeap);
-typedef LPVOID (WINAPI *Type_HeapAlloc)(HANDLE hHeap, DWORD dwFlags,
- DWORD_PTR dwBytes);
-typedef LPVOID (WINAPI *Type_HeapReAlloc)(HANDLE hHeap, DWORD dwFlags,
- LPVOID lpMem, SIZE_T dwBytes);
-typedef BOOL (WINAPI *Type_HeapFree)(HANDLE hHeap, DWORD dwFlags,
- LPVOID lpMem);
-
-// GlobalAlloc routines
-typedef HGLOBAL (WINAPI *Type_GlobalAlloc)(UINT uFlags, SIZE_T dwBytes);
-typedef HGLOBAL (WINAPI *Type_GlobalReAlloc)(HGLOBAL hMem, SIZE_T dwBytes,
- UINT uFlags);
-typedef HGLOBAL (WINAPI *Type_GlobalFree)(HGLOBAL hMem);
-
-// LocalAlloc routines
-typedef HLOCAL (WINAPI *Type_LocalAlloc)(UINT uFlags, SIZE_T uBytes);
-typedef HLOCAL (WINAPI *Type_LocalReAlloc)(HLOCAL hMem, SIZE_T uBytes,
- UINT uFlags);
-typedef HLOCAL (WINAPI *Type_LocalFree)(HLOCAL hMem);
-
-// A Windows-API equivalent of mmap and munmap, for "anonymous regions"
-typedef LPVOID (WINAPI *Type_VirtualAllocEx)(HANDLE process, LPVOID address,
- SIZE_T size, DWORD type,
- DWORD protect);
-typedef BOOL (WINAPI *Type_VirtualFreeEx)(HANDLE process, LPVOID address,
- SIZE_T size, DWORD type);
-
-// A Windows-API equivalent of mmap and munmap, for actual files
-typedef LPVOID (WINAPI *Type_MapViewOfFile)(HANDLE hFileMappingObject,
- DWORD dwDesiredAccess,
- DWORD dwFileOffsetHigh,
- DWORD dwFileOffsetLow,
- SIZE_T dwNumberOfBytesToMap);
-typedef LPVOID (WINAPI *Type_MapViewOfFileEx)(HANDLE hFileMappingObject,
- DWORD dwDesiredAccess,
- DWORD dwFileOffsetHigh,
- DWORD dwFileOffsetLow,
- SIZE_T dwNumberOfBytesToMap,
- LPVOID lpBaseAddress);
-typedef BOOL (WINAPI *Type_UnmapViewOfFile)(LPVOID lpBaseAddress);
-
-typedef DWORD (WINAPI *Type_NtUnmapViewOfSection)(HANDLE process,
- LPVOID lpBaseAddress);
-
-
-// Patch is a template for keeping the pointer to the original
-// hooked routine, the function to call when hooked, and the
-// stub routine which is patched.
-template<class T>
-class Patch {
- public:
- // Constructor. Does not hook the function yet.
- Patch<T>()
- : original_function_(NULL),
- patch_function_(NULL),
- stub_function_(NULL) {
- }
-
- // Destructor. Unhooks the function if it has been hooked.
- ~Patch<T>() {
- Uninstall();
- }
-
- // Patches original function with func.
- // Must have called set_original to set the original function.
- void Install(T func) {
- patch_function_ = func;
- CHECK(patch_function_ != NULL);
- CHECK(original_function_ != NULL);
- CHECK(stub_function_ == NULL);
- CHECK(sidestep::SIDESTEP_SUCCESS ==
- sidestep::PreamblePatcher::Patch(original_function_,
- patch_function_, &stub_function_));
- }
-
- // Un-patches the function.
- void Uninstall() {
- if (stub_function_)
- sidestep::PreamblePatcher::Unpatch(original_function_,
- patch_function_, stub_function_);
- stub_function_ = NULL;
- }
-
- // Set the function to be patched.
- void set_original(T original) { original_function_ = original; }
-
- // Get the original function being patched.
- T original() { return original_function_; }
-
- // Get the patched function. (e.g. the replacement function)
- T patched() { return patch_function_; }
-
- // Access to the stub for calling the original function
- // while it is patched.
- T operator()() {
- DCHECK(stub_function_);
- return stub_function_;
- }
-
- private:
- // The function that we plan to patch.
- T original_function_;
- // The function to replace the original with.
- T patch_function_;
- // To unpatch, we also need to keep around a "stub" that points to the
- // pre-patched Windows function.
- T stub_function_;
-};
-
-
-// All Windows memory-allocation routines call through to one of these.
-DECLARE_PATCH(HeapCreate);
-DECLARE_PATCH(HeapDestroy);
-DECLARE_PATCH(HeapAlloc);
-DECLARE_PATCH(HeapReAlloc);
-DECLARE_PATCH(HeapFree);
-DECLARE_PATCH(VirtualAllocEx);
-DECLARE_PATCH(VirtualFreeEx);
-DECLARE_PATCH(MapViewOfFile);
-DECLARE_PATCH(MapViewOfFileEx);
-DECLARE_PATCH(UnmapViewOfFile);
-DECLARE_PATCH(GlobalAlloc);
-DECLARE_PATCH(GlobalReAlloc);
-DECLARE_PATCH(GlobalFree);
-DECLARE_PATCH(LocalAlloc);
-DECLARE_PATCH(LocalReAlloc);
-DECLARE_PATCH(LocalFree);
-DECLARE_PATCH(NtUnmapViewOfSection);
-
-// Our replacement functions.
-
-static HANDLE WINAPI Perftools_HeapCreate(DWORD flOptions,
- SIZE_T dwInitialSize,
- SIZE_T dwMaximumSize) {
- if (dwInitialSize > 4096)
- dwInitialSize = 4096;
- return patch_HeapCreate()(flOptions, dwInitialSize, dwMaximumSize);
-}
-
-static BOOL WINAPI Perftools_HeapDestroy(HANDLE hHeap) {
- return patch_HeapDestroy()(hHeap);
-}
-
-static LPVOID WINAPI Perftools_HeapAlloc(HANDLE hHeap, DWORD dwFlags,
- DWORD_PTR dwBytes) {
- LPVOID rv = patch_HeapAlloc()(hHeap, dwFlags, dwBytes);
- MemoryHook::hook()->OnTrack(hHeap, reinterpret_cast<int32>(rv), dwBytes);
- return rv;
-}
-
-static BOOL WINAPI Perftools_HeapFree(HANDLE hHeap, DWORD dwFlags,
- LPVOID lpMem) {
- size_t size = 0;
- if (lpMem != 0) {
- size = HeapSize(hHeap, 0, lpMem); // Will crash if lpMem is 0.
- // Note: size could be 0; HeapAlloc does allocate 0 length buffers.
- }
- MemoryHook::hook()->OnUntrack(hHeap, reinterpret_cast<int32>(lpMem), size);
- return patch_HeapFree()(hHeap, dwFlags, lpMem);
-}
-
-static LPVOID WINAPI Perftools_HeapReAlloc(HANDLE hHeap, DWORD dwFlags,
- LPVOID lpMem, SIZE_T dwBytes) {
- // Don't call realloc, but instead do a free/malloc. The problem is that
- // the builtin realloc may either expand a buffer, or it may simply
- // just call free/malloc. If so, we will already have tracked the new
- // block via Perftools_HeapAlloc.
-
- LPVOID rv = Perftools_HeapAlloc(hHeap, dwFlags, dwBytes);
- DCHECK_EQ((HEAP_REALLOC_IN_PLACE_ONLY & dwFlags), 0u);
-
- // If there was an old buffer, now copy the data to the new buffer.
- if (lpMem != 0) {
- size_t size = HeapSize(hHeap, 0, lpMem);
- if (size > dwBytes)
- size = dwBytes;
- // Note: size could be 0; HeapAlloc does allocate 0 length buffers.
- memcpy(rv, lpMem, size);
- Perftools_HeapFree(hHeap, dwFlags, lpMem);
- }
- return rv;
-}
-
-static LPVOID WINAPI Perftools_VirtualAllocEx(HANDLE process, LPVOID address,
- SIZE_T size, DWORD type,
- DWORD protect) {
- bool already_committed = false;
- if (address != NULL) {
- MEMORY_BASIC_INFORMATION info;
- CHECK(VirtualQuery(address, &info, sizeof(info)));
- if (info.State & MEM_COMMIT) {
- already_committed = true;
- CHECK(size >= info.RegionSize);
- }
- }
- bool reserving = (address == NULL) || (type & MEM_RESERVE);
- bool committing = !already_committed && (type & MEM_COMMIT);
-
-
- LPVOID result = patch_VirtualAllocEx()(process, address, size, type,
- protect);
- MEMORY_BASIC_INFORMATION info;
- CHECK(VirtualQuery(result, &info, sizeof(info)));
- size = info.RegionSize;
-
- if (committing)
- MemoryHook::hook()->OnTrack(0, reinterpret_cast<int32>(result), size);
-
- return result;
-}
-
-static BOOL WINAPI Perftools_VirtualFreeEx(HANDLE process, LPVOID address,
- SIZE_T size, DWORD type) {
- int chunk_size = size;
- MEMORY_BASIC_INFORMATION info;
- CHECK(VirtualQuery(address, &info, sizeof(info)));
- if (chunk_size == 0)
- chunk_size = info.RegionSize;
- bool decommit = (info.State & MEM_COMMIT) != 0;
-
- if (decommit)
- MemoryHook::hook()->OnUntrack(0, reinterpret_cast<int32>(address),
- chunk_size);
-
- return patch_VirtualFreeEx()(process, address, size, type);
-}
-
-static base::Lock known_maps_lock;
-static std::map<void*, int> known_maps;
-
-static LPVOID WINAPI Perftools_MapViewOfFileEx(HANDLE hFileMappingObject,
- DWORD dwDesiredAccess,
- DWORD dwFileOffsetHigh,
- DWORD dwFileOffsetLow,
- SIZE_T dwNumberOfBytesToMap,
- LPVOID lpBaseAddress) {
- // For this function pair, you always deallocate the full block of
- // data that you allocate, so NewHook/DeleteHook is the right API.
- LPVOID result = patch_MapViewOfFileEx()(hFileMappingObject, dwDesiredAccess,
- dwFileOffsetHigh, dwFileOffsetLow,
- dwNumberOfBytesToMap, lpBaseAddress);
- {
- base::AutoLock lock(known_maps_lock);
- MEMORY_BASIC_INFORMATION info;
- if (known_maps.find(result) == known_maps.end()) {
- CHECK(VirtualQuery(result, &info, sizeof(info)));
- // TODO(mbelshe): THIS map uses the standard heap!!!!
- known_maps[result] = 1;
- MemoryHook::hook()->OnTrack(0, reinterpret_cast<int32>(result),
- info.RegionSize);
- } else {
- known_maps[result] = known_maps[result] + 1;
- }
- }
- return result;
-}
-
-static LPVOID WINAPI Perftools_MapViewOfFile(HANDLE hFileMappingObject,
- DWORD dwDesiredAccess,
- DWORD dwFileOffsetHigh,
- DWORD dwFileOffsetLow,
- SIZE_T dwNumberOfBytesToMap) {
- return Perftools_MapViewOfFileEx(hFileMappingObject, dwDesiredAccess,
- dwFileOffsetHigh, dwFileOffsetLow,
- dwNumberOfBytesToMap, 0);
-}
-
-static BOOL WINAPI Perftools_UnmapViewOfFile(LPVOID lpBaseAddress) {
- // This will call into NtUnmapViewOfSection().
- return patch_UnmapViewOfFile()(lpBaseAddress);
-}
-
-static DWORD WINAPI Perftools_NtUnmapViewOfSection(HANDLE process,
- LPVOID lpBaseAddress) {
- // Some windows APIs call directly into this routine rather
- // than calling UnmapViewOfFile. If we didn't trap this function,
- // then we appear to have bogus leaks.
- {
- base::AutoLock lock(known_maps_lock);
- MEMORY_BASIC_INFORMATION info;
- CHECK(VirtualQuery(lpBaseAddress, &info, sizeof(info)));
- if (known_maps.find(lpBaseAddress) != known_maps.end()) {
- if (known_maps[lpBaseAddress] == 1) {
- MemoryHook::hook()->OnUntrack(0, reinterpret_cast<int32>(lpBaseAddress),
- info.RegionSize);
- known_maps.erase(lpBaseAddress);
- } else {
- known_maps[lpBaseAddress] = known_maps[lpBaseAddress] - 1;
- }
- }
- }
- return patch_NtUnmapViewOfSection()(process, lpBaseAddress);
-}
-
-static HGLOBAL WINAPI Perftools_GlobalAlloc(UINT uFlags, SIZE_T dwBytes) {
- // GlobalAlloc is built atop HeapAlloc anyway. So we don't track these.
- // GlobalAlloc will internally call into HeapAlloc and we track there.
-
- // Force all memory to be fixed.
- uFlags &= ~GMEM_MOVEABLE;
- HGLOBAL rv = patch_GlobalAlloc()(uFlags, dwBytes);
- return rv;
-}
-
-static HGLOBAL WINAPI Perftools_GlobalFree(HGLOBAL hMem) {
- return patch_GlobalFree()(hMem);
-}
-
-static HGLOBAL WINAPI Perftools_GlobalReAlloc(HGLOBAL hMem, SIZE_T dwBytes,
- UINT uFlags) {
- // TODO(jar): [The following looks like a copy/paste typo from LocalRealloc.]
- // GlobalDiscard is a macro which calls LocalReAlloc with size 0.
- if (dwBytes == 0) {
- return patch_GlobalReAlloc()(hMem, dwBytes, uFlags);
- }
-
- HGLOBAL rv = Perftools_GlobalAlloc(uFlags, dwBytes);
- if (hMem != 0) {
- size_t size = GlobalSize(hMem);
- if (size > dwBytes)
- size = dwBytes;
- // Note: size could be 0; HeapAlloc does allocate 0 length buffers.
- memcpy(rv, hMem, size);
- Perftools_GlobalFree(hMem);
- }
-
- return rv;
-}
-
-static HLOCAL WINAPI Perftools_LocalAlloc(UINT uFlags, SIZE_T dwBytes) {
- // LocalAlloc is built atop HeapAlloc anyway. So we don't track these.
- // LocalAlloc will internally call into HeapAlloc and we track there.
-
- // Force all memory to be fixed.
- uFlags &= ~LMEM_MOVEABLE;
- HLOCAL rv = patch_LocalAlloc()(uFlags, dwBytes);
- return rv;
-}
-
-static HLOCAL WINAPI Perftools_LocalFree(HLOCAL hMem) {
- return patch_LocalFree()(hMem);
-}
-
-static HLOCAL WINAPI Perftools_LocalReAlloc(HLOCAL hMem, SIZE_T dwBytes,
- UINT uFlags) {
- // LocalDiscard is a macro which calls LocalReAlloc with size 0.
- if (dwBytes == 0) {
- return patch_LocalReAlloc()(hMem, dwBytes, uFlags);
- }
-
- HGLOBAL rv = Perftools_LocalAlloc(uFlags, dwBytes);
- if (hMem != 0) {
- size_t size = LocalSize(hMem);
- if (size > dwBytes)
- size = dwBytes;
- // Note: size could be 0; HeapAlloc does allocate 0 length buffers.
- memcpy(rv, hMem, size);
- Perftools_LocalFree(hMem);
- }
-
- return rv;
-}
-
-bool MemoryHook::hooked_ = false;
-MemoryHook* MemoryHook::global_hook_ = NULL;
-
-MemoryHook::MemoryHook()
- : watcher_(NULL),
- heap_(NULL) {
- CreateHeap();
-}
-
-MemoryHook::~MemoryHook() {
- // It's a bit dangerous to ever close this heap; MemoryWatchers may have
- // used this heap for their tracking data. Closing the heap while any
- // MemoryWatchers still exist is pretty dangerous.
- CloseHeap();
-}
-
-bool MemoryHook::Initialize() {
- if (global_hook_ == NULL)
- global_hook_ = new MemoryHook();
- return true;
-}
-
-bool MemoryHook::Hook() {
- DCHECK(!hooked_);
- if (!hooked_) {
- DCHECK(global_hook_);
-
- // Luckily, Patch() doesn't call malloc or windows alloc routines
- // itself -- though it does call new (we can use PatchWithStub to
- // get around that, and will need to if we need to patch new).
-
- HMODULE hkernel32 = ::GetModuleHandle(L"kernel32");
- CHECK(hkernel32 != NULL);
-
- HMODULE hntdll = ::GetModuleHandle(L"ntdll");
- CHECK(hntdll != NULL);
-
- // Now that we've found all the functions, patch them
- INSTALL_PATCH(HeapCreate);
- INSTALL_PATCH(HeapDestroy);
- INSTALL_PATCH(HeapAlloc);
- INSTALL_PATCH(HeapReAlloc);
- INSTALL_PATCH(HeapFree);
- INSTALL_PATCH(VirtualAllocEx);
- INSTALL_PATCH(VirtualFreeEx);
- INSTALL_PATCH(MapViewOfFileEx);
- INSTALL_PATCH(MapViewOfFile);
- INSTALL_PATCH(UnmapViewOfFile);
- INSTALL_NTDLLPATCH(NtUnmapViewOfSection);
- INSTALL_PATCH(GlobalAlloc);
- INSTALL_PATCH(GlobalReAlloc);
- INSTALL_PATCH(GlobalFree);
- INSTALL_PATCH(LocalAlloc);
- INSTALL_PATCH(LocalReAlloc);
- INSTALL_PATCH(LocalFree);
-
- // We are finally completely hooked.
- hooked_ = true;
- }
- return true;
-}
-
-bool MemoryHook::Unhook() {
- if (hooked_) {
- // We need to go back to the system malloc/etc at global destruct time,
- // so objects that were constructed before tcmalloc, using the system
- // malloc, can destroy themselves using the system free. This depends
- // on DLLs unloading in the reverse order in which they load!
- //
- // We also go back to the default HeapAlloc/etc, just for consistency.
- // Who knows, it may help avoid weird bugs in some situations.
- UNINSTALL_PATCH(HeapCreate);
- UNINSTALL_PATCH(HeapDestroy);
- UNINSTALL_PATCH(HeapAlloc);
- UNINSTALL_PATCH(HeapReAlloc);
- UNINSTALL_PATCH(HeapFree);
- UNINSTALL_PATCH(VirtualAllocEx);
- UNINSTALL_PATCH(VirtualFreeEx);
- UNINSTALL_PATCH(MapViewOfFile);
- UNINSTALL_PATCH(MapViewOfFileEx);
- UNINSTALL_PATCH(UnmapViewOfFile);
- UNINSTALL_PATCH(NtUnmapViewOfSection);
- UNINSTALL_PATCH(GlobalAlloc);
- UNINSTALL_PATCH(GlobalReAlloc);
- UNINSTALL_PATCH(GlobalFree);
- UNINSTALL_PATCH(LocalAlloc);
- UNINSTALL_PATCH(LocalReAlloc);
- UNINSTALL_PATCH(LocalFree);
-
- hooked_ = false;
- }
- return true;
-}
-
-bool MemoryHook::RegisterWatcher(MemoryObserver* watcher) {
- DCHECK(global_hook_->watcher_ == NULL);
-
- if (!hooked_)
- Hook();
-
- DCHECK(global_hook_);
- global_hook_->watcher_ = watcher;
- return true;
-}
-
-bool MemoryHook::UnregisterWatcher(MemoryObserver* watcher) {
- DCHECK(hooked_);
- DCHECK(global_hook_->watcher_ == watcher);
- // TODO(jar): changing watcher_ here is very racy. Other threads may (without
- // a lock) testing, and then calling through this value. We probably can't
- // remove this until we are single threaded.
- global_hook_->watcher_ = NULL;
-
- // For now, since there are no more watchers, unhook memory.
- return Unhook();
-}
-
-bool MemoryHook::CreateHeap() {
- // Create a heap for our own memory.
- DCHECK(heap_ == NULL);
- heap_ = HeapCreate(0, 0, 0);
- DCHECK(heap_ != NULL);
- return heap_ != NULL;
-}
-
-bool MemoryHook::CloseHeap() {
- DCHECK(heap_ != NULL);
- HeapDestroy(heap_);
- heap_ = NULL;
- return true;
-}
-
-void MemoryHook::OnTrack(HANDLE heap, int32 id, int32 size) {
- // Don't notify about allocations to our internal heap.
- if (heap == heap_)
- return;
-
- if (watcher_)
- watcher_->OnTrack(heap, id, size);
-}
-
-void MemoryHook::OnUntrack(HANDLE heap, int32 id, int32 size) {
- // Don't notify about allocations to our internal heap.
- if (heap == heap_)
- return;
-
- if (watcher_)
- watcher_->OnUntrack(heap, id, size);
-}
« no previous file with comments | « tools/memory_watcher/memory_hook.h ('k') | tools/memory_watcher/memory_watcher.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698