summaryrefslogtreecommitdiff
path: root/absl/debugging
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2018-04-23 15:50:21 -0700
committerGravatar Derek Mauro <dmauro@google.com>2018-04-24 10:09:46 -0400
commit19b3c95727316cef3b0b40eaf37f6645a876f8d2 (patch)
tree093012eb09e5d01e98c941607a884dd79d0db55b /absl/debugging
parentaf7882601aad93ada881486eeaabc562f1733961 (diff)
- 3a9532fb2d6ae45c3cba44c9bb0dbdfc1558b7d3 Fix the description of Span::subspan(). by Abseil Team <absl-team@google.com>
- bae1a1c21924bd31fa7315eff05ea6158d9e7947 Port the symbolizer to Windows. by Derek Mauro <dmauro@google.com> - 2253c04c1a4f39d9581772f1dc4491878aa3831f Support absl::Hex() and absl::Dec() as arguments to absl:... by Jorg Brown <jorg@google.com> - 552c3ac259e9c254fda9244755487f3423d2fe4b Internal change by Jorg Brown <jorg@google.com> GitOrigin-RevId: 3a9532fb2d6ae45c3cba44c9bb0dbdfc1558b7d3 Change-Id: I448133c9bb6d837037c12b45a9a16a7945049453
Diffstat (limited to 'absl/debugging')
-rw-r--r--absl/debugging/BUILD.bazel1
-rw-r--r--absl/debugging/CMakeLists.txt1
-rw-r--r--absl/debugging/symbolize.cc9
-rw-r--r--absl/debugging/symbolize_test.cc43
-rw-r--r--absl/debugging/symbolize_win32.inc74
5 files changed, 125 insertions, 3 deletions
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel
index 8543200d..556bb383 100644
--- a/absl/debugging/BUILD.bazel
+++ b/absl/debugging/BUILD.bazel
@@ -46,6 +46,7 @@ cc_library(
"symbolize.cc",
"symbolize_elf.inc",
"symbolize_unimplemented.inc",
+ "symbolize_win32.inc",
],
hdrs = [
"internal/symbolize.h",
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt
index 8d2ec845..456d0727 100644
--- a/absl/debugging/CMakeLists.txt
+++ b/absl/debugging/CMakeLists.txt
@@ -45,6 +45,7 @@ list(APPEND SYMBOLIZE_SRC
"symbolize.cc"
"symbolize_elf.inc"
"symbolize_unimplemented.inc"
+ "symbolize_win32.inc"
"internal/demangle.cc"
${DEBUGGING_PUBLIC_HEADERS}
${DEBUGGING_INTERNAL_HEADERS}
diff --git a/absl/debugging/symbolize.cc b/absl/debugging/symbolize.cc
index 355bf9ff..a35e24cc 100644
--- a/absl/debugging/symbolize.cc
+++ b/absl/debugging/symbolize.cc
@@ -14,8 +14,15 @@
#include "absl/debugging/symbolize.h"
-#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE)
#include "absl/debugging/symbolize_elf.inc"
+#elif defined(_WIN32) && defined(_DEBUG)
+// The Windows Symbolizer only works in debug mode. Note that _DEBUG
+// is the macro that defines whether or not MS C-Runtime debug info is
+// available. Note that the PDB files containing the debug info must
+// also be available to the program at runtime for the symbolizer to
+// work.
+#include "absl/debugging/symbolize_win32.inc"
#else
#include "absl/debugging/symbolize_unimplemented.inc"
#endif
diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc
index b23a8011..c1090b8d 100644
--- a/absl/debugging/symbolize_test.cc
+++ b/absl/debugging/symbolize_test.cc
@@ -90,8 +90,6 @@ static constexpr size_t kHpageSize = 1 << 21;
const char kHpageTextPadding[kHpageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(
".text") = "";
-#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
-
static char try_symbolize_buffer[4096];
// A wrapper function for absl::Symbolize() to make the unit test simple. The
@@ -120,6 +118,8 @@ static const char *TrySymbolize(void *pc) {
return TrySymbolizeWithLimit(pc, sizeof(try_symbolize_buffer));
}
+#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+
TEST(Symbolize, Cached) {
// Compilers should give us pointers to them.
EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
@@ -442,6 +442,45 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() {
#endif
}
+#elif defined(_WIN32) && defined(_DEBUG)
+
+TEST(Symbolize, Basics) {
+ EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
+
+ // The name of an internal linkage symbol is not specified; allow either a
+ // mangled or an unmangled name here.
+ const char* static_func_symbol = TrySymbolize((void *)(&static_func));
+ ASSERT_TRUE(static_func_symbol != nullptr);
+ EXPECT_TRUE(strstr(static_func_symbol, "static_func") != nullptr);
+
+ EXPECT_TRUE(nullptr == TrySymbolize(nullptr));
+}
+
+TEST(Symbolize, Truncation) {
+ constexpr char kNonStaticFunc[] = "nonstatic_func";
+ EXPECT_STREQ("nonstatic_func",
+ TrySymbolizeWithLimit((void *)(&nonstatic_func),
+ strlen(kNonStaticFunc) + 1));
+ EXPECT_STREQ("nonstatic_...",
+ TrySymbolizeWithLimit((void *)(&nonstatic_func),
+ strlen(kNonStaticFunc) + 0));
+ EXPECT_STREQ("nonstatic...",
+ TrySymbolizeWithLimit((void *)(&nonstatic_func),
+ strlen(kNonStaticFunc) - 1));
+ EXPECT_STREQ("n...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 5));
+ EXPECT_STREQ("...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 4));
+ EXPECT_STREQ("..", TrySymbolizeWithLimit((void *)(&nonstatic_func), 3));
+ EXPECT_STREQ(".", TrySymbolizeWithLimit((void *)(&nonstatic_func), 2));
+ EXPECT_STREQ("", TrySymbolizeWithLimit((void *)(&nonstatic_func), 1));
+ EXPECT_EQ(nullptr, TrySymbolizeWithLimit((void *)(&nonstatic_func), 0));
+}
+
+TEST(Symbolize, SymbolizeWithDemangling) {
+ const char* result = TrySymbolize((void *)(&Foo::func));
+ ASSERT_TRUE(result != nullptr);
+ EXPECT_TRUE(strstr(result, "Foo::func") != nullptr) << result;
+}
+
#else // Symbolizer unimplemented
TEST(Symbolize, Unimplemented) {
diff --git a/absl/debugging/symbolize_win32.inc b/absl/debugging/symbolize_win32.inc
new file mode 100644
index 00000000..c300c50a
--- /dev/null
+++ b/absl/debugging/symbolize_win32.inc
@@ -0,0 +1,74 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// See "Retrieving Symbol Information by Address":
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx
+
+#include <windows.h>
+#include <DbgHelp.h>
+#pragma comment(lib, "DbgHelp")
+
+#include <algorithm>
+#include <cstring>
+
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+
+static HANDLE process = NULL;
+
+void InitializeSymbolizer(const char *argv0) {
+ if (process != nullptr) {
+ return;
+ }
+ process = GetCurrentProcess();
+
+ // Symbols are not loaded until a reference is made requiring the
+ // symbols be loaded. This is the fastest, most efficient way to use
+ // the symbol handler.
+ SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
+ if (!SymInitialize(process, nullptr, true)) {
+ // GetLastError() returns a Win32 DWORD, but we assign to
+ // unsigned long to simplify the ABSL_RAW_LOG case below. The uniform
+ // initialization guarantees this is not a narrowing conversion.
+ const unsigned long long error{GetLastError()}; // NOLINT(runtime/int)
+ ABSL_RAW_LOG(FATAL, "SymInitialize() failed: %llu", error);
+ }
+}
+
+bool Symbolize(const void *pc, char *out, int out_size) {
+ if (out_size <= 0) {
+ return false;
+ }
+ std::aligned_storage<sizeof(SYMBOL_INFO) + MAX_SYM_NAME,
+ alignof(SYMBOL_INFO)>::type buf;
+ SYMBOL_INFO *symbol = reinterpret_cast<SYMBOL_INFO *>(&buf);
+ symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+ symbol->MaxNameLen = MAX_SYM_NAME;
+ if (!SymFromAddr(process, reinterpret_cast<DWORD64>(pc), nullptr, symbol)) {
+ return false;
+ }
+ strncpy(out, symbol->Name, out_size);
+ if (out[out_size - 1] != '\0') {
+ // strncpy() does not '\0' terminate when it truncates.
+ static constexpr char kEllipsis[] = "...";
+ int ellipsis_size =
+ std::min<int>(sizeof(kEllipsis) - 1, out_size - 1);
+ memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size);
+ out[out_size - 1] = '\0';
+ }
+ return true;
+}
+
+} // namespace absl