28 #include <ext/stdio_filebuf.h> 29 #include <ext/stdio_sync_filebuf.h> 53 namespace symbolizer {
57 ElfCache* defaultElfCache() {
58 static constexpr
size_t defaultCapacity = 500;
59 static auto cache =
new ElfCache(defaultCapacity);
66 const std::shared_ptr<ElfFile>& file,
72 address += file->getBaseAddress();
73 auto sym = file->getDefinitionByAddress(address);
79 name = file->getSymbolName(sym);
87 size_t symbolCacheSize)
88 : cache_(cache ? cache : defaultElfCache()), mode_(mode) {
89 if (symbolCacheSize > 0) {
95 const uintptr_t* addresses,
99 for (
size_t i = 0;
i < addrCount; ++
i) {
100 auto& frame = frames[
i];
107 if (remaining == 0) {
115 char selfPath[PATH_MAX + 8];
117 if ((selfSize = readlink(
"/proc/self/exe", selfPath, PATH_MAX + 1)) == -1) {
121 selfPath[selfSize] =
'\0';
123 for (
auto lmap =
_r_debug.r_map; lmap !=
nullptr && remaining != 0;
124 lmap = lmap->l_next) {
130 auto const objPath = lmap->l_name[0] !=
'\0' ? lmap->l_name : selfPath;
142 lmap->l_addr != 0 ? lmap->l_addr : elfFile->getBaseAddress();
144 for (
size_t i = 0;
i < addrCount && remaining != 0; ++
i) {
145 auto& frame = frames[
i];
150 auto const addr = addresses[
i];
156 auto const iter = lockedSymbolCache->find(
addr);
157 if (iter != lockedSymbolCache->end()) {
158 frame = iter->second;
164 auto const adjusted =
addr - base;
166 if (elfFile->getSectionContainingAddress(adjusted)) {
167 frame.set(elfFile, adjusted,
mode_);
180 constexpr
char kHexChars[] =
"0123456789abcdef";
181 constexpr
auto kAddressColor = SymbolizePrinter::Color::BLUE;
182 constexpr
auto kFunctionColor = SymbolizePrinter::Color::PURPLE;
183 constexpr
auto kFileColor = SymbolizePrinter::Color::DEFAULT;
187 constexpr std::array<const char*, SymbolizePrinter::Color::NUM>
191 memcpy(buf_, bufTemplate,
sizeof(buf_));
196 static_assert(
sizeof(uintptr_t) <= 8,
"huge uintptr_t?");
197 char*
end = buf_ +
sizeof(buf_) - 1 - (16 - 2 *
sizeof(uintptr_t));
200 while (address != 0) {
201 *p-- = kHexChars[address & 0xf];
209 if (options_ & TERSE) {
210 printTerse(address, frame);
215 color(Color::DEFAULT);
218 if (!(options_ & NO_FRAME_ADDRESS)) {
219 color(kAddressColor);
222 doPrint(formatter.
format(address));
225 const char padBuf[] =
" ";
227 padBuf,
sizeof(padBuf) - 1 - (16 - 2 *
sizeof(uintptr_t)));
229 color(kFunctionColor);
231 doPrint(
" (not found)");
235 if (!frame.
name || frame.
name[0] ==
'\0') {
236 doPrint(
" (unknown)");
238 char demangledBuf[2048];
239 demangle(frame.
name, demangledBuf,
sizeof(demangledBuf));
241 doPrint(demangledBuf[0] ==
'\0' ? frame.
name : demangledBuf);
244 if (!(options_ & NO_FILE_AND_LINE)) {
246 char fileBuf[PATH_MAX];
261 char mainFileBuf[PATH_MAX];
262 mainFileBuf[0] =
'\0';
268 doPrint(mainFileBuf);
275 if ((options_ & COLOR) == 0 && ((options_ & COLOR_IF_TTY) == 0 || !isTty_)) {
278 if (static_cast<size_t>(color) >= kColorMap.size()) {
281 doPrint(kColorMap[color]);
287 print(address, frame);
295 char demangledBuf[2048] = {0};
296 demangle(frame.
name, demangledBuf,
sizeof(demangledBuf));
297 doPrint(demangledBuf[0] ==
'\0' ? frame.
name : demangledBuf);
300 static_assert(
sizeof(uintptr_t) <= 8,
"huge uintptr_t?");
301 char buf[] =
"0x0000000000000000";
302 char*
end = buf +
sizeof(buf) - 1 - (16 - 2 *
sizeof(uintptr_t));
305 while (address != 0) {
306 *p-- = kHexChars[address & 0xf];
314 const uintptr_t* addresses,
317 for (
size_t i = 0;
i < frameCount; ++
i) {
324 int getFD(
const std::ios&
stream) {
325 #if defined(__GNUC__) && FOLLY_HAS_RTTI 326 std::streambuf* buf = stream.rdbuf();
327 using namespace __gnu_cxx;
330 auto sbuf =
dynamic_cast<stdio_sync_filebuf<char>*
>(buf);
332 return fileno(sbuf->file());
336 auto sbuf =
dynamic_cast<stdio_filebuf<char>*
>(buf);
347 bool isColorfulTty(
int options,
int fd) {
353 auto term = ::getenv(
"TERM");
354 return !(term ==
nullptr || term[0] ==
'\0' || strcmp(term,
"dumb") == 0);
410 size_t minSignalSafeElfCacheSize,
450 print(
"(error retrieving stack trace)\n");
451 }
else if (symbolize) {
454 print(
"(safe mode, symbolizer not available)\n");
464 std::unique_ptr<SymbolizePrinter> printer,
466 size_t symbolCacheSize)
487 printer_->print(
"(error retrieving stack trace)\n");
488 }
else if (symbolize) {
496 printer_->print(
"(safe mode, symbolizer not available)\n");
512 const size_t kMmapStackSize = 1 * 1024 * 1024;
514 using MmapPtr = std::unique_ptr<char, void (*)(char*)>;
517 return MmapPtr(
nullptr, [](
char*) {});
522 MmapPtr allocateStack(ucontext_t* oucp,
size_t pageSize) {
527 PROT_WRITE | PROT_READ,
528 MAP_ANONYMOUS | MAP_PRIVATE,
534 munmap(addr, kMmapStackSize);
542 if (pageSize * 2 >= kMmapStackSize) {
545 size_t upperBound = ((kMmapStackSize - 1) / pageSize) * pageSize;
546 if (mprotect(p.get(), pageSize, PROT_NONE) != 0) {
549 if (mprotect(p.get() + upperBound, kMmapStackSize - upperBound, PROT_NONE) !=
554 oucp->uc_stack.ss_sp = p.get() + pageSize;
555 oucp->uc_stack.ss_size = upperBound - pageSize;
556 oucp->uc_stack.ss_flags = 0;
564 if (pageSizeUnchecked_ <= 0) {
569 memset(&cur, 0,
sizeof(cur));
571 memset(&alt, 0,
sizeof(alt));
573 if (getcontext(&alt) != 0) {
578 MmapPtr p = allocateStack(&alt, (
size_t)pageSizeUnchecked_);
584 that->SafeStackTracePrinter::printSymbolizedStackTrace();
594 if (swapcontext(&cur, &alt) != 0) {
void printSymbolizedStackTrace() override
const std::unique_ptr< SymbolizePrinter > printer_
virtual std::shared_ptr< ElfFile > getFile(StringPiece path)=0
uint32_t uint64ToBufferUnsafe(uint64_t v, char *const buffer)
ssize_t getStackTraceSafe(uintptr_t *addresses, size_t maxAddresses)
~FDSymbolizePrinter() override
Dwarf::LocationInfo location
void printTerse(uintptr_t address, const SymbolizedFrame &frame)
const std::unique_ptr< ElfCache > elfCache_
void doPrint(StringPiece sp) override
constexpr detail::Map< Move > move
virtual void printSymbolizedStackTrace()
Symbolizer(Dwarf::LocationInfoMode mode=kDefaultLocationInfoMode)
const Dwarf::LocationInfoMode mode_
std::unique_ptr< IOBuf > buffer_
constexpr size_type size() const
—— Concurrent Priority Queue Implementation ——
FDSymbolizePrinter(int fd, int options=0, size_t bufferSize=0)
in_place_tag in_place(in_place_tag={})
void print(uintptr_t address, const SymbolizedFrame &frame)
FastStackTracePrinter(std::unique_ptr< SymbolizePrinter > printer, size_t elfCacheSize=0, size_t symbolCacheSize=kDefaultSymbolCacheSize)
OStreamSymbolizePrinter(std::ostream &out, int options=0)
folly::Optional< PskKeyExchangeMode > mode
void println(uintptr_t address, const SymbolizedFrame &frame)
SafeStackTracePrinter(size_t minSignalSafeElfCacheSize=kDefaultMinSignalSafeElfCacheSize, int fd=STDERR_FILENO)
std::shared_ptr< ElfFile > file_
const int kMaxStackTraceDepth
auto end(TestAdlIterable &instance)
constexpr Iter data() const
void doPrint(StringPiece sp) override
size_t countLoadedElfFiles()
ssize_t writeFull(int fd, const void *buf, size_t count)
ElfCacheBase *const cache_
size_t toBuffer(char *buf, size_t bufSize) const
void set(const std::shared_ptr< ElfFile > &file, uintptr_t address, Dwarf::LocationInfoMode mode)
static constexpr std::array< const char *, Color::NUM > kColorMap
std::enable_if<!std::is_array< T >::value, std::unique_ptr< T > >::type make_unique(Args &&...args)
FOLLY_NOINLINE void printStackTrace(bool symbolize)
folly::Optional< Synchronized< SymbolCache > > symbolCache_
FOLLY_NOINLINE void printStackTrace(bool symbolize)
FILESymbolizePrinter(FILE *file, int options=0)
SignalSafeElfCache elfCache_
std::unique_ptr< FrameArray< kMaxStackTraceDepth > > addresses_
virtual void flush() override
Range< const char * > StringPiece
void symbolize(const uintptr_t *addresses, SymbolizedFrame *frames, size_t frameCount)
void doPrint(StringPiece sp) override
std::unique_ptr< unsigned char[]> buffer_
ThreadPoolListHook * addr
void doPrint(StringPiece sp) override
GMockOutputTest ExpectedCall FILE
void print(StringPiece sp)
fbstring demangle(const char *name)
FDSymbolizePrinter printer_