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-2025 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 */
47static 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