2 * Copyright 2016 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.
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 {
44 void set(const std::shared_ptr<ElfFile>& file, uintptr_t address);
45 void clear() { *this = SymbolizedFrame(); }
48 const char* name = nullptr;
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_;
65 size_t 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* const cache_ = nullptr;
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 a string, no endling newline.
179 void print(StringPiece sp) { doPrint(sp); }
182 * Print multiple addresses on separate lines, skipping the first
186 void println(const FrameArray<N>& fa, size_t skip=0) {
187 if (skip < fa.frameCount) {
188 println(fa.addresses + skip, fa.frames + skip, fa.frameCount - skip);
192 virtual ~SymbolizePrinter() { }
195 // Skip file and line information
196 NO_FILE_AND_LINE = 1 << 0,
198 // As terse as it gets: function name if found, address otherwise
201 // Always colorize output (ANSI escape code)
204 // Colorize output only if output is printed to a TTY (ANSI escape code)
205 COLOR_IF_TTY = 1 << 3,
208 // NOTE: enum values used as indexes in kColorMap.
209 enum Color { DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, WHITE, PURPLE, NUM };
213 explicit SymbolizePrinter(int options, bool isTty = false)
222 void printTerse(uintptr_t address, const SymbolizedFrame& frame);
223 virtual void doPrint(StringPiece sp) = 0;
225 static constexpr std::array<const char*, Color::NUM> kColorMap = {{
238 * Print a list of symbolized addresses to a stream.
239 * Not reentrant. Do not use from signal handling code.
241 class OStreamSymbolizePrinter : public SymbolizePrinter {
243 explicit OStreamSymbolizePrinter(std::ostream& out, int options=0);
245 void doPrint(StringPiece sp) override;
250 * Print a list of symbolized addresses to a file descriptor.
251 * Ignores errors. Async-signal-safe.
253 class FDSymbolizePrinter : public SymbolizePrinter {
255 explicit FDSymbolizePrinter(int fd, int options=0,
256 size_t bufferSize=0);
257 ~FDSymbolizePrinter();
260 void doPrint(StringPiece sp) override;
263 std::unique_ptr<IOBuf> buffer_;
267 * Print a list of symbolized addresses to a FILE*.
268 * Ignores errors. Not reentrant. Do not use from signal handling code.
270 class FILESymbolizePrinter : public SymbolizePrinter {
272 explicit FILESymbolizePrinter(FILE* file, int options=0);
274 void doPrint(StringPiece sp) override;
275 FILE* const file_ = nullptr;
279 * Print a list of symbolized addresses to a std::string.
280 * Not reentrant. Do not use from signal handling code.
282 class StringSymbolizePrinter : public SymbolizePrinter {
284 explicit StringSymbolizePrinter(int options=0) : SymbolizePrinter(options) { }
286 std::string str() const { return buf_.toStdString(); }
287 const fbstring& fbstr() const { return buf_; }
288 fbstring moveFbString() { return std::move(buf_); }
291 void doPrint(StringPiece sp) override;
295 } // namespace symbolizer