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 }