diff options
author | maruel@google.com <maruel@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-25 22:08:44 +0000 |
---|---|---|
committer | maruel@google.com <maruel@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-25 22:08:44 +0000 |
commit | de8d2667d6953abb31b7c5385ca718ad47adf6a1 (patch) | |
tree | 3d4499631bbf551dd81bb50b43452705b37d7bfb /tools/memory_watcher | |
parent | c9ec45429c64884c35f83b74131c0e3ae5b2bbe9 (diff) | |
download | chromium_src-de8d2667d6953abb31b7c5385ca718ad47adf6a1.zip chromium_src-de8d2667d6953abb31b7c5385ca718ad47adf6a1.tar.gz chromium_src-de8d2667d6953abb31b7c5385ca718ad47adf6a1.tar.bz2 |
Wow, it's been a while since we cleaned EOL.
Ran dos2unix on *.cc, *.h, *.py and SCons*.*
Ran for /R /D %a in (*.*) do @if exist %a\.svn\. svn pset svn:eol-style LF %a\*.cc
Ran for /R /D %a in (*.*) do @if exist %a\.svn\. svn pset svn:eol-style LF %a\*.h
Ran for /R /D %a in (*.*) do @if exist %a\.svn\. svn pset svn:eol-style LF %a\*.py
Ran for /R /D %a in (*.*) do @if exist %a\.svn\. svn pset svn:eol-style LF %a\SCons*.*
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2611 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools/memory_watcher')
-rw-r--r-- | tools/memory_watcher/call_stack.cc | 752 |
1 files changed, 376 insertions, 376 deletions
diff --git a/tools/memory_watcher/call_stack.cc b/tools/memory_watcher/call_stack.cc index dcbe541..ff73278 100644 --- a/tools/memory_watcher/call_stack.cc +++ b/tools/memory_watcher/call_stack.cc @@ -1,376 +1,376 @@ -// 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.
-
-#include "call_stack.h"
-#include <shlwapi.h>
-#include <tlhelp32.h>
-
-#include "memory_hook.h"
-#include "base/string_util.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);
-
-// According to http://msdn2.microsoft.com/en-us/library/ms680650(VS.85).aspx
-// "All DbgHelp functions, such as this one, are single threaded. Therefore,
-// calls from more than one thread to this function will likely result in
-// unexpected behavior or memory corruption. To avoid this, you must
-// synchromize all concurrent calls from one thread to this function."
-//
-// dbghelp_lock_ is used to serialize access across all calls to the DbgHelp
-// library. This may be overly conservative (serializing them all together),
-// but does guarantee correctness.
-static Lock dbghelp_lock_;
-
-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)
-
-// Dynamically load the DbgHelp library and supporting routines that we
-// will use.
-static bool LoadDbgHelp() {
- static bool loaded = false;
- if (!loaded) {
- AutoLock Lock(dbghelp_lock_);
-
- // Re-check if we've loaded successfully now that we have the lock.
- if (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);
- loaded = true;
- } else {
- return false;
- }
- }
- return 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);
-
- LoadDbgHelp();
- CHECK(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::GetStackTrace() {
- // 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;
- {
- AutoLock lock(dbghelp_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);
- }
- }
- return true;
-}
-
-void CallStack::ToString(std::string* output) {
- static const int kStackWalkMaxNameLen = MAX_SYM_NAME;
- HANDLE current_process = GetCurrentProcess();
-
- if (!LoadSymbols(current_process)) {
- *output = "Error";
- return;
- }
-
- AutoLock lock(dbghelp_lock_);
-
- // Iterate through each frame in the call stack.
- for (int32 index = 0; index < frame_count_; index++) {
- std::string 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] = std::string("");
- continue;
- }
-
- line += " ";
- line += static_cast<char*>(Line.FileName);
- line += " (";
- line += IntToString(Line.LineNumber);
- 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";
-}
-
-
-Lock AllocationStack::freelist_lock_;
-AllocationStack* AllocationStack::freelist_ = NULL;
-
-void* AllocationStack::operator new(size_t size) {
- DCHECK(size == sizeof(AllocationStack));
- {
- 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);
- AutoLock lock(freelist_lock_);
- DCHECK(stack->next_ == NULL);
- stack->next_ = freelist_;
- freelist_ = stack;
-}
-
+// 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. + +#include "call_stack.h" +#include <shlwapi.h> +#include <tlhelp32.h> + +#include "memory_hook.h" +#include "base/string_util.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); + +// According to http://msdn2.microsoft.com/en-us/library/ms680650(VS.85).aspx +// "All DbgHelp functions, such as this one, are single threaded. Therefore, +// calls from more than one thread to this function will likely result in +// unexpected behavior or memory corruption. To avoid this, you must +// synchromize all concurrent calls from one thread to this function." +// +// dbghelp_lock_ is used to serialize access across all calls to the DbgHelp +// library. This may be overly conservative (serializing them all together), +// but does guarantee correctness. +static Lock dbghelp_lock_; + +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) + +// Dynamically load the DbgHelp library and supporting routines that we +// will use. +static bool LoadDbgHelp() { + static bool loaded = false; + if (!loaded) { + AutoLock Lock(dbghelp_lock_); + + // Re-check if we've loaded successfully now that we have the lock. + if (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); + loaded = true; + } else { + return false; + } + } + return 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); + + LoadDbgHelp(); + CHECK(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::GetStackTrace() { + // 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; + { + AutoLock lock(dbghelp_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); + } + } + return true; +} + +void CallStack::ToString(std::string* output) { + static const int kStackWalkMaxNameLen = MAX_SYM_NAME; + HANDLE current_process = GetCurrentProcess(); + + if (!LoadSymbols(current_process)) { + *output = "Error"; + return; + } + + AutoLock lock(dbghelp_lock_); + + // Iterate through each frame in the call stack. + for (int32 index = 0; index < frame_count_; index++) { + std::string 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] = std::string(""); + continue; + } + + line += " "; + line += static_cast<char*>(Line.FileName); + line += " ("; + line += IntToString(Line.LineNumber); + 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"; +} + + +Lock AllocationStack::freelist_lock_; +AllocationStack* AllocationStack::freelist_ = NULL; + +void* AllocationStack::operator new(size_t size) { + DCHECK(size == sizeof(AllocationStack)); + { + 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); + AutoLock lock(freelist_lock_); + DCHECK(stack->next_ == NULL); + stack->next_ = freelist_; + freelist_ = stack; +} + |