authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-23 22:08:53-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-23 22:15:48-05:00
log4183c6f1a52959ab5eef540c8eec1758079554eb
treecbdecf12598c72f3d66d7fa5618d8a9c6338fa53
parent9dae796fe3bd08c4e636f09d1849f6ce2879a50b

move std/debug.zig to a subdirectory

self hosted compiler parser tests do some fuzz testing

76 files changed, 1288 insertions(+), 1214 deletions(-)

CMakeLists.txt+2-1
......@@ -516,7 +516,8 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/c/index.zig" DESTINATION "${ZIG_STD_DEST}
516516install(FILES "${CMAKE_SOURCE_DIR}/std/c/linux.zig" DESTINATION "${ZIG_STD_DEST}/c")
517517install(FILES "${CMAKE_SOURCE_DIR}/std/c/windows.zig" DESTINATION "${ZIG_STD_DEST}/c")
518518install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}")
519install(FILES "${CMAKE_SOURCE_DIR}/std/debug.zig" DESTINATION "${ZIG_STD_DEST}")
519install(FILES "${CMAKE_SOURCE_DIR}/std/debug/index.zig" DESTINATION "${ZIG_STD_DEST}/debug")
520install(FILES "${CMAKE_SOURCE_DIR}/std/debug/failing_allocator.zig" DESTINATION "${ZIG_STD_DEST}/debug")
520521install(FILES "${CMAKE_SOURCE_DIR}/std/dwarf.zig" DESTINATION "${ZIG_STD_DEST}")
521522install(FILES "${CMAKE_SOURCE_DIR}/std/elf.zig" DESTINATION "${ZIG_STD_DEST}")
522523install(FILES "${CMAKE_SOURCE_DIR}/std/empty.zig" DESTINATION "${ZIG_STD_DEST}")
build.zig+2-1
......@@ -172,7 +172,8 @@ pub fn installStdLib(b: &Builder) {
172172 "c/linux.zig",
173173 "c/windows.zig",
174174 "cstr.zig",
175 "debug.zig",
175 "debug/failing_allocator.zig",
176 "debug/index.zig",
176177 "dwarf.zig",
177178 "elf.zig",
178179 "empty.zig",
src-self-hosted/parser.zig+18-12
......@@ -1119,18 +1119,24 @@ fn testCanonical(source: []const u8) {
11191119 break :x failing_allocator.index;
11201120 };
11211121
1122 // TODO make this pass
1123 //var fail_index = needed_alloc_count;
1124 //while (fail_index != 0) {
1125 // fail_index -= 1;
1126 // var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1127 // var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index);
1128 // if (testParse(source, &failing_allocator.allocator)) |_| {
1129 // @panic("non-deterministic memory usage");
1130 // } else |err| {
1131 // assert(err == error.OutOfMemory);
1132 // }
1133 //}
1122 var fail_index: usize = 0;
1123 while (fail_index < needed_alloc_count) : (fail_index += 1) {
1124 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1125 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index);
1126 if (testParse(source, &failing_allocator.allocator)) |_| {
1127 @panic("non-deterministic memory usage");
1128 } else |err| {
1129 assert(err == error.OutOfMemory);
1130 // TODO make this pass
1131 //if (failing_allocator.allocated_bytes != failing_allocator.freed_bytes) {
1132 // warn("\nfail_index: {}/{}\nallocated bytes: {}\nfreed bytes: {}\nallocations: {}\ndeallocations: {}\n",
1133 // fail_index, needed_alloc_count,
1134 // failing_allocator.allocated_bytes, failing_allocator.freed_bytes,
1135 // failing_allocator.index, failing_allocator.deallocations);
1136 // @panic("memory leak detected");
1137 //}
1138 }
1139 }
11341140}
11351141
11361142test "zig fmt" {
std/array_list.zig+3-2
......@@ -1,6 +1,7 @@
1const debug = @import("debug.zig");
1const std = @import("index.zig");
2const debug = std.debug;
23const assert = debug.assert;
3const mem = @import("mem.zig");
4const mem = std.mem;
45const Allocator = mem.Allocator;
56
67pub fn ArrayList(comptime T: type) -> type {
std/base64.zig+3-2
......@@ -1,5 +1,6 @@
1const assert = @import("debug.zig").assert;
2const mem = @import("mem.zig");
1const std = @import("index.zig");
2const assert = std.debug.assert;
3const mem = std.mem;
34
45pub const standard_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
56pub const standard_pad_char = '=';
std/buffer.zig+5-4
......@@ -1,10 +1,11 @@
1const debug = @import("debug.zig");
2const mem = @import("mem.zig");
1const std = @import("index.zig");
2const debug = std.debug;
3const mem = std.mem;
34const Allocator = mem.Allocator;
45const assert = debug.assert;
5const ArrayList = @import("array_list.zig").ArrayList;
6const ArrayList = std.ArrayList;
67
7const fmt = @import("fmt/index.zig");
8const fmt = std.fmt;
89
910/// A buffer that allocates memory and maintains a null byte at the end.
1011pub const Buffer = struct {
std/cstr.zig+3-2
......@@ -1,5 +1,6 @@
1const debug = @import("debug.zig");
2const mem = @import("mem.zig");
1const std = @import("index.zig");
2const debug = std.debug;
3const mem = std.mem;
34const assert = debug.assert;
45
56pub fn len(ptr: &const u8) -> usize {
std/debug.zig deleted-1050
......@@ -1,1050 +0,0 @@
1const std = @import("index.zig");
2const math = std.math;
3const mem = std.mem;
4const io = std.io;
5const os = std.os;
6const elf = @import("elf.zig");
7const DW = @import("dwarf.zig");
8const ArrayList = std.ArrayList;
9const builtin = @import("builtin");
10
11error MissingDebugInfo;
12error InvalidDebugInfo;
13error UnsupportedDebugInfo;
14
15
16/// Tries to write to stderr, unbuffered, and ignores any error returned.
17/// Does not append a newline.
18/// TODO atomic/multithread support
19var stderr_file: io.File = undefined;
20var stderr_file_out_stream: io.FileOutStream = undefined;
21var stderr_stream: ?&io.OutStream = null;
22pub fn warn(comptime fmt: []const u8, args: ...) {
23 const stderr = getStderrStream() %% return;
24 stderr.print(fmt, args) %% return;
25}
26fn getStderrStream() -> %&io.OutStream {
27 if (stderr_stream) |st| {
28 return st;
29 } else {
30 stderr_file = %return io.getStdErr();
31 stderr_file_out_stream = io.FileOutStream.init(&stderr_file);
32 const st = &stderr_file_out_stream.stream;
33 stderr_stream = st;
34 return st;
35 }
36}
37
38/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
39pub fn dumpStackTrace() {
40 const stderr = getStderrStream() %% return;
41 writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) %% return;
42}
43
44/// This function invokes undefined behavior when `ok` is `false`.
45/// In Debug and ReleaseSafe modes, calls to this function are always
46/// generated, and the `unreachable` statement triggers a panic.
47/// In ReleaseFast and ReleaseSmall modes, calls to this function can be
48/// optimized away.
49pub fn assert(ok: bool) {
50 if (!ok) {
51 // In ReleaseFast test mode, we still want assert(false) to crash, so
52 // we insert an explicit call to @panic instead of unreachable.
53 // TODO we should use `assertOrPanic` in tests and remove this logic.
54 if (builtin.is_test) {
55 @panic("assertion failure");
56 } else {
57 unreachable; // assertion failure
58 }
59 }
60}
61
62/// Call this function when you want to panic if the condition is not true.
63/// If `ok` is `false`, this function will panic in every release mode.
64pub fn assertOrPanic(ok: bool) {
65 if (!ok) {
66 @panic("assertion failure");
67 }
68}
69
70var panicking = false;
71/// This is the default panic implementation.
72pub fn panic(comptime format: []const u8, args: ...) -> noreturn {
73 // TODO an intrinsic that labels this as unlikely to be reached
74
75 // TODO
76 // if (@atomicRmw(AtomicOp.XChg, &panicking, true, AtomicOrder.SeqCst)) { }
77 if (panicking) {
78 // Panicked during a panic.
79 // TODO detect if a different thread caused the panic, because in that case
80 // we would want to return here instead of calling abort, so that the thread
81 // which first called panic can finish printing a stack trace.
82 os.abort();
83 } else {
84 panicking = true;
85 }
86
87 const stderr = getStderrStream() %% os.abort();
88 stderr.print(format ++ "\n", args) %% os.abort();
89 writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) %% os.abort();
90
91 os.abort();
92}
93
94const GREEN = "\x1b[32;1m";
95const WHITE = "\x1b[37;1m";
96const DIM = "\x1b[2m";
97const RESET = "\x1b[0m";
98
99error PathNotFound;
100error InvalidDebugInfo;
101
102pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool,
103 ignore_frame_count: usize) -> %void
104{
105 switch (builtin.object_format) {
106 builtin.ObjectFormat.elf => {
107 var stack_trace = ElfStackTrace {
108 .self_exe_file = undefined,
109 .elf = undefined,
110 .debug_info = undefined,
111 .debug_abbrev = undefined,
112 .debug_str = undefined,
113 .debug_line = undefined,
114 .debug_ranges = null,
115 .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
116 .compile_unit_list = ArrayList(CompileUnit).init(allocator),
117 };
118 const st = &stack_trace;
119 st.self_exe_file = %return os.openSelfExe();
120 defer st.self_exe_file.close();
121
122 %return st.elf.openFile(allocator, &st.self_exe_file);
123 defer st.elf.close();
124
125 st.debug_info = (%return st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;
126 st.debug_abbrev = (%return st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;
127 st.debug_str = (%return st.elf.findSection(".debug_str")) ?? return error.MissingDebugInfo;
128 st.debug_line = (%return st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;
129 st.debug_ranges = (%return st.elf.findSection(".debug_ranges"));
130 %return scanAllCompileUnits(st);
131
132 var ignored_count: usize = 0;
133
134 var fp = @ptrToInt(@frameAddress());
135 while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
136 if (ignored_count < ignore_frame_count) {
137 ignored_count += 1;
138 continue;
139 }
140
141 const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
142
143 // TODO we really should be able to convert @sizeOf(usize) * 2 to a string literal
144 // at compile time. I'll call it issue #313
145 const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}";
146
147 const compile_unit = findCompileUnit(st, return_address) %% {
148 %return out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
149 return_address);
150 continue;
151 };
152 const compile_unit_name = %return compile_unit.die.getAttrString(st, DW.AT_name);
153 if (getLineNumberInfo(st, compile_unit, usize(return_address) - 1)) |line_info| {
154 defer line_info.deinit();
155 %return out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++
156 DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
157 line_info.file_name, line_info.line, line_info.column,
158 return_address, compile_unit_name);
159 if (printLineFromFile(st.allocator(), out_stream, line_info)) {
160 if (line_info.column == 0) {
161 %return out_stream.write("\n");
162 } else {
163 {var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) {
164 %return out_stream.writeByte(' ');
165 }}
166 %return out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
167 }
168 } else |err| switch (err) {
169 error.EndOfFile, error.PathNotFound => {},
170 else => return err,
171 }
172 } else |err| switch (err) {
173 error.MissingDebugInfo, error.InvalidDebugInfo => {
174 %return out_stream.print(ptr_hex ++ " in ??? ({})\n",
175 return_address, compile_unit_name);
176 },
177 else => return err,
178 }
179 }
180 },
181 builtin.ObjectFormat.coff => {
182 %return out_stream.write("(stack trace unavailable for COFF object format)\n");
183 },
184 builtin.ObjectFormat.macho => {
185 %return out_stream.write("(stack trace unavailable for Mach-O object format)\n");
186 },
187 builtin.ObjectFormat.wasm => {
188 %return out_stream.write("(stack trace unavailable for WASM object format)\n");
189 },
190 builtin.ObjectFormat.unknown => {
191 %return out_stream.write("(stack trace unavailable for unknown object format)\n");
192 },
193 }
194}
195
196fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_info: &const LineInfo) -> %void {
197 var f = %return io.File.openRead(line_info.file_name, allocator);
198 defer f.close();
199 // TODO fstat and make sure that the file has the correct size
200
201 var buf: [os.page_size]u8 = undefined;
202 var line: usize = 1;
203 var column: usize = 1;
204 var abs_index: usize = 0;
205 while (true) {
206 const amt_read = %return f.read(buf[0..]);
207 const slice = buf[0..amt_read];
208
209 for (slice) |byte| {
210 if (line == line_info.line) {
211 %return out_stream.writeByte(byte);
212 if (byte == '\n') {
213 return;
214 }
215 }
216 if (byte == '\n') {
217 line += 1;
218 column = 1;
219 } else {
220 column += 1;
221 }
222 }
223
224 if (amt_read < buf.len)
225 return error.EndOfFile;
226 }
227}
228
229const ElfStackTrace = struct {
230 self_exe_file: io.File,
231 elf: elf.Elf,
232 debug_info: &elf.SectionHeader,
233 debug_abbrev: &elf.SectionHeader,
234 debug_str: &elf.SectionHeader,
235 debug_line: &elf.SectionHeader,
236 debug_ranges: ?&elf.SectionHeader,
237 abbrev_table_list: ArrayList(AbbrevTableHeader),
238 compile_unit_list: ArrayList(CompileUnit),
239
240 pub fn allocator(self: &const ElfStackTrace) -> &mem.Allocator {
241 return self.abbrev_table_list.allocator;
242 }
243
244 pub fn readString(self: &ElfStackTrace) -> %[]u8 {
245 var in_file_stream = io.FileInStream.init(&self.self_exe_file);
246 const in_stream = &in_file_stream.stream;
247 return readStringRaw(self.allocator(), in_stream);
248 }
249};
250
251const PcRange = struct {
252 start: u64,
253 end: u64,
254};
255
256const CompileUnit = struct {
257 version: u16,
258 is_64: bool,
259 die: &Die,
260 index: usize,
261 pc_range: ?PcRange,
262};
263
264const AbbrevTable = ArrayList(AbbrevTableEntry);
265
266const AbbrevTableHeader = struct {
267 // offset from .debug_abbrev
268 offset: u64,
269 table: AbbrevTable,
270};
271
272const AbbrevTableEntry = struct {
273 has_children: bool,
274 abbrev_code: u64,
275 tag_id: u64,
276 attrs: ArrayList(AbbrevAttr),
277};
278
279const AbbrevAttr = struct {
280 attr_id: u64,
281 form_id: u64,
282};
283
284const FormValue = union(enum) {
285 Address: u64,
286 Block: []u8,
287 Const: Constant,
288 ExprLoc: []u8,
289 Flag: bool,
290 SecOffset: u64,
291 Ref: []u8,
292 RefAddr: u64,
293 RefSig8: u64,
294 String: []u8,
295 StrPtr: u64,
296};
297
298const Constant = struct {
299 payload: []u8,
300 signed: bool,
301
302 fn asUnsignedLe(self: &const Constant) -> %u64 {
303 if (self.payload.len > @sizeOf(u64))
304 return error.InvalidDebugInfo;
305 if (self.signed)
306 return error.InvalidDebugInfo;
307 return mem.readInt(self.payload, u64, builtin.Endian.Little);
308 }
309};
310
311const Die = struct {
312 tag_id: u64,
313 has_children: bool,
314 attrs: ArrayList(Attr),
315
316 const Attr = struct {
317 id: u64,
318 value: FormValue,
319 };
320
321 fn getAttr(self: &const Die, id: u64) -> ?&const FormValue {
322 for (self.attrs.toSliceConst()) |*attr| {
323 if (attr.id == id)
324 return &attr.value;
325 }
326 return null;
327 }
328
329 fn getAttrAddr(self: &const Die, id: u64) -> %u64 {
330 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
331 return switch (*form_value) {
332 FormValue.Address => |value| value,
333 else => error.InvalidDebugInfo,
334 };
335 }
336
337 fn getAttrSecOffset(self: &const Die, id: u64) -> %u64 {
338 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
339 return switch (*form_value) {
340 FormValue.Const => |value| value.asUnsignedLe(),
341 FormValue.SecOffset => |value| value,
342 else => error.InvalidDebugInfo,
343 };
344 }
345
346 fn getAttrUnsignedLe(self: &const Die, id: u64) -> %u64 {
347 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
348 return switch (*form_value) {
349 FormValue.Const => |value| value.asUnsignedLe(),
350 else => error.InvalidDebugInfo,
351 };
352 }
353
354 fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) -> %[]u8 {
355 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
356 return switch (*form_value) {
357 FormValue.String => |value| value,
358 FormValue.StrPtr => |offset| getString(st, offset),
359 else => error.InvalidDebugInfo,
360 };
361 }
362};
363
364const FileEntry = struct {
365 file_name: []const u8,
366 dir_index: usize,
367 mtime: usize,
368 len_bytes: usize,
369};
370
371const LineInfo = struct {
372 line: usize,
373 column: usize,
374 file_name: []u8,
375 allocator: &mem.Allocator,
376
377 fn deinit(self: &const LineInfo) {
378 self.allocator.free(self.file_name);
379 }
380};
381
382const LineNumberProgram = struct {
383 address: usize,
384 file: usize,
385 line: isize,
386 column: usize,
387 is_stmt: bool,
388 basic_block: bool,
389 end_sequence: bool,
390
391 target_address: usize,
392 include_dirs: []const []const u8,
393 file_entries: &ArrayList(FileEntry),
394
395 prev_address: usize,
396 prev_file: usize,
397 prev_line: isize,
398 prev_column: usize,
399 prev_is_stmt: bool,
400 prev_basic_block: bool,
401 prev_end_sequence: bool,
402
403 pub fn init(is_stmt: bool, include_dirs: []const []const u8,
404 file_entries: &ArrayList(FileEntry), target_address: usize) -> LineNumberProgram
405 {
406 return LineNumberProgram {
407 .address = 0,
408 .file = 1,
409 .line = 1,
410 .column = 0,
411 .is_stmt = is_stmt,
412 .basic_block = false,
413 .end_sequence = false,
414 .include_dirs = include_dirs,
415 .file_entries = file_entries,
416 .target_address = target_address,
417 .prev_address = 0,
418 .prev_file = undefined,
419 .prev_line = undefined,
420 .prev_column = undefined,
421 .prev_is_stmt = undefined,
422 .prev_basic_block = undefined,
423 .prev_end_sequence = undefined,
424 };
425 }
426
427 pub fn checkLineMatch(self: &LineNumberProgram) -> %?LineInfo {
428 if (self.target_address >= self.prev_address and self.target_address < self.address) {
429 const file_entry = if (self.prev_file == 0) {
430 return error.MissingDebugInfo;
431 } else if (self.prev_file - 1 >= self.file_entries.len) {
432 return error.InvalidDebugInfo;
433 } else &self.file_entries.items[self.prev_file - 1];
434
435 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
436 return error.InvalidDebugInfo;
437 } else self.include_dirs[file_entry.dir_index];
438 const file_name = %return os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
439 %defer self.file_entries.allocator.free(file_name);
440 return LineInfo {
441 .line = if (self.prev_line >= 0) usize(self.prev_line) else 0,
442 .column = self.prev_column,
443 .file_name = file_name,
444 .allocator = self.file_entries.allocator,
445 };
446 }
447
448 self.prev_address = self.address;
449 self.prev_file = self.file;
450 self.prev_line = self.line;
451 self.prev_column = self.column;
452 self.prev_is_stmt = self.is_stmt;
453 self.prev_basic_block = self.basic_block;
454 self.prev_end_sequence = self.end_sequence;
455 return null;
456 }
457};
458
459fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) -> %[]u8 {
460 var buf = ArrayList(u8).init(allocator);
461 while (true) {
462 const byte = %return in_stream.readByte();
463 if (byte == 0)
464 break;
465 %return buf.append(byte);
466 }
467 return buf.toSlice();
468}
469
470fn getString(st: &ElfStackTrace, offset: u64) -> %[]u8 {
471 const pos = st.debug_str.offset + offset;
472 %return st.self_exe_file.seekTo(pos);
473 return st.readString();
474}
475
476fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %[]u8 {
477 const buf = %return global_allocator.alloc(u8, size);
478 %defer global_allocator.free(buf);
479 if ((%return in_stream.read(buf)) < size) return error.EndOfFile;
480 return buf;
481}
482
483fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
484 const buf = %return readAllocBytes(allocator, in_stream, size);
485 return FormValue { .Block = buf };
486}
487
488fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
489 const block_len = %return in_stream.readVarInt(builtin.Endian.Little, usize, size);
490 return parseFormValueBlockLen(allocator, in_stream, block_len);
491}
492
493fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue {
494 return FormValue { .Const = Constant {
495 .signed = signed,
496 .payload = %return readAllocBytes(allocator, in_stream, size),
497 }};
498}
499
500fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) -> %u64 {
501 return if (is_64) %return in_stream.readIntLe(u64)
502 else u64(%return in_stream.readIntLe(u32)) ;
503}
504
505fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 {
506 return if (@sizeOf(usize) == 4) u64(%return in_stream.readIntLe(u32))
507 else if (@sizeOf(usize) == 8) %return in_stream.readIntLe(u64)
508 else unreachable;
509}
510
511fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
512 const buf = %return readAllocBytes(allocator, in_stream, size);
513 return FormValue { .Ref = buf };
514}
515
516fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptime T: type) -> %FormValue {
517 const block_len = %return in_stream.readIntLe(T);
518 return parseFormValueRefLen(allocator, in_stream, block_len);
519}
520
521fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u64, is_64: bool) -> %FormValue {
522 return switch (form_id) {
523 DW.FORM_addr => FormValue { .Address = %return parseFormValueTargetAddrSize(in_stream) },
524 DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
525 DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
526 DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
527 DW.FORM_block => x: {
528 const block_len = %return readULeb128(in_stream);
529 return parseFormValueBlockLen(allocator, in_stream, block_len);
530 },
531 DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
532 DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
533 DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
534 DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
535 DW.FORM_udata, DW.FORM_sdata => {
536 const block_len = %return readULeb128(in_stream);
537 const signed = form_id == DW.FORM_sdata;
538 return parseFormValueConstant(allocator, in_stream, signed, block_len);
539 },
540 DW.FORM_exprloc => {
541 const size = %return readULeb128(in_stream);
542 const buf = %return readAllocBytes(allocator, in_stream, size);
543 return FormValue { .ExprLoc = buf };
544 },
545 DW.FORM_flag => FormValue { .Flag = (%return in_stream.readByte()) != 0 },
546 DW.FORM_flag_present => FormValue { .Flag = true },
547 DW.FORM_sec_offset => FormValue { .SecOffset = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
548
549 DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
550 DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
551 DW.FORM_ref4 => parseFormValueRef(allocator, in_stream, u32),
552 DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64),
553 DW.FORM_ref_udata => {
554 const ref_len = %return readULeb128(in_stream);
555 return parseFormValueRefLen(allocator, in_stream, ref_len);
556 },
557
558 DW.FORM_ref_addr => FormValue { .RefAddr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
559 DW.FORM_ref_sig8 => FormValue { .RefSig8 = %return in_stream.readIntLe(u64) },
560
561 DW.FORM_string => FormValue { .String = %return readStringRaw(allocator, in_stream) },
562 DW.FORM_strp => FormValue { .StrPtr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
563 DW.FORM_indirect => {
564 const child_form_id = %return readULeb128(in_stream);
565 return parseFormValue(allocator, in_stream, child_form_id, is_64);
566 },
567 else => error.InvalidDebugInfo,
568 };
569}
570
571fn parseAbbrevTable(st: &ElfStackTrace) -> %AbbrevTable {
572 const in_file = &st.self_exe_file;
573 var in_file_stream = io.FileInStream.init(in_file);
574 const in_stream = &in_file_stream.stream;
575 var result = AbbrevTable.init(st.allocator());
576 while (true) {
577 const abbrev_code = %return readULeb128(in_stream);
578 if (abbrev_code == 0)
579 return result;
580 %return result.append(AbbrevTableEntry {
581 .abbrev_code = abbrev_code,
582 .tag_id = %return readULeb128(in_stream),
583 .has_children = (%return in_stream.readByte()) == DW.CHILDREN_yes,
584 .attrs = ArrayList(AbbrevAttr).init(st.allocator()),
585 });
586 const attrs = &result.items[result.len - 1].attrs;
587
588 while (true) {
589 const attr_id = %return readULeb128(in_stream);
590 const form_id = %return readULeb128(in_stream);
591 if (attr_id == 0 and form_id == 0)
592 break;
593 %return attrs.append(AbbrevAttr {
594 .attr_id = attr_id,
595 .form_id = form_id,
596 });
597 }
598 }
599}
600
601/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
602/// seeks in the stream and parses it.
603fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) -> %&const AbbrevTable {
604 for (st.abbrev_table_list.toSlice()) |*header| {
605 if (header.offset == abbrev_offset) {
606 return &header.table;
607 }
608 }
609 %return st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset);
610 %return st.abbrev_table_list.append(AbbrevTableHeader {
611 .offset = abbrev_offset,
612 .table = %return parseAbbrevTable(st),
613 });
614 return &st.abbrev_table_list.items[st.abbrev_table_list.len - 1].table;
615}
616
617fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) -> ?&const AbbrevTableEntry {
618 for (abbrev_table.toSliceConst()) |*table_entry| {
619 if (table_entry.abbrev_code == abbrev_code)
620 return table_entry;
621 }
622 return null;
623}
624
625fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) -> %Die {
626 const in_file = &st.self_exe_file;
627 var in_file_stream = io.FileInStream.init(in_file);
628 const in_stream = &in_file_stream.stream;
629 const abbrev_code = %return readULeb128(in_stream);
630 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) ?? return error.InvalidDebugInfo;
631
632 var result = Die {
633 .tag_id = table_entry.tag_id,
634 .has_children = table_entry.has_children,
635 .attrs = ArrayList(Die.Attr).init(st.allocator()),
636 };
637 %return result.attrs.resize(table_entry.attrs.len);
638 for (table_entry.attrs.toSliceConst()) |attr, i| {
639 result.attrs.items[i] = Die.Attr {
640 .id = attr.attr_id,
641 .value = %return parseFormValue(st.allocator(), in_stream, attr.form_id, is_64),
642 };
643 }
644 return result;
645}
646
647fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, target_address: usize) -> %LineInfo {
648 const compile_unit_cwd = %return compile_unit.die.getAttrString(st, DW.AT_comp_dir);
649
650 const in_file = &st.self_exe_file;
651 const debug_line_end = st.debug_line.offset + st.debug_line.size;
652 var this_offset = st.debug_line.offset;
653 var this_index: usize = 0;
654
655 var in_file_stream = io.FileInStream.init(in_file);
656 const in_stream = &in_file_stream.stream;
657
658 while (this_offset < debug_line_end) : (this_index += 1) {
659 %return in_file.seekTo(this_offset);
660
661 var is_64: bool = undefined;
662 const unit_length = %return readInitialLength(in_stream, &is_64);
663 if (unit_length == 0)
664 return error.MissingDebugInfo;
665 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
666
667 if (compile_unit.index != this_index) {
668 this_offset += next_offset;
669 continue;
670 }
671
672 const version = %return in_stream.readInt(st.elf.endian, u16);
673 if (version != 2) return error.InvalidDebugInfo;
674
675 const prologue_length = %return in_stream.readInt(st.elf.endian, u32);
676 const prog_start_offset = (%return in_file.getPos()) + prologue_length;
677
678 const minimum_instruction_length = %return in_stream.readByte();
679 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
680
681 const default_is_stmt = (%return in_stream.readByte()) != 0;
682 const line_base = %return in_stream.readByteSigned();
683
684 const line_range = %return in_stream.readByte();
685 if (line_range == 0)
686 return error.InvalidDebugInfo;
687
688 const opcode_base = %return in_stream.readByte();
689
690 const standard_opcode_lengths = %return st.allocator().alloc(u8, opcode_base - 1);
691
692 {var i: usize = 0; while (i < opcode_base - 1) : (i += 1) {
693 standard_opcode_lengths[i] = %return in_stream.readByte();
694 }}
695
696 var include_directories = ArrayList([]u8).init(st.allocator());
697 %return include_directories.append(compile_unit_cwd);
698 while (true) {
699 const dir = %return st.readString();
700 if (dir.len == 0)
701 break;
702 %return include_directories.append(dir);
703 }
704
705 var file_entries = ArrayList(FileEntry).init(st.allocator());
706 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(),
707 &file_entries, target_address);
708
709 while (true) {
710 const file_name = %return st.readString();
711 if (file_name.len == 0)
712 break;
713 const dir_index = %return readULeb128(in_stream);
714 const mtime = %return readULeb128(in_stream);
715 const len_bytes = %return readULeb128(in_stream);
716 %return file_entries.append(FileEntry {
717 .file_name = file_name,
718 .dir_index = dir_index,
719 .mtime = mtime,
720 .len_bytes = len_bytes,
721 });
722 }
723
724 %return in_file.seekTo(prog_start_offset);
725
726 while (true) {
727 const opcode = %return in_stream.readByte();
728
729 var sub_op: u8 = undefined; // TODO move this to the correct scope and fix the compiler crash
730 if (opcode == DW.LNS_extended_op) {
731 const op_size = %return readULeb128(in_stream);
732 if (op_size < 1)
733 return error.InvalidDebugInfo;
734 sub_op = %return in_stream.readByte();
735 switch (sub_op) {
736 DW.LNE_end_sequence => {
737 prog.end_sequence = true;
738 if (%return prog.checkLineMatch()) |info| return info;
739 return error.MissingDebugInfo;
740 },
741 DW.LNE_set_address => {
742 const addr = %return in_stream.readInt(st.elf.endian, usize);
743 prog.address = addr;
744 },
745 DW.LNE_define_file => {
746 const file_name = %return st.readString();
747 const dir_index = %return readULeb128(in_stream);
748 const mtime = %return readULeb128(in_stream);
749 const len_bytes = %return readULeb128(in_stream);
750 %return file_entries.append(FileEntry {
751 .file_name = file_name,
752 .dir_index = dir_index,
753 .mtime = mtime,
754 .len_bytes = len_bytes,
755 });
756 },
757 else => {
758 const fwd_amt = math.cast(isize, op_size - 1) %% return error.InvalidDebugInfo;
759 %return in_file.seekForward(fwd_amt);
760 },
761 }
762 } else if (opcode >= opcode_base) {
763 // special opcodes
764 const adjusted_opcode = opcode - opcode_base;
765 const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
766 const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
767 prog.line += inc_line;
768 prog.address += inc_addr;
769 if (%return prog.checkLineMatch()) |info| return info;
770 prog.basic_block = false;
771 } else {
772 switch (opcode) {
773 DW.LNS_copy => {
774 if (%return prog.checkLineMatch()) |info| return info;
775 prog.basic_block = false;
776 },
777 DW.LNS_advance_pc => {
778 const arg = %return readULeb128(in_stream);
779 prog.address += arg * minimum_instruction_length;
780 },
781 DW.LNS_advance_line => {
782 const arg = %return readILeb128(in_stream);
783 prog.line += arg;
784 },
785 DW.LNS_set_file => {
786 const arg = %return readULeb128(in_stream);
787 prog.file = arg;
788 },
789 DW.LNS_set_column => {
790 const arg = %return readULeb128(in_stream);
791 prog.column = arg;
792 },
793 DW.LNS_negate_stmt => {
794 prog.is_stmt = !prog.is_stmt;
795 },
796 DW.LNS_set_basic_block => {
797 prog.basic_block = true;
798 },
799 DW.LNS_const_add_pc => {
800 const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
801 prog.address += inc_addr;
802 },
803 DW.LNS_fixed_advance_pc => {
804 const arg = %return in_stream.readInt(st.elf.endian, u16);
805 prog.address += arg;
806 },
807 DW.LNS_set_prologue_end => {
808 },
809 else => {
810 if (opcode - 1 >= standard_opcode_lengths.len)
811 return error.InvalidDebugInfo;
812 const len_bytes = standard_opcode_lengths[opcode - 1];
813 %return in_file.seekForward(len_bytes);
814 },
815 }
816 }
817 }
818
819 this_offset += next_offset;
820 }
821
822 return error.MissingDebugInfo;
823}
824
825fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
826 const debug_info_end = st.debug_info.offset + st.debug_info.size;
827 var this_unit_offset = st.debug_info.offset;
828 var cu_index: usize = 0;
829
830 var in_file_stream = io.FileInStream.init(&st.self_exe_file);
831 const in_stream = &in_file_stream.stream;
832
833 while (this_unit_offset < debug_info_end) {
834 %return st.self_exe_file.seekTo(this_unit_offset);
835
836 var is_64: bool = undefined;
837 const unit_length = %return readInitialLength(in_stream, &is_64);
838 if (unit_length == 0)
839 return;
840 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
841
842 const version = %return in_stream.readInt(st.elf.endian, u16);
843 if (version < 2 or version > 5) return error.InvalidDebugInfo;
844
845 const debug_abbrev_offset =
846 if (is_64) %return in_stream.readInt(st.elf.endian, u64)
847 else %return in_stream.readInt(st.elf.endian, u32);
848
849 const address_size = %return in_stream.readByte();
850 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
851
852 const compile_unit_pos = %return st.self_exe_file.getPos();
853 const abbrev_table = %return getAbbrevTable(st, debug_abbrev_offset);
854
855 %return st.self_exe_file.seekTo(compile_unit_pos);
856
857 const compile_unit_die = %return st.allocator().create(Die);
858 *compile_unit_die = %return parseDie(st, abbrev_table, is_64);
859
860 if (compile_unit_die.tag_id != DW.TAG_compile_unit)
861 return error.InvalidDebugInfo;
862
863 const pc_range = x: {
864 if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
865 if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
866 const pc_end = switch (*high_pc_value) {
867 FormValue.Address => |value| value,
868 FormValue.Const => |value| b: {
869 const offset = %return value.asUnsignedLe();
870 break :b (low_pc + offset);
871 },
872 else => return error.InvalidDebugInfo,
873 };
874 break :x PcRange {
875 .start = low_pc,
876 .end = pc_end,
877 };
878 } else {
879 break :x null;
880 }
881 } else |err| {
882 if (err != error.MissingDebugInfo)
883 return err;
884 break :x null;
885 }
886 };
887
888 %return st.compile_unit_list.append(CompileUnit {
889 .version = version,
890 .is_64 = is_64,
891 .pc_range = pc_range,
892 .die = compile_unit_die,
893 .index = cu_index,
894 });
895
896 this_unit_offset += next_offset;
897 cu_index += 1;
898 }
899}
900
901fn findCompileUnit(st: &ElfStackTrace, target_address: u64) -> %&const CompileUnit {
902 var in_file_stream = io.FileInStream.init(&st.self_exe_file);
903 const in_stream = &in_file_stream.stream;
904 for (st.compile_unit_list.toSlice()) |*compile_unit| {
905 if (compile_unit.pc_range) |range| {
906 if (target_address >= range.start and target_address < range.end)
907 return compile_unit;
908 }
909 if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
910 var base_address: usize = 0;
911 if (st.debug_ranges) |debug_ranges| {
912 %return st.self_exe_file.seekTo(debug_ranges.offset + ranges_offset);
913 while (true) {
914 const begin_addr = %return in_stream.readIntLe(usize);
915 const end_addr = %return in_stream.readIntLe(usize);
916 if (begin_addr == 0 and end_addr == 0) {
917 break;
918 }
919 if (begin_addr == @maxValue(usize)) {
920 base_address = begin_addr;
921 continue;
922 }
923 if (target_address >= begin_addr and target_address < end_addr) {
924 return compile_unit;
925 }
926 }
927 }
928 } else |err| {
929 if (err != error.MissingDebugInfo)
930 return err;
931 continue;
932 }
933 }
934 return error.MissingDebugInfo;
935}
936
937fn readInitialLength(in_stream: &io.InStream, is_64: &bool) -> %u64 {
938 const first_32_bits = %return in_stream.readIntLe(u32);
939 *is_64 = (first_32_bits == 0xffffffff);
940 if (*is_64) {
941 return in_stream.readIntLe(u64);
942 } else {
943 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
944 return u64(first_32_bits);
945 }
946}
947
948fn readULeb128(in_stream: &io.InStream) -> %u64 {
949 var result: u64 = 0;
950 var shift: usize = 0;
951
952 while (true) {
953 const byte = %return in_stream.readByte();
954
955 var operand: u64 = undefined;
956
957 if (@shlWithOverflow(u64, byte & 0b01111111, u6(shift), &operand))
958 return error.InvalidDebugInfo;
959
960 result |= operand;
961
962 if ((byte & 0b10000000) == 0)
963 return result;
964
965 shift += 7;
966 }
967}
968
969fn readILeb128(in_stream: &io.InStream) -> %i64 {
970 var result: i64 = 0;
971 var shift: usize = 0;
972
973 while (true) {
974 const byte = %return in_stream.readByte();
975
976 var operand: i64 = undefined;
977
978 if (@shlWithOverflow(i64, byte & 0b01111111, u6(shift), &operand))
979 return error.InvalidDebugInfo;
980
981 result |= operand;
982 shift += 7;
983
984 if ((byte & 0b10000000) == 0) {
985 if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0)
986 result |= -(i64(1) << u6(shift));
987 return result;
988 }
989 }
990}
991
992pub const global_allocator = &global_fixed_allocator.allocator;
993var global_fixed_allocator = mem.FixedBufferAllocator.init(global_allocator_mem[0..]);
994var global_allocator_mem: [100 * 1024]u8 = undefined;
995
996/// Allocator that fails after N allocations, useful for making sure out of
997/// memory conditions are handled correctly.
998pub const FailingAllocator = struct {
999 allocator: mem.Allocator,
1000 index: usize,
1001 fail_index: usize,
1002 internal_allocator: &mem.Allocator,
1003 allocated_bytes: usize,
1004
1005 pub fn init(allocator: &mem.Allocator, fail_index: usize) -> FailingAllocator {
1006 return FailingAllocator {
1007 .internal_allocator = allocator,
1008 .fail_index = fail_index,
1009 .index = 0,
1010 .allocated_bytes = 0,
1011 .allocator = mem.Allocator {
1012 .allocFn = alloc,
1013 .reallocFn = realloc,
1014 .freeFn = free,
1015 },
1016 };
1017 }
1018
1019 fn alloc(allocator: &mem.Allocator, n: usize, alignment: u29) -> %[]u8 {
1020 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
1021 if (self.index == self.fail_index) {
1022 return error.OutOfMemory;
1023 }
1024 self.index += 1;
1025 const result = %return self.internal_allocator.allocFn(self.internal_allocator, n, alignment);
1026 self.allocated_bytes += result.len;
1027 return result;
1028 }
1029
1030 fn realloc(allocator: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 {
1031 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
1032 if (new_size <= old_mem.len) {
1033 self.allocated_bytes -= old_mem.len - new_size;
1034 return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, new_size, alignment);
1035 }
1036 if (self.index == self.fail_index) {
1037 return error.OutOfMemory;
1038 }
1039 self.index += 1;
1040 const result = %return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, new_size, alignment);
1041 self.allocated_bytes += new_size - old_mem.len;
1042 return result;
1043 }
1044
1045 fn free(allocator: &mem.Allocator, bytes: []u8) {
1046 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
1047 self.allocated_bytes -= bytes.len;
1048 return self.internal_allocator.freeFn(self.internal_allocator, bytes);
1049 }
1050};
std/debug/failing_allocator.zig created+64
......@@ -0,0 +1,64 @@
1const std = @import("../index.zig");
2const mem = std.mem;
3
4/// Allocator that fails after N allocations, useful for making sure out of
5/// memory conditions are handled correctly.
6pub const FailingAllocator = struct {
7 allocator: mem.Allocator,
8 index: usize,
9 fail_index: usize,
10 internal_allocator: &mem.Allocator,
11 allocated_bytes: usize,
12 freed_bytes: usize,
13 deallocations: usize,
14
15 pub fn init(allocator: &mem.Allocator, fail_index: usize) -> FailingAllocator {
16 return FailingAllocator {
17 .internal_allocator = allocator,
18 .fail_index = fail_index,
19 .index = 0,
20 .allocated_bytes = 0,
21 .freed_bytes = 0,
22 .deallocations = 0,
23 .allocator = mem.Allocator {
24 .allocFn = alloc,
25 .reallocFn = realloc,
26 .freeFn = free,
27 },
28 };
29 }
30
31 fn alloc(allocator: &mem.Allocator, n: usize, alignment: u29) -> %[]u8 {
32 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
33 if (self.index == self.fail_index) {
34 return error.OutOfMemory;
35 }
36 const result = %return self.internal_allocator.allocFn(self.internal_allocator, n, alignment);
37 self.allocated_bytes += result.len;
38 self.index += 1;
39 return result;
40 }
41
42 fn realloc(allocator: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 {
43 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
44 if (new_size <= old_mem.len) {
45 self.freed_bytes += old_mem.len - new_size;
46 return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, new_size, alignment);
47 }
48 if (self.index == self.fail_index) {
49 return error.OutOfMemory;
50 }
51 const result = %return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, new_size, alignment);
52 self.allocated_bytes += new_size - old_mem.len;
53 self.deallocations += 1;
54 self.index += 1;
55 return result;
56 }
57
58 fn free(allocator: &mem.Allocator, bytes: []u8) {
59 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
60 self.freed_bytes += bytes.len;
61 self.deallocations += 1;
62 return self.internal_allocator.freeFn(self.internal_allocator, bytes);
63 }
64};
std/debug/index.zig created+994
......@@ -0,0 +1,994 @@
1const std = @import("../index.zig");
2const math = std.math;
3const mem = std.mem;
4const io = std.io;
5const os = std.os;
6const elf = std.elf;
7const DW = std.dwarf;
8const ArrayList = std.ArrayList;
9const builtin = @import("builtin");
10
11error MissingDebugInfo;
12error InvalidDebugInfo;
13error UnsupportedDebugInfo;
14
15
16/// Tries to write to stderr, unbuffered, and ignores any error returned.
17/// Does not append a newline.
18/// TODO atomic/multithread support
19var stderr_file: io.File = undefined;
20var stderr_file_out_stream: io.FileOutStream = undefined;
21var stderr_stream: ?&io.OutStream = null;
22pub fn warn(comptime fmt: []const u8, args: ...) {
23 const stderr = getStderrStream() %% return;
24 stderr.print(fmt, args) %% return;
25}
26fn getStderrStream() -> %&io.OutStream {
27 if (stderr_stream) |st| {
28 return st;
29 } else {
30 stderr_file = %return io.getStdErr();
31 stderr_file_out_stream = io.FileOutStream.init(&stderr_file);
32 const st = &stderr_file_out_stream.stream;
33 stderr_stream = st;
34 return st;
35 }
36}
37
38/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
39pub fn dumpStackTrace() {
40 const stderr = getStderrStream() %% return;
41 writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) %% return;
42}
43
44/// This function invokes undefined behavior when `ok` is `false`.
45/// In Debug and ReleaseSafe modes, calls to this function are always
46/// generated, and the `unreachable` statement triggers a panic.
47/// In ReleaseFast and ReleaseSmall modes, calls to this function can be
48/// optimized away.
49pub fn assert(ok: bool) {
50 if (!ok) {
51 // In ReleaseFast test mode, we still want assert(false) to crash, so
52 // we insert an explicit call to @panic instead of unreachable.
53 // TODO we should use `assertOrPanic` in tests and remove this logic.
54 if (builtin.is_test) {
55 @panic("assertion failure");
56 } else {
57 unreachable; // assertion failure
58 }
59 }
60}
61
62/// Call this function when you want to panic if the condition is not true.
63/// If `ok` is `false`, this function will panic in every release mode.
64pub fn assertOrPanic(ok: bool) {
65 if (!ok) {
66 @panic("assertion failure");
67 }
68}
69
70var panicking = false;
71/// This is the default panic implementation.
72pub fn panic(comptime format: []const u8, args: ...) -> noreturn {
73 // TODO an intrinsic that labels this as unlikely to be reached
74
75 // TODO
76 // if (@atomicRmw(AtomicOp.XChg, &panicking, true, AtomicOrder.SeqCst)) { }
77 if (panicking) {
78 // Panicked during a panic.
79 // TODO detect if a different thread caused the panic, because in that case
80 // we would want to return here instead of calling abort, so that the thread
81 // which first called panic can finish printing a stack trace.
82 os.abort();
83 } else {
84 panicking = true;
85 }
86
87 const stderr = getStderrStream() %% os.abort();
88 stderr.print(format ++ "\n", args) %% os.abort();
89 writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) %% os.abort();
90
91 os.abort();
92}
93
94const GREEN = "\x1b[32;1m";
95const WHITE = "\x1b[37;1m";
96const DIM = "\x1b[2m";
97const RESET = "\x1b[0m";
98
99error PathNotFound;
100error InvalidDebugInfo;
101
102pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool,
103 ignore_frame_count: usize) -> %void
104{
105 switch (builtin.object_format) {
106 builtin.ObjectFormat.elf => {
107 var stack_trace = ElfStackTrace {
108 .self_exe_file = undefined,
109 .elf = undefined,
110 .debug_info = undefined,
111 .debug_abbrev = undefined,
112 .debug_str = undefined,
113 .debug_line = undefined,
114 .debug_ranges = null,
115 .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
116 .compile_unit_list = ArrayList(CompileUnit).init(allocator),
117 };
118 const st = &stack_trace;
119 st.self_exe_file = %return os.openSelfExe();
120 defer st.self_exe_file.close();
121
122 %return st.elf.openFile(allocator, &st.self_exe_file);
123 defer st.elf.close();
124
125 st.debug_info = (%return st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;
126 st.debug_abbrev = (%return st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;
127 st.debug_str = (%return st.elf.findSection(".debug_str")) ?? return error.MissingDebugInfo;
128 st.debug_line = (%return st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;
129 st.debug_ranges = (%return st.elf.findSection(".debug_ranges"));
130 %return scanAllCompileUnits(st);
131
132 var ignored_count: usize = 0;
133
134 var fp = @ptrToInt(@frameAddress());
135 while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
136 if (ignored_count < ignore_frame_count) {
137 ignored_count += 1;
138 continue;
139 }
140
141 const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
142
143 // TODO we really should be able to convert @sizeOf(usize) * 2 to a string literal
144 // at compile time. I'll call it issue #313
145 const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}";
146
147 const compile_unit = findCompileUnit(st, return_address) %% {
148 %return out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
149 return_address);
150 continue;
151 };
152 const compile_unit_name = %return compile_unit.die.getAttrString(st, DW.AT_name);
153 if (getLineNumberInfo(st, compile_unit, usize(return_address) - 1)) |line_info| {
154 defer line_info.deinit();
155 %return out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++
156 DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
157 line_info.file_name, line_info.line, line_info.column,
158 return_address, compile_unit_name);
159 if (printLineFromFile(st.allocator(), out_stream, line_info)) {
160 if (line_info.column == 0) {
161 %return out_stream.write("\n");
162 } else {
163 {var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) {
164 %return out_stream.writeByte(' ');
165 }}
166 %return out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
167 }
168 } else |err| switch (err) {
169 error.EndOfFile, error.PathNotFound => {},
170 else => return err,
171 }
172 } else |err| switch (err) {
173 error.MissingDebugInfo, error.InvalidDebugInfo => {
174 %return out_stream.print(ptr_hex ++ " in ??? ({})\n",
175 return_address, compile_unit_name);
176 },
177 else => return err,
178 }
179 }
180 },
181 builtin.ObjectFormat.coff => {
182 %return out_stream.write("(stack trace unavailable for COFF object format)\n");
183 },
184 builtin.ObjectFormat.macho => {
185 %return out_stream.write("(stack trace unavailable for Mach-O object format)\n");
186 },
187 builtin.ObjectFormat.wasm => {
188 %return out_stream.write("(stack trace unavailable for WASM object format)\n");
189 },
190 builtin.ObjectFormat.unknown => {
191 %return out_stream.write("(stack trace unavailable for unknown object format)\n");
192 },
193 }
194}
195
196fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_info: &const LineInfo) -> %void {
197 var f = %return io.File.openRead(line_info.file_name, allocator);
198 defer f.close();
199 // TODO fstat and make sure that the file has the correct size
200
201 var buf: [os.page_size]u8 = undefined;
202 var line: usize = 1;
203 var column: usize = 1;
204 var abs_index: usize = 0;
205 while (true) {
206 const amt_read = %return f.read(buf[0..]);
207 const slice = buf[0..amt_read];
208
209 for (slice) |byte| {
210 if (line == line_info.line) {
211 %return out_stream.writeByte(byte);
212 if (byte == '\n') {
213 return;
214 }
215 }
216 if (byte == '\n') {
217 line += 1;
218 column = 1;
219 } else {
220 column += 1;
221 }
222 }
223
224 if (amt_read < buf.len)
225 return error.EndOfFile;
226 }
227}
228
229const ElfStackTrace = struct {
230 self_exe_file: io.File,
231 elf: elf.Elf,
232 debug_info: &elf.SectionHeader,
233 debug_abbrev: &elf.SectionHeader,
234 debug_str: &elf.SectionHeader,
235 debug_line: &elf.SectionHeader,
236 debug_ranges: ?&elf.SectionHeader,
237 abbrev_table_list: ArrayList(AbbrevTableHeader),
238 compile_unit_list: ArrayList(CompileUnit),
239
240 pub fn allocator(self: &const ElfStackTrace) -> &mem.Allocator {
241 return self.abbrev_table_list.allocator;
242 }
243
244 pub fn readString(self: &ElfStackTrace) -> %[]u8 {
245 var in_file_stream = io.FileInStream.init(&self.self_exe_file);
246 const in_stream = &in_file_stream.stream;
247 return readStringRaw(self.allocator(), in_stream);
248 }
249};
250
251const PcRange = struct {
252 start: u64,
253 end: u64,
254};
255
256const CompileUnit = struct {
257 version: u16,
258 is_64: bool,
259 die: &Die,
260 index: usize,
261 pc_range: ?PcRange,
262};
263
264const AbbrevTable = ArrayList(AbbrevTableEntry);
265
266const AbbrevTableHeader = struct {
267 // offset from .debug_abbrev
268 offset: u64,
269 table: AbbrevTable,
270};
271
272const AbbrevTableEntry = struct {
273 has_children: bool,
274 abbrev_code: u64,
275 tag_id: u64,
276 attrs: ArrayList(AbbrevAttr),
277};
278
279const AbbrevAttr = struct {
280 attr_id: u64,
281 form_id: u64,
282};
283
284const FormValue = union(enum) {
285 Address: u64,
286 Block: []u8,
287 Const: Constant,
288 ExprLoc: []u8,
289 Flag: bool,
290 SecOffset: u64,
291 Ref: []u8,
292 RefAddr: u64,
293 RefSig8: u64,
294 String: []u8,
295 StrPtr: u64,
296};
297
298const Constant = struct {
299 payload: []u8,
300 signed: bool,
301
302 fn asUnsignedLe(self: &const Constant) -> %u64 {
303 if (self.payload.len > @sizeOf(u64))
304 return error.InvalidDebugInfo;
305 if (self.signed)
306 return error.InvalidDebugInfo;
307 return mem.readInt(self.payload, u64, builtin.Endian.Little);
308 }
309};
310
311const Die = struct {
312 tag_id: u64,
313 has_children: bool,
314 attrs: ArrayList(Attr),
315
316 const Attr = struct {
317 id: u64,
318 value: FormValue,
319 };
320
321 fn getAttr(self: &const Die, id: u64) -> ?&const FormValue {
322 for (self.attrs.toSliceConst()) |*attr| {
323 if (attr.id == id)
324 return &attr.value;
325 }
326 return null;
327 }
328
329 fn getAttrAddr(self: &const Die, id: u64) -> %u64 {
330 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
331 return switch (*form_value) {
332 FormValue.Address => |value| value,
333 else => error.InvalidDebugInfo,
334 };
335 }
336
337 fn getAttrSecOffset(self: &const Die, id: u64) -> %u64 {
338 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
339 return switch (*form_value) {
340 FormValue.Const => |value| value.asUnsignedLe(),
341 FormValue.SecOffset => |value| value,
342 else => error.InvalidDebugInfo,
343 };
344 }
345
346 fn getAttrUnsignedLe(self: &const Die, id: u64) -> %u64 {
347 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
348 return switch (*form_value) {
349 FormValue.Const => |value| value.asUnsignedLe(),
350 else => error.InvalidDebugInfo,
351 };
352 }
353
354 fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) -> %[]u8 {
355 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
356 return switch (*form_value) {
357 FormValue.String => |value| value,
358 FormValue.StrPtr => |offset| getString(st, offset),
359 else => error.InvalidDebugInfo,
360 };
361 }
362};
363
364const FileEntry = struct {
365 file_name: []const u8,
366 dir_index: usize,
367 mtime: usize,
368 len_bytes: usize,
369};
370
371const LineInfo = struct {
372 line: usize,
373 column: usize,
374 file_name: []u8,
375 allocator: &mem.Allocator,
376
377 fn deinit(self: &const LineInfo) {
378 self.allocator.free(self.file_name);
379 }
380};
381
382const LineNumberProgram = struct {
383 address: usize,
384 file: usize,
385 line: isize,
386 column: usize,
387 is_stmt: bool,
388 basic_block: bool,
389 end_sequence: bool,
390
391 target_address: usize,
392 include_dirs: []const []const u8,
393 file_entries: &ArrayList(FileEntry),
394
395 prev_address: usize,
396 prev_file: usize,
397 prev_line: isize,
398 prev_column: usize,
399 prev_is_stmt: bool,
400 prev_basic_block: bool,
401 prev_end_sequence: bool,
402
403 pub fn init(is_stmt: bool, include_dirs: []const []const u8,
404 file_entries: &ArrayList(FileEntry), target_address: usize) -> LineNumberProgram
405 {
406 return LineNumberProgram {
407 .address = 0,
408 .file = 1,
409 .line = 1,
410 .column = 0,
411 .is_stmt = is_stmt,
412 .basic_block = false,
413 .end_sequence = false,
414 .include_dirs = include_dirs,
415 .file_entries = file_entries,
416 .target_address = target_address,
417 .prev_address = 0,
418 .prev_file = undefined,
419 .prev_line = undefined,
420 .prev_column = undefined,
421 .prev_is_stmt = undefined,
422 .prev_basic_block = undefined,
423 .prev_end_sequence = undefined,
424 };
425 }
426
427 pub fn checkLineMatch(self: &LineNumberProgram) -> %?LineInfo {
428 if (self.target_address >= self.prev_address and self.target_address < self.address) {
429 const file_entry = if (self.prev_file == 0) {
430 return error.MissingDebugInfo;
431 } else if (self.prev_file - 1 >= self.file_entries.len) {
432 return error.InvalidDebugInfo;
433 } else &self.file_entries.items[self.prev_file - 1];
434
435 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
436 return error.InvalidDebugInfo;
437 } else self.include_dirs[file_entry.dir_index];
438 const file_name = %return os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
439 %defer self.file_entries.allocator.free(file_name);
440 return LineInfo {
441 .line = if (self.prev_line >= 0) usize(self.prev_line) else 0,
442 .column = self.prev_column,
443 .file_name = file_name,
444 .allocator = self.file_entries.allocator,
445 };
446 }
447
448 self.prev_address = self.address;
449 self.prev_file = self.file;
450 self.prev_line = self.line;
451 self.prev_column = self.column;
452 self.prev_is_stmt = self.is_stmt;
453 self.prev_basic_block = self.basic_block;
454 self.prev_end_sequence = self.end_sequence;
455 return null;
456 }
457};
458
459fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) -> %[]u8 {
460 var buf = ArrayList(u8).init(allocator);
461 while (true) {
462 const byte = %return in_stream.readByte();
463 if (byte == 0)
464 break;
465 %return buf.append(byte);
466 }
467 return buf.toSlice();
468}
469
470fn getString(st: &ElfStackTrace, offset: u64) -> %[]u8 {
471 const pos = st.debug_str.offset + offset;
472 %return st.self_exe_file.seekTo(pos);
473 return st.readString();
474}
475
476fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %[]u8 {
477 const buf = %return global_allocator.alloc(u8, size);
478 %defer global_allocator.free(buf);
479 if ((%return in_stream.read(buf)) < size) return error.EndOfFile;
480 return buf;
481}
482
483fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
484 const buf = %return readAllocBytes(allocator, in_stream, size);
485 return FormValue { .Block = buf };
486}
487
488fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
489 const block_len = %return in_stream.readVarInt(builtin.Endian.Little, usize, size);
490 return parseFormValueBlockLen(allocator, in_stream, block_len);
491}
492
493fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue {
494 return FormValue { .Const = Constant {
495 .signed = signed,
496 .payload = %return readAllocBytes(allocator, in_stream, size),
497 }};
498}
499
500fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) -> %u64 {
501 return if (is_64) %return in_stream.readIntLe(u64)
502 else u64(%return in_stream.readIntLe(u32)) ;
503}
504
505fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 {
506 return if (@sizeOf(usize) == 4) u64(%return in_stream.readIntLe(u32))
507 else if (@sizeOf(usize) == 8) %return in_stream.readIntLe(u64)
508 else unreachable;
509}
510
511fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
512 const buf = %return readAllocBytes(allocator, in_stream, size);
513 return FormValue { .Ref = buf };
514}
515
516fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptime T: type) -> %FormValue {
517 const block_len = %return in_stream.readIntLe(T);
518 return parseFormValueRefLen(allocator, in_stream, block_len);
519}
520
521fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u64, is_64: bool) -> %FormValue {
522 return switch (form_id) {
523 DW.FORM_addr => FormValue { .Address = %return parseFormValueTargetAddrSize(in_stream) },
524 DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
525 DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
526 DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
527 DW.FORM_block => x: {
528 const block_len = %return readULeb128(in_stream);
529 return parseFormValueBlockLen(allocator, in_stream, block_len);
530 },
531 DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
532 DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
533 DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
534 DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
535 DW.FORM_udata, DW.FORM_sdata => {
536 const block_len = %return readULeb128(in_stream);
537 const signed = form_id == DW.FORM_sdata;
538 return parseFormValueConstant(allocator, in_stream, signed, block_len);
539 },
540 DW.FORM_exprloc => {
541 const size = %return readULeb128(in_stream);
542 const buf = %return readAllocBytes(allocator, in_stream, size);
543 return FormValue { .ExprLoc = buf };
544 },
545 DW.FORM_flag => FormValue { .Flag = (%return in_stream.readByte()) != 0 },
546 DW.FORM_flag_present => FormValue { .Flag = true },
547 DW.FORM_sec_offset => FormValue { .SecOffset = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
548
549 DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
550 DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
551 DW.FORM_ref4 => parseFormValueRef(allocator, in_stream, u32),
552 DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64),
553 DW.FORM_ref_udata => {
554 const ref_len = %return readULeb128(in_stream);
555 return parseFormValueRefLen(allocator, in_stream, ref_len);
556 },
557
558 DW.FORM_ref_addr => FormValue { .RefAddr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
559 DW.FORM_ref_sig8 => FormValue { .RefSig8 = %return in_stream.readIntLe(u64) },
560
561 DW.FORM_string => FormValue { .String = %return readStringRaw(allocator, in_stream) },
562 DW.FORM_strp => FormValue { .StrPtr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
563 DW.FORM_indirect => {
564 const child_form_id = %return readULeb128(in_stream);
565 return parseFormValue(allocator, in_stream, child_form_id, is_64);
566 },
567 else => error.InvalidDebugInfo,
568 };
569}
570
571fn parseAbbrevTable(st: &ElfStackTrace) -> %AbbrevTable {
572 const in_file = &st.self_exe_file;
573 var in_file_stream = io.FileInStream.init(in_file);
574 const in_stream = &in_file_stream.stream;
575 var result = AbbrevTable.init(st.allocator());
576 while (true) {
577 const abbrev_code = %return readULeb128(in_stream);
578 if (abbrev_code == 0)
579 return result;
580 %return result.append(AbbrevTableEntry {
581 .abbrev_code = abbrev_code,
582 .tag_id = %return readULeb128(in_stream),
583 .has_children = (%return in_stream.readByte()) == DW.CHILDREN_yes,
584 .attrs = ArrayList(AbbrevAttr).init(st.allocator()),
585 });
586 const attrs = &result.items[result.len - 1].attrs;
587
588 while (true) {
589 const attr_id = %return readULeb128(in_stream);
590 const form_id = %return readULeb128(in_stream);
591 if (attr_id == 0 and form_id == 0)
592 break;
593 %return attrs.append(AbbrevAttr {
594 .attr_id = attr_id,
595 .form_id = form_id,
596 });
597 }
598 }
599}
600
601/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
602/// seeks in the stream and parses it.
603fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) -> %&const AbbrevTable {
604 for (st.abbrev_table_list.toSlice()) |*header| {
605 if (header.offset == abbrev_offset) {
606 return &header.table;
607 }
608 }
609 %return st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset);
610 %return st.abbrev_table_list.append(AbbrevTableHeader {
611 .offset = abbrev_offset,
612 .table = %return parseAbbrevTable(st),
613 });
614 return &st.abbrev_table_list.items[st.abbrev_table_list.len - 1].table;
615}
616
617fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) -> ?&const AbbrevTableEntry {
618 for (abbrev_table.toSliceConst()) |*table_entry| {
619 if (table_entry.abbrev_code == abbrev_code)
620 return table_entry;
621 }
622 return null;
623}
624
625fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) -> %Die {
626 const in_file = &st.self_exe_file;
627 var in_file_stream = io.FileInStream.init(in_file);
628 const in_stream = &in_file_stream.stream;
629 const abbrev_code = %return readULeb128(in_stream);
630 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) ?? return error.InvalidDebugInfo;
631
632 var result = Die {
633 .tag_id = table_entry.tag_id,
634 .has_children = table_entry.has_children,
635 .attrs = ArrayList(Die.Attr).init(st.allocator()),
636 };
637 %return result.attrs.resize(table_entry.attrs.len);
638 for (table_entry.attrs.toSliceConst()) |attr, i| {
639 result.attrs.items[i] = Die.Attr {
640 .id = attr.attr_id,
641 .value = %return parseFormValue(st.allocator(), in_stream, attr.form_id, is_64),
642 };
643 }
644 return result;
645}
646
647fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, target_address: usize) -> %LineInfo {
648 const compile_unit_cwd = %return compile_unit.die.getAttrString(st, DW.AT_comp_dir);
649
650 const in_file = &st.self_exe_file;
651 const debug_line_end = st.debug_line.offset + st.debug_line.size;
652 var this_offset = st.debug_line.offset;
653 var this_index: usize = 0;
654
655 var in_file_stream = io.FileInStream.init(in_file);
656 const in_stream = &in_file_stream.stream;
657
658 while (this_offset < debug_line_end) : (this_index += 1) {
659 %return in_file.seekTo(this_offset);
660
661 var is_64: bool = undefined;
662 const unit_length = %return readInitialLength(in_stream, &is_64);
663 if (unit_length == 0)
664 return error.MissingDebugInfo;
665 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
666
667 if (compile_unit.index != this_index) {
668 this_offset += next_offset;
669 continue;
670 }
671
672 const version = %return in_stream.readInt(st.elf.endian, u16);
673 if (version != 2) return error.InvalidDebugInfo;
674
675 const prologue_length = %return in_stream.readInt(st.elf.endian, u32);
676 const prog_start_offset = (%return in_file.getPos()) + prologue_length;
677
678 const minimum_instruction_length = %return in_stream.readByte();
679 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
680
681 const default_is_stmt = (%return in_stream.readByte()) != 0;
682 const line_base = %return in_stream.readByteSigned();
683
684 const line_range = %return in_stream.readByte();
685 if (line_range == 0)
686 return error.InvalidDebugInfo;
687
688 const opcode_base = %return in_stream.readByte();
689
690 const standard_opcode_lengths = %return st.allocator().alloc(u8, opcode_base - 1);
691
692 {var i: usize = 0; while (i < opcode_base - 1) : (i += 1) {
693 standard_opcode_lengths[i] = %return in_stream.readByte();
694 }}
695
696 var include_directories = ArrayList([]u8).init(st.allocator());
697 %return include_directories.append(compile_unit_cwd);
698 while (true) {
699 const dir = %return st.readString();
700 if (dir.len == 0)
701 break;
702 %return include_directories.append(dir);
703 }
704
705 var file_entries = ArrayList(FileEntry).init(st.allocator());
706 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(),
707 &file_entries, target_address);
708
709 while (true) {
710 const file_name = %return st.readString();
711 if (file_name.len == 0)
712 break;
713 const dir_index = %return readULeb128(in_stream);
714 const mtime = %return readULeb128(in_stream);
715 const len_bytes = %return readULeb128(in_stream);
716 %return file_entries.append(FileEntry {
717 .file_name = file_name,
718 .dir_index = dir_index,
719 .mtime = mtime,
720 .len_bytes = len_bytes,
721 });
722 }
723
724 %return in_file.seekTo(prog_start_offset);
725
726 while (true) {
727 const opcode = %return in_stream.readByte();
728
729 var sub_op: u8 = undefined; // TODO move this to the correct scope and fix the compiler crash
730 if (opcode == DW.LNS_extended_op) {
731 const op_size = %return readULeb128(in_stream);
732 if (op_size < 1)
733 return error.InvalidDebugInfo;
734 sub_op = %return in_stream.readByte();
735 switch (sub_op) {
736 DW.LNE_end_sequence => {
737 prog.end_sequence = true;
738 if (%return prog.checkLineMatch()) |info| return info;
739 return error.MissingDebugInfo;
740 },
741 DW.LNE_set_address => {
742 const addr = %return in_stream.readInt(st.elf.endian, usize);
743 prog.address = addr;
744 },
745 DW.LNE_define_file => {
746 const file_name = %return st.readString();
747 const dir_index = %return readULeb128(in_stream);
748 const mtime = %return readULeb128(in_stream);
749 const len_bytes = %return readULeb128(in_stream);
750 %return file_entries.append(FileEntry {
751 .file_name = file_name,
752 .dir_index = dir_index,
753 .mtime = mtime,
754 .len_bytes = len_bytes,
755 });
756 },
757 else => {
758 const fwd_amt = math.cast(isize, op_size - 1) %% return error.InvalidDebugInfo;
759 %return in_file.seekForward(fwd_amt);
760 },
761 }
762 } else if (opcode >= opcode_base) {
763 // special opcodes
764 const adjusted_opcode = opcode - opcode_base;
765 const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
766 const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
767 prog.line += inc_line;
768 prog.address += inc_addr;
769 if (%return prog.checkLineMatch()) |info| return info;
770 prog.basic_block = false;
771 } else {
772 switch (opcode) {
773 DW.LNS_copy => {
774 if (%return prog.checkLineMatch()) |info| return info;
775 prog.basic_block = false;
776 },
777 DW.LNS_advance_pc => {
778 const arg = %return readULeb128(in_stream);
779 prog.address += arg * minimum_instruction_length;
780 },
781 DW.LNS_advance_line => {
782 const arg = %return readILeb128(in_stream);
783 prog.line += arg;
784 },
785 DW.LNS_set_file => {
786 const arg = %return readULeb128(in_stream);
787 prog.file = arg;
788 },
789 DW.LNS_set_column => {
790 const arg = %return readULeb128(in_stream);
791 prog.column = arg;
792 },
793 DW.LNS_negate_stmt => {
794 prog.is_stmt = !prog.is_stmt;
795 },
796 DW.LNS_set_basic_block => {
797 prog.basic_block = true;
798 },
799 DW.LNS_const_add_pc => {
800 const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
801 prog.address += inc_addr;
802 },
803 DW.LNS_fixed_advance_pc => {
804 const arg = %return in_stream.readInt(st.elf.endian, u16);
805 prog.address += arg;
806 },
807 DW.LNS_set_prologue_end => {
808 },
809 else => {
810 if (opcode - 1 >= standard_opcode_lengths.len)
811 return error.InvalidDebugInfo;
812 const len_bytes = standard_opcode_lengths[opcode - 1];
813 %return in_file.seekForward(len_bytes);
814 },
815 }
816 }
817 }
818
819 this_offset += next_offset;
820 }
821
822 return error.MissingDebugInfo;
823}
824
825fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
826 const debug_info_end = st.debug_info.offset + st.debug_info.size;
827 var this_unit_offset = st.debug_info.offset;
828 var cu_index: usize = 0;
829
830 var in_file_stream = io.FileInStream.init(&st.self_exe_file);
831 const in_stream = &in_file_stream.stream;
832
833 while (this_unit_offset < debug_info_end) {
834 %return st.self_exe_file.seekTo(this_unit_offset);
835
836 var is_64: bool = undefined;
837 const unit_length = %return readInitialLength(in_stream, &is_64);
838 if (unit_length == 0)
839 return;
840 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
841
842 const version = %return in_stream.readInt(st.elf.endian, u16);
843 if (version < 2 or version > 5) return error.InvalidDebugInfo;
844
845 const debug_abbrev_offset =
846 if (is_64) %return in_stream.readInt(st.elf.endian, u64)
847 else %return in_stream.readInt(st.elf.endian, u32);
848
849 const address_size = %return in_stream.readByte();
850 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
851
852 const compile_unit_pos = %return st.self_exe_file.getPos();
853 const abbrev_table = %return getAbbrevTable(st, debug_abbrev_offset);
854
855 %return st.self_exe_file.seekTo(compile_unit_pos);
856
857 const compile_unit_die = %return st.allocator().create(Die);
858 *compile_unit_die = %return parseDie(st, abbrev_table, is_64);
859
860 if (compile_unit_die.tag_id != DW.TAG_compile_unit)
861 return error.InvalidDebugInfo;
862
863 const pc_range = x: {
864 if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
865 if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
866 const pc_end = switch (*high_pc_value) {
867 FormValue.Address => |value| value,
868 FormValue.Const => |value| b: {
869 const offset = %return value.asUnsignedLe();
870 break :b (low_pc + offset);
871 },
872 else => return error.InvalidDebugInfo,
873 };
874 break :x PcRange {
875 .start = low_pc,
876 .end = pc_end,
877 };
878 } else {
879 break :x null;
880 }
881 } else |err| {
882 if (err != error.MissingDebugInfo)
883 return err;
884 break :x null;
885 }
886 };
887
888 %return st.compile_unit_list.append(CompileUnit {
889 .version = version,
890 .is_64 = is_64,
891 .pc_range = pc_range,
892 .die = compile_unit_die,
893 .index = cu_index,
894 });
895
896 this_unit_offset += next_offset;
897 cu_index += 1;
898 }
899}
900
901fn findCompileUnit(st: &ElfStackTrace, target_address: u64) -> %&const CompileUnit {
902 var in_file_stream = io.FileInStream.init(&st.self_exe_file);
903 const in_stream = &in_file_stream.stream;
904 for (st.compile_unit_list.toSlice()) |*compile_unit| {
905 if (compile_unit.pc_range) |range| {
906 if (target_address >= range.start and target_address < range.end)
907 return compile_unit;
908 }
909 if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
910 var base_address: usize = 0;
911 if (st.debug_ranges) |debug_ranges| {
912 %return st.self_exe_file.seekTo(debug_ranges.offset + ranges_offset);
913 while (true) {
914 const begin_addr = %return in_stream.readIntLe(usize);
915 const end_addr = %return in_stream.readIntLe(usize);
916 if (begin_addr == 0 and end_addr == 0) {
917 break;
918 }
919 if (begin_addr == @maxValue(usize)) {
920 base_address = begin_addr;
921 continue;
922 }
923 if (target_address >= begin_addr and target_address < end_addr) {
924 return compile_unit;
925 }
926 }
927 }
928 } else |err| {
929 if (err != error.MissingDebugInfo)
930 return err;
931 continue;
932 }
933 }
934 return error.MissingDebugInfo;
935}
936
937fn readInitialLength(in_stream: &io.InStream, is_64: &bool) -> %u64 {
938 const first_32_bits = %return in_stream.readIntLe(u32);
939 *is_64 = (first_32_bits == 0xffffffff);
940 if (*is_64) {
941 return in_stream.readIntLe(u64);
942 } else {
943 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
944 return u64(first_32_bits);
945 }
946}
947
948fn readULeb128(in_stream: &io.InStream) -> %u64 {
949 var result: u64 = 0;
950 var shift: usize = 0;
951
952 while (true) {
953 const byte = %return in_stream.readByte();
954
955 var operand: u64 = undefined;
956
957 if (@shlWithOverflow(u64, byte & 0b01111111, u6(shift), &operand))
958 return error.InvalidDebugInfo;
959
960 result |= operand;
961
962 if ((byte & 0b10000000) == 0)
963 return result;
964
965 shift += 7;
966 }
967}
968
969fn readILeb128(in_stream: &io.InStream) -> %i64 {
970 var result: i64 = 0;
971 var shift: usize = 0;
972
973 while (true) {
974 const byte = %return in_stream.readByte();
975
976 var operand: i64 = undefined;
977
978 if (@shlWithOverflow(i64, byte & 0b01111111, u6(shift), &operand))
979 return error.InvalidDebugInfo;
980
981 result |= operand;
982 shift += 7;
983
984 if ((byte & 0b10000000) == 0) {
985 if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0)
986 result |= -(i64(1) << u6(shift));
987 return result;
988 }
989 }
990}
991
992pub const global_allocator = &global_fixed_allocator.allocator;
993var global_fixed_allocator = mem.FixedBufferAllocator.init(global_allocator_mem[0..]);
994var global_allocator_mem: [100 * 1024]u8 = undefined;
std/fmt/errol/index.zig+4-3
......@@ -1,10 +1,11 @@
1const std = @import("../../index.zig");
12const enum3 = @import("enum3.zig").enum3;
23const enum3_data = @import("enum3.zig").enum3_data;
34const lookup_table = @import("lookup.zig").lookup_table;
45const HP = @import("lookup.zig").HP;
5const math = @import("../../math/index.zig");
6const mem = @import("../../mem.zig");
7const assert = @import("../../debug.zig").assert;
6const math = std.math;
7const mem = std.mem;
8const assert = std.debug.assert;
89
910pub const FloatDecimal = struct {
1011 digits: []u8,
std/fmt/index.zig+4-3
......@@ -1,7 +1,8 @@
1const math = @import("../math/index.zig");
2const debug = @import("../debug.zig");
1const std = @import("../index.zig");
2const math = std.math;
3const debug = std.debug;
34const assert = debug.assert;
4const mem = @import("../mem.zig");
5const mem = std.mem;
56const builtin = @import("builtin");
67const errol3 = @import("errol/index.zig").errol3;
78
std/hash_map.zig+4-3
......@@ -1,7 +1,8 @@
1const debug = @import("debug.zig");
1const std = @import("index.zig");
2const debug = std.debug;
23const assert = debug.assert;
3const math = @import("math/index.zig");
4const mem = @import("mem.zig");
4const math = std.math;
5const mem = std.mem;
56const Allocator = mem.Allocator;
67const builtin = @import("builtin");
78
std/heap.zig+5-4
......@@ -1,10 +1,11 @@
1const debug = @import("debug.zig");
1const std = @import("index.zig");
2const debug = std.debug;
23const assert = debug.assert;
3const mem = @import("mem.zig");
4const os = @import("os/index.zig");
4const mem = std.mem;
5const os = std.os;
56const builtin = @import("builtin");
67const Os = builtin.Os;
7const c = @import("c/index.zig");
8const c = std.c;
89
910const Allocator = mem.Allocator;
1011
std/index.zig+2-2
......@@ -11,7 +11,7 @@ pub const base64 = @import("base64.zig");
1111pub const build = @import("build.zig");
1212pub const c = @import("c/index.zig");
1313pub const cstr = @import("cstr.zig");
14pub const debug = @import("debug.zig");
14pub const debug = @import("debug/index.zig");
1515pub const dwarf = @import("dwarf.zig");
1616pub const elf = @import("elf.zig");
1717pub const empty_import = @import("empty.zig");
......@@ -39,7 +39,7 @@ test "std" {
3939 _ = @import("build.zig");
4040 _ = @import("c/index.zig");
4141 _ = @import("cstr.zig");
42 _ = @import("debug.zig");
42 _ = @import("debug/index.zig");
4343 _ = @import("dwarf.zig");
4444 _ = @import("elf.zig");
4545 _ = @import("empty.zig");
std/linked_list.zig+3-2
......@@ -1,6 +1,7 @@
1const debug = @import("debug.zig");
1const std = @import("index.zig");
2const debug = std.debug;
23const assert = debug.assert;
3const mem = @import("mem.zig");
4const mem = std.mem;
45const Allocator = mem.Allocator;
56
67/// Generic doubly linked list.
std/math/acos.zig+3-2
......@@ -2,8 +2,9 @@
22//
33// - acos(x) = nan if x < -1 or x > 1
44
5const math = @import("index.zig");
6const assert = @import("../debug.zig").assert;
5const std = @import("../index.zig");
6const math = std.math;
7const assert = std.debug.assert;
78
89pub fn acos(x: var) -> @typeOf(x) {
910 const T = @typeOf(x);
std/math/acosh.zig+3-2
......@@ -4,8 +4,9 @@
44// - acosh(nan) = nan
55
66const builtin = @import("builtin");
7const math = @import("index.zig");
8const assert = @import("../debug.zig").assert;
7const std = @import("../index.zig");
8const math = std.math;
9const assert = std.debug.assert;
910
1011pub fn acosh(x: var) -> @typeOf(x) {
1112 const T = @typeOf(x);
std/math/asin.zig+3-2
......@@ -3,8 +3,9 @@
33// - asin(+-0) = +-0
44// - asin(x) = nan if x < -1 or x > 1
55
6const math = @import("index.zig");
7const assert = @import("../debug.zig").assert;
6const std = @import("../index.zig");
7const math = std.math;
8const assert = std.debug.assert;
89
910pub fn asin(x: var) -> @typeOf(x) {
1011 const T = @typeOf(x);
std/math/asinh.zig+3-2
......@@ -4,8 +4,9 @@
44// - asinh(+-inf) = +-inf
55// - asinh(nan) = nan
66
7const math = @import("index.zig");
8const assert = @import("../debug.zig").assert;
7const std = @import("../index.zig");
8const math = std.math;
9const assert = std.debug.assert;
910
1011pub fn asinh(x: var) -> @typeOf(x) {
1112 const T = @typeOf(x);
std/math/atan.zig+3-2
......@@ -3,8 +3,9 @@
33// - atan(+-0) = +-0
44// - atan(+-inf) = +-pi/2
55
6const math = @import("index.zig");
7const assert = @import("../debug.zig").assert;
6const std = @import("../index.zig");
7const math = std.math;
8const assert = std.debug.assert;
89
910pub fn atan(x: var) -> @typeOf(x) {
1011 const T = @typeOf(x);
std/math/atan2.zig+3-2
......@@ -18,8 +18,9 @@
1818// atan2(+inf, x) = +pi/2
1919// atan2(-inf, x) = -pi/2
2020
21const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
21const std = @import("../index.zig");
22const math = std.math;
23const assert = std.debug.assert;
2324
2425fn atan2(comptime T: type, x: T, y: T) -> T {
2526 return switch (T) {
std/math/atanh.zig+3-2
......@@ -4,8 +4,9 @@
44// - atanh(x) = nan if |x| > 1 with signal
55// - atanh(nan) = nan
66
7const math = @import("index.zig");
8const assert = @import("../debug.zig").assert;
7const std = @import("../index.zig");
8const math = std.math;
9const assert = std.debug.assert;
910
1011pub fn atanh(x: var) -> @typeOf(x) {
1112 const T = @typeOf(x);
std/math/cbrt.zig+3-2
......@@ -4,8 +4,9 @@
44// - cbrt(+-inf) = +-inf
55// - cbrt(nan) = nan
66
7const math = @import("index.zig");
8const assert = @import("../debug.zig").assert;
7const std = @import("../index.zig");
8const math = std.math;
9const assert = std.debug.assert;
910
1011pub fn cbrt(x: var) -> @typeOf(x) {
1112 const T = @typeOf(x);
std/math/ceil.zig+3-2
......@@ -5,8 +5,9 @@
55// - ceil(nan) = nan
66
77const builtin = @import("builtin");
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011
1112pub fn ceil(x: var) -> @typeOf(x) {
1213 const T = @typeOf(x);
std/math/copysign.zig+3-2
......@@ -1,5 +1,6 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const math = std.math;
3const assert = std.debug.assert;
34
45pub fn copysign(comptime T: type, x: T, y: T) -> T {
56 return switch (T) {
std/math/cos.zig+3-2
......@@ -4,8 +4,9 @@
44// - cos(nan) = nan
55
66const builtin = @import("builtin");
7const math = @import("index.zig");
8const assert = @import("../debug.zig").assert;
7const std = @import("../index.zig");
8const math = std.math;
9const assert = std.debug.assert;
910
1011pub fn cos(x: var) -> @typeOf(x) {
1112 const T = @typeOf(x);
std/math/cosh.zig+3-2
......@@ -5,9 +5,10 @@
55// - cosh(nan) = nan
66
77const builtin = @import("builtin");
8const math = @import("index.zig");
8const std = @import("../index.zig");
9const math = std.math;
910const expo2 = @import("expo2.zig").expo2;
10const assert = @import("../debug.zig").assert;
11const assert = std.debug.assert;
1112
1213pub fn cosh(x: var) -> @typeOf(x) {
1314 const T = @typeOf(x);
std/math/exp.zig+3-2
......@@ -3,8 +3,9 @@
33// - exp(+inf) = +inf
44// - exp(nan) = nan
55
6const math = @import("index.zig");
7const assert = @import("../debug.zig").assert;
6const std = @import("../index.zig");
7const math = std.math;
8const assert = std.debug.assert;
89
910pub fn exp(x: var) -> @typeOf(x) {
1011 const T = @typeOf(x);
std/math/exp2.zig+3-2
......@@ -3,8 +3,9 @@
33// - exp2(+inf) = +inf
44// - exp2(nan) = nan
55
6const math = @import("index.zig");
7const assert = @import("../debug.zig").assert;
6const std = @import("../index.zig");
7const math = std.math;
8const assert = std.debug.assert;
89
910pub fn exp2(x: var) -> @typeOf(x) {
1011 const T = @typeOf(x);
std/math/expm1.zig+3-2
......@@ -4,8 +4,9 @@
44// - expm1(-inf) = -1
55// - expm1(nan) = nan
66
7const math = @import("index.zig");
8const assert = @import("../debug.zig").assert;
7const std = @import("../index.zig");
8const math = std.math;
9const assert = std.debug.assert;
910
1011pub fn expm1(x: var) -> @typeOf(x) {
1112 const T = @typeOf(x);
std/math/fabs.zig+3-2
......@@ -3,8 +3,9 @@
33// - fabs(+-inf) = +inf
44// - fabs(nan) = nan
55
6const math = @import("index.zig");
7const assert = @import("../debug.zig").assert;
6const std = @import("../index.zig");
7const math = std.math;
8const assert = std.debug.assert;
89
910pub fn fabs(x: var) -> @typeOf(x) {
1011 const T = @typeOf(x);
std/math/floor.zig+3-2
......@@ -5,8 +5,9 @@
55// - floor(nan) = nan
66
77const builtin = @import("builtin");
8const assert = @import("../debug.zig").assert;
9const math = @import("index.zig");
8const assert = std.debug.assert;
9const std = @import("../index.zig");
10const math = std.math;
1011
1112pub fn floor(x: var) -> @typeOf(x) {
1213 const T = @typeOf(x);
std/math/fma.zig+3-2
......@@ -1,5 +1,6 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const math = std.math;
3const assert = std.debug.assert;
34
45pub fn fma(comptime T: type, x: T, y: T, z: T) -> T {
56 return switch (T) {
std/math/frexp.zig+3-2
......@@ -4,8 +4,9 @@
44// - frexp(+-inf) = +-inf, 0
55// - frexp(nan) = nan, undefined
66
7const math = @import("index.zig");
8const assert = @import("../debug.zig").assert;
7const std = @import("../index.zig");
8const math = std.math;
9const assert = std.debug.assert;
910
1011fn frexp_result(comptime T: type) -> type {
1112 return struct {
std/math/hypot.zig+3-2
......@@ -5,8 +5,9 @@
55// - hypot(nan, y) = nan
66// - hypot(x, nan) = nan
77
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011
1112pub fn hypot(comptime T: type, x: T, y: T) -> T {
1213 return switch (T) {
std/math/ilogb.zig+3-2
......@@ -4,8 +4,9 @@
44// - ilogb(0) = @maxValue(i32)
55// - ilogb(nan) = @maxValue(i32)
66
7const math = @import("index.zig");
8const assert = @import("../debug.zig").assert;
7const std = @import("../index.zig");
8const math = std.math;
9const assert = std.debug.assert;
910
1011pub fn ilogb(x: var) -> i32 {
1112 const T = @typeOf(x);
std/math/index.zig+2-1
......@@ -1,6 +1,7 @@
11const builtin = @import("builtin");
2const std = @import("../index.zig");
23const TypeId = builtin.TypeId;
3const assert = @import("../debug.zig").assert;
4const assert = std.debug.assert;
45
56pub const e = 2.71828182845904523536028747135266249775724709369995;
67pub const pi = 3.14159265358979323846264338327950288419716939937510;
std/math/inf.zig+3-2
......@@ -1,5 +1,6 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const math = std.math;
3const assert = std.debug.assert;
34
45pub fn inf(comptime T: type) -> T {
56 return switch (T) {
std/math/isfinite.zig+3-2
......@@ -1,5 +1,6 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const math = std.math;
3const assert = std.debug.assert;
34
45pub fn isFinite(x: var) -> bool {
56 const T = @typeOf(x);
std/math/isinf.zig+3-2
......@@ -1,5 +1,6 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const math = std.math;
3const assert = std.debug.assert;
34
45pub fn isInf(x: var) -> bool {
56 const T = @typeOf(x);
std/math/isnan.zig+3-2
......@@ -1,5 +1,6 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const math = std.math;
3const assert = std.debug.assert;
34
45pub fn isNan(x: var) -> bool {
56 const T = @typeOf(x);
std/math/isnormal.zig+3-2
......@@ -1,5 +1,6 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const math = std.math;
3const assert = std.debug.assert;
34
45pub fn isNormal(x: var) -> bool {
56 const T = @typeOf(x);
std/math/ln.zig+3-2
......@@ -5,8 +5,9 @@
55// - ln(x) = nan if x < 0
66// - ln(nan) = nan
77
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011const builtin = @import("builtin");
1112const TypeId = builtin.TypeId;
1213
std/math/log.zig+3-2
......@@ -1,7 +1,8 @@
1const math = @import("index.zig");
1const std = @import("../index.zig");
2const math = std.math;
23const builtin = @import("builtin");
34const TypeId = builtin.TypeId;
4const assert = @import("../debug.zig").assert;
5const assert = std.debug.assert;
56
67pub fn log(comptime T: type, base: T, x: T) -> T {
78 if (base == 2) {
std/math/log10.zig+3-2
......@@ -5,8 +5,9 @@
55// - log10(x) = nan if x < 0
66// - log10(nan) = nan
77
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011const builtin = @import("builtin");
1112const TypeId = builtin.TypeId;
1213
std/math/log1p.zig+3-2
......@@ -6,8 +6,9 @@
66// - log1p(x) = nan if x < -1
77// - log1p(nan) = nan
88
9const math = @import("index.zig");
10const assert = @import("../debug.zig").assert;
9const std = @import("../index.zig");
10const math = std.math;
11const assert = std.debug.assert;
1112
1213pub fn log1p(x: var) -> @typeOf(x) {
1314 const T = @typeOf(x);
std/math/log2.zig+3-2
......@@ -5,8 +5,9 @@
55// - log2(x) = nan if x < 0
66// - log2(nan) = nan
77
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011const builtin = @import("builtin");
1112const TypeId = builtin.TypeId;
1213
std/math/modf.zig+3-2
......@@ -3,8 +3,9 @@
33// - modf(+-inf) = +-inf, nan
44// - modf(nan) = nan, nan
55
6const math = @import("index.zig");
7const assert = @import("../debug.zig").assert;
6const std = @import("../index.zig");
7const math = std.math;
8const assert = std.debug.assert;
89
910fn modf_result(comptime T: type) -> type {
1011 return struct {
std/math/pow.zig+3-2
......@@ -22,8 +22,9 @@
2222// pow(x, y) = nan for finite x < 0 and finite non-integer y
2323
2424const builtin = @import("builtin");
25const math = @import("index.zig");
26const assert = @import("../debug.zig").assert;
25const std = @import("../index.zig");
26const math = std.math;
27const assert = std.debug.assert;
2728
2829// This implementation is taken from the go stlib, musl is a bit more complex.
2930pub fn pow(comptime T: type, x: T, y: T) -> T {
std/math/round.zig+3-2
......@@ -5,8 +5,9 @@
55// - round(nan) = nan
66
77const builtin = @import("builtin");
8const assert = @import("../debug.zig").assert;
9const math = @import("index.zig");
8const assert = std.debug.assert;
9const std = @import("../index.zig");
10const math = std.math;
1011
1112pub fn round(x: var) -> @typeOf(x) {
1213 const T = @typeOf(x);
std/math/scalbn.zig+3-2
......@@ -1,5 +1,6 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const math = std.math;
3const assert = std.debug.assert;
34
45pub fn scalbn(x: var, n: i32) -> @typeOf(x) {
56 const T = @typeOf(x);
std/math/signbit.zig+3-2
......@@ -1,5 +1,6 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const math = std.math;
3const assert = std.debug.assert;
34
45pub fn signbit(x: var) -> bool {
56 const T = @typeOf(x);
std/math/sin.zig+3-2
......@@ -5,8 +5,9 @@
55// - sin(nan) = nan
66
77const builtin = @import("builtin");
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011
1112pub fn sin(x: var) -> @typeOf(x) {
1213 const T = @typeOf(x);
std/math/sinh.zig+3-2
......@@ -5,8 +5,9 @@
55// - sinh(nan) = nan
66
77const builtin = @import("builtin");
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011const expo2 = @import("expo2.zig").expo2;
1112
1213pub fn sinh(x: var) -> @typeOf(x) {
std/math/sqrt.zig+3-2
......@@ -5,8 +5,9 @@
55// - sqrt(x) = nan if x < 0
66// - sqrt(nan) = nan
77
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011const builtin = @import("builtin");
1112const TypeId = builtin.TypeId;
1213
std/math/tan.zig+3-2
......@@ -5,8 +5,9 @@
55// - tan(nan) = nan
66
77const builtin = @import("builtin");
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011
1112pub fn tan(x: var) -> @typeOf(x) {
1213 const T = @typeOf(x);
std/math/tanh.zig+3-2
......@@ -5,8 +5,9 @@
55// - sinh(nan) = nan
66
77const builtin = @import("builtin");
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011const expo2 = @import("expo2.zig").expo2;
1112
1213pub fn tanh(x: var) -> @typeOf(x) {
std/math/trunc.zig+3-2
......@@ -4,8 +4,9 @@
44// - trunc(+-inf) = +-inf
55// - trunc(nan) = nan
66
7const math = @import("index.zig");
8const assert = @import("../debug.zig").assert;
7const std = @import("../index.zig");
8const math = std.math;
9const assert = std.debug.assert;
910
1011pub fn trunc(x: var) -> @typeOf(x) {
1112 const T = @typeOf(x);
std/mem.zig+3-2
......@@ -1,6 +1,7 @@
1const debug = @import("debug.zig");
1const std = @import("index.zig");
2const debug = std.debug;
23const assert = debug.assert;
3const math = @import("math/index.zig");
4const math = std.math;
45const builtin = @import("builtin");
56
67error OutOfMemory;
std/net.zig+4-3
......@@ -1,6 +1,7 @@
1const linux = @import("os/linux.zig");
2const assert = @import("debug.zig").assert;
3const endian = @import("endian.zig");
1const std = @import("index.zig");
2const linux = std.os.linux;
3const assert = std.debug.assert;
4const endian = std.endian;
45
56error SigInterrupt;
67error Io;
std/os/darwin.zig+3-2
......@@ -1,5 +1,6 @@
1const c = @import("../c/index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const c = std.c;
3const assert = std.debug.assert;
34
45pub use @import("darwin_errno.zig");
56
std/os/index.zig+11-10
......@@ -1,3 +1,4 @@
1const std = @import("../index.zig");
12const builtin = @import("builtin");
23const Os = builtin.Os;
34const is_windows = builtin.os == Os.windows;
......@@ -37,22 +38,22 @@ pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
3738
3839pub const FileHandle = if (is_windows) windows.HANDLE else i32;
3940
40const debug = @import("../debug.zig");
41const debug = std.debug;
4142const assert = debug.assert;
4243
43const c = @import("../c/index.zig");
44const c = std.c;
4445
45const mem = @import("../mem.zig");
46const mem = std.mem;
4647const Allocator = mem.Allocator;
4748
48const BufMap = @import("../buf_map.zig").BufMap;
49const cstr = @import("../cstr.zig");
49const BufMap = std.BufMap;
50const cstr = std.cstr;
5051
51const io = @import("../io.zig");
52const base64 = @import("../base64.zig");
53const ArrayList = @import("../array_list.zig").ArrayList;
54const Buffer = @import("../buffer.zig").Buffer;
55const math = @import("../index.zig").math;
52const io = std.io;
53const base64 = std.base64;
54const ArrayList = std.ArrayList;
55const Buffer = std.Buffer;
56const math = std.math;
5657
5758error SystemResources;
5859error AccessDenied;
std/os/linux.zig+2-1
......@@ -1,4 +1,5 @@
1const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const assert = std.debug.assert;
23const builtin = @import("builtin");
34const arch = switch (builtin.arch) {
45 builtin.Arch.x86_64 => @import("linux_x86_64.zig"),
std/os/path.zig+7-7
......@@ -1,16 +1,16 @@
1const std = @import("../index.zig");
12const builtin = @import("builtin");
23const Os = builtin.Os;
3const debug = @import("../debug.zig");
4const debug = std.debug;
45const assert = debug.assert;
5const mem = @import("../mem.zig");
6const fmt = @import("../fmt/index.zig");
6const mem = std.mem;
7const fmt = std.fmt;
78const Allocator = mem.Allocator;
8const os = @import("index.zig");
9const math = @import("../math/index.zig");
9const os = std.os;
10const math = std.math;
1011const posix = os.posix;
1112const windows = os.windows;
12const c = @import("../c/index.zig");
13const cstr = @import("../cstr.zig");
13const cstr = std.cstr;
1414
1515pub const sep_windows = '\\';
1616pub const sep_posix = '/';
std/rand.zig+4-3
......@@ -1,8 +1,9 @@
1const std = @import("index.zig");
12const builtin = @import("builtin");
2const assert = @import("debug.zig").assert;
3const assert = std.debug.assert;
34const rand_test = @import("rand_test.zig");
4const mem = @import("mem.zig");
5const math = @import("math/index.zig");
5const mem = std.mem;
6const math = std.math;
67
78pub const MT19937_32 = MersenneTwister(
89 u32, 624, 397, 31,
std/special/compiler_rt/fixunsdfdi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi;
2const assert = @import("../../debug.zig").assert;
2const assert = @import("../../index.zig").debug.assert;
33
44fn test__fixunsdfdi(a: f64, expected: u64) {
55 const x = __fixunsdfdi(a);
std/special/compiler_rt/fixunsdfsi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi;
2const assert = @import("../../debug.zig").assert;
2const assert = @import("../../index.zig").debug.assert;
33
44fn test__fixunsdfsi(a: f64, expected: u32) {
55 const x = __fixunsdfsi(a);
std/special/compiler_rt/fixunsdfti_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti;
2const assert = @import("../../debug.zig").assert;
2const assert = @import("../../index.zig").debug.assert;
33
44fn test__fixunsdfti(a: f64, expected: u128) {
55 const x = __fixunsdfti(a);
std/special/compiler_rt/fixunssfdi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi;
2const assert = @import("../../debug.zig").assert;
2const assert = @import("../../index.zig").debug.assert;
33
44fn test__fixunssfdi(a: f32, expected: u64) {
55 const x = __fixunssfdi(a);
std/special/compiler_rt/fixunssfsi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi;
2const assert = @import("../../debug.zig").assert;
2const assert = @import("../../index.zig").debug.assert;
33
44fn test__fixunssfsi(a: f32, expected: u32) {
55 const x = __fixunssfsi(a);
std/special/compiler_rt/fixunssfti_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunssfti = @import("fixunssfti.zig").__fixunssfti;
2const assert = @import("../../debug.zig").assert;
2const assert = @import("../../index.zig").debug.assert;
33
44fn test__fixunssfti(a: f32, expected: u128) {
55 const x = __fixunssfti(a);
std/special/compiler_rt/fixunstfdi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi;
2const assert = @import("../../debug.zig").assert;
2const assert = @import("../../index.zig").debug.assert;
33
44fn test__fixunstfdi(a: f128, expected: u64) {
55 const x = __fixunstfdi(a);
std/special/compiler_rt/fixunstfsi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi;
2const assert = @import("../../debug.zig").assert;
2const assert = @import("../../index.zig").debug.assert;
33
44fn test__fixunstfsi(a: f128, expected: u32) {
55 const x = __fixunstfsi(a);
std/special/compiler_rt/fixunstfti_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunstfti = @import("fixunstfti.zig").__fixunstfti;
2const assert = @import("../../debug.zig").assert;
2const assert = @import("../../index.zig").debug.assert;
33
44fn test__fixunstfti(a: f128, expected: u128) {
55 const x = __fixunstfti(a);
std/special/compiler_rt/index.zig+1-1
......@@ -68,7 +68,7 @@ comptime {
6868 }
6969}
7070
71const assert = @import("../../debug.zig").assert;
71const assert = @import("../../index.zig").debug.assert;
7272
7373const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
7474