Skip to content

Commit 9f1244c

Browse files
tweenkcopybara-github
authored andcommitted
Support NDK weak symbol mode for backtrace() on Android.
Allows code compiled for API level 32 or lower to support backtrace() when it runs on API level 33 or higher. PiperOrigin-RevId: 783954794 Change-Id: Ie3e2552d4625092fe5750f6d2d64ae78597d97c3
1 parent c952a1d commit 9f1244c

2 files changed

Lines changed: 74 additions & 42 deletions

File tree

absl/debugging/internal/stacktrace_config.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@
4242
#define ABSL_STACKTRACE_INL_HEADER \
4343
"absl/debugging/internal/stacktrace_emscripten-inl.inc"
4444

45-
#elif defined(__ANDROID__) && __ANDROID_API__ >= 33
46-
#ifdef ABSL_HAVE_THREAD_LOCAL
47-
// Use the generic implementation for Android 33+ (Android T+). This is the
48-
// first version of Android for which <execinfo.h> implements backtrace().
45+
#elif defined(__ANDROID__)
46+
#if defined(ABSL_HAVE_THREAD_LOCAL) && \
47+
(__ANDROID_API__ >= 33 || \
48+
defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__))
4949
#define ABSL_STACKTRACE_INL_HEADER \
5050
"absl/debugging/internal/stacktrace_generic-inl.inc"
51-
#endif // defined(ABSL_HAVE_THREAD_LOCAL)
51+
#endif
5252

5353
#elif defined(__linux__) && !defined(__ANDROID__)
5454

absl/debugging/internal/stacktrace_generic-inl.inc

Lines changed: 69 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,38 @@
2121
#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_
2222

2323
#include <execinfo.h>
24+
2425
#include <atomic>
26+
#include <cstdint>
2527
#include <cstring>
2628

27-
#include "absl/debugging/stacktrace.h"
2829
#include "absl/base/attributes.h"
30+
#include "absl/debugging/stacktrace.h"
31+
32+
// When the macro __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__ is defined, Android
33+
// NDK supports a mode where all symbols added later than the target API level
34+
// are weak. In this mode, __builtin_available can be used to check the actual
35+
// API level available at runtime. There is also a compiler warning,
36+
// -Wunguarded-availability, that detects unchecked uses of APIs above the level
37+
// specified by __ANDROID_API__ that are not guarded by __builtin_available.
38+
// Details: https://developer.android.com/ndk/guides/using-newer-apis
39+
//
40+
// We take advantage of this mode to weakly link to backtrace() even when the
41+
// target API level is below 33, which is the first version of Android that
42+
// provides backtrace() in its libc.
43+
//
44+
// Unfortunately, -Wunguarded-availability does not do any control flow analysis
45+
// and will trigger if we do anything other than putting all calls to the target
46+
// function in an if() statement that calls the builtin. We can't return early
47+
// or even negate the condition.
48+
#if defined(__ANDROID__) && defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__)
49+
// In weak symbol mode, check the compiler builtin.
50+
#define ABSL_INTERNAL_BACKTRACE_AVAILABLE() __builtin_available(android 33, *)
51+
#else
52+
// Otherwise, assume that backtrace() is available, because otherwise this file
53+
// wouldn't be included.
54+
#define ABSL_INTERNAL_BACKTRACE_AVAILABLE() true
55+
#endif
2956

3057
// Sometimes, we can try to get a stack trace from within a stack
3158
// trace, because we don't block signals inside this code (which would be too
@@ -46,12 +73,14 @@ static std::atomic<bool> disable_stacktraces(true); // Disabled until healthy.
4673
// Waiting until static initializers run seems to be late enough.
4774
// This file is included into stacktrace.cc so this will only run once.
4875
ABSL_ATTRIBUTE_UNUSED static int stacktraces_enabler = []() {
49-
void* unused_stack[1];
50-
// Force the first backtrace to happen early to get the one-time shared lib
51-
// loading (allocation) out of the way. After the first call it is much safer
52-
// to use backtrace from a signal handler if we crash somewhere later.
53-
backtrace(unused_stack, 1);
54-
disable_stacktraces.store(false, std::memory_order_relaxed);
76+
if (ABSL_INTERNAL_BACKTRACE_AVAILABLE()) {
77+
void* unused_stack[1];
78+
// Force the first backtrace to happen early to get the one-time shared lib
79+
// loading (allocation) out of the way. After the first call it is much
80+
// safer to use backtrace from a signal handler if we crash somewhere later.
81+
backtrace(unused_stack, 1);
82+
disable_stacktraces.store(false, std::memory_order_relaxed);
83+
}
5584
return 0;
5685
}();
5786

@@ -62,43 +91,46 @@ static int UnwindImpl(void** result, uintptr_t* frames, int* sizes,
6291
if (recursive || disable_stacktraces.load(std::memory_order_relaxed)) {
6392
return 0;
6493
}
65-
++recursive;
94+
if (ABSL_INTERNAL_BACKTRACE_AVAILABLE()) {
95+
++recursive;
6696

67-
static_cast<void>(ucp); // Unused.
68-
static const int kStackLength = 64;
69-
void * stack[kStackLength];
70-
int size;
97+
static_cast<void>(ucp); // Unused.
98+
static const int kStackLength = 64;
99+
void * stack[kStackLength];
100+
int size;
71101

72-
size = backtrace(stack, kStackLength);
73-
skip_count++; // we want to skip the current frame as well
74-
int result_count = size - skip_count;
75-
if (result_count < 0)
76-
result_count = 0;
77-
if (result_count > max_depth)
78-
result_count = max_depth;
79-
for (int i = 0; i < result_count; i++)
80-
result[i] = stack[i + skip_count];
102+
size = backtrace(stack, kStackLength);
103+
skip_count++; // we want to skip the current frame as well
104+
int result_count = size - skip_count;
105+
if (result_count < 0)
106+
result_count = 0;
107+
if (result_count > max_depth)
108+
result_count = max_depth;
109+
for (int i = 0; i < result_count; i++)
110+
result[i] = stack[i + skip_count];
81111

82-
if (IS_STACK_FRAMES) {
83-
// No implementation for finding out the stack frames yet.
84-
if (frames != nullptr) {
85-
memset(frames, 0, sizeof(*frames) * static_cast<size_t>(result_count));
86-
}
87-
if (sizes != nullptr) {
88-
memset(sizes, 0, sizeof(*sizes) * static_cast<size_t>(result_count));
112+
if (IS_STACK_FRAMES) {
113+
// No implementation for finding out the stack frames yet.
114+
if (frames != nullptr) {
115+
memset(frames, 0, sizeof(*frames) * static_cast<size_t>(result_count));
116+
}
117+
if (sizes != nullptr) {
118+
memset(sizes, 0, sizeof(*sizes) * static_cast<size_t>(result_count));
119+
}
89120
}
90-
}
91-
if (min_dropped_frames != nullptr) {
92-
if (size - skip_count - max_depth > 0) {
93-
*min_dropped_frames = size - skip_count - max_depth;
94-
} else {
95-
*min_dropped_frames = 0;
121+
if (min_dropped_frames != nullptr) {
122+
if (size - skip_count - max_depth > 0) {
123+
*min_dropped_frames = size - skip_count - max_depth;
124+
} else {
125+
*min_dropped_frames = 0;
126+
}
96127
}
97-
}
98128

99-
--recursive;
129+
--recursive;
100130

101-
return result_count;
131+
return result_count;
132+
}
133+
return 0;
102134
}
103135

104136
namespace absl {

0 commit comments

Comments
 (0)