Commit 5357f0f4 authored by Tudor Bosman's avatar Tudor Bosman Committed by Jordan DeLong

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
parent 51fea298
...@@ -40,6 +40,19 @@ ...@@ -40,6 +40,19 @@
// symbols" (but, interestingly enough, will resolve undefined weak symbols // symbols" (but, interestingly enough, will resolve undefined weak symbols
// with definitions from archive members that were extracted in order to // with definitions from archive members that were extracted in order to
// resolve an undefined global (strong) symbol) // 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( extern "C" int cplus_demangle_v3_callback(
const char* mangled, const char* mangled,
int options, // We use DMGL_PARAMS | DMGL_TYPES, aka 0x11 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) { ...@@ -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 // Unlike most library functions, this returns 1 on success and 0 on failure
int status = cplus_demangle_v3_callback( int status = cplus_demangle_v3_callback(
name, name,
0x11, // DMGL_PARAMS | DMGL_TYPES DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES,
demangleCallback, demangleCallback,
&dbuf); &dbuf);
if (status == 0) { // failed, return original if (status == 0) { // failed, return original
...@@ -410,3 +423,15 @@ size_t hexDumpLine(const void* ptr, size_t offset, size_t size, ...@@ -410,3 +423,15 @@ size_t hexDumpLine(const void* ptr, size_t offset, size_t size,
} // namespace detail } // namespace detail
} // namespace folly } // 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
...@@ -70,7 +70,7 @@ std::ostream& operator<<(std::ostream& out, const ExceptionInfo& info) { ...@@ -70,7 +70,7 @@ std::ostream& operator<<(std::ostream& out, const ExceptionInfo& info) {
symbolizer.symbolize(addresses, frames.data(), frameCount); symbolizer.symbolize(addresses, frames.data(), frameCount);
OStreamSymbolizePrinter osp(out); OStreamSymbolizePrinter osp(out);
osp.print(addresses, frames.data(), frameCount); osp.println(addresses, frames.data(), frameCount);
} }
} catch (const std::exception& e) { } catch (const std::exception& e) {
out << "\n !! caught " << folly::exceptionStr(e) << "\n"; out << "\n !! caught " << folly::exceptionStr(e) << "\n";
......
...@@ -201,7 +201,7 @@ void dumpStackTrace() { ...@@ -201,7 +201,7 @@ void dumpStackTrace() {
symbolizer.symbolize(addresses); symbolizer.symbolize(addresses);
FDSymbolizePrinter printer(STDERR_FILENO); FDSymbolizePrinter printer(STDERR_FILENO);
printer.print(addresses); printer.println(addresses);
} }
} }
......
...@@ -247,6 +247,11 @@ const char kHexChars[] = "0123456789abcdef"; ...@@ -247,6 +247,11 @@ const char kHexChars[] = "0123456789abcdef";
} // namespace } // namespace
void SymbolizePrinter::print(uintptr_t address, const SymbolizedFrame& frame) { void SymbolizePrinter::print(uintptr_t address, const SymbolizedFrame& frame) {
if (options_ & TERSE) {
printTerse(address, frame);
return;
}
// Can't use sprintf, not async-signal-safe // Can't use sprintf, not async-signal-safe
static_assert(sizeof(uintptr_t) <= 8, "huge uintptr_t?"); static_assert(sizeof(uintptr_t) <= 8, "huge uintptr_t?");
char buf[] = " @ 0000000000000000"; char buf[] = " @ 0000000000000000";
...@@ -273,7 +278,6 @@ void SymbolizePrinter::print(uintptr_t address, const SymbolizedFrame& frame) { ...@@ -273,7 +278,6 @@ void SymbolizePrinter::print(uintptr_t address, const SymbolizedFrame& frame) {
} else if (frame.name.size() >= sizeof(mangledBuf)) { } else if (frame.name.size() >= sizeof(mangledBuf)) {
doPrint(" "); doPrint(" ");
doPrint(frame.name); doPrint(frame.name);
doPrint("\n");
} else { } else {
memcpy(mangledBuf, frame.name.data(), frame.name.size()); memcpy(mangledBuf, frame.name.data(), frame.name.size());
mangledBuf[frame.name.size()] = '\0'; mangledBuf[frame.name.size()] = '\0';
...@@ -282,41 +286,73 @@ void SymbolizePrinter::print(uintptr_t address, const SymbolizedFrame& frame) { ...@@ -282,41 +286,73 @@ void SymbolizePrinter::print(uintptr_t address, const SymbolizedFrame& frame) {
demangle(mangledBuf, demangledBuf, sizeof(demangledBuf)); demangle(mangledBuf, demangledBuf, sizeof(demangledBuf));
doPrint(" "); doPrint(" ");
doPrint(demangledBuf); doPrint(demangledBuf);
doPrint("\n");
} }
char fileBuf[PATH_MAX]; if (!(options_ & NO_FILE_AND_LINE)) {
fileBuf[0] = '\0'; char fileBuf[PATH_MAX];
if (frame.location.hasFileAndLine) { fileBuf[0] = '\0';
frame.location.file.toBuffer(fileBuf, sizeof(fileBuf)); if (frame.location.hasFileAndLine) {
doPrint(pad); frame.location.file.toBuffer(fileBuf, sizeof(fileBuf));
doPrint(fileBuf); doPrint("\n");
doPrint(pad);
char buf[22]; doPrint(fileBuf);
uint32_t n = uint64ToBufferUnsafe(frame.location.line, buf);
doPrint(":"); char buf[22];
doPrint(StringPiece(buf, n)); uint32_t n = uint64ToBufferUnsafe(frame.location.line, buf);
doPrint("\n"); 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) { void SymbolizePrinter::println(uintptr_t address,
char mainFileBuf[PATH_MAX]; const SymbolizedFrame& frame) {
mainFileBuf[0] = '\0'; print(address, frame);
frame.location.mainFile.toBuffer(mainFileBuf, sizeof(mainFileBuf)); doPrint("\n");
if (!frame.location.hasFileAndLine || strcmp(fileBuf, mainFileBuf)) { }
doPrint(pad);
doPrint("-> "); void SymbolizePrinter::printTerse(uintptr_t address,
doPrint(mainFileBuf); const SymbolizedFrame& frame) {
doPrint("\n"); 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, void SymbolizePrinter::println(const uintptr_t* addresses,
const SymbolizedFrame* frames, const SymbolizedFrame* frames,
size_t frameCount) { size_t frameCount) {
for (size_t i = 0; i < frameCount; ++i) { 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) { ...@@ -328,5 +364,13 @@ void FDSymbolizePrinter::doPrint(StringPiece sp) {
writeFull(fd_, sp.data(), sp.size()); 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 symbolizer
} // namespace folly } // namespace folly
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include "folly/FBString.h"
#include "folly/Range.h" #include "folly/Range.h"
#include "folly/experimental/symbolizer/Elf.h" #include "folly/experimental/symbolizer/Elf.h"
#include "folly/experimental/symbolizer/Dwarf.h" #include "folly/experimental/symbolizer/Dwarf.h"
...@@ -110,20 +111,50 @@ class Symbolizer { ...@@ -110,20 +111,50 @@ class Symbolizer {
*/ */
class SymbolizePrinter { class SymbolizePrinter {
public: public:
/**
* Print one address, no ending newline.
*/
void print(uintptr_t address, const SymbolizedFrame& frame); 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 <size_t N> template <size_t N>
void print(const FrameArray<N>& fa, size_t skip=0) { void println(const FrameArray<N>& fa, size_t skip=0) {
if (skip < fa.frameCount) { 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() { } 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: private:
void printTerse(uintptr_t address, const SymbolizedFrame& frame);
virtual void doPrint(StringPiece sp) = 0; virtual void doPrint(StringPiece sp) = 0;
}; };
...@@ -133,7 +164,9 @@ class SymbolizePrinter { ...@@ -133,7 +164,9 @@ class SymbolizePrinter {
*/ */
class OStreamSymbolizePrinter : public SymbolizePrinter { class OStreamSymbolizePrinter : public SymbolizePrinter {
public: public:
explicit OStreamSymbolizePrinter(std::ostream& out) : out_(out) { } explicit OStreamSymbolizePrinter(std::ostream& out, int options=0)
: SymbolizePrinter(options),
out_(out) { }
private: private:
void doPrint(StringPiece sp) override; void doPrint(StringPiece sp) override;
std::ostream& out_; std::ostream& out_;
...@@ -145,12 +178,45 @@ class OStreamSymbolizePrinter : public SymbolizePrinter { ...@@ -145,12 +178,45 @@ class OStreamSymbolizePrinter : public SymbolizePrinter {
*/ */
class FDSymbolizePrinter : public SymbolizePrinter { class FDSymbolizePrinter : public SymbolizePrinter {
public: public:
explicit FDSymbolizePrinter(int fd) : fd_(fd) { } explicit FDSymbolizePrinter(int fd, int options=0)
: SymbolizePrinter(options),
fd_(fd) { }
private: private:
void doPrint(StringPiece sp) override; void doPrint(StringPiece sp) override;
int fd_; 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 symbolizer
} // namespace folly } // namespace folly
......
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