interface/debug: log_backtrace_chain(): Move backtrace chain logging to a single location

master
Perttu Ahola 2014-10-30 12:56:24 +02:00
parent 0115364cbe
commit 15133b2d91
6 changed files with 95 additions and 51 deletions

View File

@ -1,6 +1,7 @@
// http://www.apache.org/licenses/LICENSE-2.0
// Copyright 2014 Perttu Ahola <celeron55@gmail.com>
#include "interface/debug.h"
#include "interface/mutex.h"
#include "core/log.h"
#include <c55/string_util.h>
#include <stdexcept>
@ -68,7 +69,8 @@ static void* get_library_executable_address(const ss_ &lib_path)
#define REG_EIP REG_RIP
#endif
static void log_backtrace(void* const *trace, int trace_size, const ss_ &title);
static void log_backtrace(void* const *trace, int trace_size, const ss_ &title,
bool use_lock = true);
static void debug_sighandler(int sig, siginfo_t *info, void *secret)
{
@ -103,10 +105,19 @@ void init_signal_handlers(const SigConfig &config)
sigaction(SIGABRT, &sa, NULL);
}
static std::atomic_int log_backtrace_spinlock(0);
static interface::Mutex backtrace_mutex;
static char backtrace_buffer[10000];
static size_t backtrace_buffer_len = 0;
static void bt_print_newline()
{
backtrace_buffer_len += snprintf(
backtrace_buffer + backtrace_buffer_len,
sizeof backtrace_buffer - backtrace_buffer_len,
"\n");
}
static void bt_print(const char *fmt, ...)
{
va_list va_args;
@ -116,28 +127,13 @@ static void bt_print(const char *fmt, ...)
sizeof backtrace_buffer - backtrace_buffer_len,
fmt, va_args);
va_end(va_args);
backtrace_buffer_len += snprintf(
backtrace_buffer + backtrace_buffer_len,
sizeof backtrace_buffer - backtrace_buffer_len,
"\n");
bt_print_newline();
}
static void log_backtrace(void* const *trace, int trace_size, const ss_ &title)
static void bt_print_backtrace(char **symbols, void* const *trace, int trace_size,
int start_from_i = 1)
{
char **symbols = backtrace_symbols(trace, trace_size);
// Lock spinlock
for(;;){
int previous_value = log_backtrace_spinlock.fetch_add(1);
if(previous_value == 0)
break;
log_backtrace_spinlock--;
}
// The first stack frame points to this functiton
backtrace_buffer_len = 0;
bt_print("\n %s", cs(title));
int first_real_i = 1;
int first_real_i = start_from_i;
for(int i = 1; i < trace_size; i++){
char cmdbuf[500];
// Parse symbol to get file name
@ -182,12 +178,36 @@ static void log_backtrace(void* const *trace, int trace_size, const ss_ &title)
}
}
// Remove trailing newline
if(backtrace_buffer[backtrace_buffer_len-1] == '\n'){
backtrace_buffer[backtrace_buffer_len-1] = 0;
backtrace_buffer_len--;
}
}
static void log_backtrace(void* const *trace, int trace_size, const ss_ &title,
bool use_lock)
{
char **symbols = backtrace_symbols(trace, trace_size);
if(use_lock){
// Lock spinlock
backtrace_mutex.lock();
}
backtrace_buffer_len = 0;
bt_print("\n %s", cs(title));
// The first stack frame points to this functiton
bt_print_backtrace(symbols, trace, trace_size, 1);
// Print to log
backtrace_buffer[sizeof backtrace_buffer - 1] = 0;
log_i(MODULE, "%s", backtrace_buffer);
// Unlock spinlock
log_backtrace_spinlock--;
if(use_lock){
// Unlock spinlock
backtrace_mutex.unlock();
}
}
void log_current_backtrace(const ss_ &title)
@ -254,6 +274,35 @@ void log_backtrace(const StoredBacktrace &result, const ss_ &title)
log_backtrace(result.frames, result.num_frames, title);
}
void log_backtrace_chain(const std::list<ThreadBacktrace> &chain,
const char *reason)
{
interface::MutexScope ms(backtrace_mutex);
backtrace_buffer_len = 0;
ss_ ex_name;
bool header_printed = false;
for(const interface::debug::ThreadBacktrace &bt_step : chain){
if(!bt_step.bt.exception_name.empty()){
ex_name = bt_step.bt.exception_name;
}
if(!header_printed){
header_printed = true;
if(!ex_name.empty())
bt_print("\n Backtrace for %s(\"%s\"):", cs(ex_name), reason);
else
bt_print("\n Backtrace for %s:", reason);
}
bt_print(" Thread(%s):", cs(bt_step.thread_name));
char **symbols = backtrace_symbols(bt_step.bt.frames, bt_step.bt.num_frames);
bt_print_backtrace(symbols, bt_step.bt.frames, bt_step.bt.num_frames, 1);
bt_print_newline();
}
// Print to log
backtrace_buffer[sizeof backtrace_buffer - 1] = 0;
log_i(MODULE, "%s", backtrace_buffer);
}
}
}
// vim: set noet ts=4 sw=4:

