LCOV - code coverage report
Current view: top level - lunchbox - debug.cpp (source / functions) Hit Total Coverage
Test: Lunchbox Lines: 37 56 66.1 %
Date: 2016-11-11 05:21:33 Functions: 7 10 70.0 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2007-2015, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *                          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             : #include "sleep.h"
      24             : #include "thread.h"
      25             : 
      26             : #include <errno.h>
      27             : 
      28             : #define LB_BACKTRACE_DEPTH 256
      29             : #ifdef _WIN32
      30             : #  include "scopedMutex.h"
      31             : #  define LB_SYMBOL_LENGTH 256
      32             : #  include <dbghelp.h>
      33             : #  pragma comment(lib, "DbgHelp.lib")
      34             : #else
      35             : #  include <cxxabi.h>
      36             : #  include <execinfo.h>
      37             : #  include <stdlib.h>
      38             : #  include <string.h>
      39             : #endif
      40             : 
      41             : namespace lunchbox
      42             : {
      43             : 
      44           0 : void abort( const bool dumpThreads )
      45             : {
      46           0 :     LBERROR << "  in: " << backtrace << "\n";
      47           0 :     if( dumpThreads )
      48             :     {
      49           0 :         LBERROR << "\nThreads:" << std::endl;
      50           0 :         Thread::_dumpAll();
      51           0 :         sleep( 100 ); // threads need a bit to print
      52             :     }
      53             :     else
      54           0 :         LBERROR << std::endl;
      55             : 
      56             :     // if LB_ABORT_WAIT is set, spin forever to allow identifying and debugging
      57             :     // crashed nodes.
      58           0 :     if( getenv( "LB_ABORT_WAIT" ))
      59           0 :         while( true ) ;
      60             : 
      61           0 :     ::abort();
      62             : }
      63             : 
      64    37858218 : void checkHeap()
      65             : {
      66             : #ifdef _MSC_VER
      67             :     static a_int32_t count( 0 );
      68             :     if( ( ++count % 10000 ) == 0 && _heapchk() != _HEAPOK )
      69             :     {
      70             :         LBERROR << disableFlush << "Abort: heap corruption detected"<< std::endl
      71             :                 << "    Set breakpoint in " << __FILE__ << ':' << __LINE__ + 1
      72             :                 << " to debug" << std::endl << enableFlush;
      73             :     }
      74             : #else
      75             : #endif
      76    37858218 : }
      77             : 
      78             : namespace
      79             : {
      80           1 : static void backtrace_( std::ostream& os, const size_t skipFrames )
      81             : {
      82             : #ifdef _WIN32
      83             :     // Sym* functions from DbgHelp are not thread-safe...
      84             :     static Lock lock;
      85             :     ScopedMutex<> mutex( lock );
      86             : 
      87             :     typedef USHORT (WINAPI *CaptureStackBackTraceType)( ULONG, ULONG,
      88             :                                                         PVOID*,
      89             :                                                         PULONG );
      90             :     CaptureStackBackTraceType backtraceFunc = (CaptureStackBackTraceType)
      91             :        GetProcAddress(LoadLibrary("kernel32.dll"), "RtlCaptureStackBackTrace");
      92             :     if( !backtraceFunc )
      93             :         return;
      94             : 
      95             :     SymSetOptions( SYMOPT_UNDNAME | SYMOPT_LOAD_LINES );
      96             :     HANDLE hProcess = GetCurrentProcess();
      97             :     if( !SymInitialize( hProcess, 0, TRUE ))
      98             :         return;
      99             : 
     100             :     void* stack[ LB_BACKTRACE_DEPTH ];
     101             :     const size_t frames = (backtraceFunc)( 0, LB_BACKTRACE_DEPTH, stack, 0 );
     102             : 
     103             :     SYMBOL_INFO* symbol = (SYMBOL_INFO*)calloc( sizeof(SYMBOL_INFO) +
     104             :                                         (LB_SYMBOL_LENGTH+-1)*sizeof(char), 1 );
     105             :     symbol->MaxNameLen   = LB_SYMBOL_LENGTH;
     106             :     symbol->SizeOfStruct = sizeof( SYMBOL_INFO );
     107             : 
     108             :     for( size_t i = skipFrames; i < frames; ++i )
     109             :     {
     110             :         os << "\n  " << frames-i-1 << ": ";
     111             :         if ( !SymFromAddr( hProcess, (DWORD64)stack[i], 0, symbol ))
     112             :             os << "Unknown symbol";
     113             :         else
     114             :         {
     115             :             os << symbol->Name << " - ";
     116             :             IMAGEHLP_LINE64 line = { sizeof(IMAGEHLP_LINE64) };
     117             :             DWORD displ;
     118             :             if( !SymGetLineFromAddr64( hProcess, (DWORD64)stack[i], &displ, &line ))
     119             :                 os << std::hex << "0x" << symbol->Address << std::dec;
     120             :             else
     121             :                 os << line.FileName << ":" << line.LineNumber;
     122             :         }
     123             :     }
     124             :     os << std::endl;
     125             :     free( symbol );
     126             :     SymCleanup( hProcess );
     127             : #else
     128             :     void* callstack[ LB_BACKTRACE_DEPTH ];
     129           1 :     const int frames = ::backtrace( callstack, LB_BACKTRACE_DEPTH );
     130           1 :     char** names = ::backtrace_symbols( callstack, frames );
     131           5 :     for( int i = skipFrames + 1; i < frames; ++i )
     132             :     {
     133           8 :         std::string name = names[ i ];
     134             : #  ifdef __linux__
     135           4 :         const size_t symbolPos = name.find( "(_" );
     136             : #  else
     137             :         const size_t symbolPos = name.find( " _" );
     138             : #  endif
     139           4 :         if( symbolPos != std::string::npos )
     140           2 :             name = name.substr( symbolPos+1, name.length( ));
     141             : 
     142             : #  ifdef __linux__
     143           4 :         const size_t spacePos = name.find( '+' );
     144             : #  else
     145             :         const size_t spacePos = name.find( ' ' );
     146             : #  endif
     147           4 :         if( spacePos != std::string::npos )
     148           3 :             name = name.substr( 0, spacePos );
     149             : 
     150             :         int status;
     151           4 :         char* demangled = abi::__cxa_demangle( name.c_str(), 0, 0, &status);
     152             : 
     153           4 :         os << "\n  " << frames-i-1 << ": ";
     154           4 :         if( symbolPos == std::string::npos || spacePos == std::string::npos )
     155           2 :             os << names[ i ];
     156             :         else
     157             :         {
     158           2 :             if( demangled )
     159             :             {
     160           1 :                 os << demangled;
     161           1 :                 free( demangled );
     162             :             }
     163             :             else
     164           1 :                 os << name;
     165             :         }
     166             :     }
     167           1 :     os << "\n";
     168           1 :     ::free( names );
     169             : #endif
     170           1 : }
     171             : }
     172             : 
     173           1 : std::string backtrace( const size_t skipFrames )
     174             : {
     175           2 :     std::ostringstream os;
     176           1 :     backtrace_( os, skipFrames + 1/*cut self*/ );
     177           2 :     return os.str();
     178             : }
     179             : 
     180           0 : std::ostream& backtrace( std::ostream& os )
     181             : {
     182           0 :     backtrace_( os, 1 /*cut self*/ );
     183           0 :     return os;
     184             : }
     185             : 
     186        1666 : std::string demangleTypeID( const char* mangled )
     187             : {
     188             : #ifdef _WIN32
     189             :     return std::string( mangled );
     190             : #else
     191             :     int status;
     192        1666 :     char* name = abi::__cxa_demangle( mangled, 0, 0, &status );
     193        1666 :     if( !name || status != 0 )
     194             :     {
     195           0 :         free( name );
     196           0 :         return mangled;
     197             :     }
     198             : 
     199        3332 :     const std::string result = name;
     200        1666 :     free( name );
     201        1666 :     return result;
     202             : #endif
     203             : }
     204             : 
     205           3 : std::ostream& sysError( std::ostream& os )
     206             : {
     207             : #ifdef _WIN32
     208             :     const DWORD error = GetLastError();
     209             :     char text[512] = "";
     210             :     FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, 0, error, 0, text, 511, 0 );
     211             :     const size_t length = strlen( text );
     212             :     if( length>2 && text[length-2] == '\r' )
     213             :         text[length-2] = '\0';
     214             : 
     215             :     return os << text << " (" << error << ")";
     216             : #else
     217           3 :     return os << strerror( errno ) << " (" << errno << ")";
     218             : #endif
     219             : }
     220             : 
     221           0 : std::string sysError()
     222             : {
     223           0 :     std::ostringstream os;
     224           0 :     os << sysError;
     225           0 :     return os.str();
     226             : }
     227             : 
     228          72 : }

Generated by: LCOV version 1.11