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