diff options
author | Mike Klein <mtklein@chromium.org> | 2017-08-30 10:23:01 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-08-30 17:50:07 +0000 |
commit | 1b4602bd9b29feaecc6255db5ddc384835d7ee0a (patch) | |
tree | b1bbe6fb104924a20294593e934b67034d15b9d5 /tools | |
parent | f3b46e5193da843cac07d42fdc36c76c05f7fa77 (diff) |
ok, backtrace support on Android
This adds a fallback backtracer for use on Android where <execinfo.h>
ins't present, instead using <unwind.h> to unwind and <dlfcn.h> to
lookup function names and addresses.
lockf() wasn't available until NDK API 24, so I've just no-op'd file
locking on older targets. I tried switching from lockf() to flock(),
but flock() didn't see to _do_ anything, neither on Android nor on my
Mac laptop. I think I should be able to use the lower-level fcntl()
APIs to restore file locking uniformly in a follow-up. The upshot is
until then, we'll have interlaced logs and stack traces on Android
devices unless you set ndk_api=24 in GN.
We need to add a couple build flags to make backtraces useful:
* -funwind-tables makes the call to _Unwind_Backtrace() actually
traverse the call stack. This is a small extra binary size cost.
* -rdynamic makes symbols linked into the main executable visible
to dladdr(). We do this on Linux already for the same reason.
Here's an example where I made aaxfermodes call SK_ABORT():
650 ok, 1 crashed
caught signal SIGABRT while running 'aaxfermodes'
0x76ed936288 [unknown]+308
0x76eec014e0 [unknown]+510811706592
0x76ed367b2c tgkill+8
0x76ed364f50 pthread_kill+68
0x76ed31ff5c raise+28
0x76ed318814 abort+56
0x76edebd070 sk_out_of_memory()+12
0x76ed99f664 AAXfermodesGM::draw_pass(SkCanvas*, AAXfermodesGM::DrawingPass)+96
0x76ed99f4e4 AAXfermodesGM::onDraw(SkCanvas*)+36
0x76ed9e8550 skiagm::GM::drawContent(SkCanvas*)+224
0x76ed9e82ac skiagm::GM::draw(SkCanvas*)+288
0x76ed93b10c GMStream::GMSrc::draw(SkCanvas*)+96
0x76ed937b08 SWDst::draw(Src*)+284
0x76ed936ca0 [unknown]+112
0x76ed939b4c ForkEngine::spawn(std::function<Status ()>)+88
0x76ed934d00 main+2200
0x76ed316598 __libc_init+92
0x76ed93434c [unknown]+510791992140
Change-Id: Ica4849d99a3b97f48d778f4c15a7fa36275b8133
Reviewed-on: https://skia-review.googlesource.com/40802
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Mike Klein <mtklein@chromium.org>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/ok.cpp | 67 |
1 files changed, 58 insertions, 9 deletions
diff --git a/tools/ok.cpp b/tools/ok.cpp index ca99f33a16..eb33439248 100644 --- a/tools/ok.cpp +++ b/tools/ok.cpp @@ -24,11 +24,63 @@ static thread_local const char* tls_currently_running = ""; -#if __has_include(<execinfo.h>) && __has_include(<fcntl.h>) && __has_include(<signal.h>) +#if __has_include(<execinfo.h>) #include <execinfo.h> + + #define CAN_BACKTRACE + static void backtrace(int fd) { + void* stack[128]; + int frames = backtrace(stack, sizeof(stack)/sizeof(*stack)); + backtrace_symbols_fd(stack, frames, fd); + } + +#elif __has_include(<dlfcn.h>) && __has_include(<unwind.h>) + #include <cxxabi.h> + #include <dlfcn.h> + #include <unwind.h> + + #define CAN_BACKTRACE + static void backtrace(int fd) { + FILE* file = fdopen(fd, "a"); + _Unwind_Backtrace([](_Unwind_Context* ctx, void* arg) { + auto file = (FILE*)arg; + if (auto ip = (void*)_Unwind_GetIP(ctx)) { + const char* name = "[unknown]"; + void* addr = nullptr; + Dl_info info; + if (dladdr(ip, &info) && info.dli_sname && info.dli_saddr) { + name = info.dli_sname; + addr = info.dli_saddr; + } + + int ok; + char* demangled = abi::__cxa_demangle(name, nullptr,0, &ok); + if (ok == 0 && demangled) { + name = demangled; + } + + fprintf(file, "\t%p %s+%zu\n", ip, name, (size_t)ip - (size_t)addr); + free(demangled); + } + return _URC_NO_REASON; + }, file); + fflush(file); + } +#endif + +#if defined(CAN_BACKTRACE) && __has_include(<fcntl.h>) && __has_include(<signal.h>) #include <fcntl.h> #include <signal.h> + #if defined(__ANDROID_API__) && __ANDROID_API__ < 24 + // TODO: do all locking manually with fcntl() so we can lock on older Android NDK APIs? + static void lock_fd(int) {} + static void unlock_fd(int) {} + #else + static void lock_fd(int fd) { lockf(fd, F_LOCK, 0); } + static void unlock_fd(int fd) { lockf(fd, F_ULOCK, 0); } + #endif + static int log_fd = 2/*stderr*/; static void log(const char* msg) { @@ -39,7 +91,7 @@ static thread_local const char* tls_currently_running = ""; static void (*original_handlers[32])(int); for (int sig : std::vector<int>{ SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV }) { original_handlers[sig] = signal(sig, [](int sig) { - lockf(log_fd, F_LOCK, 0); + lock_fd(log_fd); log("\ncaught signal "); switch (sig) { #define CASE(s) case s: log(#s); break @@ -53,11 +105,8 @@ static thread_local const char* tls_currently_running = ""; log(" while running '"); log(tls_currently_running); log("'\n"); - - void* stack[128]; - int frames = backtrace(stack, sizeof(stack)/sizeof(*stack)); - backtrace_symbols_fd(stack, frames, log_fd); - lockf(log_fd, F_ULOCK, 0); + backtrace(log_fd); + unlock_fd(log_fd); signal(sig, original_handlers[sig]); raise(sig); @@ -77,13 +126,13 @@ static thread_local const char* tls_currently_running = ""; } void ok_log(const char* msg) { - lockf(log_fd, F_LOCK, 0); + lock_fd(log_fd); log("["); log(tls_currently_running); log("]\t"); log(msg); log("\n"); - lockf(log_fd, F_ULOCK, 0); + unlock_fd(log_fd); } #else |