Hand-apply 155b4b9f615f42b5cc26e2953860aba34b17bbc0; allow build of Windows debug...
[dcpomatic.git] / src / lib / stack.cpp
diff --git a/src/lib/stack.cpp b/src/lib/stack.cpp
deleted file mode 100644 (file)
index 1675240..0000000
+++ /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
-