diff options
Diffstat (limited to 'src/lib/stack.cpp')
| -rw-r--r-- | src/lib/stack.cpp | 460 |
1 files changed, 0 insertions, 460 deletions
diff --git a/src/lib/stack.cpp b/src/lib/stack.cpp deleted file mode 100644 index 167524017..000000000 --- a/src/lib/stack.cpp +++ /dev/null @@ -1,460 +0,0 @@ -// Copyright 2007 Edd Dawson. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include <cassert> -#include <cstring> -#include <cstdlib> -#include <iomanip> -#include <ostream> -#include <stdexcept> - -#include "stack.hpp" - -#if defined(_WIN32) -# include <windows.h> -# include <imagehlp.h> - -# if defined(__MINGW32__) -# define PACKAGE 1 -# define PACKAGE_VERSION 1 -# include <bfd.h> // link against libbfd and libiberty -# include <psapi.h> // link against psapi -# include <cxxabi.h> -# endif - -#elif defined(__GNUC__) -# include <dlfcn.h> -# include <cxxabi.h> -#endif - -namespace -{ - const char * const unknown_function = "[unknown function]"; - const char * const unknown_module = "[unknown module]"; - -#if defined(__GNUC__) - std::string demangle(const char *name) - { - if (!name) - return unknown_function; - - int status = 0; - char *d = 0; - std::string ret = name; - try - { - if ((d = abi::__cxa_demangle(name, 0, 0, &status))) - ret = d; - } - catch (const std::bad_alloc &) { } - - std::free(d); - return ret; - } -#endif - -#if defined(_WIN32) - - // Derive from this to disallow copying of your class. - // c.f. boost::noncopyable - class uncopyable - { - protected: - uncopyable() { } - - private: - uncopyable(const uncopyable &); - uncopyable &operator= (const uncopyable &); - }; - -#if defined(__MINGW32__) - - // Provides a means to translate a program counter offset in to the name of the corresponding function. - class bfd_context : uncopyable - { - private: - struct find_data - { - std::string func; - unsigned int line; - asymbol **symbol_table; - bfd_vma counter; - }; - - public: - bfd_context() : - abfd_(0), - sec_(0), - symbol_table_(0) - { - char procname[MAX_PATH]; - GetModuleFileNameA(NULL, procname, sizeof procname); - - bfd_init(); - abfd_ = bfd_openr(procname, 0); - if (!abfd_) - throw std::runtime_error("Failed to parse object data for the executable"); - - char **formats = 0; - bool b1 = bfd_check_format(abfd_, bfd_object); - bool b2 = bfd_check_format_matches(abfd_, bfd_object, &formats); - bool b3 = bfd_get_file_flags(abfd_) & HAS_SYMS; - - if (!(b1 && b2 && b3)) - { - bfd_close(abfd_); - free(formats); - throw std::runtime_error("Failed to parse object data for the executable"); - } - free(formats); - - // Load symbol table - unsigned dummy = 0; - if (bfd_read_minisymbols(abfd_, FALSE, reinterpret_cast<void **>(&symbol_table_), &dummy) == 0 && - bfd_read_minisymbols(abfd_, TRUE, reinterpret_cast<void **>(&symbol_table_), &dummy) < 0) - { - free(symbol_table_); - bfd_close(abfd_); - throw std::runtime_error("Failed to parse object data for the executable"); - } - } - - ~bfd_context() - { - free(symbol_table_); - bfd_close(abfd_); - } - - std::pair<std::string, unsigned int> get_function_name_and_line(DWORD offset) - { - find_data data; - data.symbol_table = symbol_table_; - data.counter = offset; - - bfd_map_over_sections(abfd_, &find_function_name_in_section, &data); - - return std::make_pair(data.func, data.line); - } - - private: - static void find_function_name_in_section(bfd *abfd, asection *sec, void *opaque_data) - { - assert(sec); - assert(opaque_data); - find_data &data = *static_cast<find_data *>(opaque_data); - - if (!data.func.empty()) return; // already found it - - if (!(bfd_get_section_flags(abfd, sec) & SEC_ALLOC)) return; - - bfd_vma vma = bfd_get_section_vma(abfd, sec); - if (data.counter < vma || vma + bfd_get_section_size(sec) <= data.counter) return; - - const char *func = 0; - const char *file = 0; - unsigned line = 0; - - if (bfd_find_nearest_line(abfd, sec, data.symbol_table, data.counter - vma, &file, &func, &line) && func) { - data.func = demangle(func); - data.line = line; - } - } - - private: - bfd *abfd_; - asection *sec_; - asymbol **symbol_table_; - }; - -#endif // __MINGW32__ - - // g++ spouts warnings if you use {0} to initialize PODs. So we use this instead: - const struct - { - template<typename POD> - operator POD () const { POD p; std::memset(&p, 0, sizeof p); return p; } - } - empty_pod = { }; - - // Wraps a FARPROC. Implicitly convertible to any kind of pointer-to-function. - // Avoids having reinterpret casts all over the place. - struct auto_cast_function_ptr - { - auto_cast_function_ptr(FARPROC f) : fptr_(f) { } - - template<typename FuncPtr> - operator FuncPtr() const { return reinterpret_cast<FuncPtr>(fptr_); } - - FARPROC fptr_; - }; - - // A wrapper around a DLL. Can dynamically get function pointers with the function() function! - class windows_dll : uncopyable - { - public: - explicit windows_dll(const std::string &libname) : - name_(libname), - lib_(LoadLibraryA(name_.c_str())) - { - if (!lib_) throw std::runtime_error("Failed to load dll " + name_); - } - - ~windows_dll() { FreeLibrary(lib_); } - - const std::string &name() const { return name_; } - - auto_cast_function_ptr function(const char *func_name) const - { - FARPROC proc = GetProcAddress(lib_, func_name); - if (!proc) throw std::runtime_error(std::string("failed to load function ") + func_name + " from library " + name_); - - return proc; - } - - private: - std::string name_; - HMODULE lib_; - }; - - // An object that makes sure debugging symbols are available - class symbol_context : uncopyable - { - public: - symbol_context() - { - if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) - throw std::runtime_error("Failed to initialize symbol context"); - } - ~symbol_context() { SymCleanup(GetCurrentProcess()); } - }; - - // A simple Windows mutex class. Use a lock object to lock the mutex for the duration of a scope. - class mutex : uncopyable - { - public: - mutex() { InitializeCriticalSection(&cs_); } - ~mutex() { DeleteCriticalSection(&cs_); } - - private: - friend class lock; - void lock() { EnterCriticalSection(&cs_); } - void unlock() { LeaveCriticalSection(&cs_); } - - CRITICAL_SECTION cs_; - } - g_fill_frames_mtx; - - // A lock for the mutex - class lock : uncopyable - { - public: - lock(mutex &m) : m_(m) { m.lock(); } - ~lock() { m_.unlock(); } - private: - mutex &m_; - }; - - - void fill_frames(std::list<dbg::stack_frame> &frames, dbg::stack::depth_type limit) - { - lock lk(g_fill_frames_mtx); - - symbol_context sc; -#ifdef __MINGW32__ - bfd_context bfdc; -#endif - - STACKFRAME frame = empty_pod; - CONTEXT context = empty_pod; - context.ContextFlags = CONTEXT_FULL; - - windows_dll kernel32("kernel32.dll"); - void (WINAPI *RtlCaptureContext_)(CONTEXT*) = kernel32.function("RtlCaptureContext"); - - RtlCaptureContext_(&context); - -#if defined(_M_AMD64) - frame.AddrPC.Offset = context.Rip; - frame.AddrPC.Mode = AddrModeFlat; - frame.AddrStack.Offset = context.Rsp; - frame.AddrStack.Mode = AddrModeFlat; - frame.AddrFrame.Offset = context.Rbp; - frame.AddrFrame.Mode = AddrModeFlat; -#else - frame.AddrPC.Offset = context.Eip; - frame.AddrPC.Mode = AddrModeFlat; - frame.AddrStack.Offset = context.Esp; - frame.AddrStack.Mode = AddrModeFlat; - frame.AddrFrame.Offset = context.Ebp; - frame.AddrFrame.Mode = AddrModeFlat; -#endif - - HANDLE process = GetCurrentProcess(); - HANDLE thread = GetCurrentThread(); - - bool skip = true; - bool has_limit = limit != 0; - char symbol_buffer[sizeof(IMAGEHLP_SYMBOL) + 255]; - char module_name_raw[MAX_PATH]; - -#if defined(_M_AMD64) - const DWORD machine = IMAGE_FILE_MACHINE_AMD64; -#else - const DWORD machine = IMAGE_FILE_MACHINE_I386; -#endif - - while(StackWalk(machine, process, thread, &frame, &context, 0, SymFunctionTableAccess, SymGetModuleBase, 0)) - { - if (skip) - { - skip = false; - continue; - } - - if (has_limit && limit-- == 0) break; - - IMAGEHLP_SYMBOL *symbol = reinterpret_cast<IMAGEHLP_SYMBOL *>(symbol_buffer); - symbol->SizeOfStruct = (sizeof *symbol) + 255; - symbol->MaxNameLength = 254; - -#if defined(_WIN64) - DWORD64 module_base = SymGetModuleBase(process, frame.AddrPC.Offset); -#else - DWORD module_base = SymGetModuleBase(process, frame.AddrPC.Offset); -#endif - std::string module_name = unknown_module; - if (module_base && GetModuleFileNameA(reinterpret_cast<HINSTANCE>(module_base), module_name_raw, MAX_PATH)) - module_name = module_name_raw; - -#if defined(__MINGW32__) - std::pair<std::string, unsigned int> func_and_line = bfdc.get_function_name_and_line(frame.AddrPC.Offset); - - if (func_and_line.first.empty()) - { -#if defined(_WIN64) - DWORD64 dummy = 0; -#else - DWORD dummy = 0; -#endif - BOOL got_symbol = SymGetSymFromAddr(process, frame.AddrPC.Offset, &dummy, symbol); - func_and_line.first = got_symbol ? symbol->Name : unknown_function; - } -#else - DWORD dummy = 0; - BOOL got_symbol = SymGetSymFromAddr(process, frame.AddrPC.Offset, &dummy, symbol); - std::string func = got_symbol ? symbol->Name : unknown_function; -#endif - - dbg::stack_frame f(reinterpret_cast<const void *>(frame.AddrPC.Offset), func_and_line.first, func_and_line.second, module_name); - frames.push_back(f); - } - } -#elif defined(__GNUC__) -# if defined(__i386__) || defined(__amd64__) - - void fill_frames(std::list<dbg::stack_frame> &frames, dbg::stack::depth_type limit) - { - // Based on code found at: - // http://www.tlug.org.za/wiki/index.php/Obtaining_a_stack_trace_in_C_upon_SIGSEGV - - Dl_info info; - void **frame = static_cast<void **>(__builtin_frame_address(0)); - void **bp = static_cast<void **>(*frame); - void *ip = frame[1]; - - bool has_limit = limit != 0; - bool skip = true; - - while(bp && ip && dladdr(ip, &info)) - { - if (skip) - skip = false; - else - { - if (has_limit && limit-- == 0) break; - frames.push_back(dbg::stack_frame(ip, demangle(info.dli_sname), info.dli_fname)); - - if(info.dli_sname && !std::strcmp(info.dli_sname, "main")) break; - } - - ip = bp[1]; - bp = static_cast<void**>(bp[0]); - } - } - -# elif defined(__ppc__) - - void fill_frames(std::list<dbg::stack_frame> &frames, dbg::stack::depth_type limit) - { - // Based on code found at: - // http://www.informit.com/articles/article.aspx?p=606582&seqNum=4&rl=1 - - void *ip = __builtin_return_address(0); - void **frame = static_cast<void **>(__builtin_frame_address(1)); - bool has_limit = limit != 0; - Dl_info info; - - do - { - if (has_limit && limit-- == 0) break; - - if (dladdr(ip, &info)) - frames.push_back(dbg::stack_frame(ip, demangle(info.dli_sname), info.dli_fname)); - - if (frame && (frame = static_cast<void**>(*frame))) ip = *(frame + 2); - } - while (frame && ip); - } - -# else - // GNU, but not x86, x64 nor PPC -# error "Sorry but dbg::stack is not supported on this architecture" -# endif -#else - // Unsupported compiler -# error "Sorry but dbg::stack is not supported on this compiler" -#endif - -} // close anonymous namespace - - - -namespace dbg -{ - stack_frame::stack_frame(const void *instruction, const std::string &function, unsigned int line, const std::string &module) : - instruction(instruction), - function(function), - line(line), - module(module) - { - } - - std::ostream &operator<< (std::ostream &out, const stack_frame &frame) - { - return out << frame.instruction << ": " << frame.function << ":" << frame.line << " in " << frame.module; - } - - stack::stack(depth_type limit) - { - fill_frames(frames_, limit); - } - - stack::const_iterator stack::begin() const - { - return frames_.begin(); - } - - stack::const_iterator stack::end() const - { - return frames_.end(); - } - - stack::depth_type stack::depth() const - { - return frames_.size(); - } - -} // close namespace dbg - |
