LCOV - code coverage report
Current view: top level - lunchbox - debug.cpp (source / functions) Hit Total Coverage
Test: Lunchbox Lines: 37 56 66.1 %
Date: 2017-08-03 05:21:41 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 "atomic.h"
      22             : #include "os.h" // must come before atomic.h, ordering issue
      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           0 : void abort(const bool dumpThreads)
      44             : {
      45           0 :     LBERROR << " in: " << backtrace << "\n";
      46           0 :     if (dumpThreads)
      47             :     {
      48           0 :         LBERROR << "\nThreads:" << std::endl;
      49           0 :         Thread::_dumpAll();
      50           0 :         sleep(100); // threads need a bit to print
      51             :     }
      52             :     else
      53           0 :         LBERROR << std::endl;
      54             : 
      55             :     // if LB_ABORT_WAIT is set, spin forever to allow identifying and debugging
      56             :     // crashed nodes.
      57           0 :     if (getenv("LB_ABORT_WAIT"))
      58           0 :         while (true)
      59             :             ;
      60             : 
      61           0 :     ::abort();
      62             : }
      63             : 
      64    36575284 : 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"
      71             :                 << std::endl
      72             :                 << "    Set breakpoint in " << __FILE__ << ':' << __LINE__ + 1
      73             :                 << " to debug" << std::endl
      74             :                 << enableFlush;
      75             :     }
      76             : #else
      77             : #endif
      78    36575284 : }
      79             : 
      80             : namespace
      81             : {
      82           1 : static void backtrace_(std::ostream& os, const size_t skipFrames)
      83             : {
      84             : #ifdef _WIN32
      85             :     // Sym* functions from DbgHelp are not thread-safe...
      86             :     static Lock lock;
      87             :     ScopedMutex<> mutex(lock);
      88             : 
      89             :     typedef USHORT(WINAPI * CaptureStackBackTraceType)(ULONG, ULONG, PVOID*,
      90             :                                                        PULONG);
      91             :     CaptureStackBackTraceType backtraceFunc =
      92             :         (CaptureStackBackTraceType)GetProcAddress(LoadLibrary("kernel32.dll"),
      93             :                                                   "RtlCaptureStackBackTrace");
      94             :     if (!backtraceFunc)
      95             :         return;
      96             : 
      97             :     SymSetOptions(SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
      98             :     HANDLE hProcess = GetCurrentProcess();
      99             :     if (!SymInitialize(hProcess, 0, TRUE))
     100             :         return;
     101             : 
     102             :     void* stack[LB_BACKTRACE_DEPTH];
     103             :     const size_t frames = (backtraceFunc)(0, LB_BACKTRACE_DEPTH, stack, 0);
     104             : 
     105             :     SYMBOL_INFO* symbol = (SYMBOL_INFO*)
     106             :         calloc(sizeof(SYMBOL_INFO) + (LB_SYMBOL_LENGTH + -1) * sizeof(char), 1);
     107             :     symbol->MaxNameLen = LB_SYMBOL_LENGTH;
     108             :     symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
     109             : 
     110             :     for (size_t i = skipFrames; i < frames; ++i)
     111             :     {
     112             :         os << "\n  " << frames - i - 1 << ": ";
     113             :         if (!SymFromAddr(hProcess, (DWORD64)stack[i], 0, symbol))
     114             :             os << "Unknown symbol";
     115             :         else
     116             :         {
     117             :             os << symbol->Name << " - ";
     118             :             IMAGEHLP_LINE64 line = {sizeof(IMAGEHLP_LINE64)};
     119             :             DWORD displ;
     120             :             if (!SymGetLineFromAddr64(hProcess, (DWORD64)stack[i], &displ,
     121             :                                       &line))
     122             :                 os << std::hex << "0x" << symbol->Address << std::dec;
     123             :             else
     124             :                 os << line.FileName << ":" << line.LineNumber;
     125             :         }
     126             :     }
     127             :     os << std::endl;
     128             :     free(symbol);
     129             :     SymCleanup(hProcess);
     130             : #else
     131             :     void* callstack[LB_BACKTRACE_DEPTH];
     132           1 :     const int frames = ::backtrace(callstack, LB_BACKTRACE_DEPTH);
     133           1 :     char** names = ::backtrace_symbols(callstack, frames);
     134           5 :     for (int i = skipFrames + 1; i < frames; ++i)
     135             :     {
     136           8 :         std::string name = names[i];
     137             : #ifdef __linux__
     138           4 :         const size_t symbolPos = name.find("(_");
     139             : #else
     140             :         const size_t symbolPos = name.find(" _");
     141             : #endif
     142           4 :         if (symbolPos != std::string::npos)
     143           2 :             name = name.substr(symbolPos + 1, name.length());
     144             : 
     145             : #ifdef __linux__
     146           4 :         const size_t spacePos = name.find('+');
     147             : #else
     148             :         const size_t spacePos = name.find(' ');
     149             : #endif
     150           4 :         if (spacePos != std::string::npos)
     151           3 :             name = name.substr(0, spacePos);
     152             : 
     153             :         int status;
     154           4 :         char* demangled = abi::__cxa_demangle(name.c_str(), 0, 0, &status);
     155             : 
     156           4 :         os << "\n  " << frames - i - 1 << ": ";
     157           4 :         if (symbolPos == std::string::npos || spacePos == std::string::npos)
     158           2 :             os << names[i];
     159             :         else
     160             :         {
     161           2 :             if (demangled)
     162             :             {
     163           1 :                 os << demangled;
     164           1 :                 free(demangled);
     165             :             }
     166             :             else
     167           1 :                 os << name;
     168             :         }
     169             :     }
     170           1 :     os << "\n";
     171           1 :     ::free(names);
     172             : #endif
     173           1 : }
     174             : }
     175             : 
     176           1 : std::string backtrace(const size_t skipFrames)
     177             : {
     178           2 :     std::ostringstream os;
     179           1 :     backtrace_(os, skipFrames + 1 /*cut self*/);
     180           2 :     return os.str();
     181             : }
     182             : 
     183           0 : std::ostream& backtrace(std::ostream& os)
     184             : {
     185           0 :     backtrace_(os, 1 /*cut self*/);
     186           0 :     return os;
     187             : }
     188             : 
     189        1665 : std::string demangleTypeID(const char* mangled)
     190             : {
     191             : #ifdef _WIN32
     192             :     return std::string(mangled);
     193             : #else
     194             :     int status;
     195        1665 :     char* name = abi::__cxa_demangle(mangled, 0, 0, &status);
     196        1665 :     if (!name || status != 0)
     197             :     {
     198           0 :         free(name);
     199           0 :         return mangled;
     200             :     }
     201             : 
     202        3330 :     const std::string result = name;
     203        1665 :     free(name);
     204        1665 :     return result;
     205             : #endif
     206             : }
     207             : 
     208           3 : std::ostream& sysError(std::ostream& os)
     209             : {
     210             : #ifdef _WIN32
     211             :     const DWORD error = GetLastError();
     212             :     char text[512] = "";
     213             :     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, error, 0, text, 511, 0);
     214             :     const size_t length = strlen(text);
     215             :     if (length > 2 && text[length - 2] == '\r')
     216             :         text[length - 2] = '\0';
     217             : 
     218             :     return os << text << " (" << error << ")";
     219             : #else
     220           3 :     return os << strerror(errno) << " (" << errno << ")";
     221             : #endif
     222             : }
     223             : 
     224           0 : std::string sysError()
     225             : {
     226           0 :     std::ostringstream os;
     227           0 :     os << sysError;
     228           0 :     return os.str();
     229             : }
     230          75 : }

Generated by: LCOV version 1.11