summaryrefslogtreecommitdiffstats
path: root/chromium/tools/memory_watcher/call_stack.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/tools/memory_watcher/call_stack.cc')
-rw-r--r--chromium/tools/memory_watcher/call_stack.cc399
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;
-}