0000614114431f85c8ad87d53a03ee473efa2b95
[folly.git] / folly / experimental / symbolizer / Symbolizer.h
1 /*
2  * Copyright 2014 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 #ifndef FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_
18 #define FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_
19
20 #include <cstdint>
21 #include <string>
22 #include <unordered_map>
23
24 #include "folly/FBString.h"
25 #include "folly/Range.h"
26 #include "folly/String.h"
27 #include "folly/experimental/symbolizer/Elf.h"
28 #include "folly/experimental/symbolizer/ElfCache.h"
29 #include "folly/experimental/symbolizer/Dwarf.h"
30 #include "folly/experimental/symbolizer/StackTrace.h"
31
32 namespace folly {
33 namespace symbolizer {
34
35 class Symbolizer;
36
37 /**
38  * Frame information: symbol name and location.
39  */
40 struct SymbolizedFrame {
41   SymbolizedFrame() : found(false) { }
42
43   void set(const std::shared_ptr<ElfFile>& file, uintptr_t address);
44   void clear() { *this = SymbolizedFrame(); }
45
46   bool isSignalFrame;
47   bool found;
48   StringPiece name;
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 demangle(name.fbstr().c_str());
56   }
57  private:
58   std::shared_ptr<ElfFile> file_;
59 };
60
61 template <size_t N>
62 struct FrameArray {
63   FrameArray() : frameCount(0) { }
64
65   size_t frameCount;
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* cache_;
134 };
135
136 /**
137  * Format one address in the way it's usually printer 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 multiple addresses on separate lines, skipping the first
178    * skip addresses.
179    */
180   template <size_t N>
181   void println(const FrameArray<N>& fa, size_t skip=0) {
182     if (skip < fa.frameCount) {
183       println(fa.addresses + skip, fa.frames + skip, fa.frameCount - skip);
184     }
185   }
186
187   virtual ~SymbolizePrinter() { }
188
189   enum Options {
190     // Skip file and line information
191     NO_FILE_AND_LINE = 1 << 0,
192
193     // As terse as it gets: function name if found, address otherwise
194     TERSE = 1 << 1,
195
196     // Always colorize output (ANSI escape code)
197     COLOR = 1 << 2,
198
199     // Colorize output only if output is printed to a TTY (ANSI escape code)
200     COLOR_IF_TTY = 1 << 3,
201   };
202
203   enum Color { DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, WHITE, PURPLE };
204   void color(Color c);
205
206  protected:
207   explicit SymbolizePrinter(int options, bool isTty = false)
208     : options_(options),
209       isTty_(isTty) {
210   }
211
212   const int options_;
213   const bool isTty_;
214
215  private:
216   void printTerse(uintptr_t address, const SymbolizedFrame& frame);
217   virtual void doPrint(StringPiece sp) = 0;
218 };
219
220 /**
221  * Print a list of symbolized addresses to a stream.
222  * Not reentrant. Do not use from signal handling code.
223  */
224 class OStreamSymbolizePrinter : public SymbolizePrinter {
225  public:
226   explicit OStreamSymbolizePrinter(std::ostream& out, int options=0);
227  private:
228   void doPrint(StringPiece sp) override;
229   std::ostream& out_;
230 };
231
232 /**
233  * Print a list of symbolized addresses to a file descriptor.
234  * Ignores errors. Async-signal-safe.
235  */
236 class FDSymbolizePrinter : public SymbolizePrinter {
237  public:
238   explicit FDSymbolizePrinter(int fd, int options=0);
239  private:
240   void doPrint(StringPiece sp) override;
241   int fd_;
242 };
243
244 /**
245  * Print a list of symbolized addresses to a FILE*.
246  * Ignores errors. Not reentrant. Do not use from signal handling code.
247  */
248 class FILESymbolizePrinter : public SymbolizePrinter {
249  public:
250   explicit FILESymbolizePrinter(FILE* file, int options=0);
251  private:
252   void doPrint(StringPiece sp) override;
253   FILE* file_;
254 };
255
256 /**
257  * Print a list of symbolized addresses to a std::string.
258  * Not reentrant. Do not use from signal handling code.
259  */
260 class StringSymbolizePrinter : public SymbolizePrinter {
261  public:
262   explicit StringSymbolizePrinter(int options=0) : SymbolizePrinter(options) { }
263
264   std::string str() const { return buf_.toStdString(); }
265   const fbstring& fbstr() const { return buf_; }
266   fbstring moveFbString() { return std::move(buf_); }
267
268  private:
269   void doPrint(StringPiece sp) override;
270   fbstring buf_;
271 };
272
273 }  // namespace symbolizer
274 }  // namespace folly
275
276 #endif /* FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_ */