From: Lucian Grijincu Date: Tue, 14 Jan 2014 23:38:21 +0000 (-0800) Subject: folly: symbolizer: small terse write fix + colorize signal handler output if printing... X-Git-Tag: v0.22.0~738 X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=commitdiff_plain;h=f41fd6f718fb39b617bbdbc6af0e34f3eae5e381 folly: symbolizer: small terse write fix + colorize signal handler output if printing to TTY Summary: Detailed output is a bit hard to parse visually. Add some colors for clarity (clownyness?). Enabled only when printing stack traces from a signal-handler to TTY. Also: - terse output printed empty lines if it could not find a symbol for an address; fixed by printing "(unknown)". - added a dummy ##Crash## program to test colorization easily Test Plan: n/a Reviewed By: tudorb@fb.com FB internal diff: D1128303 --- diff --git a/folly/experimental/exception_tracer/ExceptionTracer.cpp b/folly/experimental/exception_tracer/ExceptionTracer.cpp index c2fd2b9f..04d3b55e 100644 --- a/folly/experimental/exception_tracer/ExceptionTracer.cpp +++ b/folly/experimental/exception_tracer/ExceptionTracer.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013 Facebook, Inc. + * 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. @@ -14,7 +14,6 @@ * limitations under the License. */ - #include "folly/experimental/exception_tracer/ExceptionTracer.h" #include @@ -69,7 +68,7 @@ std::ostream& operator<<(std::ostream& out, const ExceptionInfo& info) { Symbolizer symbolizer; symbolizer.symbolize(addresses, frames.data(), frameCount); - OStreamSymbolizePrinter osp(out); + OStreamSymbolizePrinter osp(out, SymbolizePrinter::COLOR_IF_TTY); osp.println(addresses, frames.data(), frameCount); } } catch (const std::exception& e) { @@ -206,4 +205,3 @@ void installHandlers() { } // namespace exception_tracer } // namespace folly - diff --git a/folly/experimental/symbolizer/SignalHandler.cpp b/folly/experimental/symbolizer/SignalHandler.cpp index 545380f7..89a58d1c 100644 --- a/folly/experimental/symbolizer/SignalHandler.cpp +++ b/folly/experimental/symbolizer/SignalHandler.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013 Facebook, Inc. + * 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. @@ -201,7 +201,7 @@ void dumpStackTrace() { Symbolizer symbolizer; symbolizer.symbolize(addresses); - FDSymbolizePrinter printer(STDERR_FILENO); + FDSymbolizePrinter printer(STDERR_FILENO, SymbolizePrinter::COLOR_IF_TTY); printer.println(addresses); } } @@ -286,4 +286,3 @@ void installFatalSignalHandler() { } }} // namespaces - diff --git a/folly/experimental/symbolizer/Symbolizer.cpp b/folly/experimental/symbolizer/Symbolizer.cpp index d0f0c165..d7f4db96 100644 --- a/folly/experimental/symbolizer/Symbolizer.cpp +++ b/folly/experimental/symbolizer/Symbolizer.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013 Facebook, Inc. + * 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. @@ -17,15 +17,25 @@ #include "folly/experimental/symbolizer/Symbolizer.h" #include +#include +#include +#include + +#ifdef __GNUC__ +#include +#include +#endif #include "folly/Conv.h" #include "folly/FileUtil.h" +#include "folly/ScopeGuard.h" #include "folly/String.h" #include "folly/experimental/symbolizer/Elf.h" #include "folly/experimental/symbolizer/Dwarf.h" #include "folly/experimental/symbolizer/LineReader.h" + namespace folly { namespace symbolizer { @@ -244,6 +254,9 @@ void Symbolizer::symbolize(const uintptr_t* addresses, namespace { const char kHexChars[] = "0123456789abcdef"; +const SymbolizePrinter::Color kAddressColor = SymbolizePrinter::Color::BLUE; +const SymbolizePrinter::Color kFunctionColor = SymbolizePrinter::Color::PURPLE; +const SymbolizePrinter::Color kFileColor = SymbolizePrinter::Color::DEFAULT; } // namespace void SymbolizePrinter::print(uintptr_t address, const SymbolizedFrame& frame) { @@ -252,6 +265,9 @@ void SymbolizePrinter::print(uintptr_t address, const SymbolizedFrame& frame) { return; } + SCOPE_EXIT { color(Color::DEFAULT); }; + + color(kAddressColor); // Can't use sprintf, not async-signal-safe static_assert(sizeof(uintptr_t) <= 8, "huge uintptr_t?"); char buf[] = " @ 0000000000000000"; @@ -267,6 +283,7 @@ void SymbolizePrinter::print(uintptr_t address, const SymbolizedFrame& frame) { } doPrint(folly::StringPiece(buf, end)); + color(kFunctionColor); char mangledBuf[1024]; if (!frame.found) { doPrint(" (not found)"); @@ -289,6 +306,7 @@ void SymbolizePrinter::print(uintptr_t address, const SymbolizedFrame& frame) { } if (!(options_ & NO_FILE_AND_LINE)) { + color(kFileColor); char fileBuf[PATH_MAX]; fileBuf[0] = '\0'; if (frame.location.hasFileAndLine) { @@ -317,6 +335,33 @@ void SymbolizePrinter::print(uintptr_t address, const SymbolizedFrame& frame) { } } +namespace { + +const std::map kColorMap = { + { SymbolizePrinter::Color::DEFAULT, "\x1B[0m" }, + { SymbolizePrinter::Color::RED, "\x1B[31m" }, + { SymbolizePrinter::Color::GREEN, "\x1B[32m" }, + { SymbolizePrinter::Color::YELLOW, "\x1B[33m" }, + { SymbolizePrinter::Color::BLUE, "\x1B[34m" }, + { SymbolizePrinter::Color::CYAN, "\x1B[36m" }, + { SymbolizePrinter::Color::WHITE, "\x1B[37m" }, + { SymbolizePrinter::Color::PURPLE, "\x1B[35m" }, +}; + +} + +void SymbolizePrinter::color(SymbolizePrinter::Color color) { + if ((options_ & COLOR) == 0 && + ((options_ & COLOR_IF_TTY) == 0 || !isTty_)) { + return; + } + auto it = kColorMap.find(color); + if (it == kColorMap.end()) { + return; + } + doPrint(it->second); +} + void SymbolizePrinter::println(uintptr_t address, const SymbolizedFrame& frame) { print(address, frame); @@ -330,9 +375,9 @@ void SymbolizePrinter::printTerse(uintptr_t address, memcpy(mangledBuf, frame.name.data(), frame.name.size()); mangledBuf[frame.name.size()] = '\0'; - char demangledBuf[1024]; + char demangledBuf[1024] = {0}; demangle(mangledBuf, demangledBuf, sizeof(demangledBuf)); - doPrint(demangledBuf); + doPrint(strlen(demangledBuf) == 0 ? "(unknown)" : demangledBuf); } else { // Can't use sprintf, not async-signal-safe static_assert(sizeof(uintptr_t) <= 8, "huge uintptr_t?"); @@ -356,14 +401,60 @@ void SymbolizePrinter::println(const uintptr_t* addresses, } } +namespace { + +int getFD(const std::ios& stream) { +#ifdef __GNUC__ + std::streambuf* buf = stream.rdbuf(); + using namespace __gnu_cxx; + + { + auto sbuf = dynamic_cast*>(buf); + if (sbuf) { + return fileno(sbuf->file()); + } + } + { + auto sbuf = dynamic_cast*>(buf); + if (sbuf) { + return sbuf->fd(); + } + } +#endif // __GNUC__ + return -1; +} + +bool isTty(int options, int fd) { + return ((options & SymbolizePrinter::TERSE) == 0 && + (options & SymbolizePrinter::COLOR_IF_TTY) != 0 && + fd >= 0 && ::isatty(fd)); +} + +} // anonymous namespace + +OStreamSymbolizePrinter::OStreamSymbolizePrinter(std::ostream& out, int options) + : SymbolizePrinter(options, isTty(options, getFD(out))), + out_(out) { +} + void OStreamSymbolizePrinter::doPrint(StringPiece sp) { out_ << sp; } +FDSymbolizePrinter::FDSymbolizePrinter(int fd, int options) + : SymbolizePrinter(options, isTty(options, fd)), + fd_(fd) { +} + void FDSymbolizePrinter::doPrint(StringPiece sp) { writeFull(fd_, sp.data(), sp.size()); } +FILESymbolizePrinter::FILESymbolizePrinter(FILE* file, int options) + : SymbolizePrinter(options, isTty(options, fileno(file))), + file_(file) { +} + void FILESymbolizePrinter::doPrint(StringPiece sp) { fwrite(sp.data(), 1, sp.size(), file_); } diff --git a/folly/experimental/symbolizer/Symbolizer.h b/folly/experimental/symbolizer/Symbolizer.h index 02655492..0c87ed77 100644 --- a/folly/experimental/symbolizer/Symbolizer.h +++ b/folly/experimental/symbolizer/Symbolizer.h @@ -1,5 +1,5 @@ /* - * Copyright 2013 Facebook, Inc. + * 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. @@ -14,7 +14,6 @@ * limitations under the License. */ - #ifndef FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_ #define FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_ @@ -158,11 +157,25 @@ class SymbolizePrinter { // As terse as it gets: function name if found, address otherwise TERSE = 1 << 1, + + // Always colorize output (ANSI escape code) + COLOR = 1 << 2, + + // Colorize output only if output is printed to a TTY (ANSI escape code) + COLOR_IF_TTY = 1 << 3, }; + enum Color { DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, WHITE, PURPLE }; + void color(Color c); + protected: - explicit SymbolizePrinter(int options) : options_(options) { } + explicit SymbolizePrinter(int options, bool isTty = false) + : options_(options), + isTty_(isTty) { + } + const int options_; + const bool isTty_; private: void printTerse(uintptr_t address, const SymbolizedFrame& frame); @@ -175,9 +188,7 @@ class SymbolizePrinter { */ class OStreamSymbolizePrinter : public SymbolizePrinter { public: - explicit OStreamSymbolizePrinter(std::ostream& out, int options=0) - : SymbolizePrinter(options), - out_(out) { } + explicit OStreamSymbolizePrinter(std::ostream& out, int options=0); private: void doPrint(StringPiece sp) override; std::ostream& out_; @@ -189,9 +200,7 @@ class OStreamSymbolizePrinter : public SymbolizePrinter { */ class FDSymbolizePrinter : public SymbolizePrinter { public: - explicit FDSymbolizePrinter(int fd, int options=0) - : SymbolizePrinter(options), - fd_(fd) { } + explicit FDSymbolizePrinter(int fd, int options=0); private: void doPrint(StringPiece sp) override; int fd_; @@ -203,9 +212,7 @@ class FDSymbolizePrinter : public SymbolizePrinter { */ class FILESymbolizePrinter : public SymbolizePrinter { public: - explicit FILESymbolizePrinter(FILE* file, int options=0) - : SymbolizePrinter(options), - file_(file) { } + explicit FILESymbolizePrinter(FILE* file, int options=0); private: void doPrint(StringPiece sp) override; FILE* file_; @@ -232,4 +239,3 @@ class StringSymbolizePrinter : public SymbolizePrinter { } // namespace folly #endif /* FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_ */ - diff --git a/folly/experimental/symbolizer/test/Crash.cpp b/folly/experimental/symbolizer/test/Crash.cpp new file mode 100644 index 00000000..74eedad8 --- /dev/null +++ b/folly/experimental/symbolizer/test/Crash.cpp @@ -0,0 +1,23 @@ +/* + * 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/experimental/symbolizer/SignalHandler.h" + +int main() { + folly::symbolizer::installFatalSignalHandler(); + *(int*) nullptr = 1; + return 0; +}