fix consistancy of gradient on coupled patches
[OpenFOAM-1.6-ext.git] / src / OSspecific / POSIX / printStack.C
blob0e78d51506dd508e700e854a988d160f6828e313
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright held by original author
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 #ifndef darwin
36 #include <execinfo.h>
37 #endif
38 #include <dlfcn.h>
40 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
42 namespace Foam
45 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
47 string pOpen(const string &cmd, label line=0)
49     const int MAX = 1000;
51     FILE *cmdPipe = popen(cmd.c_str(), "r");
53     if (cmdPipe)
54     {
55         // Read line number of lines
56         for (label cnt = 0; cnt <= line; cnt++)
57         {
58             char buffer[MAX];
60             char* s = fgets(buffer, MAX-1, cmdPipe);
62             if (s == NULL)
63             {
64 #ifdef darwin
65                 // workaround for the Python-Script
66                 for(int i=0;i<MAX;i++) {
67                     if(buffer[i]=='\n') {
68                         buffer[i]='\0';
69                     }
70                 }
71                 return buffer;
72 #else
73                 return "";
74 #endif
75             }
77             if (cnt == line)
78             {
79                 string str(buffer);
80                 return str.substr(0, str.size()-1);
81             }
82         }
83         pclose(cmdPipe);
84     }
86     return "";
90 // use popen to call addr2line (using bfd.h directly would have
91 // meant relinking everything)
93 void printSourceFileAndLine
95     Ostream& os,
96     const HashTable<label, fileName>& addressMap,
97     const fileName& filename,
98     const word& address
101     word myAddress = address;
103 #ifndef darwin
104     if (filename.ext() == "so")
105 #else
106     if (filename.ext() == "dylib")
107 #endif
108     {
109         // Convert offset into .so into offset into executable.
111         void *addr;
112         sscanf(myAddress.c_str(), "%p",&addr);
114         Dl_info info;
116         dladdr(addr, &info);
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();
128     }
130     if (filename[0] == '/')
131     {
132         string line = pOpen
133         (
134 #ifndef darwin
135             "addr2line -f --demangle=auto --exe "
136 #else
137             //            "gaddr2line -f --inline --demangle=auto --exe "
138             "addr2line4Mac.py "
139 #endif
140           + filename
141           + " "
142           + myAddress,
143             1
144         );
146         if (line == "")
147         {
148             os << " addr2line failed";
149         }
150         else if (line == "??:0")
151         {
152             os << " in " << filename;
153         }
154         else
155         {
156             string cwdLine(line.replaceAll(cwd() + '/', ""));
158             string homeLine(cwdLine.replaceAll(home(), '~'));
160             os << " at " << homeLine.c_str();
161         }
162     }
165 #ifdef darwin
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
170 template<int level>
171 void *getStackAddress() 
173     const unsigned int stackLevel=level;
174     return (
175         __builtin_frame_address(level) 
176         ? __builtin_return_address(stackLevel)
177         : (void *)0
178     );
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)
187     switch(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);
210         default:
211             return (void *)0;
212             break;
213     }
216 unsigned backtrace(void **bt, unsigned maxAddrs) 
218     unsigned valid=0;
219     bool ok=true;
221     for(int level=0;level<maxAddrs;level++) {
222         if(ok) {
223             bt[level]=getStackAddress(level);
224             
225             if(bt[level]!=(void *)0) {
226                 valid=level;
227             } else {
228                 ok=false;
229             }
230         } else {
231             bt[level]=(void *)0;
232         }
233     }
235     return valid;
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++) {
244         Dl_info info;
245         int result=dladdr(bt[i],&info);
247         char tmp[1000];
248 #ifdef darwinIntel64
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]);
250 #else
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]);
252 #endif
253         strings[i]=(char *)malloc(strlen(tmp)+1);
254         strcpy(strings[i],tmp);
255     }
257     return strings;
260 #endif
262 void getSymbolForRaw
264     Ostream& os,
265     const string& raw,
266     const fileName& filename,
267     const word& address
270     if (filename.size() && filename[0] == '/')
271     {
272         string fcnt = pOpen
273         (
274 #ifndef darwin
275             "addr2line -f --demangle=auto --exe "
276 #else
277             //            "gaddr2line -f --inline --demangle=auto --exe "
278             "addr2line4Mac.py "
279 #endif
280           + filename
281           + " "
282           + address
283         );
285         if (fcnt != "")
286         {
287             os << fcnt.c_str();
288             return;
289         }
290     }
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"))
298     {
299         return;
300     }
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;
309     {
310         IFstream is("/proc/" + name(pid()) + "/maps");
312         while(is.good())
313         {
314             string line;
315             is.getLine(line);
317             string::size_type space = line.rfind(' ') + 1;
318             fileName libPath = line.substr(space, line.size()-space);
320             if (libPath.size() && libPath[0] == '/')
321             {
322                 string offsetString(line.substr(0, line.find('-')));
323                 IStringStream offsetStr(offsetString);
324                 addressMap.insert(libPath, readHexLabel(offsetStr));
325             }
326         }
327     }
329     // Get raw stack symbols
330     void *array[100];
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
337     os << nl;
338     for (size_t i = 0; i < size; i++)
339     {
340         string msg(strings[i]);
341         fileName programFile;
342         word address;
344         os << '#' << label(i) << "  ";
345         //os << "Raw   : " << msg << "\n\t";
346         {
347             string::size_type lPos = msg.find('[');
348             string::size_type rPos = msg.find(']');
350             if (lPos != string::npos && rPos != string::npos && lPos<rPos)
351             {
352                 address = msg.substr(lPos+1, rPos-lPos-1);
353                 msg = msg.substr(0, lPos);
354             }
356             string::size_type bracketPos = msg.find('(');
357             string::size_type spacePos = msg.find(' ');
358             if (bracketPos != string::npos || spacePos != string::npos)
359             {
360                 programFile = msg.substr(0, min(spacePos, bracketPos));
362                 // not an absolute path
363                 if (programFile[0] != '/')
364                 {
365                     string tmp = pOpen("which " + programFile);
366                     if (tmp[0] == '/' || tmp[0] == '~')
367                     {
368                         programFile = tmp;
369                     }
370                 }
371             }
372         }
374         string::size_type bracketPos = msg.find('(');
376         if (bracketPos != string::npos)
377         {
378             string::size_type start = bracketPos+1;
380             string::size_type plusPos = msg.find('+', start);
382             if (plusPos != string::npos)
383             {
384                 string cName(msg.substr(start, plusPos-start));
386                 int status;
387                 char* cplusNamePtr = abi::__cxa_demangle
388                 (
389                     cName.c_str(),
390                     NULL,                   // have it malloc itself
391                     0,
392                     &status
393                 );
395                 if (status == 0 && cplusNamePtr)
396                 {
397                     os << cplusNamePtr;
398                     free(cplusNamePtr);
399                 }
400                 else
401                 {
402                     os << cName.c_str();
403                 }
404             }
405             else
406             {
407                 string::size_type endBracketPos = msg.find(')', start);
409                 if (endBracketPos != string::npos)
410                 {
411                     string fullName(msg.substr(start, endBracketPos-start));
413                     os << fullName.c_str() << nl;
414                 }
415                 else
416                 {
417                     // Print raw message
418                     getSymbolForRaw(os, msg, programFile, address);
419                 }
420             }
421         }
422         else
423         {
424             // Print raw message
425             getSymbolForRaw(os, msg, programFile, address);
426         }
428         printSourceFileAndLine(os, addressMap, programFile, address);
430         os << nl;
431     }
433     free(strings);
437 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
439 } // End namespace Foam
441 // ************************************************************************* //