026554920481b59d0c77f18db00583d550653c4c
[folly.git] / folly / experimental / symbolizer / Symbolizer.h
1 /*
2  * Copyright 2013 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
18 #ifndef FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_
19 #define FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_
20
21 #include <cstdint>
22 #include <string>
23 #include <unordered_map>
24
25 #include "folly/FBString.h"
26 #include "folly/Range.h"
27 #include "folly/experimental/symbolizer/Elf.h"
28 #include "folly/experimental/symbolizer/Dwarf.h"
29 #include "folly/experimental/symbolizer/StackTrace.h"
30
31 namespace folly {
32 namespace symbolizer {
33
34 /**
35  * Frame information: symbol name and location.
36  *
37  * Note that both name and location are references in the Symbolizer object,
38  * which must outlive this SymbolizedFrame object.
39  */
40 struct SymbolizedFrame {
41   SymbolizedFrame() : found(false) { }
42   bool isSignalFrame;
43   bool found;
44   StringPiece name;
45   Dwarf::LocationInfo location;
46 };
47
48 template <size_t N>
49 struct FrameArray {
50   FrameArray() : frameCount(0) { }
51
52   size_t frameCount;
53   uintptr_t addresses[N];
54   SymbolizedFrame frames[N];
55 };
56
57 /**
58  * Get stack trace into a given FrameArray, return true on success (and
59  * set frameCount to the actual frame count, which may be > N) and false
60  * on failure.
61  */
62 namespace detail {
63 template <size_t N>
64 bool fixFrameArray(FrameArray<N>& fa, ssize_t n) {
65   if (n != -1) {
66     fa.frameCount = n;
67     for (size_t i = 0; i < fa.frameCount; ++i) {
68       fa.frames[i].found = false;
69     }
70     return true;
71   } else {
72     fa.frameCount = 0;
73     return false;
74   }
75 }
76 }  // namespace detail
77
78 template <size_t N>
79 bool getStackTrace(FrameArray<N>& fa) {
80   return detail::fixFrameArray(fa, getStackTrace(fa.addresses, N));
81 }
82
83 template <size_t N>
84 bool getStackTraceSafe(FrameArray<N>& fa) {
85   return detail::fixFrameArray(fa, getStackTraceSafe(fa.addresses, N));
86 }
87
88 class Symbolizer {
89  public:
90   Symbolizer() : fileCount_(0) { }
91
92   /**
93    * Symbolize given addresses.
94    */
95   void symbolize(const uintptr_t* addresses,
96                  SymbolizedFrame* frames,
97                  size_t frameCount);
98
99   template <size_t N>
100   void symbolize(FrameArray<N>& fa) {
101     symbolize(fa.addresses, fa.frames, fa.frameCount);
102   }
103
104   /**
105    * Shortcut to symbolize one address.
106    */
107   bool symbolize(uintptr_t address, SymbolizedFrame& frame) {
108     symbolize(&address, &frame, 1);
109     return frame.found;
110   }
111
112  private:
113   // We can't allocate memory, so we'll preallocate room.
114   // "1023 shared libraries should be enough for everyone"
115   static constexpr size_t kMaxFiles = 1024;
116   size_t fileCount_;
117   ElfFile files_[kMaxFiles];
118 };
119
120 /**
121  * Print a list of symbolized addresses. Base class.
122  */
123 class SymbolizePrinter {
124  public:
125   /**
126    * Print one address, no ending newline.
127    */
128   void print(uintptr_t address, const SymbolizedFrame& frame);
129
130   /**
131    * Print one address with ending newline.
132    */
133   void println(uintptr_t address, const SymbolizedFrame& frame);
134
135   /**
136    * Print multiple addresses on separate lines.
137    */
138   void println(const uintptr_t* addresses,
139                const SymbolizedFrame* frames,
140                size_t frameCount);
141
142   /**
143    * Print multiple addresses on separate lines, skipping the first
144    * skip addresses.
145    */
146   template <size_t N>
147   void println(const FrameArray<N>& fa, size_t skip=0) {
148     if (skip < fa.frameCount) {
149       println(fa.addresses + skip, fa.frames + skip, fa.frameCount - skip);
150     }
151   }
152
153   virtual ~SymbolizePrinter() { }
154
155   enum Options {
156     // Skip file and line information
157     NO_FILE_AND_LINE = 1 << 0,
158
159     // As terse as it gets: function name if found, address otherwise
160     TERSE = 1 << 1,
161   };
162
163  protected:
164   explicit SymbolizePrinter(int options) : options_(options) { }
165   const int options_;
166
167  private:
168   void printTerse(uintptr_t address, const SymbolizedFrame& frame);
169   virtual void doPrint(StringPiece sp) = 0;
170 };
171
172 /**
173  * Print a list of symbolized addresses to a stream.
174  * Not reentrant. Do not use from signal handling code.
175  */
176 class OStreamSymbolizePrinter : public SymbolizePrinter {
177  public:
178   explicit OStreamSymbolizePrinter(std::ostream& out, int options=0)
179     : SymbolizePrinter(options),
180       out_(out) { }
181  private:
182   void doPrint(StringPiece sp) override;
183   std::ostream& out_;
184 };
185
186 /**
187  * Print a list of symbolized addresses to a file descriptor.
188  * Ignores errors. Async-signal-safe.
189  */
190 class FDSymbolizePrinter : public SymbolizePrinter {
191  public:
192   explicit FDSymbolizePrinter(int fd, int options=0)
193     : SymbolizePrinter(options),
194       fd_(fd) { }
195  private:
196   void doPrint(StringPiece sp) override;
197   int fd_;
198 };
199
200 /**
201  * Print a list of symbolized addresses to a FILE*.
202  * Ignores errors. Not reentrant. Do not use from signal handling code.
203  */
204 class FILESymbolizePrinter : public SymbolizePrinter {
205  public:
206   explicit FILESymbolizePrinter(FILE* file, int options=0)
207     : SymbolizePrinter(options),
208       file_(file) { }
209  private:
210   void doPrint(StringPiece sp) override;
211   FILE* file_;
212 };
213
214 /**
215  * Print a list of symbolized addresses to a std::string.
216  * Not reentrant. Do not use from signal handling code.
217  */
218 class StringSymbolizePrinter : public SymbolizePrinter {
219  public:
220   explicit StringSymbolizePrinter(int options=0) : SymbolizePrinter(options) { }
221
222   std::string str() const { return buf_.toStdString(); }
223   const fbstring& fbstr() const { return buf_; }
224   fbstring moveFbString() { return std::move(buf_); }
225
226  private:
227   void doPrint(StringPiece sp) override;
228   fbstring buf_;
229 };
230
231 }  // namespace symbolizer
232 }  // namespace folly
233
234 #endif /* FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_ */
235