valgrind_requests/drd.rs
1// Copyright (C) 2006-2020 Bart Van Assche <bvanassche@acm.org>.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions
6// are met:
7//
8// 1. Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10//
11// 2. The origin of this software must not be misrepresented; you must
12// not claim that you wrote the original software. If you use this
13// software in a product, an acknowledgment in the product
14// documentation would be appreciated but is not required.
15//
16// 3. Altered source versions must be plainly marked as such, and must
17// not be misrepresented as being the original software.
18//
19// 4. The name of the author may not be used to endorse or promote
20// products derived from this software without specific prior written
21// permission.
22//
23// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
24// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
27// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34//
35// ----------------------------------------------------------------
36//
37// We're using a lot of the original documentation from the `drd.h` header file with some
38// small adjustments, so above is the original license from `drd.h` file.
39//
40// This file is distributed under the same License as the rest of `valgrind-requests`.
41//
42// ----------------------------------------------------------------
43//
44//! All public client requests from the `drd.h` header file
45//!
46//! The client requests which do nothing or are not implemented (as of valgrind version 3.22) are
47//! not available.
48//!
49//! See also [DRD Client
50//! Requests](https://valgrind.org/docs/manual/drd-manual.html#drd-manual.clientreqs)
51use core::ffi::CStr;
52
53use super::{
54 bindings, fatal_error, helgrind, valgrind_do_client_request_expr,
55 valgrind_do_client_request_stmt,
56};
57
58/// Obtain the thread ID assigned by Valgrind's core
59///
60/// Valgrind's thread ID's start at one and are recycled in case a thread stops.
61#[inline(always)]
62pub fn get_valgrind_threadid() -> usize {
63 do_client_request!(
64 "drd::get_valgrind_threadid",
65 0,
66 bindings::VR_DRDClientRequest::VR_DRD_GET_VALGRIND_THREAD_ID,
67 0,
68 0,
69 0,
70 0,
71 0
72 )
73}
74
75/// Obtain the thread ID assigned by DRD
76///
77/// These are the thread ID's reported by DRD in data race reports and in trace messages. DRD's
78/// thread ID's start at one and are never recycled.
79#[inline(always)]
80pub fn get_drd_threadid() -> usize {
81 do_client_request!(
82 "drd::get_drd_threadid",
83 0,
84 bindings::VR_DRDClientRequest::VR_DRD_GET_DRD_THREAD_ID,
85 0,
86 0,
87 0,
88 0,
89 0
90 )
91}
92
93/// Tell DRD not to complain about data races for the specified variable
94///
95/// Some applications contain intentional races. There exist e.g. applications where the same value
96/// is assigned to a shared variable from two different threads. It may be more convenient to
97/// suppress such races than to solve these. This client request allows one to suppress such races.
98#[inline(always)]
99pub fn ignore_var<T>(var: &T) {
100 do_client_request!(
101 "drd::ignore_var",
102 bindings::VR_DRDClientRequest::VR_DRD_START_SUPPRESSION,
103 core::ptr::from_ref::<T>(var) as usize,
104 core::mem::size_of::<T>(),
105 0,
106 0,
107 0
108 );
109}
110
111/// Tell DRD to no longer ignore data races for the specified variable that was suppressed via
112/// [`ignore_var`]
113#[inline(always)]
114pub fn stop_ignoring_var<T>(var: &T) {
115 do_client_request!(
116 "drd::stop_ignoring_var",
117 bindings::VR_DRDClientRequest::VR_DRD_FINISH_SUPPRESSION,
118 core::ptr::from_ref::<T>(var) as usize,
119 core::mem::size_of::<T>(),
120 0,
121 0,
122 0
123 );
124}
125
126/// Tell DRD to trace all memory accesses for the specified variable until the memory that was
127/// allocated for the variable is freed.
128///
129/// When DRD reports a data race on a specified variable, and it's not immediately clear which
130/// source code statements triggered the conflicting accesses, it can be very helpful to trace all
131/// activity on the offending memory location.
132#[inline(always)]
133pub fn trace_var<T>(var: &T) {
134 do_client_request!(
135 "drd::trace_var",
136 bindings::VR_DRDClientRequest::VR_DRD_START_TRACE_ADDR,
137 core::ptr::from_ref::<T>(var) as usize,
138 core::mem::size_of::<T>(),
139 0,
140 0,
141 0
142 );
143}
144
145/// Tell DRD to stop tracing memory accesses for the specified variable
146#[inline(always)]
147pub fn stop_tracing_var<T>(var: &T) {
148 do_client_request!(
149 "drd::stop_tracing_var",
150 bindings::VR_DRDClientRequest::VR_DRD_STOP_TRACE_ADDR,
151 core::ptr::from_ref::<T>(var) as usize,
152 core::mem::size_of::<T>(),
153 0,
154 0,
155 0
156 );
157}
158
159/// Create completely arbitrary happens-before edges between threads
160///
161/// See [`super::helgrind::annotate_happens_before`]
162#[inline(always)]
163pub fn annotate_happens_before(obj: *const ()) {
164 helgrind::annotate_happens_before(obj);
165}
166
167/// See [`super::helgrind::annotate_happens_before`]
168#[inline(always)]
169pub fn annotate_happens_after(obj: *const ()) {
170 helgrind::annotate_happens_after(obj);
171}
172
173/// Report that a lock has just been created at address `lock`
174///
175/// See [`super::helgrind::annotate_rwlock_create`]
176#[inline(always)]
177pub fn annotate_rwlock_create(lock: *const ()) {
178 helgrind::annotate_rwlock_create(lock);
179}
180
181/// Report that the lock at address `lock` is about to be destroyed
182///
183/// See [`super::helgrind::annotate_rwlock_create`]
184#[inline(always)]
185pub fn annotate_rwlock_destroy(lock: *const ()) {
186 helgrind::annotate_rwlock_destroy(lock);
187}
188
189/// Report that the lock at address `lock` has just been acquired
190///
191/// See also [`super::helgrind::annotate_rwlock_create`]
192#[inline(always)]
193pub fn annotate_rwlock_acquired(lock: *const (), is_writer_lock: bool) {
194 helgrind::annotate_rwlock_acquired(lock, is_writer_lock);
195}
196
197/// Report that the lock at address `lock` is about to be released
198///
199/// See also [`super::helgrind::annotate_rwlock_create`]
200#[inline(always)]
201pub fn annotate_rwlock_released(lock: *const (), is_writer_lock: bool) {
202 helgrind::annotate_rwlock_released(lock, is_writer_lock);
203}
204
205/// Tell DRD that a semaphore object is going to be initialized.
206#[inline(always)]
207pub fn annotate_sem_init_pre(sem: *const (), value: usize) {
208 do_client_request!(
209 "drd::annotate_sem_init_pre",
210 bindings::VR_DRDClientRequest::VR_DRD_ANNOTATE_SEM_INIT_PRE,
211 sem as usize,
212 value,
213 0,
214 0,
215 0
216 );
217}
218
219/// Tell DRD that a semaphore object has been destroyed.
220#[inline(always)]
221pub fn annotate_sem_destroy_post(sem: *const ()) {
222 do_client_request!(
223 "drd::annotate_sem_destroy_post",
224 bindings::VR_DRDClientRequest::VR_DRD_ANNOTATE_SEM_DESTROY_POST,
225 sem as usize,
226 0,
227 0,
228 0,
229 0
230 );
231}
232
233/// Tell DRD that a semaphore is going to be acquired.
234#[inline(always)]
235pub fn annotate_sem_wait_pre(sem: *const ()) {
236 do_client_request!(
237 "drd::annotate_sem_wait_pre",
238 bindings::VR_DRDClientRequest::VR_DRD_ANNOTATE_SEM_WAIT_PRE,
239 sem as usize,
240 0,
241 0,
242 0,
243 0
244 );
245}
246
247/// Tell DRD that a semaphore has been acquired.
248#[inline(always)]
249pub fn annotate_sem_wait_post(sem: *const ()) {
250 do_client_request!(
251 "drd::annotate_sem_wait_post",
252 bindings::VR_DRDClientRequest::VR_DRD_ANNOTATE_SEM_WAIT_POST,
253 sem as usize,
254 0,
255 0,
256 0,
257 0
258 );
259}
260
261/// Tell DRD that a semaphore is going to be released.
262#[inline(always)]
263pub fn annotate_sem_post_pre(sem: *const ()) {
264 do_client_request!(
265 "drd::annotate_sem_post_pre",
266 bindings::VR_DRDClientRequest::VR_DRD_ANNOTATE_SEM_POST_PRE,
267 sem as usize,
268 0,
269 0,
270 0,
271 0
272 );
273}
274
275/// Tell DRD that data races at the specified address are expected and must not be reported
276///
277/// Any races detected on the specified variable are benign and hence should not be reported.
278#[inline(always)]
279pub fn annotate_benign_race<T>(addr: &T) {
280 do_client_request!(
281 "drd::annotate_benign_race",
282 bindings::VR_DRDClientRequest::VR_DRD_START_SUPPRESSION,
283 core::ptr::from_ref::<T>(addr) as usize,
284 core::mem::size_of::<T>(),
285 0,
286 0,
287 0
288 );
289}
290
291/// Same as [`annotate_benign_race`], but applies to the memory range [addr, addr + size).
292///
293/// Any races detected on the specified variable are benign and hence should not be reported.
294#[inline(always)]
295pub fn annotate_benign_race_sized<T>(addr: &T, size: usize) {
296 do_client_request!(
297 "drd::annotate_benign_race_sized",
298 bindings::VR_DRDClientRequest::VR_DRD_START_SUPPRESSION,
299 core::ptr::from_ref::<T>(addr) as usize,
300 size,
301 0,
302 0,
303 0
304 );
305}
306
307/// Tell DRD to ignore all reads performed by the current thread
308#[inline(always)]
309pub fn annotate_ignore_reads_begin() {
310 do_client_request!(
311 "drd::annotate_ignore_reads_begin",
312 bindings::VR_DRDClientRequest::VR_DRD_RECORD_LOADS,
313 0,
314 0,
315 0,
316 0,
317 0
318 );
319}
320
321/// Tell DRD to no longer ignore the reads performed by the current thread.
322#[inline(always)]
323pub fn annotate_ignore_reads_end() {
324 do_client_request!(
325 "drd::annotate_ignore_reads_end",
326 bindings::VR_DRDClientRequest::VR_DRD_RECORD_LOADS,
327 1,
328 0,
329 0,
330 0,
331 0
332 );
333}
334
335/// Tell DRD to ignore all writes performed by the current thread.
336#[inline(always)]
337pub fn annotate_ignore_writes_begin() {
338 do_client_request!(
339 "drd::annotate_ignore_writes_begin",
340 bindings::VR_DRDClientRequest::VR_DRD_RECORD_STORES,
341 0,
342 0,
343 0,
344 0,
345 0
346 );
347}
348
349/// Tell DRD to no longer ignore the writes performed by the current thread.
350#[inline(always)]
351pub fn annotate_ignore_writes_end() {
352 do_client_request!(
353 "drd::annotate_ignore_writes_end",
354 bindings::VR_DRDClientRequest::VR_DRD_RECORD_STORES,
355 1,
356 0,
357 0,
358 0,
359 0
360 );
361}
362
363/// Tell DRD to ignore all memory accesses performed by the current thread.
364#[inline(always)]
365pub fn annotate_ignore_reads_and_writes_begin() {
366 annotate_ignore_reads_begin();
367 annotate_ignore_writes_begin();
368}
369
370/// Tell DRD to no longer ignore the memory accesses performed by the current thread.
371#[inline(always)]
372pub fn annotate_ignore_reads_and_writes_end() {
373 annotate_ignore_reads_end();
374 annotate_ignore_writes_end();
375}
376
377/// Tell DRD that size bytes starting at addr has been allocated by a custom memory allocator
378#[inline(always)]
379pub fn annotate_new_memory(addr: *const (), size: usize) {
380 do_client_request!(
381 "drd::annotate_new_memory",
382 bindings::VR_DRDClientRequest::VR_DRD_CLEAN_MEMORY,
383 addr as usize,
384 size,
385 0,
386 0,
387 0
388 );
389}
390
391/// Ask DRD to report every access to the specified address
392///
393/// Trace all load and store activity that touches at least the single byte at the address `addr`.
394#[inline(always)]
395pub fn annotate_trace_memory(addr: *const ()) {
396 do_client_request!(
397 "drd::annotate_trace_memory",
398 bindings::VR_DRDClientRequest::VR_DRD_START_TRACE_ADDR,
399 addr as usize,
400 core::mem::size_of::<cty::c_char>(),
401 0,
402 0,
403 0
404 );
405}
406
407/// Tell DRD to assign the specified name to the current thread.
408///
409/// This name will be used in error messages printed by DRD.
410#[inline(always)]
411pub fn annotate_thread_name<T>(name: T)
412where
413 T: AsRef<CStr>,
414{
415 do_client_request!(
416 "drd::annotate_thread_name",
417 bindings::VR_DRDClientRequest::VR_DRD_SET_THREAD_NAME,
418 name.as_ref().as_ptr() as usize,
419 0,
420 0,
421 0,
422 0
423 );
424}