mirror of
https://github.com/RetroShare/libretroshare.git
synced 2026-09-14 11:05:45 +05:00
Add option to use Cpptrace to print stack trace
Cpptrace works also on platforms libretroshare did lack print_stacktrace implementation, and display very nice colored stack traces Move implementation details into rsstacktrace.cc keeping header lean and mean to reduce compile time and binary size (skip first frame instead of inlining the function around)
This commit is contained in:
parent
96169cac56
commit
954178f813
@ -159,11 +159,18 @@ cmake_dependent_option(
|
||||
# doesn't make the library fat as the debugging symbols are stored
|
||||
# separately, enable us to symbolicate crash reports produced by release builds
|
||||
# @see https://www.productive-cpp.com/improving-cpp-builds-with-split-dwarf/
|
||||
# https://web.archive.org/web/20231127210015/https://www.productive-cpp.com/improving-cpp-builds-with-split-dwarf/
|
||||
option(
|
||||
RS_SPLIT_DEBUG
|
||||
"Generate split debug symbols, useful for debugabble release builds"
|
||||
OFF )
|
||||
|
||||
option(
|
||||
RS_CPPTRACE_STACKTRACE
|
||||
"Use Jeremy Rifkin Cpptrace library to print stacktrace instead of \
|
||||
our implementation"
|
||||
OFF )
|
||||
|
||||
set(
|
||||
RS_MAJOR_VERSION
|
||||
""
|
||||
@ -702,3 +709,20 @@ endif()
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION ON)
|
||||
endif()
|
||||
|
||||
################################################################################
|
||||
|
||||
if(RS_CPPTRACE_STACKTRACE)
|
||||
FetchContent_Declare(
|
||||
cpptrace
|
||||
GIT_REPOSITORY https://github.com/jeremy-rifkin/cpptrace.git
|
||||
GIT_TAG v0.3.1
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_PROGRESS TRUE
|
||||
TIMEOUT 10
|
||||
)
|
||||
FetchContent_MakeAvailable(cpptrace)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE cpptrace::cpptrace)
|
||||
target_compile_definitions(
|
||||
${LIBRARY_NAME} PRIVATE RS_JEREMY_RIFKIN_CPPTRACE )
|
||||
endif(RS_CPPTRACE_STACKTRACE)
|
||||
|
||||
@ -613,6 +613,7 @@ list(
|
||||
util/rsdnsutils.cc
|
||||
util/rsnet.cc
|
||||
util/rsnet_ss.cc
|
||||
util/rsstacktrace.cc
|
||||
util/rsthreads.cc )
|
||||
|
||||
# util/i2pcommon.cpp
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# SPDX-FileCopyrightText: (C) 2004-2021 Retroshare Team <contact@retroshare.cc>
|
||||
# SPDX-FileCopyrightText: (C) 2004-2024 Retroshare Team <contact@retroshare.cc>
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri")
|
||||
@ -658,6 +658,7 @@ SOURCES += util/folderiterator.cc \
|
||||
util/rsrandom.cc \
|
||||
util/rstickevent.cc \
|
||||
util/rsrecogn.cc \
|
||||
util/rsstacktrace.cc \
|
||||
util/rstime.cc \
|
||||
util/rsurl.cc \
|
||||
util/rsbase64.cc
|
||||
|
||||
313
src/util/rsstacktrace.cc
Normal file
313
src/util/rsstacktrace.cc
Normal file
@ -0,0 +1,313 @@
|
||||
/*******************************************************************************
|
||||
* libretroshare *
|
||||
* *
|
||||
* Copyright (C) 2016-2024 Gioacchino Mazzurco <gio@retroshare.cc>
|
||||
* Copyright (C) 2024 Asociación Civil Altermundi <info@altermundi.net>
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, 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 Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#include <cstdio>
|
||||
#include <csignal>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "util/stacktrace.h"
|
||||
|
||||
#if defined(RS_JEREMY_RIFKIN_CPPTRACE)
|
||||
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
|
||||
void print_stacktrace(
|
||||
bool /*demangle*/, FILE* /*out*/, unsigned int maxFrames )
|
||||
{
|
||||
cpptrace::generate_trace(1, maxFrames).print();
|
||||
}
|
||||
|
||||
#elif defined(__linux__) && defined(__GLIBC__)
|
||||
|
||||
#include <execinfo.h>
|
||||
#include <cxxabi.h>
|
||||
|
||||
/* Freely inspired by Timo Bingmann implementation
|
||||
* https://panthema.net/2008/0901-stacktrace-demangled/
|
||||
* https://web.archive.org/web/20230815072644/https://panthema.net/2008/0901-stacktrace-demangled/
|
||||
*/
|
||||
void print_stacktrace(
|
||||
bool demangle, FILE* out, unsigned int maxFrames )
|
||||
{
|
||||
if(!out)
|
||||
{
|
||||
fprintf(stderr, "print_stacktrace invalid output file!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(out, "stack trace:\n");
|
||||
|
||||
// storage array for stack trace address data
|
||||
void* addrlist[maxFrames+1];
|
||||
|
||||
// retrieve current stack addresses
|
||||
int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));
|
||||
|
||||
if (addrlen == 0)
|
||||
{
|
||||
fprintf(out, " <empty, possibly corrupt>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Skip first address which is print_stacktrace return address itself */
|
||||
auto callerRetPtr = addrlist + 1;
|
||||
|
||||
if(!demangle)
|
||||
{
|
||||
int outFd = fileno(out);
|
||||
if(outFd < 0)
|
||||
{
|
||||
fprintf(stderr, "print_stacktrace invalid output file descriptor!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
backtrace_symbols_fd(callerRetPtr, addrlen, outFd);
|
||||
return;
|
||||
}
|
||||
|
||||
// resolve addresses into strings containing "filename(function+address)",
|
||||
// this array must be free()-ed
|
||||
char** symbollist = backtrace_symbols(callerRetPtr, addrlen);
|
||||
|
||||
// allocate string which will be filled with the demangled function name
|
||||
size_t funcnamesize = 256;
|
||||
char* funcname = (char*)malloc(funcnamesize);
|
||||
|
||||
// iterate over the returned symbol lines. skip the first, it is
|
||||
// the address of this function.
|
||||
for (int i = 1; i < addrlen; i++)
|
||||
{
|
||||
char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
|
||||
|
||||
/* find parentheses and +address offset surrounding the mangled
|
||||
* name: ./module(function+0x15c) [0x8048a6d] */
|
||||
for (char *p = symbollist[i]; *p; ++p)
|
||||
{
|
||||
if (*p == '(') begin_name = p;
|
||||
else if (*p == '+') begin_offset = p;
|
||||
else if (*p == ')' && begin_offset)
|
||||
{
|
||||
end_offset = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( begin_name && begin_offset && end_offset
|
||||
&& begin_name < begin_offset )
|
||||
{
|
||||
*begin_name++ = '\0';
|
||||
*begin_offset++ = '\0';
|
||||
*end_offset = '\0';
|
||||
|
||||
// mangled name is now in [begin_name, begin_offset) and caller
|
||||
// offset in [begin_offset, end_offset). now apply
|
||||
// __cxa_demangle():
|
||||
|
||||
int status;
|
||||
char* ret = abi::__cxa_demangle(
|
||||
begin_name, funcname, &funcnamesize, &status );
|
||||
if (status == 0)
|
||||
{
|
||||
funcname = ret; // use possibly realloc()-ed string
|
||||
fprintf( out, " %s : %s+%s\n",
|
||||
symbollist[i], funcname, begin_offset );
|
||||
}
|
||||
else
|
||||
{
|
||||
// demangling failed. Output function name as a C function
|
||||
// with no arguments.
|
||||
fprintf( out, " %s : %s()+%s\n",
|
||||
symbollist[i], begin_name, begin_offset );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// couldn't parse the line? print the whole line.
|
||||
fprintf(out, " %s\n", symbollist[i]);
|
||||
}
|
||||
}
|
||||
|
||||
free(funcname);
|
||||
free(symbollist);
|
||||
}
|
||||
#elif defined(__ANDROID__) // defined(__linux__) && defined(__GLIBC__)
|
||||
|
||||
/* Freely inspired by the solution proposed by Louis Semprini on this thread
|
||||
* https://stackoverflow.com/questions/8115192/android-ndk-getting-the-backtrace/35586148
|
||||
* https://web.archive.org/web/20240121102501/https://stackoverflow.com/questions/8115192/android-ndk-getting-the-backtrace/35586148
|
||||
*/
|
||||
|
||||
#include <unwind.h>
|
||||
#include <dlfcn.h>
|
||||
#include <cxxabi.h>
|
||||
|
||||
#include "util/rsdebug.h"
|
||||
|
||||
struct RsAndroidBacktraceState
|
||||
{
|
||||
void** current;
|
||||
void** end;
|
||||
};
|
||||
|
||||
static _Unwind_Reason_Code android_unwind_callback(
|
||||
struct _Unwind_Context* context, void* arg )
|
||||
{
|
||||
RsAndroidBacktraceState* state = static_cast<RsAndroidBacktraceState*>(arg);
|
||||
uintptr_t pc = _Unwind_GetIP(context);
|
||||
if(pc)
|
||||
{
|
||||
if (state->current == state->end) return _URC_END_OF_STACK;
|
||||
|
||||
*state->current++ = reinterpret_cast<void*>(pc);
|
||||
}
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
void print_stacktrace(
|
||||
bool demangle, FILE* /*out*/, unsigned int /*maxFrames*/)
|
||||
{
|
||||
constexpr int max = 5000;
|
||||
void* buffer[max];
|
||||
|
||||
RsAndroidBacktraceState state;
|
||||
state.current = buffer;
|
||||
state.end = buffer + max;
|
||||
|
||||
_Unwind_Backtrace(android_unwind_callback, &state);
|
||||
|
||||
RsDbg() << std::endl << std::endl
|
||||
<< 0 << " " << buffer[0] << " " << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
// Skip first frame which is print_stacktrace
|
||||
int count = static_cast<int>(state.current - buffer);
|
||||
for(int idx = 1; idx < count; ++idx)
|
||||
{
|
||||
const void* addr = buffer[idx];
|
||||
|
||||
/* Ignore null addresses.
|
||||
* They sometimes happen when using _Unwind_Backtrace()
|
||||
* with compiler optimizations, when the Link Register is overwritten
|
||||
* by the inner stack frames. */
|
||||
if(!addr) continue;
|
||||
|
||||
/* Ignore duplicate addresses.
|
||||
* They sometimes happen when using _Unwind_Backtrace() with compiler
|
||||
* optimizations. */
|
||||
if(addr == buffer[idx-1]) continue;
|
||||
|
||||
Dl_info info;
|
||||
if( !(dladdr(addr, &info) && info.dli_sname) )
|
||||
{
|
||||
RsDbg() << idx << " " << addr << " " << info.dli_fname
|
||||
<< " symbol not found" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(demangle)
|
||||
{
|
||||
int status = 0;
|
||||
char* demangled = __cxxabiv1::__cxa_demangle(
|
||||
info.dli_sname, nullptr, nullptr, &status );
|
||||
|
||||
if(demangled && (status == 0))
|
||||
RsDbg() << idx << " " << addr << " " << demangled << std::endl;
|
||||
else
|
||||
RsDbg() << idx << " " << addr << " "
|
||||
<< (info.dli_sname ? info.dli_sname : info.dli_fname)
|
||||
<< " __cxa_demangle failed with: " << status
|
||||
<< std::endl;
|
||||
|
||||
free(demangled);
|
||||
}
|
||||
else RsDbg() << idx << " " << addr << " "
|
||||
<< (info.dli_sname ? info.dli_sname : info.dli_fname)
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
RsDbg() << std::endl << std::endl;
|
||||
}
|
||||
|
||||
#else // defined(__linux__) && defined(__GLIBC__)
|
||||
|
||||
void print_stacktrace(
|
||||
bool /*demangle*/, FILE* out, unsigned int /*max_frames*/ )
|
||||
{
|
||||
/** Notify the user which signal was caught. We use printf, because this
|
||||
* is the most basic output function. Once you get a crash, it is
|
||||
* possible that more complex output systems like streams and the like
|
||||
* may be corrupted. So we make the most basic call possible
|
||||
* to the lowest level, most standard print function. */
|
||||
fprintf(out, "print_stacktrace Not implemented yet for this platform\n");
|
||||
}
|
||||
#endif // defined(__linux__) && defined(__GLIBC__)
|
||||
|
||||
|
||||
/* Freely inspired to:
|
||||
* https://oroboro.com/stack-trace-on-crash/
|
||||
* https://web.archive.org/web/20221005052001/https://oroboro.com/stack-trace-on-crash/
|
||||
*/
|
||||
CrashStackTrace::CrashStackTrace()
|
||||
{
|
||||
signal(SIGABRT, &CrashStackTrace::abortHandler);
|
||||
signal(SIGSEGV, &CrashStackTrace::abortHandler);
|
||||
signal(SIGILL, &CrashStackTrace::abortHandler);
|
||||
signal(SIGFPE, &CrashStackTrace::abortHandler);
|
||||
#ifdef SIGBUS
|
||||
signal(SIGBUS, &CrashStackTrace::abortHandler);
|
||||
#endif
|
||||
}
|
||||
|
||||
[[ noreturn ]]
|
||||
/*static*/ void CrashStackTrace::abortHandler(int signum)
|
||||
{
|
||||
// associate each signal with a signal name string.
|
||||
const char* name = nullptr;
|
||||
switch(signum)
|
||||
{
|
||||
case SIGABRT: name = "SIGABRT"; break;
|
||||
case SIGSEGV: name = "SIGSEGV"; break;
|
||||
case SIGILL: name = "SIGILL"; break;
|
||||
case SIGFPE: name = "SIGFPE"; break;
|
||||
#ifdef SIGBUS
|
||||
case SIGBUS: name = "SIGBUS"; break;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef __ANDROID__
|
||||
/** Notify the user which signal was caught. We use fprintf, because this
|
||||
* is the most basic output function. Once you get a crash, it is
|
||||
* possible that more complex output systems like streams and the like
|
||||
* may be corrupted. So we make the most basic call possible
|
||||
* to the lowest level, most standard print function. */
|
||||
if(name)
|
||||
fprintf(stderr, "Caught signal %d (%s)\n", signum, name);
|
||||
else
|
||||
fprintf(stderr, "Caught signal %d\n", signum);
|
||||
#else // ndef __ANDROID__
|
||||
/** On Android the best we can to is to rely on RS debug utils */
|
||||
RsFatal() << __PRETTY_FUNCTION__ << " Caught signal " << signum << " "
|
||||
<< (name ? name : "") << std::endl;
|
||||
#endif
|
||||
|
||||
print_stacktrace(false);
|
||||
|
||||
exit(-signum);
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
/*******************************************************************************
|
||||
* libretroshare *
|
||||
* *
|
||||
* Copyright (C) 2016-2022 Gioacchino Mazzurco <gio@retroshare.cc> *
|
||||
* Copyright (C) 2008 Timo Bingmann http://idlebox.net/ *
|
||||
* Copyright (C) 2016-2024 Gioacchino Mazzurco <gio@retroshare.cc> *
|
||||
* Copyright (C) 2024 Asociación Civil Altermundi <info@altermundi.net>
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
@ -21,12 +21,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <csignal>
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
# include "util/rsdebug.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Print a backtrace to FILE* out.
|
||||
@ -37,275 +32,18 @@
|
||||
* @param[in] out output file
|
||||
* @param[in] maxFrames maximum number of stack frames you want to bu printed
|
||||
*/
|
||||
static void print_stacktrace(
|
||||
void print_stacktrace(
|
||||
bool demangle = true, FILE *out = stderr, unsigned int maxFrames = 63 );
|
||||
|
||||
|
||||
#if defined(__linux__) && defined(__GLIBC__)
|
||||
|
||||
#include <execinfo.h>
|
||||
#include <cxxabi.h>
|
||||
|
||||
static void print_stacktrace(
|
||||
bool demangle, FILE* out, unsigned int maxFrames )
|
||||
{
|
||||
if(!out)
|
||||
{
|
||||
fprintf(stderr, "print_stacktrace invalid output file!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(out, "stack trace:\n");
|
||||
|
||||
// storage array for stack trace address data
|
||||
void* addrlist[maxFrames+1];
|
||||
|
||||
// retrieve current stack addresses
|
||||
int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));
|
||||
|
||||
if (addrlen == 0)
|
||||
{
|
||||
fprintf(out, " <empty, possibly corrupt>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!demangle)
|
||||
{
|
||||
int outFd = fileno(out);
|
||||
if(outFd < 0)
|
||||
{
|
||||
fprintf(stderr, "print_stacktrace invalid output file descriptor!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
backtrace_symbols_fd(addrlist, addrlen, outFd);
|
||||
return;
|
||||
}
|
||||
|
||||
// resolve addresses into strings containing "filename(function+address)",
|
||||
// this array must be free()-ed
|
||||
char** symbollist = backtrace_symbols(addrlist, addrlen);
|
||||
|
||||
// allocate string which will be filled with the demangled function name
|
||||
size_t funcnamesize = 256;
|
||||
char* funcname = (char*)malloc(funcnamesize);
|
||||
|
||||
// iterate over the returned symbol lines. skip the first, it is
|
||||
// the address of this function.
|
||||
for (int i = 1; i < addrlen; i++)
|
||||
{
|
||||
char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
|
||||
|
||||
/* find parentheses and +address offset surrounding the mangled
|
||||
* name: ./module(function+0x15c) [0x8048a6d] */
|
||||
for (char *p = symbollist[i]; *p; ++p)
|
||||
{
|
||||
if (*p == '(') begin_name = p;
|
||||
else if (*p == '+') begin_offset = p;
|
||||
else if (*p == ')' && begin_offset)
|
||||
{
|
||||
end_offset = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( begin_name && begin_offset && end_offset
|
||||
&& begin_name < begin_offset )
|
||||
{
|
||||
*begin_name++ = '\0';
|
||||
*begin_offset++ = '\0';
|
||||
*end_offset = '\0';
|
||||
|
||||
// mangled name is now in [begin_name, begin_offset) and caller
|
||||
// offset in [begin_offset, end_offset). now apply
|
||||
// __cxa_demangle():
|
||||
|
||||
int status;
|
||||
char* ret = abi::__cxa_demangle(
|
||||
begin_name, funcname, &funcnamesize, &status );
|
||||
if (status == 0)
|
||||
{
|
||||
funcname = ret; // use possibly realloc()-ed string
|
||||
fprintf( out, " %s : %s+%s\n",
|
||||
symbollist[i], funcname, begin_offset );
|
||||
}
|
||||
else
|
||||
{
|
||||
// demangling failed. Output function name as a C function
|
||||
// with no arguments.
|
||||
fprintf( out, " %s : %s()+%s\n",
|
||||
symbollist[i], begin_name, begin_offset );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// couldn't parse the line? print the whole line.
|
||||
fprintf(out, " %s\n", symbollist[i]);
|
||||
}
|
||||
}
|
||||
|
||||
free(funcname);
|
||||
free(symbollist);
|
||||
}
|
||||
#elif defined(__ANDROID__) // defined(__linux__) && defined(__GLIBC__)
|
||||
|
||||
/* Inspired by the solution proposed by Louis Semprini on this thread
|
||||
* https://stackoverflow.com/questions/8115192/android-ndk-getting-the-backtrace/35586148
|
||||
*/
|
||||
|
||||
#include <unwind.h>
|
||||
#include <dlfcn.h>
|
||||
#include <cxxabi.h>
|
||||
|
||||
struct RsAndroidBacktraceState
|
||||
{
|
||||
void** current;
|
||||
void** end;
|
||||
};
|
||||
|
||||
static _Unwind_Reason_Code android_unwind_callback(
|
||||
struct _Unwind_Context* context, void* arg )
|
||||
{
|
||||
RsAndroidBacktraceState* state = static_cast<RsAndroidBacktraceState*>(arg);
|
||||
uintptr_t pc = _Unwind_GetIP(context);
|
||||
if(pc)
|
||||
{
|
||||
if (state->current == state->end) return _URC_END_OF_STACK;
|
||||
|
||||
*state->current++ = reinterpret_cast<void*>(pc);
|
||||
}
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
static void print_stacktrace(
|
||||
bool demangle, FILE* /*out*/, unsigned int /*maxFrames*/)
|
||||
{
|
||||
constexpr int max = 5000;
|
||||
void* buffer[max];
|
||||
|
||||
RsAndroidBacktraceState state;
|
||||
state.current = buffer;
|
||||
state.end = buffer + max;
|
||||
|
||||
_Unwind_Backtrace(android_unwind_callback, &state);
|
||||
|
||||
RsDbg() << std::endl << std::endl
|
||||
<< 0 << " " << buffer[0] << " " << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
// Skip first frame which is print_stacktrace
|
||||
int count = static_cast<int>(state.current - buffer);
|
||||
for(int idx = 1; idx < count; ++idx)
|
||||
{
|
||||
const void* addr = buffer[idx];
|
||||
|
||||
/* Ignore null addresses.
|
||||
* They sometimes happen when using _Unwind_Backtrace()
|
||||
* with compiler optimizations, when the Link Register is overwritten
|
||||
* by the inner stack frames. */
|
||||
if(!addr) continue;
|
||||
|
||||
/* Ignore duplicate addresses.
|
||||
* They sometimes happen when using _Unwind_Backtrace() with compiler
|
||||
* optimizations. */
|
||||
if(addr == buffer[idx-1]) continue;
|
||||
|
||||
Dl_info info;
|
||||
if( !(dladdr(addr, &info) && info.dli_sname) )
|
||||
{
|
||||
RsDbg() << idx << " " << addr << " " << info.dli_fname
|
||||
<< " symbol not found" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(demangle)
|
||||
{
|
||||
int status = 0;
|
||||
char* demangled = __cxxabiv1::__cxa_demangle(
|
||||
info.dli_sname, nullptr, nullptr, &status );
|
||||
|
||||
if(demangled && (status == 0))
|
||||
RsDbg() << idx << " " << addr << " " << demangled << std::endl;
|
||||
else
|
||||
RsDbg() << idx << " " << addr << " "
|
||||
<< (info.dli_sname ? info.dli_sname : info.dli_fname)
|
||||
<< " __cxa_demangle failed with: " << status
|
||||
<< std::endl;
|
||||
|
||||
free(demangled);
|
||||
}
|
||||
else RsDbg() << idx << " " << addr << " "
|
||||
<< (info.dli_sname ? info.dli_sname : info.dli_fname)
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
RsDbg() << std::endl << std::endl;
|
||||
}
|
||||
|
||||
#else // defined(__linux__) && defined(__GLIBC__)
|
||||
|
||||
static void print_stacktrace(
|
||||
bool /*demangle*/, FILE* out, unsigned int /*max_frames*/ )
|
||||
{
|
||||
/** Notify the user which signal was caught. We use printf, because this
|
||||
* is the most basic output function. Once you get a crash, it is
|
||||
* possible that more complex output systems like streams and the like
|
||||
* may be corrupted. So we make the most basic call possible
|
||||
* to the lowest level, most standard print function. */
|
||||
fprintf(out, "print_stacktrace Not implemented yet for this platform\n");
|
||||
}
|
||||
#endif // defined(__linux__) && defined(__GLIBC__)
|
||||
|
||||
/**
|
||||
* @brief CrashStackTrace catch crash signals and print stack trace
|
||||
* Inspired too https://oroboro.com/stack-trace-on-crash/
|
||||
* Place an instance of this in your main file to get stacktraces printed
|
||||
* automatically on crash
|
||||
*/
|
||||
struct CrashStackTrace
|
||||
{
|
||||
CrashStackTrace()
|
||||
{
|
||||
signal(SIGABRT, &CrashStackTrace::abortHandler);
|
||||
signal(SIGSEGV, &CrashStackTrace::abortHandler);
|
||||
signal(SIGILL, &CrashStackTrace::abortHandler);
|
||||
signal(SIGFPE, &CrashStackTrace::abortHandler);
|
||||
#ifdef SIGBUS
|
||||
signal(SIGBUS, &CrashStackTrace::abortHandler);
|
||||
#endif
|
||||
}
|
||||
CrashStackTrace();
|
||||
|
||||
[[ noreturn ]]
|
||||
static void abortHandler(int signum)
|
||||
{
|
||||
// associate each signal with a signal name string.
|
||||
const char* name = nullptr;
|
||||
switch(signum)
|
||||
{
|
||||
case SIGABRT: name = "SIGABRT"; break;
|
||||
case SIGSEGV: name = "SIGSEGV"; break;
|
||||
case SIGILL: name = "SIGILL"; break;
|
||||
case SIGFPE: name = "SIGFPE"; break;
|
||||
#ifdef SIGBUS
|
||||
case SIGBUS: name = "SIGBUS"; break;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef __ANDROID__
|
||||
/** Notify the user which signal was caught. We use printf, because this
|
||||
* is the most basic output function. Once you get a crash, it is
|
||||
* possible that more complex output systems like streams and the like
|
||||
* may be corrupted. So we make the most basic call possible
|
||||
* to the lowest level, most standard print function. */
|
||||
if(name)
|
||||
fprintf(stderr, "Caught signal %d (%s)\n", signum, name);
|
||||
else
|
||||
fprintf(stderr, "Caught signal %d\n", signum);
|
||||
#else // ndef __ANDROID__
|
||||
/** On Android the best we can to is to rely on RS debug utils */
|
||||
RsFatal() << __PRETTY_FUNCTION__ << " Caught signal " << signum << " "
|
||||
<< (name ? name : "") << std::endl;
|
||||
#endif
|
||||
|
||||
print_stacktrace(false);
|
||||
|
||||
exit(-signum);
|
||||
}
|
||||
static void abortHandler(int signum);
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user