1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
7 -------------------------------------------------------------------------------
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
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 \*---------------------------------------------------------------------------*/
28 #include "IStringStream.H"
29 #include "OStringStream.H"
30 #include "OSspecific.H"
32 #include "readHexLabel.H"
40 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
45 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
47 string pOpen(const string &cmd, label line=0)
51 FILE *cmdPipe = popen(cmd.c_str(), "r");
55 // Read line number of lines
56 for (label cnt = 0; cnt <= line; cnt++)
60 char* s = fgets(buffer, MAX-1, cmdPipe);
65 // workaround for the Python-Script
66 for(int i=0;i<MAX;i++) {
80 return str.substr(0, str.size()-1);
90 // use popen to call addr2line (using bfd.h directly would have
91 // meant relinking everything)
93 void printSourceFileAndLine
96 const HashTable<label, fileName>& addressMap,
97 const fileName& filename,
101 word myAddress = address;
104 if (filename.ext() == "so")
106 if (filename.ext() == "dylib")
109 // Convert offset into .so into offset into executable.
112 sscanf(myAddress.c_str(), "%p",&addr);
118 unsigned long offset = reinterpret_cast<unsigned long>(info.dli_fbase);
120 IStringStream addressStr(address.substr(2));
121 label addressValue = readHexLabel(addressStr);
122 label relativeAddress = addressValue-offset;
124 // Reconstruct hex word from address
125 OStringStream nStream;
126 nStream << "0x" << hex << relativeAddress;
127 myAddress = nStream.str();
130 if (filename[0] == '/')
135 "addr2line -f --demangle=auto --exe "
137 // "gaddr2line -f --inline --demangle=auto --exe "
148 os << " addr2line failed";
150 else if (line == "??:0")
152 os << " in " << filename;
156 string cwdLine(line.replaceAll(cwd() + '/', ""));
158 string homeLine(cwdLine.replaceAll(home(), '~'));
160 os << " at " << homeLine.c_str();
167 // Trying to emulate the original backtrace and backtrace_symbol from the glibc
168 // After an idea published by Rush Manbert at http://lists.apple.com/archives/xcode-users/2006/Apr/msg00528.html
171 void *getStackAddress()
173 const unsigned int stackLevel=level;
175 __builtin_frame_address(level)
176 ? __builtin_return_address(stackLevel)
181 #define GET_STACK_ADDRESS(lvl) \
182 case lvl: {return getStackAddress<lvl>(); break; }
184 // please don't laugh. For some reason this is necessary (the compiler won't accept it otherwise)
185 void *getStackAddress(int level)
188 GET_STACK_ADDRESS(0);
189 GET_STACK_ADDRESS(1);
190 GET_STACK_ADDRESS(2);
191 GET_STACK_ADDRESS(3);
192 GET_STACK_ADDRESS(4);
193 GET_STACK_ADDRESS(5);
194 GET_STACK_ADDRESS(6);
195 GET_STACK_ADDRESS(7);
196 GET_STACK_ADDRESS(8);
197 GET_STACK_ADDRESS(9);
198 GET_STACK_ADDRESS(10);
199 GET_STACK_ADDRESS(11);
200 GET_STACK_ADDRESS(12);
201 GET_STACK_ADDRESS(13);
202 GET_STACK_ADDRESS(14);
203 GET_STACK_ADDRESS(15);
204 GET_STACK_ADDRESS(16);
205 GET_STACK_ADDRESS(17);
206 GET_STACK_ADDRESS(18);
207 GET_STACK_ADDRESS(19);
208 GET_STACK_ADDRESS(20);
209 GET_STACK_ADDRESS(21);
216 unsigned backtrace(void **bt, unsigned maxAddrs)
221 for(int level=0;level<maxAddrs;level++) {
223 bt[level]=getStackAddress(level);
225 if(bt[level]!=(void *)0) {
238 // This function is a potential memory leak. But I don't care because the program is terminating anyway
239 char **backtrace_symbols(void **bt,unsigned nr)
241 char **strings=(char **)malloc(sizeof(char *)*nr);
243 for(unsigned i=0;i<nr;i++) {
245 int result=dladdr(bt[i],&info);
249 sprintf(tmp,"%s(%s+%p) [%p]",info.dli_fname,info.dli_sname,(void *)((unsigned long)bt[i]-(unsigned long)info.dli_saddr),bt[i]);
251 sprintf(tmp,"%s(%s+%p) [%p]",info.dli_fname,info.dli_sname,(void *)((unsigned int)bt[i]-(unsigned int)info.dli_saddr),bt[i]);
253 strings[i]=(char *)malloc(strlen(tmp)+1);
254 strcpy(strings[i],tmp);
266 const fileName& filename,
270 if (filename.size() && filename[0] == '/')
275 "addr2line -f --demangle=auto --exe "
277 // "gaddr2line -f --inline --demangle=auto --exe "
291 os << "Uninterpreted: " << raw.c_str();
294 void error::printStack(Ostream& os)
296 // Do not print anything if FOAM_ABORT is not set
297 if (!env("FOAM_ABORT"))
302 // Reads the starting addresses for the dynamically linked libraries
303 // from the /proc/pid/maps-file
304 // I'm afraid this works only for Linux 2.6-Kernels (may work on 2.4)
305 // Note2: the filenames in here will have softlinks resolved so will
306 // go wrong when having e.g. OpenFOAM installed under a softlink.
308 HashTable<label, fileName> addressMap;
310 IFstream is("/proc/" + name(pid()) + "/maps");
317 string::size_type space = line.rfind(' ') + 1;
318 fileName libPath = line.substr(space, line.size()-space);
320 if (libPath.size() && libPath[0] == '/')
322 string offsetString(line.substr(0, line.find('-')));
323 IStringStream offsetStr(offsetString);
324 addressMap.insert(libPath, readHexLabel(offsetStr));
329 // Get raw stack symbols
331 size_t size = backtrace(array, 100);
332 char **strings = backtrace_symbols(array, size);
334 // See if they contain function between () e.g. "(__libc_start_main+0xd0)"
335 // and see if cplus_demangle can make sense of part before +
336 // HJ, formatting of stack backtrace. 17/Dec/2008
338 for (size_t i = 0; i < size; i++)
340 string msg(strings[i]);
341 fileName programFile;
344 os << '#' << label(i) << " ";
345 //os << "Raw : " << msg << "\n\t";
347 string::size_type lPos = msg.find('[');
348 string::size_type rPos = msg.find(']');
350 if (lPos != string::npos && rPos != string::npos && lPos<rPos)
352 address = msg.substr(lPos+1, rPos-lPos-1);
353 msg = msg.substr(0, lPos);
356 string::size_type bracketPos = msg.find('(');
357 string::size_type spacePos = msg.find(' ');
358 if (bracketPos != string::npos || spacePos != string::npos)
360 programFile = msg.substr(0, min(spacePos, bracketPos));
362 // not an absolute path
363 if (programFile[0] != '/')
365 string tmp = pOpen("which " + programFile);
366 if (tmp[0] == '/' || tmp[0] == '~')
374 string::size_type bracketPos = msg.find('(');
376 if (bracketPos != string::npos)
378 string::size_type start = bracketPos+1;
380 string::size_type plusPos = msg.find('+', start);
382 if (plusPos != string::npos)
384 string cName(msg.substr(start, plusPos-start));
387 char* cplusNamePtr = abi::__cxa_demangle
390 NULL, // have it malloc itself
395 if (status == 0 && cplusNamePtr)
407 string::size_type endBracketPos = msg.find(')', start);
409 if (endBracketPos != string::npos)
411 string fullName(msg.substr(start, endBracketPos-start));
413 os << fullName.c_str() << nl;
418 getSymbolForRaw(os, msg, programFile, address);
425 getSymbolForRaw(os, msg, programFile, address);
428 printSourceFileAndLine(os, addressMap, programFile, address);
437 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
439 } // End namespace Foam
441 // ************************************************************************* //