View File

@ -36,7 +36,7 @@ struct CThread: public Thread
bool m_thread_exists = false;
// Debug data
std::list<ThreadBacktrace> m_backtraces;
std::list<debug::ThreadBacktrace> m_backtraces;
Thread *m_caller_thread = nullptr;
CThread(ThreadedThing *thing)
@ -95,15 +95,8 @@ struct CThread: public Thread
log_w(MODULE, "ThreadThing of thread %p (%s) failed: %s",
arg, cs(thread_name), e.what());
if(!thread->m_backtraces.empty()){
ss_ ex_name;
for(const interface::ThreadBacktrace &bt_step :
thread->m_backtraces){
if(!bt_step.bt.exception_name.empty())
ex_name = bt_step.bt.exception_name;
interface::debug::log_backtrace(bt_step.bt,
"Backtrace in M["+bt_step.thread_name+"] for "+
ex_name+"(\""+e.what()+"\")");
}
interface::debug::log_backtrace_chain(
thread->m_backtraces, e.what());
} else {
interface::debug::StoredBacktrace bt;
interface::debug::get_exception_backtrace(bt);
@ -196,7 +189,7 @@ struct CThread: public Thread
return m_name;
}
std::list<ThreadBacktrace>& ref_backtraces()
std::list<debug::ThreadBacktrace>& ref_backtraces()
{
return m_backtraces;
}

View File

@ -34,6 +34,11 @@ void log_backtrace(const StoredBacktrace &result, const ss_ &title)
{
}
void log_backtrace_chain(const std::list<ThreadBacktrace> &chain,
const char *reason)
{
}
}
}
// vim: set noet ts=4 sw=4:

View File

@ -2,6 +2,7 @@
// Copyright 2014 Perttu Ahola <celeron55@gmail.com>
#pragma once
#include "core/types.h"
#include <list>
namespace interface
{
@ -28,6 +29,14 @@ namespace interface
void log_backtrace(const StoredBacktrace &result,
const ss_ &title="Stored backtrace:");
struct ThreadBacktrace {
ss_ thread_name;
interface::debug::StoredBacktrace bt;
};
void log_backtrace_chain(const std::list<ThreadBacktrace> &chain,
const char *reason);
}
}
// vim: set noet ts=4 sw=4:

View File

@ -16,11 +16,6 @@ namespace interface
virtual void run(interface::Thread *thread) = 0;
};
struct ThreadBacktrace {
ss_ thread_name;
interface::debug::StoredBacktrace bt;
};
struct Thread
{
virtual ~Thread(){}
@ -33,7 +28,7 @@ namespace interface
// Debugging interface (not thread-safe; access only from thread itself)
virtual ss_ get_name() = 0;
virtual std::list<ThreadBacktrace>& ref_backtraces() = 0;
virtual std::list<debug::ThreadBacktrace>& ref_backtraces() = 0;
virtual void set_caller_thread(Thread *thread) = 0;
virtual Thread* get_caller_thread() = 0;

View File

@ -332,7 +332,7 @@ void ModuleThread::handle_direct_cb(
// Insert exception backtrace to original chain initiator's
// backtrace list, IF the list is empty
if(orig_thread->ref_backtraces().empty()){
interface::ThreadBacktrace bt_step;
interface::debug::ThreadBacktrace bt_step;
bt_step.thread_name = current_thread->get_name();
interface::debug::get_exception_backtrace(bt_step.bt);
orig_thread->ref_backtraces().push_back(bt_step);
@ -368,15 +368,8 @@ void ModuleThread::handle_event(Event &event)
log_w(MODULE, "M[%s]->event() failed: %s",
cs(mc->info.name), e.what());
if(!mc->thread->ref_backtraces().empty()){
ss_ ex_name;
for(const interface::ThreadBacktrace &bt_step :
mc->thread->ref_backtraces()){
if(!bt_step.bt.exception_name.empty())
ex_name = bt_step.bt.exception_name;
interface::debug::log_backtrace(bt_step.bt,
"Backtrace in M["+bt_step.thread_name+"] for "+
ex_name+"(\""+e.what()+"\")");
}
interface::debug::log_backtrace_chain(
mc->thread->ref_backtraces(), e.what());
} else {
interface::debug::StoredBacktrace bt;
interface::debug::get_exception_backtrace(bt);
@ -1060,7 +1053,7 @@ struct CState: public State, public interface::Server
}
// Insert backtrace to original chain initiator's backtrace list
interface::ThreadBacktrace bt_step;
interface::debug::ThreadBacktrace bt_step;
bt_step.thread_name = current_thread->get_name();
interface::debug::get_current_backtrace(bt_step.bt);
orig_thread->ref_backtraces().push_back(bt_step);