Symbolizer.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. /*
  2. * Copyright 2012-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <folly/experimental/symbolizer/Symbolizer.h>
  17. #include <link.h>
  18. #include <ucontext.h>
  19. #include <climits>
  20. #include <cstdio>
  21. #include <cstdlib>
  22. #include <iostream>
  23. #ifdef __GLIBCXX__
  24. #include <ext/stdio_filebuf.h>
  25. #include <ext/stdio_sync_filebuf.h>
  26. #endif
  27. #include <folly/Conv.h>
  28. #include <folly/FileUtil.h>
  29. #include <folly/Memory.h>
  30. #include <folly/ScopeGuard.h>
  31. #include <folly/String.h>
  32. #include <folly/experimental/symbolizer/Dwarf.h>
  33. #include <folly/experimental/symbolizer/Elf.h>
  34. #include <folly/experimental/symbolizer/LineReader.h>
  35. #include <folly/portability/SysMman.h>
  36. #include <folly/portability/Unistd.h>
  37. /*
  38. * This is declared in `link.h' on Linux platforms, but apparently not on the
  39. * Mac version of the file. It's harmless to declare again, in any case.
  40. *
  41. * Note that declaring it with `extern "C"` results in linkage conflicts.
  42. */
  43. extern struct r_debug _r_debug;
  44. namespace folly {
  45. namespace symbolizer {
  46. namespace {
  47. ElfCache* defaultElfCache() {
  48. static constexpr size_t defaultCapacity = 500;
  49. static auto cache = new ElfCache(defaultCapacity);
  50. return cache;
  51. }
  52. } // namespace
  53. void SymbolizedFrame::set(
  54. const std::shared_ptr<ElfFile>& file,
  55. uintptr_t address,
  56. Dwarf::LocationInfoMode mode) {
  57. clear();
  58. found = true;
  59. address += file->getBaseAddress();
  60. auto sym = file->getDefinitionByAddress(address);
  61. if (!sym.first) {
  62. return;
  63. }
  64. file_ = file;
  65. name = file->getSymbolName(sym);
  66. Dwarf(file.get()).findAddress(address, location, mode);
  67. }
  68. Symbolizer::Symbolizer(
  69. ElfCacheBase* cache,
  70. Dwarf::LocationInfoMode mode,
  71. size_t symbolCacheSize)
  72. : cache_(cache ? cache : defaultElfCache()), mode_(mode) {
  73. if (symbolCacheSize > 0) {
  74. symbolCache_.emplace(folly::in_place, symbolCacheSize);
  75. }
  76. }
  77. void Symbolizer::symbolize(
  78. const uintptr_t* addresses,
  79. SymbolizedFrame* frames,
  80. size_t addrCount) {
  81. size_t remaining = 0;
  82. for (size_t i = 0; i < addrCount; ++i) {
  83. auto& frame = frames[i];
  84. if (!frame.found) {
  85. ++remaining;
  86. frame.clear();
  87. }
  88. }
  89. if (remaining == 0) { // we're done
  90. return;
  91. }
  92. if (_r_debug.r_version != 1) {
  93. return;
  94. }
  95. char selfPath[PATH_MAX + 8];
  96. ssize_t selfSize;
  97. if ((selfSize = readlink("/proc/self/exe", selfPath, PATH_MAX + 1)) == -1) {
  98. // Something has gone terribly wrong.
  99. return;
  100. }
  101. selfPath[selfSize] = '\0';
  102. for (auto lmap = _r_debug.r_map; lmap != nullptr && remaining != 0;
  103. lmap = lmap->l_next) {
  104. // The empty string is used in place of the filename for the link_map
  105. // corresponding to the running executable. Additionally, the `l_addr' is
  106. // 0 and the link_map appears to be first in the list---but none of this
  107. // behavior appears to be documented, so checking for the empty string is
  108. // as good as anything.
  109. auto const objPath = lmap->l_name[0] != '\0' ? lmap->l_name : selfPath;
  110. auto const elfFile = cache_->getFile(objPath);
  111. if (!elfFile) {
  112. continue;
  113. }
  114. // Get the address at which the object is loaded. We have to use the ELF
  115. // header for the running executable, since its `l_addr' is zero, but we
  116. // should use `l_addr' for everything else---in particular, if the object
  117. // is position-independent, getBaseAddress() (which is p_vaddr) will be 0.
  118. auto const base =
  119. lmap->l_addr != 0 ? lmap->l_addr : elfFile->getBaseAddress();
  120. for (size_t i = 0; i < addrCount && remaining != 0; ++i) {
  121. auto& frame = frames[i];
  122. if (frame.found) {
  123. continue;
  124. }
  125. auto const addr = addresses[i];
  126. if (symbolCache_) {
  127. // Need a write lock, because EvictingCacheMap brings found item to
  128. // front of eviction list.
  129. auto lockedSymbolCache = symbolCache_->wlock();
  130. auto const iter = lockedSymbolCache->find(addr);
  131. if (iter != lockedSymbolCache->end()) {
  132. frame = iter->second;
  133. continue;
  134. }
  135. }
  136. // Get the unrelocated, ELF-relative address.
  137. auto const adjusted = addr - base;
  138. if (elfFile->getSectionContainingAddress(adjusted)) {
  139. frame.set(elfFile, adjusted, mode_);
  140. --remaining;
  141. if (symbolCache_) {
  142. // frame may already have been set here. That's ok, we'll just
  143. // overwrite, which doesn't cause a correctness problem.
  144. symbolCache_->wlock()->set(addr, frame);
  145. }
  146. }
  147. }
  148. }
  149. }
  150. namespace {
  151. constexpr char kHexChars[] = "0123456789abcdef";
  152. constexpr auto kAddressColor = SymbolizePrinter::Color::BLUE;
  153. constexpr auto kFunctionColor = SymbolizePrinter::Color::PURPLE;
  154. constexpr auto kFileColor = SymbolizePrinter::Color::DEFAULT;
  155. } // namespace
  156. constexpr char AddressFormatter::bufTemplate[];
  157. constexpr std::array<const char*, SymbolizePrinter::Color::NUM>
  158. SymbolizePrinter::kColorMap;
  159. AddressFormatter::AddressFormatter() {
  160. memcpy(buf_, bufTemplate, sizeof(buf_));
  161. }
  162. folly::StringPiece AddressFormatter::format(uintptr_t address) {
  163. // Can't use sprintf, not async-signal-safe
  164. static_assert(sizeof(uintptr_t) <= 8, "huge uintptr_t?");
  165. char* end = buf_ + sizeof(buf_) - 1 - (16 - 2 * sizeof(uintptr_t));
  166. char* p = end;
  167. *p-- = '\0';
  168. while (address != 0) {
  169. *p-- = kHexChars[address & 0xf];
  170. address >>= 4;
  171. }
  172. return folly::StringPiece(buf_, end);
  173. }
  174. void SymbolizePrinter::print(uintptr_t address, const SymbolizedFrame& frame) {
  175. if (options_ & TERSE) {
  176. printTerse(address, frame);
  177. return;
  178. }
  179. SCOPE_EXIT {
  180. color(Color::DEFAULT);
  181. };
  182. if (!(options_ & NO_FRAME_ADDRESS)) {
  183. color(kAddressColor);
  184. AddressFormatter formatter;
  185. doPrint(formatter.format(address));
  186. }
  187. const char padBuf[] = " ";
  188. folly::StringPiece pad(
  189. padBuf, sizeof(padBuf) - 1 - (16 - 2 * sizeof(uintptr_t)));
  190. color(kFunctionColor);
  191. if (!frame.found) {
  192. doPrint(" (not found)");
  193. return;
  194. }
  195. if (!frame.name || frame.name[0] == '\0') {
  196. doPrint(" (unknown)");
  197. } else {
  198. char demangledBuf[2048];
  199. demangle(frame.name, demangledBuf, sizeof(demangledBuf));
  200. doPrint(" ");
  201. doPrint(demangledBuf[0] == '\0' ? frame.name : demangledBuf);
  202. }
  203. if (!(options_ & NO_FILE_AND_LINE)) {
  204. color(kFileColor);
  205. char fileBuf[PATH_MAX];
  206. fileBuf[0] = '\0';
  207. if (frame.location.hasFileAndLine) {
  208. frame.location.file.toBuffer(fileBuf, sizeof(fileBuf));
  209. doPrint("\n");
  210. doPrint(pad);
  211. doPrint(fileBuf);
  212. char buf[22];
  213. uint32_t n = uint64ToBufferUnsafe(frame.location.line, buf);
  214. doPrint(":");
  215. doPrint(StringPiece(buf, n));
  216. }
  217. if (frame.location.hasMainFile) {
  218. char mainFileBuf[PATH_MAX];
  219. mainFileBuf[0] = '\0';
  220. frame.location.mainFile.toBuffer(mainFileBuf, sizeof(mainFileBuf));
  221. if (!frame.location.hasFileAndLine || strcmp(fileBuf, mainFileBuf)) {
  222. doPrint("\n");
  223. doPrint(pad);
  224. doPrint("-> ");
  225. doPrint(mainFileBuf);
  226. }
  227. }
  228. }
  229. }
  230. void SymbolizePrinter::color(SymbolizePrinter::Color color) {
  231. if ((options_ & COLOR) == 0 && ((options_ & COLOR_IF_TTY) == 0 || !isTty_)) {
  232. return;
  233. }
  234. if (static_cast<size_t>(color) >= kColorMap.size()) { // catches underflow too
  235. return;
  236. }
  237. doPrint(kColorMap[color]);
  238. }
  239. void SymbolizePrinter::println(
  240. uintptr_t address,
  241. const SymbolizedFrame& frame) {
  242. print(address, frame);
  243. doPrint("\n");
  244. }
  245. void SymbolizePrinter::printTerse(
  246. uintptr_t address,
  247. const SymbolizedFrame& frame) {
  248. if (frame.found && frame.name && frame.name[0] != '\0') {
  249. char demangledBuf[2048] = {0};
  250. demangle(frame.name, demangledBuf, sizeof(demangledBuf));
  251. doPrint(demangledBuf[0] == '\0' ? frame.name : demangledBuf);
  252. } else {
  253. // Can't use sprintf, not async-signal-safe
  254. static_assert(sizeof(uintptr_t) <= 8, "huge uintptr_t?");
  255. char buf[] = "0x0000000000000000";
  256. char* end = buf + sizeof(buf) - 1 - (16 - 2 * sizeof(uintptr_t));
  257. char* p = end;
  258. *p-- = '\0';
  259. while (address != 0) {
  260. *p-- = kHexChars[address & 0xf];
  261. address >>= 4;
  262. }
  263. doPrint(StringPiece(buf, end));
  264. }
  265. }
  266. void SymbolizePrinter::println(
  267. const uintptr_t* addresses,
  268. const SymbolizedFrame* frames,
  269. size_t frameCount) {
  270. for (size_t i = 0; i < frameCount; ++i) {
  271. println(addresses[i], frames[i]);
  272. }
  273. }
  274. namespace {
  275. int getFD(const std::ios& stream) {
  276. #if defined(__GNUC__) && FOLLY_HAS_RTTI
  277. std::streambuf* buf = stream.rdbuf();
  278. using namespace __gnu_cxx;
  279. {
  280. auto sbuf = dynamic_cast<stdio_sync_filebuf<char>*>(buf);
  281. if (sbuf) {
  282. return fileno(sbuf->file());
  283. }
  284. }
  285. {
  286. auto sbuf = dynamic_cast<stdio_filebuf<char>*>(buf);
  287. if (sbuf) {
  288. return sbuf->fd();
  289. }
  290. }
  291. #else
  292. (void)stream;
  293. #endif // __GNUC__
  294. return -1;
  295. }
  296. bool isColorfulTty(int options, int fd) {
  297. if ((options & SymbolizePrinter::TERSE) != 0 ||
  298. (options & SymbolizePrinter::COLOR_IF_TTY) == 0 || fd < 0 ||
  299. !::isatty(fd)) {
  300. return false;
  301. }
  302. auto term = ::getenv("TERM");
  303. return !(term == nullptr || term[0] == '\0' || strcmp(term, "dumb") == 0);
  304. }
  305. } // namespace
  306. OStreamSymbolizePrinter::OStreamSymbolizePrinter(std::ostream& out, int options)
  307. : SymbolizePrinter(options, isColorfulTty(options, getFD(out))),
  308. out_(out) {}
  309. void OStreamSymbolizePrinter::doPrint(StringPiece sp) {
  310. out_ << sp;
  311. }
  312. FDSymbolizePrinter::FDSymbolizePrinter(int fd, int options, size_t bufferSize)
  313. : SymbolizePrinter(options, isColorfulTty(options, fd)),
  314. fd_(fd),
  315. buffer_(bufferSize ? IOBuf::create(bufferSize) : nullptr) {}
  316. FDSymbolizePrinter::~FDSymbolizePrinter() {
  317. flush();
  318. }
  319. void FDSymbolizePrinter::doPrint(StringPiece sp) {
  320. if (buffer_) {
  321. if (sp.size() > buffer_->tailroom()) {
  322. flush();
  323. writeFull(fd_, sp.data(), sp.size());
  324. } else {
  325. memcpy(buffer_->writableTail(), sp.data(), sp.size());
  326. buffer_->append(sp.size());
  327. }
  328. } else {
  329. writeFull(fd_, sp.data(), sp.size());
  330. }
  331. }
  332. void FDSymbolizePrinter::flush() {
  333. if (buffer_ && !buffer_->empty()) {
  334. writeFull(fd_, buffer_->data(), buffer_->length());
  335. buffer_->clear();
  336. }
  337. }
  338. FILESymbolizePrinter::FILESymbolizePrinter(FILE* file, int options)
  339. : SymbolizePrinter(options, isColorfulTty(options, fileno(file))),
  340. file_(file) {}
  341. void FILESymbolizePrinter::doPrint(StringPiece sp) {
  342. fwrite(sp.data(), 1, sp.size(), file_);
  343. }
  344. void StringSymbolizePrinter::doPrint(StringPiece sp) {
  345. buf_.append(sp.data(), sp.size());
  346. }
  347. SafeStackTracePrinter::SafeStackTracePrinter(
  348. size_t minSignalSafeElfCacheSize,
  349. int fd)
  350. : fd_(fd),
  351. elfCache_(std::max(countLoadedElfFiles(), minSignalSafeElfCacheSize)),
  352. printer_(
  353. fd,
  354. SymbolizePrinter::COLOR_IF_TTY,
  355. size_t(64) << 10), // 64KiB
  356. addresses_(std::make_unique<FrameArray<kMaxStackTraceDepth>>()) {}
  357. void SafeStackTracePrinter::flush() {
  358. printer_.flush();
  359. fsyncNoInt(fd_);
  360. }
  361. void SafeStackTracePrinter::printSymbolizedStackTrace() {
  362. // This function might run on an alternative stack allocated by
  363. // UnsafeSelfAllocateStackTracePrinter. Capturing a stack from
  364. // here is probably wrong.
  365. // Do our best to populate location info, process is going to terminate,
  366. // so performance isn't critical.
  367. Symbolizer symbolizer(&elfCache_, Dwarf::LocationInfoMode::FULL);
  368. symbolizer.symbolize(*addresses_);
  369. // Skip the top 2 frames captured by printStackTrace:
  370. // getStackTraceSafe
  371. // SafeStackTracePrinter::printStackTrace (captured stack)
  372. //
  373. // Leaving signalHandler on the stack for clarity, I think.
  374. printer_.println(*addresses_, 2);
  375. }
  376. void SafeStackTracePrinter::printStackTrace(bool symbolize) {
  377. SCOPE_EXIT {
  378. flush();
  379. };
  380. // Skip the getStackTrace frame
  381. if (!getStackTraceSafe(*addresses_)) {
  382. print("(error retrieving stack trace)\n");
  383. } else if (symbolize) {
  384. printSymbolizedStackTrace();
  385. } else {
  386. print("(safe mode, symbolizer not available)\n");
  387. AddressFormatter formatter;
  388. for (size_t i = 0; i < addresses_->frameCount; ++i) {
  389. print(formatter.format(addresses_->addresses[i]));
  390. print("\n");
  391. }
  392. }
  393. }
  394. FastStackTracePrinter::FastStackTracePrinter(
  395. std::unique_ptr<SymbolizePrinter> printer,
  396. size_t elfCacheSize,
  397. size_t symbolCacheSize)
  398. : elfCache_(
  399. elfCacheSize == 0
  400. ? nullptr
  401. : new ElfCache{std::max(countLoadedElfFiles(), elfCacheSize)}),
  402. printer_(std::move(printer)),
  403. symbolizer_(
  404. elfCache_ ? elfCache_.get() : defaultElfCache(),
  405. Dwarf::LocationInfoMode::FULL,
  406. symbolCacheSize) {}
  407. FastStackTracePrinter::~FastStackTracePrinter() {}
  408. void FastStackTracePrinter::printStackTrace(bool symbolize) {
  409. SCOPE_EXIT {
  410. printer_->flush();
  411. };
  412. FrameArray<kMaxStackTraceDepth> addresses;
  413. if (!getStackTraceSafe(addresses)) {
  414. printer_->print("(error retrieving stack trace)\n");
  415. } else if (symbolize) {
  416. symbolizer_.symbolize(addresses);
  417. // Skip the top 2 frames:
  418. // getStackTraceSafe
  419. // FastStackTracePrinter::printStackTrace (here)
  420. printer_->println(addresses, 2);
  421. } else {
  422. printer_->print("(safe mode, symbolizer not available)\n");
  423. AddressFormatter formatter;
  424. for (size_t i = 0; i < addresses.frameCount; ++i) {
  425. printer_->print(formatter.format(addresses.addresses[i]));
  426. printer_->print("\n");
  427. }
  428. }
  429. }
  430. void FastStackTracePrinter::flush() {
  431. printer_->flush();
  432. }
  433. // Stack utilities used by UnsafeSelfAllocateStackTracePrinter
  434. namespace {
  435. // Size of mmap-allocated stack. Not to confuse with sigaltstack.
  436. const size_t kMmapStackSize = 1 * 1024 * 1024;
  437. using MmapPtr = std::unique_ptr<char, void (*)(char*)>;
  438. MmapPtr getNull() {
  439. return MmapPtr(nullptr, [](char*) {});
  440. }
  441. // Assign a mmap-allocated stack to oucp.
  442. // Return a non-empty smart pointer on success.
  443. MmapPtr allocateStack(ucontext_t* oucp, size_t pageSize) {
  444. MmapPtr p(
  445. (char*)mmap(
  446. nullptr,
  447. kMmapStackSize,
  448. PROT_WRITE | PROT_READ,
  449. MAP_ANONYMOUS | MAP_PRIVATE,
  450. /* fd */ -1,
  451. /* offset */ 0),
  452. [](char* addr) {
  453. // Usually runs inside a fatal signal handler.
  454. // Error handling is skipped.
  455. munmap(addr, kMmapStackSize);
  456. });
  457. if (!p) {
  458. return getNull();
  459. }
  460. // Prepare read-only guard pages on both ends
  461. if (pageSize * 2 >= kMmapStackSize) {
  462. return getNull();
  463. }
  464. size_t upperBound = ((kMmapStackSize - 1) / pageSize) * pageSize;
  465. if (mprotect(p.get(), pageSize, PROT_NONE) != 0) {
  466. return getNull();
  467. }
  468. if (mprotect(p.get() + upperBound, kMmapStackSize - upperBound, PROT_NONE) !=
  469. 0) {
  470. return getNull();
  471. }
  472. oucp->uc_stack.ss_sp = p.get() + pageSize;
  473. oucp->uc_stack.ss_size = upperBound - pageSize;
  474. oucp->uc_stack.ss_flags = 0;
  475. return p;
  476. }
  477. } // namespace
  478. void UnsafeSelfAllocateStackTracePrinter::printSymbolizedStackTrace() {
  479. if (pageSizeUnchecked_ <= 0) {
  480. return;
  481. }
  482. ucontext_t cur;
  483. memset(&cur, 0, sizeof(cur));
  484. ucontext_t alt;
  485. memset(&alt, 0, sizeof(alt));
  486. if (getcontext(&alt) != 0) {
  487. return;
  488. }
  489. alt.uc_link = &cur;
  490. MmapPtr p = allocateStack(&alt, (size_t)pageSizeUnchecked_);
  491. if (!p) {
  492. return;
  493. }
  494. auto contextStart = [](UnsafeSelfAllocateStackTracePrinter* that) {
  495. that->SafeStackTracePrinter::printSymbolizedStackTrace();
  496. };
  497. makecontext(
  498. &alt,
  499. (void (*)())(void (*)(UnsafeSelfAllocateStackTracePrinter*))(
  500. contextStart),
  501. /* argc */ 1,
  502. /* arg */ this);
  503. // NOTE: swapcontext is not async-signal-safe
  504. if (swapcontext(&cur, &alt) != 0) {
  505. return;
  506. }
  507. }
  508. } // namespace symbolizer
  509. } // namespace folly