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