Add optional linux crash reporting with backtrace (using libbfd)
Notice: To get backtrace too for leak check, you need to define GET_STACK_TRACE in leak_check.cpp, but will slow down STK
This commit is contained in:
parent
c17070209d
commit
6222ce650f
@ -39,6 +39,7 @@ endif()
|
||||
if(UNIX AND NOT APPLE)
|
||||
option(USE_XRANDR "Use xrandr instead of vidmode" ON)
|
||||
option(USE_ASAN "Build with Leak/Address sanitizer" OFF)
|
||||
option(USE_LIBBFD "Use libbfd for crash reporting and leak check" OFF)
|
||||
endif()
|
||||
|
||||
set(STK_SOURCE_DIR "src")
|
||||
@ -364,6 +365,10 @@ if(UNIX AND NOT APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||
target_link_libraries(supertuxkart "-fsanitize=address")
|
||||
endif()
|
||||
if(USE_LIBBFD)
|
||||
add_definitions(-DENABLE_LIBBFD)
|
||||
target_link_libraries(supertuxkart "-lbfd")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# FreeBSD does not search in /usr/local/lib, but at least Freetype is installed there :(
|
||||
|
@ -320,19 +320,201 @@
|
||||
}
|
||||
} // end namespace CrashReporting
|
||||
|
||||
#else
|
||||
#elif ENABLE_LIBBFD
|
||||
// --------------------- Unix version -----------------------
|
||||
/* Derived from addr2line.c from binutils
|
||||
|
||||
addr2line.c -- convert addresses to line number and function name
|
||||
Copyright (C) 1997-2015 Free Software Foundation, Inc.
|
||||
Contributed by Ulrich Lauther <Ulrich.Lauther@mchp.siemens.de>
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 51 Franklin Street - Fifth Floor, Boston,
|
||||
MA 02110-1301, USA. */
|
||||
|
||||
#define PACKAGE 1
|
||||
#define PACKAGE_VERSION 1
|
||||
#include <signal.h>
|
||||
#include <execinfo.h>
|
||||
#include <bfd.h>
|
||||
|
||||
#include "string_utils.hpp"
|
||||
|
||||
namespace CrashReporting
|
||||
{
|
||||
// BFD of current running STK binary, only can be useful
|
||||
// if compiled with debug symbols
|
||||
static bfd *m_stk_bfd = NULL;
|
||||
|
||||
// Symbol table
|
||||
static asymbol **m_syms = NULL;
|
||||
|
||||
// Address in BFD to find file names or function name
|
||||
static bfd_vma m_adress = 0;
|
||||
|
||||
static const char *m_file_name = NULL;
|
||||
static const char *m_function_name = NULL;
|
||||
static unsigned int m_line = 0;
|
||||
static int m_found = 0;
|
||||
|
||||
// Look for an address in a section. This is called via
|
||||
// bfd_map_over_sections.
|
||||
void findAddressInSection(bfd* input, asection *section,
|
||||
void *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
bfd_vma vma = 0;
|
||||
bfd_size_type size = 0;
|
||||
|
||||
if (m_found)
|
||||
return;
|
||||
|
||||
if ((bfd_get_section_flags(m_stk_bfd, section) & SEC_ALLOC) == 0)
|
||||
return;
|
||||
|
||||
vma = bfd_get_section_vma(m_stk_bfd, section);
|
||||
if (m_adress < vma)
|
||||
return;
|
||||
|
||||
size = bfd_section_size(m_stk_bfd, section);
|
||||
if (m_adress >= vma + size)
|
||||
return;
|
||||
|
||||
m_found = bfd_find_nearest_line(m_stk_bfd, section, m_syms,
|
||||
m_adress - vma, &m_file_name, &m_function_name, &m_line);
|
||||
}
|
||||
|
||||
void signalHandler(int signal_no)
|
||||
{
|
||||
if (m_stk_bfd == NULL)
|
||||
{
|
||||
Log::warn("CrashReporting", "Failed loading or missing BFD of "
|
||||
"STK binary, no backtrace available when reporting");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
Log::error("CrashReporting", "STK has crashed! Backtrace info:");
|
||||
std::string stack;
|
||||
getCallStack(stack);
|
||||
|
||||
std::vector<std::string> each = StringUtils::split(stack, '\n');
|
||||
for (unsigned int i = 3; i < each.size(); i++)
|
||||
{
|
||||
// Skip 3 stacks which are crash_reporting doing
|
||||
Log::error("CrashReporting", "%s", each[i].c_str());
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void loadSTKBFD()
|
||||
{
|
||||
const char* path = realpath("/proc/self/exe", NULL);
|
||||
m_stk_bfd = bfd_openr(path, NULL);
|
||||
free((void*)path);
|
||||
|
||||
if (m_stk_bfd == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (bfd_check_format(m_stk_bfd, bfd_archive))
|
||||
{
|
||||
m_stk_bfd = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bfd_check_format(m_stk_bfd, bfd_object))
|
||||
{
|
||||
m_stk_bfd = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Read in the symbol table.
|
||||
unsigned int size = 0;
|
||||
long symcount = 0;
|
||||
|
||||
if ((bfd_get_file_flags(m_stk_bfd) & HAS_SYMS) == 0)
|
||||
{
|
||||
m_stk_bfd = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
symcount = bfd_read_minisymbols(m_stk_bfd, false, (void**)&m_syms,
|
||||
&size);
|
||||
if (symcount == 0)
|
||||
{
|
||||
symcount = bfd_read_minisymbols(m_stk_bfd, true/* dynamic*/,
|
||||
(void**)&m_syms, &size);
|
||||
}
|
||||
|
||||
if (symcount < 0)
|
||||
{
|
||||
m_stk_bfd = NULL;
|
||||
m_syms = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void installHandlers()
|
||||
{
|
||||
// TODO!
|
||||
loadSTKBFD();
|
||||
struct sigaction sa = {0};
|
||||
sa.sa_handler = &signalHandler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
sigaction(SIGUSR1, &sa, NULL);
|
||||
}
|
||||
|
||||
void getCallStack(std::string& callstack)
|
||||
{
|
||||
// TODO!
|
||||
if (m_stk_bfd == NULL) return;
|
||||
|
||||
void *trace[16];
|
||||
int i, trace_size = 0;
|
||||
trace_size = backtrace(trace, 16);
|
||||
for (i = 0; i < trace_size; i++)
|
||||
{
|
||||
m_adress = (bfd_vma)(trace[i]);
|
||||
m_found = 0;
|
||||
m_file_name = NULL;
|
||||
m_function_name = NULL;
|
||||
m_line = 0;
|
||||
|
||||
bfd_map_over_sections(m_stk_bfd, findAddressInSection, NULL);
|
||||
if (m_found && m_file_name != NULL)
|
||||
{
|
||||
callstack = callstack + m_file_name + ":" +
|
||||
StringUtils::toString(m_line) + "\n";
|
||||
}
|
||||
else if (m_function_name != NULL)
|
||||
{
|
||||
callstack = callstack + m_function_name + "\n";
|
||||
}
|
||||
else
|
||||
callstack = callstack + "No symbol found" + "\n";
|
||||
}
|
||||
}
|
||||
} // end namespace CrashReporting
|
||||
|
||||
#else
|
||||
|
||||
namespace CrashReporting
|
||||
{
|
||||
void installHandlers() {}
|
||||
void getCallStack(std::string& callstack) {}
|
||||
} // end namespace CrashReporting
|
||||
|
||||
#endif
|
||||
|
@ -26,8 +26,7 @@
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
/** Switch this to 1 to get the backtrace of the leaks (slows down execution a little)
|
||||
* Atm only implemented for OSX and windows. */
|
||||
/** Define this to get the backtrace of the leaks (slows down execution a little) */
|
||||
#undef GET_STACK_TRACE
|
||||
|
||||
Synchronised<int> m_lock_stacktrace;
|
||||
@ -59,7 +58,7 @@ namespace MemoryLeaks
|
||||
m_stack_size = backtrace(callstack, max_size);
|
||||
|
||||
m_stack = backtrace_symbols(callstack, m_stack_size);
|
||||
# elif defined(WIN32)
|
||||
# elif defined(WIN32) || ENABLE_LIBBFD
|
||||
m_lock_stacktrace.lock();
|
||||
CrashReporting::getCallStack(m_stack);
|
||||
m_lock_stacktrace.unlock();
|
||||
@ -79,7 +78,14 @@ namespace MemoryLeaks
|
||||
void AllocatedObject::print() const
|
||||
{
|
||||
#ifdef GET_STACK_TRACE
|
||||
# if defined(__APPLE__)
|
||||
# if defined ENABLE_LIBBFD
|
||||
std::vector<std::string> calls = StringUtils::split(m_stack, '\n');
|
||||
// Ignore the first 3 entries
|
||||
for (unsigned int i = 3; i < calls.size(); ++i)
|
||||
{
|
||||
Log::error("LeakCheck", " %s", calls[i].c_str());
|
||||
}
|
||||
# elif defined(__APPLE__)
|
||||
for (int i = 0; i < m_stack_size; ++i)
|
||||
{
|
||||
Log::error("LeakCheck", " %s\n", m_stack[i]);
|
||||
|
@ -40,9 +40,9 @@ namespace MemoryLeaks
|
||||
char **m_stack;
|
||||
/** Keeps stacksize information if available (OSX only). */
|
||||
int m_stack_size;
|
||||
#elif defined(WIN32)
|
||||
/** Keep the stack information the way it is returned by windows,
|
||||
* a flat string, which will be split when printing it. */
|
||||
#elif defined(WIN32) || ENABLE_LIBBFD
|
||||
/** Keep the stack information the way it is returned by windows or
|
||||
* libbfd, a flat string, which will be split when printing it. */
|
||||
std::string m_stack;
|
||||
#endif
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user