-e7fe121fedc6d837c5bc8ab31e4b36c50497c4cd
250ff9430c5e3727e2c5e24f81bc6d05a8700b49
df4337db7d2f94f430caaf1b89f41dfae777799b
46db828eab42862bf950b4690d9ad191faf9393e
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':
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)
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:
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
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"
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"
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"
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)
!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"
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)
+++ /dev/null
-// 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
-
+++ /dev/null
-// 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 <string>
-#include <list>
-#include <iosfwd>
-
-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<stack_frame>::size_type depth_type;
- typedef std::list<stack_frame>::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<stack_frame> frames_;
- };
-
-} // close namespace dbg
-
-#endif // STACK_HPP_0022_01092007
#include "md5_digester.h"
#include "audio_processor.h"
#include "safe_stringstream.h"
-#ifdef DCPOMATIC_WINDOWS
-#include "stack.hpp"
-#endif
#include <dcp/version.h>
#include <dcp/util.h>
#include <dcp/signer.h>
#include <boost/filesystem.hpp>
#ifdef DCPOMATIC_WINDOWS
#include <boost/locale.hpp>
+#include <dbghelp.h>
#endif
#include <signal.h>
#include <iomanip>
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;
}
#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
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 ()
{
#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;
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'
using std::vector;
using boost::shared_ptr;
-static string program_name;
-
static void
help ()
{