00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "absl/debugging/symbolize.h"
00016
00017 #ifndef _WIN32
00018 #include <fcntl.h>
00019 #include <sys/mman.h>
00020 #endif
00021
00022 #include <cstring>
00023 #include <iostream>
00024 #include <memory>
00025
00026 #include "gmock/gmock.h"
00027 #include "gtest/gtest.h"
00028 #include "absl/base/attributes.h"
00029 #include "absl/base/casts.h"
00030 #include "absl/base/internal/per_thread_tls.h"
00031 #include "absl/base/internal/raw_logging.h"
00032 #include "absl/base/optimization.h"
00033 #include "absl/debugging/internal/stack_consumption.h"
00034 #include "absl/memory/memory.h"
00035
00036 using testing::Contains;
00037
00038
00039 extern "C" {
00040 void nonstatic_func() { ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); }
00041 static void static_func() { ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); }
00042 }
00043
00044 struct Foo {
00045 static void func(int x);
00046 };
00047
00048
00049 void ABSL_ATTRIBUTE_NOINLINE Foo::func(int) {
00050 ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
00051 }
00052
00053
00054
00055 int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.unlikely) unlikely_func() {
00056 return 0;
00057 }
00058
00059 int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.hot) hot_func() {
00060 return 0;
00061 }
00062
00063 int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.startup) startup_func() {
00064 return 0;
00065 }
00066
00067 int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.exit) exit_func() {
00068 return 0;
00069 }
00070
00071 int regular_func() {
00072 return 0;
00073 }
00074
00075
00076
00077 #if ABSL_PER_THREAD_TLS
00078 static ABSL_PER_THREAD_TLS_KEYWORD char symbolize_test_thread_small[1];
00079 static ABSL_PER_THREAD_TLS_KEYWORD char
00080 symbolize_test_thread_big[2 * 1024 * 1024];
00081 #endif
00082
00083
00084
00085
00086 static volatile bool volatile_bool = false;
00087
00088
00089 static constexpr size_t kHpageSize = 1 << 21;
00090 const char kHpageTextPadding[kHpageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(
00091 .text) = "";
00092
00093 static char try_symbolize_buffer[4096];
00094
00095
00096
00097
00098
00099 static const char *TrySymbolizeWithLimit(void *pc, int limit) {
00100 ABSL_RAW_CHECK(limit <= sizeof(try_symbolize_buffer),
00101 "try_symbolize_buffer is too small");
00102
00103
00104 auto heap_buffer = absl::make_unique<char[]>(sizeof(try_symbolize_buffer));
00105 bool found = absl::Symbolize(pc, heap_buffer.get(), limit);
00106 if (found) {
00107 ABSL_RAW_CHECK(strnlen(heap_buffer.get(), limit) < limit,
00108 "absl::Symbolize() did not properly terminate the string");
00109 strncpy(try_symbolize_buffer, heap_buffer.get(),
00110 sizeof(try_symbolize_buffer));
00111 }
00112
00113 return found ? try_symbolize_buffer : nullptr;
00114 }
00115
00116
00117 static const char *TrySymbolize(void *pc) {
00118 return TrySymbolizeWithLimit(pc, sizeof(try_symbolize_buffer));
00119 }
00120
00121 #ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
00122
00123 TEST(Symbolize, Cached) {
00124
00125 EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
00126
00127
00128
00129 const char *static_func_symbol = TrySymbolize((void *)(&static_func));
00130 EXPECT_TRUE(strcmp("static_func", static_func_symbol) == 0 ||
00131 strcmp("static_func()", static_func_symbol) == 0);
00132
00133 EXPECT_TRUE(nullptr == TrySymbolize(nullptr));
00134 }
00135
00136 TEST(Symbolize, Truncation) {
00137 constexpr char kNonStaticFunc[] = "nonstatic_func";
00138 EXPECT_STREQ("nonstatic_func",
00139 TrySymbolizeWithLimit((void *)(&nonstatic_func),
00140 strlen(kNonStaticFunc) + 1));
00141 EXPECT_STREQ("nonstatic_...",
00142 TrySymbolizeWithLimit((void *)(&nonstatic_func),
00143 strlen(kNonStaticFunc) + 0));
00144 EXPECT_STREQ("nonstatic...",
00145 TrySymbolizeWithLimit((void *)(&nonstatic_func),
00146 strlen(kNonStaticFunc) - 1));
00147 EXPECT_STREQ("n...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 5));
00148 EXPECT_STREQ("...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 4));
00149 EXPECT_STREQ("..", TrySymbolizeWithLimit((void *)(&nonstatic_func), 3));
00150 EXPECT_STREQ(".", TrySymbolizeWithLimit((void *)(&nonstatic_func), 2));
00151 EXPECT_STREQ("", TrySymbolizeWithLimit((void *)(&nonstatic_func), 1));
00152 EXPECT_EQ(nullptr, TrySymbolizeWithLimit((void *)(&nonstatic_func), 0));
00153 }
00154
00155 TEST(Symbolize, SymbolizeWithDemangling) {
00156 Foo::func(100);
00157 EXPECT_STREQ("Foo::func()", TrySymbolize((void *)(&Foo::func)));
00158 }
00159
00160 TEST(Symbolize, SymbolizeSplitTextSections) {
00161 EXPECT_STREQ("unlikely_func()", TrySymbolize((void *)(&unlikely_func)));
00162 EXPECT_STREQ("hot_func()", TrySymbolize((void *)(&hot_func)));
00163 EXPECT_STREQ("startup_func()", TrySymbolize((void *)(&startup_func)));
00164 EXPECT_STREQ("exit_func()", TrySymbolize((void *)(&exit_func)));
00165 EXPECT_STREQ("regular_func()", TrySymbolize((void *)(®ular_func)));
00166 }
00167
00168
00169 #ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
00170
00171 static void *g_pc_to_symbolize;
00172 static char g_symbolize_buffer[4096];
00173 static char *g_symbolize_result;
00174
00175 static void SymbolizeSignalHandler(int signo) {
00176 if (absl::Symbolize(g_pc_to_symbolize, g_symbolize_buffer,
00177 sizeof(g_symbolize_buffer))) {
00178 g_symbolize_result = g_symbolize_buffer;
00179 } else {
00180 g_symbolize_result = nullptr;
00181 }
00182 }
00183
00184
00185 static const char *SymbolizeStackConsumption(void *pc, int *stack_consumed) {
00186 g_pc_to_symbolize = pc;
00187 *stack_consumed = absl::debugging_internal::GetSignalHandlerStackConsumption(
00188 SymbolizeSignalHandler);
00189 return g_symbolize_result;
00190 }
00191
00192 static int GetStackConsumptionUpperLimit() {
00193
00194 int stack_consumption_upper_limit = 2048;
00195 #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
00196 defined(THREAD_SANITIZER)
00197
00198 stack_consumption_upper_limit *= 5;
00199 #endif
00200 return stack_consumption_upper_limit;
00201 }
00202
00203 TEST(Symbolize, SymbolizeStackConsumption) {
00204 int stack_consumed = 0;
00205
00206 const char *symbol =
00207 SymbolizeStackConsumption((void *)(&nonstatic_func), &stack_consumed);
00208 EXPECT_STREQ("nonstatic_func", symbol);
00209 EXPECT_GT(stack_consumed, 0);
00210 EXPECT_LT(stack_consumed, GetStackConsumptionUpperLimit());
00211
00212
00213
00214 symbol = SymbolizeStackConsumption((void *)(&static_func), &stack_consumed);
00215 EXPECT_TRUE(strcmp("static_func", symbol) == 0 ||
00216 strcmp("static_func()", symbol) == 0);
00217 EXPECT_GT(stack_consumed, 0);
00218 EXPECT_LT(stack_consumed, GetStackConsumptionUpperLimit());
00219 }
00220
00221 TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) {
00222 Foo::func(100);
00223 int stack_consumed = 0;
00224
00225 const char *symbol =
00226 SymbolizeStackConsumption((void *)(&Foo::func), &stack_consumed);
00227
00228 EXPECT_STREQ("Foo::func()", symbol);
00229 EXPECT_GT(stack_consumed, 0);
00230 EXPECT_LT(stack_consumed, GetStackConsumptionUpperLimit());
00231 }
00232
00233 #endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
00234
00235
00236 const size_t kPageSize = 64 << 10;
00237
00238
00239 const char kPadding0[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) =
00240 "";
00241 const char kPadding1[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) =
00242 "";
00243
00244 static int FilterElfHeader(struct dl_phdr_info *info, size_t size, void *data) {
00245 for (int i = 0; i < info->dlpi_phnum; i++) {
00246 if (info->dlpi_phdr[i].p_type == PT_LOAD &&
00247 info->dlpi_phdr[i].p_flags == (PF_R | PF_X)) {
00248 const void *const vaddr =
00249 absl::bit_cast<void *>(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
00250 const auto segsize = info->dlpi_phdr[i].p_memsz;
00251
00252 const char *self_exe;
00253 if (info->dlpi_name != nullptr && info->dlpi_name[0] != '\0') {
00254 self_exe = info->dlpi_name;
00255 } else {
00256 self_exe = "/proc/self/exe";
00257 }
00258
00259 absl::debugging_internal::RegisterFileMappingHint(
00260 vaddr, reinterpret_cast<const char *>(vaddr) + segsize,
00261 info->dlpi_phdr[i].p_offset, self_exe);
00262
00263 return 1;
00264 }
00265 }
00266
00267 return 1;
00268 }
00269
00270 TEST(Symbolize, SymbolizeWithMultipleMaps) {
00271
00272 if (volatile_bool) {
00273 ABSL_RAW_LOG(INFO, "%s", kPadding0);
00274 ABSL_RAW_LOG(INFO, "%s", kPadding1);
00275 }
00276
00277
00278 char buf[512];
00279 memset(buf, 0, sizeof(buf));
00280 absl::Symbolize(kPadding0, buf, sizeof(buf));
00281 EXPECT_STREQ("kPadding0", buf);
00282
00283 memset(buf, 0, sizeof(buf));
00284 absl::Symbolize(kPadding1, buf, sizeof(buf));
00285 EXPECT_STREQ("kPadding1", buf);
00286
00287
00288 dl_iterate_phdr(FilterElfHeader, nullptr);
00289
00290
00291 const char *ptrs[] = {kPadding0, kPadding1};
00292
00293 for (const char *ptr : ptrs) {
00294 const int kMapFlags = MAP_ANONYMOUS | MAP_PRIVATE;
00295 void *addr = mmap(nullptr, kPageSize, PROT_READ, kMapFlags, 0, 0);
00296 ASSERT_NE(addr, MAP_FAILED);
00297
00298
00299
00300 void *remapped = reinterpret_cast<void *>(
00301 reinterpret_cast<uintptr_t>(ptr + kPageSize) & ~(kPageSize - 1ULL));
00302
00303 const int kMremapFlags = (MREMAP_MAYMOVE | MREMAP_FIXED);
00304 void *ret = mremap(addr, kPageSize, kPageSize, kMremapFlags, remapped);
00305 ASSERT_NE(ret, MAP_FAILED);
00306 }
00307
00308
00309 absl::Symbolize(nullptr, buf, sizeof(buf));
00310
00311
00312 const char *expected[] = {"kPadding0", "kPadding1"};
00313 const size_t offsets[] = {0, kPageSize, 2 * kPageSize, 3 * kPageSize};
00314
00315 for (int i = 0; i < 2; i++) {
00316 for (size_t offset : offsets) {
00317 memset(buf, 0, sizeof(buf));
00318 absl::Symbolize(ptrs[i] + offset, buf, sizeof(buf));
00319 EXPECT_STREQ(expected[i], buf);
00320 }
00321 }
00322 }
00323
00324
00325 static void DummySymbolDecorator(
00326 const absl::debugging_internal::SymbolDecoratorArgs *args) {
00327 std::string *message = static_cast<std::string *>(args->arg);
00328 strncat(args->symbol_buf, message->c_str(),
00329 args->symbol_buf_size - strlen(args->symbol_buf) - 1);
00330 }
00331
00332 TEST(Symbolize, InstallAndRemoveSymbolDecorators) {
00333 int ticket_a;
00334 std::string a_message("a");
00335 EXPECT_GE(ticket_a = absl::debugging_internal::InstallSymbolDecorator(
00336 DummySymbolDecorator, &a_message),
00337 0);
00338
00339 int ticket_b;
00340 std::string b_message("b");
00341 EXPECT_GE(ticket_b = absl::debugging_internal::InstallSymbolDecorator(
00342 DummySymbolDecorator, &b_message),
00343 0);
00344
00345 int ticket_c;
00346 std::string c_message("c");
00347 EXPECT_GE(ticket_c = absl::debugging_internal::InstallSymbolDecorator(
00348 DummySymbolDecorator, &c_message),
00349 0);
00350
00351 char *address = reinterpret_cast<char *>(1);
00352 EXPECT_STREQ("abc", TrySymbolize(address++));
00353
00354 EXPECT_TRUE(absl::debugging_internal::RemoveSymbolDecorator(ticket_b));
00355
00356 EXPECT_STREQ("ac", TrySymbolize(address++));
00357
00358
00359
00360 EXPECT_TRUE(absl::debugging_internal::RemoveSymbolDecorator(ticket_a));
00361 EXPECT_TRUE(absl::debugging_internal::RemoveSymbolDecorator(ticket_c));
00362 }
00363
00364
00365
00366
00367
00368 static int in_data_section = 1;
00369
00370 TEST(Symbolize, ForEachSection) {
00371 int fd = TEMP_FAILURE_RETRY(open("/proc/self/exe", O_RDONLY));
00372 ASSERT_NE(fd, -1);
00373
00374 std::vector<std::string> sections;
00375 ASSERT_TRUE(absl::debugging_internal::ForEachSection(
00376 fd, [§ions](const std::string &name, const ElfW(Shdr) &) {
00377 sections.push_back(name);
00378 return true;
00379 }));
00380
00381
00382 EXPECT_THAT(sections, Contains(".text"));
00383 EXPECT_THAT(sections, Contains(".rodata"));
00384 EXPECT_THAT(sections, Contains(".bss"));
00385 ++in_data_section;
00386 EXPECT_THAT(sections, Contains(".data"));
00387
00388 close(fd);
00389 }
00390
00391
00392 extern "C" {
00393 inline void *ABSL_ATTRIBUTE_ALWAYS_INLINE inline_func() {
00394 void *pc = nullptr;
00395 #if defined(__i386__)
00396 __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [ PC ] "=r"(pc));
00397 #elif defined(__x86_64__)
00398 __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [ PC ] "=r"(pc));
00399 #endif
00400 return pc;
00401 }
00402
00403 void *ABSL_ATTRIBUTE_NOINLINE non_inline_func() {
00404 void *pc = nullptr;
00405 #if defined(__i386__)
00406 __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [ PC ] "=r"(pc));
00407 #elif defined(__x86_64__)
00408 __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [ PC ] "=r"(pc));
00409 #endif
00410 return pc;
00411 }
00412
00413 void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() {
00414 #if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) && \
00415 (defined(__i386__) || defined(__x86_64__))
00416 void *pc = non_inline_func();
00417 const char *symbol = TrySymbolize(pc);
00418 ABSL_RAW_CHECK(symbol != nullptr, "TestWithPCInsideNonInlineFunction failed");
00419 ABSL_RAW_CHECK(strcmp(symbol, "non_inline_func") == 0,
00420 "TestWithPCInsideNonInlineFunction failed");
00421 std::cout << "TestWithPCInsideNonInlineFunction passed" << std::endl;
00422 #endif
00423 }
00424
00425 void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() {
00426 #if defined(ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE) && \
00427 (defined(__i386__) || defined(__x86_64__))
00428 void *pc = inline_func();
00429 const char *symbol = TrySymbolize(pc);
00430 ABSL_RAW_CHECK(symbol != nullptr, "TestWithPCInsideInlineFunction failed");
00431 ABSL_RAW_CHECK(strcmp(symbol, __FUNCTION__) == 0,
00432 "TestWithPCInsideInlineFunction failed");
00433 std::cout << "TestWithPCInsideInlineFunction passed" << std::endl;
00434 #endif
00435 }
00436 }
00437
00438
00439 void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() {
00440 #if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE)
00441 void *return_address = __builtin_return_address(0);
00442 const char *symbol = TrySymbolize(return_address);
00443 ABSL_RAW_CHECK(symbol != nullptr, "TestWithReturnAddress failed");
00444 ABSL_RAW_CHECK(strcmp(symbol, "main") == 0, "TestWithReturnAddress failed");
00445 std::cout << "TestWithReturnAddress passed" << std::endl;
00446 #endif
00447 }
00448
00449 #elif defined(_WIN32) && defined(_DEBUG)
00450
00451 TEST(Symbolize, Basics) {
00452 EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
00453
00454
00455
00456 const char* static_func_symbol = TrySymbolize((void *)(&static_func));
00457 ASSERT_TRUE(static_func_symbol != nullptr);
00458 EXPECT_TRUE(strstr(static_func_symbol, "static_func") != nullptr);
00459
00460 EXPECT_TRUE(nullptr == TrySymbolize(nullptr));
00461 }
00462
00463 TEST(Symbolize, Truncation) {
00464 constexpr char kNonStaticFunc[] = "nonstatic_func";
00465 EXPECT_STREQ("nonstatic_func",
00466 TrySymbolizeWithLimit((void *)(&nonstatic_func),
00467 strlen(kNonStaticFunc) + 1));
00468 EXPECT_STREQ("nonstatic_...",
00469 TrySymbolizeWithLimit((void *)(&nonstatic_func),
00470 strlen(kNonStaticFunc) + 0));
00471 EXPECT_STREQ("nonstatic...",
00472 TrySymbolizeWithLimit((void *)(&nonstatic_func),
00473 strlen(kNonStaticFunc) - 1));
00474 EXPECT_STREQ("n...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 5));
00475 EXPECT_STREQ("...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 4));
00476 EXPECT_STREQ("..", TrySymbolizeWithLimit((void *)(&nonstatic_func), 3));
00477 EXPECT_STREQ(".", TrySymbolizeWithLimit((void *)(&nonstatic_func), 2));
00478 EXPECT_STREQ("", TrySymbolizeWithLimit((void *)(&nonstatic_func), 1));
00479 EXPECT_EQ(nullptr, TrySymbolizeWithLimit((void *)(&nonstatic_func), 0));
00480 }
00481
00482 TEST(Symbolize, SymbolizeWithDemangling) {
00483 const char* result = TrySymbolize((void *)(&Foo::func));
00484 ASSERT_TRUE(result != nullptr);
00485 EXPECT_TRUE(strstr(result, "Foo::func") != nullptr) << result;
00486 }
00487
00488 #else // Symbolizer unimplemented
00489
00490 TEST(Symbolize, Unimplemented) {
00491 char buf[64];
00492 EXPECT_FALSE(absl::Symbolize((void *)(&nonstatic_func), buf, sizeof(buf)));
00493 EXPECT_FALSE(absl::Symbolize((void *)(&static_func), buf, sizeof(buf)));
00494 EXPECT_FALSE(absl::Symbolize((void *)(&Foo::func), buf, sizeof(buf)));
00495 }
00496
00497 #endif
00498
00499 int main(int argc, char **argv) {
00500
00501 if (volatile_bool) {
00502 ABSL_RAW_LOG(INFO, "%s", kHpageTextPadding);
00503 }
00504
00505 #if ABSL_PER_THREAD_TLS
00506
00507 symbolize_test_thread_small[0] = 0;
00508 symbolize_test_thread_big[0] = 0;
00509 #endif
00510
00511 absl::InitializeSymbolizer(argv[0]);
00512 testing::InitGoogleTest(&argc, argv);
00513
00514 #ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
00515 TestWithPCInsideInlineFunction();
00516 TestWithPCInsideNonInlineFunction();
00517 TestWithReturnAddress();
00518 #endif
00519
00520 return RUN_ALL_TESTS();
00521 }