Line data Source code
1 : /********************************************************************\
2 :
3 : Name: mexception.hxx
4 : Created by: Stefan Ritt
5 :
6 : Contents: Midas exception with stack trace
7 :
8 : \********************************************************************/
9 :
10 : #ifndef _MEXCEPT_HXX
11 : #define _MEXCEPT_HXX
12 :
13 : #include <string>
14 : #include <iostream>
15 : #include <sstream>
16 : #include <stdexcept>
17 : #include <execinfo.h>
18 : #include <dlfcn.h>
19 : #include <cxxabi.h>
20 :
21 : /*------------------------------------------------------------------*/
22 :
23 : // throw exception with full stack trace
24 : #define mthrow(arg) (throw mexception(arg, true, __FILE__, __LINE__))
25 :
26 : // throw exception with line number and file name
27 : #define mthrow1(arg) (throw mexception(arg, false, __FILE__, __LINE__))
28 :
29 : // throw exception without file and line number
30 : #define mthrow2(arg) (throw mexception(arg, false, "", 0))
31 :
32 : class mexception : public std::runtime_error {
33 : std::string msg;
34 : public:
35 0 : mexception(const std::string &arg, bool stack_trace, const char *file, int line) :
36 0 : std::runtime_error(arg) {
37 0 : std::stringstream trace_buf;
38 0 : if (file[0])
39 0 : trace_buf << file << ":" << line << ": " << arg;
40 : else
41 0 : trace_buf << arg;
42 :
43 0 : if (stack_trace) {
44 : // create strack trace and add it to message
45 0 : trace_buf << std::endl << "Stack trace:" << std::endl;
46 0 : void *callstack[128];
47 0 : char buf[1024];
48 0 : int n = backtrace(callstack, sizeof(callstack) / sizeof(callstack[0]));
49 0 : char **symbols = backtrace_symbols(callstack, n);
50 0 : for (int i = 1; i < n; i++) {
51 0 : Dl_info info;
52 0 : if (dladdr(callstack[i], &info)) {
53 0 : char *demangled = nullptr;
54 0 : int status = 0;
55 0 : demangled = abi::__cxa_demangle(info.dli_sname, nullptr, 0, &status);
56 0 : snprintf(buf, sizeof(buf), "%-3d 0x%018lX %s + %zd\n",
57 0 : i, (long unsigned int) callstack[i],
58 0 : status == 0 ? demangled : info.dli_sname,
59 0 : (char *) callstack[i] - (char *) info.dli_saddr);
60 0 : free(demangled);
61 : } else {
62 0 : snprintf(buf, sizeof(buf), "%-3d 0x%018lX\n",
63 0 : i, (long unsigned int) callstack[i]);
64 : }
65 0 : trace_buf << buf;
66 : }
67 0 : free(symbols);
68 : }
69 :
70 0 : msg = trace_buf.str();
71 0 : }
72 :
73 0 : ~mexception() throw() {}
74 :
75 0 : const char *what() const throw() {
76 0 : return msg.c_str();
77 : }
78 :
79 : friend std::ostream &operator<<(std::ostream &output, mexception &m) {
80 : output << m.what();
81 : return output;
82 : };
83 :
84 : mexception(const mexception &ex) noexcept : std::runtime_error(ex.msg),msg(ex.msg) {};
85 : };
86 :
87 : static_assert(std::is_nothrow_copy_constructible<mexception>::value,
88 : "mexception must be nothrow copy constructible");
89 :
90 : #endif // _MEXCEPT_HXX
|