authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-03-11 13:34:51-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-03-11 13:34:51-04:00
logd633dcd07a053d76942217ca845ff2735a0ce6a2
tree0e7580ec1e9a9c88da1f6fe94ca5113684f1aa02
parent5362ca204ff68716727915d98bd25d9d7b2c9f80
signaturelock-open Commit is signed but in an unrecognized format.

remove the valgrind integration with std.mem.Allocator

See #1837

4 files changed, 370 insertions(+), 392 deletions(-)

std/heap.zig+7-14
...@@ -240,9 +240,8 @@ pub const ArenaAllocator = struct {...@@ -240,9 +240,8 @@ pub const ArenaAllocator = struct {
240 while (true) {240 while (true) {
241 const cur_buf = cur_node.data[@sizeOf(BufNode)..];241 const cur_buf = cur_node.data[@sizeOf(BufNode)..];
242 const addr = @ptrToInt(cur_buf.ptr) + self.end_index;242 const addr = @ptrToInt(cur_buf.ptr) + self.end_index;
243 const rem = @rem(addr, alignment);243 const adjusted_addr = mem.alignForward(addr, alignment);
244 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);244 const adjusted_index = self.end_index + (adjusted_addr - addr);
245 const adjusted_index = self.end_index + march_forward_bytes;
246 const new_end_index = adjusted_index + n;245 const new_end_index = adjusted_index + n;
247 if (new_end_index > cur_buf.len) {246 if (new_end_index > cur_buf.len) {
248 cur_node = try self.createNode(cur_buf.len, n + alignment);247 cur_node = try self.createNode(cur_buf.len, n + alignment);
...@@ -273,10 +272,6 @@ pub const FixedBufferAllocator = struct {...@@ -273,10 +272,6 @@ pub const FixedBufferAllocator = struct {
273 buffer: []u8,272 buffer: []u8,
274273
275 pub fn init(buffer: []u8) FixedBufferAllocator {274 pub fn init(buffer: []u8) FixedBufferAllocator {
276 // This loop gets optimized out in ReleaseFast mode
277 for (buffer) |*byte| {
278 byte.* = undefined;
279 }
280 return FixedBufferAllocator{275 return FixedBufferAllocator{
281 .allocator = Allocator{276 .allocator = Allocator{
282 .allocFn = alloc,277 .allocFn = alloc,
...@@ -291,9 +286,8 @@ pub const FixedBufferAllocator = struct {...@@ -291,9 +286,8 @@ pub const FixedBufferAllocator = struct {
291 fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {286 fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {
292 const self = @fieldParentPtr(FixedBufferAllocator, "allocator", allocator);287 const self = @fieldParentPtr(FixedBufferAllocator, "allocator", allocator);
293 const addr = @ptrToInt(self.buffer.ptr) + self.end_index;288 const addr = @ptrToInt(self.buffer.ptr) + self.end_index;
294 const rem = @rem(addr, alignment);289 const adjusted_addr = mem.alignForward(addr, alignment);
295 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);290 const adjusted_index = self.end_index + (adjusted_addr - addr);
296 const adjusted_index = self.end_index + march_forward_bytes;
297 const new_end_index = adjusted_index + n;291 const new_end_index = adjusted_index + n;
298 if (new_end_index > self.buffer.len) {292 if (new_end_index > self.buffer.len) {
299 return error.OutOfMemory;293 return error.OutOfMemory;
...@@ -330,7 +324,7 @@ pub const ThreadSafeFixedBufferAllocator = blk: {...@@ -330,7 +324,7 @@ pub const ThreadSafeFixedBufferAllocator = blk: {
330 if (builtin.single_threaded) {324 if (builtin.single_threaded) {
331 break :blk FixedBufferAllocator;325 break :blk FixedBufferAllocator;
332 } else {326 } else {
333 /// lock free327 // lock free
334 break :blk struct {328 break :blk struct {
335 allocator: Allocator,329 allocator: Allocator,
336 end_index: usize,330 end_index: usize,
...@@ -353,9 +347,8 @@ pub const ThreadSafeFixedBufferAllocator = blk: {...@@ -353,9 +347,8 @@ pub const ThreadSafeFixedBufferAllocator = blk: {
353 var end_index = @atomicLoad(usize, &self.end_index, builtin.AtomicOrder.SeqCst);347 var end_index = @atomicLoad(usize, &self.end_index, builtin.AtomicOrder.SeqCst);
354 while (true) {348 while (true) {
355 const addr = @ptrToInt(self.buffer.ptr) + end_index;349 const addr = @ptrToInt(self.buffer.ptr) + end_index;
356 const rem = @rem(addr, alignment);350 const adjusted_addr = mem.alignForward(addr, alignment);
357 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);351 const adjusted_index = end_index + (adjusted_addr - addr);
358 const adjusted_index = end_index + march_forward_bytes;
359 const new_end_index = adjusted_index + n;352 const new_end_index = adjusted_index + n;
360 if (new_end_index > self.buffer.len) {353 if (new_end_index > self.buffer.len) {
361 return error.OutOfMemory;354 return error.OutOfMemory;
std/mem.zig-15
...@@ -49,7 +49,6 @@ pub const Allocator = struct {...@@ -49,7 +49,6 @@ pub const Allocator = struct {
49 pub fn destroy(self: *Allocator, ptr: var) void {49 pub fn destroy(self: *Allocator, ptr: var) void {
50 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr));50 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr));
51 self.freeFn(self, non_const_ptr[0..@sizeOf(@typeOf(ptr).Child)]);51 self.freeFn(self, non_const_ptr[0..@sizeOf(@typeOf(ptr).Child)]);
52 _ = std.valgrind.freeLikeBlock(non_const_ptr, 0);
53 }52 }
5453
55 pub fn alloc(self: *Allocator, comptime T: type, n: usize) ![]T {54 pub fn alloc(self: *Allocator, comptime T: type, n: usize) ![]T {
...@@ -63,7 +62,6 @@ pub const Allocator = struct {...@@ -63,7 +62,6 @@ pub const Allocator = struct {
63 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;62 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
64 const byte_slice = try self.allocFn(self, byte_count, alignment);63 const byte_slice = try self.allocFn(self, byte_count, alignment);
65 assert(byte_slice.len == byte_count);64 assert(byte_slice.len == byte_count);
66 _ = std.valgrind.mallocLikeBlock(byte_slice, 0, false);
67 // This loop gets optimized out in ReleaseFast mode65 // This loop gets optimized out in ReleaseFast mode
68 for (byte_slice) |*byte| {66 for (byte_slice) |*byte| {
69 byte.* = undefined;67 byte.* = undefined;
...@@ -88,12 +86,6 @@ pub const Allocator = struct {...@@ -88,12 +86,6 @@ pub const Allocator = struct {
88 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;86 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
89 const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment);87 const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment);
90 assert(byte_slice.len == byte_count);88 assert(byte_slice.len == byte_count);
91 if (byte_slice.ptr == old_byte_slice.ptr) {
92 _ = std.valgrind.resizeInPlaceBlock(old_byte_slice, byte_count, 0);
93 } else {
94 _ = std.valgrind.freeLikeBlock(old_byte_slice.ptr, 0);
95 _ = std.valgrind.mallocLikeBlock(byte_slice, 0, false);
96 }
97 if (n > old_mem.len) {89 if (n > old_mem.len) {
98 // This loop gets optimized out in ReleaseFast mode90 // This loop gets optimized out in ReleaseFast mode
99 for (byte_slice[old_byte_slice.len..]) |*byte| {91 for (byte_slice[old_byte_slice.len..]) |*byte| {
...@@ -125,12 +117,6 @@ pub const Allocator = struct {...@@ -125,12 +117,6 @@ pub const Allocator = struct {
125 const old_byte_slice = @sliceToBytes(old_mem);117 const old_byte_slice = @sliceToBytes(old_mem);
126 const byte_slice = self.reallocFn(self, old_byte_slice, byte_count, alignment) catch unreachable;118 const byte_slice = self.reallocFn(self, old_byte_slice, byte_count, alignment) catch unreachable;
127 assert(byte_slice.len == byte_count);119 assert(byte_slice.len == byte_count);
128 if (byte_slice.ptr == old_byte_slice.ptr) {
129 _ = std.valgrind.resizeInPlaceBlock(old_byte_slice, byte_count, 0);
130 } else {
131 _ = std.valgrind.freeLikeBlock(old_byte_slice.ptr, 0);
132 _ = std.valgrind.mallocLikeBlock(byte_slice, 0, false);
133 }
134 return @bytesToSlice(T, @alignCast(alignment, byte_slice));120 return @bytesToSlice(T, @alignCast(alignment, byte_slice));
135 }121 }
136122
...@@ -139,7 +125,6 @@ pub const Allocator = struct {...@@ -139,7 +125,6 @@ pub const Allocator = struct {
139 if (bytes.len == 0) return;125 if (bytes.len == 0) return;
140 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(bytes.ptr));126 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(bytes.ptr));
141 self.freeFn(self, non_const_ptr[0..bytes.len]);127 self.freeFn(self, non_const_ptr[0..bytes.len]);
142 _ = std.valgrind.freeLikeBlock(non_const_ptr, 0);
143 }128 }
144};129};
145130
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/index.zig deleted-363
...@@ -1,363 +0,0 @@
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");