interface/debug: log_backtrace_chain(): Move backtrace chain logging to a single location
parent
0115364cbe
commit
15133b2d91
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue