diff options
Diffstat (limited to 'absl/debugging')
-rw-r--r-- | absl/debugging/BUILD.bazel | 5 | ||||
-rw-r--r-- | absl/debugging/internal/demangle.cc | 24 | ||||
-rw-r--r-- | absl/debugging/internal/demangle.h | 68 | ||||
-rw-r--r-- | absl/debugging/internal/demangle_test.cc | 22 |
4 files changed, 85 insertions, 34 deletions
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel index 42124bfb..f50c73f3 100644 --- a/absl/debugging/BUILD.bazel +++ b/absl/debugging/BUILD.bazel @@ -217,7 +217,10 @@ cc_library( hdrs = ["internal/demangle.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = ["//visibility:private"], + visibility = [ + "//absl/container:__pkg__", + "//absl/debugging:__pkg__", + ], deps = [ "//absl/base", "//absl/base:config", diff --git a/absl/debugging/internal/demangle.cc b/absl/debugging/internal/demangle.cc index f2832915..381a2b50 100644 --- a/absl/debugging/internal/demangle.cc +++ b/absl/debugging/internal/demangle.cc @@ -21,7 +21,15 @@ #include <cstdint> #include <cstdio> +#include <cstdlib> #include <limits> +#include <string> + +#include "absl/base/config.h" + +#if ABSL_INTERNAL_HAS_CXA_DEMANGLE +#include <cxxabi.h> +#endif namespace absl { ABSL_NAMESPACE_BEGIN @@ -1983,6 +1991,22 @@ bool Demangle(const char* mangled, char* out, size_t out_size) { state.parse_state.out_cur_idx > 0; } +std::string DemangleString(const char* mangled) { + std::string out; + int status = 0; + char* demangled = nullptr; +#if ABSL_INTERNAL_HAS_CXA_DEMANGLE + demangled = abi::__cxa_demangle(mangled, nullptr, nullptr, &status); +#endif + if (status == 0 && demangled != nullptr) { + out.append(demangled); + free(demangled); + } else { + out.append(mangled); + } + return out; +} + } // namespace debugging_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/debugging/internal/demangle.h b/absl/debugging/internal/demangle.h index e1f15698..146d1150 100644 --- a/absl/debugging/internal/demangle.h +++ b/absl/debugging/internal/demangle.h @@ -12,13 +12,23 @@ // See the License for the specific language governing permissions and // limitations under the License. -// An async-signal-safe and thread-safe demangler for Itanium C++ ABI -// (aka G++ V3 ABI). +#ifndef ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_ +#define ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_ + +#include <string> +#include "absl/base/config.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace debugging_internal { + +// Demangle `mangled`. On success, return true and write the +// demangled symbol name to `out`. Otherwise, return false. +// `out` is modified even if demangling is unsuccessful. // -// The demangler is implemented to be used in async signal handlers to -// symbolize stack traces. We cannot use libstdc++'s -// abi::__cxa_demangle() in such signal handlers since it's not async -// signal safe (it uses malloc() internally). +// This function provides an alternative to libstdc++'s abi::__cxa_demangle, +// which is not async signal safe (it uses malloc internally). It's intended to +// be used in async signal handlers to symbolize stack traces. // // Note that this demangler doesn't support full demangling. More // specifically, it doesn't print types of function parameters and @@ -30,40 +40,32 @@ // // Example: // -// | Mangled Name | The Demangler | abi::__cxa_demangle() -// |---------------|---------------|----------------------- -// | _Z1fv | f() | f() -// | _Z1fi | f() | f(int) -// | _Z3foo3bar | foo() | foo(bar) -// | _Z1fIiEvi | f<>() | void f<int>(int) -// | _ZN1N1fE | N::f | N::f -// | _ZN3Foo3BarEv | Foo::Bar() | Foo::Bar() -// | _Zrm1XS_" | operator%() | operator%(X, X) -// | _ZN3FooC1Ev | Foo::Foo() | Foo::Foo() -// | _Z1fSs | f() | f(std::basic_string<char, -// | | | std::char_traits<char>, -// | | | std::allocator<char> >) +// | Mangled Name | Demangle | DemangleString +// |---------------|-------------|----------------------- +// | _Z1fv | f() | f() +// | _Z1fi | f() | f(int) +// | _Z3foo3bar | foo() | foo(bar) +// | _Z1fIiEvi | f<>() | void f<int>(int) +// | _ZN1N1fE | N::f | N::f +// | _ZN3Foo3BarEv | Foo::Bar() | Foo::Bar() +// | _Zrm1XS_" | operator%() | operator%(X, X) +// | _ZN3FooC1Ev | Foo::Foo() | Foo::Foo() +// | _Z1fSs | f() | f(std::basic_string<char, +// | | | std::char_traits<char>, +// | | | std::allocator<char> >) // // See the unit test for more examples. // // Note: we might want to write demanglers for ABIs other than Itanium // C++ ABI in the future. -// - -#ifndef ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_ -#define ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_ - -#include "absl/base/config.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace debugging_internal { - -// Demangle `mangled`. On success, return true and write the -// demangled symbol name to `out`. Otherwise, return false. -// `out` is modified even if demangling is unsuccessful. bool Demangle(const char* mangled, char* out, size_t out_size); +// A wrapper around `abi::__cxa_demangle()`. On success, returns the demangled +// name. On failure, returns the input mangled name. +// +// This function is not async-signal-safe. +std::string DemangleString(const char* mangled); + } // namespace debugging_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/debugging/internal/demangle_test.cc b/absl/debugging/internal/demangle_test.cc index faec72b5..26ed9cee 100644 --- a/absl/debugging/internal/demangle_test.cc +++ b/absl/debugging/internal/demangle_test.cc @@ -17,6 +17,7 @@ #include <cstdlib> #include <string> +#include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/base/config.h" #include "absl/debugging/internal/stack_consumption.h" @@ -28,6 +29,8 @@ ABSL_NAMESPACE_BEGIN namespace debugging_internal { namespace { +using ::testing::ContainsRegex; + // A wrapper function for Demangle() to make the unit test simple. static const char *DemangleIt(const char * const mangled) { static char demangled[4096]; @@ -237,6 +240,25 @@ TEST(DemangleRegression, DeeplyNestedArrayType) { TestOnInput(data.c_str()); } +struct Base { + virtual ~Base() = default; +}; + +struct Derived : public Base {}; + +TEST(DemangleStringTest, SupportsSymbolNameReturnedByTypeId) { + EXPECT_EQ(DemangleString(typeid(int).name()), "int"); + // We want to test that `DemangleString` can demangle the symbol names + // returned by `typeid`, but without hard-coding the actual demangled values + // (because they are platform-specific). + EXPECT_THAT( + DemangleString(typeid(Base).name()), + ContainsRegex("absl.*debugging_internal.*anonymous namespace.*::Base")); + EXPECT_THAT(DemangleString(typeid(Derived).name()), + ContainsRegex( + "absl.*debugging_internal.*anonymous namespace.*::Derived")); +} + } // namespace } // namespace debugging_internal ABSL_NAMESPACE_END |