Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:17:36

0001 
0002 // Copyright 2020, Jefferson Science Associates, LLC.
0003 // Subject to the terms in the LICENSE file found in the top-level directory.
0004 
0005 
0006 #include "JBacktrace.h"
0007 
0008 #include <chrono>
0009 #include <sstream>
0010 #include <execinfo.h>
0011 #include <cxxabi.h>
0012 #include <dlfcn.h>
0013 #include <cstring>
0014 #include <thread>
0015 #include <iomanip>
0016 
0017 
0018 JBacktrace::JBacktrace(const JBacktrace& other) {
0019     m_ready = other.m_ready.load();
0020     m_frame_count = other.m_frame_count;
0021     m_frames_to_omit = other.m_frames_to_omit;
0022     m_buffer = other.m_buffer;
0023 }
0024 
0025 JBacktrace& JBacktrace::operator=(const JBacktrace& other) {
0026     m_ready = other.m_ready.load();
0027     m_frame_count = other.m_frame_count;
0028     m_frames_to_omit = other.m_frames_to_omit;
0029     m_buffer = other.m_buffer;
0030     return *this;
0031 }
0032 
0033 JBacktrace::JBacktrace(JBacktrace&& other) {
0034     m_ready = other.m_ready.load();
0035     m_frame_count = other.m_frame_count;
0036     m_frames_to_omit = other.m_frames_to_omit;
0037     m_buffer = std::move(other.m_buffer);
0038 }
0039 
0040 void JBacktrace::Reset() {
0041     m_ready = false;
0042 }
0043 
0044 void JBacktrace::WaitForCapture() const {
0045     while (!m_ready.load(std::memory_order_acquire)) {
0046         std::this_thread::sleep_for(std::chrono::milliseconds(10));
0047     }
0048 }
0049 
0050 void JBacktrace::Capture(int frames_to_omit) {
0051     m_frame_count = backtrace(m_buffer.data(), MAX_FRAMES);
0052     m_frames_to_omit = frames_to_omit;
0053     m_ready.store(true, std::memory_order_release);
0054 }
0055 
0056 void JBacktrace::Format(std::ostream& os) const {
0057     char** symbols = backtrace_symbols(m_buffer.data(), m_frame_count);
0058     // Skip the first few frames, which are inevitably signal handlers, JBacktrace ctors, or JException ctors
0059     for (int i=m_frames_to_omit; i<m_frame_count; ++i) {
0060 
0061         std::string name;
0062 
0063         // We are going to get the symbol names from dl, so that we can demangle them
0064         Dl_info dlinfo;
0065         if (dladdr(m_buffer[i], &dlinfo)) { // dladdr succeeded
0066             if (dlinfo.dli_sname) { // dladdr found a corresponding symbol
0067 
0068                 int demangle_status = 0;
0069                 auto demangled_name = abi::__cxa_demangle(dlinfo.dli_sname, nullptr, nullptr, &demangle_status);
0070 
0071                 if (demangle_status == 0) { // Demangle succeeded, we have a symbol name!
0072                     name = std::string(demangled_name);
0073                 }
0074                 else { // Demangle failed, so we use mangled version
0075                     name = std::string(dlinfo.dli_sname);
0076                 }
0077                 free(demangled_name);
0078             }
0079             else { // Otherwise use the shared object name
0080                 name = "???";
0081             }
0082         }
0083         else { // dladdr failed for some reason, so we fall back on backtrace_symbols
0084             name = symbols[i];
0085         }
0086         size_t offset = (size_t) m_buffer[i] - (size_t) dlinfo.dli_fbase;
0087         os << "  " << std::setw(2) << i-m_frames_to_omit << ": " << name << std::endl;
0088         os << "      " << AddrToLineInfo(dlinfo.dli_fname, offset) << std::endl;
0089     }
0090     free(symbols);
0091 }
0092 
0093 std::string JBacktrace::AddrToLineInfo(const char* filename, size_t offset) const {
0094 
0095     char backup_line_info[256];
0096     std::snprintf(backup_line_info, sizeof(backup_line_info), "%s:%zx\n", filename, offset);
0097 
0098     static bool addr2line_works = false;
0099     if (addr2line_works) {
0100         char command[256];
0101         std::snprintf(command, sizeof(command), "addr2line -e %s %zx", filename, offset);
0102 
0103         FILE* pipe = popen(command, "r");
0104         if (pipe) {
0105             // Capture stdout
0106             std::string line_info;
0107             char buffer[128];
0108             while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
0109                 line_info += buffer;
0110             }
0111 
0112             int return_code = pclose(pipe);
0113             if (return_code == 0) {
0114                 if (line_info != "??:0\n" && line_info != "??:?\n") {
0115                     return line_info;
0116                 }
0117             }
0118         }
0119         else {
0120             addr2line_works = false;
0121         }
0122     }
0123     // If addr2line failed for any reason, return the dladdr results instead
0124     return std::string(backup_line_info);
0125 }
0126 
0127 std::string JBacktrace::ToString() const {
0128     std::ostringstream oss;
0129     Format(oss);
0130     return oss.str();
0131 }
0132 
0133 
0134