diff --git a/folly/Demangle.cpp b/folly/Demangle.cpp new file mode 100644 index 00000000000..3922f74fcb4 --- /dev/null +++ b/folly/Demangle.cpp @@ -0,0 +1,142 @@ +/* + * Copyright 2014 Facebook, Inc. + * + * 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. + */ + +#include "folly/Demangle.h" + +#include +#include + +#include "folly/Malloc.h" + +#if FOLLY_HAVE_CPLUS_DEMANGLE_V3_CALLBACK +# include + +// From libiberty +// +// TODO(tudorb): Detect this with autoconf for the open-source version. +// +// __attribute__((weak)) doesn't work, because cplus_demangle_v3_callback +// is exported by an object file in libiberty.a, and the ELF spec says +// "The link editor does not extract archive members to resolve undefined weak +// symbols" (but, interestingly enough, will resolve undefined weak symbols +// with definitions from archive members that were extracted in order to +// resolve an undefined global (strong) symbol) + +# ifndef DMGL_NO_OPTS +# define FOLLY_DEFINED_DMGL 1 +# define DMGL_NO_OPTS 0 /* For readability... */ +# define DMGL_PARAMS (1 << 0) /* Include function args */ +# define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ +# define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */ +# define DMGL_VERBOSE (1 << 3) /* Include implementation details. */ +# define DMGL_TYPES (1 << 4) /* Also try to demangle type encodings. */ +# define DMGL_RET_POSTFIX (1 << 5) /* Print function return types (when + present) after function signature */ +# endif + +extern "C" int cplus_demangle_v3_callback( + const char* mangled, + int options, // We use DMGL_PARAMS | DMGL_TYPES, aka 0x11 + void (*callback)(const char*, size_t, void*), + void* arg); + +#endif + +namespace { + +// glibc doesn't have strlcpy +size_t my_strlcpy(char* dest, const char* src, size_t size) { + size_t len = strlen(src); + if (size != 0) { + size_t n = std::min(len, size - 1); // always null terminate! + memcpy(dest, src, n); + dest[n] = '\0'; + } + return len; +} + +} // namespace + +namespace folly { + +#if FOLLY_HAVE_CPLUS_DEMANGLE_V3_CALLBACK + +fbstring demangle(const char* name) { + int status; + size_t len = 0; + // malloc() memory for the demangled type name + char* demangled = abi::__cxa_demangle(name, nullptr, &len, &status); + if (status != 0) { + return name; + } + // len is the length of the buffer (including NUL terminator and maybe + // other junk) + return fbstring(demangled, strlen(demangled), len, AcquireMallocatedString()); +} + +namespace { + +struct DemangleBuf { + char* dest; + size_t remaining; + size_t total; +}; + +void demangleCallback(const char* str, size_t size, void* p) { + DemangleBuf* buf = static_cast(p); + size_t n = std::min(buf->remaining, size); + memcpy(buf->dest, str, n); + buf->dest += n; + buf->remaining -= n; + buf->total += size; +} + +} // namespace + +size_t demangle(const char* name, char* out, size_t outSize) { + DemangleBuf dbuf; + dbuf.dest = out; + dbuf.remaining = outSize ? outSize - 1 : 0; // leave room for null term + dbuf.total = 0; + + // Unlike most library functions, this returns 1 on success and 0 on failure + int status = cplus_demangle_v3_callback( + name, + DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES, + demangleCallback, + &dbuf); + if (status == 0) { // failed, return original + return my_strlcpy(out, name, outSize); + } + if (outSize != 0) { + *dbuf.dest = '\0'; + } + return dbuf.total; +} + +#else + +fbstring demangle(const char* name) { + return name; +} + +size_t demangle(const char* name, char* out, size_t outSize) { + return my_strlcpy(out, name, outSize); +} + +#endif + +} // folly diff --git a/folly/Demangle.h b/folly/Demangle.h new file mode 100644 index 00000000000..205fdb65a3f --- /dev/null +++ b/folly/Demangle.h @@ -0,0 +1,62 @@ +/* + * Copyright 2014 Facebook, Inc. + * + * 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. + */ + +#pragma once + +#include "folly/FBString.h" + +namespace folly { + +/** + * Return the demangled (prettyfied) version of a C++ type. + * + * This function tries to produce a human-readable type, but the type name will + * be returned unchanged in case of error or if demangling isn't supported on + * your system. + * + * Use for debugging -- do not rely on demangle() returning anything useful. + * + * This function may allocate memory (and therefore throw std::bad_alloc). + */ +fbstring demangle(const char* name); +inline fbstring demangle(const std::type_info& type) { + return demangle(type.name()); +} + +/** + * Return the demangled (prettyfied) version of a C++ type in a user-provided + * buffer. + * + * The semantics are the same as for snprintf or strlcpy: bufSize is the size + * of the buffer, the string is always null-terminated, and the return value is + * the number of characters (not including the null terminator) that would have + * been written if the buffer was big enough. (So a return value >= bufSize + * indicates that the output was truncated) + * + * This function does not allocate memory and is async-signal-safe. + * + * Note that the underlying function for the fbstring-returning demangle is + * somewhat standard (abi::__cxa_demangle, which uses malloc), the underlying + * function for this version is less so (cplus_demangle_v3_callback from + * libiberty), so it is possible for the fbstring version to work, while this + * version returns the original, mangled name. + */ +size_t demangle(const char* name, char* buf, size_t bufSize); +inline size_t demangle(const std::type_info& type, char* buf, size_t bufSize) { + return demangle(type.name(), buf, bufSize); +} + +} diff --git a/folly/Makefile.am b/folly/Makefile.am index fb4220eb279..6dd25ab061b 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -162,6 +162,7 @@ libfolly_la_SOURCES = \ Benchmark.cpp \ Bits.cpp \ Conv.cpp \ + Demangle.cpp \ detail/CacheLocality.cpp \ dynamic.cpp \ EscapeTables.cpp \ diff --git a/folly/String.cpp b/folly/String.cpp index 2841ce0c94a..d8c25b55174 100644 --- a/folly/String.cpp +++ b/folly/String.cpp @@ -24,40 +24,6 @@ #include #include -#if FOLLY_HAVE_CPLUS_DEMANGLE_V3_CALLBACK -# include - -// From libiberty -// -// TODO(tudorb): Detect this with autoconf for the open-source version. -// -// __attribute__((weak)) doesn't work, because cplus_demangle_v3_callback -// is exported by an object file in libiberty.a, and the ELF spec says -// "The link editor does not extract archive members to resolve undefined weak -// symbols" (but, interestingly enough, will resolve undefined weak symbols -// with definitions from archive members that were extracted in order to -// resolve an undefined global (strong) symbol) - -# ifndef DMGL_NO_OPTS -# define FOLLY_DEFINED_DMGL 1 -# define DMGL_NO_OPTS 0 /* For readability... */ -# define DMGL_PARAMS (1 << 0) /* Include function args */ -# define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ -# define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */ -# define DMGL_VERBOSE (1 << 3) /* Include implementation details. */ -# define DMGL_TYPES (1 << 4) /* Also try to demangle type encodings. */ -# define DMGL_RET_POSTFIX (1 << 5) /* Print function return types (when - present) after function signature */ -# endif - -extern "C" int cplus_demangle_v3_callback( - const char* mangled, - int options, // We use DMGL_PARAMS | DMGL_TYPES, aka 0x11 - void (*callback)(const char*, size_t, void*), - void* arg); - -#endif - namespace folly { namespace { @@ -292,88 +258,6 @@ fbstring errnoStr(int err) { return result; } -namespace { - -// glibc doesn't have strlcpy -size_t my_strlcpy(char* dest, const char* src, size_t size) { - size_t len = strlen(src); - if (size != 0) { - size_t n = std::min(len, size - 1); // always null terminate! - memcpy(dest, src, n); - dest[n] = '\0'; - } - return len; -} - -} // namespace - -#if FOLLY_HAVE_CPLUS_DEMANGLE_V3_CALLBACK - -fbstring demangle(const char* name) { - int status; - size_t len = 0; - // malloc() memory for the demangled type name - char* demangled = abi::__cxa_demangle(name, nullptr, &len, &status); - if (status != 0) { - return name; - } - // len is the length of the buffer (including NUL terminator and maybe - // other junk) - return fbstring(demangled, strlen(demangled), len, AcquireMallocatedString()); -} - -namespace { - -struct DemangleBuf { - char* dest; - size_t remaining; - size_t total; -}; - -void demangleCallback(const char* str, size_t size, void* p) { - DemangleBuf* buf = static_cast(p); - size_t n = std::min(buf->remaining, size); - memcpy(buf->dest, str, n); - buf->dest += n; - buf->remaining -= n; - buf->total += size; -} - -} // namespace - -size_t demangle(const char* name, char* out, size_t outSize) { - DemangleBuf dbuf; - dbuf.dest = out; - dbuf.remaining = outSize ? outSize - 1 : 0; // leave room for null term - dbuf.total = 0; - - // Unlike most library functions, this returns 1 on success and 0 on failure - int status = cplus_demangle_v3_callback( - name, - DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES, - demangleCallback, - &dbuf); - if (status == 0) { // failed, return original - return my_strlcpy(out, name, outSize); - } - if (outSize != 0) { - *dbuf.dest = '\0'; - } - return dbuf.total; -} - -#else - -fbstring demangle(const char* name) { - return name; -} - -size_t demangle(const char* name, char* out, size_t outSize) { - return my_strlcpy(out, name, outSize); -} - -#endif - namespace detail { size_t hexDumpLine(const void* ptr, size_t offset, size_t size, diff --git a/folly/String.h b/folly/String.h index 90f9c739385..241d4dbf6aa 100644 --- a/folly/String.h +++ b/folly/String.h @@ -30,6 +30,7 @@ #include #include "folly/Conv.h" +#include "folly/Demangle.h" #include "folly/FBString.h" #include "folly/FBVector.h" #include "folly/Portability.h" @@ -317,45 +318,6 @@ std::string hexDump(const void* ptr, size_t size); */ fbstring errnoStr(int err); -/** - * Return the demangled (prettyfied) version of a C++ type. - * - * This function tries to produce a human-readable type, but the type name will - * be returned unchanged in case of error or if demangling isn't supported on - * your system. - * - * Use for debugging -- do not rely on demangle() returning anything useful. - * - * This function may allocate memory (and therefore throw std::bad_alloc). - */ -fbstring demangle(const char* name); -inline fbstring demangle(const std::type_info& type) { - return demangle(type.name()); -} - -/** - * Return the demangled (prettyfied) version of a C++ type in a user-provided - * buffer. - * - * The semantics are the same as for snprintf or strlcpy: bufSize is the size - * of the buffer, the string is always null-terminated, and the return value is - * the number of characters (not including the null terminator) that would have - * been written if the buffer was big enough. (So a return value >= bufSize - * indicates that the output was truncated) - * - * This function does not allocate memory and is async-signal-safe. - * - * Note that the underlying function for the fbstring-returning demangle is - * somewhat standard (abi::__cxa_demangle, which uses malloc), the underlying - * function for this version is less so (cplus_demangle_v3_callback from - * libiberty), so it is possible for the fbstring version to work, while this - * version returns the original, mangled name. - */ -size_t demangle(const char* name, char* buf, size_t bufSize); -inline size_t demangle(const std::type_info& type, char* buf, size_t bufSize) { - return demangle(type.name(), buf, bufSize); -} - /** * Debug string for an exception: include type and what(). */