LCOV - code coverage report
Current view: top level - lunchbox - debug.cpp (source / functions) Hit Total Coverage
Test: Lunchbox Lines: 37 56 66.1 %
Date: 2018-10-03 05:33:11 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             : #include <mutex>
      28             : 
      29             : #define LB_BACKTRACE_DEPTH 256
      30             : #ifdef _WIN32
      31             : #include "scopedMutex.h"
      32             : #define LB_SYMBOL_LENGTH 256
      33             : #include <dbghelp.h>
      34             : #pragma comment(lib, "DbgHelp.lib")
      35             : #else
      36             : #include <cxxabi.h>
      37             : #include <execinfo.h>
      38             : #include <stdlib.h>
      39             : #include <string.h>
      40             : #endif
      41             : 
      42             : namespace lunchbox
      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             : 
      62           0 :     ::abort();
      63             : }
      64             : 
      65    36917224 : void checkHeap()
      66             : {
      67             : #ifdef _MSC_VER
      68             :     static a_int32_t count(0);
      69             :     if ((++count % 10000) == 0 && _heapchk() != _HEAPOK)
      70             :     {
      71             :         LBERROR << disableFlush << "Abort: heap corruption detected"
      72             :                 << std::endl
      73             :                 << "    Set breakpoint in " << __FILE__ << ':' << __LINE__ + 1
      74             :                 << " to debug" << std::endl
      75             :                 << enableFlush;
      76             :     }
      77             : #else
      78             : #endif
      79    36917224 : }
      80             : 
      81             : namespace
      82             : {
      83           1 : static void backtrace_(std::ostream& os, const size_t skipFrames)
      84             : {
      85             : #ifdef _WIN32
      86             :     // Sym* functions from DbgHelp are not thread-safe...
      87             :     static std::mutex lock;
      88             :     ScopedWrite scopedWrite(lock);
      89             : 
      90             :     typedef USHORT(WINAPI * CaptureStackBackTraceType)(ULONG, ULONG, PVOID*,
      91             :                                                        PULONG);
      92             :     CaptureStackBackTraceType backtraceFunc =
      93             :         (CaptureStackBackTraceType)GetProcAddress(LoadLibrary("kernel32.dll"),
      94             :                                                   "RtlCaptureStackBackTrace");
      95             :     if (!backtraceFunc)
      96             :         return;
      97             : 
      98             :     SymSetOptions(SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
      99             :     HANDLE hProcess = GetCurrentProcess();
     100             :     if (!SymInitialize(hProcess, 0, TRUE))
     101             :         return;
     102             : 
     103             :     void* stack[LB_BACKTRACE_DEPTH];
     104             :     const size_t frames = (backtraceFunc)(0, LB_BACKTRACE_DEPTH, stack, 0);
     105             : 
     106             :     SYMBOL_INFO* symbol = (SYMBOL_INFO*)
     107             :         calloc(sizeof(SYMBOL_INFO) + (LB_SYMBOL_LENGTH + -1) * sizeof(char), 1);
     108             :     symbol->MaxNameLen = LB_SYMBOL_LENGTH;
     109             :     symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
     110             : 
     111             :     for (size_t i = skipFrames; i < frames; ++i)
     112             :     {
     113             :         os << "\n  " << frames - i - 1 << ": ";
     114             :         if (!SymFromAddr(hProcess, (DWORD64)stack[i], 0, symbol))
     115             :             os << "Unknown symbol";
     116             :         else
     117             :         {
     118             :             os << symbol->Name << " - ";
     119             :             IMAGEHLP_LINE64 line = {sizeof(IMAGEHLP_LINE64)};
     120             :             DWORD displ;
     121             :             if (!SymGetLineFromAddr64(hProcess, (DWORD64)stack[i], &displ,
     122             :                                       &line))
     123             :                 os << std::hex << "0x" << symbol->Address << std::dec;
     124             :             else
     125             :                 os << line.FileName << ":" << line.LineNumber;
     126             :         }
     127             :     }
     128             :     os << std::endl;
     129             :     free(symbol);
     130             :     SymCleanup(hProcess);
     131             : #else
     132             :     void* callstack[LB_BACKTRACE_DEPTH];
     133           1 :     const int frames = ::backtrace(callstack, LB_BACKTRACE_DEPTH);
     134           1 :     char** names = ::backtrace_symbols(callstack, frames);
     135           5 :     for (int i = skipFrames + 1; i < frames; ++i)
     136             :     {
     137           8 :         std::string name = names[i];
     138             : #ifdef __linux__
     139           4 :         const size_t symbolPos = name.find("(_");
     140             : #else
     141             :         const size_t symbolPos = name.find(" _");
     142             : #endif
     143           4 :         if (symbolPos != std::string::npos)
     144           2 :             name = name.substr(symbolPos + 1, name.length());
     145             : 
     146             : #ifdef __linux__
     147           4 :         const size_t spacePos = name.find('+');
     148             : #else
     149             :         const size_t spacePos = name.find(' ');
     150             : #endif
     151           4 :         if (spacePos != std::string::npos)
     152           3 :             name = name.substr(0, spacePos);
     153             : 
     154             :         int status;
     155           4 :         char* demangled = abi::__cxa_demangle(name.c_str(), 0, 0, &status);
     156             : 
     157           4 :         os << "\n  " << frames - i - 1 << ": ";
     158           4 :         if (symbolPos == std::string::npos || spacePos == std::string::npos)
     159           2 :             os << names[i];
     160             :         else
     161             :         {
     162           2 :             if (demangled)
     163             :             {
     164           1 :                 os << demangled;
     165           1 :                 free(demangled);
     166             :             }
     167             :             else
     168           1 :                 os << name;
     169             :         }
     170             :     }
     171           1 :     os << "\n";
     172           1 :     ::free(names);
     173             : #endif
     174           1 : }
     175             : }
     176             : 
     177           1 : std::string backtrace(const size_t skipFrames)
     178             : {
     179           2 :     std::ostringstream os;
     180           1 :     backtrace_(os, skipFrames + 1 /*cut self*/);
     181           2 :     return os.str();
     182             : }
     183             : 
     184           0 : std::ostream& backtrace(std::ostream& os)
     185             : {
     186           0 :     backtrace_(os, 1 /*cut self*/);
     187           0 :     return os;
     188             : }
     189             : 
     190        1665 : std::string demangleTypeID(const char* mangled)
     191             : {
     192             : #ifdef _WIN32
     193             :     return std::string(mangled);
     194             : #else
     195             :     int status;
     196        1665 :     char* name = abi::__cxa_demangle(mangled, 0, 0, &status);
     197        1665 :     if (!name || status != 0)
     198             :     {
     199           0 :         free(name);
     200           0 :         return mangled;
     201             :     }
     202             : 
     203        3330 :     const std::string result = name;
     204        1665 :     free(name);
     205        1665 :     return result;
     206             : #endif
     207             : }
     208             : 
     209           3 : std::ostream& sysError(std::ostream& os)
     210             : {
     211             : #ifdef _WIN32
     212             :     const DWORD error = GetLastError();
     213             :     char text[512] = "";
     214             :     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, error, 0, text, 511, 0);
     215             :     const size_t length = strlen(text);
     216             :     if (length > 2 && text[length - 2] == '\r')
     217             :         text[length - 2] = '\0';
     218             : 
     219             :     return os << text << " (" << error << ")";
     220             : #else
     221           3 :     return os << strerror(errno) << " (" << errno << ")";
     222             : #endif
     223             : }
     224             : 
     225           0 : std::string sysError()
     226             : {
     227           0 :     std::ostringstream os;
     228           0 :     os << sysError;
     229           0 :     return os.str();
     230             : }
     231          75 : }

Generated by: LCOV version 1.11