Commit 52264b66 authored by Chad Austin's avatar Chad Austin Committed by Facebook GitHub Bot

split SymbolizePrinter into its own target

Summary:
The SymbolizePrinter classes are portable to any unix, so split them
into their own target.

Reviewed By: yfeldblum, luciang

Differential Revision: D22883912

fbshipit-source-id: 3bce6d6584182b818bf803da187eae56477bac8a
parent 78f06465
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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/SymbolizePrinter.h>
#include <folly/Conv.h>
#include <folly/Demangle.h>
#include <folly/FileUtil.h>
#include <folly/ScopeGuard.h>
#include <folly/io/IOBuf.h>
#ifdef __GLIBCXX__
#include <ext/stdio_filebuf.h>
#include <ext/stdio_sync_filebuf.h>
#endif
namespace folly {
namespace symbolizer {
namespace {
constexpr char kHexChars[] = "0123456789abcdef";
constexpr auto kAddressColor = SymbolizePrinter::Color::BLUE;
constexpr auto kFunctionColor = SymbolizePrinter::Color::PURPLE;
constexpr auto kFileColor = SymbolizePrinter::Color::DEFAULT;
} // namespace
constexpr char AddressFormatter::bufTemplate[];
constexpr std::array<const char*, SymbolizePrinter::Color::NUM>
SymbolizePrinter::kColorMap;
AddressFormatter::AddressFormatter() {
memcpy(buf_, bufTemplate, sizeof(buf_));
}
folly::StringPiece AddressFormatter::format(uintptr_t address) {
// Can't use sprintf, not async-signal-safe
static_assert(sizeof(uintptr_t) <= 8, "huge uintptr_t?");
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;
}
return folly::StringPiece(buf_, end);
}
void SymbolizePrinter::print(const SymbolizedFrame& frame) {
if (options_ & TERSE) {
printTerse(frame);
return;
}
SCOPE_EXIT {
color(Color::DEFAULT);
};
if (!(options_ & NO_FRAME_ADDRESS) && !(options_ & TERSE_FILE_AND_LINE)) {
color(kAddressColor);
AddressFormatter formatter;
doPrint(formatter.format(frame.addr));
}
const char padBuf[] = " ";
folly::StringPiece pad(
padBuf, sizeof(padBuf) - 1 - (16 - 2 * sizeof(uintptr_t)));
color(kFunctionColor);
if (!frame.found) {
doPrint(" (not found)");
return;
}
if (!(options_ & TERSE_FILE_AND_LINE)) {
if (!frame.name || frame.name[0] == '\0') {
doPrint(" (unknown)");
} else {
char demangledBuf[2048];
folly::demangle(frame.name, demangledBuf, sizeof(demangledBuf));
doPrint(" ");
doPrint(demangledBuf[0] == '\0' ? frame.name : demangledBuf);
}
}
if (!(options_ & NO_FILE_AND_LINE)) {
color(kFileColor);
char fileBuf[PATH_MAX];
fileBuf[0] = '\0';
if (frame.location.hasFileAndLine) {
frame.location.file.toBuffer(fileBuf, sizeof(fileBuf));
if (!(options_ & TERSE_FILE_AND_LINE)) {
doPrint("\n");
doPrint(pad);
}
doPrint(fileBuf);
char buf[22];
uint32_t n = uint64ToBufferUnsafe(frame.location.line, buf);
doPrint(":");
doPrint(StringPiece(buf, n));
} else {
if ((options_ & TERSE_FILE_AND_LINE)) {
doPrint("(unknown)");
}
}
if (frame.location.hasMainFile && !(options_ & TERSE_FILE_AND_LINE)) {
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);
}
}
}
}
void SymbolizePrinter::color(SymbolizePrinter::Color color) {
if ((options_ & COLOR) == 0 && ((options_ & COLOR_IF_TTY) == 0 || !isTty_)) {
return;
}
if (static_cast<size_t>(color) >= kColorMap.size()) { // catches underflow too
return;
}
doPrint(kColorMap[color]);
}
void SymbolizePrinter::println(const SymbolizedFrame& frame) {
print(frame);
doPrint("\n");
}
void SymbolizePrinter::printTerse(const SymbolizedFrame& frame) {
if (frame.found && frame.name && frame.name[0] != '\0') {
char demangledBuf[2048] = {0};
demangle(frame.name, demangledBuf, sizeof(demangledBuf));
doPrint(demangledBuf[0] == '\0' ? frame.name : 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';
auto address = frame.addr;
while (address != 0) {
*p-- = kHexChars[address & 0xf];
address >>= 4;
}
doPrint(StringPiece(buf, end));
}
}
void SymbolizePrinter::println(
const SymbolizedFrame* frames,
size_t frameCount) {
for (size_t i = 0; i < frameCount; ++i) {
println(frames[i]);
}
}
namespace {
int getFD(const std::ios& stream) {
#if FOLLY_USE_LIBSTDCPP && FOLLY_HAS_RTTI
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();
}
}
#else
(void)stream;
#endif // __GNUC__
return -1;
}
bool isColorfulTty(int options, int fd) {
if ((options & SymbolizePrinter::TERSE) != 0 ||
(options & SymbolizePrinter::COLOR_IF_TTY) == 0 || fd < 0 ||
!::isatty(fd)) {
return false;
}
auto term = ::getenv("TERM");
return !(term == nullptr || term[0] == '\0' || strcmp(term, "dumb") == 0);
}
} // namespace
OStreamSymbolizePrinter::OStreamSymbolizePrinter(std::ostream& out, int options)
: SymbolizePrinter(options, isColorfulTty(options, getFD(out))),
out_(out) {}
void OStreamSymbolizePrinter::doPrint(StringPiece sp) {
out_ << sp;
}
FDSymbolizePrinter::FDSymbolizePrinter(int fd, int options, size_t bufferSize)
: SymbolizePrinter(options, isColorfulTty(options, fd)),
fd_(fd),
buffer_(bufferSize ? IOBuf::create(bufferSize) : nullptr) {}
FDSymbolizePrinter::~FDSymbolizePrinter() {
flush();
}
void FDSymbolizePrinter::doPrint(StringPiece sp) {
if (buffer_) {
if (sp.size() > buffer_->tailroom()) {
flush();
writeFull(fd_, sp.data(), sp.size());
} else {
memcpy(buffer_->writableTail(), sp.data(), sp.size());
buffer_->append(sp.size());
}
} else {
writeFull(fd_, sp.data(), sp.size());
}
}
void FDSymbolizePrinter::flush() {
if (buffer_ && !buffer_->empty()) {
writeFull(fd_, buffer_->data(), buffer_->length());
buffer_->clear();
}
}
FILESymbolizePrinter::FILESymbolizePrinter(FILE* file, int options)
: SymbolizePrinter(options, isColorfulTty(options, fileno(file))),
file_(file) {}
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
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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>
#include <folly/Range.h>
#include <folly/experimental/symbolizer/SymbolizedFrame.h>
#include <cstdint>
namespace folly {
class IOBuf;
namespace symbolizer {
/**
* Format one address in the way it's usually printed by SymbolizePrinter.
* Async-signal-safe.
*/
class AddressFormatter {
public:
AddressFormatter();
/**
* Format the address. Returns an internal buffer.
*/
StringPiece format(uintptr_t address);
private:
static constexpr char bufTemplate[] = " @ 0000000000000000";
char buf_[sizeof(bufTemplate)];
};
/**
* Print a list of symbolized addresses. Base class.
*/
class SymbolizePrinter {
public:
/**
* Print one frame, no ending newline.
*/
void print(const SymbolizedFrame& frame);
/**
* Print one frame with ending newline.
*/
void println(const SymbolizedFrame& frame);
/**
* Print multiple frames on separate lines.
*/
void println(const SymbolizedFrame* frames, size_t frameCount);
/**
* Print a string, no endling newline.
*/
void print(StringPiece sp) {
doPrint(sp);
}
/**
* Print multiple frames on separate lines, skipping the first
* skip addresses.
*/
template <size_t N>
void println(const FrameArray<N>& fa, size_t skip = 0) {
if (skip < fa.frameCount) {
println(fa.frames + skip, fa.frameCount - skip);
}
}
/**
* If output buffered inside this class, send it to the output stream, so that
* any output done in other ways appears after this.
*/
virtual void flush() {}
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,
// 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,
// Skip frame address information
NO_FRAME_ADDRESS = 1 << 4,
// Simple file and line output
TERSE_FILE_AND_LINE = 1 << 5,
};
// NOTE: enum values used as indexes in kColorMap.
enum Color { DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, WHITE, PURPLE, NUM };
void color(Color c);
protected:
explicit SymbolizePrinter(int options, bool isTty = false)
: options_(options), isTty_(isTty) {}
const int options_;
const bool isTty_;
private:
void printTerse(const SymbolizedFrame& frame);
virtual void doPrint(StringPiece sp) = 0;
static constexpr std::array<const char*, Color::NUM> kColorMap = {{
"\x1B[0m",
"\x1B[31m",
"\x1B[32m",
"\x1B[33m",
"\x1B[34m",
"\x1B[36m",
"\x1B[37m",
"\x1B[35m",
}};
};
/**
* Print a list of symbolized addresses to a stream.
* Not reentrant. Do not use from signal handling code.
*/
class OStreamSymbolizePrinter : public SymbolizePrinter {
public:
explicit OStreamSymbolizePrinter(std::ostream& out, int options = 0);
private:
void doPrint(StringPiece sp) override;
std::ostream& out_;
};
/**
* Print a list of symbolized addresses to a file descriptor.
* Ignores errors. Async-signal-safe.
*/
class FDSymbolizePrinter : public SymbolizePrinter {
public:
explicit FDSymbolizePrinter(int fd, int options = 0, size_t bufferSize = 0);
~FDSymbolizePrinter() override;
virtual void flush() override;
private:
void doPrint(StringPiece sp) override;
const int fd_;
std::unique_ptr<IOBuf> buffer_;
};
/**
* 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);
private:
void doPrint(StringPiece sp) override;
FILE* const file_ = nullptr;
};
/**
* 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
...@@ -24,11 +24,6 @@ ...@@ -24,11 +24,6 @@
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
#ifdef __GLIBCXX__
#include <ext/stdio_filebuf.h>
#include <ext/stdio_sync_filebuf.h>
#endif
#include <folly/Conv.h> #include <folly/Conv.h>
#include <folly/FileUtil.h> #include <folly/FileUtil.h>
#include <folly/Memory.h> #include <folly/Memory.h>
...@@ -239,240 +234,6 @@ size_t Symbolizer::symbolize( ...@@ -239,240 +234,6 @@ size_t Symbolizer::symbolize(
return addrCount; return addrCount;
} }
namespace {
constexpr char kHexChars[] = "0123456789abcdef";
constexpr auto kAddressColor = SymbolizePrinter::Color::BLUE;
constexpr auto kFunctionColor = SymbolizePrinter::Color::PURPLE;
constexpr auto kFileColor = SymbolizePrinter::Color::DEFAULT;
} // namespace
constexpr char AddressFormatter::bufTemplate[];
constexpr std::array<const char*, SymbolizePrinter::Color::NUM>
SymbolizePrinter::kColorMap;
AddressFormatter::AddressFormatter() {
memcpy(buf_, bufTemplate, sizeof(buf_));
}
folly::StringPiece AddressFormatter::format(uintptr_t address) {
// Can't use sprintf, not async-signal-safe
static_assert(sizeof(uintptr_t) <= 8, "huge uintptr_t?");
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;
}
return folly::StringPiece(buf_, end);
}
void SymbolizePrinter::print(const SymbolizedFrame& frame) {
if (options_ & TERSE) {
printTerse(frame);
return;
}
SCOPE_EXIT {
color(Color::DEFAULT);
};
if (!(options_ & NO_FRAME_ADDRESS) && !(options_ & TERSE_FILE_AND_LINE)) {
color(kAddressColor);
AddressFormatter formatter;
doPrint(formatter.format(frame.addr));
}
const char padBuf[] = " ";
folly::StringPiece pad(
padBuf, sizeof(padBuf) - 1 - (16 - 2 * sizeof(uintptr_t)));
color(kFunctionColor);
if (!frame.found) {
doPrint(" (not found)");
return;
}
if (!(options_ & TERSE_FILE_AND_LINE)) {
if (!frame.name || frame.name[0] == '\0') {
doPrint(" (unknown)");
} else {
char demangledBuf[2048];
demangle(frame.name, demangledBuf, sizeof(demangledBuf));
doPrint(" ");
doPrint(demangledBuf[0] == '\0' ? frame.name : demangledBuf);
}
}
if (!(options_ & NO_FILE_AND_LINE)) {
color(kFileColor);
char fileBuf[PATH_MAX];
fileBuf[0] = '\0';
if (frame.location.hasFileAndLine) {
frame.location.file.toBuffer(fileBuf, sizeof(fileBuf));
if (!(options_ & TERSE_FILE_AND_LINE)) {
doPrint("\n");
doPrint(pad);
}
doPrint(fileBuf);
char buf[22];
uint32_t n = uint64ToBufferUnsafe(frame.location.line, buf);
doPrint(":");
doPrint(StringPiece(buf, n));
} else {
if ((options_ & TERSE_FILE_AND_LINE)) {
doPrint("(unknown)");
}
}
if (frame.location.hasMainFile && !(options_ & TERSE_FILE_AND_LINE)) {
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);
}
}
}
}
void SymbolizePrinter::color(SymbolizePrinter::Color color) {
if ((options_ & COLOR) == 0 && ((options_ & COLOR_IF_TTY) == 0 || !isTty_)) {
return;
}
if (static_cast<size_t>(color) >= kColorMap.size()) { // catches underflow too
return;
}
doPrint(kColorMap[color]);
}
void SymbolizePrinter::println(const SymbolizedFrame& frame) {
print(frame);
doPrint("\n");
}
void SymbolizePrinter::printTerse(const SymbolizedFrame& frame) {
if (frame.found && frame.name && frame.name[0] != '\0') {
char demangledBuf[2048] = {0};
demangle(frame.name, demangledBuf, sizeof(demangledBuf));
doPrint(demangledBuf[0] == '\0' ? frame.name : 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';
auto address = frame.addr;
while (address != 0) {
*p-- = kHexChars[address & 0xf];
address >>= 4;
}
doPrint(StringPiece(buf, end));
}
}
void SymbolizePrinter::println(
const SymbolizedFrame* frames,
size_t frameCount) {
for (size_t i = 0; i < frameCount; ++i) {
println(frames[i]);
}
}
namespace {
int getFD(const std::ios& stream) {
#if FOLLY_USE_LIBSTDCPP && FOLLY_HAS_RTTI
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();
}
}
#else
(void)stream;
#endif // __GNUC__
return -1;
}
bool isColorfulTty(int options, int fd) {
if ((options & SymbolizePrinter::TERSE) != 0 ||
(options & SymbolizePrinter::COLOR_IF_TTY) == 0 || fd < 0 ||
!::isatty(fd)) {
return false;
}
auto term = ::getenv("TERM");
return !(term == nullptr || term[0] == '\0' || strcmp(term, "dumb") == 0);
}
} // namespace
OStreamSymbolizePrinter::OStreamSymbolizePrinter(std::ostream& out, int options)
: SymbolizePrinter(options, isColorfulTty(options, getFD(out))),
out_(out) {}
void OStreamSymbolizePrinter::doPrint(StringPiece sp) {
out_ << sp;
}
FDSymbolizePrinter::FDSymbolizePrinter(int fd, int options, size_t bufferSize)
: SymbolizePrinter(options, isColorfulTty(options, fd)),
fd_(fd),
buffer_(bufferSize ? IOBuf::create(bufferSize) : nullptr) {}
FDSymbolizePrinter::~FDSymbolizePrinter() {
flush();
}
void FDSymbolizePrinter::doPrint(StringPiece sp) {
if (buffer_) {
if (sp.size() > buffer_->tailroom()) {
flush();
writeFull(fd_, sp.data(), sp.size());
} else {
memcpy(buffer_->writableTail(), sp.data(), sp.size());
buffer_->append(sp.size());
}
} else {
writeFull(fd_, sp.data(), sp.size());
}
}
void FDSymbolizePrinter::flush() {
if (buffer_ && !buffer_->empty()) {
writeFull(fd_, buffer_->data(), buffer_->length());
buffer_->clear();
}
}
FILESymbolizePrinter::FILESymbolizePrinter(FILE* file, int options)
: SymbolizePrinter(options, isColorfulTty(options, fileno(file))),
file_(file) {}
void FILESymbolizePrinter::doPrint(StringPiece sp) {
fwrite(sp.data(), 1, sp.size(), file_);
}
void StringSymbolizePrinter::doPrint(StringPiece sp) {
buf_.append(sp.data(), sp.size());
}
SafeStackTracePrinter::SafeStackTracePrinter(int fd) SafeStackTracePrinter::SafeStackTracePrinter(int fd)
: fd_(fd), : fd_(fd),
printer_( printer_(
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <folly/container/EvictingCacheMap.h> #include <folly/container/EvictingCacheMap.h>
#include <folly/experimental/symbolizer/Dwarf.h> #include <folly/experimental/symbolizer/Dwarf.h>
#include <folly/experimental/symbolizer/StackTrace.h> #include <folly/experimental/symbolizer/StackTrace.h>
#include <folly/experimental/symbolizer/SymbolizePrinter.h>
#include <folly/experimental/symbolizer/SymbolizedFrame.h> #include <folly/experimental/symbolizer/SymbolizedFrame.h>
#include <folly/io/IOBuf.h> #include <folly/io/IOBuf.h>
...@@ -153,184 +154,6 @@ class Symbolizer { ...@@ -153,184 +154,6 @@ class Symbolizer {
folly::Optional<Synchronized<SymbolCache>> symbolCache_; folly::Optional<Synchronized<SymbolCache>> symbolCache_;
}; };
/**
* Format one address in the way it's usually printed by SymbolizePrinter.
* Async-signal-safe.
*/
class AddressFormatter {
public:
AddressFormatter();
/**
* Format the address. Returns an internal buffer.
*/
StringPiece format(uintptr_t address);
private:
static constexpr char bufTemplate[] = " @ 0000000000000000";
char buf_[sizeof(bufTemplate)];
};
/**
* Print a list of symbolized addresses. Base class.
*/
class SymbolizePrinter {
public:
/**
* Print one frame, no ending newline.
*/
void print(const SymbolizedFrame& frame);
/**
* Print one frame with ending newline.
*/
void println(const SymbolizedFrame& frame);
/**
* Print multiple frames on separate lines.
*/
void println(const SymbolizedFrame* frames, size_t frameCount);
/**
* Print a string, no endling newline.
*/
void print(StringPiece sp) {
doPrint(sp);
}
/**
* Print multiple frames on separate lines, skipping the first
* skip addresses.
*/
template <size_t N>
void println(const FrameArray<N>& fa, size_t skip = 0) {
if (skip < fa.frameCount) {
println(fa.frames + skip, fa.frameCount - skip);
}
}
/**
* If output buffered inside this class, send it to the output stream, so that
* any output done in other ways appears after this.
*/
virtual void flush() {}
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,
// 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,
// Skip frame address information
NO_FRAME_ADDRESS = 1 << 4,
// Simple file and line output
TERSE_FILE_AND_LINE = 1 << 5,
};
// NOTE: enum values used as indexes in kColorMap.
enum Color { DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, WHITE, PURPLE, NUM };
void color(Color c);
protected:
explicit SymbolizePrinter(int options, bool isTty = false)
: options_(options), isTty_(isTty) {}
const int options_;
const bool isTty_;
private:
void printTerse(const SymbolizedFrame& frame);
virtual void doPrint(StringPiece sp) = 0;
static constexpr std::array<const char*, Color::NUM> kColorMap = {{
"\x1B[0m",
"\x1B[31m",
"\x1B[32m",
"\x1B[33m",
"\x1B[34m",
"\x1B[36m",
"\x1B[37m",
"\x1B[35m",
}};
};
/**
* Print a list of symbolized addresses to a stream.
* Not reentrant. Do not use from signal handling code.
*/
class OStreamSymbolizePrinter : public SymbolizePrinter {
public:
explicit OStreamSymbolizePrinter(std::ostream& out, int options = 0);
private:
void doPrint(StringPiece sp) override;
std::ostream& out_;
};
/**
* Print a list of symbolized addresses to a file descriptor.
* Ignores errors. Async-signal-safe.
*/
class FDSymbolizePrinter : public SymbolizePrinter {
public:
explicit FDSymbolizePrinter(int fd, int options = 0, size_t bufferSize = 0);
~FDSymbolizePrinter() override;
virtual void flush() override;
private:
void doPrint(StringPiece sp) override;
const int fd_;
std::unique_ptr<IOBuf> buffer_;
};
/**
* 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);
private:
void doPrint(StringPiece sp) override;
FILE* const file_ = nullptr;
};
/**
* 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_;
};
/** /**
* Use this class to print a stack trace from a signal handler, or other place * Use this class to print a stack trace from a signal handler, or other place
* where you shouldn't allocate memory on the heap, and fsync()ing your file * where you shouldn't allocate memory on the heap, and fsync()ing your file
......
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