// 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
// 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
} // 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
+
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";
symbolizer.symbolize(addresses);
FDSymbolizePrinter printer(STDERR_FILENO);
- printer.print(addresses);
+ printer.println(addresses);
}
}
} // 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";
} 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';
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]);
}
}
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
#include <string>
#include <unordered_map>
+#include "folly/FBString.h"
#include "folly/Range.h"
#include "folly/experimental/symbolizer/Elf.h"
#include "folly/experimental/symbolizer/Dwarf.h"
*/
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 <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) {
- 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;
};
*/
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_;
*/
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