Fix a typo
[folly.git] / folly / experimental / symbolizer / Symbolizer.h
1 /*
2  * Copyright 2016 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/io/IOBuf.h>
28 #include <folly/experimental/symbolizer/Elf.h>
29 #include <folly/experimental/symbolizer/ElfCache.h>
30 #include <folly/experimental/symbolizer/Dwarf.h>
31 #include <folly/experimental/symbolizer/StackTrace.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, uintptr_t address);
45   void clear() { *this = SymbolizedFrame(); }
46
47   bool found = false;
48   const char* name = nullptr;
49   Dwarf::LocationInfo location;
50
51   /**
52    * Demangle the name and return it. Not async-signal-safe; allocates memory.
53    */
54   fbstring demangledName() const {
55     return name ? demangle(name) : fbstring();
56   }
57  private:
58   std::shared_ptr<ElfFile> file_;
59 };
60
61 template <size_t N>
62 struct FrameArray {
63   FrameArray() { }
64
65   size_t frameCount = 0;
66   uintptr_t addresses[N];
67   SymbolizedFrame frames[N];
68 };
69
70 /**
71  * Get stack trace into a given FrameArray, return true on success (and
72  * set frameCount to the actual frame count, which may be > N) and false
73  * on failure.
74  */
75 namespace detail {
76 template <size_t N>
77 bool fixFrameArray(FrameArray<N>& fa, ssize_t n) {
78   if (n != -1) {
79     fa.frameCount = n;
80     for (size_t i = 0; i < fa.frameCount; ++i) {
81       fa.frames[i].found = false;
82     }
83     return true;
84   } else {
85     fa.frameCount = 0;
86     return false;
87   }
88 }
89 }  // namespace detail
90
91 // Always inline these functions; they don't do much, and unittests rely
92 // on them never showing up in a stack trace.
93 template <size_t N>
94 FOLLY_ALWAYS_INLINE bool getStackTrace(FrameArray<N>& fa);
95
96 template <size_t N>
97 inline bool getStackTrace(FrameArray<N>& fa) {
98   return detail::fixFrameArray(fa, getStackTrace(fa.addresses, N));
99 }
100 template <size_t N>
101 FOLLY_ALWAYS_INLINE bool getStackTraceSafe(FrameArray<N>& fa);
102
103 template <size_t N>
104 inline bool getStackTraceSafe(FrameArray<N>& fa) {
105   return detail::fixFrameArray(fa, getStackTraceSafe(fa.addresses, N));
106 }
107
108 class Symbolizer {
109  public:
110   explicit Symbolizer(ElfCacheBase* cache = nullptr);
111
112   /**
113    * Symbolize given addresses.
114    */
115   void symbolize(const uintptr_t* addresses,
116                  SymbolizedFrame* frames,
117                  size_t frameCount);
118
119   template <size_t N>
120   void symbolize(FrameArray<N>& fa) {
121     symbolize(fa.addresses, fa.frames, fa.frameCount);
122   }
123
124   /**
125    * Shortcut to symbolize one address.
126    */
127   bool symbolize(uintptr_t address, SymbolizedFrame& frame) {
128     symbolize(&address, &frame, 1);
129     return frame.found;
130   }
131
132  private:
133   ElfCacheBase* const cache_ = nullptr;
134 };
135
136 /**
137  * Format one address in the way it's usually printed by SymbolizePrinter.
138  * Async-signal-safe.
139  */
140 class AddressFormatter {
141  public:
142   AddressFormatter();
143
144   /**
145    * Format the address. Returns an internal buffer.
146    */
147   StringPiece format(uintptr_t address);
148
149  private:
150   static constexpr char bufTemplate[] = "    @ 0000000000000000";
151   char buf_[sizeof(bufTemplate)];
152 };
153
154 /**
155  * Print a list of symbolized addresses. Base class.
156  */
157 class SymbolizePrinter {
158  public:
159   /**
160    * Print one address, no ending newline.
161    */
162   void print(uintptr_t address, const SymbolizedFrame& frame);
163
164   /**
165    * Print one address with ending newline.
166    */
167   void println(uintptr_t address, const SymbolizedFrame& frame);
168
169   /**
170    * Print multiple addresses on separate lines.
171    */
172   void println(const uintptr_t* addresses,
173                const SymbolizedFrame* frames,
174                size_t frameCount);
175
176   /**
177    * Print a string, no endling newline.
178    */
179   void print(StringPiece sp) { doPrint(sp); }
180
181   /**
182    * Print multiple addresses on separate lines, skipping the first
183    * skip addresses.
184    */
185   template <size_t N>
186   void println(const FrameArray<N>& fa, size_t skip=0) {
187     if (skip < fa.frameCount) {
188       println(fa.addresses + skip, fa.frames + skip, fa.frameCount - skip);
189     }
190   }
191
192   virtual ~SymbolizePrinter() { }
193
194   enum Options {
195     // Skip file and line information
196     NO_FILE_AND_LINE = 1 << 0,
197
198     // As terse as it gets: function name if found, address otherwise
199     TERSE = 1 << 1,
200
201     // Always colorize output (ANSI escape code)
202     COLOR = 1 << 2,
203
204     // Colorize output only if output is printed to a TTY (ANSI escape code)
205     COLOR_IF_TTY = 1 << 3,
206
207     // Skip frame address information
208     NO_FRAME_ADDRESS = 1 << 4,
209   };
210
211   // NOTE: enum values used as indexes in kColorMap.
212   enum Color { DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, WHITE, PURPLE, NUM };
213   void color(Color c);
214
215  protected:
216   explicit SymbolizePrinter(int options, bool isTty = false)
217     : options_(options),
218       isTty_(isTty) {
219   }
220
221   const int options_;
222   const bool isTty_;
223
224  private:
225   void printTerse(uintptr_t address, const SymbolizedFrame& frame);
226   virtual void doPrint(StringPiece sp) = 0;
227
228   static constexpr std::array<const char*, Color::NUM> kColorMap = {{
229       "\x1B[0m",
230       "\x1B[31m",
231       "\x1B[32m",
232       "\x1B[33m",
233       "\x1B[34m",
234       "\x1B[36m",
235       "\x1B[37m",
236       "\x1B[35m",
237   }};
238 };
239
240 /**
241  * Print a list of symbolized addresses to a stream.
242  * Not reentrant. Do not use from signal handling code.
243  */
244 class OStreamSymbolizePrinter : public SymbolizePrinter {
245  public:
246   explicit OStreamSymbolizePrinter(std::ostream& out, int options=0);
247  private:
248   void doPrint(StringPiece sp) override;
249   std::ostream& out_;
250 };
251
252 /**
253  * Print a list of symbolized addresses to a file descriptor.
254  * Ignores errors. Async-signal-safe.
255  */
256 class FDSymbolizePrinter : public SymbolizePrinter {
257  public:
258   explicit FDSymbolizePrinter(int fd, int options=0,
259                               size_t bufferSize=0);
260   ~FDSymbolizePrinter();
261   void flush();
262  private:
263   void doPrint(StringPiece sp) override;
264
265   const int fd_;
266   std::unique_ptr<IOBuf> buffer_;
267 };
268
269 /**
270  * Print a list of symbolized addresses to a FILE*.
271  * Ignores errors. Not reentrant. Do not use from signal handling code.
272  */
273 class FILESymbolizePrinter : public SymbolizePrinter {
274  public:
275   explicit FILESymbolizePrinter(FILE* file, int options=0);
276  private:
277   void doPrint(StringPiece sp) override;
278   FILE* const file_ = nullptr;
279 };
280
281 /**
282  * Print a list of symbolized addresses to a std::string.
283  * Not reentrant. Do not use from signal handling code.
284  */
285 class StringSymbolizePrinter : public SymbolizePrinter {
286  public:
287   explicit StringSymbolizePrinter(int options=0) : SymbolizePrinter(options) { }
288
289   std::string str() const { return buf_.toStdString(); }
290   const fbstring& fbstr() const { return buf_; }
291   fbstring moveFbString() { return std::move(buf_); }
292
293  private:
294   void doPrint(StringPiece sp) override;
295   fbstring buf_;
296 };
297
298 }  // namespace symbolizer
299 }  // namespace folly