LCOV - code coverage report
Current view: top level - core - Backtrace.cpp (source / functions) Hit Total Coverage
Test: test_coverage.info.cleaned Lines: 0 61 0.0 %
Date: 2022-08-04 03:43:28 Functions: 0 6 0.0 %

          Line data    Source code
       1             : #include "Backtrace.h"
       2             : 
       3             : #include <cxxabi.h>
       4             : #include <dlfcn.h>
       5             : #include <execinfo.h>
       6             : #include <sstream>
       7             : 
       8             : namespace elsa::detail
       9             : {
      10             : 
      11           0 :     std::string symbolDemangle(const char* symbol)
      12             :     {
      13             :         int status;
      14           0 :         char* buf = abi::__cxa_demangle(symbol, nullptr, nullptr, &status);
      15             : 
      16           0 :         if (status != 0) {
      17           0 :             return symbol;
      18             :         } else {
      19           0 :             std::string result{buf};
      20           0 :             ::free(buf);
      21           0 :             return result;
      22           0 :         }
      23             :     }
      24             : 
      25           0 :     std::string addrToString(const void* addr)
      26             :     {
      27           0 :         std::ostringstream out;
      28           0 :         out << "[" << addr << "]";
      29           0 :         return out.str();
      30           0 :     }
      31             : 
      32           0 :     std::string symbolName(const void* addr, bool require_exact_addr, bool no_pure_addrs)
      33             :     {
      34             :         Dl_info addr_info;
      35             : 
      36           0 :         if (::dladdr(addr, &addr_info) == 0) {
      37             :             // dladdr has... failed.
      38           0 :             return no_pure_addrs ? "" : addrToString(addr);
      39             :         } else {
      40           0 :             size_t symbol_offset =
      41           0 :                 reinterpret_cast<size_t>(addr) - reinterpret_cast<size_t>(addr_info.dli_saddr);
      42             : 
      43           0 :             if (addr_info.dli_sname == nullptr or (symbol_offset != 0 and require_exact_addr)) {
      44             : 
      45           0 :                 return no_pure_addrs ? "" : addrToString(addr);
      46             :             }
      47             : 
      48           0 :             if (symbol_offset == 0) {
      49             :                 // this is our symbol name.
      50           0 :                 return symbolDemangle(addr_info.dli_sname);
      51             :             } else {
      52           0 :                 std::ostringstream out;
      53           0 :                 out << symbolDemangle(addr_info.dli_sname) << "+0x" << std::hex << symbol_offset
      54           0 :                     << std::dec;
      55           0 :                 return out.str();
      56           0 :             }
      57             :         }
      58             :     }
      59             : 
      60             : } // namespace elsa::detail
      61             : 
      62             : namespace elsa
      63             : {
      64             : 
      65           0 :     void Backtrace::analyze()
      66             :     {
      67           0 :         std::vector<void*> buffer{32};
      68             : 
      69             :         // increase buffer size until it's enough
      70             :         while (true) {
      71           0 :             int buff_size = static_cast<int>(buffer.size());
      72           0 :             auto elements = static_cast<size_t>(::backtrace(buffer.data(), buff_size));
      73           0 :             if (elements < buffer.size()) {
      74           0 :                 buffer.resize(elements);
      75           0 :                 break;
      76             :             }
      77           0 :             buffer.resize(buffer.size() * 2);
      78           0 :         }
      79             : 
      80           0 :         for (void* element : buffer) {
      81           0 :             this->stack_addrs.push_back(element);
      82             :         }
      83           0 :     }
      84             : 
      85           0 :     void Backtrace::getSymbols(const std::function<void(const backtrace_symbol*)>& cb,
      86             :                                bool reversed) const
      87             :     {
      88           0 :         backtrace_symbol symbol;
      89             : 
      90           0 :         if (reversed) {
      91           0 :             for (size_t idx = this->stack_addrs.size(); idx-- > 0;) {
      92           0 :                 void* pc = this->stack_addrs[idx];
      93             : 
      94           0 :                 symbol.functionname = detail::symbolName(pc, false, true);
      95           0 :                 symbol.pc = pc;
      96             : 
      97           0 :                 cb(&symbol);
      98             :             }
      99             :         } else {
     100           0 :             for (void* pc : this->stack_addrs) {
     101           0 :                 symbol.functionname = detail::symbolName(pc, false, true);
     102           0 :                 symbol.pc = pc;
     103             : 
     104           0 :                 cb(&symbol);
     105             :             }
     106             :         }
     107           0 :     }
     108             : 
     109           0 :     void Backtrace::trimToCurrentStackFrame()
     110             :     {
     111           0 :         Backtrace current;
     112           0 :         current.analyze();
     113             : 
     114           0 :         while (not current.stack_addrs.empty() and not this->stack_addrs.empty()) {
     115           0 :             if (this->stack_addrs.back() != current.stack_addrs.back()) {
     116           0 :                 break;
     117             :             }
     118             : 
     119           0 :             this->stack_addrs.pop_back();
     120           0 :             current.stack_addrs.pop_back();
     121             :         }
     122           0 :     }
     123             : 
     124             : } // namespace elsa

Generated by: LCOV version 1.14