LCOV - code coverage report
Current view: top level - elsa/core - Backtrace.cpp (source / functions) Hit Total Coverage
Test: coverage-all.lcov Lines: 24 79 30.4 %
Date: 2024-05-16 04:22:26 Functions: 2 6 33.3 %

          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             :     std::string symbolDemangle(const char* symbol)
      12           0 :     {
      13           0 :         int status;
      14           0 :         char* buf = abi::__cxa_demangle(symbol, nullptr, nullptr, &status);
      15             : 
      16           0 :         if (status != 0) {
      17           0 :             return symbol;
      18           0 :         } else {
      19           0 :             std::string result{buf};
      20           0 :             ::free(buf);
      21           0 :             return result;
      22           0 :         }
      23           0 :     }
      24             : 
      25             :     std::string addrToString(const void* addr)
      26           0 :     {
      27           0 :         std::ostringstream out;
      28           0 :         out << "[" << addr << "]";
      29           0 :         return out.str();
      30           0 :     }
      31             : 
      32             :     std::string symbolName(const void* addr, bool require_exact_addr, bool no_pure_addrs)
      33           0 :     {
      34           0 :         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           0 :         } 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           0 :             }
      47             : 
      48           0 :             if (symbol_offset == 0) {
      49             :                 // this is our symbol name.
      50           0 :                 return symbolDemangle(addr_info.dli_sname);
      51           0 :             } 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           0 :         }
      58           0 :     }
      59             : 
      60             : } // namespace elsa::detail
      61             : 
      62             : namespace elsa
      63             : {
      64             : 
      65             :     void Backtrace::analyze()
      66         383 :     {
      67         383 :         std::vector<void*> buffer{32};
      68             : 
      69             :         // increase buffer size until it's enough
      70         383 :         while (true) {
      71         383 :             int buff_size = static_cast<int>(buffer.size());
      72         383 :             auto elements = static_cast<size_t>(::backtrace(buffer.data(), buff_size));
      73         383 :             if (elements < buffer.size()) {
      74         383 :                 buffer.resize(elements);
      75         383 :                 break;
      76         383 :             }
      77           0 :             buffer.resize(buffer.size() * 2);
      78           0 :         }
      79             : 
      80        3775 :         for (void* element : buffer) {
      81        3775 :             this->stack_addrs.push_back(element);
      82        3775 :         }
      83         383 :     }
      84             : 
      85             :     void Backtrace::getSymbols(const std::function<void(const backtrace_symbol*)>& cb,
      86             :                                bool reversed) const
      87           0 :     {
      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           0 :             }
      99           0 :         } 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           0 :             }
     106           0 :         }
     107           0 :     }
     108             : 
     109             :     void Backtrace::trimToCurrentStackFrame()
     110           2 :     {
     111           2 :         Backtrace current;
     112           2 :         current.analyze();
     113             : 
     114          14 :         while (not current.stack_addrs.empty() and not this->stack_addrs.empty()) {
     115          14 :             if (this->stack_addrs.back() != current.stack_addrs.back()) {
     116           2 :                 break;
     117           2 :             }
     118             : 
     119          12 :             this->stack_addrs.pop_back();
     120          12 :             current.stack_addrs.pop_back();
     121          12 :         }
     122           2 :     }
     123             : 
     124             : } // namespace elsa

Generated by: LCOV version 1.14