From 815e4cf7441d83ffca6d4d797a1a313f7c6464ab Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 15 Dec 2014 10:58:01 +0000 Subject: [PATCH] Hand-apply 155b4b9f615f42b5cc26e2953860aba34b17bbc0; allow build of Windows debug version using gdb. --- TO_PORT | 1 - cscript | 3 + platform/windows/wscript | 121 ++++++++-- src/lib/stack.cpp | 460 ------------------------------------- src/lib/stack.hpp | 58 ----- src/lib/util.cc | 78 ++++++- src/lib/util.h | 2 + src/lib/wscript | 1 - src/tools/dcpomatic_kdm.cc | 2 - 9 files changed, 171 insertions(+), 555 deletions(-) delete mode 100644 src/lib/stack.cpp delete mode 100644 src/lib/stack.hpp diff --git a/TO_PORT b/TO_PORT index e340470c2..3a54c0d1e 100644 --- a/TO_PORT +++ b/TO_PORT @@ -1,4 +1,3 @@ -e7fe121fedc6d837c5bc8ab31e4b36c50497c4cd 250ff9430c5e3727e2c5e24f81bc6d05a8700b49 df4337db7d2f94f430caaf1b89f41dfae777799b 46db828eab42862bf950b4690d9ad191faf9393e diff --git a/cscript b/cscript index 5621ef51f..fffec8035 100644 --- a/cscript +++ b/cscript @@ -161,6 +161,8 @@ def dependencies(target): def build(target, options): cmd = './waf configure --prefix=%s' % target.directory + if target.debug: + cmd += ' --enable-debug' if target.platform == 'windows': cmd += ' --target-windows' elif target.platform == 'linux': @@ -185,6 +187,7 @@ def package_windows(target): target.command('sed -i "s~%%resources%%~%s/platform/windows~g" build/platform/windows/installer2.%s.nsi' % (os.getcwd(), target.bits)) target.command('sed -i "s~%%static_deps%%~%s~g" build/platform/windows/installer2.%s.nsi' % (target.windows_prefix, target.bits)) target.command('sed -i "s~%%cdist_deps%%~%s~g" build/platform/windows/installer2.%s.nsi' % (target.directory, target.bits)) + target.command('sed -i "s~%%mingw%%~%s~g" build/platform/windows/installer2.%s.nsi' % (target.mingw_path, target.bits)) target.command('sed -i "s~%%binaries%%~%s/build~g" build/platform/windows/installer2.%s.nsi' % (os.getcwd(), target.bits)) target.command('sed -i "s~%%bits%%~32~g" build/platform/windows/installer2.%s.nsi' % target.bits) target.command('makensis build/platform/windows/installer2.%s.nsi' % target.bits) diff --git a/platform/windows/wscript b/platform/windows/wscript index 4e38e4f2d..cdfc24931 100644 --- a/platform/windows/wscript +++ b/platform/windows/wscript @@ -1,7 +1,7 @@ from __future__ import print_function import os -def write_installer(bits, version): +def write_installer(bits, version, debug): try: os.makedirs('build/platform/windows') except: @@ -12,18 +12,31 @@ def write_installer(bits, version): if bits == 64: print('!include "x64.nsh"', file=f) - print('Name "DCP-o-matic"', file=f) + if debug: + print('Name "DCP-o-matic Debug"', file=f) + else: + print('Name "DCP-o-matic"', file=f) + print('RequestExecutionLevel admin', file=f) - print('outFile "DCP-o-matic %s %d-bit Installer.exe"' % (version, bits), file=f) + if debug: + print('outFile "DCP-o-matic Debug %s %d-bit Installer.exe"' % (version, bits), file=f) + else: + print('outFile "DCP-o-matic %s %d-bit Installer.exe"' % (version, bits), file=f) + print(""" !define MUI_ICON "%resources%/dcpomatic.ico" !define MUI_UNICON "%resources%/dcpomatic.ico" !define MUI_SPECIALBITMAP "%resources%/dcpomatic.bmp" !include "Sections.nsh" + """, file=f) -InstallDir "$PROGRAMFILES\\DCP-o-matic 2" + if debug: + print('InstallDir "$PROGRAMFILES\\DCP-o-matic 2 Debug"', file=f) + else: + print('InstallDir "$PROGRAMFILES\\DCP-o-matic 2"', file=f) + print(""" !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "../../../COPYING" !insertmacro MUI_PAGE_DIRECTORY @@ -121,10 +134,18 @@ File "%cdist_deps%/bin/swscale-3.dll" File "%cdist_deps%/bin/cxml-0.dll" File "%cdist_deps%/bin/sub.dll" File "%cdist_deps%/bin/ffprobe.exe" + """, file=f) -File "%binaries%/src/wx/dcpomatic2-wx.dll" -File "%binaries%/src/lib/dcpomatic2.dll" + if debug: + print('File "%resources%/gdb_script"', file=f) + print('File "%resources%/debug.bat"', file=f) + print('File "%mingw%/gdb.exe"', file=f) + print('File "%mingw%/addr2line.exe"', file=f) + else: + print('File "%binaries%/src/wx/dcpomatic2-wx.dll"', file=f) + print('File "%binaries%/src/lib/dcpomatic2.dll"', file=f) + print(""" SetOutPath "$INSTDIR\\lib\\pango\\1.8.0\\modules" File "%static_deps%/lib/pango/1.8.0/modules/pango-arabic-lang.dll" File "%static_deps%/lib/pango/1.8.0/modules/pango-basic-win32.dll" @@ -168,9 +189,16 @@ File "%binaries%/src/lib/mo/nl_NL/libdcpomatic2.mo" File "%binaries%/src/wx/mo/nl_NL/libdcpomatic2-wx.mo" File "%binaries%/src/tools/mo/nl_NL/dcpomatic2.mo" File "%static_deps%/share/locale/nl/LC_MESSAGES/wxstd.mo" + """, file=f) + + if debug: + print('WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\DCP-o-matic 2 Debug" "DisplayName" "DCP-o-matic 2 Debug (remove only)"', file=f) + print('WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\DCP-o-matic 2 Debug" "UninstallString" "$INSTDIR\\Uninstall.exe"', file=f) + else: + print('WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\DCP-o-matic 2" "DisplayName" "DCP-o-matic 2 (remove only)"', file=f) + print('WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\DCP-o-matic 2" "UninstallString" "$INSTDIR\\Uninstall.exe"', file=f) -WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\DCP-o-matic2" "DisplayName" "DCP-o-matic 2 (remove only)" -WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\DCP-o-matic2" "UninstallString" "$INSTDIR\\Uninstall.exe" + print(""" WriteUninstaller "$INSTDIR\\Uninstall.exe" CreateDirectory "$INSTDIR\etc\pango" @@ -179,23 +207,48 @@ SetOutPath "$INSTDIR" nsExec::ExecToLog '$0 /C bin\pango-querymodules.exe > etc\pango\pango.modules' SectionEnd + """, file=f) -Section "DCP-o-matic" SEC_MASTER -SetOutPath "$INSTDIR\\bin" -CreateDirectory "$SMPROGRAMS\\DCP-o-matic 2" + if debug: + print('Section "DCP-o-matic 2 Debug" SEC_MASTER', file=f) + else: + print('Section "DCP-o-matic 2" SEC_MASTER', file=f) + + print('SetOutPath "$INSTDIR\\bin"', file=f) + + if debug: + print('CreateDirectory "$SMPROGRAMS\\DCP-o-matic 2 Debug"', file=f) + else: + print('CreateDirectory "$SMPROGRAMS\\DCP-o-matic 2"', file=f) + + print(""" File "%binaries%/src/tools/dcpomatic2.exe" File "%binaries%/src/tools/dcpomatic2_batch.exe" File "%binaries%/src/tools/dcpomatic2_cli.exe" -CreateShortCut "$DESKTOP\\DCP-o-matic 2.lnk" "$INSTDIR\\bin\\dcpomatic2.exe" "" -CreateShortCut "$SMPROGRAMS\\DCP-o-matic 2\\DCP-o-matic 2.lnk" "$INSTDIR\\bin\\dcpomatic2.exe" "" "$INSTDIR\\bin\\dcpomatic2.exe" 0 -CreateShortCut "$DESKTOP\\DCP-o-matic 2 batch converter.lnk" "$INSTDIR\\bin\\dcpomatic2_batch.exe" "" -CreateShortCut "$SMPROGRAMS\\DCP-o-matic 2\\DCP-o-matic 2 batch converter.lnk" "$INSTDIR\\bin\\dcpomatic2.exe" "" "$INSTDIR\\bin\\dcpomatic2_batch.exe" 0 -CreateShortCut "$SMPROGRAMS\\DCP-o-matic 2\\Uninstall DCP-o-matic 2.lnk" "$INSTDIR\\Uninstall.exe" "" "$INSTDIR\\Uninstall.exe" 0 -WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\DCP-o-matic2" "DisplayName" "DCP-o-matic 2 (remove only)" -WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\DCP-o-matic2" "UninstallString" "$INSTDIR\\Uninstall.exe" + """, file=f) + + if debug: + print('CreateShortCut "$DESKTOP\\DCP-o-matic 2 Debug.lnk" "$INSTDIR\\bin\\debug.bat" ""', file=f) + print('CreateShortCut "$SMPROGRAMS\\DCP-o-matic 2 Debug\\DCP-o-matic 2 Debug.lnk" "$INSTDIR\\bin\\debug.bat"', file=f) + print('CreateShortCut "$SMPROGRAMS\\DCP-o-matic 2\\Uninstall DCP-o-matic 2 Debug.lnk" "$INSTDIR\\Uninstall.exe"', file=f) + print('WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\DCP-o-matic 2 Debug" "DisplayName" "DCP-o-matic 2 Debug (remove only)"', file=f) + print('WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\DCP-o-matic 2 Debug" "UninstallString" "$INSTDIR\\Uninstall.exe"', file=f) + else: + print('CreateShortCut "$DESKTOP\\DCP-o-matic 2.lnk" "$INSTDIR\\bin\\dcpomatic2.exe" ""', file=f) + print('CreateShortCut "$SMPROGRAMS\\DCP-o-matic 2\\DCP-o-matic 2.lnk" "$INSTDIR\\bin\\dcpomatic2.exe"', file=f) + print('CreateShortCut "$DESKTOP\\DCP-o-matic 2 batch converter.lnk" "$INSTDIR\\bin\\dcpomatic2_batch.exe"', file=f) + print('CreateShortCut "$SMPROGRAMS\\DCP-o-matic 2\\DCP-o-matic 2 batch converter.lnk" "$INSTDIR\\bin\\dcpomatic2.exe"', file=f) + print('CreateShortCut "$SMPROGRAMS\\DCP-o-matic 2\\Uninstall DCP-o-matic 2.lnk" "$INSTDIR\\Uninstall.exe"', file=f) + print('WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\DCP-o-matic2" "DisplayName" "DCP-o-matic 2 (remove only)"', file=f) + print('WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\DCP-o-matic2" "UninstallString" "$INSTDIR\\Uninstall.exe"', file=f) + + print(""" WriteUninstaller "$INSTDIR\\Uninstall.exe" SectionEnd + """, file=f) + if not debug: + print(""" Section "Encode server" SEC_SERVER SetOutPath "$INSTDIR\\bin" CreateDirectory "$SMPROGRAMS\\DCP-o-matic 2" @@ -205,10 +258,15 @@ CreateShortCut "$DESKTOP\\DCP-o-matic 2 encode server.lnk" "$INSTDIR\\bin\\dcpom CreateShortCut "$SMPROGRAMS\\DCP-o-matic 2\\DCP-o-matic 2 encode server.lnk" "$INSTDIR\\bin\\dcpomatic_server.exe" "" "$INSTDIR\\bin\\dcpomatic2_server.exe" 0 CreateShortCut "$SMPROGRAMS\\DCP-o-matic 2\\Uninstall DCP-o-matic 2.lnk" "$INSTDIR\\Uninstall.exe" "" "$INSTDIR\\Uninstall.exe" 0 SectionEnd + """, file=f) -LangString DESC_SEC_MASTER ${LANG_ENGLISH} "DCP-o-matic" -LangString DESC_SEC_SERVER ${LANG_ENGLISH} "DCP-o-matic encode server" + if debug: + print('LangString DESC_SEC_MASTER ${LANG_ENGLISH} "DCP-o-matic 2 Debug"', file=f) + else: + print('LangString DESC_SEC_MASTER ${LANG_ENGLISH} "DCP-o-matic 2"', file=f) + print('LangString DESC_SEC_SERVER ${LANG_ENGLISH} "DCP-o-matic 2 encode server"', file=f) + printf(""" !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_DESCRIPTION_TEXT ${SEC_MASTER} $(DESC_SEC_MASTER) !insertmacro MUI_DESCRIPTION_TEXT ${SEC_SERVER} $(DESC_SEC_SERVER) @@ -222,7 +280,22 @@ LangString DESC_SEC_SERVER ${LANG_ENGLISH} "DCP-o-matic encode server" !insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_UNPAGE_FINISH !insertmacro MUI_LANGUAGE "English" + """, file=f) + if debug: + print(""" +Section "Uninstall" +RMDir /r "$INSTDIR\\*.*" +RMDir "$INSTDIR" +Delete "$DESKTOP\\DCP-o-matic 2 Debug.lnk" +Delete "$SMPROGRAMS\\DCP-o-matic 2 Debug\\*.*" +RmDir "$SMPROGRAMS\\DCP-o-matic 2 Debug" +DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\\DCP-o-matic 2 Debug" +DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\DCP-o-matic 2 Debug" + SectionEnd + """, file=f) + else: + print(""" Section "Uninstall" RMDir /r "$INSTDIR\\*.*" RMDir "$INSTDIR" @@ -231,12 +304,12 @@ Delete "$DESKTOP\\DCP-o-matic 2 batch converter.lnk" Delete "$DESKTOP\\DCP-o-matic 2 encode server.lnk" Delete "$SMPROGRAMS\\DCP-o-matic 2\\*.*" RmDir "$SMPROGRAMS\\DCP-o-matic 2" -DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\\DCP-o-matic2" -DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\DCP-o-matic2" +DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\\DCP-o-matic 2" +DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\DCP-o-matic 2" SectionEnd """, file=f) def build(bld): - write_installer(32, bld.env.VERSION) - write_installer(64, bld.env.VERSION) + write_installer(32, bld.env.VERSION, bld.env.DEBUG) + write_installer(64, bld.env.VERSION, bld.env.DEBUG) 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 -#include -#include -#include -#include -#include - -#include "stack.hpp" - -#if defined(_WIN32) -# include -# include - -# if defined(__MINGW32__) -# define PACKAGE 1 -# define PACKAGE_VERSION 1 -# include // link against libbfd and libiberty -# include // link against psapi -# include -# endif - -#elif defined(__GNUC__) -# include -# include -#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(&symbol_table_), &dummy) == 0 && - bfd_read_minisymbols(abfd_, TRUE, reinterpret_cast(&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 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(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 - 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 - operator FuncPtr() const { return reinterpret_cast(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 &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(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(module_base), module_name_raw, MAX_PATH)) - module_name = module_name_raw; - -#if defined(__MINGW32__) - std::pair 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(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 &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(__builtin_frame_address(0)); - void **bp = static_cast(*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(bp[0]); - } - } - -# elif defined(__ppc__) - - void fill_frames(std::list &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(__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(*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 - diff --git a/src/lib/stack.hpp b/src/lib/stack.hpp deleted file mode 100644 index 73a13bf85..000000000 --- a/src/lib/stack.hpp +++ /dev/null @@ -1,58 +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) - -#ifndef STACK_HPP_0022_01092007 -#define STACK_HPP_0022_01092007 - -#include -#include -#include - -namespace dbg -{ - //! stack_frame objects are collected by a stack object. They contain information about the instruction pointer, - //! the name of the corresponding function and the "module" (executable or library) in which the function resides. - struct stack_frame - { - stack_frame(const void *instruction, const std::string &function, unsigned int line, const std::string &module); - - const void *instruction; - std::string function; - unsigned int line; - std::string module; - }; - - //! Allows you to write a stack_frame object to an std::ostream - std::ostream &operator<< (std::ostream &out, const stack_frame &frame); - - //! Instantiate a dbg::stack object to collect information about the current call stack. Once created, a stack object - //! may be freely copied about and will continue to contain the information about the scope in which collection occurred. - class stack - { - public: - typedef std::list::size_type depth_type; - typedef std::list::const_iterator const_iterator; - - //! Collect information about the current call stack. Information on the most recent frames will be collected - //! up to the specified limit. 0 means unlimited. - //! An std::runtime_error may be thrown on failure. - stack(depth_type limit = 0); - - //! Returns an iterator referring to the "top" stack frame - const_iterator begin() const; - - //! Returns an iterator referring to one past the "bottom" stack frame - const_iterator end() const; - - //! Returns the number of frames collected - depth_type depth() const; - - private: - std::list frames_; - }; - -} // close namespace dbg - -#endif // STACK_HPP_0022_01092007 diff --git a/src/lib/util.cc b/src/lib/util.cc index e03b47568..502393094 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -37,9 +37,6 @@ #include "md5_digester.h" #include "audio_processor.h" #include "safe_stringstream.h" -#ifdef DCPOMATIC_WINDOWS -#include "stack.hpp" -#endif #include #include #include @@ -69,6 +66,7 @@ extern "C" { #include #ifdef DCPOMATIC_WINDOWS #include +#include #endif #include #include @@ -103,6 +101,10 @@ using boost::optional; using dcp::Size; using dcp::raw_convert; +/** Path to our executable, required by the stacktrace stuff and filled + * in during App::onInit(). + */ +string program_name; static boost::thread::id ui_thread; static boost::filesystem::path backtrace_file; @@ -263,15 +265,69 @@ seconds (struct timeval t) } #ifdef DCPOMATIC_WINDOWS + +/** Resolve symbol name and source location given the path to the executable */ +int +addr2line (void const * const adr) +{ + char addr2line_cmd[512] = { 0 }; + sprintf (addr2line_cmd, "addr2line -f -p -e %.256s %p > %s", program_name.c_str(), addr, backtrace_file.string().c_str()); + return system(addr2line_cmd); +} + +/** This is called when C signals occur on Windows (e.g. SIGSEGV) + * (NOT C++ exceptions!). We write a backtrace to backtrace_file by dark means. + * Adapted from code here: http://spin.atomicobject.com/2013/01/13/exceptions-stack-traces-c/ + */ LONG WINAPI exception_handler(struct _EXCEPTION_POINTERS *) { - dbg::stack s; FILE* f = fopen_boost (backtrace_file, "w"); - fprintf (f, "Exception thrown:"); - for (dbg::stack::const_iterator i = s.begin(); i != s.end(); ++i) { - fprintf (f, "%p %s %d %s\n", i->instruction, i->function.c_str(), i->line, i->module.c_str()); + fprintf (f, "C-style exception %d\n", info->ExceptionRecord->ExceptionCode); + fclose(f); + + if (info->ExceptionRecord->ExceptionCode != EXCEPTION_STACK_OVERFLOW) { + CONTEXT* context = info->ContextRecord; + SymInitialize (GetCurrentProcess (), 0, true); + + STACKFRAME frame = { 0 }; + + /* setup initial stack frame */ +#if _WIN64 + frame.AddrPC.Offset = context->Rip; + frame.AddrStack.Offset = context->Rsp; + frame.AddrFrame.Offset = context->Rbp; +#else + frame.AddrPC.Offset = context->Eip; + frame.AddrStack.Offset = context->Esp; + frame.AddrFrame.Offset = context->Ebp; +#endif + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrStack.Mode = AddrModeFlat; + frame.AddrFrame.Mode = AddrModeFlat; + + while ( + StackWalk ( + IMAGE_FILE_MACHINE_I386, + GetCurrentProcess (), + GetCurrentThread (), + &frame, + context, + 0, + SymFunctionTableAccess, + SymGetModuleBase, + 0 + ) + ) { + addr2line((void *) frame.AddrPC.Offset); + } + } else { +#ifdef _WIN64 + addr2line ((void *) info->ContextRecord->Rip); +#else + addr2line ((void *) info->ContextRecord->Eip); +#endif } - fclose (f); + return EXCEPTION_CONTINUE_SEARCH; } #endif @@ -282,7 +338,11 @@ set_backtrace_file (boost::filesystem::path p) backtrace_file = p; } -/* From http://stackoverflow.com/questions/2443135/how-do-i-find-where-an-exception-was-thrown-in-c */ +/** This is called when there is an unhandled exception. Any + * backtrace in this function is useless on Windows as the stack has + * already been unwound from the throw; we have the gdb wrap hack to + * cope with that. + */ void terminate () { diff --git a/src/lib/util.h b/src/lib/util.h index 1d04d358b..f5d0b3aca 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -48,6 +48,8 @@ extern "C" { #define HISTORY_SIZE 10 #define REPORT_PROBLEM _("Please report this problem by using Help -> Report a problem or via email to carl@dcpomatic.com") +extern std::string program_name; + class Job; struct AVSubtitle; diff --git a/src/lib/wscript b/src/lib/wscript index 0a6b79207..7edd5dcdf 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -118,7 +118,6 @@ def build(bld): if bld.env.TARGET_WINDOWS: obj.uselib += ' WINSOCK2 BFD DBGHELP IBERTY SHLWAPI MSWSOCK BOOST_LOCALE' - obj.source += ' stack.cpp' if bld.env.BUILD_STATIC: obj.uselib += ' XMLPP' diff --git a/src/tools/dcpomatic_kdm.cc b/src/tools/dcpomatic_kdm.cc index 6257d60af..2398dc74d 100644 --- a/src/tools/dcpomatic_kdm.cc +++ b/src/tools/dcpomatic_kdm.cc @@ -33,8 +33,6 @@ using std::list; using std::vector; using boost::shared_ptr; -static string program_name; - static void help () { -- 2.30.2