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-------------------------------------------------------------------------------
11License
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
41namespace Foam
42{
43
44// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
45
46string 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
90inline 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
102inline 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
163fileName 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
181word 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
211void 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
231void 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// ************************************************************************* //
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
Input/output from string buffers.
Output to string buffer, using a OSstream. Always UNCOMPRESSED.
Definition: StringStream.H:231
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:62
static void printStack(Ostream &os)
Helper function to print a stack.
static void safePrintStack(std::ostream &os)
A class for handling file names.
Definition: fileName.H:76
bool hasExt() const
Various checks for extensions.
Definition: stringI.H:56
A line primitive.
Definition: line.H:68
A class for handling character strings derived from std::string.
Definition: string.H:79
A class for managing temporary objects.
Definition: tmp.H:65
A class for handling words, derived from Foam::string.
Definition: word.H:68
const cellModel & hex
OBJstream os(runTime.globalPath()/outputName)
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))
Namespace for OpenFOAM.
string pOpen(const string &cmd, label line=0)
Definition: printStack.C:46
fileName cwd()
The physical or logical current working directory path name.
Definition: MSwindows.C:476
void printSourceFileAndLine(Ostream &os, const fileName &filename, Dl_info *info, void *addr)
Definition: printStack.C:111
word demangleSymbol(const char *sn)
Definition: printStack.C:181
string & shorterPath(string &s)
Definition: printStack.C:102
fileName absolutePath(const char *fn)
Definition: printStack.C:163
word addressToWord(const uintptr_t addr)
Definition: printStack.C:90
fileName home()
Return home directory path name for the current user.
Definition: MSwindows.C:457
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53