Loading...
Searching...
No Matches
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-2025 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
32#include <cinttypes>
33#include <sstream>
34#include <cxxabi.h>
35#include <dlfcn.h>
36#include <execinfo.h>
37
38// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
39
40namespace
41{
42
43// Read up to and including lineNum from the piped command
44// Return the final line read
45std::string pipeOpen(const std::string& cmd, const int lineNum = 0)
46{
47 std::string str;
48
49 FILE *handle = popen(cmd.c_str(), "r");
50 if (!handle) return str;
51
52 char* buf = nullptr;
53 size_t len = 0;
54 ssize_t nread;
55
56 // Read lineNum number of lines
57 for
58 (
59 int cnt = 0;
60 cnt <= lineNum && (nread = ::getline(&buf, &len, handle)) >= 0;
61 ++cnt
62 )
63 {
64 if (cnt == lineNum)
65 {
66 // Retain the last line, trimming trailing newline
67 if (nread > 0)
68 {
69 buf[nread-1] = '\0';
70 }
71 str.assign(buf);
72 }
73 }
74
75 free(buf);
76 pclose(handle);
77
78 return str;
79}
80
81
82inline std::string addressToWord(const uintptr_t addr)
83{
84 std::ostringstream buf;
85 buf.setf(std::ios_base::hex, std::ios_base::basefield);
86
87 buf << "0x"; // Same as setf(std::ios::showbase)
88
89 #ifdef __APPLE__
90 buf << uint64_t(addr);
91 #else
92 buf << addr;
93 #endif
94
95 return buf.str(); // Needs no stripping
96}
97
98
99// Note: demangle requires symbols only - without extra '(' etc.
100inline std::string demangleSymbol(const char* sn)
101{
102 int st = 0;
103
104 char* cxx_sname = abi::__cxa_demangle(sn, nullptr, nullptr, &st);
105
106 if (st == 0 && cxx_sname)
107 {
108 std::string demangled(cxx_sname);
109 free(cxx_sname);
110
111 return demangled;
112 }
113
114 return sn;
115}
116
117
118inline Foam::string& shorterPath(Foam::string& s)
119{
120 s.replace(Foam::cwd() + '/', "");
121 s.replace(Foam::home(), "~");
122 return s;
123}
124
125
126void printSourceFileAndLine
127(
129 const Foam::fileName& filename,
130 const Dl_info& info,
131 void *addr
132)
133{
134 uintptr_t address = uintptr_t(addr);
135 std::string myAddress = addressToWord(address);
136
137 // Can use relative addresses for executables and libraries with the
138 // Darwin addr2line implementation.
139 // On other systems (Linux), only use relative addresses for libraries.
140
141 #ifndef __APPLE__
142 if (filename.has_ext("so"))
143 #endif
144 {
145 // Convert address into offset into dynamic library
146 uintptr_t offset = uintptr_t(info.dli_fbase);
147 intptr_t relativeAddress = address - offset;
148 myAddress = addressToWord(relativeAddress);
149 }
150
151 if (filename[0] == '/')
152 {
153 Foam::string line = pipeOpen
154 (
155 "addr2line -f --demangle=auto --exe "
156 + filename
157 + " "
158 + myAddress,
159 1
160 );
161
162 if (line.empty())
163 {
164 os << " addr2line failed";
165 }
166 else if (line == "??:0" || line == "??:?" )
167 {
168 line = filename;
169 os << " in " << shorterPath(line).c_str();
170 }
171 else
172 {
173 os << " at " << shorterPath(line).c_str();
174 }
175 }
176}
177
178
179// Uses 'which' to find executable on PATH
180// - could also iterate through PATH directly
181inline Foam::fileName whichPath(const char* fn)
182{
183 Foam::fileName fname(fn);
184
185 if (!fname.empty() && fname[0] != '/' && fname[0] != '~')
186 {
187 std::string s = pipeOpen("which " + fname);
188
189 if (s[0] == '/' || s[0] == '~')
190 {
191 fname = s;
192 }
193 }
194
195 return fname;
196}
197
198} // End anonymous namespace
199
200
201// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
202
203void Foam::error::safePrintStack(std::ostream& os, int size)
204{
205 // Get raw stack symbols
206 void *callstack[100];
207 size = backtrace(callstack, (size > 0 && size < 100) ? size + 1 : 100);
208
209 char **strings = backtrace_symbols(callstack, size);
210 size_t rdelim;
211
212 // Frame 0 is 'printStack()' - report something more meaningful
213 os << "[stack trace]" << std::endl
214 << "=============" << std::endl;
215
216 for (int i = 1; i < size; ++i)
217 {
218 std::string str(strings[i]);
219
220 os << '#' << i << '\t';
221
222 // Possibly shorten paths that appear to correspond to OpenFOAM
223 // locations (platforms).
224 //
225 // Eg, "/path/openfoam/platforms/linux64GccDPInt32Opt/lib/libxyz.so"
226 // --> "platforms/linux64GccDPInt32Opt/lib/libxyz.so"
227
228 auto ldelim = str.find('(');
229 auto beg = str.find("/platforms/");
230
231 if (beg == std::string::npos || !beg || beg > ldelim)
232 {
233 beg = 0;
234 }
235 else
236 {
237 ++beg;
238 }
239
240 if
241 (
242 (ldelim != std::string::npos)
243 && (rdelim = str.find('+', ldelim+1)) != std::string::npos
244 && (rdelim > ldelim+1)
245 )
246 {
247 // Found function between () e.g. "(__libc_start_main+0xd0)"
248 // - demangle function name (before the '+' offset)
249 // - preserve trailing [0xAddr]
250
251 os << str.substr(beg, ldelim-beg)
252 << ' '
253 << demangleSymbol
254 (
255 str.substr(ldelim+1, rdelim-ldelim-1).c_str()
256 );
257
258 if ((rdelim = str.find('[', rdelim)) != std::string::npos)
259 {
260 os << ' ' << str.substr(rdelim);
261 }
262 }
263 else if (beg)
264 {
265 // With shortened path name
266 os << str.substr(beg);
267 }
268 else
269 {
270 // No modification to string
271 os << str;
272 }
273 os << std::endl;
274 }
275
276 os << "=============" << std::endl;
277
278 free(strings);
279}
280
281
282void Foam::error::printStack(Ostream& os, int size)
283{
284 // Get raw stack symbols
285 void *callstack[100];
286 size = backtrace(callstack, (size > 0 && size < 100) ? size + 1 : 100);
287
288 Dl_info info;
289 fileName fname;
290
291 // Frame 0 is 'printStack()' - report something more meaningful
292 os << "[stack trace]" << nl
293 << "=============" << nl;
294
295 for (int i = 1; i < size; ++i)
296 {
297 int st = dladdr(callstack[i], &info);
298
299 os << '#' << i << " ";
300 if (st != 0 && info.dli_fname != nullptr && *(info.dli_fname))
301 {
302 fname = whichPath(info.dli_fname);
303
304 if (info.dli_sname)
305 {
306 os << demangleSymbol(info.dli_sname).c_str();
307 }
308 else
309 {
310 os << '?';
311 }
312 }
313 else
314 {
315 fname = "???";
316 os << '?';
317 }
318
319 printSourceFileAndLine(os, fname, info, callstack[i]);
320 os << nl;
321 }
322
323 os << "=============" << nl;
324}
325
326
327// ************************************************************************* //
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition Ostream.H:59
static void safePrintStack(std::ostream &os, int size=-1)
Helper function to print a stack, with optional upper limit. Used when OpenFOAM IO not yet initialise...
static void printStack(Ostream &os, int size=-1)
Helper function to print a stack, with optional upper limit.
A class for handling file names.
Definition fileName.H:75
bool has_ext() const
Various checks for extensions.
Definition stringI.H:43
A class for handling character strings derived from std::string.
Definition string.H:76
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))
fileName cwd()
The physical or logical current working directory path name.
Definition POSIX.C:592
fileName home()
Return home directory path name for the current user.
Definition POSIX.C:442
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50