proxygen
Symbolizer.h
Go to the documentation of this file.
1 /*
2  * Copyright 2012-present 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 #pragma once
18 
19 #include <array>
20 #include <cstdint>
21 #include <memory>
22 #include <string>
23 
24 #include <folly/FBString.h>
25 #include <folly/Optional.h>
26 #include <folly/Range.h>
27 #include <folly/String.h>
28 #include <folly/Synchronized.h>
34 #include <folly/io/IOBuf.h>
35 
36 namespace folly {
37 namespace symbolizer {
38 
39 class Symbolizer;
40 
46 
47  void set(
48  const std::shared_ptr<ElfFile>& file,
49  uintptr_t address,
51 
52  void clear() {
53  *this = SymbolizedFrame();
54  }
55 
56  bool found = false;
57  const char* name = nullptr;
59 
64  return name ? demangle(name) : fbstring();
65  }
66 
67  private:
68  std::shared_ptr<ElfFile> file_;
69 };
70 
71 template <size_t N>
72 struct FrameArray {
74 
75  size_t frameCount = 0;
76  uintptr_t addresses[N];
77  SymbolizedFrame frames[N];
78 };
79 
85 namespace detail {
86 template <size_t N>
87 bool fixFrameArray(FrameArray<N>& fa, ssize_t n) {
88  if (n != -1) {
89  fa.frameCount = n;
90  for (size_t i = 0; i < fa.frameCount; ++i) {
91  fa.frames[i].found = false;
92  }
93  return true;
94  } else {
95  fa.frameCount = 0;
96  return false;
97  }
98 }
99 } // namespace detail
100 
101 // Always inline these functions; they don't do much, and unittests rely
102 // on them never showing up in a stack trace.
103 template <size_t N>
105 
106 template <size_t N>
107 inline bool getStackTrace(FrameArray<N>& fa) {
108  return detail::fixFrameArray(fa, getStackTrace(fa.addresses, N));
109 }
110 template <size_t N>
112 
113 template <size_t N>
116 }
117 
118 class Symbolizer {
119  public:
120  static constexpr Dwarf::LocationInfoMode kDefaultLocationInfoMode =
122 
123  explicit Symbolizer(Dwarf::LocationInfoMode mode = kDefaultLocationInfoMode)
124  : Symbolizer(nullptr, mode) {}
125 
126  explicit Symbolizer(
127  ElfCacheBase* cache,
128  Dwarf::LocationInfoMode mode = kDefaultLocationInfoMode,
129  size_t symbolCacheSize = 0);
133  void symbolize(
134  const uintptr_t* addresses,
135  SymbolizedFrame* frames,
136  size_t frameCount);
137 
138  template <size_t N>
140  symbolize(fa.addresses, fa.frames, fa.frameCount);
141  }
142 
146  bool symbolize(uintptr_t address, SymbolizedFrame& frame) {
147  symbolize(&address, &frame, 1);
148  return frame.found;
149  }
150 
151  private:
154 
157 };
158 
164  public:
166 
170  StringPiece format(uintptr_t address);
171 
172  private:
173  static constexpr char bufTemplate[] = " @ 0000000000000000";
174  char buf_[sizeof(bufTemplate)];
175 };
176 
181  public:
185  void print(uintptr_t address, const SymbolizedFrame& frame);
186 
190  void println(uintptr_t address, const SymbolizedFrame& frame);
191 
195  void println(
196  const uintptr_t* addresses,
197  const SymbolizedFrame* frames,
198  size_t frameCount);
199 
203  void print(StringPiece sp) {
204  doPrint(sp);
205  }
206 
211  template <size_t N>
212  void println(const FrameArray<N>& fa, size_t skip = 0) {
213  if (skip < fa.frameCount) {
214  println(fa.addresses + skip, fa.frames + skip, fa.frameCount - skip);
215  }
216  }
217 
222  virtual void flush() {}
223 
224  virtual ~SymbolizePrinter() {}
225 
226  enum Options {
227  // Skip file and line information
228  NO_FILE_AND_LINE = 1 << 0,
229 
230  // As terse as it gets: function name if found, address otherwise
231  TERSE = 1 << 1,
232 
233  // Always colorize output (ANSI escape code)
234  COLOR = 1 << 2,
235 
236  // Colorize output only if output is printed to a TTY (ANSI escape code)
237  COLOR_IF_TTY = 1 << 3,
238 
239  // Skip frame address information
240  NO_FRAME_ADDRESS = 1 << 4,
241  };
242 
243  // NOTE: enum values used as indexes in kColorMap.
244  enum Color { DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, WHITE, PURPLE, NUM };
245  void color(Color c);
246 
247  protected:
248  explicit SymbolizePrinter(int options, bool isTty = false)
249  : options_(options), isTty_(isTty) {}
250 
251  const int options_;
252  const bool isTty_;
253 
254  private:
255  void printTerse(uintptr_t address, const SymbolizedFrame& frame);
256  virtual void doPrint(StringPiece sp) = 0;
257 
258  static constexpr std::array<const char*, Color::NUM> kColorMap = {{
259  "\x1B[0m",
260  "\x1B[31m",
261  "\x1B[32m",
262  "\x1B[33m",
263  "\x1B[34m",
264  "\x1B[36m",
265  "\x1B[37m",
266  "\x1B[35m",
267  }};
268 };
269 
275  public:
276  explicit OStreamSymbolizePrinter(std::ostream& out, int options = 0);
277 
278  private:
279  void doPrint(StringPiece sp) override;
280  std::ostream& out_;
281 };
282 
288  public:
289  explicit FDSymbolizePrinter(int fd, int options = 0, size_t bufferSize = 0);
290  ~FDSymbolizePrinter() override;
291  virtual void flush() override;
292 
293  private:
294  void doPrint(StringPiece sp) override;
295 
296  const int fd_;
297  std::unique_ptr<IOBuf> buffer_;
298 };
299 
305  public:
306  explicit FILESymbolizePrinter(FILE* file, int options = 0);
307 
308  private:
309  void doPrint(StringPiece sp) override;
310  FILE* const file_ = nullptr;
311 };
312 
318  public:
319  explicit StringSymbolizePrinter(int options = 0)
320  : SymbolizePrinter(options) {}
321 
322  std::string str() const {
323  return buf_.toStdString();
324  }
325  const fbstring& fbstr() const {
326  return buf_;
327  }
329  return std::move(buf_);
330  }
331 
332  private:
333  void doPrint(StringPiece sp) override;
335 };
336 
352  public:
353  static constexpr size_t kDefaultMinSignalSafeElfCacheSize = 500;
354 
355  explicit SafeStackTracePrinter(
356  size_t minSignalSafeElfCacheSize = kDefaultMinSignalSafeElfCacheSize,
357  int fd = STDERR_FILENO);
358 
360 
369  FOLLY_NOINLINE void printStackTrace(bool symbolize);
370 
371  void print(StringPiece sp) {
372  printer_.print(sp);
373  }
374 
375  // Flush printer_, also fsync, in case we're about to crash again...
376  void flush();
377 
378  protected:
379  virtual void printSymbolizedStackTrace();
380 
381  private:
382  static constexpr size_t kMaxStackTraceDepth = 100;
383 
384  int fd_;
387  std::unique_ptr<FrameArray<kMaxStackTraceDepth>> addresses_;
388 };
389 
398  public:
399  static constexpr size_t kDefaultSymbolCacheSize = 10000;
400 
401  explicit FastStackTracePrinter(
402  std::unique_ptr<SymbolizePrinter> printer,
403  size_t elfCacheSize = 0, // 0 means "use the default elf cache instance."
404  size_t symbolCacheSize = kDefaultSymbolCacheSize);
405 
407 
412  FOLLY_NOINLINE void printStackTrace(bool symbolize);
413 
414  void flush();
415 
416  private:
417  static constexpr size_t kMaxStackTraceDepth = 100;
418 
419  const std::unique_ptr<ElfCache> elfCache_;
420  const std::unique_ptr<SymbolizePrinter> printer_;
422 };
423 
435  protected:
436  void printSymbolizedStackTrace() override;
437  const long pageSizeUnchecked_ = sysconf(_SC_PAGESIZE);
438 };
439 
440 } // namespace symbolizer
441 } // namespace folly
const fbstring & fbstr() const
Definition: Symbolizer.h:325
bool symbolize(uintptr_t address, SymbolizedFrame &frame)
Definition: Symbolizer.h:146
const std::unique_ptr< SymbolizePrinter > printer_
Definition: Symbolizer.h:420
#define FOLLY_ALWAYS_INLINE
Definition: CPortability.h:151
ssize_t getStackTraceSafe(uintptr_t *addresses, size_t maxAddresses)
Definition: StackTrace.cpp:53
Dwarf::LocationInfo location
Definition: Symbolizer.h:58
const std::unique_ptr< ElfCache > elfCache_
Definition: Symbolizer.h:419
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
Symbolizer(Dwarf::LocationInfoMode mode=kDefaultLocationInfoMode)
Definition: Symbolizer.h:123
const Dwarf::LocationInfoMode mode_
Definition: Symbolizer.h:153
std::unique_ptr< IOBuf > buffer_
Definition: Symbolizer.h:297
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
detail::Skip skip(size_t count)
Definition: Base-inl.h:2598
#define nullptr
Definition: http_parser.c:41
void println(const FrameArray< N > &fa, size_t skip=0)
Definition: Symbolizer.h:212
folly::Optional< PskKeyExchangeMode > mode
#define FOLLY_NOINLINE
Definition: CPortability.h:142
std::shared_ptr< ElfFile > file_
Definition: Symbolizer.h:68
ssize_t getStackTrace(uintptr_t *addresses, size_t maxAddresses)
Definition: StackTrace.cpp:25
const int kMaxStackTraceDepth
Definition: gtest.h:147
auto println
Definition: set_done_2.cpp:41
ElfCacheBase *const cache_
Definition: Symbolizer.h:152
SymbolizePrinter(int options, bool isTty=false)
Definition: Symbolizer.h:248
SymbolizedFrame frames[N]
Definition: Symbolizer.h:77
bool fixFrameArray(FrameArray< N > &fa, ssize_t n)
Definition: Symbolizer.h:87
fbstring demangledName() const
Definition: Symbolizer.h:63
folly::Optional< Synchronized< SymbolCache > > symbolCache_
Definition: Symbolizer.h:156
const char * string
Definition: Conv.cpp:212
Formatter< false, Args... > format(StringPiece fmt, Args &&...args)
Definition: Format.h:271
std::unique_ptr< FrameArray< kMaxStackTraceDepth > > addresses_
Definition: Symbolizer.h:387
basic_fbstring< char > fbstring
Definition: FBString.h:2904
char c
GMockOutputTest ExpectedCall FILE
void symbolize(FrameArray< N > &fa)
Definition: Symbolizer.h:139
fbstring demangle(const char *name)
Definition: Demangle.cpp:111