Symbolizer.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  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. #pragma once
  17. #include <array>
  18. #include <cstdint>
  19. #include <memory>
  20. #include <string>
  21. #include <folly/FBString.h>
  22. #include <folly/Optional.h>
  23. #include <folly/Range.h>
  24. #include <folly/String.h>
  25. #include <folly/Synchronized.h>
  26. #include <folly/container/EvictingCacheMap.h>
  27. #include <folly/experimental/symbolizer/Dwarf.h>
  28. #include <folly/experimental/symbolizer/Elf.h>
  29. #include <folly/experimental/symbolizer/ElfCache.h>
  30. #include <folly/experimental/symbolizer/StackTrace.h>
  31. #include <folly/io/IOBuf.h>
  32. namespace folly {
  33. namespace symbolizer {
  34. class Symbolizer;
  35. /**
  36. * Frame information: symbol name and location.
  37. */
  38. struct SymbolizedFrame {
  39. SymbolizedFrame() {}
  40. void set(
  41. const std::shared_ptr<ElfFile>& file,
  42. uintptr_t address,
  43. Dwarf::LocationInfoMode mode);
  44. void clear() {
  45. *this = SymbolizedFrame();
  46. }
  47. bool found = false;
  48. const char* name = nullptr;
  49. Dwarf::LocationInfo location;
  50. /**
  51. * Demangle the name and return it. Not async-signal-safe; allocates memory.
  52. */
  53. fbstring demangledName() const {
  54. return name ? demangle(name) : fbstring();
  55. }
  56. private:
  57. std::shared_ptr<ElfFile> file_;
  58. };
  59. template <size_t N>
  60. struct FrameArray {
  61. FrameArray() {}
  62. size_t frameCount = 0;
  63. uintptr_t addresses[N];
  64. SymbolizedFrame frames[N];
  65. };
  66. /**
  67. * Get stack trace into a given FrameArray, return true on success (and
  68. * set frameCount to the actual frame count, which may be > N) and false
  69. * on failure.
  70. */
  71. namespace detail {
  72. template <size_t N>
  73. bool fixFrameArray(FrameArray<N>& fa, ssize_t n) {
  74. if (n != -1) {
  75. fa.frameCount = n;
  76. for (size_t i = 0; i < fa.frameCount; ++i) {
  77. fa.frames[i].found = false;
  78. }
  79. return true;
  80. } else {
  81. fa.frameCount = 0;
  82. return false;
  83. }
  84. }
  85. } // namespace detail
  86. // Always inline these functions; they don't do much, and unittests rely
  87. // on them never showing up in a stack trace.
  88. template <size_t N>
  89. FOLLY_ALWAYS_INLINE bool getStackTrace(FrameArray<N>& fa);
  90. template <size_t N>
  91. inline bool getStackTrace(FrameArray<N>& fa) {
  92. return detail::fixFrameArray(fa, getStackTrace(fa.addresses, N));
  93. }
  94. template <size_t N>
  95. FOLLY_ALWAYS_INLINE bool getStackTraceSafe(FrameArray<N>& fa);
  96. template <size_t N>
  97. inline bool getStackTraceSafe(FrameArray<N>& fa) {
  98. return detail::fixFrameArray(fa, getStackTraceSafe(fa.addresses, N));
  99. }
  100. class Symbolizer {
  101. public:
  102. static constexpr Dwarf::LocationInfoMode kDefaultLocationInfoMode =
  103. Dwarf::LocationInfoMode::FAST;
  104. explicit Symbolizer(Dwarf::LocationInfoMode mode = kDefaultLocationInfoMode)
  105. : Symbolizer(nullptr, mode) {}
  106. explicit Symbolizer(
  107. ElfCacheBase* cache,
  108. Dwarf::LocationInfoMode mode = kDefaultLocationInfoMode,
  109. size_t symbolCacheSize = 0);
  110. /**
  111. * Symbolize given addresses.
  112. */
  113. void symbolize(
  114. const uintptr_t* addresses,
  115. SymbolizedFrame* frames,
  116. size_t frameCount);
  117. template <size_t N>
  118. void symbolize(FrameArray<N>& fa) {
  119. symbolize(fa.addresses, fa.frames, fa.frameCount);
  120. }
  121. /**
  122. * Shortcut to symbolize one address.
  123. */
  124. bool symbolize(uintptr_t address, SymbolizedFrame& frame) {
  125. symbolize(&address, &frame, 1);
  126. return frame.found;
  127. }
  128. private:
  129. ElfCacheBase* const cache_;
  130. const Dwarf::LocationInfoMode mode_;
  131. using SymbolCache = EvictingCacheMap<uintptr_t, SymbolizedFrame>;
  132. folly::Optional<Synchronized<SymbolCache>> symbolCache_;
  133. };
  134. /**
  135. * Format one address in the way it's usually printed by SymbolizePrinter.
  136. * Async-signal-safe.
  137. */
  138. class AddressFormatter {
  139. public:
  140. AddressFormatter();
  141. /**
  142. * Format the address. Returns an internal buffer.
  143. */
  144. StringPiece format(uintptr_t address);
  145. private:
  146. static constexpr char bufTemplate[] = " @ 0000000000000000";
  147. char buf_[sizeof(bufTemplate)];
  148. };
  149. /**
  150. * Print a list of symbolized addresses. Base class.
  151. */
  152. class SymbolizePrinter {
  153. public:
  154. /**
  155. * Print one address, no ending newline.
  156. */
  157. void print(uintptr_t address, const SymbolizedFrame& frame);
  158. /**
  159. * Print one address with ending newline.
  160. */
  161. void println(uintptr_t address, const SymbolizedFrame& frame);
  162. /**
  163. * Print multiple addresses on separate lines.
  164. */
  165. void println(
  166. const uintptr_t* addresses,
  167. const SymbolizedFrame* frames,
  168. size_t frameCount);
  169. /**
  170. * Print a string, no endling newline.
  171. */
  172. void print(StringPiece sp) {
  173. doPrint(sp);
  174. }
  175. /**
  176. * Print multiple addresses on separate lines, skipping the first
  177. * skip addresses.
  178. */
  179. template <size_t N>
  180. void println(const FrameArray<N>& fa, size_t skip = 0) {
  181. if (skip < fa.frameCount) {
  182. println(fa.addresses + skip, fa.frames + skip, fa.frameCount - skip);
  183. }
  184. }
  185. /**
  186. * If output buffered inside this class, send it to the output stream, so that
  187. * any output done in other ways appears after this.
  188. */
  189. virtual void flush() {}
  190. virtual ~SymbolizePrinter() {}
  191. enum Options {
  192. // Skip file and line information
  193. NO_FILE_AND_LINE = 1 << 0,
  194. // As terse as it gets: function name if found, address otherwise
  195. TERSE = 1 << 1,
  196. // Always colorize output (ANSI escape code)
  197. COLOR = 1 << 2,
  198. // Colorize output only if output is printed to a TTY (ANSI escape code)
  199. COLOR_IF_TTY = 1 << 3,
  200. // Skip frame address information
  201. NO_FRAME_ADDRESS = 1 << 4,
  202. };
  203. // NOTE: enum values used as indexes in kColorMap.
  204. enum Color { DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, WHITE, PURPLE, NUM };
  205. void color(Color c);
  206. protected:
  207. explicit SymbolizePrinter(int options, bool isTty = false)
  208. : options_(options), isTty_(isTty) {}
  209. const int options_;
  210. const bool isTty_;
  211. private:
  212. void printTerse(uintptr_t address, const SymbolizedFrame& frame);
  213. virtual void doPrint(StringPiece sp) = 0;
  214. static constexpr std::array<const char*, Color::NUM> kColorMap = {{
  215. "\x1B[0m",
  216. "\x1B[31m",
  217. "\x1B[32m",
  218. "\x1B[33m",
  219. "\x1B[34m",
  220. "\x1B[36m",
  221. "\x1B[37m",
  222. "\x1B[35m",
  223. }};
  224. };
  225. /**
  226. * Print a list of symbolized addresses to a stream.
  227. * Not reentrant. Do not use from signal handling code.
  228. */
  229. class OStreamSymbolizePrinter : public SymbolizePrinter {
  230. public:
  231. explicit OStreamSymbolizePrinter(std::ostream& out, int options = 0);
  232. private:
  233. void doPrint(StringPiece sp) override;
  234. std::ostream& out_;
  235. };
  236. /**
  237. * Print a list of symbolized addresses to a file descriptor.
  238. * Ignores errors. Async-signal-safe.
  239. */
  240. class FDSymbolizePrinter : public SymbolizePrinter {
  241. public:
  242. explicit FDSymbolizePrinter(int fd, int options = 0, size_t bufferSize = 0);
  243. ~FDSymbolizePrinter() override;
  244. virtual void flush() override;
  245. private:
  246. void doPrint(StringPiece sp) override;
  247. const int fd_;
  248. std::unique_ptr<IOBuf> buffer_;
  249. };
  250. /**
  251. * Print a list of symbolized addresses to a FILE*.
  252. * Ignores errors. Not reentrant. Do not use from signal handling code.
  253. */
  254. class FILESymbolizePrinter : public SymbolizePrinter {
  255. public:
  256. explicit FILESymbolizePrinter(FILE* file, int options = 0);
  257. private:
  258. void doPrint(StringPiece sp) override;
  259. FILE* const file_ = nullptr;
  260. };
  261. /**
  262. * Print a list of symbolized addresses to a std::string.
  263. * Not reentrant. Do not use from signal handling code.
  264. */
  265. class StringSymbolizePrinter : public SymbolizePrinter {
  266. public:
  267. explicit StringSymbolizePrinter(int options = 0)
  268. : SymbolizePrinter(options) {}
  269. std::string str() const {
  270. return buf_.toStdString();
  271. }
  272. const fbstring& fbstr() const {
  273. return buf_;
  274. }
  275. fbstring moveFbString() {
  276. return std::move(buf_);
  277. }
  278. private:
  279. void doPrint(StringPiece sp) override;
  280. fbstring buf_;
  281. };
  282. /**
  283. * Use this class to print a stack trace from a signal handler, or other place
  284. * where you shouldn't allocate memory on the heap, and fsync()ing your file
  285. * descriptor is more important than performance.
  286. *
  287. * Make sure to create one of these on startup, not in the signal handler, as
  288. * the constructor allocates on the heap, whereas the other methods don't. Best
  289. * practice is to just leak this object, rather than worry about destruction
  290. * order.
  291. *
  292. * These methods aren't thread safe, so if you could have signals on multiple
  293. * threads at the same time, you need to do your own locking to ensure you don't
  294. * call these methods from multiple threads. They are signal safe, however.
  295. */
  296. class SafeStackTracePrinter {
  297. public:
  298. static constexpr size_t kDefaultMinSignalSafeElfCacheSize = 500;
  299. explicit SafeStackTracePrinter(
  300. size_t minSignalSafeElfCacheSize = kDefaultMinSignalSafeElfCacheSize,
  301. int fd = STDERR_FILENO);
  302. virtual ~SafeStackTracePrinter() {}
  303. /**
  304. * Only allocates on the stack and is signal-safe but not thread-safe. Don't
  305. * call printStackTrace() on the same StackTracePrinter object from multiple
  306. * threads at the same time.
  307. *
  308. * This is NOINLINE to make sure it shows up in the stack we grab, which makes
  309. * it easy to skip printing it.
  310. */
  311. FOLLY_NOINLINE void printStackTrace(bool symbolize);
  312. void print(StringPiece sp) {
  313. printer_.print(sp);
  314. }
  315. // Flush printer_, also fsync, in case we're about to crash again...
  316. void flush();
  317. protected:
  318. virtual void printSymbolizedStackTrace();
  319. private:
  320. static constexpr size_t kMaxStackTraceDepth = 100;
  321. int fd_;
  322. SignalSafeElfCache elfCache_;
  323. FDSymbolizePrinter printer_;
  324. std::unique_ptr<FrameArray<kMaxStackTraceDepth>> addresses_;
  325. };
  326. /**
  327. * Use this class to print a stack trace from normal code. It will malloc and
  328. * won't flush or sync.
  329. *
  330. * These methods are thread safe, through locking. However, they are not signal
  331. * safe.
  332. */
  333. class FastStackTracePrinter {
  334. public:
  335. static constexpr size_t kDefaultSymbolCacheSize = 10000;
  336. explicit FastStackTracePrinter(
  337. std::unique_ptr<SymbolizePrinter> printer,
  338. size_t elfCacheSize = 0, // 0 means "use the default elf cache instance."
  339. size_t symbolCacheSize = kDefaultSymbolCacheSize);
  340. ~FastStackTracePrinter();
  341. /**
  342. * This is NOINLINE to make sure it shows up in the stack we grab, which makes
  343. * it easy to skip printing it.
  344. */
  345. FOLLY_NOINLINE void printStackTrace(bool symbolize);
  346. void flush();
  347. private:
  348. static constexpr size_t kMaxStackTraceDepth = 100;
  349. const std::unique_ptr<ElfCache> elfCache_;
  350. const std::unique_ptr<SymbolizePrinter> printer_;
  351. Symbolizer symbolizer_;
  352. };
  353. /**
  354. * Use this class in rare situations where signal handlers are running in a
  355. * tiny stack specified by sigaltstack.
  356. *
  357. * This is neither thread-safe nor signal-safe. However, it can usually print
  358. * something useful while SafeStackTracePrinter would stack overflow.
  359. *
  360. * Signal handlers would need to block other signals to make this safer.
  361. * Note it's still unsafe even with that.
  362. */
  363. class UnsafeSelfAllocateStackTracePrinter : public SafeStackTracePrinter {
  364. protected:
  365. void printSymbolizedStackTrace() override;
  366. const long pageSizeUnchecked_ = sysconf(_SC_PAGESIZE);
  367. };
  368. } // namespace symbolizer
  369. } // namespace folly