From f8a2ddc4645f05f22bbb71cbc973e8d568f06adf Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Thu, 6 Mar 2014 10:59:13 +0100 Subject: [PATCH] Include source file name and line numbers in stack traces. Fixes #5715 --- CMakeLists.txt | 1 + config.h.cmake | 1 + lib/base/stacktrace.cpp | 55 +++++++++++++++++++++++++++++++++++++++-- lib/base/stacktrace.h | 2 ++ 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b7b8c19d..369700273 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,6 +104,7 @@ include(CheckLibraryExists) check_function_exists(vfork HAVE_VFORK) check_function_exists(backtrace_symbols HAVE_BACKTRACE_SYMBOLS) check_function_exists(pipe2 HAVE_PIPE2) +check_function_exists(dladdr HAVE_DLADDR) check_library_exists(crypto BIO_f_zlib "" HAVE_BIOZLIB) include(GNUInstallDirs) diff --git a/config.h.cmake b/config.h.cmake index cc80a2e04..68dec8472 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -5,6 +5,7 @@ #cmakedefine HAVE_BACKTRACE_SYMBOLS #cmakedefine HAVE_PIPE2 #cmakedefine HAVE_VFORK +#cmakedefine HAVE_DLADDR #define ICINGA_PREFIX "${CMAKE_INSTALL_PREFIX}" #define ICINGA_SYSCONFDIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}" diff --git a/lib/base/stacktrace.cpp b/lib/base/stacktrace.cpp index 4703a1b43..624c1502c 100644 --- a/lib/base/stacktrace.cpp +++ b/lib/base/stacktrace.cpp @@ -20,6 +20,8 @@ #include "base/stacktrace.h" #include "base/qstring.h" #include "base/utility.h" +#include "base/convert.h" +#include #ifdef HAVE_BACKTRACE_SYMBOLS # include @@ -97,6 +99,39 @@ void StackTrace::Initialize(void) #endif /* _WIN32 */ } +/** + * Looks up source file name and line number information for the specified + * ELF executable and RVA. + * + * @param exe The ELF file. + * @param rva The RVA. + * @returns Source file and line number. + */ +String StackTrace::Addr2Line(const String& exe, uintptr_t rva) +{ +#ifndef _WIN32 + std::ostringstream msgbuf; + msgbuf << "addr2line -s -e " << exe << " " << std::hex << rva; + + String args = msgbuf.str(); + + FILE *fp = popen(args.CStr(), "r"); + + if (!fp) + return "RVA: " + Convert::ToString(rva); + + char buffer[512]; + fgets(buffer, sizeof(buffer), fp); + + String line = buffer; + boost::algorithm::trim_right(line); + + return line; +#else /* _WIN32 */ + return String(); +#endif /* _WIN32 */ +} + /** * Prints a stacktrace to the specified stream. * @@ -118,7 +153,7 @@ void StackTrace::Print(std::ostream& fp, int ignoreFrames) const char *sym_begin = strchr(messages[i], '('); - if (sym_begin != NULL) { + if (sym_begin) { char *sym_end = strchr(sym_begin, '+'); if (sym_end != NULL) { @@ -128,7 +163,23 @@ void StackTrace::Print(std::ostream& fp, int ignoreFrames) const if (sym_demangled.IsEmpty()) sym_demangled = ""; - message = String(messages[i], sym_begin) + ": " + sym_demangled + " (" + String(sym_end); + String path = String(messages[i], sym_begin); + + size_t slashp = path.RFind("/"); + + if (slashp != String::NPos) + path = path.SubStr(slashp + 1); + + message = path + ": " + sym_demangled + " (" + String(sym_end); + +#ifdef HAVE_DLADDR + Dl_info dli; + + if (dladdr(m_Frames[i], &dli) > 0) { + uintptr_t rva = reinterpret_cast(m_Frames[i]) - reinterpret_cast(dli.dli_fbase); + message += " (" + Addr2Line(dli.dli_fname, rva) + ")"; + } +#endif /* HAVE_DLADDR */ } } diff --git a/lib/base/stacktrace.h b/lib/base/stacktrace.h index fcbdfb66f..e93825270 100644 --- a/lib/base/stacktrace.h +++ b/lib/base/stacktrace.h @@ -21,6 +21,7 @@ #define STACKTRACE_H #include "base/i2-base.h" +#include "base/qstring.h" #include #include @@ -49,6 +50,7 @@ private: static boost::once_flag m_OnceFlag; static void Initialize(void); + static String Addr2Line(const String& exe, uintptr_t rva); }; I2_BASE_API std::ostream& operator<<(std::ostream& stream, const StackTrace& trace);