Skip to content

Commit 52b8e7f

Browse files
authored
[android] print backtraces on ds2 crashes/errors
## Purpose Add support to print ds2 backtraces on Android from the signal handler to diagnose crashes and fatal errors in DS2 itself. ## Overview * Reuse the existing backtrace plumbing and implement only the glibc `backtrace` functionality missing on Android * Log the module-relative address of each stack frame in addition to the existing information. ## Problem Details No backtraces are currently logged when DS2 crashes or encounters a fatal error on Android because `ds2::utils::PrintBacktrace` function is stubbed-out on platforms without glibc. Instead of glibc, Android provides `libunwind` in the NDK exposed in the `unwind.h` header. ## Validation Manually verified mostly complete backtraces are emitted from signal handler context during a ds2 crash on a Debug. Verified with ds2 built for 4 Android ABIs. x86, x86_64, armeabi-v7a, and arm64-v8a. Example fatal error log (from x86_64): ``` [10853][void ds2::Utils::PrintBacktrace()] ERROR : 0x00005f03b2caed35 <unknown>+0x5f03b2caed35 (/data/local/tmp/ds2+0xa7d35) [10853][void ds2::Utils::PrintBacktrace()] ERROR : 0x00005f03b2cafb88 <unknown>+0x5f03b2cafb88 (/data/local/tmp/ds2+0xa8b88) [10853][void ds2::Utils::PrintBacktrace()] ERROR : 0x00005f03b2cc144f <unknown>+0x5f03b2cc144f (/data/local/tmp/ds2+0xba44f) [10853][void ds2::Utils::PrintBacktrace()] ERROR : 0x00005f03b2c785ed <unknown>+0x5f03b2c785ed (/data/local/tmp/ds2+0x715ed) [10853][void ds2::Utils::PrintBacktrace()] ERROR : 0x00005f03b2c9c59f <unknown>+0x5f03b2c9c59f (/data/local/tmp/ds2+0x9559f) [10853][void ds2::Utils::PrintBacktrace()] ERROR : 0x00005f03b2c84bfe <unknown>+0x5f03b2c84bfe (/data/local/tmp/ds2+0x7dbfe) [10853][void ds2::Utils::PrintBacktrace()] ERROR : 0x00005f03b2c847d2 <unknown>+0x5f03b2c847d2 (/data/local/tmp/ds2+0x7d7d2) [10853][void ds2::Utils::PrintBacktrace()] ERROR : 0x00005f03b2ca2dc8 <unknown>+0x5f03b2ca2dc8 (/data/local/tmp/ds2+0x9bdc8) [10853][void ds2::Utils::PrintBacktrace()] ERROR : 0x00005f03b2c646dd <unknown>+0x5f03b2c646dd (/data/local/tmp/ds2+0x5d6dd) [10853][void ds2::Utils::PrintBacktrace()] ERROR : 0x00005f03b2c60977 <unknown>+0x5f03b2c60977 (/data/local/tmp/ds2+0x59977) [10853][void ds2::Utils::PrintBacktrace()] ERROR : 0x00007be7296c09f0 __libc_init+0x60 (/apex/com.android.runtime/lib64/bionic/libc.so+0x529f0) ``` Addresses relative to the module can be decoded on the build machine with `lldb-symbolizer`: ``` $ llvm-symbolizer --obj=./build/ds2 <stack.txt ds2::Utils::PrintBacktrace() ??:0:0 ds2::Log(int, char const*, char const*, char const*, ...) ??:0:0 ds2::Target::Linux::Process::wait() ??:0:0 ds2::GDBRemote::DebugSessionImplBase::onResume(ds2::GDBRemote::Session&, std::__ndk1::vector<ds2::GDBRemote::ThreadResumeAction, std::__ndk1::allocator<ds2::GDBRemote::ThreadResumeAction>> const&, ds2::GDBRemote::StopInfo&) ??:0:0 ds2::GDBRemote::Session::Handle_vCont(ds2::GDBRemote::ProtocolInterpreter::Handler const&, std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char>> const&) ??:0:0 ds2::GDBRemote::ProtocolInterpreter::onCommand(std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char>> const&, std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char>> const&) ??:0:0 ds2::GDBRemote::ProtocolInterpreter::onPacketData(std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char>> const&, bool) ??:0:0 ds2::GDBRemote::SessionBase::receive(bool) ??:0:0 RunDebugServer(ds2::Host::Channel*, ds2::GDBRemote::SessionDelegate*) main.cpp:0:0 main ??:0:0 ``` NOTE: file location debug information is also shown if ds2 is compiled with `-g`.
1 parent e492429 commit 52b8e7f

