printStack.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "error.H"
27 #include "OStringStream.H"
28 #include "OSspecific.H"
29 #include "IFstream.H"
30 
31 #include <inttypes.h>
32 #include <cxxabi.h>
33 #include <execinfo.h>
34 #include <dlfcn.h>
35 
36 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
37 
38 namespace Foam
39 {
40 
41 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
42 
43 string pOpen(const string &cmd, label line=0)
44 {
45  string res = "\n";
46 
47  FILE *cmdPipe = popen(cmd.c_str(), "r");
48 
49  if (cmdPipe)
50  {
51  char *buf = nullptr;
52 
53  // Read line number of lines
54  for (label cnt = 0; cnt <= line; cnt++)
55  {
56  size_t linecap = 0;
57  ssize_t linelen;
58  linelen = getline(&buf, &linecap, cmdPipe);
59 
60  if (linelen < 0)
61  {
62  break;
63  }
64 
65  if (cnt == line)
66  {
67  res = string(buf);
68  break;
69  }
70  }
71 
72  if (buf != nullptr)
73  {
74  free(buf);
75  }
76 
77  pclose(cmdPipe);
78  }
79 
80  return res.substr(0, res.size() - 1);
81 }
82 
83 
84 inline word addressToWord(const uintptr_t addr)
85 {
86  OStringStream nStream;
87  nStream << "0x" << hex << addr;
88  return nStream.str();
89 }
90 
91 
93 (
94  Ostream& os,
95  const fileName& filename,
96  Dl_info *info,
97  void *addr
98 )
99 {
100  uintptr_t address = uintptr_t(addr);
101  word myAddress = addressToWord(address);
102 
103  if (filename.ext() == "so")
104  {
105  // Convert address into offset into dynamic library
106  uintptr_t offset = uintptr_t(info->dli_fbase);
107  intptr_t relativeAddress = address - offset;
108  myAddress = addressToWord(relativeAddress);
109  }
110 
111  if (filename[0] == '/')
112  {
113  string line = pOpen
114  (
115  "addr2line -f --demangle=auto --exe "
116  + filename
117  + " "
118  + myAddress,
119  1
120  );
121 
122  if (line == "")
123  {
124  os << " addr2line failed";
125  }
126  else if (line == "??:0")
127  {
128  os << " in " << filename;
129  }
130  else
131  {
132  string cwdLine(line.replaceAll(cwd() + '/', ""));
133  string homeLine(cwdLine.replaceAll(home(), '~'));
134 
135  os << " at " << homeLine.c_str();
136  }
137  }
138 }
139 
140 
141 fileName absolutePath(const char* fn)
142 {
143  fileName fname(fn);
144 
145  if (fname[0] != '/' && fname[0] != '~')
146  {
147  string tmp = pOpen("which " + fname);
148 
149  if (tmp[0] == '/' || tmp[0] == '~')
150  {
151  fname = tmp;
152  }
153  }
154 
155  return fname;
156 }
157 
158 
159 word demangleSymbol(const char* sn)
160 {
161  word res;
162  int st;
163  char* cxx_sname = abi::__cxa_demangle
164  (
165  sn,
166  nullptr,
167  0,
168  &st
169  );
170 
171  if (st == 0 && cxx_sname)
172  {
173  res = word(cxx_sname);
174  free(cxx_sname);
175  }
176  else
177  {
178  res = word(sn);
179  }
180 
181  return res;
182 }
183 
184 
185 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
186 
187 } // End namespace Foam
188 
189 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
190 
191 
192 void Foam::error::safePrintStack(std::ostream& os)
193 {
194  // Get raw stack symbols
195  void *array[100];
196  size_t size = backtrace(array, 100);
197  char **strings = backtrace_symbols(array, size);
198 
199  // See if they contain function between () e.g. "(__libc_start_main+0xd0)"
200  // and see if cplus_demangle can make sense of part before +
201  for (size_t i = 0; i < size; i++)
202  {
203  string msg(strings[i]);
204  fileName programFile;
205  word address;
206 
207  os << '#' << label(i) << '\t' << msg << std::endl;
208  }
209 }
210 
211 
213 {
214  // Get raw stack symbols
215  const size_t CALLSTACK_SIZE = 128;
216 
217  void *callstack[CALLSTACK_SIZE];
218  size_t size = backtrace(callstack, CALLSTACK_SIZE);
219 
220  Dl_info *info = new Dl_info;
221 
222  fileName fname = "???";
223  word address;
224 
225  for(size_t i=0; i<size; i++)
226  {
227  int st = dladdr(callstack[i], info);
228 
229  os << '#' << label(i) << " ";
230  if (st != 0 && info->dli_fname != nullptr && info->dli_fname[0] != '\0')
231  {
232  fname = absolutePath(info->dli_fname);
233 
234  os <<
235  (
236  (info->dli_sname != nullptr)
237  ? demangleSymbol(info->dli_sname)
238  : "?"
239  );
240  }
241  else
242  {
243  os << "?";
244  }
245 
246  printSourceFileAndLine(os, fname, info, callstack[i]);
247  os << nl;
248  }
249 
250  delete info;
251 }
252 
253 
254 // ************************************************************************* //
static void printStack(Ostream &)
Helper function to print a stack.
string & replaceAll(const string &oldStr, const string &newStr, size_type start=0)
Replace all occurrences of sub-string oldStr with newStr.
Definition: string.C:82
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
A line primitive.
Definition: line.H:56
A class for handling file names.
Definition: fileName.H:79
IOstream & hex(IOstream &io)
Definition: IOstream.H:561
static void safePrintStack(std::ostream &)
Helper function to print a stack (if OpenFOAM IO not yet.
Definition: printStack.C:192
string pOpen(const string &cmd, label line=0)
Definition: printStack.C:43
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
fileName home()
Return home directory path name for the current user.
Definition: POSIX.C:186
word ext() const
Return file name extension (part after last .)
Definition: fileName.C:299
fileName absolutePath(const char *fn)
Definition: printStack.C:141
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
void printSourceFileAndLine(Ostream &os, const fileName &filename, Dl_info *info, void *addr)
Definition: printStack.C:93
A class for handling words, derived from string.
Definition: word.H:59
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:54
static const char nl
Definition: Ostream.H:260
string str() const
Return the string.
fileName cwd()
Return current working directory path name.
Definition: POSIX.C:241
word addressToWord(const uintptr_t addr)
Definition: printStack.C:84
A class for managing temporary objects.
Definition: PtrList.H:53
word demangleSymbol(const char *sn)
Definition: printStack.C:159
A class for handling character strings derived from std::string.
Definition: string.H:76
Output to memory buffer stream.
Definition: OStringStream.H:49
Namespace for OpenFOAM.