Index: tools/memory_watcher/call_stack.cc |
diff --git a/tools/memory_watcher/call_stack.cc b/tools/memory_watcher/call_stack.cc |
deleted file mode 100644 |
index 6f829b450178ce1b01c4a62efebb2f65f71ce561..0000000000000000000000000000000000000000 |
--- a/tools/memory_watcher/call_stack.cc |
+++ /dev/null |
@@ -1,399 +0,0 @@ |
-// Copyright (c) 2010 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. |
- |
-#include "tools/memory_watcher/call_stack.h" |
- |
-#include <shlwapi.h> |
-#include <tlhelp32.h> |
- |
-#include "base/strings/string_number_conversions.h" |
-#include "tools/memory_watcher/memory_hook.h" |
- |
-// Typedefs for explicit dynamic linking with functions exported from |
-// dbghelp.dll. |
-typedef BOOL (__stdcall *t_StackWalk64)(DWORD, HANDLE, HANDLE, |
- LPSTACKFRAME64, PVOID, |
- PREAD_PROCESS_MEMORY_ROUTINE64, |
- PFUNCTION_TABLE_ACCESS_ROUTINE64, |
- PGET_MODULE_BASE_ROUTINE64, |
- PTRANSLATE_ADDRESS_ROUTINE64); |
-typedef PVOID (__stdcall *t_SymFunctionTableAccess64)(HANDLE, DWORD64); |
-typedef DWORD64 (__stdcall *t_SymGetModuleBase64)(HANDLE, DWORD64); |
-typedef BOOL (__stdcall *t_SymCleanup)(HANDLE); |
-typedef BOOL (__stdcall *t_SymGetSymFromAddr64)(HANDLE, DWORD64, |
- PDWORD64, PIMAGEHLP_SYMBOL64); |
-typedef BOOL (__stdcall *t_SymGetLineFromAddr64)(HANDLE, DWORD64, PDWORD, |
- PIMAGEHLP_LINE64); |
-typedef BOOL (__stdcall *t_SymInitialize)(HANDLE, PCTSTR, BOOL); |
-typedef DWORD (__stdcall *t_SymGetOptions)(void); |
-typedef DWORD (__stdcall *t_SymSetOptions)(DWORD); |
-typedef BOOL (__stdcall *t_SymGetSearchPath)(HANDLE, PTSTR, DWORD); |
-typedef DWORD64 (__stdcall *t_SymLoadModule64)(HANDLE, HANDLE, PCSTR, |
- PCSTR, DWORD64, DWORD); |
-typedef BOOL (__stdcall *t_SymGetModuleInfo64)(HANDLE, DWORD64, |
- PIMAGEHLP_MODULE64); |
- |
-// static |
-base::Lock CallStack::dbghelp_lock_; |
-// static |
-bool CallStack::dbghelp_loaded_ = false; |
-// static |
-DWORD CallStack::active_thread_id_ = 0; |
- |
- |
-static t_StackWalk64 pStackWalk64 = NULL; |
-static t_SymCleanup pSymCleanup = NULL; |
-static t_SymGetSymFromAddr64 pSymGetSymFromAddr64 = NULL; |
-static t_SymFunctionTableAccess64 pSymFunctionTableAccess64 = NULL; |
-static t_SymGetModuleBase64 pSymGetModuleBase64 = NULL; |
-static t_SymGetLineFromAddr64 pSymGetLineFromAddr64 = NULL; |
-static t_SymInitialize pSymInitialize = NULL; |
-static t_SymGetOptions pSymGetOptions = NULL; |
-static t_SymSetOptions pSymSetOptions = NULL; |
-static t_SymGetModuleInfo64 pSymGetModuleInfo64 = NULL; |
-static t_SymGetSearchPath pSymGetSearchPath = NULL; |
-static t_SymLoadModule64 pSymLoadModule64 = NULL; |
- |
-#define LOADPROC(module, name) do { \ |
- p##name = reinterpret_cast<t_##name>(GetProcAddress(module, #name)); \ |
- if (p##name == NULL) return false; \ |
-} while (0) |
- |
-// This code has to be VERY careful to not induce any allocations, as memory |
-// watching code may cause recursion, which may obscure the stack for the truly |
-// offensive issue. We use this function to break into a debugger, and it |
-// is guaranteed to not do any allocations (in fact, not do anything). |
-static void UltraSafeDebugBreak() { |
- _asm int(3); |
-} |
- |
-// static |
-bool CallStack::LoadDbgHelp() { |
- if (!dbghelp_loaded_) { |
- base::AutoLock Lock(dbghelp_lock_); |
- |
- // Re-check if we've loaded successfully now that we have the lock. |
- if (dbghelp_loaded_) |
- return true; |
- |
- // Load dbghelp.dll, and obtain pointers to the exported functions that we |
- // will be using. |
- HMODULE dbghelp_module = LoadLibrary(L"dbghelp.dll"); |
- if (dbghelp_module) { |
- LOADPROC(dbghelp_module, StackWalk64); |
- LOADPROC(dbghelp_module, SymFunctionTableAccess64); |
- LOADPROC(dbghelp_module, SymGetModuleBase64); |
- LOADPROC(dbghelp_module, SymCleanup); |
- LOADPROC(dbghelp_module, SymGetSymFromAddr64); |
- LOADPROC(dbghelp_module, SymGetLineFromAddr64); |
- LOADPROC(dbghelp_module, SymInitialize); |
- LOADPROC(dbghelp_module, SymGetOptions); |
- LOADPROC(dbghelp_module, SymSetOptions); |
- LOADPROC(dbghelp_module, SymGetModuleInfo64); |
- LOADPROC(dbghelp_module, SymGetSearchPath); |
- LOADPROC(dbghelp_module, SymLoadModule64); |
- dbghelp_loaded_ = true; |
- } else { |
- UltraSafeDebugBreak(); |
- return false; |
- } |
- } |
- return dbghelp_loaded_; |
-} |
- |
-// Load the symbols for generating stack traces. |
-static bool LoadSymbols(HANDLE process_handle) { |
- static bool symbols_loaded = false; |
- if (symbols_loaded) return true; |
- |
- BOOL ok; |
- |
- // Initialize the symbol engine. |
- ok = pSymInitialize(process_handle, /* hProcess */ |
- NULL, /* UserSearchPath */ |
- FALSE); /* fInvadeProcess */ |
- if (!ok) return false; |
- |
- DWORD options = pSymGetOptions(); |
- options |= SYMOPT_LOAD_LINES; |
- options |= SYMOPT_FAIL_CRITICAL_ERRORS; |
- options |= SYMOPT_UNDNAME; |
- options = pSymSetOptions(options); |
- |
- const DWORD kMaxSearchPath = 1024; |
- TCHAR buf[kMaxSearchPath] = {0}; |
- ok = pSymGetSearchPath(process_handle, buf, kMaxSearchPath); |
- if (!ok) |
- return false; |
- |
- HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, |
- GetCurrentProcessId()); |
- if (snapshot == INVALID_HANDLE_VALUE) |
- return false; |
- |
- MODULEENTRY32W module; |
- module.dwSize = sizeof(module); // Set the size of the structure. |
- BOOL cont = Module32FirstW(snapshot, &module); |
- while (cont) { |
- DWORD64 base; |
- // NOTE the SymLoadModule64 function has the peculiarity of accepting a |
- // both unicode and ASCII strings even though the parameter is PSTR. |
- base = pSymLoadModule64(process_handle, |
- 0, |
- reinterpret_cast<PSTR>(module.szExePath), |
- reinterpret_cast<PSTR>(module.szModule), |
- reinterpret_cast<DWORD64>(module.modBaseAddr), |
- module.modBaseSize); |
- if (base == 0) { |
- int err = GetLastError(); |
- if (err != ERROR_MOD_NOT_FOUND && err != ERROR_INVALID_HANDLE) |
- return false; |
- } |
- cont = Module32NextW(snapshot, &module); |
- } |
- CloseHandle(snapshot); |
- |
- symbols_loaded = true; |
- return true; |
-} |
- |
- |
-CallStack::SymbolCache* CallStack::symbol_cache_; |
- |
-bool CallStack::Initialize() { |
- // We need to delay load the symbol cache until after |
- // the MemoryHook heap is alive. |
- symbol_cache_ = new SymbolCache(); |
- return LoadDbgHelp(); |
-} |
- |
-CallStack::CallStack() { |
- static LONG callstack_id = 0; |
- frame_count_ = 0; |
- hash_ = 0; |
- id_ = InterlockedIncrement(&callstack_id); |
- valid_ = false; |
- |
- if (!dbghelp_loaded_) { |
- UltraSafeDebugBreak(); // Initialize should have been called. |
- return; |
- } |
- |
- GetStackTrace(); |
-} |
- |
-bool CallStack::IsEqual(const CallStack &target) { |
- if (frame_count_ != target.frame_count_) |
- return false; // They can't be equal if the sizes are different. |
- |
- // Walk the frames array until we |
- // either find a mismatch, or until we reach the end of the call stacks. |
- for (int index = 0; index < frame_count_; index++) { |
- if (frames_[index] != target.frames_[index]) |
- return false; // Found a mismatch. They are not equal. |
- } |
- |
- // Reached the end of the call stacks. They are equal. |
- return true; |
-} |
- |
-void CallStack::AddFrame(DWORD_PTR pc) { |
- DCHECK(frame_count_ < kMaxTraceFrames); |
- frames_[frame_count_++] = pc; |
- |
- // Create a unique id for this CallStack. |
- pc = pc + (frame_count_ * 13); // Alter the PC based on position in stack. |
- hash_ = ~hash_ + (pc << 15); |
- hash_ = hash_ ^ (pc >> 12); |
- hash_ = hash_ + (pc << 2); |
- hash_ = hash_ ^ (pc >> 4); |
- hash_ = hash_ * 2057; |
- hash_ = hash_ ^ (pc >> 16); |
-} |
- |
-bool CallStack::LockedRecursionDetected() const { |
- if (!active_thread_id_) return false; |
- DWORD thread_id = GetCurrentThreadId(); |
- // TODO(jar): Perchance we should use atomic access to member. |
- return thread_id == active_thread_id_; |
-} |
- |
-bool CallStack::GetStackTrace() { |
- if (LockedRecursionDetected()) |
- return false; |
- |
- // Initialize the context record. |
- CONTEXT context; |
- memset(&context, 0, sizeof(context)); |
- context.ContextFlags = CONTEXT_FULL; |
- __asm call x |
- __asm x: pop eax |
- __asm mov context.Eip, eax |
- __asm mov context.Ebp, ebp |
- __asm mov context.Esp, esp |
- |
- STACKFRAME64 frame; |
- memset(&frame, 0, sizeof(frame)); |
- |
-#ifdef _M_IX86 |
- DWORD image_type = IMAGE_FILE_MACHINE_I386; |
- frame.AddrPC.Offset = context.Eip; |
- frame.AddrPC.Mode = AddrModeFlat; |
- frame.AddrFrame.Offset = context.Ebp; |
- frame.AddrFrame.Mode = AddrModeFlat; |
- frame.AddrStack.Offset = context.Esp; |
- frame.AddrStack.Mode = AddrModeFlat; |
-#elif |
- NOT IMPLEMENTED! |
-#endif |
- |
- HANDLE current_process = GetCurrentProcess(); |
- HANDLE current_thread = GetCurrentThread(); |
- |
- // Walk the stack. |
- unsigned int count = 0; |
- { |
- AutoDbgHelpLock thread_monitoring_lock; |
- |
- while (count < kMaxTraceFrames) { |
- count++; |
- if (!pStackWalk64(image_type, |
- current_process, |
- current_thread, |
- &frame, |
- &context, |
- 0, |
- pSymFunctionTableAccess64, |
- pSymGetModuleBase64, |
- NULL)) |
- break; // Couldn't trace back through any more frames. |
- |
- if (frame.AddrFrame.Offset == 0) |
- continue; // End of stack. |
- |
- // Push this frame's program counter onto the provided CallStack. |
- AddFrame((DWORD_PTR)frame.AddrPC.Offset); |
- } |
- valid_ = true; |
- } |
- return true; |
-} |
- |
-void CallStack::ToString(PrivateAllocatorString* output) { |
- static const int kStackWalkMaxNameLen = MAX_SYM_NAME; |
- HANDLE current_process = GetCurrentProcess(); |
- |
- if (!LoadSymbols(current_process)) { |
- *output = "Error"; |
- return; |
- } |
- |
- base::AutoLock lock(dbghelp_lock_); |
- |
- // Iterate through each frame in the call stack. |
- for (int32 index = 0; index < frame_count_; index++) { |
- PrivateAllocatorString line; |
- |
- DWORD_PTR intruction_pointer = frame(index); |
- |
- SymbolCache::iterator it; |
- it = symbol_cache_->find(intruction_pointer); |
- if (it != symbol_cache_->end()) { |
- line = it->second; |
- } else { |
- // Try to locate a symbol for this frame. |
- DWORD64 symbol_displacement = 0; |
- ULONG64 buffer[(sizeof(IMAGEHLP_SYMBOL64) + |
- sizeof(TCHAR)*kStackWalkMaxNameLen + |
- sizeof(ULONG64) - 1) / sizeof(ULONG64)]; |
- IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(buffer); |
- memset(buffer, 0, sizeof(buffer)); |
- symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); |
- symbol->MaxNameLength = kStackWalkMaxNameLen; |
- BOOL ok = pSymGetSymFromAddr64(current_process, // hProcess |
- intruction_pointer, // Address |
- &symbol_displacement, // Displacement |
- symbol); // Symbol |
- if (ok) { |
- // Try to locate more source information for the symbol. |
- IMAGEHLP_LINE64 Line; |
- memset(&Line, 0, sizeof(Line)); |
- Line.SizeOfStruct = sizeof(Line); |
- DWORD line_displacement; |
- ok = pSymGetLineFromAddr64(current_process, |
- intruction_pointer, |
- &line_displacement, |
- &Line); |
- if (ok) { |
- // Skip junk symbols from our internal stuff. |
- if (strstr(symbol->Name, "CallStack::") || |
- strstr(symbol->Name, "MemoryWatcher::") || |
- strstr(symbol->Name, "Perftools_") || |
- strstr(symbol->Name, "MemoryHook::") ) { |
- // Just record a blank string. |
- (*symbol_cache_)[intruction_pointer] = ""; |
- continue; |
- } |
- |
- line += " "; |
- line += static_cast<char*>(Line.FileName); |
- line += " ("; |
- // TODO(jar): get something like this template to work :-/ |
- // line += IntToCustomString<PrivateAllocatorString>(Line.LineNumber); |
- // ...and then delete this line, which uses std::string. |
- line += base::IntToString(Line.LineNumber).c_str(); |
- line += "): "; |
- line += symbol->Name; |
- line += "\n"; |
- } else { |
- line += " unknown (0):"; |
- line += symbol->Name; |
- line += "\n"; |
- } |
- } else { |
- // OK - couldn't get any info. Try for the module. |
- IMAGEHLP_MODULE64 module_info; |
- module_info.SizeOfStruct = sizeof(module_info); |
- if (pSymGetModuleInfo64(current_process, intruction_pointer, |
- &module_info)) { |
- line += " ("; |
- line += static_cast<char*>(module_info.ModuleName); |
- line += ")\n"; |
- } else { |
- line += " ???\n"; |
- } |
- } |
- } |
- |
- (*symbol_cache_)[intruction_pointer] = line; |
- *output += line; |
- } |
- *output += "==================\n"; |
-} |
- |
- |
-base::Lock AllocationStack::freelist_lock_; |
-AllocationStack* AllocationStack::freelist_ = NULL; |
- |
-void* AllocationStack::operator new(size_t size) { |
- DCHECK(size == sizeof(AllocationStack)); |
- { |
- base::AutoLock lock(freelist_lock_); |
- if (freelist_ != NULL) { |
- AllocationStack* stack = freelist_; |
- freelist_ = freelist_->next_; |
- stack->next_ = NULL; |
- return stack; |
- } |
- } |
- return MemoryHook::Alloc(size); |
-} |
- |
-void AllocationStack::operator delete(void* ptr) { |
- AllocationStack *stack = reinterpret_cast<AllocationStack*>(ptr); |
- base::AutoLock lock(freelist_lock_); |
- DCHECK(stack->next_ == NULL); |
- stack->next_ = freelist_; |
- freelist_ = stack; |
-} |