d3e6d4525b996079807234040500de6cdcc2e1a1
[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 #include "folly/experimental/symbolizer/StackTrace.h"
29
30 namespace folly {
31 namespace symbolizer {
32
33 /**
34  * Frame information: symbol name and location.
35  *
36  * Note that both name and location are references in the Symbolizer object,
37  * which must outlive this SymbolizedFrame object.
38  */
39 struct SymbolizedFrame {
40   SymbolizedFrame() : found(false) { }
41   bool isSignalFrame;
42   bool found;
43   StringPiece name;
44   Dwarf::LocationInfo location;
45 };
46
47 template <size_t N>
48 struct FrameArray {
49   FrameArray() : frameCount(0) { }
50
51   size_t frameCount;
52   uintptr_t addresses[N];
53   SymbolizedFrame frames[N];
54 };
55
56 /**
57  * Get stack trace into a given FrameArray, return true on success (and
58  * set frameCount to the actual frame count, which may be > N) and false
59  * on failure.
60  */
61 template <size_t N>
62 bool getStackTrace(FrameArray<N>& fa) {
63   ssize_t n = getStackTrace(fa.addresses, N);
64   if (n != -1) {
65     fa.frameCount = n;
66     for (size_t i = 0; i < fa.frameCount; ++i) {
67       fa.frames[i].found = false;
68     }
69     return true;
70   } else {
71     fa.frameCount = 0;
72     return false;
73   }
74 }
75
76 class Symbolizer {
77  public:
78   Symbolizer() : fileCount_(0) { }
79
80   /**
81    * Symbolize given addresses.
82    */
83   void symbolize(const uintptr_t* addresses,
84                  SymbolizedFrame* frames,
85                  size_t frameCount);
86
87   template <size_t N>
88   void symbolize(FrameArray<N>& fa) {
89     symbolize(fa.addresses, fa.frames, fa.frameCount);
90   }
91
92   /**
93    * Shortcut to symbolize one address.
94    */
95   bool symbolize(uintptr_t address, SymbolizedFrame& frame) {
96     symbolize(&address, &frame, 1);
97     return frame.found;
98   }
99
100  private:
101   // We can't allocate memory, so we'll preallocate room.
102   // "1023 shared libraries should be enough for everyone"
103   static constexpr size_t kMaxFiles = 1024;
104   size_t fileCount_;
105   ElfFile files_[kMaxFiles];
106 };
107
108 /**
109  * Print a list of symbolized addresses. Base class.
110  */
111 class SymbolizePrinter {
112  public:
113   void print(uintptr_t address, const SymbolizedFrame& frame);
114   void print(const uintptr_t* addresses,
115              const SymbolizedFrame* frames,
116              size_t frameCount);
117
118   template <size_t N>
119   void print(const FrameArray<N>& fa, size_t skip=0) {
120     if (skip < fa.frameCount) {
121       print(fa.addresses + skip, fa.frames + skip, fa.frameCount - skip);
122     }
123   }
124
125   virtual ~SymbolizePrinter() { }
126  private:
127   virtual void doPrint(StringPiece sp) = 0;
128 };
129
130 /**
131  * Print a list of symbolized addresses to a stream.
132  * Not reentrant. Do not use from signal handling code.
133  */
134 class OStreamSymbolizePrinter : public SymbolizePrinter {
135  public:
136   explicit OStreamSymbolizePrinter(std::ostream& out) : out_(out) { }
137  private:
138   void doPrint(StringPiece sp) override;
139   std::ostream& out_;
140 };
141
142 /**
143  * Print a list of symbolized addresses to a file descriptor.
144  * Ignores errors. Async-signal-safe.
145  */
146 class FDSymbolizePrinter : public SymbolizePrinter {
147  public:
148   explicit FDSymbolizePrinter(int fd) : fd_(fd) { }
149  private:
150   void doPrint(StringPiece sp) override;
151   int fd_;
152 };
153
154 }  // namespace symbolizer
155 }  // namespace folly
156
157 #endif /* FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_ */
158