Fix typos on hand-applying patch.
[dcpomatic.git] / src / lib / util.cc
index 20b7ba4706d97ecb6ee989a2a8b62a16629319fd..ebb7c046b7831c7d1624d1ac07db7709d6d91307 100644 (file)
@@ -37,9 +37,6 @@
 #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>
@@ -69,6 +66,7 @@ extern "C" {
 #include <boost/filesystem.hpp>
 #ifdef DCPOMATIC_WINDOWS
 #include <boost/locale.hpp>
+#include <dbghelp.h>
 #endif
 #include <signal.h>
 #include <iomanip>
@@ -88,20 +86,14 @@ using std::setfill;
 using std::ostream;
 using std::endl;
 using std::vector;
-using std::hex;
-using std::setw;
-using std::ios;
 using std::min;
 using std::max;
 using std::list;
 using std::multimap;
-using std::map;
 using std::istream;
-using std::numeric_limits;
 using std::pair;
 using std::cout;
 using std::bad_alloc;
-using std::streampos;
 using std::set_terminate;
 using boost::shared_ptr;
 using boost::thread;
@@ -109,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;
 
@@ -130,9 +126,9 @@ seconds_to_hms (int s)
        SafeStringStream hms;
        hms << h << N_(":");
        hms.width (2);
-       hms << std::setfill ('0') << m << N_(":");
+       hms << setfill ('0') << m << N_(":");
        hms.width (2);
-       hms << std::setfill ('0') << s;
+       hms << setfill ('0') << s;
 
        return hms.str ();
 }
@@ -269,15 +265,70 @@ seconds (struct timeval t)
 }
 
 #ifdef DCPOMATIC_WINDOWS
-LONG WINAPI exception_handler(struct _EXCEPTION_POINTERS *)
+
+/** Resolve symbol name and source location given the path to the executable */
+int
+addr2line (void const * const addr)
+{
+       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 * info)
 {
-       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
@@ -288,7 +339,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 ()
 {
@@ -654,7 +709,7 @@ stride_round_up (int c, int const * stride, int t)
 int
 round_to (float n, int r)
 {
-       assert (r == 1 || r == 2 || r == 4);
+       DCPOMATIC_ASSERT (r == 1 || r == 2 || r == 4);
        return int (n + float(r) / 2) &~ (r - 1);
 }
 
@@ -759,13 +814,13 @@ get_optional_int (multimap<string, string> const & kv, string k)
 void
 ensure_ui_thread ()
 {
-       assert (boost::this_thread::get_id() == ui_thread);
+       DCPOMATIC_ASSERT (boost::this_thread::get_id() == ui_thread);
 }
 
 string
 audio_channel_name (int c)
 {
-       assert (MAX_DCP_AUDIO_CHANNELS == 12);
+       DCPOMATIC_ASSERT (MAX_DCP_AUDIO_CHANNELS == 12);
 
        /// TRANSLATORS: these are the names of audio channels; Lfe (sub) is the low-frequency
        /// enhancement channel (sub-woofer).  HI is the hearing-impaired audio track and
@@ -823,52 +878,6 @@ tidy_for_filename (string f)
        return t;
 }
 
-map<string, string>
-split_get_request (string url)
-{
-       enum {
-               AWAITING_QUESTION_MARK,
-               KEY,
-               VALUE
-       } state = AWAITING_QUESTION_MARK;
-       
-       map<string, string> r;
-       string k;
-       string v;
-       for (size_t i = 0; i < url.length(); ++i) {
-               switch (state) {
-               case AWAITING_QUESTION_MARK:
-                       if (url[i] == '?') {
-                               state = KEY;
-                       }
-                       break;
-               case KEY:
-                       if (url[i] == '=') {
-                               v.clear ();
-                               state = VALUE;
-                       } else {
-                               k += url[i];
-                       }
-                       break;
-               case VALUE:
-                       if (url[i] == '&') {
-                               r.insert (make_pair (k, v));
-                               k.clear ();
-                               state = KEY;
-                       } else {
-                               v += url[i];
-                       }
-                       break;
-               }
-       }
-
-       if (state == VALUE) {
-               r.insert (make_pair (k, v));
-       }
-
-       return r;
-}
-
 dcp::Size
 fit_ratio_within (float ratio, dcp::Size full_frame, int round)
 {