mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-05-09 09:35:32 -04:00
Implement stracktrace for Android
Tested both on armeabi and arm64
This commit is contained in:
parent
5381f58707
commit
3820e324b0
1 changed files with 122 additions and 12 deletions
|
@ -23,12 +23,10 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#if defined(__linux__) && defined(__GLIBC__)
|
#ifdef __ANDROID__
|
||||||
|
# include "util/rsdebug.h"
|
||||||
#include <execinfo.h>
|
#endif
|
||||||
#include <cxxabi.h>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Print a backtrace to FILE* out.
|
* @brief Print a backtrace to FILE* out.
|
||||||
|
@ -40,7 +38,16 @@
|
||||||
* @param[in] maxFrames maximum number of stack frames you want to bu printed
|
* @param[in] maxFrames maximum number of stack frames you want to bu printed
|
||||||
*/
|
*/
|
||||||
static inline void print_stacktrace(
|
static inline void print_stacktrace(
|
||||||
bool demangle = true, FILE *out = stderr, unsigned int maxFrames = 63 )
|
bool demangle = true, FILE *out = stderr, unsigned int maxFrames = 63 );
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__linux__) && defined(__GLIBC__)
|
||||||
|
|
||||||
|
#include <execinfo.h>
|
||||||
|
#include <cxxabi.h>
|
||||||
|
|
||||||
|
static inline void print_stacktrace(
|
||||||
|
bool demangle, FILE* out, unsigned int maxFrames )
|
||||||
{
|
{
|
||||||
if(!out)
|
if(!out)
|
||||||
{
|
{
|
||||||
|
@ -140,15 +147,111 @@ static inline void print_stacktrace(
|
||||||
free(funcname);
|
free(funcname);
|
||||||
free(symbollist);
|
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 inline _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 inline 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__)
|
#else // defined(__linux__) && defined(__GLIBC__)
|
||||||
static inline void print_stacktrace(
|
|
||||||
bool demangle = true, FILE *out = stderr, unsigned int max_frames = 63 )
|
|
||||||
{
|
|
||||||
(void) demangle;
|
|
||||||
(void) max_frames;
|
|
||||||
|
|
||||||
fprintf(out, "TODO: 2016/01/01 print_stacktrace not implemented yet for WINDOWS_SYS and ANDROID\n");
|
static inline 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__)
|
#endif // defined(__linux__) && defined(__GLIBC__)
|
||||||
|
|
||||||
|
@ -169,6 +272,7 @@ struct CrashStackTrace
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[ noreturn ]]
|
||||||
static void abortHandler(int signum)
|
static void abortHandler(int signum)
|
||||||
{
|
{
|
||||||
// associate each signal with a signal name string.
|
// associate each signal with a signal name string.
|
||||||
|
@ -184,6 +288,7 @@ struct CrashStackTrace
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef __ANDROID__
|
||||||
/** Notify the user which signal was caught. We use printf, because this
|
/** 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
|
* is the most basic output function. Once you get a crash, it is
|
||||||
* possible that more complex output systems like streams and the like
|
* possible that more complex output systems like streams and the like
|
||||||
|
@ -193,6 +298,11 @@ struct CrashStackTrace
|
||||||
fprintf(stderr, "Caught signal %d (%s)\n", signum, name);
|
fprintf(stderr, "Caught signal %d (%s)\n", signum, name);
|
||||||
else
|
else
|
||||||
fprintf(stderr, "Caught signal %d\n", signum);
|
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);
|
print_stacktrace(false);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue