|
16 | 16 |
|
17 | 17 | #include <folly/debugging/symbolizer/detail/Debug.h>
|
18 | 18 |
|
19 |
| -#include <folly/CppAttributes.h> |
| 19 | +#include <folly/Portability.h> |
| 20 | + |
| 21 | +#ifndef _WIN32 |
| 22 | +#include <dlfcn.h> |
| 23 | +#endif |
20 | 24 |
|
21 | 25 | #if FOLLY_HAVE_ELF
|
22 | 26 | #include <link.h>
|
23 | 27 | #endif
|
24 | 28 |
|
25 | 29 | #if defined(__APPLE__) && !TARGET_OS_OSX
|
26 |
| -#define NO_R_DEBUG |
| 30 | +#define FOLLY_DETAIL_HAS_R_DEBUG 0 |
27 | 31 | #elif !defined(__linux__) || !FOLLY_HAVE_ELF || !FOLLY_HAVE_DWARF
|
28 |
| -#define NO_R_DEBUG |
| 32 | +#define FOLLY_DETAIL_HAS_R_DEBUG 0 |
| 33 | +#else |
| 34 | +#define FOLLY_DETAIL_HAS_R_DEBUG 1 |
29 | 35 | #endif
|
30 | 36 |
|
31 | 37 | namespace folly {
|
32 | 38 | namespace symbolizer {
|
33 | 39 | namespace detail {
|
34 | 40 |
|
| 41 | +#if FOLLY_DETAIL_HAS_R_DEBUG |
| 42 | + |
| 43 | +/// There is a strong requirement of finding the true _r_debug in ld.so. |
| 44 | +/// |
| 45 | +/// The previous code used the declaration of the extern variable as found in |
| 46 | +/// |
| 47 | +/// #include <link.h> |
| 48 | +/// |
| 49 | +/// The intention of using the extern variable is to get the toolchain to emit a |
| 50 | +/// GOT access, e.g. like: |
| 51 | +/// |
| 52 | +/// mov rax, qword ptr [rip + _r_debug@GOTPCREL] |
| 53 | +/// |
| 54 | +/// This works in typical conditions. However, in the case of compiling with: |
| 55 | +/// |
| 56 | +/// -mcmodel=small -fno-pic |
| 57 | +/// |
| 58 | +/// ie with non-pic and small-code-model, there is a different outcome. Here |
| 59 | +/// instead, the toolchain emits a COPY relocation to copy _r_debug into the |
| 60 | +/// executable and emits a direct non-GOT access to the copy like: |
| 61 | +/// |
| 62 | +/// mov eax, offset _r_debug |
| 63 | +/// |
| 64 | +/// This causes all accesses in ld.so to be redirected to the copy in the main |
| 65 | +/// executable, which is a valid approach. |
| 66 | +/// |
| 67 | +/// However, LLDB specifically looks for _r_debug in ld.so. When the debugger |
| 68 | +/// inspects a process, the _r_debug in the executable has all of the current |
| 69 | +/// information about the link and load state, but the debugger looks only at |
| 70 | +/// the _r_debug in ld.so which is empty! This breaks debugging. |
| 71 | +static r_debug* r_debug_cache_; |
| 72 | +[[gnu::constructor(101)]] void r_debug_cache_init_() { |
| 73 | + r_debug_cache_ = static_cast<r_debug*>(dlsym(RTLD_DEFAULT, "_r_debug")); |
| 74 | +} |
| 75 | + |
| 76 | +#endif |
| 77 | + |
35 | 78 | struct r_debug* get_r_debug() {
|
36 |
| -#ifdef NO_R_DEBUG |
37 |
| - return nullptr; |
38 |
| -#else |
39 |
| - return &_r_debug; |
| 79 | +#if FOLLY_DETAIL_HAS_R_DEBUG |
| 80 | + return r_debug_cache_; |
40 | 81 | #endif
|
| 82 | + return nullptr; |
41 | 83 | }
|
42 | 84 |
|
43 | 85 | } // namespace detail
|
|
0 commit comments