Harden failure signal handler in the face of memory corruptions
[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 /**
36  * Frame information: symbol name and location.
37  *
38  * Note that both name and location are references in the Symbolizer object,
39  * which must outlive this SymbolizedFrame object.
40  */
41 struct SymbolizedFrame {
42   SymbolizedFrame() : found(false) { }
43   bool isSignalFrame;
44   bool found;
45   StringPiece name;
46   Dwarf::LocationInfo location;
47
48   /**
49    * Demangle the name and return it. Not async-signal-safe; allocates memory.
50    */
51   fbstring demangledName() const {
52     return demangle(name.fbstr().c_str());
53   }
54 };
55
56 template <size_t N>
57 struct FrameArray {
58   FrameArray() : frameCount(0) { }
59
60   size_t frameCount;
61   uintptr_t addresses[N];
62   SymbolizedFrame frames[N];
63 };
64
65 /**
66  * Get stack trace into a given FrameArray, return true on success (and
67  * set frameCount to the actual frame count, which may be > N) and false
68  * on failure.
69  */
70 namespace detail {
71 template <size_t N>
72 bool fixFrameArray(FrameArray<N>& fa, ssize_t n) {
73   if (n != -1) {
74     fa.frameCount = n;
75     for (size_t i = 0; i < fa.frameCount; ++i) {
76       fa.frames[i].found = false;
77     }
78     return true;
79   } else {
80     fa.frameCount = 0;
81     return false;
82   }
83 }
84 }  // namespace detail
85
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 inline bool getStackTrace(FrameArray<N>& fa) __attribute__((always_inline));
90
91 template <size_t N>
92 inline bool getStackTrace(FrameArray<N>& fa) {
93   return detail::fixFrameArray(fa, getStackTrace(fa.addresses, N));
94 }
95 template <size_t N>
96 inline bool getStackTraceSafe(FrameArray<N>& fa) __attribute__((always_inline));
97
98 template <size_t N>
99 inline bool getStackTraceSafe(FrameArray<N>& fa) {
100   return detail::fixFrameArray(fa, getStackTraceSafe(fa.addresses, N));
101 }
102
103 class Symbolizer {
104  public:
105   explicit Symbolizer(ElfCacheBase* cache = nullptr);
106
107   /**
108    * Symbolize given addresses.
109    */
110   void symbolize(const uintptr_t* addresses,
111                  SymbolizedFrame* frames,
112                  size_t frameCount);
113
114   template <size_t N>
115   void symbolize(FrameArray<N>& fa) {
116     symbolize(fa.addresses, fa.frames, fa.frameCount);
117   }
118
119   /**
120    * Shortcut to symbolize one address.
121    */
122   bool symbolize(uintptr_t address, SymbolizedFrame& frame) {
123     symbolize(&address, &frame, 1);
124     return frame.found;
125   }
126
127  private:
128   ElfCacheBase* cache_;
129 };
130
131 /**
132  * Format one address in the way it's usually printer by SymbolizePrinter.
133  * Async-signal-safe.
134  */
135 class AddressFormatter {
136  public:
137   AddressFormatter();
138
139   /**
140    * Format the address. Returns an internal buffer.
141    */
142   StringPiece format(uintptr_t address);
143
144  private:
145   static constexpr char bufTemplate[] = "    @ 0000000000000000";
146   char buf_[sizeof(bufTemplate)];
147 };
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   /**
160    * Print one address with ending newline.
161    */
162   void println(uintptr_t address, const SymbolizedFrame& frame);
163
164   /**
165    * Print multiple addresses on separate lines.
166    */
167   void println(const uintptr_t* addresses,
168                const SymbolizedFrame* frames,
169                size_t frameCount);
170
171   /**
172    * Print multiple addresses on separate lines, skipping the first
173    * skip addresses.
174    */
175   template <size_t N>
176   void println(const FrameArray<N>& fa, size_t skip=0) {
177     if (skip < fa.frameCount) {
178       println(fa.addresses + skip, fa.frames + skip, fa.frameCount - skip);
179     }
180   }
181
182   virtual ~SymbolizePrinter() { }
183
184   enum Options {
185     // Skip file and line information
186     NO_FILE_AND_LINE = 1 << 0,
187
188     // As terse as it gets: function name if found, address otherwise
189     TERSE = 1 << 1,
190
191     // Always colorize output (ANSI escape code)
192     COLOR = 1 << 2,
193
194     // Colorize output only if output is printed to a TTY (ANSI escape code)
195     COLOR_IF_TTY = 1 << 3,
196   };
197
198   enum Color { DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, WHITE, PURPLE };
199   void color(Color c);
200
201  protected:
202   explicit SymbolizePrinter(int options, bool isTty = false)
203     : options_(options),
204       isTty_(isTty) {
205   }
206
207   const int options_;
208   const bool isTty_;
209
210  private:
211   void printTerse(uintptr_t address, const SymbolizedFrame& frame);
212   virtual void doPrint(StringPiece sp) = 0;
213 };
214
215 /**
216  * Print a list of symbolized addresses to a stream.
217  * Not reentrant. Do not use from signal handling code.
218  */
219 class OStreamSymbolizePrinter : public SymbolizePrinter {
220  public:
221   explicit OStreamSymbolizePrinter(std::ostream& out, int options=0);
222  private:
223   void doPrint(StringPiece sp) override;
224   std::ostream& out_;
225 };
226
227 /**
228  * Print a list of symbolized addresses to a file descriptor.
229  * Ignores errors. Async-signal-safe.
230  */
231 class FDSymbolizePrinter : public SymbolizePrinter {
232  public:
233   explicit FDSymbolizePrinter(int fd, int options=0);
234  private:
235   void doPrint(StringPiece sp) override;
236   int fd_;
237 };
238
239 /**
240  * Print a list of symbolized addresses to a FILE*.
241  * Ignores errors. Not reentrant. Do not use from signal handling code.
242  */
243 class FILESymbolizePrinter : public SymbolizePrinter {
244  public:
245   explicit FILESymbolizePrinter(FILE* file, int options=0);
246  private:
247   void doPrint(StringPiece sp) override;
248   FILE* file_;
249 };
250
251 /**
252  * Print a list of symbolized addresses to a std::string.
253  * Not reentrant. Do not use from signal handling code.
254  */
255 class StringSymbolizePrinter : public SymbolizePrinter {
256  public:
257   explicit StringSymbolizePrinter(int options=0) : SymbolizePrinter(options) { }
258
259   std::string str() const { return buf_.toStdString(); }
260   const fbstring& fbstr() const { return buf_; }
261   fbstring moveFbString() { return std::move(buf_); }
262
263  private:
264   void doPrint(StringPiece sp) override;
265   fbstring buf_;
266 };
267
268 }  // namespace symbolizer
269 }  // namespace folly
270
271 #endif /* FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_ */