84913526917a36d32b2cf6f7c9711ae832848b72
[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/Range.h"
26 #include "folly/experimental/symbolizer/Elf.h"
27 #include "folly/experimental/symbolizer/Dwarf.h"
28
29 namespace folly {
30 namespace symbolizer {
31
32 /**
33  * Frame information: symbol name and location.
34  *
35  * Note that both name and location are references in the Symbolizer object,
36  * which must outlive this FrameInfo object.
37  */
38 struct FrameInfo {
39   /* implicit */ FrameInfo(uintptr_t a=0, bool sf=false)
40     : address(a),
41       isSignalFrame(sf),
42       found(false) { }
43   uintptr_t address;
44   bool isSignalFrame;
45   bool found;
46   StringPiece name;
47   Dwarf::LocationInfo location;
48 };
49
50 template <size_t N>
51 struct FrameArray {
52   FrameArray() : frameCount(0) { }
53
54   size_t frameCount;
55   FrameInfo frames[N];
56 };
57
58 /**
59  * Get the current stack trace into addresses, which has room for at least
60  * maxAddresses frames. Skip the first (topmost) skip entries.
61  *
62  * Returns the number of frames in the stack trace. Just like snprintf,
63  * if the number of frames is greater than maxAddresses, it will return
64  * the actual number of frames, so the stack trace was truncated iff
65  * the return value > maxAddresses.
66  *
67  * Returns -1 on failure.
68  */
69 ssize_t getStackTrace(FrameInfo* addresses,
70                       size_t maxAddresses,
71                       size_t skip=0);
72
73 /**
74  * Get stack trace into a given FrameArray, return true on success (and
75  * set frameCount to the actual frame count, which may be > N) and false
76  * on failure.
77  */
78 template <size_t N>
79 bool getStackTrace(FrameArray<N>& fa, size_t skip=0) {
80   ssize_t n = getStackTrace(fa.frames, N, skip);
81   if (n != -1) {
82     fa.frameCount = n;
83     return true;
84   } else {
85     fa.frameCount = 0;
86     return false;
87   }
88 }
89
90 class Symbolizer {
91  public:
92   Symbolizer() : fileCount_(0) { }
93
94   /**
95    * Symbolize given addresses.
96    */
97   void symbolize(FrameInfo* addresses, size_t addressCount);
98
99   template <size_t N>
100   void symbolize(FrameArray<N>& fa) {
101     symbolize(fa.frames, std::min(fa.frameCount, N));
102   }
103
104   /**
105    * Shortcut to symbolize one address.
106    */
107   bool symbolize(FrameInfo& address) {
108     symbolize(&address, 1);
109     return address.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   void print(const FrameInfo& ainfo);
126   void print(const FrameInfo* addresses,
127              size_t addressesSize,
128              size_t frameCount);
129
130   template <size_t N>
131   void print(const FrameArray<N>& fa) {
132     print(fa.frames, N, fa.frameCount);
133   }
134
135   virtual ~SymbolizePrinter() { }
136  private:
137   virtual void doPrint(StringPiece sp) = 0;
138 };
139
140 /**
141  * Print a list of symbolized addresses to a stream.
142  * Not reentrant. Do not use from signal handling code.
143  */
144 class OStreamSymbolizePrinter : public SymbolizePrinter {
145  public:
146   explicit OStreamSymbolizePrinter(std::ostream& out) : out_(out) { }
147  private:
148   void doPrint(StringPiece sp) override;
149   std::ostream& out_;
150 };
151
152 /**
153  * Print a list of symbolized addresses to a file descriptor.
154  * Ignores errors. Async-signal-safe.
155  */
156 class FDSymbolizePrinter : public SymbolizePrinter {
157  public:
158   explicit FDSymbolizePrinter(int fd) : fd_(fd) { }
159  private:
160   void doPrint(StringPiece sp) override;
161   int fd_;
162 };
163
164 /**
165  * Print an FrameInfo to a stream. Note that the Symbolizer that
166  * symbolized the address must outlive the FrameInfo. Just like
167  * OStreamSymbolizePrinter (which it uses internally), this is not
168  * reentrant; do not use from signal handling code.
169  */
170 std::ostream& operator<<(std::ostream& out, const FrameInfo& ainfo);
171
172 }  // namespace symbolizer
173 }  // namespace folly
174
175 #endif /* FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_ */
176