xref: /freebsd/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_trace.h (revision 257e70f1d5ee61037c8c59b116538d3b6b1427a2)
1 //===-- tsan_trace.h --------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is a part of ThreadSanitizer (TSan), a race detector.
10 //
11 //===----------------------------------------------------------------------===//
12 #ifndef TSAN_TRACE_H
13 #define TSAN_TRACE_H
14 
15 #include "tsan_defs.h"
16 #include "tsan_ilist.h"
17 #include "tsan_mutexset.h"
18 #include "tsan_stack_trace.h"
19 
20 namespace __tsan {
21 
22 enum class EventType : u64 {
23   kAccessExt,
24   kAccessRange,
25   kLock,
26   kRLock,
27   kUnlock,
28   kTime,
29 };
30 
31 // "Base" type for all events for type dispatch.
32 struct Event {
33   // We use variable-length type encoding to give more bits to some event
34   // types that need them. If is_access is set, this is EventAccess.
35   // Otherwise, if is_func is set, this is EventFunc.
36   // Otherwise type denotes the type.
37   u64 is_access : 1;
38   u64 is_func : 1;
39   EventType type : 3;
40   u64 _ : 59;
41 };
42 static_assert(sizeof(Event) == 8, "bad Event size");
43 
44 // Nop event used as padding and does not affect state during replay.
45 static constexpr Event NopEvent = {1, 0, EventType::kAccessExt, 0};
46 
47 // Compressed memory access can represent only some events with PCs
48 // close enough to each other. Otherwise we fall back to EventAccessExt.
49 struct EventAccess {
50   static constexpr uptr kPCBits = 15;
51   static_assert(kPCBits + kCompressedAddrBits + 5 == 64,
52                 "unused bits in EventAccess");
53 
54   u64 is_access : 1;  // = 1
55   u64 is_read : 1;
56   u64 is_atomic : 1;
57   u64 size_log : 2;
58   u64 pc_delta : kPCBits;  // signed delta from the previous memory access PC
59   u64 addr : kCompressedAddrBits;
60 };
61 static_assert(sizeof(EventAccess) == 8, "bad EventAccess size");
62 
63 // Function entry (pc != 0) or exit (pc == 0).
64 struct EventFunc {
65   u64 is_access : 1;  // = 0
66   u64 is_func : 1;    // = 1
67   u64 pc : 62;
68 };
69 static_assert(sizeof(EventFunc) == 8, "bad EventFunc size");
70 
71 // Extended memory access with full PC.
72 struct EventAccessExt {
73   // Note: precisely specifying the unused parts of the bitfield is critical for
74   // performance. If we don't specify them, compiler will generate code to load
75   // the old value and shuffle it to extract the unused bits to apply to the new
76   // value. If we specify the unused part and store 0 in there, all that
77   // unnecessary code goes away (store of the 0 const is combined with other
78   // constant parts).
79   static constexpr uptr kUnusedBits = 11;
80   static_assert(kCompressedAddrBits + kUnusedBits + 9 == 64,
81                 "unused bits in EventAccessExt");
82 
83   u64 is_access : 1;   // = 0
84   u64 is_func : 1;     // = 0
85   EventType type : 3;  // = EventType::kAccessExt
86   u64 is_read : 1;
87   u64 is_atomic : 1;
88   u64 size_log : 2;
89   u64 _ : kUnusedBits;
90   u64 addr : kCompressedAddrBits;
91   u64 pc;
92 };
93 static_assert(sizeof(EventAccessExt) == 16, "bad EventAccessExt size");
94 
95 // Access to a memory range.
96 struct EventAccessRange {
97   static constexpr uptr kSizeLoBits = 13;
98   static_assert(kCompressedAddrBits + kSizeLoBits + 7 == 64,
99                 "unused bits in EventAccessRange");
100 
101   u64 is_access : 1;   // = 0
102   u64 is_func : 1;     // = 0
103   EventType type : 3;  // = EventType::kAccessRange
104   u64 is_read : 1;
105   u64 is_free : 1;
106   u64 size_lo : kSizeLoBits;
107   u64 pc : kCompressedAddrBits;
108   u64 addr : kCompressedAddrBits;
109   u64 size_hi : 64 - kCompressedAddrBits;
110 };
111 static_assert(sizeof(EventAccessRange) == 16, "bad EventAccessRange size");
112 
113 // Mutex lock.
114 struct EventLock {
115   static constexpr uptr kStackIDLoBits = 15;
116   static constexpr uptr kStackIDHiBits =
117       sizeof(StackID) * kByteBits - kStackIDLoBits;
118   static constexpr uptr kUnusedBits = 3;
119   static_assert(kCompressedAddrBits + kStackIDLoBits + 5 == 64,
120                 "unused bits in EventLock");
121   static_assert(kCompressedAddrBits + kStackIDHiBits + kUnusedBits == 64,
122                 "unused bits in EventLock");
123 
124   u64 is_access : 1;   // = 0
125   u64 is_func : 1;     // = 0
126   EventType type : 3;  // = EventType::kLock or EventType::kRLock
127   u64 pc : kCompressedAddrBits;
128   u64 stack_lo : kStackIDLoBits;
129   u64 stack_hi : sizeof(StackID) * kByteBits - kStackIDLoBits;
130   u64 _ : kUnusedBits;
131   u64 addr : kCompressedAddrBits;
132 };
133 static_assert(sizeof(EventLock) == 16, "bad EventLock size");
134 
135 // Mutex unlock.
136 struct EventUnlock {
137   static constexpr uptr kUnusedBits = 15;
138   static_assert(kCompressedAddrBits + kUnusedBits + 5 == 64,
139                 "unused bits in EventUnlock");
140 
141   u64 is_access : 1;   // = 0
142   u64 is_func : 1;     // = 0
143   EventType type : 3;  // = EventType::kUnlock
144   u64 _ : kUnusedBits;
145   u64 addr : kCompressedAddrBits;
146 };
147 static_assert(sizeof(EventUnlock) == 8, "bad EventUnlock size");
148 
149 // Time change event.
150 struct EventTime {
151   static constexpr uptr kUnusedBits = 37;
152   static_assert(kUnusedBits + sizeof(Sid) * kByteBits + kEpochBits + 5 == 64,
153                 "unused bits in EventTime");
154 
155   u64 is_access : 1;   // = 0
156   u64 is_func : 1;     // = 0
157   EventType type : 3;  // = EventType::kTime
158   u64 sid : sizeof(Sid) * kByteBits;
159   u64 epoch : kEpochBits;
160   u64 _ : kUnusedBits;
161 };
162 static_assert(sizeof(EventTime) == 8, "bad EventTime size");
163 
164 struct Trace;
165 
166 struct TraceHeader {
167   Trace* trace = nullptr;  // back-pointer to Trace containing this part
168   INode trace_parts;       // in Trace::parts
169   INode global;            // in Contex::trace_part_recycle
170 };
171 
172 struct TracePart : TraceHeader {
173   // There are a lot of goroutines in Go, so we use smaller parts.
174   static constexpr uptr kByteSize = (SANITIZER_GO ? 128 : 256) << 10;
175   static constexpr uptr kSize =
176       (kByteSize - sizeof(TraceHeader)) / sizeof(Event);
177   // TraceAcquire does a fast event pointer overflow check by comparing
178   // pointer into TracePart::events with kAlignment mask. Since TracePart's
179   // are allocated page-aligned, this check detects end of the array
180   // (it also have false positives in the middle that are filtered separately).
181   // This also requires events to be the last field.
182   static constexpr uptr kAlignment = 0xff0;
183   Event events[kSize];
184 
185   TracePart() {}
186 };
187 static_assert(sizeof(TracePart) == TracePart::kByteSize, "bad TracePart size");
188 
189 struct Trace {
190   Mutex mtx;
191   IList<TraceHeader, &TraceHeader::trace_parts, TracePart> parts;
192   // First node non-queued into ctx->trace_part_recycle.
193   TracePart* local_head;
194   // Final position in the last part for finished threads.
195   Event* final_pos = nullptr;
196   // Number of trace parts allocated on behalf of this trace specifically.
197   // Total number of parts in this trace can be larger if we retake some
198   // parts from other traces.
199   uptr parts_allocated = 0;
200 
201   Trace() : mtx(MutexTypeTrace) {}
202 
203   // We need at least 3 parts per thread, because we want to keep at last
204   // 2 parts per thread that are not queued into ctx->trace_part_recycle
205   // (the current one being filled and one full part that ensures that
206   // we always have at least one part worth of previous memory accesses).
207   static constexpr uptr kMinParts = 3;
208 
209   static constexpr uptr kFinishedThreadLo = 16;
210   static constexpr uptr kFinishedThreadHi = 64;
211 };
212 
213 }  // namespace __tsan
214 
215 #endif  // TSAN_TRACE_H
216