2 * Copyright 2017 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,
46 Dwarf::LocationInfoMode mode);
48 void clear() { *this = SymbolizedFrame(); }
51 const char* name = nullptr;
52 Dwarf::LocationInfo location;
55 * Demangle the name and return it. Not async-signal-safe; allocates memory.
57 fbstring demangledName() const {
58 return name ? demangle(name) : fbstring();
62 std::shared_ptr<ElfFile> file_;
69 size_t frameCount = 0;
70 uintptr_t addresses[N];
71 SymbolizedFrame frames[N];
75 * Get stack trace into a given FrameArray, return true on success (and
76 * set frameCount to the actual frame count, which may be > N) and false
81 bool fixFrameArray(FrameArray<N>& fa, ssize_t n) {
84 for (size_t i = 0; i < fa.frameCount; ++i) {
85 fa.frames[i].found = false;
95 // Always inline these functions; they don't do much, and unittests rely
96 // on them never showing up in a stack trace.
98 FOLLY_ALWAYS_INLINE bool getStackTrace(FrameArray<N>& fa);
101 inline bool getStackTrace(FrameArray<N>& fa) {
102 return detail::fixFrameArray(fa, getStackTrace(fa.addresses, N));
105 FOLLY_ALWAYS_INLINE bool getStackTraceSafe(FrameArray<N>& fa);
108 inline bool getStackTraceSafe(FrameArray<N>& fa) {
109 return detail::fixFrameArray(fa, getStackTraceSafe(fa.addresses, N));
114 static constexpr Dwarf::LocationInfoMode kDefaultLocationInfoMode =
115 Dwarf::LocationInfoMode::FAST;
117 explicit Symbolizer(Dwarf::LocationInfoMode mode = kDefaultLocationInfoMode)
118 : Symbolizer(nullptr, mode) {}
120 explicit Symbolizer(ElfCacheBase* cache,
121 Dwarf::LocationInfoMode mode = kDefaultLocationInfoMode);
124 * Symbolize given addresses.
126 void symbolize(const uintptr_t* addresses,
127 SymbolizedFrame* frames,
131 void symbolize(FrameArray<N>& fa) {
132 symbolize(fa.addresses, fa.frames, fa.frameCount);
136 * Shortcut to symbolize one address.
138 bool symbolize(uintptr_t address, SymbolizedFrame& frame) {
139 symbolize(&address, &frame, 1);
144 ElfCacheBase* const cache_;
145 const Dwarf::LocationInfoMode mode_;
149 * Format one address in the way it's usually printed by SymbolizePrinter.
152 class AddressFormatter {
157 * Format the address. Returns an internal buffer.
159 StringPiece format(uintptr_t address);
162 static constexpr char bufTemplate[] = " @ 0000000000000000";
163 char buf_[sizeof(bufTemplate)];
167 * Print a list of symbolized addresses. Base class.
169 class SymbolizePrinter {
172 * Print one address, no ending newline.
174 void print(uintptr_t address, const SymbolizedFrame& frame);
177 * Print one address with ending newline.
179 void println(uintptr_t address, const SymbolizedFrame& frame);
182 * Print multiple addresses on separate lines.
184 void println(const uintptr_t* addresses,
185 const SymbolizedFrame* frames,
189 * Print a string, no endling newline.
191 void print(StringPiece sp) { doPrint(sp); }
194 * Print multiple addresses on separate lines, skipping the first
198 void println(const FrameArray<N>& fa, size_t skip=0) {
199 if (skip < fa.frameCount) {
200 println(fa.addresses + skip, fa.frames + skip, fa.frameCount - skip);
204 virtual ~SymbolizePrinter() { }
207 // Skip file and line information
208 NO_FILE_AND_LINE = 1 << 0,
210 // As terse as it gets: function name if found, address otherwise
213 // Always colorize output (ANSI escape code)
216 // Colorize output only if output is printed to a TTY (ANSI escape code)
217 COLOR_IF_TTY = 1 << 3,
219 // Skip frame address information
220 NO_FRAME_ADDRESS = 1 << 4,
223 // NOTE: enum values used as indexes in kColorMap.
224 enum Color { DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, WHITE, PURPLE, NUM };
228 explicit SymbolizePrinter(int options, bool isTty = false)
237 void printTerse(uintptr_t address, const SymbolizedFrame& frame);
238 virtual void doPrint(StringPiece sp) = 0;
240 static constexpr std::array<const char*, Color::NUM> kColorMap = {{
253 * Print a list of symbolized addresses to a stream.
254 * Not reentrant. Do not use from signal handling code.
256 class OStreamSymbolizePrinter : public SymbolizePrinter {
258 explicit OStreamSymbolizePrinter(std::ostream& out, int options=0);
260 void doPrint(StringPiece sp) override;
265 * Print a list of symbolized addresses to a file descriptor.
266 * Ignores errors. Async-signal-safe.
268 class FDSymbolizePrinter : public SymbolizePrinter {
270 explicit FDSymbolizePrinter(int fd, int options=0,
271 size_t bufferSize=0);
272 ~FDSymbolizePrinter() override;
275 void doPrint(StringPiece sp) override;
278 std::unique_ptr<IOBuf> buffer_;
282 * Print a list of symbolized addresses to a FILE*.
283 * Ignores errors. Not reentrant. Do not use from signal handling code.
285 class FILESymbolizePrinter : public SymbolizePrinter {
287 explicit FILESymbolizePrinter(FILE* file, int options=0);
289 void doPrint(StringPiece sp) override;
290 FILE* const file_ = nullptr;
294 * Print a list of symbolized addresses to a std::string.
295 * Not reentrant. Do not use from signal handling code.
297 class StringSymbolizePrinter : public SymbolizePrinter {
299 explicit StringSymbolizePrinter(int options=0) : SymbolizePrinter(options) { }
301 std::string str() const { return buf_.toStdString(); }
302 const fbstring& fbstr() const { return buf_; }
303 fbstring moveFbString() { return std::move(buf_); }
306 void doPrint(StringPiece sp) override;
311 * Use this class to print a stack trace from a signal handler, or other place
312 * where you shouldn't allocate memory on the heap, and fsync()ing your file
313 * descriptor is more important than performance.
315 * Make sure to create one of these on startup, not in the signal handler, as
316 * the constructo allocates on the heap, whereas the other methods don't. Best
317 * practice is to just leak this object, rather than worry about destruction
320 * These methods aren't thread safe, so if you could have signals on multiple
321 * threads at the same time, you need to do your own locking to ensure you don't
322 * call these methods from multiple threads. They are signal safe, however.
324 class StackTracePrinter {
326 static constexpr size_t kDefaultMinSignalSafeElfCacheSize = 500;
328 explicit StackTracePrinter(
329 size_t minSignalSafeElfCacheSize = kDefaultMinSignalSafeElfCacheSize,
330 int fd = STDERR_FILENO);
333 * Only allocates on the stack and is signal-safe but not thread-safe. Don't
334 * call printStackTrace() on the same StackTracePrinter object from multiple
335 * threads at the same time.
337 FOLLY_NOINLINE void printStackTrace(bool symbolize);
339 void print(StringPiece sp) {
343 // Flush printer_, also fsync, in case we're about to crash again...
347 static constexpr size_t kMaxStackTraceDepth = 100;
350 SignalSafeElfCache elfCache_;
351 FDSymbolizePrinter printer_;
352 std::unique_ptr<FrameArray<kMaxStackTraceDepth>> addresses_;
355 } // namespace symbolizer