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