LCOV - code coverage report
Current view: top level - lunchbox - debug.cpp (source / functions) Hit Total Coverage
Test: lcov2.info Lines: 37 51 72.5 %
Date: 2014-08-05 Functions: 7 10 70.0 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2007-2014, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *               2009-2012, Daniel Nachbaur <danielnachbaur@gmail.com>
       4             :  *
       5             :  * This library is free software; you can redistribute it and/or modify it under
       6             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       7             :  * by the Free Software Foundation.
       8             :  *
       9             :  * This library is distributed in the hope that it will be useful, but WITHOUT
      10             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      11             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      12             :  * details.
      13             :  *
      14             :  * You should have received a copy of the GNU Lesser General Public License
      15             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      16             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      17             :  */
      18             : 
      19             : #include "debug.h"
      20             : 
      21             : #include "os.h" // must come before atomic.h, ordering issue
      22             : #include "atomic.h"
      23             : 
      24             : #include <errno.h>
      25             : 
      26             : #define LB_BACKTRACE_DEPTH 256
      27             : #ifdef _WIN32
      28             : #  include "scopedMutex.h"
      29             : #  define LB_SYMBOL_LENGTH 256
      30             : #  include <DbgHelp.h>
      31             : #  pragma comment(lib, "DbgHelp.lib")
      32             : #else
      33             : #  include <cxxabi.h>
      34             : #  include <execinfo.h>
      35             : #  include <stdlib.h>
      36             : #  include <string.h>
      37             : #endif
      38             : 
      39             : namespace lunchbox
      40             : {
      41             : 
      42           0 : void abort()
      43             : {
      44           0 :     LBERROR << "  in: " << backtrace << std::endl;
      45             : 
      46             :     // if LB_ABORT_WAIT is set, spin forever to allow identifying and debugging
      47             :     // crashed nodes.
      48           0 :     if( getenv( "LB_ABORT_WAIT" ))
      49             :         while( true ) ;
      50             : 
      51           0 :     ::abort();
      52             : }
      53             : 
      54   728807271 : void checkHeap()
      55             : {
      56             : #ifdef _MSC_VER
      57             :     static a_int32_t count( 0 );
      58             :     if( ( ++count % 10000 ) == 0 && _heapchk() != _HEAPOK )
      59             :     {
      60             :         LBERROR << disableFlush << "Abort: heap corruption detected"<< std::endl
      61             :                 << "    Set breakpoint in " << __FILE__ << ':' << __LINE__ + 1
      62             :                 << " to debug" << std::endl << enableFlush;
      63             :     }
      64             : #else
      65             : #endif
      66   728807271 : }
      67             : 
      68             : namespace
      69             : {
      70           1 : static void backtrace_( std::ostream& os, const size_t skipFrames )
      71             : {
      72             : #ifdef _WIN32
      73             :     // Sym* functions from DbgHelp are not thread-safe...
      74             :     static Lock lock;
      75             :     ScopedMutex<> mutex( lock );
      76             : 
      77             :     typedef USHORT (WINAPI *CaptureStackBackTraceType)( __in ULONG, __in ULONG,
      78             :                                                         __out PVOID*,
      79             :                                                         __out_opt PULONG );
      80             :     CaptureStackBackTraceType backtraceFunc = (CaptureStackBackTraceType)
      81             :        GetProcAddress(LoadLibrary("kernel32.dll"), "RtlCaptureStackBackTrace");
      82             :     if( !backtraceFunc )
      83             :         return;
      84             : 
      85             :     SymSetOptions( SYMOPT_UNDNAME | SYMOPT_LOAD_LINES );
      86             :     HANDLE hProcess = GetCurrentProcess();
      87             :     if( !SymInitialize( hProcess, 0, TRUE ))
      88             :         return;
      89             : 
      90             :     void* stack[ LB_BACKTRACE_DEPTH ];
      91             :     const size_t frames = (backtraceFunc)( 0, LB_BACKTRACE_DEPTH, stack, 0 );
      92             : 
      93             :     SYMBOL_INFO* symbol = (SYMBOL_INFO*)calloc( sizeof(SYMBOL_INFO) +
      94             :                                         (LB_SYMBOL_LENGTH+-1)*sizeof(char), 1 );
      95             :     symbol->MaxNameLen   = LB_SYMBOL_LENGTH;
      96             :     symbol->SizeOfStruct = sizeof( SYMBOL_INFO );
      97             : 
      98             :     for( size_t i = skipFrames; i < frames; ++i )
      99             :     {
     100             :         os << "\n  " << frames-i-1 << ": ";
     101             :         if ( !SymFromAddr( hProcess, (DWORD64)stack[i], 0, symbol ))
     102             :             os << "Unknown symbol";
     103             :         else
     104             :         {
     105             :             os << symbol->Name << " - ";
     106             :             IMAGEHLP_LINE64 line = { sizeof(IMAGEHLP_LINE64) };
     107             :             if( !SymGetLineFromAddr64( hProcess, (DWORD64)stack[i], 0, &line ))
     108             :                 os << std::hex << "0x" << symbol->Address << std::dec;
     109             :             else
     110             :                 os << line.FileName << ":" << line.LineNumber;
     111             :         }
     112             :     }
     113             :     os << std::endl;
     114             :     free( symbol );
     115             :     SymCleanup( hProcess );
     116             : #else
     117             :     void* callstack[ LB_BACKTRACE_DEPTH ];
     118           1 :     const int frames = ::backtrace( callstack, LB_BACKTRACE_DEPTH );
     119           1 :     char** names = ::backtrace_symbols( callstack, frames );
     120           5 :     for( int i = skipFrames + 1; i < frames; ++i )
     121             :     {
     122           4 :         std::string name = names[ i ];
     123             : #  ifdef __linux__
     124           4 :         const size_t symbolPos = name.find( "(_" );
     125             : #  else
     126             :         const size_t symbolPos = name.find( " _" );
     127             : #  endif
     128           4 :         if( symbolPos != std::string::npos )
     129           2 :             name = name.substr( symbolPos+1, name.length( ));
     130             : 
     131             : #  ifdef __linux__
     132           4 :         const size_t spacePos = name.find( '+' );
     133             : #  else
     134             :         const size_t spacePos = name.find( ' ' );
     135             : #  endif
     136           4 :         if( spacePos != std::string::npos )
     137           3 :             name = name.substr( 0, spacePos );
     138             : 
     139             :         int status;
     140           4 :         char* demangled = abi::__cxa_demangle( name.c_str(), 0, 0, &status);
     141             : 
     142           4 :         os << "\n  " << frames-i-1 << ": ";
     143           4 :         if( symbolPos == std::string::npos || spacePos == std::string::npos )
     144           2 :             os << names[ i ];
     145             :         else
     146             :         {
     147           2 :             if( demangled )
     148             :             {
     149           1 :                 os << demangled;
     150           1 :                 free( demangled );
     151             :             }
     152             :             else
     153           1 :                 os << name;
     154             :         }
     155           4 :     }
     156           1 :     os << std::endl;
     157           1 :     ::free( names );
     158             : #endif
     159           1 : }
     160             : }
     161             : 
     162           1 : std::string backtrace( const size_t skipFrames )
     163             : {
     164           1 :     std::ostringstream os;
     165           1 :     backtrace_( os, skipFrames + 1/*cut self*/ );
     166           1 :     return os.str();
     167             : }
     168             : 
     169           0 : std::ostream& backtrace( std::ostream& os )
     170             : {
     171           0 :     backtrace_( os, 1 /*cut self*/ );
     172           0 :     return os;
     173             : }
     174             : 
     175        3542 : std::string demangleTypeID( const char* mangled )
     176             : {
     177             : #ifdef _WIN32
     178             :     return std::string( mangled );
     179             : #else
     180             :     int status;
     181        3542 :     char* name = abi::__cxa_demangle( mangled, 0, 0, &status );
     182        3542 :     if( !name || status == 0 )
     183             :     {
     184        3542 :         free( name );
     185        3542 :         return mangled;
     186             :     }
     187             : 
     188           0 :     const std::string result = name;
     189           0 :     free( name );
     190           0 :     return result;
     191             : #endif
     192             : }
     193             : 
     194           1 : std::ostream& sysError( std::ostream& os )
     195             : {
     196             : #ifdef _WIN32
     197             :     const DWORD error = GetLastError();
     198             :     char text[512] = "";
     199             :     FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, 0, error, 0, text, 511, 0 );
     200             :     const size_t length = strlen( text );
     201             :     if( length>2 && text[length-2] == '\r' )
     202             :         text[length-2] = '\0';
     203             : 
     204             :     return os << text << " (" << error << ")";
     205             : #else
     206           1 :     return os << strerror( errno ) << " (" << errno << ")";
     207             : #endif
     208             : }
     209             : 
     210           0 : std::string sysError()
     211             : {
     212           0 :     std::ostringstream os;
     213           0 :     os << sysError;
     214           0 :     return os.str();
     215             : }
     216             : 
     217          87 : }

Generated by: LCOV version 1.10