From: Tudor Bosman Date: Tue, 10 Dec 2013 03:57:56 +0000 (-0800) Subject: Switch to folly symbolizer X-Git-Tag: v0.22.0~763 X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=commitdiff_plain;h=5357f0f41cab05cc2097bd13a486103d96acaba4 Switch to folly symbolizer Summary: (not committing yet, but I want to trigger unittests) The glog symbolizer that we use has a few bugs (abort()s on certain small shared libraries) and doesn't allow us to distinguish between template specializations and function overloads (which, given that our code is more template-heavy than Google's, has in fact been an issue). Luckily, we have our own in folly, which doesn't have these problems and also supports mappings from address to file and line number. Switch translateFrames (aka the fb303 call that cpprof uses) to our symbolizer. Also, removed a lot of dead code in common/process. Test Plan: common/process, tested cpprof by hand Reviewed By: lucian@fb.com FB internal diff: D1090907 @override-unit-failures --- diff --git a/folly/String.cpp b/folly/String.cpp index 44b6a783..a90dd225 100644 --- a/folly/String.cpp +++ b/folly/String.cpp @@ -40,6 +40,19 @@ // 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 @@ -340,7 +353,7 @@ size_t demangle(const char* name, char* out, size_t outSize) { // Unlike most library functions, this returns 1 on success and 0 on failure int status = cplus_demangle_v3_callback( name, - 0x11, // DMGL_PARAMS | DMGL_TYPES + DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES, demangleCallback, &dbuf); if (status == 0) { // failed, return original @@ -410,3 +423,15 @@ size_t hexDumpLine(const void* ptr, size_t offset, size_t size, } // namespace detail } // namespace folly + +#ifdef FOLLY_DEFINED_DMGL +# undef FOLLY_DEFINED_DMGL +# undef DMGL_NO_OPTS +# undef DMGL_PARAMS +# undef DMGL_ANSI +# undef DMGL_JAVA +# undef DMGL_VERBOSE +# undef DMGL_TYPES +# undef DMGL_RET_POSTFIX +#endif + diff --git a/folly/experimental/exception_tracer/ExceptionTracer.cpp b/folly/experimental/exception_tracer/ExceptionTracer.cpp index 533eb009..c2fd2b9f 100644 --- a/folly/experimental/exception_tracer/ExceptionTracer.cpp +++ b/folly/experimental/exception_tracer/ExceptionTracer.cpp @@ -70,7 +70,7 @@ std::ostream& operator<<(std::ostream& out, const ExceptionInfo& info) { symbolizer.symbolize(addresses, frames.data(), frameCount); OStreamSymbolizePrinter osp(out); - osp.print(addresses, frames.data(), frameCount); + osp.println(addresses, frames.data(), frameCount); } } catch (const std::exception& e) { out << "\n !! caught " << folly::exceptionStr(e) << "\n"; diff --git a/folly/experimental/symbolizer/SignalHandler.cpp b/folly/experimental/symbolizer/SignalHandler.cpp index 8cdf03a4..dc34c235 100644 --- a/folly/experimental/symbolizer/SignalHandler.cpp +++ b/folly/experimental/symbolizer/SignalHandler.cpp @@ -201,7 +201,7 @@ void dumpStackTrace() { symbolizer.symbolize(addresses); FDSymbolizePrinter printer(STDERR_FILENO); - printer.print(addresses); + printer.println(addresses); } } diff --git a/folly/experimental/symbolizer/Symbolizer.cpp b/folly/experimental/symbolizer/Symbolizer.cpp index 563abb75..2719caaa 100644 --- a/folly/experimental/symbolizer/Symbolizer.cpp +++ b/folly/experimental/symbolizer/Symbolizer.cpp @@ -247,6 +247,11 @@ const char kHexChars[] = "0123456789abcdef"; } // namespace void SymbolizePrinter::print(uintptr_t address, const SymbolizedFrame& frame) { + if (options_ & TERSE) { + printTerse(address, frame); + return; + } + // Can't use sprintf, not async-signal-safe static_assert(sizeof(uintptr_t) <= 8, "huge uintptr_t?"); char buf[] = " @ 0000000000000000"; @@ -273,7 +278,6 @@ void SymbolizePrinter::print(uintptr_t address, const SymbolizedFrame& frame) { } else if (frame.name.size() >= sizeof(mangledBuf)) { doPrint(" "); doPrint(frame.name); - doPrint("\n"); } else { memcpy(mangledBuf, frame.name.data(), frame.name.size()); mangledBuf[frame.name.size()] = '\0'; @@ -282,41 +286,73 @@ void SymbolizePrinter::print(uintptr_t address, const SymbolizedFrame& frame) { demangle(mangledBuf, demangledBuf, sizeof(demangledBuf)); doPrint(" "); doPrint(demangledBuf); - doPrint("\n"); } - char fileBuf[PATH_MAX]; - fileBuf[0] = '\0'; - if (frame.location.hasFileAndLine) { - frame.location.file.toBuffer(fileBuf, sizeof(fileBuf)); - doPrint(pad); - doPrint(fileBuf); - - char buf[22]; - uint32_t n = uint64ToBufferUnsafe(frame.location.line, buf); - doPrint(":"); - doPrint(StringPiece(buf, n)); - doPrint("\n"); + if (!(options_ & NO_FILE_AND_LINE)) { + char fileBuf[PATH_MAX]; + fileBuf[0] = '\0'; + if (frame.location.hasFileAndLine) { + frame.location.file.toBuffer(fileBuf, sizeof(fileBuf)); + doPrint("\n"); + doPrint(pad); + doPrint(fileBuf); + + char buf[22]; + uint32_t n = uint64ToBufferUnsafe(frame.location.line, buf); + doPrint(":"); + doPrint(StringPiece(buf, n)); + } + + if (frame.location.hasMainFile) { + char mainFileBuf[PATH_MAX]; + mainFileBuf[0] = '\0'; + frame.location.mainFile.toBuffer(mainFileBuf, sizeof(mainFileBuf)); + if (!frame.location.hasFileAndLine || strcmp(fileBuf, mainFileBuf)) { + doPrint("\n"); + doPrint(pad); + doPrint("-> "); + doPrint(mainFileBuf); + } + } } +} - if (frame.location.hasMainFile) { - char mainFileBuf[PATH_MAX]; - mainFileBuf[0] = '\0'; - frame.location.mainFile.toBuffer(mainFileBuf, sizeof(mainFileBuf)); - if (!frame.location.hasFileAndLine || strcmp(fileBuf, mainFileBuf)) { - doPrint(pad); - doPrint("-> "); - doPrint(mainFileBuf); - doPrint("\n"); +void SymbolizePrinter::println(uintptr_t address, + const SymbolizedFrame& frame) { + print(address, frame); + doPrint("\n"); +} + +void SymbolizePrinter::printTerse(uintptr_t address, + const SymbolizedFrame& frame) { + if (frame.found) { + char mangledBuf[1024]; + memcpy(mangledBuf, frame.name.data(), frame.name.size()); + mangledBuf[frame.name.size()] = '\0'; + + char demangledBuf[1024]; + demangle(mangledBuf, demangledBuf, sizeof(demangledBuf)); + doPrint(demangledBuf); + } else { + // Can't use sprintf, not async-signal-safe + static_assert(sizeof(uintptr_t) <= 8, "huge uintptr_t?"); + char buf[] = "0x0000000000000000"; + char* end = buf + sizeof(buf) - 1 - (16 - 2 * sizeof(uintptr_t)); + char* p = end; + *p-- = '\0'; + while (address != 0) { + *p-- = kHexChars[address & 0xf]; + address >>= 4; } + doPrint(StringPiece(buf, end)); } } -void SymbolizePrinter::print(const uintptr_t* addresses, - const SymbolizedFrame* frames, - size_t frameCount) { +void SymbolizePrinter::println(const uintptr_t* addresses, + const SymbolizedFrame* frames, + size_t frameCount) { for (size_t i = 0; i < frameCount; ++i) { - print(addresses[i], frames[i]); + println(addresses[i], frames[i]); } } @@ -328,5 +364,13 @@ void FDSymbolizePrinter::doPrint(StringPiece sp) { writeFull(fd_, sp.data(), sp.size()); } +void FILESymbolizePrinter::doPrint(StringPiece sp) { + fwrite(sp.data(), 1, sp.size(), file_); +} + +void StringSymbolizePrinter::doPrint(StringPiece sp) { + buf_.append(sp.data(), sp.size()); +} + } // namespace symbolizer } // namespace folly diff --git a/folly/experimental/symbolizer/Symbolizer.h b/folly/experimental/symbolizer/Symbolizer.h index d3e6d452..bef46f3b 100644 --- a/folly/experimental/symbolizer/Symbolizer.h +++ b/folly/experimental/symbolizer/Symbolizer.h @@ -22,6 +22,7 @@ #include #include +#include "folly/FBString.h" #include "folly/Range.h" #include "folly/experimental/symbolizer/Elf.h" #include "folly/experimental/symbolizer/Dwarf.h" @@ -110,20 +111,50 @@ class Symbolizer { */ class SymbolizePrinter { public: + /** + * Print one address, no ending newline. + */ void print(uintptr_t address, const SymbolizedFrame& frame); - void print(const uintptr_t* addresses, - const SymbolizedFrame* frames, - size_t frameCount); + /** + * Print one address with ending newline. + */ + void println(uintptr_t address, const SymbolizedFrame& frame); + + /** + * Print multiple addresses on separate lines. + */ + void println(const uintptr_t* addresses, + const SymbolizedFrame* frames, + size_t frameCount); + + /** + * Print multiple addresses on separate lines, skipping the first + * skip addresses. + */ template - void print(const FrameArray& fa, size_t skip=0) { + void println(const FrameArray& fa, size_t skip=0) { if (skip < fa.frameCount) { - print(fa.addresses + skip, fa.frames + skip, fa.frameCount - skip); + println(fa.addresses + skip, fa.frames + skip, fa.frameCount - skip); } } virtual ~SymbolizePrinter() { } + + enum Options { + // Skip file and line information + NO_FILE_AND_LINE = 1 << 0, + + // As terse as it gets: function name if found, address otherwise + TERSE = 1 << 1, + }; + + protected: + explicit SymbolizePrinter(int options) : options_(options) { } + const int options_; + private: + void printTerse(uintptr_t address, const SymbolizedFrame& frame); virtual void doPrint(StringPiece sp) = 0; }; @@ -133,7 +164,9 @@ class SymbolizePrinter { */ class OStreamSymbolizePrinter : public SymbolizePrinter { public: - explicit OStreamSymbolizePrinter(std::ostream& out) : out_(out) { } + explicit OStreamSymbolizePrinter(std::ostream& out, int options=0) + : SymbolizePrinter(options), + out_(out) { } private: void doPrint(StringPiece sp) override; std::ostream& out_; @@ -145,12 +178,45 @@ class OStreamSymbolizePrinter : public SymbolizePrinter { */ class FDSymbolizePrinter : public SymbolizePrinter { public: - explicit FDSymbolizePrinter(int fd) : fd_(fd) { } + explicit FDSymbolizePrinter(int fd, int options=0) + : SymbolizePrinter(options), + fd_(fd) { } private: void doPrint(StringPiece sp) override; int fd_; }; +/** + * Print a list of symbolized addresses to a FILE*. + * Ignores errors. Not reentrant. Do not use from signal handling code. + */ +class FILESymbolizePrinter : public SymbolizePrinter { + public: + explicit FILESymbolizePrinter(FILE* file, int options=0) + : SymbolizePrinter(options), + file_(file) { } + private: + void doPrint(StringPiece sp) override; + FILE* file_; +}; + +/** + * Print a list of symbolized addresses to a std::string. + * Not reentrant. Do not use from signal handling code. + */ +class StringSymbolizePrinter : public SymbolizePrinter { + public: + explicit StringSymbolizePrinter(int options=0) : SymbolizePrinter(options) { } + + std::string str() const { return buf_.toStdString(); } + const fbstring& fbstr() const { return buf_; } + fbstring moveFbString() { return std::move(buf_); } + + private: + void doPrint(StringPiece sp) override; + fbstring buf_; +}; + } // namespace symbolizer } // namespace folly