YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/util/stack_trace.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) YugaByte, Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4
// in compliance with the License.  You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software distributed under the License
9
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
10
// or implied.  See the License for the specific language governing permissions and limitations
11
// under the License.
12
//
13
14
#ifndef YB_UTIL_STACK_TRACE_H
15
#define YB_UTIL_STACK_TRACE_H
16
17
#include <pthread.h>
18
19
#include "yb/util/enums.h"
20
#include "yb/util/math_util.h"
21
#include "yb/util/slice.h"
22
23
namespace yb {
24
25
#if defined(__linux__)
26
typedef int64_t ThreadIdForStack;
27
#else
28
typedef pthread_t ThreadIdForStack;
29
#endif
30
31
enum class StackTraceLineFormat {
32
  SHORT,
33
  CLION_CLICKABLE,
34
  SYMBOL_ONLY,
35
  DEFAULT = SHORT
36
};
37
38
// Active - thread is performing execution.
39
// Waiting - thread is waiting on mutex.
40
// Idle - thread is waiting on condition or epoll.
41
YB_DEFINE_ENUM(StackTraceGroup, (kActive)(kWaiting)(kIdle));
42
43
// Efficient class for collecting and later stringifying a stack trace.
44
//
45
// Requires external synchronization.
46
class StackTrace {
47
 public:
48
  // It is OK that frames_ is uninitialized.
49
17.5M
  StackTrace() : num_frames_(0) {
50
17.5M
  }
51
52
590M
  void Reset() {
53
590M
    num_frames_ = 0;
54
590M
  }
55
56
  // Collect and store the current stack trace. Skips the top 'skip_frames' frames
57
  // from the stack. For example, a value of '1' will skip the 'Collect()' function
58
  // call itself.
59
  //
60
  // This function is technically not async-safe. However, according to
61
  // http://lists.nongnu.org/archive/html/libunwind-devel/2011-08/msg00054.html it is "largely
62
  // async safe" and it would only deadlock in the case that you call it while a dynamic library
63
  // load is in progress. We assume that dynamic library loads would almost always be completed
64
  // very early in the application lifecycle, so for now, this is considered "async safe" until
65
  // it proves to be a problem.
66
  void Collect(int skip_frames = 1);
67
68
  enum Flags {
69
    // Do not fix up the addresses on the stack to try to point to the 'call'
70
    // instructions instead of the return address. This is necessary when dumping
71
    // addresses to be interpreted by 'pprof', which does this fix-up itself.
72
    NO_FIX_CALLER_ADDRESSES = 1
73
  };
74
75
  // Stringify the trace into the given buffer.
76
  // The resulting output is hex addresses suitable for passing into 'addr2line'
77
  // later.
78
  void StringifyToHex(char* buf, size_t size, int flags = 0) const;
79
80
  // Same as above, but returning a std::string.
81
  // This is not async-safe.
82
  std::string ToHexString(int flags = 0) const;
83
84
  // Return a string with a symbolized backtrace in a format suitable for
85
  // printing to a log file.
86
  // This is not async-safe.
87
  // If group is specified it is filled with value corresponding to this stack trace.
88
  std::string Symbolize(
89
      StackTraceLineFormat source_file_path_format = StackTraceLineFormat::DEFAULT,
90
      StackTraceGroup* group = nullptr) const;
91
92
  // Return a string with a hex-only backtrace in the format typically used in
93
  // log files. Similar to the format given by Symbolize(), but symbols are not
94
  // resolved (only the hex addresses are given).
95
  std::string ToLogFormatHexString() const;
96
97
  uint64_t HashCode() const;
98
99
0
  explicit operator bool() const {
100
0
    return num_frames_ != 0;
101
0
  }
102
103
0
  bool operator!() const {
104
0
    return num_frames_ == 0;
105
0
  }
106
107
12
  int compare(const StackTrace& rhs) const {
108
12
    return as_slice().compare(rhs.as_slice());
109
12
  }
110
111
24
  Slice as_slice() const {
112
24
    return Slice(pointer_cast<const char*>(frames_),
113
24
                 pointer_cast<const char*>(frames_ + num_frames_));
114
24
  }
115
116
 private:
117
  enum {
118
    // The maximum number of stack frames to collect.
119
    kMaxFrames = 16,
120
121
    // The max number of characters any frame requires in string form.
122
    kHexEntryLength = 16
123
  };
124
125
  int num_frames_;
126
  void* frames_[kMaxFrames];
127
128
0
  friend inline bool operator==(const StackTrace& lhs, const StackTrace& rhs) {
129
0
    return lhs.num_frames_ == rhs.num_frames_ && lhs.as_slice() == rhs.as_slice();
130
0
  }
131
132
0
  friend inline bool operator!=(const StackTrace& lhs, const StackTrace& rhs) {
133
0
    return !(lhs == rhs);
134
0
  }
135
136
0
  friend inline bool operator<(const StackTrace& lhs, const StackTrace& rhs) {
137
0
    return lhs.compare(rhs) < 0;
138
0
  }
139
};
140
141
Result<StackTrace> ThreadStack(ThreadIdForStack tid);
142
// tids should be ordered
143
std::vector<Result<StackTrace>> ThreadStacks(const std::vector<ThreadIdForStack>& tids);
144
145
// Set which POSIX signal number should be used internally for triggering
146
// stack traces. If the specified signal handler is already in use, this
147
// returns an error, and stack traces will be disabled.
148
CHECKED_STATUS SetStackTraceSignal(int signum);
149
150
}  // namespace yb
151
152
#endif  // YB_UTIL_STACK_TRACE_H