lib/sys/src/backtrace.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const capabilities = @import("capabilities.zig");
3
4 pub const required_capabilities = capabilities.pure();
5
6 pub fn supportsCapture() bool {
7 return std.options.allow_stack_tracing and pointerStorageMatchesAddress();
8 }
9
10 pub fn capture(buffer: []?*anyopaque) usize {
11 if (buffer.len == 0) return 0;
12 if (!supportsCapture()) return 0;
13 const addresses: []usize = @as([*]usize, @ptrCast(@alignCast(buffer.ptr)))[0..buffer.len];
14 const trace = std.debug.captureCurrentStackTrace(.{}, addresses);
15 for (trace.return_addresses, 0..) |address, index| {
16 buffer[index] = @ptrFromInt(address);
17 }
18 return trace.return_addresses.len;
19 }
20
21 fn pointerStorageMatchesAddress() bool {
22 return @sizeOf(?*anyopaque) == @sizeOf(usize) and @alignOf(?*anyopaque) >= @alignOf(usize);
23 }
24
25 test "backtrace capture support is queryable" {
26 _ = supportsCapture();
27 }
28
29 test "backtrace capture tolerates empty buffers" {
30 try std.testing.expectEqual(@as(usize, 0), capture(&.{}));
31 }
32
33 test "backtrace capture fits caller buffer" {
34 var buffer = @as([16]?*anyopaque, @splat(null));
35 const count = capture(&buffer);
36
37 try std.testing.expect(count <= buffer.len);
38 if (count > 0) {
39 try std.testing.expect(buffer[0] != null);
40 }
41 }