Async-signal-safe symbolizer, fatal signal handler
[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  * Address information: symbol name and location.
34  *
35  * Note that both name and location are references in the Symbolizer object,
36  * which must outlive this AddressInfo object.
37  */
38 struct AddressInfo {
39   /* implicit */ AddressInfo(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 /**
51  * Get the current stack trace into addresses, which has room for at least
52  * maxAddresses entries. Skip the first (topmost) skip entries.
53  * Returns the number of entries in addresses on success, -1 on failure.
54  */
55 ssize_t getStackTrace(AddressInfo* addresses,
56                       size_t maxAddresses,
57                       size_t skip=0);
58
59 class Symbolizer {
60  public:
61   Symbolizer() : fileCount_(0) { }
62
63   /**
64    * Symbolize given addresses.
65    */
66   void symbolize(AddressInfo* addresses, size_t addressCount);
67
68   /**
69    * Shortcut to symbolize one address.
70    */
71   bool symbolize(AddressInfo& address) {
72     symbolize(&address, 1);
73     return address.found;
74   }
75
76  private:
77   // We can't allocate memory, so we'll preallocate room.
78   // "1023 shared libraries should be enough for everyone"
79   static constexpr size_t kMaxFiles = 1024;
80   size_t fileCount_;
81   ElfFile files_[kMaxFiles];
82 };
83
84 /**
85  * Print a list of symbolized addresses. Base class.
86  */
87 class SymbolizePrinter {
88  public:
89   void print(const AddressInfo& ainfo);
90   void print(const AddressInfo* addresses, size_t addressCount);
91
92   virtual ~SymbolizePrinter() { }
93  private:
94   virtual void doPrint(StringPiece sp) = 0;
95 };
96
97 /**
98  * Print a list of symbolized addresses to a stream.
99  * Not reentrant. Do not use from signal handling code.
100  */
101 class OStreamSymbolizePrinter : public SymbolizePrinter {
102  public:
103   explicit OStreamSymbolizePrinter(std::ostream& out) : out_(out) { }
104  private:
105   void doPrint(StringPiece sp) override;
106   std::ostream& out_;
107 };
108
109 /**
110  * Print a list of symbolized addresses to a file descriptor.
111  * Ignores errors. Async-signal-safe.
112  */
113 class FDSymbolizePrinter : public SymbolizePrinter {
114  public:
115   explicit FDSymbolizePrinter(int fd) : fd_(fd) { }
116  private:
117   void doPrint(StringPiece sp) override;
118   int fd_;
119 };
120
121 /**
122  * Print an AddressInfo to a stream. Note that the Symbolizer that
123  * symbolized the address must outlive the AddressInfo. Just like
124  * OStreamSymbolizePrinter (which it uses internally), this is not
125  * reentrant; do not use from signal handling code.
126  */
127 std::ostream& operator<<(std::ostream& out, const AddressInfo& ainfo);
128
129 }  // namespace symbolizer
130 }  // namespace folly
131
132 #endif /* FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_ */
133