2 * Copyright 2014 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #ifndef FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_
18 #define FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_
22 #include <unordered_map>
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"
33 namespace symbolizer {
38 * Frame information: symbol name and location.
40 struct SymbolizedFrame {
41 SymbolizedFrame() : found(false), name(nullptr) { }
43 void set(const std::shared_ptr<ElfFile>& file, uintptr_t address);
44 void clear() { *this = SymbolizedFrame(); }
49 Dwarf::LocationInfo location;
52 * Demangle the name and return it. Not async-signal-safe; allocates memory.
54 fbstring demangledName() const {
55 return name ? demangle(name) : fbstring();
58 std::shared_ptr<ElfFile> file_;
63 FrameArray() : frameCount(0) { }
66 uintptr_t addresses[N];
67 SymbolizedFrame frames[N];
71 * Get stack trace into a given FrameArray, return true on success (and
72 * set frameCount to the actual frame count, which may be > N) and false
77 bool fixFrameArray(FrameArray<N>& fa, ssize_t n) {
80 for (size_t i = 0; i < fa.frameCount; ++i) {
81 fa.frames[i].found = false;
91 // Always inline these functions; they don't do much, and unittests rely
92 // on them never showing up in a stack trace.
94 FOLLY_ALWAYS_INLINE bool getStackTrace(FrameArray<N>& fa);
97 inline bool getStackTrace(FrameArray<N>& fa) {
98 return detail::fixFrameArray(fa, getStackTrace(fa.addresses, N));
101 FOLLY_ALWAYS_INLINE bool getStackTraceSafe(FrameArray<N>& fa);
104 inline bool getStackTraceSafe(FrameArray<N>& fa) {
105 return detail::fixFrameArray(fa, getStackTraceSafe(fa.addresses, N));
110 explicit Symbolizer(ElfCacheBase* cache = nullptr);
113 * Symbolize given addresses.
115 void symbolize(const uintptr_t* addresses,
116 SymbolizedFrame* frames,
120 void symbolize(FrameArray<N>& fa) {
121 symbolize(fa.addresses, fa.frames, fa.frameCount);
125 * Shortcut to symbolize one address.
127 bool symbolize(uintptr_t address, SymbolizedFrame& frame) {
128 symbolize(&address, &frame, 1);
133 ElfCacheBase* cache_;
137 * Format one address in the way it's usually printer by SymbolizePrinter.
140 class AddressFormatter {
145 * Format the address. Returns an internal buffer.
147 StringPiece format(uintptr_t address);
150 static constexpr char bufTemplate[] = " @ 0000000000000000";
151 char buf_[sizeof(bufTemplate)];
155 * Print a list of symbolized addresses. Base class.
157 class SymbolizePrinter {
160 * Print one address, no ending newline.
162 void print(uintptr_t address, const SymbolizedFrame& frame);
165 * Print one address with ending newline.
167 void println(uintptr_t address, const SymbolizedFrame& frame);
170 * Print multiple addresses on separate lines.
172 void println(const uintptr_t* addresses,
173 const SymbolizedFrame* frames,
177 * Print multiple addresses on separate lines, skipping the first
181 void println(const FrameArray<N>& fa, size_t skip=0) {
182 if (skip < fa.frameCount) {
183 println(fa.addresses + skip, fa.frames + skip, fa.frameCount - skip);
187 virtual ~SymbolizePrinter() { }
190 // Skip file and line information
191 NO_FILE_AND_LINE = 1 << 0,
193 // As terse as it gets: function name if found, address otherwise
196 // Always colorize output (ANSI escape code)
199 // Colorize output only if output is printed to a TTY (ANSI escape code)
200 COLOR_IF_TTY = 1 << 3,
203 enum Color { DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, WHITE, PURPLE };
207 explicit SymbolizePrinter(int options, bool isTty = false)
216 void printTerse(uintptr_t address, const SymbolizedFrame& frame);
217 virtual void doPrint(StringPiece sp) = 0;
221 * Print a list of symbolized addresses to a stream.
222 * Not reentrant. Do not use from signal handling code.
224 class OStreamSymbolizePrinter : public SymbolizePrinter {
226 explicit OStreamSymbolizePrinter(std::ostream& out, int options=0);
228 void doPrint(StringPiece sp) override;
233 * Print a list of symbolized addresses to a file descriptor.
234 * Ignores errors. Async-signal-safe.
236 class FDSymbolizePrinter : public SymbolizePrinter {
238 explicit FDSymbolizePrinter(int fd, int options=0);
240 void doPrint(StringPiece sp) override;
245 * Print a list of symbolized addresses to a FILE*.
246 * Ignores errors. Not reentrant. Do not use from signal handling code.
248 class FILESymbolizePrinter : public SymbolizePrinter {
250 explicit FILESymbolizePrinter(FILE* file, int options=0);
252 void doPrint(StringPiece sp) override;
257 * Print a list of symbolized addresses to a std::string.
258 * Not reentrant. Do not use from signal handling code.
260 class StringSymbolizePrinter : public SymbolizePrinter {
262 explicit StringSymbolizePrinter(int options=0) : SymbolizePrinter(options) { }
264 std::string str() const { return buf_.toStdString(); }
265 const fbstring& fbstr() const { return buf_; }
266 fbstring moveFbString() { return std::move(buf_); }
269 void doPrint(StringPiece sp) override;
273 } // namespace symbolizer
276 #endif /* FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_ */