stacktrace.h
Go to the documentation of this file.
1 //LIC// ====================================================================
2 //LIC// This file forms part of oomph-lib, the object-oriented,
3 //LIC// multi-physics finite-element library, available
4 //LIC// at http://www.oomph-lib.org.
5 //LIC//
6 //LIC// Version 1.0; svn revision $LastChangedRevision: 1097 $
7 //LIC//
8 //LIC// $LastChangedDate: 2015-12-17 11:53:17 +0000 (Thu, 17 Dec 2015) $
9 //LIC//
10 //LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
11 //LIC//
12 //LIC// This library is free software; you can redistribute it and/or
13 //LIC// modify it under the terms of the GNU Lesser General Public
14 //LIC// License as published by the Free Software Foundation; either
15 //LIC// version 2.1 of the License, or (at your option) any later version.
16 //LIC//
17 //LIC// This library is distributed in the hope that it will be useful,
18 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 //LIC// Lesser General Public License for more details.
21 //LIC//
22 //LIC// You should have received a copy of the GNU Lesser General Public
23 //LIC// License along with this library; if not, write to the Free Software
24 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 //LIC// 02110-1301 USA.
26 //LIC//
27 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
28 //LIC//
29 //LIC//====================================================================
30 //====================================================================
31 // stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/
32 // published under the WTFPL v2.0
33 
34 // Modified by MH to take proper C++ output stream and to produce
35 // code for retrieval of line numbers. Also obtains name of
36 // executable from oomph-lib CommandLineArgs namespace (if it's been
37 // set up)
38 //====================================================================
39 #ifndef _STACKTRACE_H_
40 #define _STACKTRACE_H_
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <execinfo.h>
45 #include <cxxabi.h>
46 
47 // Include oomph-utilities to be able to obtain name of executable
48 #include "oomph_utilities.h"
49 
50 /** Print a demangled stack backtrace of the caller function */
51 static inline void print_stacktrace(std::ostream &exception_stream,
52  unsigned int max_frames = 63)
53 {
54 
55  exception_stream << "\nStack trace:\n";
56  exception_stream << "------------\n";
57 
58  // storage array for stack trace address data
59  void* addrlist[max_frames+1];
60 
61  // retrieve current stack addresses
62  int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));
63 
64  if (addrlen == 0)
65  {
66  exception_stream << "\n<empty stack trace, possibly corrupt>\n";
67  return;
68  }
69 
70  // resolve addresses into strings containing "filename(function+address)",
71  // this array must be free()-ed
72  char** symbollist = backtrace_symbols(addrlist, addrlen);
73 
74  // allocate string which will be filled with the demangled function name
75  size_t funcnamesize = 256;
76  char* funcname = (char*)malloc(funcnamesize);
77 
78 // Stream to collect information that allows retrieval of line numbers
79  std::stringstream address_stream;
80 
81  // iterate over the returned symbol lines. skip the first, it is the
82  // address of this function.
83  for (int i = 1; i < addrlen; i++)
84  {
85 
86  // ------------- begin mh addition ---------------
87  char* begin_absolute=0, *end_absolute=0;
88 
89  // find absolute address (in square brackets)
90  // ./module(function+0x15c) [0x8048a6d]
91  for (char *p = symbollist[i]; *p; ++p)
92  {
93  if (*p == '[')
94  begin_absolute = p;
95  else if (*p == ']' && begin_absolute) {
96  end_absolute = p;
97  break;
98  }
99  }
100 
101  if (begin_absolute)
102  {
103  *begin_absolute++ = '\0';
104  *end_absolute = '\0';
106  {
107  address_stream << "addr2line -e "
108  << oomph::CommandLineArgs::Argv[0] << " "
109  << begin_absolute << "\n";
110  }
111  else
112  {
113  address_stream << "addr2line -e [name_of_executable] "
114  << begin_absolute << "\n";
115  }
116  }
117 
118  // ------------- end mh addition ---------------
119 
120  char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
121 
122  // find parentheses and +address offset surrounding the mangled name:
123  // ./module(function+0x15c) [0x8048a6d]
124  for (char *p = symbollist[i]; *p; ++p)
125  {
126  if (*p == '(')
127  begin_name = p;
128  else if (*p == '+')
129  begin_offset = p;
130  else if (*p == ')' && begin_offset) {
131  end_offset = p;
132  break;
133  }
134  }
135 
136  if (begin_name && begin_offset && end_offset
137  && begin_name < begin_offset)
138  {
139  *begin_name++ = '\0';
140  *begin_offset++ = '\0';
141  *end_offset = '\0';
142 
143  // mangled name is now in [begin_name, begin_offset) and caller
144  // offset in [begin_offset, end_offset). now apply
145  // __cxa_demangle():
146 
147  int status;
148  char* ret = abi::__cxa_demangle(begin_name,
149  funcname, &funcnamesize, &status);
150  if (status == 0) {
151  funcname = ret; // use possibly realloc()-ed string
152  /* fprintf(out, " %s : %s+%s\n", */
153  /* symbollist[i], funcname, begin_offset); */
154  exception_stream << symbollist[i] << " : " << funcname << "+"
155  << begin_offset << std::endl;
156 
157  }
158  else {
159  // demangling failed. Output function name as a C function with
160  // no arguments.
161  /* fprintf(out, " %s : %s()+%s\n", */
162  /* symbollist[i], begin_name, begin_offset); */
163 
164  exception_stream << symbollist[i] << " : " << begin_name << "+"
165  << begin_offset << std::endl;
166  }
167  }
168  else
169  {
170  // couldn't parse the line? print the whole line.
171  //fprintf(out, " %s\n", symbollist[i]);
172  exception_stream << symbollist[i]<< std::endl;
173 
174  }
175 
176  }
177 
178  exception_stream
179  << "\nHere are the commmands to obtain the line numbers:\n";
180 
181  exception_stream
182  << "--------------------------------------------------\n";
183  exception_stream << address_stream.str() << std::endl;
184 
185 
187  {
188  exception_stream << "\nNOTE: Replace [name_of_executable] by the actual\n"
189  << " name of the executable. I would have inserted\n"
190  << " this for you if you had called \n\n"
191  << " CommandLineArgs::setup(argc,argv);\n\n"
192  << " in your driver code...\n\n";
193  }
194 
195  free(funcname);
196  free(symbollist);
197 }
198 
199 #endif // _STACKTRACE_H_
char ** Argv
Arguments themselves.
cstr elem_len * i
Definition: cfortran.h:607
static void print_stacktrace(std::ostream &exception_stream, unsigned int max_frames=63)
Definition: stacktrace.h:51
int Argc
Number of arguments + 1.