tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

symbolize_test.cc (23103B)


      1 // Copyright 2018 The Abseil Authors.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      https://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "absl/debugging/symbolize.h"
     16 
     17 #ifdef __EMSCRIPTEN__
     18 #include <emscripten.h>
     19 #endif
     20 
     21 #ifndef _WIN32
     22 #include <fcntl.h>
     23 #include <sys/mman.h>
     24 #endif
     25 
     26 #include <cstring>
     27 #include <iostream>
     28 #include <memory>
     29 
     30 #include "gmock/gmock.h"
     31 #include "gtest/gtest.h"
     32 #include "absl/base/attributes.h"
     33 #include "absl/base/casts.h"
     34 #include "absl/base/config.h"
     35 #include "absl/base/internal/per_thread_tls.h"
     36 #include "absl/base/optimization.h"
     37 #include "absl/debugging/internal/stack_consumption.h"
     38 #include "absl/log/check.h"
     39 #include "absl/log/log.h"
     40 #include "absl/memory/memory.h"
     41 #include "absl/strings/string_view.h"
     42 
     43 #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
     44 #define MAP_ANONYMOUS MAP_ANON
     45 #endif
     46 
     47 using testing::Contains;
     48 
     49 #ifdef _WIN32
     50 #define ABSL_SYMBOLIZE_TEST_NOINLINE __declspec(noinline)
     51 #else
     52 #define ABSL_SYMBOLIZE_TEST_NOINLINE ABSL_ATTRIBUTE_NOINLINE
     53 #endif
     54 
     55 // Functions to symbolize. Use C linkage to avoid mangled names.
     56 extern "C" {
     57 ABSL_SYMBOLIZE_TEST_NOINLINE void nonstatic_func() {
     58  // The next line makes this a unique function to prevent the compiler from
     59  // folding identical functions together.
     60  volatile int x = __LINE__;
     61  static_cast<void>(x);
     62  ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
     63 }
     64 
     65 ABSL_SYMBOLIZE_TEST_NOINLINE static void static_func() {
     66  // The next line makes this a unique function to prevent the compiler from
     67  // folding identical functions together.
     68  volatile int x = __LINE__;
     69  static_cast<void>(x);
     70  ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
     71 }
     72 }  // extern "C"
     73 
     74 struct Foo {
     75  static void func(int x);
     76 };
     77 
     78 // A C++ method that should have a mangled name.
     79 ABSL_SYMBOLIZE_TEST_NOINLINE void Foo::func(int) {
     80  // The next line makes this a unique function to prevent the compiler from
     81  // folding identical functions together.
     82  volatile int x = __LINE__;
     83  static_cast<void>(x);
     84  ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
     85 }
     86 
     87 // Create functions that will remain in different text sections in the
     88 // final binary when linker option "-z,keep-text-section-prefix" is used.
     89 int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.unlikely) unlikely_func() {
     90  return 0;
     91 }
     92 
     93 int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.hot) hot_func() { return 0; }
     94 
     95 int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.startup) startup_func() { return 0; }
     96 
     97 int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.exit) exit_func() { return 0; }
     98 
     99 int /*ABSL_ATTRIBUTE_SECTION_VARIABLE(.text)*/ regular_func() { return 0; }
    100 
    101 // Thread-local data may confuse the symbolizer, ensure that it does not.
    102 // Variable sizes and order are important.
    103 #if ABSL_PER_THREAD_TLS
    104 static ABSL_PER_THREAD_TLS_KEYWORD char symbolize_test_thread_small[1];
    105 static ABSL_PER_THREAD_TLS_KEYWORD char
    106    symbolize_test_thread_big[2 * 1024 * 1024];
    107 #endif
    108 
    109 #if !defined(__EMSCRIPTEN__)
    110 static void *GetPCFromFnPtr(void *ptr) { return ptr; }
    111 
    112 // Used below to hopefully inhibit some compiler/linker optimizations
    113 // that may remove kHpageTextPadding, kPadding0, and kPadding1 from
    114 // the binary.
    115 static volatile bool volatile_bool = false;
    116 
    117 // Force the binary to be large enough that a THP .text remap will succeed.
    118 static constexpr size_t kHpageSize = 1 << 21;
    119 const char kHpageTextPadding[kHpageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(
    120        .text) = "";
    121 
    122 #else
    123 static void *GetPCFromFnPtr(void *ptr) {
    124  return EM_ASM_PTR(
    125      { return wasmOffsetConverter.convert(wasmTable.get($0).name, 0); }, ptr);
    126 }
    127 
    128 #endif  // !defined(__EMSCRIPTEN__)
    129 
    130 static char try_symbolize_buffer[4096];
    131 
    132 // A wrapper function for absl::Symbolize() to make the unit test simple.  The
    133 // limit must be < sizeof(try_symbolize_buffer).  Returns null if
    134 // absl::Symbolize() returns false, otherwise returns try_symbolize_buffer with
    135 // the result of absl::Symbolize().
    136 static const char *TrySymbolizeWithLimit(void *pc, int limit) {
    137  CHECK_LE(limit, sizeof(try_symbolize_buffer))
    138      << "try_symbolize_buffer is too small";
    139 
    140  // Use the heap to facilitate heap and buffer sanitizer tools.
    141  auto heap_buffer = absl::make_unique<char[]>(sizeof(try_symbolize_buffer));
    142  bool found = absl::Symbolize(pc, heap_buffer.get(), limit);
    143  if (found) {
    144    CHECK_LT(static_cast<int>(
    145                 strnlen(heap_buffer.get(), static_cast<size_t>(limit))),
    146             limit)
    147        << "absl::Symbolize() did not properly terminate the string";
    148    strncpy(try_symbolize_buffer, heap_buffer.get(),
    149            sizeof(try_symbolize_buffer) - 1);
    150    try_symbolize_buffer[sizeof(try_symbolize_buffer) - 1] = '\0';
    151  }
    152 
    153  return found ? try_symbolize_buffer : nullptr;
    154 }
    155 
    156 // A wrapper for TrySymbolizeWithLimit(), with a large limit.
    157 static const char *TrySymbolize(void *pc) {
    158  return TrySymbolizeWithLimit(pc, sizeof(try_symbolize_buffer));
    159 }
    160 
    161 #if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) ||    \
    162    defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE) || \
    163    defined(ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE)
    164 
    165 // Test with a return address.
    166 void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() {
    167 #if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE)
    168  void *return_address = __builtin_return_address(0);
    169  const char *symbol = TrySymbolize(return_address);
    170  ASSERT_NE(symbol, nullptr) << "TestWithReturnAddress failed";
    171  EXPECT_STREQ(symbol, "main") << "TestWithReturnAddress failed";
    172 #endif
    173 }
    174 
    175 TEST(Symbolize, Cached) {
    176  // Compilers should give us pointers to them.
    177  EXPECT_STREQ("nonstatic_func",
    178               TrySymbolize(GetPCFromFnPtr((void *)(&nonstatic_func))));
    179  // The name of an internal linkage symbol is not specified; allow either a
    180  // mangled or an unmangled name here.
    181  const char *static_func_symbol =
    182      TrySymbolize(GetPCFromFnPtr((void *)(&static_func)));
    183  EXPECT_TRUE(strcmp("static_func", static_func_symbol) == 0 ||
    184              strcmp("static_func()", static_func_symbol) == 0);
    185 
    186  EXPECT_TRUE(nullptr == TrySymbolize(nullptr));
    187 }
    188 
    189 TEST(Symbolize, Truncation) {
    190  constexpr char kNonStaticFunc[] = "nonstatic_func";
    191  EXPECT_STREQ("nonstatic_func",
    192               TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)),
    193                                     strlen(kNonStaticFunc) + 1));
    194  EXPECT_STREQ("nonstatic_...",
    195               TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)),
    196                                     strlen(kNonStaticFunc) + 0));
    197  EXPECT_STREQ("nonstatic...",
    198               TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)),
    199                                     strlen(kNonStaticFunc) - 1));
    200  EXPECT_STREQ("n...", TrySymbolizeWithLimit(
    201                           GetPCFromFnPtr((void *)(&nonstatic_func)), 5));
    202  EXPECT_STREQ("...", TrySymbolizeWithLimit(
    203                          GetPCFromFnPtr((void *)(&nonstatic_func)), 4));
    204  EXPECT_STREQ("..", TrySymbolizeWithLimit(
    205                         GetPCFromFnPtr((void *)(&nonstatic_func)), 3));
    206  EXPECT_STREQ(
    207      ".", TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)), 2));
    208  EXPECT_STREQ(
    209      "", TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)), 1));
    210  EXPECT_EQ(nullptr, TrySymbolizeWithLimit(
    211                         GetPCFromFnPtr((void *)(&nonstatic_func)), 0));
    212 }
    213 
    214 TEST(Symbolize, SymbolizeWithDemangling) {
    215  Foo::func(100);
    216 #ifdef __EMSCRIPTEN__
    217  // Emscripten's online symbolizer is more precise with arguments.
    218  EXPECT_STREQ("Foo::func(int)",
    219               TrySymbolize(GetPCFromFnPtr((void *)(&Foo::func))));
    220 #else
    221  EXPECT_STREQ("Foo::func()",
    222               TrySymbolize(GetPCFromFnPtr((void *)(&Foo::func))));
    223 #endif
    224 }
    225 
    226 TEST(Symbolize, SymbolizeSplitTextSections) {
    227  EXPECT_STREQ("unlikely_func()",
    228               TrySymbolize(GetPCFromFnPtr((void *)(&unlikely_func))));
    229  EXPECT_STREQ("hot_func()", TrySymbolize(GetPCFromFnPtr((void *)(&hot_func))));
    230  EXPECT_STREQ("startup_func()",
    231               TrySymbolize(GetPCFromFnPtr((void *)(&startup_func))));
    232  EXPECT_STREQ("exit_func()",
    233               TrySymbolize(GetPCFromFnPtr((void *)(&exit_func))));
    234  EXPECT_STREQ("regular_func()",
    235               TrySymbolize(GetPCFromFnPtr((void *)(&regular_func))));
    236 }
    237 
    238 // Tests that verify that Symbolize stack footprint is within some limit.
    239 #ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
    240 
    241 static void *g_pc_to_symbolize;
    242 static char g_symbolize_buffer[4096];
    243 static char *g_symbolize_result;
    244 
    245 static void SymbolizeSignalHandler(int signo) {
    246  if (absl::Symbolize(g_pc_to_symbolize, g_symbolize_buffer,
    247                      sizeof(g_symbolize_buffer))) {
    248    g_symbolize_result = g_symbolize_buffer;
    249  } else {
    250    g_symbolize_result = nullptr;
    251  }
    252 }
    253 
    254 // Call Symbolize and figure out the stack footprint of this call.
    255 static const char *SymbolizeStackConsumption(void *pc, int *stack_consumed) {
    256  g_pc_to_symbolize = pc;
    257  *stack_consumed = absl::debugging_internal::GetSignalHandlerStackConsumption(
    258      SymbolizeSignalHandler);
    259  return g_symbolize_result;
    260 }
    261 
    262 static int GetStackConsumptionUpperLimit() {
    263  // Symbolize stack consumption should be within 2kB.
    264  int stack_consumption_upper_limit = 2048;
    265 #if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
    266    defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER)
    267  // Account for sanitizer instrumentation requiring additional stack space.
    268  stack_consumption_upper_limit *= 5;
    269 #endif
    270  return stack_consumption_upper_limit;
    271 }
    272 
    273 TEST(Symbolize, SymbolizeStackConsumption) {
    274  int stack_consumed = 0;
    275 
    276  const char *symbol =
    277      SymbolizeStackConsumption((void *)(&nonstatic_func), &stack_consumed);
    278  EXPECT_STREQ("nonstatic_func", symbol);
    279  EXPECT_GT(stack_consumed, 0);
    280  EXPECT_LT(stack_consumed, GetStackConsumptionUpperLimit());
    281 
    282  // The name of an internal linkage symbol is not specified; allow either a
    283  // mangled or an unmangled name here.
    284  symbol = SymbolizeStackConsumption((void *)(&static_func), &stack_consumed);
    285  EXPECT_TRUE(strcmp("static_func", symbol) == 0 ||
    286              strcmp("static_func()", symbol) == 0);
    287  EXPECT_GT(stack_consumed, 0);
    288  EXPECT_LT(stack_consumed, GetStackConsumptionUpperLimit());
    289 }
    290 
    291 TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) {
    292  Foo::func(100);
    293  int stack_consumed = 0;
    294 
    295  const char *symbol =
    296      SymbolizeStackConsumption((void *)(&Foo::func), &stack_consumed);
    297 
    298  EXPECT_STREQ("Foo::func()", symbol);
    299  EXPECT_GT(stack_consumed, 0);
    300  EXPECT_LT(stack_consumed, GetStackConsumptionUpperLimit());
    301 }
    302 
    303 #endif  // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
    304 
    305 #if !defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE) && \
    306    !defined(ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE)
    307 // Use a 64K page size for PPC.
    308 const size_t kPageSize = 64 << 10;
    309 // We place a read-only symbols into the .text section and verify that we can
    310 // symbolize them and other symbols after remapping them.
    311 const char kPadding0[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) = "";
    312 const char kPadding1[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) = "";
    313 
    314 static int FilterElfHeader(struct dl_phdr_info *info, size_t size, void *data) {
    315  for (int i = 0; i < info->dlpi_phnum; i++) {
    316    if (info->dlpi_phdr[i].p_type == PT_LOAD &&
    317        info->dlpi_phdr[i].p_flags == (PF_R | PF_X)) {
    318      const void *const vaddr =
    319          absl::bit_cast<void *>(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
    320      const auto segsize = info->dlpi_phdr[i].p_memsz;
    321 
    322      const char *self_exe;
    323      if (info->dlpi_name != nullptr && info->dlpi_name[0] != '\0') {
    324        self_exe = info->dlpi_name;
    325      } else {
    326        self_exe = "/proc/self/exe";
    327      }
    328 
    329      absl::debugging_internal::RegisterFileMappingHint(
    330          vaddr, reinterpret_cast<const char *>(vaddr) + segsize,
    331          info->dlpi_phdr[i].p_offset, self_exe);
    332 
    333      return 1;
    334    }
    335  }
    336 
    337  return 1;
    338 }
    339 
    340 TEST(Symbolize, SymbolizeWithMultipleMaps) {
    341  // Force kPadding0 and kPadding1 to be linked in.
    342  if (volatile_bool) {
    343    LOG(INFO) << kPadding0;
    344    LOG(INFO) << kPadding1;
    345  }
    346 
    347  // Verify we can symbolize everything.
    348  char buf[512];
    349  memset(buf, 0, sizeof(buf));
    350  absl::Symbolize(kPadding0, buf, sizeof(buf));
    351  EXPECT_STREQ("kPadding0", buf);
    352 
    353  memset(buf, 0, sizeof(buf));
    354  absl::Symbolize(kPadding1, buf, sizeof(buf));
    355  EXPECT_STREQ("kPadding1", buf);
    356 
    357  // Specify a hint for the executable segment.
    358  dl_iterate_phdr(FilterElfHeader, nullptr);
    359 
    360  // Reload at least one page out of kPadding0, kPadding1
    361  const char *ptrs[] = {kPadding0, kPadding1};
    362 
    363  for (const char *ptr : ptrs) {
    364    const int kMapFlags = MAP_ANONYMOUS | MAP_PRIVATE;
    365    void *addr = mmap(nullptr, kPageSize, PROT_READ, kMapFlags, 0, 0);
    366    ASSERT_NE(addr, MAP_FAILED);
    367 
    368    // kPadding[0-1] is full of zeroes, so we can remap anywhere within it, but
    369    // we ensure there is at least a full page of padding.
    370    void *remapped = reinterpret_cast<void *>(
    371        reinterpret_cast<uintptr_t>(ptr + kPageSize) & ~(kPageSize - 1ULL));
    372 
    373    const int kMremapFlags = (MREMAP_MAYMOVE | MREMAP_FIXED);
    374    void *ret = mremap(addr, kPageSize, kPageSize, kMremapFlags, remapped);
    375    ASSERT_NE(ret, MAP_FAILED);
    376  }
    377 
    378  // Invalidate the symbolization cache so we are forced to rely on the hint.
    379  absl::Symbolize(nullptr, buf, sizeof(buf));
    380 
    381  // Verify we can still symbolize.
    382  const char *expected[] = {"kPadding0", "kPadding1"};
    383  const size_t offsets[] = {0, kPageSize, 2 * kPageSize, 3 * kPageSize};
    384 
    385  for (int i = 0; i < 2; i++) {
    386    for (size_t offset : offsets) {
    387      memset(buf, 0, sizeof(buf));
    388      absl::Symbolize(ptrs[i] + offset, buf, sizeof(buf));
    389      EXPECT_STREQ(expected[i], buf);
    390    }
    391  }
    392 }
    393 
    394 // Appends string(*args->arg) to args->symbol_buf.
    395 static void DummySymbolDecorator(
    396    const absl::debugging_internal::SymbolDecoratorArgs *args) {
    397  std::string *message = static_cast<std::string *>(args->arg);
    398  strncat(args->symbol_buf, message->c_str(),
    399          args->symbol_buf_size - strlen(args->symbol_buf) - 1);
    400 }
    401 
    402 TEST(Symbolize, InstallAndRemoveSymbolDecorators) {
    403  int ticket_a;
    404  std::string a_message("a");
    405  EXPECT_GE(ticket_a = absl::debugging_internal::InstallSymbolDecorator(
    406                DummySymbolDecorator, &a_message),
    407            0);
    408 
    409  int ticket_b;
    410  std::string b_message("b");
    411  EXPECT_GE(ticket_b = absl::debugging_internal::InstallSymbolDecorator(
    412                DummySymbolDecorator, &b_message),
    413            0);
    414 
    415  int ticket_c;
    416  std::string c_message("c");
    417  EXPECT_GE(ticket_c = absl::debugging_internal::InstallSymbolDecorator(
    418                DummySymbolDecorator, &c_message),
    419            0);
    420 
    421  // Use addresses 4 and 8 here to ensure that we always use valid addresses
    422  // even on systems that require instructions to be 32-bit aligned.
    423  char *address = reinterpret_cast<char *>(4);
    424  EXPECT_STREQ("abc", TrySymbolize(address));
    425 
    426  EXPECT_TRUE(absl::debugging_internal::RemoveSymbolDecorator(ticket_b));
    427 
    428  EXPECT_STREQ("ac", TrySymbolize(address + 4));
    429 
    430  // Cleanup: remove all remaining decorators so other stack traces don't
    431  // get mystery "ac" decoration.
    432  EXPECT_TRUE(absl::debugging_internal::RemoveSymbolDecorator(ticket_a));
    433  EXPECT_TRUE(absl::debugging_internal::RemoveSymbolDecorator(ticket_c));
    434 }
    435 
    436 // Some versions of Clang with optimizations enabled seem to be able
    437 // to optimize away the .data section if no variables live in the
    438 // section. This variable should get placed in the .data section, and
    439 // the test below checks for the existence of a .data section.
    440 static int in_data_section = 1;
    441 
    442 TEST(Symbolize, ForEachSection) {
    443  int fd = TEMP_FAILURE_RETRY(open("/proc/self/exe", O_RDONLY));
    444  ASSERT_NE(fd, -1);
    445 
    446  std::vector<std::string> sections;
    447  ASSERT_TRUE(absl::debugging_internal::ForEachSection(
    448      fd, [&sections](const absl::string_view name, const ElfW(Shdr) &) {
    449        sections.emplace_back(name);
    450        return true;
    451      }));
    452 
    453  // Check for the presence of common section names.
    454  EXPECT_THAT(sections, Contains(".text"));
    455  EXPECT_THAT(sections, Contains(".rodata"));
    456  EXPECT_THAT(sections, Contains(".bss"));
    457  ++in_data_section;
    458  EXPECT_THAT(sections, Contains(".data"));
    459 
    460  close(fd);
    461 }
    462 #endif  // !ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE &&
    463        // !ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE
    464 
    465 // x86 specific tests.  Uses some inline assembler.
    466 extern "C" {
    467 inline void *ABSL_ATTRIBUTE_ALWAYS_INLINE inline_func() {
    468  void *pc = nullptr;
    469 #if defined(__i386__)
    470  __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [PC] "=r"(pc));
    471 #elif defined(__x86_64__)
    472  __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [PC] "=r"(pc));
    473 #endif
    474  return pc;
    475 }
    476 
    477 void *ABSL_ATTRIBUTE_NOINLINE non_inline_func() {
    478  void *pc = nullptr;
    479 #if defined(__i386__)
    480  __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [PC] "=r"(pc));
    481 #elif defined(__x86_64__)
    482  __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [PC] "=r"(pc));
    483 #endif
    484  return pc;
    485 }
    486 
    487 void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() {
    488 #if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) && \
    489    (defined(__i386__) || defined(__x86_64__))
    490  void *pc = non_inline_func();
    491  const char *symbol = TrySymbolize(pc);
    492  ASSERT_NE(symbol, nullptr) << "TestWithPCInsideNonInlineFunction failed";
    493  EXPECT_STREQ(symbol, "non_inline_func")
    494      << "TestWithPCInsideNonInlineFunction failed";
    495 #endif
    496 }
    497 
    498 void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() {
    499 #if defined(ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE) && \
    500    (defined(__i386__) || defined(__x86_64__))
    501  void *pc = inline_func();  // Must be inlined.
    502  const char *symbol = TrySymbolize(pc);
    503  ASSERT_NE(symbol, nullptr) << "TestWithPCInsideInlineFunction failed";
    504  EXPECT_STREQ(symbol, __FUNCTION__) << "TestWithPCInsideInlineFunction failed";
    505 #endif
    506 }
    507 }
    508 
    509 #if defined(__arm__) && ABSL_HAVE_ATTRIBUTE(target) && \
    510    ((__ARM_ARCH >= 7) || !defined(__ARM_PCS_VFP))
    511 // Test that we correctly identify bounds of Thumb functions on ARM.
    512 //
    513 // Thumb functions have the lowest-order bit set in their addresses in the ELF
    514 // symbol table. This requires some extra logic to properly compute function
    515 // bounds. To test this logic, nudge a Thumb function right up against an ARM
    516 // function and try to symbolize the ARM function.
    517 //
    518 // A naive implementation will simply use the Thumb function's entry point as
    519 // written in the symbol table and will therefore treat the Thumb function as
    520 // extending one byte further in the instruction stream than it actually does.
    521 // When asked to symbolize the start of the ARM function, it will identify an
    522 // overlap between the Thumb and ARM functions, and it will return the name of
    523 // the Thumb function.
    524 //
    525 // A correct implementation, on the other hand, will null out the lowest-order
    526 // bit in the Thumb function's entry point. It will correctly compute the end of
    527 // the Thumb function, it will find no overlap between the Thumb and ARM
    528 // functions, and it will return the name of the ARM function.
    529 //
    530 // Unfortunately we cannot perform this test on armv6 or lower systems that use
    531 // the hard float ABI because gcc refuses to compile thumb functions on such
    532 // systems with a "sorry, unimplemented: Thumb-1 hard-float VFP ABI" error.
    533 
    534 __attribute__((target("thumb"))) int ArmThumbOverlapThumb(int x) {
    535  return x * x * x;
    536 }
    537 
    538 __attribute__((target("arm"))) int ArmThumbOverlapArm(int x) {
    539  return x * x * x;
    540 }
    541 
    542 void ABSL_ATTRIBUTE_NOINLINE TestArmThumbOverlap() {
    543 #if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE)
    544  const char *symbol = TrySymbolize((void *)&ArmThumbOverlapArm);
    545  ASSERT_NE(symbol, nullptr) << "TestArmThumbOverlap failed";
    546  EXPECT_STREQ("ArmThumbOverlapArm()", symbol) << "TestArmThumbOverlap failed";
    547 #endif
    548 }
    549 
    550 #endif  // defined(__arm__) && ABSL_HAVE_ATTRIBUTE(target) && ((__ARM_ARCH >= 7)
    551        // || !defined(__ARM_PCS_VFP))
    552 
    553 #elif defined(_WIN32)
    554 #if !defined(ABSL_CONSUME_DLL)
    555 
    556 TEST(Symbolize, Basics) {
    557  EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
    558 
    559  // The name of an internal linkage symbol is not specified; allow either a
    560  // mangled or an unmangled name here.
    561  const char *static_func_symbol = TrySymbolize((void *)(&static_func));
    562  ASSERT_TRUE(static_func_symbol != nullptr);
    563  EXPECT_TRUE(strstr(static_func_symbol, "static_func") != nullptr);
    564 
    565  EXPECT_TRUE(nullptr == TrySymbolize(nullptr));
    566 }
    567 
    568 TEST(Symbolize, Truncation) {
    569  constexpr char kNonStaticFunc[] = "nonstatic_func";
    570  EXPECT_STREQ("nonstatic_func",
    571               TrySymbolizeWithLimit((void *)(&nonstatic_func),
    572                                     strlen(kNonStaticFunc) + 1));
    573  EXPECT_STREQ("nonstatic_...",
    574               TrySymbolizeWithLimit((void *)(&nonstatic_func),
    575                                     strlen(kNonStaticFunc) + 0));
    576  EXPECT_STREQ("nonstatic...",
    577               TrySymbolizeWithLimit((void *)(&nonstatic_func),
    578                                     strlen(kNonStaticFunc) - 1));
    579  EXPECT_STREQ("n...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 5));
    580  EXPECT_STREQ("...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 4));
    581  EXPECT_STREQ("..", TrySymbolizeWithLimit((void *)(&nonstatic_func), 3));
    582  EXPECT_STREQ(".", TrySymbolizeWithLimit((void *)(&nonstatic_func), 2));
    583  EXPECT_STREQ("", TrySymbolizeWithLimit((void *)(&nonstatic_func), 1));
    584  EXPECT_EQ(nullptr, TrySymbolizeWithLimit((void *)(&nonstatic_func), 0));
    585 }
    586 
    587 TEST(Symbolize, SymbolizeWithDemangling) {
    588  const char *result = TrySymbolize((void *)(&Foo::func));
    589  ASSERT_TRUE(result != nullptr);
    590  EXPECT_TRUE(strstr(result, "Foo::func") != nullptr) << result;
    591 }
    592 
    593 #endif  // !defined(ABSL_CONSUME_DLL)
    594 #else   // Symbolizer unimplemented
    595 TEST(Symbolize, Unimplemented) {
    596  char buf[64];
    597  EXPECT_FALSE(absl::Symbolize((void *)(&nonstatic_func), buf, sizeof(buf)));
    598  EXPECT_FALSE(absl::Symbolize((void *)(&static_func), buf, sizeof(buf)));
    599  EXPECT_FALSE(absl::Symbolize((void *)(&Foo::func), buf, sizeof(buf)));
    600 }
    601 
    602 #endif
    603 
    604 int main(int argc, char **argv) {
    605 #if !defined(__EMSCRIPTEN__)
    606  // Make sure kHpageTextPadding is linked into the binary.
    607  if (volatile_bool) {
    608    LOG(INFO) << kHpageTextPadding;
    609  }
    610 #endif  // !defined(__EMSCRIPTEN__)
    611 
    612 #if ABSL_PER_THREAD_TLS
    613  // Touch the per-thread variables.
    614  symbolize_test_thread_small[0] = 0;
    615  symbolize_test_thread_big[0] = 0;
    616 #endif
    617 
    618  absl::InitializeSymbolizer(argv[0]);
    619  testing::InitGoogleTest(&argc, argv);
    620 
    621 #if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) ||        \
    622    defined(ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE) || \
    623    defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE)
    624  TestWithPCInsideInlineFunction();
    625  TestWithPCInsideNonInlineFunction();
    626  TestWithReturnAddress();
    627 #if defined(__arm__) && ABSL_HAVE_ATTRIBUTE(target) && \
    628    ((__ARM_ARCH >= 7) || !defined(__ARM_PCS_VFP))
    629  TestArmThumbOverlap();
    630 #endif
    631 #endif
    632 
    633  return RUN_ALL_TESTS();
    634 }