File tree

1 file changed

+48
-7
lines changed

1 file changed

+48
-7
lines changed

Sources/Utils/Backtrace.cpp

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#include "DebugServer2/Utils/Backtrace.h"
1212
#include "DebugServer2/Utils/Log.h"
1313

14-
#if defined(OS_DARWIN) || defined(__GLIBC__)
14+
#if defined(ANDROID) || defined(OS_DARWIN) || defined(__GLIBC__)
1515
#include <cxxabi.h>
1616
#include <dlfcn.h>
1717
#include <execinfo.h>
@@ -22,20 +22,59 @@
2222
#include <sstream>
2323
#endif
2424

25+
#if defined(ANDROID)
26+
// Android provides libunwind in the NDK instead of glibc backtrace
27+
#include <unwind.h>
28+
#endif
29+
2530
namespace ds2 {
2631
namespace Utils {
2732

28-
#if defined(OS_DARWIN) || (defined(__GLIBC__) && !defined(PLATFORM_TIZEN))
33+
#if defined(ANDROID)
34+
struct unwind_state {
35+
void **buffer_cursor;
36+
void **buffer_end;
37+
};
38+
39+
static _Unwind_Reason_Code UnwindTrace(struct _Unwind_Context* context,
40+
void* arg) {
41+
struct unwind_state* state = reinterpret_cast<struct unwind_state*>(arg);
42+
uintptr_t ip = _Unwind_GetIP(context);
43+
if (ip != 0) {
44+
if (state->buffer_cursor >= state->buffer_end)
45+
return _URC_END_OF_STACK; // Backtrace will be truncated
46+
47+
*(state->buffer_cursor++) = reinterpret_cast<void*>(ip);
48+
}
49+
return _URC_NO_REASON;
50+
}
51+
52+
// An approximation of glibc's backtrace using _Unwind_Backtrace
53+
static int UnwindBacktrace(void *stack_buffer[], int stack_size) {
54+
unwind_state state = {
55+
.buffer_cursor = stack_buffer,
56+
.buffer_end = stack_buffer + stack_size,
57+
};
58+
59+
_Unwind_Backtrace(UnwindTrace, &state);
60+
return state.buffer_cursor - stack_buffer;
61+
}
62+
#elif defined(OS_DARWIN) || (defined(__GLIBC__) && !defined(PLATFORM_TIZEN))
63+
// Forward to glibc's backtrace
64+
static int UnwindBacktrace(void *stack_buffer[], int stack_size) {
65+
return ::backtrace(stack_buffer, stack_size);
66+
}
67+
#endif
68+
69+
#if defined(ANDROID) || defined(OS_DARWIN) || (defined(__GLIBC__) && !defined(PLATFORM_TIZEN))
2970
static void PrintBacktraceEntrySimple(void *address) {
3071
DS2LOG(Error, "%" PRI_PTR, PRI_PTR_CAST(address));
3172
}
32-
#endif
3373

34-
#if defined(OS_DARWIN) || (defined(__GLIBC__) && !defined(PLATFORM_TIZEN))
3574
void PrintBacktrace() {
3675
static const int kStackSize = 100;
3776
static void *stack[kStackSize];
38-
int stackEntries = ::backtrace(stack, kStackSize);
77+
int stackEntries = UnwindBacktrace(stack, kStackSize);
3978

4079
for (int i = 0; i < stackEntries; ++i) {
4180
Dl_info info;
@@ -60,10 +99,12 @@ void PrintBacktrace() {
6099
name = "<unknown>";
61100
}
62101

63-
DS2LOG(Error, "%" PRI_PTR " %s+%#" PRIxPTR " (%s)", PRI_PTR_CAST(stack[i]),
102+
DS2LOG(Error, "%" PRI_PTR " %s+%#" PRIxPTR " (%s+%#" PRIxPTR ")",
103+
PRI_PTR_CAST(stack[i]),
64104
name,
65105
static_cast<char *>(stack[i]) - static_cast<char *>(info.dli_saddr),
66-
info.dli_fname);
106+
info.dli_fname,
107+
static_cast<char *>(stack[i]) - static_cast<char *>(info.dli_fbase));
67108

68109
::free(demangled);
69110
}

0 commit comments

Comments
 (0)