Include source file name and line numbers in stack traces.

Fixes #5715
This commit is contained in:
Gunnar Beutner 2014-03-06 10:59:13 +01:00
parent ac3cbfe801
commit f8a2ddc464
4 changed files with 57 additions and 2 deletions

View File

@ -104,6 +104,7 @@ include(CheckLibraryExists)
check_function_exists(vfork HAVE_VFORK) check_function_exists(vfork HAVE_VFORK)
check_function_exists(backtrace_symbols HAVE_BACKTRACE_SYMBOLS) check_function_exists(backtrace_symbols HAVE_BACKTRACE_SYMBOLS)
check_function_exists(pipe2 HAVE_PIPE2) check_function_exists(pipe2 HAVE_PIPE2)
check_function_exists(dladdr HAVE_DLADDR)
check_library_exists(crypto BIO_f_zlib "" HAVE_BIOZLIB) check_library_exists(crypto BIO_f_zlib "" HAVE_BIOZLIB)
include(GNUInstallDirs) include(GNUInstallDirs)

View File

@ -5,6 +5,7 @@
#cmakedefine HAVE_BACKTRACE_SYMBOLS #cmakedefine HAVE_BACKTRACE_SYMBOLS
#cmakedefine HAVE_PIPE2 #cmakedefine HAVE_PIPE2
#cmakedefine HAVE_VFORK #cmakedefine HAVE_VFORK
#cmakedefine HAVE_DLADDR
#define ICINGA_PREFIX "${CMAKE_INSTALL_PREFIX}" #define ICINGA_PREFIX "${CMAKE_INSTALL_PREFIX}"
#define ICINGA_SYSCONFDIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}" #define ICINGA_SYSCONFDIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}"

View File

@ -20,6 +20,8 @@
#include "base/stacktrace.h" #include "base/stacktrace.h"
#include "base/qstring.h" #include "base/qstring.h"
#include "base/utility.h" #include "base/utility.h"
#include "base/convert.h"
#include <boost/algorithm/string/trim.hpp>
#ifdef HAVE_BACKTRACE_SYMBOLS #ifdef HAVE_BACKTRACE_SYMBOLS
# include <execinfo.h> # include <execinfo.h>
@ -97,6 +99,39 @@ void StackTrace::Initialize(void)
#endif /* _WIN32 */ #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. * 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], '('); char *sym_begin = strchr(messages[i], '(');
if (sym_begin != NULL) { if (sym_begin) {
char *sym_end = strchr(sym_begin, '+'); char *sym_end = strchr(sym_begin, '+');
if (sym_end != NULL) { if (sym_end != NULL) {
@ -128,7 +163,23 @@ void StackTrace::Print(std::ostream& fp, int ignoreFrames) const
if (sym_demangled.IsEmpty()) if (sym_demangled.IsEmpty())
sym_demangled = "<unknown function>"; sym_demangled = "<unknown function>";
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<uintptr_t>(m_Frames[i]) - reinterpret_cast<uintptr_t>(dli.dli_fbase);
message += " (" + Addr2Line(dli.dli_fname, rva) + ")";
}
#endif /* HAVE_DLADDR */
} }
} }

View File

@ -21,6 +21,7 @@
#define STACKTRACE_H #define STACKTRACE_H
#include "base/i2-base.h" #include "base/i2-base.h"
#include "base/qstring.h"
#include <ostream> #include <ostream>
#include <boost/thread/once.hpp> #include <boost/thread/once.hpp>
@ -49,6 +50,7 @@ private:
static boost::once_flag m_OnceFlag; static boost::once_flag m_OnceFlag;
static void Initialize(void); 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); I2_BASE_API std::ostream& operator<<(std::ostream& stream, const StackTrace& trace);