-
Notifications
You must be signed in to change notification settings - Fork 205
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(ndk): Switch unwinders based on required async signal-safety
When capturing a stacktrace from a signal handler or C++ terminate handler different unwinders deadlock on different architectures and/or Android API levels. This change uses different unwinders based on whether async signal safety is required or not, by supported API levels. It introduces libunwindstack as the signal-safe unwinder for API 15+ on ARM64 and x86/x64 devices. For notify()/C++ exceptions, use libunwind, nongnu libunwind, or libcorkscrew depending on the API level. * libcorkscrew hangs when unwinding from a C++ exception on ARM 32-bit. * libunwind hangs on ARM64 from a signal handler * nongnu libunwind hangs on ARM32 from a signal handler if raise() is called directly
- Loading branch information
Showing
14 changed files
with
206 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "ndk/src/main/jni/external/libunwindstack"] | ||
path = ndk/src/main/jni/external/libunwindstack | ||
url = https://github.com/ivanarh/libunwindstack-ndk |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Submodule libunwindstack
added at
0717e9
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#include "../utils/string.h" | ||
#include "stack_unwinder_libunwindstack.h" | ||
#include <stdlib.h> | ||
#include <ucontext.h> | ||
#include <unwindstack/Elf.h> | ||
#include <unwindstack/MapInfo.h> | ||
#include <unwindstack/Maps.h> | ||
#include <unwindstack/Memory.h> | ||
#include <unwindstack/Regs.h> | ||
|
||
ssize_t | ||
bsg_unwind_stack_libunwindstack(bsg_stackframe stacktrace[BUGSNAG_FRAMES_MAX], | ||
siginfo_t *info, void *user_context) { | ||
if (user_context == NULL) { | ||
return 0; // only handle unwinding from signals | ||
} | ||
|
||
const std::unique_ptr<unwindstack::Regs> regs( | ||
unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), | ||
user_context)); | ||
|
||
// if (user_context != NULL) { | ||
// regs = unwindstack::Regs::CreateFromUcontext( | ||
// unwindstack::Regs::CurrentArch(), user_context); | ||
//} else { | ||
// regs = unwindstack::Regs::CreateFromLocal(); | ||
//} | ||
|
||
std::string unw_function_name; | ||
unwindstack::LocalMaps maps; | ||
|
||
if (!maps.Parse()) { | ||
stacktrace[0].frame_address = regs->pc(); // only known frame | ||
return 1; | ||
} | ||
|
||
const std::shared_ptr<unwindstack::Memory> memory( | ||
new unwindstack::MemoryLocal); | ||
|
||
int frame_count = 0; | ||
for (int i = 0; i < BUGSNAG_FRAMES_MAX; i++) { | ||
unwindstack::MapInfo *const map_info = maps.Find(regs->pc()); | ||
unwindstack::Elf *const elf = map_info->GetElf(memory, false); | ||
if (!map_info || !elf) { | ||
stacktrace[frame_count++].frame_address = regs->pc(); | ||
break; | ||
} | ||
|
||
// Getting value of program counter relative module where a function is | ||
// located. | ||
const uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info); | ||
uint64_t adjusted_rel_pc = rel_pc; | ||
if (frame_count != 0) { | ||
// If it's not a first frame we need to rewind program counter value to | ||
// previous instruction. For the first frame pc from ucontext points | ||
// exactly to a failed instruction, for other frames rel_pc will contain | ||
// return address after function call instruction. | ||
adjusted_rel_pc -= regs->GetPcAdjustment(rel_pc, elf); | ||
} | ||
stacktrace[frame_count++].frame_address = regs->pc(); | ||
bool finished = false; | ||
if (!elf->Step(rel_pc, adjusted_rel_pc, map_info->elf_offset, regs.get(), | ||
memory.get(), &finished)) { | ||
break; | ||
} | ||
} | ||
return frame_count; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#ifndef BUGSNAG_UTILS_STACK_UNWINDER_LIBUNWINDSTACK_H | ||
#define BUGSNAG_UTILS_STACK_UNWINDER_LIBUNWINDSTACK_H | ||
|
||
#include "../report.h" | ||
#include <signal.h> | ||
|
||
#ifdef __cplusplus | ||
extern "C" | ||
#endif | ||
ssize_t | ||
bsg_unwind_stack_libunwindstack(bsg_stackframe stacktrace[BUGSNAG_FRAMES_MAX], | ||
siginfo_t *info, void *user_context); | ||
#endif |