authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-03-11 13:42:54-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-03-11 13:42:54-04:00
loga909efae9fceb15957144194cf1ae646e8111bb6
tree0e7580ec1e9a9c88da1f6fe94ca5113684f1aa02
parent80e5af2be21427b8590c31e21c8e6b4cae1b7a6e
parentd633dcd07a053d76942217ca845ff2735a0ce6a2
signaturelock-open Commit is signed but in an unrecognized format.

Merge branch 'daurnimator-valgrind'


7 files changed, 719 insertions(+), 11 deletions(-)

CMakeLists.txt+3
......@@ -674,6 +674,9 @@ set(ZIG_STD_FILES
674674 "std.zig"
675675 "testing.zig"
676676 "unicode.zig"
677 "valgrind.zig"
678 "valgrind/callgrind.zig"
679 "valgrind/memcheck.zig"
677680 "zig.zig"
678681 "zig/ast.zig"
679682 "zig/parse.zig"
std/heap.zig+7-10
......@@ -240,9 +240,8 @@ pub const ArenaAllocator = struct {
240240 while (true) {
241241 const cur_buf = cur_node.data[@sizeOf(BufNode)..];
242242 const addr = @ptrToInt(cur_buf.ptr) + self.end_index;
243 const rem = @rem(addr, alignment);
244 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
245 const adjusted_index = self.end_index + march_forward_bytes;
243 const adjusted_addr = mem.alignForward(addr, alignment);
244 const adjusted_index = self.end_index + (adjusted_addr - addr);
246245 const new_end_index = adjusted_index + n;
247246 if (new_end_index > cur_buf.len) {
248247 cur_node = try self.createNode(cur_buf.len, n + alignment);
......@@ -287,9 +286,8 @@ pub const FixedBufferAllocator = struct {
287286 fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {
288287 const self = @fieldParentPtr(FixedBufferAllocator, "allocator", allocator);
289288 const addr = @ptrToInt(self.buffer.ptr) + self.end_index;
290 const rem = @rem(addr, alignment);
291 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
292 const adjusted_index = self.end_index + march_forward_bytes;
289 const adjusted_addr = mem.alignForward(addr, alignment);
290 const adjusted_index = self.end_index + (adjusted_addr - addr);
293291 const new_end_index = adjusted_index + n;
294292 if (new_end_index > self.buffer.len) {
295293 return error.OutOfMemory;
......@@ -326,7 +324,7 @@ pub const ThreadSafeFixedBufferAllocator = blk: {
326324 if (builtin.single_threaded) {
327325 break :blk FixedBufferAllocator;
328326 } else {
329 /// lock free
327 // lock free
330328 break :blk struct {
331329 allocator: Allocator,
332330 end_index: usize,
......@@ -349,9 +347,8 @@ pub const ThreadSafeFixedBufferAllocator = blk: {
349347 var end_index = @atomicLoad(usize, &self.end_index, builtin.AtomicOrder.SeqCst);
350348 while (true) {
351349 const addr = @ptrToInt(self.buffer.ptr) + end_index;
352 const rem = @rem(addr, alignment);
353 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
354 const adjusted_index = end_index + march_forward_bytes;
350 const adjusted_addr = mem.alignForward(addr, alignment);
351 const adjusted_index = end_index + (adjusted_addr - addr);
355352 const new_end_index = adjusted_index + n;
356353 if (new_end_index > self.buffer.len) {
357354 return error.OutOfMemory;
std/mem.zig+2-1
......@@ -114,7 +114,8 @@ pub const Allocator = struct {
114114 // n <= old_mem.len and the multiplication didn't overflow for that operation.
115115 const byte_count = @sizeOf(T) * n;
116116
117 const byte_slice = self.reallocFn(self, @sliceToBytes(old_mem), byte_count, alignment) catch unreachable;
117 const old_byte_slice = @sliceToBytes(old_mem);
118 const byte_slice = self.reallocFn(self, old_byte_slice, byte_count, alignment) catch unreachable;
118119 assert(byte_slice.len == byte_count);
119120 return @bytesToSlice(T, @alignCast(alignment, byte_slice));
120121 }
std/std.zig+2
......@@ -45,6 +45,7 @@ pub const rb = @import("rb.zig");
4545pub const sort = @import("sort.zig");
4646pub const testing = @import("testing.zig");
4747pub const unicode = @import("unicode.zig");
48pub const valgrind = @import("valgrind.zig");
4849pub const zig = @import("zig.zig");
4950
5051test "std" {
......@@ -91,5 +92,6 @@ test "std" {
9192 _ = @import("sort.zig");
9293 _ = @import("testing.zig");
9394 _ = @import("unicode.zig");
95 _ = @import("valgrind.zig");
9496 _ = @import("zig.zig");
9597}
std/valgrind.zig created+363
......@@ -0,0 +1,363 @@
1const builtin = @import("builtin");
2const math = @import("index.zig").math;
3
4
5pub fn doClientRequest(default: usize, request: usize,
6 a1: usize, a2: usize, a3: usize, a4: usize, a5: usize
7 ) usize
8{
9 if (!builtin.valgrind_support) {
10 return default;
11 }
12
13 switch (builtin.arch) {
14 builtin.Arch.i386 => {
15 return asm volatile (
16 \\ roll $3, %%edi ; roll $13, %%edi
17 \\ roll $29, %%edi ; roll $19, %%edi
18 \\ xchgl %%ebx,%%ebx
19 : [_] "={edx}" (-> usize)
20 : [_] "{eax}" (&[]usize{request, a1, a2, a3, a4, a5}),
21 [_] "0" (default)
22 : "cc", "memory"
23 );
24 },
25 builtin.Arch.x86_64 => {
26 return asm volatile (
27 \\ rolq $3, %%rdi ; rolq $13, %%rdi
28 \\ rolq $61, %%rdi ; rolq $51, %%rdi
29 \\ xchgq %%rbx,%%rbx
30 : [_] "={rdx}" (-> usize)
31 : [_] "{rax}" (&[]usize{request, a1, a2, a3, a4, a5}),
32 [_] "0" (default)
33 : "cc", "memory"
34 );
35 },
36 // ppc32
37 // ppc64
38 // arm
39 // arm64
40 // s390x
41 // mips32
42 // mips64
43 else => {
44 return default;
45 }
46 }
47}
48
49
50pub const ClientRequest = extern enum {
51 RunningOnValgrind = 4097,
52 DiscardTranslations = 4098,
53 ClientCall0 = 4353,
54 ClientCall1 = 4354,
55 ClientCall2 = 4355,
56 ClientCall3 = 4356,
57 CountErrors = 4609,
58 GdbMonitorCommand = 4610,
59 MalloclikeBlock = 4865,
60 ResizeinplaceBlock = 4875,
61 FreelikeBlock = 4866,
62 CreateMempool = 4867,
63 DestroyMempool = 4868,
64 MempoolAlloc = 4869,
65 MempoolFree = 4870,
66 MempoolTrim = 4871,
67 MoveMempool = 4872,
68 MempoolChange = 4873,
69 MempoolExists = 4874,
70 Printf = 5121,
71 PrintfBacktrace = 5122,
72 PrintfValistByRef = 5123,
73 PrintfBacktraceValistByRef = 5124,
74 StackRegister = 5377,
75 StackDeregister = 5378,
76 StackChange = 5379,
77 LoadPdbDebuginfo = 5633,
78 MapIpToSrcloc = 5889,
79 ChangeErrDisablement = 6145,
80 VexInitForIri = 6401,
81 InnerThreads = 6402,
82};
83pub fn ToolBase(base: [2]u8) u32 {
84 return (u32(base[0]&0xff) << 24) | (u32(base[1]&0xff) << 16);
85}
86pub fn IsTool(base: [2]u8, code: usize) bool {
87 return ToolBase(base) == (code & 0xffff0000);
88}
89
90fn doClientRequestExpr(default: usize, request: ClientRequest,
91 a1: usize, a2: usize, a3: usize, a4: usize, a5: usize
92 ) usize
93{
94 return doClientRequest(
95 default,
96 @intCast(usize, @enumToInt(request)),
97 a1, a2, a3, a4, a5);
98}
99
100fn doClientRequestStmt(request: ClientRequest,
101 a1: usize, a2: usize, a3: usize, a4: usize, a5: usize
102 ) void
103{
104 _ = doClientRequestExpr(0, request, a1, a2, a3, a4, a5);
105}
106
107
108
109/// Returns the number of Valgrinds this code is running under. That
110/// is, 0 if running natively, 1 if running under Valgrind, 2 if
111/// running under Valgrind which is running under another Valgrind,
112/// etc.
113pub fn runningOnValgrind() usize {
114 return doClientRequestExpr(0,
115 ClientRequest.RunningOnValgrind,
116 0, 0, 0, 0, 0);
117}
118
119
120/// Discard translation of code in the slice qzz. Useful if you are debugging
121/// a JITter or some such, since it provides a way to make sure valgrind will
122/// retranslate the invalidated area. Returns no value.
123pub fn discardTranslations(qzz: []const u8) void {
124 doClientRequestStmt(ClientRequest.DiscardTranslations,
125 @ptrToInt(qzz.ptr), qzz.len,
126 0, 0, 0);
127}
128
129
130pub fn innerThreads(qzz: [*]u8) void {
131 doClientRequestStmt(ClientRequest.InnerThreads,
132 qzz,
133 0, 0, 0, 0);
134}
135
136
137//pub fn printf(format: [*]const u8, args: ...) usize {
138// return doClientRequestExpr(0,
139// ClientRequest.PrintfValistByRef,
140// @ptrToInt(format), @ptrToInt(args),
141// 0, 0, 0);
142//}
143
144
145//pub fn printfBacktrace(format: [*]const u8, args: ...) usize {
146// return doClientRequestExpr(0,
147// ClientRequest.PrintfBacktraceValistByRef,
148// @ptrToInt(format), @ptrToInt(args),
149// 0, 0, 0);
150//}
151
152
153pub fn nonSIMDCall0(func: fn(usize) usize) usize {
154 return doClientRequestExpr(0,
155 ClientRequest.ClientCall0,
156 @ptrToInt(func),
157 0, 0, 0, 0);
158}
159
160pub fn nonSIMDCall1(func: fn(usize, usize) usize, a1: usize) usize {
161 return doClientRequestExpr(0,
162 ClientRequest.ClientCall1,
163 @ptrToInt(func), a1,
164 0, 0, 0);
165}
166
167pub fn nonSIMDCall2(func: fn(usize, usize, usize) usize,
168 a1: usize, a2: usize) usize
169{
170 return doClientRequestExpr(0,
171 ClientRequest.ClientCall2,
172 @ptrToInt(func), a1, a2,
173 0, 0);
174}
175
176pub fn nonSIMDCall3(func: fn(usize, usize, usize, usize) usize,
177 a1: usize, a2: usize, a3: usize) usize
178{
179 return doClientRequestExpr(0,
180 ClientRequest.ClientCall3,
181 @ptrToInt(func), a1, a2, a3,
182 0);
183}
184
185
186/// Counts the number of errors that have been recorded by a tool. Nb:
187/// the tool must record the errors with VG_(maybe_record_error)() or
188/// VG_(unique_error)() for them to be counted.
189pub fn countErrors() usize {
190 return doClientRequestExpr(0, // default return
191 ClientRequest.CountErrors,
192 0, 0, 0, 0, 0);
193}
194
195
196pub fn mallocLikeBlock(mem: []u8, rzB: usize, is_zeroed: bool) void {
197 doClientRequestStmt(ClientRequest.MalloclikeBlock,
198 @ptrToInt(mem.ptr), mem.len, rzB, @boolToInt(is_zeroed),
199 0);
200}
201
202
203pub fn resizeInPlaceBlock(oldmem: []u8, newsize: usize, rzB: usize) void {
204 doClientRequestStmt(ClientRequest.ResizeinplaceBlock,
205 @ptrToInt(oldmem.ptr), oldmem.len, newsize, rzB,
206 0);
207}
208
209
210pub fn freeLikeBlock(addr: [*]u8, rzB: usize) void {
211 doClientRequestStmt(ClientRequest.FreelikeBlock,
212 @ptrToInt(addr), rzB,
213 0, 0, 0);
214}
215
216
217/// Create a memory pool.
218pub const MempoolFlags = extern enum {
219 AutoFree = 1,
220 MetaPool = 2,
221};
222pub fn createMempool(pool: [*]u8, rzB: usize, is_zeroed: bool, flags: usize) void {
223 doClientRequestStmt(ClientRequest.CreateMempool,
224 @ptrToInt(pool), rzB, @boolToInt(is_zeroed), flags,
225 0);
226}
227
228/// Destroy a memory pool.
229pub fn destroyMempool(pool: [*]u8) void {
230 doClientRequestStmt(ClientRequest.DestroyMempool,
231 pool,
232 0, 0, 0, 0);
233}
234
235
236/// Associate a piece of memory with a memory pool.
237pub fn mempoolAlloc(pool: [*]u8, mem: []u8) void {
238 doClientRequestStmt(ClientRequest.MempoolAlloc,
239 @ptrToInt(pool), @ptrToInt(mem.ptr), mem.len,
240 0, 0);
241}
242
243/// Disassociate a piece of memory from a memory pool.
244pub fn mempoolFree(pool: [*]u8, addr: [*]u8) void {
245 doClientRequestStmt(ClientRequest.MempoolFree,
246 @ptrToInt(pool), @ptrToInt(addr),
247 0, 0, 0);
248}
249
250/// Disassociate any pieces outside a particular range.
251pub fn mempoolTrim(pool: [*]u8, mem: []u8) void {
252 doClientRequestStmt(ClientRequest.MempoolTrim,
253 @ptrToInt(pool), @ptrToInt(mem.ptr), mem.len,
254 0, 0);
255}
256
257/// Resize and/or move a piece associated with a memory pool.
258pub fn moveMempool(poolA: [*]u8, poolB: [*]u8) void {
259 doClientRequestStmt(ClientRequest.MoveMempool,
260 @ptrToInt(poolA), @ptrToInt(poolB),
261 0, 0, 0);
262}
263
264/// Resize and/or move a piece associated with a memory pool.
265pub fn mempoolChange(pool: [*]u8, addrA: [*]u8, mem: []u8) void {
266 doClientRequestStmt(ClientRequest.MempoolChange,
267 @ptrToInt(pool), @ptrToInt(addrA), @ptrToInt(mem.ptr), mem.len,
268 0);
269}
270
271/// Return if a mempool exists.
272pub fn mempoolExists(pool: [*]u8) bool {
273 return doClientRequestExpr(0,
274 ClientRequest.MempoolExists,
275 @ptrToInt(pool),
276 0, 0, 0, 0) != 0;
277}
278
279
280/// Mark a piece of memory as being a stack. Returns a stack id.
281/// start is the lowest addressable stack byte, end is the highest
282/// addressable stack byte.
283pub fn stackRegister(stack: []u8) usize {
284 return doClientRequestExpr(0,
285 ClientRequest.StackRegister,
286 @ptrToInt(stack.ptr), @ptrToInt(stack.ptr) + stack.len,
287 0, 0, 0);
288}
289
290/// Unmark the piece of memory associated with a stack id as being a stack.
291pub fn stackDeregister(id: usize) void {
292 doClientRequestStmt(ClientRequest.StackDeregister,
293 id,
294 0, 0, 0, 0);
295}
296
297/// Change the start and end address of the stack id.
298/// start is the new lowest addressable stack byte, end is the new highest
299/// addressable stack byte.
300pub fn stackChange(id: usize, newstack: []u8) void {
301 doClientRequestStmt(ClientRequest.StackChange,
302 id, @ptrToInt(newstack.ptr), @ptrToInt(newstack.ptr) + newstack.len,
303 0, 0);
304}
305
306
307// Load PDB debug info for Wine PE image_map.
308// pub fn loadPdbDebuginfo(fd, ptr, total_size, delta) void {
309// doClientRequestStmt(ClientRequest.LoadPdbDebuginfo,
310// fd, ptr, total_size, delta,
311// 0);
312// }
313
314
315/// Map a code address to a source file name and line number. buf64
316/// must point to a 64-byte buffer in the caller's address space. The
317/// result will be dumped in there and is guaranteed to be zero
318/// terminated. If no info is found, the first byte is set to zero.
319pub fn mapIpToSrcloc(addr: *const u8, buf64: [64]u8) usize {
320 return doClientRequestExpr(0,
321 ClientRequest.MapIpToSrcloc,
322 @ptrToInt(addr), @ptrToInt(&buf64[0]),
323 0, 0, 0);
324}
325
326
327/// Disable error reporting for this thread. Behaves in a stack like
328/// way, so you can safely call this multiple times provided that
329/// enableErrorReporting() is called the same number of times
330/// to re-enable reporting. The first call of this macro disables
331/// reporting. Subsequent calls have no effect except to increase the
332/// number of enableErrorReporting() calls needed to re-enable
333/// reporting. Child threads do not inherit this setting from their
334/// parents -- they are always created with reporting enabled.
335pub fn disableErrorReporting() void {
336 doClientRequestStmt(ClientRequest.ChangeErrDisablement,
337 1,
338 0, 0, 0, 0);
339}
340
341/// Re-enable error reporting, (see disableErrorReporting())
342pub fn enableErrorReporting() void {
343 doClientRequestStmt(ClientRequest.ChangeErrDisablement,
344 math.maxInt(usize),
345 0, 0, 0, 0);
346}
347
348
349/// Execute a monitor command from the client program.
350/// If a connection is opened with GDB, the output will be sent
351/// according to the output mode set for vgdb.
352/// If no connection is opened, output will go to the log output.
353/// Returns 1 if command not recognised, 0 otherwise.
354pub fn monitorCommand(command: [*]u8) bool {
355 return doClientRequestExpr(0,
356 ClientRequest.GdbMonitorCommand,
357 @ptrToInt(command.ptr),
358 0, 0, 0, 0) != 0;
359}
360
361
362pub const memcheck = @import("memcheck.zig");
363pub const callgrind = @import("callgrind.zig");
std/valgrind/callgrind.zig created+87
......@@ -0,0 +1,87 @@
1const std = @import("../index.zig");
2const valgrind = std.valgrind;
3
4pub const CallgrindClientRequest = extern enum {
5 DumpStats = valgrind.ToolBase("CT"),
6 ZeroStats,
7 ToggleCollect,
8 DumpStatsAt,
9 StartInstrumentation,
10 StopInstrumentation,
11};
12
13fn doCallgrindClientRequestExpr(default: usize, request: CallgrindClientRequest,
14 a1: usize, a2: usize, a3: usize, a4: usize, a5: usize
15 ) usize
16{
17 return valgrind.doClientRequest(
18 default,
19 @intCast(usize, @enumToInt(request)),
20 a1, a2, a3, a4, a5);
21}
22
23fn doCallgrindClientRequestStmt(request: CallgrindClientRequest,
24 a1: usize, a2: usize, a3: usize, a4: usize, a5: usize
25 ) void
26{
27 _ = doCallgrindClientRequestExpr(0, request, a1, a2, a3, a4, a5);
28}
29
30
31
32/// Dump current state of cost centers, and zero them afterwards
33pub fn dumpStats() void {
34 doCallgrindClientRequestStmt(CallgrindClientRequest.DumpStats,
35 0, 0, 0, 0, 0);
36}
37
38
39/// Dump current state of cost centers, and zero them afterwards.
40/// The argument is appended to a string stating the reason which triggered
41/// the dump. This string is written as a description field into the
42/// profile data dump.
43pub fn dumpStatsAt(pos_str: [*]u8) void {
44 doCallgrindClientRequestStmt(CallgrindClientRequest.DumpStatsAt,
45 @ptrToInt(pos_str),
46 0, 0, 0, 0);
47}
48
49
50/// Zero cost centers
51pub fn zeroStats() void {
52 doCallgrindClientRequestStmt(CallgrindClientRequest.ZeroStats,
53 0, 0, 0, 0, 0);
54}
55
56
57/// Toggles collection state.
58/// The collection state specifies whether the happening of events
59/// should be noted or if they are to be ignored. Events are noted
60/// by increment of counters in a cost center
61pub fn toggleCollect() void {
62 doCallgrindClientRequestStmt(CallgrindClientRequest.ToggleCollect,
63 0, 0, 0, 0, 0);
64}
65
66
67/// Start full callgrind instrumentation if not already switched on.
68/// When cache simulation is done, it will flush the simulated cache;
69/// this will lead to an artificial cache warmup phase afterwards with
70/// cache misses which would not have happened in reality.
71pub fn startInstrumentation() void {
72 doCallgrindClientRequestStmt(CallgrindClientRequest.StartInstrumentation,
73 0, 0, 0, 0, 0);
74}
75
76
77/// Stop full callgrind instrumentation if not already switched off.
78/// This flushes Valgrinds translation cache, and does no additional
79/// instrumentation afterwards, which effectivly will run at the same
80/// speed as the "none" tool (ie. at minimal slowdown).
81/// Use this to bypass Callgrind aggregation for uninteresting code parts.
82/// To start Callgrind in this mode to ignore the setup phase, use
83/// the option "--instr-atstart=no".
84pub fn stopInstrumentation() void {
85 doCallgrindClientRequestStmt(CallgrindClientRequest.StopInstrumentation,
86 0, 0, 0, 0, 0);
87}
std/valgrind/memcheck.zig created+255
......@@ -0,0 +1,255 @@
1const std = @import("../index.zig");
2const valgrind = std.valgrind;
3
4pub const MemCheckClientRequest = extern enum {
5 MakeMemNoAccess = valgrind.ToolBase("MC"),
6 MakeMemUndefined,
7 MakeMemDefined,
8 Discard,
9 CheckMemIsAddressable,
10 CheckMemIsDefined,
11 DoLeakCheck,
12 CountLeaks,
13 GetVbits,
14 SetVbits,
15 CreateBlock,
16 MakeMemDefinedIfAddressable,
17 CountLeakBlocks,
18 EnableAddrErrorReportingInRange,
19 DisableAddrErrorReportingInRange,
20};
21
22fn doMemCheckClientRequestExpr(default: usize, request: MemCheckClientRequest,
23 a1: usize, a2: usize, a3: usize, a4: usize, a5: usize
24 ) usize
25{
26 return valgrind.doClientRequest(
27 default,
28 @intCast(usize, @enumToInt(request)),
29 a1, a2, a3, a4, a5);
30}
31
32fn doMemCheckClientRequestStmt(request: MemCheckClientRequest,
33 a1: usize, a2: usize, a3: usize, a4: usize, a5: usize
34 ) void
35{
36 _ = doMemCheckClientRequestExpr(0, request, a1, a2, a3, a4, a5);
37}
38
39
40
41/// Mark memory at qzz.ptr as unaddressable for qzz.len bytes.
42/// This returns -1 when run on Valgrind and 0 otherwise.
43pub fn makeMemNoAccess(qzz: []u8) i1 {
44 return @intCast(i1, doMemCheckClientRequestExpr(0, // default return
45 MemCheckClientRequest.MakeMemNoAccess,
46 @ptrToInt(qzz.ptr), qzz.len,
47 0, 0, 0));
48}
49
50
51/// Similarly, mark memory at qzz.ptr as addressable but undefined
52/// for qzz.len bytes.
53/// This returns -1 when run on Valgrind and 0 otherwise.
54pub fn makeMemUndefined(qzz: []u8) i1 {
55 return @intCast(i1, doMemCheckClientRequestExpr(0, // default return
56 MemCheckClientRequest.MakeMemUndefined,
57 @ptrToInt(qzz.ptr), qzz.len,
58 0, 0, 0));
59}
60
61
62/// Similarly, mark memory at qzz.ptr as addressable and defined
63/// for qzz.len bytes.
64pub fn makeMemDefined(qzz: []u8) i1 {
65// This returns -1 when run on Valgrind and 0 otherwise.
66 return @intCast(i1, doMemCheckClientRequestExpr(0, // default return
67 MemCheckClientRequest.MakeMemDefined,
68 @ptrToInt(qzz.ptr), qzz.len,
69 0, 0, 0));
70}
71
72
73/// Similar to makeMemDefined except that addressability is
74/// not altered: bytes which are addressable are marked as defined,
75/// but those which are not addressable are left unchanged.
76/// This returns -1 when run on Valgrind and 0 otherwise.
77pub fn makeMemDefinedIfAddressable(qzz: []u8) i1 {
78 return @intCast(i1, doMemCheckClientRequestExpr(0, // default return
79 MemCheckClientRequest.MakeMemDefinedIfAddressable,
80 @ptrToInt(qzz.ptr), qzz.len,
81 0, 0, 0));
82}
83
84
85/// Create a block-description handle. The description is an ascii
86/// string which is included in any messages pertaining to addresses
87/// within the specified memory range. Has no other effect on the
88/// properties of the memory range.
89pub fn createBlock(qzz: []u8, desc: [*]u8) usize {
90 return doMemCheckClientRequestExpr(0, // default return
91 MemCheckClientRequest.CreateBlock,
92 @ptrToInt(qzz.ptr), qzz.len, @ptrToInt(desc),
93 0, 0);
94}
95
96
97/// Discard a block-description-handle. Returns 1 for an
98/// invalid handle, 0 for a valid handle.
99pub fn discard(blkindex) bool {
100 return doMemCheckClientRequestExpr(0, // default return
101 MemCheckClientRequest.Discard,
102 0, blkindex,
103 0, 0, 0) != 0;
104}
105
106
107/// Check that memory at qzz.ptr is addressable for qzz.len bytes.
108/// If suitable addressibility is not established, Valgrind prints an
109/// error message and returns the address of the first offending byte.
110/// Otherwise it returns zero.
111pub fn checkMemIsAddressable(qzz: []u8) usize {
112 return doMemCheckClientRequestExpr(0,
113 MemCheckClientRequest.CheckMemIsAddressable,
114 @ptrToInt(qzz.ptr), qzz.len,
115 0, 0, 0);
116}
117
118
119/// Check that memory at qzz.ptr is addressable and defined for
120/// qzz.len bytes. If suitable addressibility and definedness are not
121/// established, Valgrind prints an error message and returns the
122/// address of the first offending byte. Otherwise it returns zero.
123pub fn checkMemIsDefined(qzz: []u8) usize {
124 return doMemCheckClientRequestExpr(0,
125 MemCheckClientRequest.CheckMemIsDefined,
126 @ptrToInt(qzz.ptr), qzz.len,
127 0, 0, 0);
128}
129
130/// Do a full memory leak check (like --leak-check=full) mid-execution.
131pub fn doLeakCheck() void {
132 doMemCheckClientRequestStmt(MemCheckClientRequest.DO_LEAK_CHECK,
133 0, 0,
134 0, 0, 0);
135}
136
137/// Same as doLeakCheck() but only showing the entries for
138/// which there was an increase in leaked bytes or leaked nr of blocks
139/// since the previous leak search.
140pub fn doAddedLeakCheck() void {
141 doMemCheckClientRequestStmt(MemCheckClientRequest.DO_LEAK_CHECK,
142 0, 1,
143 0, 0, 0);
144}
145
146
147/// Same as doAddedLeakCheck() but showing entries with
148/// increased or decreased leaked bytes/blocks since previous leak
149/// search.
150pub fn doChangedLeakCheck() void {
151 doMemCheckClientRequestStmt(MemCheckClientRequest.DO_LEAK_CHECK,
152 0, 2,
153 0, 0, 0);
154}
155
156
157/// Do a summary memory leak check (like --leak-check=summary) mid-execution.
158pub fn doQuickLeakCheck() void {
159 doMemCheckClientRequestStmt(MemCheckClientRequest.DO_LEAK_CHECK,
160 1, 0,
161 0, 0, 0);
162}
163
164
165/// Return number of leaked, dubious, reachable and suppressed bytes found by
166/// all previous leak checks.
167const CountResult = struct {
168 leaked: usize,
169 dubious: usize,
170 reachable: usize,
171 suppressed: usize,
172};
173
174pub fn countLeaks() CountResult {
175 var res = CountResult {
176 .leaked = 0,
177 .dubious = 0,
178 .reachable = 0,
179 .suppressed = 0,
180 };
181 doMemCheckClientRequestStmt(MemCheckClientRequest.CountLeaks,
182 &res.leaked, &res.dubious,
183 &res.reachable, &res.suppressed,
184 0);
185 return res;
186}
187
188pub fn countLeakBlocks() CountResult {
189 var res = CountResult {
190 .leaked = 0,
191 .dubious = 0,
192 .reachable = 0,
193 .suppressed = 0,
194 };
195 doMemCheckClientRequestStmt(MemCheckClientRequest.CountLeakBlocks,
196 &res.leaked, &res.dubious,
197 &res.reachable, &res.suppressed,
198 0);
199 return res;
200}
201
202
203/// Get the validity data for addresses zza and copy it
204/// into the provided zzvbits array. Return values:
205/// 0 if not running on valgrind
206/// 1 success
207/// 2 [previously indicated unaligned arrays; these are now allowed]
208/// 3 if any parts of zzsrc/zzvbits are not addressable.
209/// The metadata is not copied in cases 0, 2 or 3 so it should be
210/// impossible to segfault your system by using this call.
211pub fn getVbits(zza: []u8, zzvbits: []u8) u2 {
212 std.debug.assert(zzvbits.len >= zza.len / 8);
213 return @intCast(u2, doMemCheckClientRequestExpr(0,
214 MemCheckClientRequest.GetVbits,
215 @ptrToInt(zza.ptr),
216 @ptrToInt(zzvbits),
217 zza.len,
218 0, 0));
219}
220
221
222/// Set the validity data for addresses zza, copying it
223/// from the provided zzvbits array. Return values:
224/// 0 if not running on valgrind
225/// 1 success
226/// 2 [previously indicated unaligned arrays; these are now allowed]
227/// 3 if any parts of zza/zzvbits are not addressable.
228/// The metadata is not copied in cases 0, 2 or 3 so it should be
229/// impossible to segfault your system by using this call.
230pub fn setVbits(zzvbits: []u8, zza: []u8) u2 {
231 std.debug.assert(zzvbits.len >= zza.len / 8);
232 return @intCast(u2, doMemCheckClientRequestExpr(0,
233 MemCheckClientRequest.SetVbits,
234 @ptrToInt(zza.ptr),
235 @ptrToInt(zzvbits),
236 zza.len,
237 0, 0));
238}
239
240
241/// Disable and re-enable reporting of addressing errors in the
242/// specified address range.
243pub fn disableAddrErrorReportingInRange(qzz: []u8) usize {
244 return doMemCheckClientRequestExpr(0, // default return
245 MemCheckClientRequest.DisableAddrErrorReportingInRange,
246 @ptrToInt(qzz.ptr), qzz.len,
247 0, 0, 0);
248}
249
250pub fn enableAddrErrorReportingInRange(qzz: []u8) usize {
251 return doMemCheckClientRequestExpr(0, // default return
252 MemCheckClientRequest.EnableAddrErrorReportingInRange,
253 @ptrToInt(qzz.ptr), qzz.len,
254 0, 0, 0);
255}