FreeFOAM The Cross-Platform CFD Toolkit
printStack.C
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*\
2  ______ _ ____ __ __
3  | ____| _| |_ / __ \ /\ | \/ |
4  | |__ _ __ ___ ___ / \| | | | / \ | \ / |
5  | __| '__/ _ \/ _ ( (| |) ) | | |/ /\ \ | |\/| |
6  | | | | | __/ __/\_ _/| |__| / ____ \| | | |
7  |_| |_| \___|\___| |_| \____/_/ \_\_| |_|
8 
9  FreeFOAM: The Cross-Platform CFD Toolkit
10 
11  Copyright (C) 2008-2012 Michael Wild <themiwi@users.sf.net>
12  Gerber van der Graaf <gerber_graaf@users.sf.net>
13 --------------------------------------------------------------------------------
14 License
15  This file is part of FreeFOAM.
16 
17  FreeFOAM is free software: you can redistribute it and/or modify it
18  under the terms of the GNU General Public License as published by
19  the Free Software Foundation, either version 3 of the License, or
20  (at your option) any later version.
21 
22  FreeFOAM is distributed in the hope that it will be useful, but WITHOUT
23  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
24  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25  for more details.
26 
27  You should have received a copy of the GNU General Public License
28  along with FreeFOAM. If not, see <http://www.gnu.org/licenses/>.
29 
30 \*----------------------------------------------------------------------------*/
31 
32 #include <OpenFOAM/error.H>
33 #include <OpenFOAM/OStringStream.H>
34 
35 #include <cxxabi.h>
36 #include <execinfo.h>
37 
38 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
39 
40 // Local helper function
41 void tokenizeSymbols( const Foam::string& symbols, Foam::string& module,
42  Foam::string& address, Foam::string& function,
43  Foam::string& offset )
44 {
45  size_t s(0), e;
46  // Mac OS X uses a different output format for backtrac_symbols.
47  // Thanks Apple, really.
48 #ifdef darwin
49  // this is for Mac OS X 10.5 Leopard and newer
50  std::string blanks(" \t");
51  // format: level module address function + offset
52  // skip the stack level
53  s = symbols.find_first_of(blanks,s);
54  // find the module name
55  s = symbols.find_first_not_of(blanks,s+1);
56  e = symbols.find_first_of(blanks,s+1);
57  module = symbols.substr(s,e-s);
58  // find the address
59  s = symbols.find_first_not_of(blanks,e+1);
60  e = symbols.find_first_of(blanks,s+1);
61  address = symbols.substr(s,e-s);
62  // find the (mangled) function name
63  s = symbols.find_first_not_of(blanks,e+1);
64  e = symbols.find_first_of(blanks,s+1);
65  function = symbols.substr(s,e-s);
66  // skip the + sign
67  s = symbols.find_first_not_of(blanks,e+1);
68  e = symbols.find_first_of(blanks,s+1);
69  // find the offset into the function
70  s = symbols.find_first_not_of(blanks,e+1);
71  e = symbols.find_first_of(blanks,s+1);
72  offset = symbols.substr(s,e-s);
73 #else
74  // this is for GNU glibc (assumed)
75  // format: module(function+offset) [address]
76  // find the module name
77  e = symbols.find('(',s);
78  module = symbols.substr(s,e-s);
79  // find the (mangled) function name
80  s = e;
81  e = symbols.find('+',s+1);
82  function = symbols.substr(s+1,e-s-1);
83  // find the offset
84  s = e;
85  e = symbols.find(')',s+1);
86  offset = symbols.substr(s+1,e-s-1);
87  // find the address
88  s = symbols.find('[',s+1);
89  e = symbols.find(']',s+2);
90  address = symbols.substr(s+1,e-s-1);
91 #endif
92 }
93 
94 
96 {
97  os << " Stack trace:\n";
98 
99  // storage array for stack trace address data
100  const size_t max_frames = 100;
101  void* addrlist[max_frames];
102 
103  // retrieve current stack addresses
104  int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));
105 
106  if (addrlen == 0) {
107  os << "* <EMPTY BACKTRACE, POSSIBLY CORRUPT STACK.> *\n";
108  } else {
109  // resolve addresses into strings containing "filename(function+address)",
110  // this array must be free()-ed
111  char** symbollist = backtrace_symbols(addrlist, addrlen);
112 
113  // allocate string which will be filled with the demangled function name
114  size_t funcnamesize = 256;
115  char* funcname = new char[funcnamesize];
116 
117  // iterate over the returned symbol lines. skip the first two, it is the
118  // address of this function and the sigSegvImpl::sigSegvHandler function.
119  for (size_t i = 2; i < addrlen; i++)
120  {
121  // tokenize the symbols string
122  string module, function, address, offset;
123  tokenizeSymbols( symbollist[i], module, address, function, offset );
124 
125  if (! (module.empty() || address.empty() || function.empty() || offset.empty()) )
126  {
127  // try to demangle
128  int status;
129  char* ret = abi::__cxa_demangle(function.c_str(), NULL, 0, &status);
130  if (status == 0) {
131  function.assign( ret );
132  free( ret );
133  os << " " << int(i-2) << " " << module.c_str() << " [" << address.c_str() << "]: "
134  << function.c_str() << " + " << offset.c_str() << "\n";
135  }
136  else {
137  // demangling failed. Output function name as a C function with
138  // no arguments.
139  os << " " << int(i-2) << " " << module.c_str() << " [" << address.c_str() << "]: "
140  << function.c_str() << " + " << offset.c_str() << "\n";
141  }
142  }
143  else
144  {
145  // couldn't parse the line? print the whole line.
146  os << " " << int(i-2) << " " << symbollist[i] << "\n";
147  }
148  }
149 
150  delete[] funcname;
151  free(symbollist);
152  }
153 }
154 
155 // ************************ vim: set sw=4 sts=4 et: ************************ //