Commit f41fd6f7 authored by Lucian Grijincu's avatar Lucian Grijincu Committed by Jordan DeLong

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
parent 29d4c417
/*
* 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 <dlfcn.h>
......@@ -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
/*
* 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
/*
* 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 <limits.h>
#include <cstdio>
#include <iostream>
#include <map>
#ifdef __GNUC__
#include <ext/stdio_filebuf.h>
#include <ext/stdio_sync_filebuf.h>
#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<SymbolizePrinter::Color, std::string> 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<stdio_sync_filebuf<char>*>(buf);
if (sbuf) {
return fileno(sbuf->file());
}
}
{
auto sbuf = dynamic_cast<stdio_filebuf<char>*>(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_);
}
......
/*
* 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_ */
/*
* 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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment