correction to d4edb38234db8268907f04836d49bb93461b8a88
[OpenFOAM-1.5.x.git] / src / OSspecific / Unix / printStack.C
blob33a7fb5394a0e627eabdd13342a19ed9b9556b1b
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
6      \\/     M anipulation  |
7 -------------------------------------------------------------------------------
8 License
9     This file is part of OpenFOAM.
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 the
13     Free Software Foundation; either version 2 of the License, or (at your
14     option) any later version.
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.
21     You should have received a copy of the GNU General Public License
22     along with OpenFOAM; if not, write to the Free Software Foundation,
23     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "error.H"
28 #include "IStringStream.H"
29 #include "OStringStream.H"
30 #include "OSspecific.H"
31 #include "IFstream.H"
32 #include "readHexLabel.H"
34 #include <cxxabi.h>
35 #include <execinfo.h>
36 #include <dlfcn.h>
38 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
40 namespace Foam
43 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
45 string pOpen(const string &cmd, label line=0)
47     const int MAX = 1000;
49     FILE *cmdPipe = popen(cmd.c_str(), "r");
51     if (cmdPipe)
52     {
53         // Read line number of lines
54         for (label cnt = 0; cnt <= line; cnt++)
55         {
56             char buffer[MAX];
57             char* s = fgets(buffer, MAX-1, cmdPipe);
59             if (s == NULL)
60             {
61                 return "";
62             }
64             if (cnt == line)
65             {
66                 string str(buffer);
67                 return str.substr(0, str.size()-1);
68             }
69         }
70         pclose(cmdPipe);
71     }
73     return "";
77 // use popen to call addr2line (using bfd.h directly would have
78 // meant relinking everything)
80 void printSourceFileAndLine
82     Ostream& os,
83     const HashTable<label, fileName>& addressMap,
84     const fileName& filename,
85     const word& address
88     word myAddress = address;
90     if (filename.ext() == "so")
91     {
92         // Convert offset into .so into offset into executable.
94         void *addr;
95         sscanf(myAddress.c_str(), "%p",&addr);
97         Dl_info info;
99         dladdr(addr, &info);
101         unsigned long offset = ulong(info.dli_fbase);
103         IStringStream addressStr(address.substr(2));
104         label addressValue = readHexLabel(addressStr);
105         label relativeAddress = addressValue-offset;
107         // Reconstruct hex word from address
108         OStringStream nStream;
109         nStream << "0x" << hex << relativeAddress;
110         myAddress = nStream.str();
111     }
113     if (filename[0] == '/')
114     {
115         string line = pOpen
116         (
117             "addr2line -f --demangle=auto --exe "
118           + filename
119           + " "
120           + myAddress,
121             1
122         );
124         if (line == "")
125         {
126             os << " addr2line failed";
127         }
128         else if (line == "??:0")
129         {
130             os << " in " << filename;
131         }
132         else
133         {
134             string cwdLine(line.replaceAll(cwd() + '/', ""));
136             string homeLine(cwdLine.replaceAll(home(), '~'));
138             os << " at " << homeLine.c_str();
139         }
140     }
144 void getSymbolForRaw
146     Ostream& os,
147     const string& raw,
148     const fileName& filename,
149     const word& address
152     if (filename.size() > 0 && filename[0] == '/')
153     {
154         string fcnt = pOpen
155         (
156             "addr2line -f --demangle=auto --exe "
157           + filename
158           + " "
159           + address
160         );
162         if (fcnt != "")
163         {
164             os << fcnt.c_str();
165             return;
166         }
167     }
168     os << "Uninterpreted: " << raw.c_str();
172 void error::printStack(Ostream& os)
174     // Reads the starting addresses for the dynamically linked libraries
175     // from the /proc/pid/maps-file
176     // I'm afraid this works only for Linux 2.6-Kernels (may work on 2.4)
177     // Note2: the filenames in here will have softlinks resolved so will
178     // go wrong when having e.g. OpenFOAM installed under a softlink.
180     HashTable<label, fileName> addressMap;
181     {
182         IFstream is("/proc/" + name(pid()) + "/maps");
184         while(is.good())
185         {
186             string line;
187             is.getLine(line);
189             string::size_type space = line.rfind(' ') + 1;
190             fileName libPath = line.substr(space, line.size()-space);
192             if (libPath.size() > 0 && libPath[0] == '/')
193             {
194                 string offsetString(line.substr(0, line.find('-')));
195                 IStringStream offsetStr(offsetString);
196                 addressMap.insert(libPath, readHexLabel(offsetStr));
197             }
198         }
199     }
201     // Get raw stack symbols
202     void *array[100];
203     size_t size = backtrace(array, 100);
204     char **strings = backtrace_symbols(array, size);
206     // See if they contain function between () e.g. "(__libc_start_main+0xd0)"
207     // and see if cplus_demangle can make sense of part before +
208     for (size_t i = 0; i < size; i++)
209     {
210         string msg(strings[i]);
211         fileName programFile;
212         word address;
214         os << '#' << label(i) << "  ";
215         //os << "Raw   : " << msg << "\n\t";
216         {
217             string::size_type lPos = msg.find('[');
218             string::size_type rPos = msg.find(']');
220             if (lPos != string::npos && rPos != string::npos && lPos<rPos)
221             {
222                 address = msg.substr(lPos+1, rPos-lPos-1);
223                 msg = msg.substr(0, lPos);
224             }
226             string::size_type bracketPos = msg.find('(');
227             string::size_type spacePos = msg.find(' ');
228             if (bracketPos != string::npos || spacePos != string::npos)
229             {
230                 programFile = msg.substr(0, min(spacePos, bracketPos));
232                 // not an absolute path
233                 if (programFile[0] != '/')
234                 {
235                     string tmp = pOpen("which "+programFile);
236                     if (tmp[0] == '/' || tmp[0] == '~')
237                     {
238                         programFile = tmp;
239                     }
240                 }
241             }
242         }
244         string::size_type bracketPos = msg.find('(');
246         if (bracketPos != string::size_type(string::npos))
247         {
248             string::size_type start = bracketPos+1;
250             string::size_type plusPos = msg.find('+', start);
252             if (plusPos != string::size_type(string::npos))
253             {
254                 string cName(msg.substr(start, plusPos-start));
256                 int status;
257                 char* cplusNamePtr = abi::__cxa_demangle
258                 (
259                     cName.c_str(),
260                     NULL,                   // have it malloc itself
261                     0,
262                     &status
263                 );
265                 if (status == 0 && cplusNamePtr)
266                 {
267                     os << cplusNamePtr;
268                     free(cplusNamePtr);
269                 }
270                 else
271                 {
272                     os << cName.c_str();
273                 }
274             }
275             else
276             {
277                 string::size_type endBracketPos = msg.find(')', start);
279                 if (endBracketPos != string::size_type(string::npos))
280                 {
281                     string fullName(msg.substr(start, endBracketPos-start));
283                     os << fullName.c_str() << nl;
284                 }
285                 else
286                 {
287                     // Print raw message
288                     getSymbolForRaw(os, msg, programFile, address);
289                 }
290             }
291         }
292         else
293         {
294             // Print raw message
295             getSymbolForRaw(os, msg, programFile, address);
296         }
298         printSourceFileAndLine(os, addressMap, programFile, address);
300         os << nl;
301     }
303     free(strings);
307 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
309 } // End namespace Foam
311 // ************************************************************************* //