File indexing completed on 2025-01-18 10:17:36
0001
0002
0003
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
0059 for (int i=m_frames_to_omit; i<m_frame_count; ++i) {
0060
0061 std::string name;
0062
0063
0064 Dl_info dlinfo;
0065 if (dladdr(m_buffer[i], &dlinfo)) {
0066 if (dlinfo.dli_sname) {
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) {
0072 name = std::string(demangled_name);
0073 }
0074 else {
0075 name = std::string(dlinfo.dli_sname);
0076 }
0077 free(demangled_name);
0078 }
0079 else {
0080 name = "???";
0081 }
0082 }
0083 else {
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
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
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