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/io/IOBuf.h"
28 #include "folly/experimental/symbolizer/Elf.h"
29 #include "folly/experimental/symbolizer/ElfCache.h"
30 #include "folly/experimental/symbolizer/Dwarf.h"
31 #include "folly/experimental/symbolizer/StackTrace.h"
34 namespace symbolizer {
39 * Frame information: symbol name and location.
41 struct SymbolizedFrame {
42 SymbolizedFrame() : found(false), name(nullptr) { }
44 void set(const std::shared_ptr<ElfFile>& file, uintptr_t address);
45 void clear() { *this = SymbolizedFrame(); }
50 Dwarf::LocationInfo location;
53 * Demangle the name and return it. Not async-signal-safe; allocates memory.
55 fbstring demangledName() const {
56 return name ? demangle(name) : fbstring();
59 std::shared_ptr<ElfFile> file_;
64 FrameArray() : frameCount(0) { }
67 uintptr_t addresses[N];
68 SymbolizedFrame frames[N];
72 * Get stack trace into a given FrameArray, return true on success (and
73 * set frameCount to the actual frame count, which may be > N) and false
78 bool fixFrameArray(FrameArray<N>& fa, ssize_t n) {
81 for (size_t i = 0; i < fa.frameCount; ++i) {
82 fa.frames[i].found = false;
92 // Always inline these functions; they don't do much, and unittests rely
93 // on them never showing up in a stack trace.
95 FOLLY_ALWAYS_INLINE bool getStackTrace(FrameArray<N>& fa);
98 inline bool getStackTrace(FrameArray<N>& fa) {
99 return detail::fixFrameArray(fa, getStackTrace(fa.addresses, N));
102 FOLLY_ALWAYS_INLINE bool getStackTraceSafe(FrameArray<N>& fa);
105 inline bool getStackTraceSafe(FrameArray<N>& fa) {
106 return detail::fixFrameArray(fa, getStackTraceSafe(fa.addresses, N));
111 explicit Symbolizer(ElfCacheBase* cache = nullptr);
114 * Symbolize given addresses.
116 void symbolize(const uintptr_t* addresses,
117 SymbolizedFrame* frames,
121 void symbolize(FrameArray<N>& fa) {
122 symbolize(fa.addresses, fa.frames, fa.frameCount);
126 * Shortcut to symbolize one address.
128 bool symbolize(uintptr_t address, SymbolizedFrame& frame) {
129 symbolize(&address, &frame, 1);
134 ElfCacheBase* cache_;
138 * Format one address in the way it's usually printer by SymbolizePrinter.
141 class AddressFormatter {
146 * Format the address. Returns an internal buffer.
148 StringPiece format(uintptr_t address);
151 static constexpr char bufTemplate[] = " @ 0000000000000000";
152 char buf_[sizeof(bufTemplate)];
156 * Print a list of symbolized addresses. Base class.
158 class SymbolizePrinter {
161 * Print one address, no ending newline.
163 void print(uintptr_t address, const SymbolizedFrame& frame);
166 * Print one address with ending newline.
168 void println(uintptr_t address, const SymbolizedFrame& frame);
171 * Print multiple addresses on separate lines.
173 void println(const uintptr_t* addresses,
174 const SymbolizedFrame* frames,
178 * Print a string, no endling newline.
180 void print(StringPiece sp) { doPrint(sp); }
183 * Print multiple addresses on separate lines, skipping the first
187 void println(const FrameArray<N>& fa, size_t skip=0) {
188 if (skip < fa.frameCount) {
189 println(fa.addresses + skip, fa.frames + skip, fa.frameCount - skip);
193 virtual ~SymbolizePrinter() { }
196 // Skip file and line information
197 NO_FILE_AND_LINE = 1 << 0,
199 // As terse as it gets: function name if found, address otherwise
202 // Always colorize output (ANSI escape code)
205 // Colorize output only if output is printed to a TTY (ANSI escape code)
206 COLOR_IF_TTY = 1 << 3,
209 enum Color { DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, WHITE, PURPLE };
213 explicit SymbolizePrinter(int options, bool isTty = false)
222 void printTerse(uintptr_t address, const SymbolizedFrame& frame);
223 virtual void doPrint(StringPiece sp) = 0;
227 * Print a list of symbolized addresses to a stream.
228 * Not reentrant. Do not use from signal handling code.
230 class OStreamSymbolizePrinter : public SymbolizePrinter {
232 explicit OStreamSymbolizePrinter(std::ostream& out, int options=0);
234 void doPrint(StringPiece sp) override;
239 * Print a list of symbolized addresses to a file descriptor.
240 * Ignores errors. Async-signal-safe.
242 class FDSymbolizePrinter : public SymbolizePrinter {
244 explicit FDSymbolizePrinter(int fd, int options=0,
245 size_t bufferSize=0);
246 ~FDSymbolizePrinter();
249 void doPrint(StringPiece sp) override;
252 std::unique_ptr<IOBuf> buffer_;
256 * Print a list of symbolized addresses to a FILE*.
257 * Ignores errors. Not reentrant. Do not use from signal handling code.
259 class FILESymbolizePrinter : public SymbolizePrinter {
261 explicit FILESymbolizePrinter(FILE* file, int options=0);
263 void doPrint(StringPiece sp) override;
268 * Print a list of symbolized addresses to a std::string.
269 * Not reentrant. Do not use from signal handling code.
271 class StringSymbolizePrinter : public SymbolizePrinter {
273 explicit StringSymbolizePrinter(int options=0) : SymbolizePrinter(options) { }
275 std::string str() const { return buf_.toStdString(); }
276 const fbstring& fbstr() const { return buf_; }
277 fbstring moveFbString() { return std::move(buf_); }
280 void doPrint(StringPiece sp) override;
284 } // namespace symbolizer
287 #endif /* FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_ */