Forward compatibility: flex
[foam-extend-3.2.git] / src / OSspecific / POSIX / printStack.C
blob7fa688239f643ed9e50130682fd991de8042ce06
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | foam-extend: Open Source CFD
4    \\    /   O peration     | Version:     3.2
5     \\  /    A nd           | Web:         http://www.foam-extend.org
6      \\/     M anipulation  | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
8 License
9     This file is part of foam-extend.
11     foam-extend is free software: you can redistribute it and/or modify it
12     under the terms of the GNU General Public License as published by the
13     Free Software Foundation, either version 3 of the License, or (at your
14     option) any later version.
16     foam-extend is distributed in the hope that it will be useful, but
17     WITHOUT ANY WARRANTY; without even the implied warranty of
18     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19     General Public License for more details.
21     You should have received a copy of the GNU General Public License
22     along with foam-extend.  If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "error.H"
27 #include "IStringStream.H"
28 #include "OStringStream.H"
29 #include "OSspecific.H"
30 #include "IFstream.H"
31 #include "readHexLabel.H"
33 #include <cxxabi.h>
34 #include <execinfo.h>
35 #include <dlfcn.h>
36 #include <string.h>
38 #ifdef darwin
39 #include <mach-o/dyld.h>
40 #endif
42 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
44 namespace Foam
47 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
49 string pOpen(const string &cmd, label line=0)
51     const int MAX = 1000;
53     FILE *cmdPipe = popen(cmd.c_str(), "r");
55     if (cmdPipe)
56     {
57         // Read line number of lines
58         for (label cnt = 0; cnt <= line; cnt++)
59         {
60             char buffer[MAX];
62             char* s = fgets(buffer, MAX-1, cmdPipe);
64             if (s == NULL)
65             {
66 #ifdef darwin
67                 // workaround for the Python-Script
68                 for(int i=0;i<MAX;i++) {
69                     if(buffer[i]=='\n') {
70                         buffer[i]='\0';
71                     }
72                 }
73                 return buffer;
74 #else
75                 return "";
76 #endif
77             }
79             if (cnt == line)
80             {
81                 string str(buffer);
82                 return str.substr(0, str.size()-1);
83             }
84         }
85         pclose(cmdPipe);
86     }
88     return "";
92 // use popen to call addr2line (using bfd.h directly would have
93 // meant relinking everything)
95 void printSourceFileAndLine
97     Ostream& os,
98     const HashTable<label, fileName>& addressMap,
99     const fileName& filename,
100     const word& address
103     word myAddress = address;
105 #ifndef darwin
106     if (filename.ext() == "so")
107 #else
108     if (filename.ext() == "dylib")
109 #endif
110     {
111         // Convert offset into .so into offset into executable.
113         void *addr;
114         sscanf(myAddress.c_str(), "%p",&addr);
116         Dl_info info;
118         dladdr(addr, &info);
120         unsigned long offset = reinterpret_cast<unsigned long>(info.dli_fbase);
122         IStringStream addressStr(address.substr(2));
123         label addressValue = readHexLabel(addressStr);
124         label relativeAddress = addressValue-offset;
126         // Reconstruct hex word from address
127         OStringStream nStream;
128         nStream << "0x" << hex << relativeAddress;
129         myAddress = nStream.str();
130     }
132 #ifndef darwin
133     if (filename[0] == '/')
134 #else
135     if (1)
136 #endif
137     {
138         string line = pOpen
139         (
140 #ifndef darwin
141             "addr2line -f --demangle=auto --exe "
142 #else
143             "addr2line4Mac.py "
144 #endif
145           + filename
146           + " "
147           + myAddress,
148             1
149         );
151         if (line == "")
152         {
153             os  << " addr2line failed";
154         }
155         else if (line == "??:0")
156         {
157             os  << " in " << filename;
158         }
159         else
160         {
161             string cwdLine(line.replaceAll(cwd() + '/', ""));
162             string homeLine(cwdLine.replaceAll(home(), '~'));
164             os  << " at " << homeLine.c_str();
165         }
166     }
170 void getSymbolForRaw
172     Ostream& os,
173     const string& raw,
174     const fileName& filename,
175     const word& address
178     if (filename.size() && filename[0] == '/')
179     {
180         string fcnt = pOpen
181         (
182 #ifndef darwin
183             "addr2line -f --demangle=auto --exe "
184 #else
185             "addr2line4Mac.py "
186 #endif
187           + filename
188           + " "
189           + address
190         );
192         if (fcnt != "")
193         {
194             os  << fcnt.c_str();
195             return;
196         }
197     }
198     os  << "Uninterpreted: " << raw.c_str();
201 void error::printStack(Ostream& os)
203     // Do not print anything if FOAM_ABORT is not set
204     if (!env("FOAM_ABORT"))
205     {
206         return;
207     }
209     // Reads the starting addresses for the dynamically linked libraries
210     // from the /proc/pid/maps-file
211     // I'm afraid this works only for Linux 2.6-Kernels (may work on 2.4)
212     // Note2: the filenames in here will have softlinks resolved so will
213     // go wrong when having e.g. FOAM installed under a softlink.
215     HashTable<label, fileName> addressMap;
216     {
217         IFstream is("/proc/" + name(pid()) + "/maps");
219         while (is.good())
220         {
221             string line;
222             is.getLine(line);
224             string::size_type space = line.rfind(' ') + 1;
225             fileName libPath = line.substr(space, line.size()-space);
227             if (libPath.size() && libPath[0] == '/')
228             {
229                 string offsetString(line.substr(0, line.find('-')));
230                 IStringStream offsetStr(offsetString);
231                 addressMap.insert(libPath, readHexLabel(offsetStr));
232             }
233         }
234     }
236     // Get raw stack symbols
237     void *array[100];
238     size_t size = backtrace(array, 100);
239     char **strings = backtrace_symbols(array, size);
241     // See if they contain function between () e.g. "(__libc_start_main+0xd0)"
242     // and see if cplus_demangle can make sense of part before +
243     // HJ, formatting of stack backtrace.  17/Dec/2008
244     os << nl;
245     for (size_t i = 0; i < size; i++)
246     {
247         string msg(strings[i]);
248         fileName programFile;
249         word address;
251         os  << '#' << label(i) << "  ";
252         //os  << "Raw   : " << msg << "\n\t";
253 #ifndef darwin
254         {
255             string::size_type lPos = msg.find('[');
256             string::size_type rPos = msg.find(']');
258             if (lPos != string::npos && rPos != string::npos && lPos < rPos)
259             {
260                 address = msg.substr(lPos+1, rPos-lPos-1);
261                 msg = msg.substr(0, lPos);
262             }
264             string::size_type bracketPos = msg.find('(');
265             string::size_type spacePos = msg.find(' ');
266             if (bracketPos != string::npos || spacePos != string::npos)
267             {
268                 programFile = msg.substr(0, min(spacePos, bracketPos));
270                 // not an absolute path
271                 if (programFile[0] != '/')
272                 {
273                     string tmp = pOpen("which " + programFile);
274                     if (tmp[0] == '/' || tmp[0] == '~')
275                     {
276                         programFile = tmp;
277                     }
278                 }
279             }
280         }
282         string::size_type bracketPos = msg.find('(');
283 #else
284         string::size_type counter=0;
285         while(msg[counter]!=' ') {
286             counter++;
287         }
288         while(msg[counter]==' ') {
289             counter++;
290         }
291         string::size_type fileStart=counter;
292         while(msg[counter]!=' ') {
293             counter++;
294         }
295         programFile = msg.substr(fileStart,counter-fileStart);
296         if(programFile=="???") {
297             char path[1024];
298             uint32_t size = sizeof(path);
299             if (_NSGetExecutablePath(path, &size) == 0) {
300                 programFile=path;
301             } else {
302                 programFile="unknownFile";
303             }
304         }
305         while(msg[counter]==' ') {
306             counter++;
307         }
308         string::size_type addrStart=counter;
309         while(msg[counter]!=' ') {
310             counter++;
311         }
312         address = msg.substr(addrStart,counter-addrStart);
313 #endif
314 #ifndef darwin
315         if (bracketPos != string::npos)
316         {
317             string::size_type start = bracketPos+1;
319             string::size_type plusPos = msg.find('+', start);
321             if (plusPos != string::npos)
322             {
323                 string cName(msg.substr(start, plusPos-start));
324 #else
325         if(1){
326             while(msg[counter]==' ') {
327                 counter++;
328             }
329             string::size_type nameStart=counter;
330             while(msg[counter]!=' ') {
331                 counter++;
332             }
334             string::size_type start = counter;
336             if(1) {
337                 string cName(msg.substr(nameStart,counter-nameStart));
338 #endif
339                 int status;
340                 char* cplusNamePtr = abi::__cxa_demangle
341                 (
342                     cName.c_str(),
343                     NULL,                   // have it malloc itself
344                     0,
345                     &status
346                 );
348                 if (status == 0 && cplusNamePtr)
349                 {
350                     os  << cplusNamePtr;
351                     free(cplusNamePtr);
352                 }
353                 else
354                 {
355                     os  << cName.c_str();
356                 }
357             }
358             else
359             {
360                 string::size_type endBracketPos = msg.find(')', start);
362                 if (endBracketPos != string::npos)
363                 {
364                     string fullName(msg.substr(start, endBracketPos-start));
366                     os  << fullName.c_str() << nl;
367                 }
368                 else
369                 {
370                     // Print raw message
371                     getSymbolForRaw(os, msg, programFile, address);
372                 }
373             }
374         }
375         else
376         {
377             // Print raw message
378             getSymbolForRaw(os, msg, programFile, address);
379         }
381         printSourceFileAndLine(os, addressMap, programFile, address);
383         os  << nl;
384     }
386     free(strings);
390 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
392 } // End namespace Foam
394 // ************************************************************************* //