PetaVision  Alpha
PVAssert.hpp
1 #ifndef _pv_assert_h
2 #define _pv_assert_h
3 
22 #include "utils/PVLog.hpp"
23 #include <cxxabi.h>
24 #include <execinfo.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 
28 #ifdef NDEBUG
29 #define pvAssert(c)
30 #define pvAssertMessage(c, fmt, ...)
31 #else
32 
38 #define pvAssert(c) \
39  if (!(c)) { \
40  PV::pv_assert_failed(__FILE__, __LINE__, #c); \
41  }
42 
45 #define pvAssertMessage(c, fmt, ...) \
46  if (!(c)) { \
47  PV::pv_assert_failed_message(__FILE__, __LINE__, #c, fmt, ##__VA_ARGS__); \
48  }
49 #endif
50 
51 namespace PV {
52 void pv_assert_failed(const char *file, int line, const char *condition);
53 void pv_assert_failed_message(
54  const char *file,
55  int line,
56  const char *condition,
57  const char *fmt,
58  ...);
59 
61 static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames = 63) {
62  StackTrace() << "stack trace:" << std::endl;
63 
64  // storage array for stack trace address data
65  void *addrlist[max_frames + 1];
66 
67  // retrieve current stack addresses
68  int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void *));
69 
70  if (addrlen == 0) {
71  StackTrace() << " <empty, possibly corrupt>" << std::endl;
72  return;
73  }
74 
75  // resolve addresses into strings containing "filename(function+address)",
76  // this array must be free()-ed
77  char **symbollist = backtrace_symbols(addrlist, addrlen);
78 
79  // allocate string which will be filled with the demangled function name
80  size_t funcnamesize = 256;
81  char *funcname = (char *)malloc(funcnamesize);
82 
83  // iterate over the returned symbol lines. skip the first, it is the
84  // address of this function.
85  for (int i = 1; i < addrlen; i++) {
86  char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
87 
88  // find parentheses and +address offset surrounding the mangled name:
89  // ./module(function+0x15c) [0x8048a6d]
90  for (char *p = symbollist[i]; *p; ++p) {
91  if (*p == '(')
92  begin_name = p;
93  else if (*p == '+')
94  begin_offset = p;
95  else if (*p == ')' && begin_offset) {
96  end_offset = p;
97  break;
98  }
99  }
100 
101  if (begin_name && begin_offset && end_offset && begin_name < begin_offset) {
102  *begin_name++ = '\0';
103  *begin_offset++ = '\0';
104  *end_offset = '\0';
105 
106  // mangled name is now in [begin_name, begin_offset) and caller
107  // offset in [begin_offset, end_offset). now apply
108  // __cxa_demangle():
109 
110  int status;
111  char *ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status);
112  if (status == 0) {
113  funcname = ret; // use possibly realloc()-ed string
114  StackTrace() << " " << symbollist[i] << " : " << funcname << "+" << begin_offset
115  << std::endl;
116  }
117  else {
118  // demangling failed. Output function name as a C function with
119  // no arguments.
120  StackTrace() << " " << symbollist[i] << " : " << begin_name << "+" << begin_offset
121  << std::endl;
122  }
123  }
124  else {
125  // couldn't parse the line? print the whole line.
126  StackTrace() << " " << symbollist[i] << std::endl;
127  }
128  }
129 
130  free(funcname);
131  free(symbollist);
132 }
133 }
134 
135 #endif