diff options
Diffstat (limited to 'chromium/tools/memory_watcher/call_stack.cc')
-rw-r--r-- | chromium/tools/memory_watcher/call_stack.cc | 399 |
1 files changed, 0 insertions, 399 deletions
diff --git a/chromium/tools/memory_watcher/call_stack.cc b/chromium/tools/memory_watcher/call_stack.cc deleted file mode 100644 index 6f829b45017..00000000000 --- a/chromium/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; -} |