| author | |
| committer | |
| log | 4183c6f1a52959ab5eef540c8eec1758079554eb |
| tree | cbdecf12598c72f3d66d7fa5618d8a9c6338fa53 |
| parent | 9dae796fe3bd08c4e636f09d1849f6ce2879a50b |
self hosted compiler parser tests do some fuzz testing76 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} | ... | @@ -516,7 +516,8 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/c/index.zig" DESTINATION "${ZIG_STD_DEST} |
| 516 | install(FILES "${CMAKE_SOURCE_DIR}/std/c/linux.zig" DESTINATION "${ZIG_STD_DEST}/c") | 516 | install(FILES "${CMAKE_SOURCE_DIR}/std/c/linux.zig" DESTINATION "${ZIG_STD_DEST}/c") |
| 517 | install(FILES "${CMAKE_SOURCE_DIR}/std/c/windows.zig" DESTINATION "${ZIG_STD_DEST}/c") | 517 | install(FILES "${CMAKE_SOURCE_DIR}/std/c/windows.zig" DESTINATION "${ZIG_STD_DEST}/c") |
| 518 | install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}") | 518 | install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}") |
| 519 | install(FILES "${CMAKE_SOURCE_DIR}/std/debug.zig" DESTINATION "${ZIG_STD_DEST}") | 519 | install(FILES "${CMAKE_SOURCE_DIR}/std/debug/index.zig" DESTINATION "${ZIG_STD_DEST}/debug") |
| 520 | install(FILES "${CMAKE_SOURCE_DIR}/std/debug/failing_allocator.zig" DESTINATION "${ZIG_STD_DEST}/debug") | ||
| 520 | install(FILES "${CMAKE_SOURCE_DIR}/std/dwarf.zig" DESTINATION "${ZIG_STD_DEST}") | 521 | install(FILES "${CMAKE_SOURCE_DIR}/std/dwarf.zig" DESTINATION "${ZIG_STD_DEST}") |
| 521 | install(FILES "${CMAKE_SOURCE_DIR}/std/elf.zig" DESTINATION "${ZIG_STD_DEST}") | 522 | install(FILES "${CMAKE_SOURCE_DIR}/std/elf.zig" DESTINATION "${ZIG_STD_DEST}") |
| 522 | install(FILES "${CMAKE_SOURCE_DIR}/std/empty.zig" DESTINATION "${ZIG_STD_DEST}") | 523 | install(FILES "${CMAKE_SOURCE_DIR}/std/empty.zig" DESTINATION "${ZIG_STD_DEST}") |
build.zig+2-1| ... | @@ -172,7 +172,8 @@ pub fn installStdLib(b: &Builder) { | ... | @@ -172,7 +172,8 @@ pub fn installStdLib(b: &Builder) { |
| 172 | "c/linux.zig", | 172 | "c/linux.zig", |
| 173 | "c/windows.zig", | 173 | "c/windows.zig", |
| 174 | "cstr.zig", | 174 | "cstr.zig", |
| 175 | "debug.zig", | 175 | "debug/failing_allocator.zig", |
| 176 | "debug/index.zig", | ||
| 176 | "dwarf.zig", | 177 | "dwarf.zig", |
| 177 | "elf.zig", | 178 | "elf.zig", |
| 178 | "empty.zig", | 179 | "empty.zig", |
src-self-hosted/parser.zig+18-12| ... | @@ -1119,18 +1119,24 @@ fn testCanonical(source: []const u8) { | ... | @@ -1119,18 +1119,24 @@ fn testCanonical(source: []const u8) { |
| 1119 | break :x failing_allocator.index; | 1119 | break :x failing_allocator.index; |
| 1120 | }; | 1120 | }; |
| 1121 | 1121 | ||
| 1122 | // TODO make this pass | 1122 | var fail_index: usize = 0; |
| 1123 | //var fail_index = needed_alloc_count; | 1123 | while (fail_index < needed_alloc_count) : (fail_index += 1) { |
| 1124 | //while (fail_index != 0) { | 1124 | var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]); |
| 1125 | // fail_index -= 1; | 1125 | var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index); |
| 1126 | // var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]); | 1126 | if (testParse(source, &failing_allocator.allocator)) |_| { |
| 1127 | // var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index); | 1127 | @panic("non-deterministic memory usage"); |
| 1128 | // if (testParse(source, &failing_allocator.allocator)) |_| { | 1128 | } else |err| { |
| 1129 | // @panic("non-deterministic memory usage"); | 1129 | assert(err == error.OutOfMemory); |
| 1130 | // } else |err| { | 1130 | // TODO make this pass |
| 1131 | // assert(err == error.OutOfMemory); | 1131 | //if (failing_allocator.allocated_bytes != failing_allocator.freed_bytes) { |
| 1132 | // } | 1132 | // warn("\nfail_index: {}/{}\nallocated bytes: {}\nfreed bytes: {}\nallocations: {}\ndeallocations: {}\n", |
| 1133 | //} | 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 | } | ||
| 1134 | } | 1140 | } |
| 1135 | 1141 | ||
| 1136 | test "zig fmt" { | 1142 | test "zig fmt" { |
std/array_list.zig+3-2| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const debug = @import("debug.zig"); | 1 | const std = @import("index.zig"); |
| 2 | const debug = std.debug; | ||
| 2 | const assert = debug.assert; | 3 | const assert = debug.assert; |
| 3 | const mem = @import("mem.zig"); | 4 | const mem = std.mem; |
| 4 | const Allocator = mem.Allocator; | 5 | const Allocator = mem.Allocator; |
| 5 | 6 | ||
| 6 | pub fn ArrayList(comptime T: type) -> type { | 7 | pub fn ArrayList(comptime T: type) -> type { |
std/base64.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const assert = @import("debug.zig").assert; | 1 | const std = @import("index.zig"); |
| 2 | const mem = @import("mem.zig"); | 2 | const assert = std.debug.assert; |
| 3 | const mem = std.mem; | ||
| 3 | 4 | ||
| 4 | pub const standard_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | 5 | pub const standard_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
| 5 | pub const standard_pad_char = '='; | 6 | pub const standard_pad_char = '='; |
std/buffer.zig+5-4| ... | @@ -1,10 +1,11 @@ | ... | @@ -1,10 +1,11 @@ |
| 1 | const debug = @import("debug.zig"); | 1 | const std = @import("index.zig"); |
| 2 | const mem = @import("mem.zig"); | 2 | const debug = std.debug; |
| 3 | const mem = std.mem; | ||
| 3 | const Allocator = mem.Allocator; | 4 | const Allocator = mem.Allocator; |
| 4 | const assert = debug.assert; | 5 | const assert = debug.assert; |
| 5 | const ArrayList = @import("array_list.zig").ArrayList; | 6 | const ArrayList = std.ArrayList; |
| 6 | 7 | ||
| 7 | const fmt = @import("fmt/index.zig"); | 8 | const fmt = std.fmt; |
| 8 | 9 | ||
| 9 | /// A buffer that allocates memory and maintains a null byte at the end. | 10 | /// A buffer that allocates memory and maintains a null byte at the end. |
| 10 | pub const Buffer = struct { | 11 | pub const Buffer = struct { |
std/cstr.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const debug = @import("debug.zig"); | 1 | const std = @import("index.zig"); |
| 2 | const mem = @import("mem.zig"); | 2 | const debug = std.debug; |
| 3 | const mem = std.mem; | ||
| 3 | const assert = debug.assert; | 4 | const assert = debug.assert; |
| 4 | 5 | ||
| 5 | pub fn len(ptr: &const u8) -> usize { | 6 | pub fn len(ptr: &const u8) -> usize { |
std/debug.zig deleted-1050| ... | @@ -1,1050 +0,0 @@ | ||
| 1 | const std = @import("index.zig"); | ||
| 2 | const math = std.math; | ||
| 3 | const mem = std.mem; | ||
| 4 | const io = std.io; | ||
| 5 | const os = std.os; | ||
| 6 | const elf = @import("elf.zig"); | ||
| 7 | const DW = @import("dwarf.zig"); | ||
| 8 | const ArrayList = std.ArrayList; | ||
| 9 | const builtin = @import("builtin"); | ||
| 10 | |||
| 11 | error MissingDebugInfo; | ||
| 12 | error InvalidDebugInfo; | ||
| 13 | error 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 | ||
| 19 | var stderr_file: io.File = undefined; | ||
| 20 | var stderr_file_out_stream: io.FileOutStream = undefined; | ||
| 21 | var stderr_stream: ?&io.OutStream = null; | ||
| 22 | pub fn warn(comptime fmt: []const u8, args: ...) { | ||
| 23 | const stderr = getStderrStream() %% return; | ||
| 24 | stderr.print(fmt, args) %% return; | ||
| 25 | } | ||
| 26 | fn 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. | ||
| 39 | pub 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. | ||
| 49 | pub 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. | ||
| 64 | pub fn assertOrPanic(ok: bool) { | ||
| 65 | if (!ok) { | ||
| 66 | @panic("assertion failure"); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | var panicking = false; | ||
| 71 | /// This is the default panic implementation. | ||
| 72 | pub 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 | |||
| 94 | const GREEN = "\x1b[32;1m"; | ||
| 95 | const WHITE = "\x1b[37;1m"; | ||
| 96 | const DIM = "\x1b[2m"; | ||
| 97 | const RESET = "\x1b[0m"; | ||
| 98 | |||
| 99 | error PathNotFound; | ||
| 100 | error InvalidDebugInfo; | ||
| 101 | |||
| 102 | pub 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 | |||
| 196 | fn 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 | |||
| 229 | const 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 | |||
| 251 | const PcRange = struct { | ||
| 252 | start: u64, | ||
| 253 | end: u64, | ||
| 254 | }; | ||
| 255 | |||
| 256 | const CompileUnit = struct { | ||
| 257 | version: u16, | ||
| 258 | is_64: bool, | ||
| 259 | die: &Die, | ||
| 260 | index: usize, | ||
| 261 | pc_range: ?PcRange, | ||
| 262 | }; | ||
| 263 | |||
| 264 | const AbbrevTable = ArrayList(AbbrevTableEntry); | ||
| 265 | |||
| 266 | const AbbrevTableHeader = struct { | ||
| 267 | // offset from .debug_abbrev | ||
| 268 | offset: u64, | ||
| 269 | table: AbbrevTable, | ||
| 270 | }; | ||
| 271 | |||
| 272 | const AbbrevTableEntry = struct { | ||
| 273 | has_children: bool, | ||
| 274 | abbrev_code: u64, | ||
| 275 | tag_id: u64, | ||
| 276 | attrs: ArrayList(AbbrevAttr), | ||
| 277 | }; | ||
| 278 | |||
| 279 | const AbbrevAttr = struct { | ||
| 280 | attr_id: u64, | ||
| 281 | form_id: u64, | ||
| 282 | }; | ||
| 283 | |||
| 284 | const 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 | |||
| 298 | const 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 | |||
| 311 | const 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 | |||
| 364 | const FileEntry = struct { | ||
| 365 | file_name: []const u8, | ||
| 366 | dir_index: usize, | ||
| 367 | mtime: usize, | ||
| 368 | len_bytes: usize, | ||
| 369 | }; | ||
| 370 | |||
| 371 | const 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 | |||
| 382 | const 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 | |||
| 459 | fn 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 | |||
| 470 | fn 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 | |||
| 476 | fn 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 | |||
| 483 | fn 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 | |||
| 488 | fn 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 | |||
| 493 | fn 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 | |||
| 500 | fn 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 | |||
| 505 | fn 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 | |||
| 511 | fn 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 | |||
| 516 | fn 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 | |||
| 521 | fn 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 | |||
| 571 | fn 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. | ||
| 603 | fn 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 | |||
| 617 | fn 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 | |||
| 625 | fn 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 | |||
| 647 | fn 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 | |||
| 825 | fn 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 | |||
| 901 | fn 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 | |||
| 937 | fn 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 | |||
| 948 | fn 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 | |||
| 969 | fn 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 | |||
| 992 | pub const global_allocator = &global_fixed_allocator.allocator; | ||
| 993 | var global_fixed_allocator = mem.FixedBufferAllocator.init(global_allocator_mem[0..]); | ||
| 994 | var 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. | ||
| 998 | pub 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 @@ | ||
| 1 | const std = @import("../index.zig"); | ||
| 2 | const mem = std.mem; | ||
| 3 | |||
| 4 | /// Allocator that fails after N allocations, useful for making sure out of | ||
| 5 | /// memory conditions are handled correctly. | ||
| 6 | pub 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 @@ | ||
| 1 | const std = @import("../index.zig"); | ||
| 2 | const math = std.math; | ||
| 3 | const mem = std.mem; | ||
| 4 | const io = std.io; | ||
| 5 | const os = std.os; | ||
| 6 | const elf = std.elf; | ||
| 7 | const DW = std.dwarf; | ||
| 8 | const ArrayList = std.ArrayList; | ||
| 9 | const builtin = @import("builtin"); | ||
| 10 | |||
| 11 | error MissingDebugInfo; | ||
| 12 | error InvalidDebugInfo; | ||
| 13 | error 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 | ||
| 19 | var stderr_file: io.File = undefined; | ||
| 20 | var stderr_file_out_stream: io.FileOutStream = undefined; | ||
| 21 | var stderr_stream: ?&io.OutStream = null; | ||
| 22 | pub fn warn(comptime fmt: []const u8, args: ...) { | ||
| 23 | const stderr = getStderrStream() %% return; | ||
| 24 | stderr.print(fmt, args) %% return; | ||
| 25 | } | ||
| 26 | fn 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. | ||
| 39 | pub 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. | ||
| 49 | pub 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. | ||
| 64 | pub fn assertOrPanic(ok: bool) { | ||
| 65 | if (!ok) { | ||
| 66 | @panic("assertion failure"); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | var panicking = false; | ||
| 71 | /// This is the default panic implementation. | ||
| 72 | pub 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 | |||
| 94 | const GREEN = "\x1b[32;1m"; | ||
| 95 | const WHITE = "\x1b[37;1m"; | ||
| 96 | const DIM = "\x1b[2m"; | ||
| 97 | const RESET = "\x1b[0m"; | ||
| 98 | |||
| 99 | error PathNotFound; | ||
| 100 | error InvalidDebugInfo; | ||
| 101 | |||
| 102 | pub 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 | |||
| 196 | fn 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 | |||
| 229 | const 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 | |||
| 251 | const PcRange = struct { | ||
| 252 | start: u64, | ||
| 253 | end: u64, | ||
| 254 | }; | ||
| 255 | |||
| 256 | const CompileUnit = struct { | ||
| 257 | version: u16, | ||
| 258 | is_64: bool, | ||
| 259 | die: &Die, | ||
| 260 | index: usize, | ||
| 261 | pc_range: ?PcRange, | ||
| 262 | }; | ||
| 263 | |||
| 264 | const AbbrevTable = ArrayList(AbbrevTableEntry); | ||
| 265 | |||
| 266 | const AbbrevTableHeader = struct { | ||
| 267 | // offset from .debug_abbrev | ||
| 268 | offset: u64, | ||
| 269 | table: AbbrevTable, | ||
| 270 | }; | ||
| 271 | |||
| 272 | const AbbrevTableEntry = struct { | ||
| 273 | has_children: bool, | ||
| 274 | abbrev_code: u64, | ||
| 275 | tag_id: u64, | ||
| 276 | attrs: ArrayList(AbbrevAttr), | ||
| 277 | }; | ||
| 278 | |||
| 279 | const AbbrevAttr = struct { | ||
| 280 | attr_id: u64, | ||
| 281 | form_id: u64, | ||
| 282 | }; | ||
| 283 | |||
| 284 | const 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 | |||
| 298 | const 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 | |||
| 311 | const 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 | |||
| 364 | const FileEntry = struct { | ||
| 365 | file_name: []const u8, | ||
| 366 | dir_index: usize, | ||
| 367 | mtime: usize, | ||
| 368 | len_bytes: usize, | ||
| 369 | }; | ||
| 370 | |||
| 371 | const 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 | |||
| 382 | const 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 | |||
| 459 | fn 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 | |||
| 470 | fn 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 | |||
| 476 | fn 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 | |||
| 483 | fn 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 | |||
| 488 | fn 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 | |||
| 493 | fn 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 | |||
| 500 | fn 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 | |||
| 505 | fn 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 | |||
| 511 | fn 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 | |||
| 516 | fn 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 | |||
| 521 | fn 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 | |||
| 571 | fn 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. | ||
| 603 | fn 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 | |||
| 617 | fn 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 | |||
| 625 | fn 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 | |||
| 647 | fn 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 | |||
| 825 | fn 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 | |||
| 901 | fn 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 | |||
| 937 | fn 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 | |||
| 948 | fn 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 | |||
| 969 | fn 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 | |||
| 992 | pub const global_allocator = &global_fixed_allocator.allocator; | ||
| 993 | var global_fixed_allocator = mem.FixedBufferAllocator.init(global_allocator_mem[0..]); | ||
| 994 | var global_allocator_mem: [100 * 1024]u8 = undefined; | ||
std/fmt/errol/index.zig+4-3| ... | @@ -1,10 +1,11 @@ | ... | @@ -1,10 +1,11 @@ |
| 1 | const std = @import("../../index.zig"); | ||
| 1 | const enum3 = @import("enum3.zig").enum3; | 2 | const enum3 = @import("enum3.zig").enum3; |
| 2 | const enum3_data = @import("enum3.zig").enum3_data; | 3 | const enum3_data = @import("enum3.zig").enum3_data; |
| 3 | const lookup_table = @import("lookup.zig").lookup_table; | 4 | const lookup_table = @import("lookup.zig").lookup_table; |
| 4 | const HP = @import("lookup.zig").HP; | 5 | const HP = @import("lookup.zig").HP; |
| 5 | const math = @import("../../math/index.zig"); | 6 | const math = std.math; |
| 6 | const mem = @import("../../mem.zig"); | 7 | const mem = std.mem; |
| 7 | const assert = @import("../../debug.zig").assert; | 8 | const assert = std.debug.assert; |
| 8 | 9 | ||
| 9 | pub const FloatDecimal = struct { | 10 | pub const FloatDecimal = struct { |
| 10 | digits: []u8, | 11 | digits: []u8, |
std/fmt/index.zig+4-3| ... | @@ -1,7 +1,8 @@ | ... | @@ -1,7 +1,8 @@ |
| 1 | const math = @import("../math/index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const debug = @import("../debug.zig"); | 2 | const math = std.math; |
| 3 | const debug = std.debug; | ||
| 3 | const assert = debug.assert; | 4 | const assert = debug.assert; |
| 4 | const mem = @import("../mem.zig"); | 5 | const mem = std.mem; |
| 5 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 6 | const errol3 = @import("errol/index.zig").errol3; | 7 | const errol3 = @import("errol/index.zig").errol3; |
| 7 | 8 |
std/hash_map.zig+4-3| ... | @@ -1,7 +1,8 @@ | ... | @@ -1,7 +1,8 @@ |
| 1 | const debug = @import("debug.zig"); | 1 | const std = @import("index.zig"); |
| 2 | const debug = std.debug; | ||
| 2 | const assert = debug.assert; | 3 | const assert = debug.assert; |
| 3 | const math = @import("math/index.zig"); | 4 | const math = std.math; |
| 4 | const mem = @import("mem.zig"); | 5 | const mem = std.mem; |
| 5 | const Allocator = mem.Allocator; | 6 | const Allocator = mem.Allocator; |
| 6 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 7 | 8 |
std/heap.zig+5-4| ... | @@ -1,10 +1,11 @@ | ... | @@ -1,10 +1,11 @@ |
| 1 | const debug = @import("debug.zig"); | 1 | const std = @import("index.zig"); |
| 2 | const debug = std.debug; | ||
| 2 | const assert = debug.assert; | 3 | const assert = debug.assert; |
| 3 | const mem = @import("mem.zig"); | 4 | const mem = std.mem; |
| 4 | const os = @import("os/index.zig"); | 5 | const os = std.os; |
| 5 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 6 | const Os = builtin.Os; | 7 | const Os = builtin.Os; |
| 7 | const c = @import("c/index.zig"); | 8 | const c = std.c; |
| 8 | 9 | ||
| 9 | const Allocator = mem.Allocator; | 10 | const Allocator = mem.Allocator; |
| 10 | 11 |
std/index.zig+2-2| ... | @@ -11,7 +11,7 @@ pub const base64 = @import("base64.zig"); | ... | @@ -11,7 +11,7 @@ pub const base64 = @import("base64.zig"); |
| 11 | pub const build = @import("build.zig"); | 11 | pub const build = @import("build.zig"); |
| 12 | pub const c = @import("c/index.zig"); | 12 | pub const c = @import("c/index.zig"); |
| 13 | pub const cstr = @import("cstr.zig"); | 13 | pub const cstr = @import("cstr.zig"); |
| 14 | pub const debug = @import("debug.zig"); | 14 | pub const debug = @import("debug/index.zig"); |
| 15 | pub const dwarf = @import("dwarf.zig"); | 15 | pub const dwarf = @import("dwarf.zig"); |
| 16 | pub const elf = @import("elf.zig"); | 16 | pub const elf = @import("elf.zig"); |
| 17 | pub const empty_import = @import("empty.zig"); | 17 | pub const empty_import = @import("empty.zig"); |
| ... | @@ -39,7 +39,7 @@ test "std" { | ... | @@ -39,7 +39,7 @@ test "std" { |
| 39 | _ = @import("build.zig"); | 39 | _ = @import("build.zig"); |
| 40 | _ = @import("c/index.zig"); | 40 | _ = @import("c/index.zig"); |
| 41 | _ = @import("cstr.zig"); | 41 | _ = @import("cstr.zig"); |
| 42 | _ = @import("debug.zig"); | 42 | _ = @import("debug/index.zig"); |
| 43 | _ = @import("dwarf.zig"); | 43 | _ = @import("dwarf.zig"); |
| 44 | _ = @import("elf.zig"); | 44 | _ = @import("elf.zig"); |
| 45 | _ = @import("empty.zig"); | 45 | _ = @import("empty.zig"); |
std/linked_list.zig+3-2| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const debug = @import("debug.zig"); | 1 | const std = @import("index.zig"); |
| 2 | const debug = std.debug; | ||
| 2 | const assert = debug.assert; | 3 | const assert = debug.assert; |
| 3 | const mem = @import("mem.zig"); | 4 | const mem = std.mem; |
| 4 | const Allocator = mem.Allocator; | 5 | const Allocator = mem.Allocator; |
| 5 | 6 | ||
| 6 | /// Generic doubly linked list. | 7 | /// Generic doubly linked list. |
std/math/acos.zig+3-2| ... | @@ -2,8 +2,9 @@ | ... | @@ -2,8 +2,9 @@ |
| 2 | // | 2 | // |
| 3 | // - acos(x) = nan if x < -1 or x > 1 | 3 | // - acos(x) = nan if x < -1 or x > 1 |
| 4 | 4 | ||
| 5 | const math = @import("index.zig"); | 5 | const std = @import("../index.zig"); |
| 6 | const assert = @import("../debug.zig").assert; | 6 | const math = std.math; |
| 7 | const assert = std.debug.assert; | ||
| 7 | 8 | ||
| 8 | pub fn acos(x: var) -> @typeOf(x) { | 9 | pub fn acos(x: var) -> @typeOf(x) { |
| 9 | const T = @typeOf(x); | 10 | const T = @typeOf(x); |
std/math/acosh.zig+3-2| ... | @@ -4,8 +4,9 @@ | ... | @@ -4,8 +4,9 @@ |
| 4 | // - acosh(nan) = nan | 4 | // - acosh(nan) = nan |
| 5 | 5 | ||
| 6 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 7 | const math = @import("index.zig"); | 7 | const std = @import("../index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const math = std.math; |
| 9 | const assert = std.debug.assert; | ||
| 9 | 10 | ||
| 10 | pub fn acosh(x: var) -> @typeOf(x) { | 11 | pub fn acosh(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
std/math/asin.zig+3-2| ... | @@ -3,8 +3,9 @@ | ... | @@ -3,8 +3,9 @@ |
| 3 | // - asin(+-0) = +-0 | 3 | // - asin(+-0) = +-0 |
| 4 | // - asin(x) = nan if x < -1 or x > 1 | 4 | // - asin(x) = nan if x < -1 or x > 1 |
| 5 | 5 | ||
| 6 | const math = @import("index.zig"); | 6 | const std = @import("../index.zig"); |
| 7 | const assert = @import("../debug.zig").assert; | 7 | const math = std.math; |
| 8 | const assert = std.debug.assert; | ||
| 8 | 9 | ||
| 9 | pub fn asin(x: var) -> @typeOf(x) { | 10 | pub fn asin(x: var) -> @typeOf(x) { |
| 10 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
std/math/asinh.zig+3-2| ... | @@ -4,8 +4,9 @@ | ... | @@ -4,8 +4,9 @@ |
| 4 | // - asinh(+-inf) = +-inf | 4 | // - asinh(+-inf) = +-inf |
| 5 | // - asinh(nan) = nan | 5 | // - asinh(nan) = nan |
| 6 | 6 | ||
| 7 | const math = @import("index.zig"); | 7 | const std = @import("../index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const math = std.math; |
| 9 | const assert = std.debug.assert; | ||
| 9 | 10 | ||
| 10 | pub fn asinh(x: var) -> @typeOf(x) { | 11 | pub fn asinh(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
std/math/atan.zig+3-2| ... | @@ -3,8 +3,9 @@ | ... | @@ -3,8 +3,9 @@ |
| 3 | // - atan(+-0) = +-0 | 3 | // - atan(+-0) = +-0 |
| 4 | // - atan(+-inf) = +-pi/2 | 4 | // - atan(+-inf) = +-pi/2 |
| 5 | 5 | ||
| 6 | const math = @import("index.zig"); | 6 | const std = @import("../index.zig"); |
| 7 | const assert = @import("../debug.zig").assert; | 7 | const math = std.math; |
| 8 | const assert = std.debug.assert; | ||
| 8 | 9 | ||
| 9 | pub fn atan(x: var) -> @typeOf(x) { | 10 | pub fn atan(x: var) -> @typeOf(x) { |
| 10 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
std/math/atan2.zig+3-2| ... | @@ -18,8 +18,9 @@ | ... | @@ -18,8 +18,9 @@ |
| 18 | // atan2(+inf, x) = +pi/2 | 18 | // atan2(+inf, x) = +pi/2 |
| 19 | // atan2(-inf, x) = -pi/2 | 19 | // atan2(-inf, x) = -pi/2 |
| 20 | 20 | ||
| 21 | const math = @import("index.zig"); | 21 | const std = @import("../index.zig"); |
| 22 | const assert = @import("../debug.zig").assert; | 22 | const math = std.math; |
| 23 | const assert = std.debug.assert; | ||
| 23 | 24 | ||
| 24 | fn atan2(comptime T: type, x: T, y: T) -> T { | 25 | fn atan2(comptime T: type, x: T, y: T) -> T { |
| 25 | return switch (T) { | 26 | return switch (T) { |
std/math/atanh.zig+3-2| ... | @@ -4,8 +4,9 @@ | ... | @@ -4,8 +4,9 @@ |
| 4 | // - atanh(x) = nan if |x| > 1 with signal | 4 | // - atanh(x) = nan if |x| > 1 with signal |
| 5 | // - atanh(nan) = nan | 5 | // - atanh(nan) = nan |
| 6 | 6 | ||
| 7 | const math = @import("index.zig"); | 7 | const std = @import("../index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const math = std.math; |
| 9 | const assert = std.debug.assert; | ||
| 9 | 10 | ||
| 10 | pub fn atanh(x: var) -> @typeOf(x) { | 11 | pub fn atanh(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
std/math/cbrt.zig+3-2| ... | @@ -4,8 +4,9 @@ | ... | @@ -4,8 +4,9 @@ |
| 4 | // - cbrt(+-inf) = +-inf | 4 | // - cbrt(+-inf) = +-inf |
| 5 | // - cbrt(nan) = nan | 5 | // - cbrt(nan) = nan |
| 6 | 6 | ||
| 7 | const math = @import("index.zig"); | 7 | const std = @import("../index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const math = std.math; |
| 9 | const assert = std.debug.assert; | ||
| 9 | 10 | ||
| 10 | pub fn cbrt(x: var) -> @typeOf(x) { | 11 | pub fn cbrt(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
std/math/ceil.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - ceil(nan) = nan | 5 | // - ceil(nan) = nan |
| 6 | 6 | ||
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | 11 | ||
| 11 | pub fn ceil(x: var) -> @typeOf(x) { | 12 | pub fn ceil(x: var) -> @typeOf(x) { |
| 12 | const T = @typeOf(x); | 13 | const T = @typeOf(x); |
std/math/copysign.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub fn copysign(comptime T: type, x: T, y: T) -> T { | 5 | pub fn copysign(comptime T: type, x: T, y: T) -> T { |
| 5 | return switch (T) { | 6 | return switch (T) { |
std/math/cos.zig+3-2| ... | @@ -4,8 +4,9 @@ | ... | @@ -4,8 +4,9 @@ |
| 4 | // - cos(nan) = nan | 4 | // - cos(nan) = nan |
| 5 | 5 | ||
| 6 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 7 | const math = @import("index.zig"); | 7 | const std = @import("../index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const math = std.math; |
| 9 | const assert = std.debug.assert; | ||
| 9 | 10 | ||
| 10 | pub fn cos(x: var) -> @typeOf(x) { | 11 | pub fn cos(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
std/math/cosh.zig+3-2| ... | @@ -5,9 +5,10 @@ | ... | @@ -5,9 +5,10 @@ |
| 5 | // - cosh(nan) = nan | 5 | // - cosh(nan) = nan |
| 6 | 6 | ||
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const math = std.math; | ||
| 9 | const expo2 = @import("expo2.zig").expo2; | 10 | const expo2 = @import("expo2.zig").expo2; |
| 10 | const assert = @import("../debug.zig").assert; | 11 | const assert = std.debug.assert; |
| 11 | 12 | ||
| 12 | pub fn cosh(x: var) -> @typeOf(x) { | 13 | pub fn cosh(x: var) -> @typeOf(x) { |
| 13 | const T = @typeOf(x); | 14 | const T = @typeOf(x); |
std/math/exp.zig+3-2| ... | @@ -3,8 +3,9 @@ | ... | @@ -3,8 +3,9 @@ |
| 3 | // - exp(+inf) = +inf | 3 | // - exp(+inf) = +inf |
| 4 | // - exp(nan) = nan | 4 | // - exp(nan) = nan |
| 5 | 5 | ||
| 6 | const math = @import("index.zig"); | 6 | const std = @import("../index.zig"); |
| 7 | const assert = @import("../debug.zig").assert; | 7 | const math = std.math; |
| 8 | const assert = std.debug.assert; | ||
| 8 | 9 | ||
| 9 | pub fn exp(x: var) -> @typeOf(x) { | 10 | pub fn exp(x: var) -> @typeOf(x) { |
| 10 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
std/math/exp2.zig+3-2| ... | @@ -3,8 +3,9 @@ | ... | @@ -3,8 +3,9 @@ |
| 3 | // - exp2(+inf) = +inf | 3 | // - exp2(+inf) = +inf |
| 4 | // - exp2(nan) = nan | 4 | // - exp2(nan) = nan |
| 5 | 5 | ||
| 6 | const math = @import("index.zig"); | 6 | const std = @import("../index.zig"); |
| 7 | const assert = @import("../debug.zig").assert; | 7 | const math = std.math; |
| 8 | const assert = std.debug.assert; | ||
| 8 | 9 | ||
| 9 | pub fn exp2(x: var) -> @typeOf(x) { | 10 | pub fn exp2(x: var) -> @typeOf(x) { |
| 10 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
std/math/expm1.zig+3-2| ... | @@ -4,8 +4,9 @@ | ... | @@ -4,8 +4,9 @@ |
| 4 | // - expm1(-inf) = -1 | 4 | // - expm1(-inf) = -1 |
| 5 | // - expm1(nan) = nan | 5 | // - expm1(nan) = nan |
| 6 | 6 | ||
| 7 | const math = @import("index.zig"); | 7 | const std = @import("../index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const math = std.math; |
| 9 | const assert = std.debug.assert; | ||
| 9 | 10 | ||
| 10 | pub fn expm1(x: var) -> @typeOf(x) { | 11 | pub fn expm1(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
std/math/fabs.zig+3-2| ... | @@ -3,8 +3,9 @@ | ... | @@ -3,8 +3,9 @@ |
| 3 | // - fabs(+-inf) = +inf | 3 | // - fabs(+-inf) = +inf |
| 4 | // - fabs(nan) = nan | 4 | // - fabs(nan) = nan |
| 5 | 5 | ||
| 6 | const math = @import("index.zig"); | 6 | const std = @import("../index.zig"); |
| 7 | const assert = @import("../debug.zig").assert; | 7 | const math = std.math; |
| 8 | const assert = std.debug.assert; | ||
| 8 | 9 | ||
| 9 | pub fn fabs(x: var) -> @typeOf(x) { | 10 | pub fn fabs(x: var) -> @typeOf(x) { |
| 10 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
std/math/floor.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - floor(nan) = nan | 5 | // - floor(nan) = nan |
| 6 | 6 | ||
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const assert = std.debug.assert; |
| 9 | const math = @import("index.zig"); | 9 | const std = @import("../index.zig"); |
| 10 | const math = std.math; | ||
| 10 | 11 | ||
| 11 | pub fn floor(x: var) -> @typeOf(x) { | 12 | pub fn floor(x: var) -> @typeOf(x) { |
| 12 | const T = @typeOf(x); | 13 | const T = @typeOf(x); |
std/math/fma.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub fn fma(comptime T: type, x: T, y: T, z: T) -> T { | 5 | pub fn fma(comptime T: type, x: T, y: T, z: T) -> T { |
| 5 | return switch (T) { | 6 | return switch (T) { |
std/math/frexp.zig+3-2| ... | @@ -4,8 +4,9 @@ | ... | @@ -4,8 +4,9 @@ |
| 4 | // - frexp(+-inf) = +-inf, 0 | 4 | // - frexp(+-inf) = +-inf, 0 |
| 5 | // - frexp(nan) = nan, undefined | 5 | // - frexp(nan) = nan, undefined |
| 6 | 6 | ||
| 7 | const math = @import("index.zig"); | 7 | const std = @import("../index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const math = std.math; |
| 9 | const assert = std.debug.assert; | ||
| 9 | 10 | ||
| 10 | fn frexp_result(comptime T: type) -> type { | 11 | fn frexp_result(comptime T: type) -> type { |
| 11 | return struct { | 12 | return struct { |
std/math/hypot.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - hypot(nan, y) = nan | 5 | // - hypot(nan, y) = nan |
| 6 | // - hypot(x, nan) = nan | 6 | // - hypot(x, nan) = nan |
| 7 | 7 | ||
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | 11 | ||
| 11 | pub fn hypot(comptime T: type, x: T, y: T) -> T { | 12 | pub fn hypot(comptime T: type, x: T, y: T) -> T { |
| 12 | return switch (T) { | 13 | return switch (T) { |
std/math/ilogb.zig+3-2| ... | @@ -4,8 +4,9 @@ | ... | @@ -4,8 +4,9 @@ |
| 4 | // - ilogb(0) = @maxValue(i32) | 4 | // - ilogb(0) = @maxValue(i32) |
| 5 | // - ilogb(nan) = @maxValue(i32) | 5 | // - ilogb(nan) = @maxValue(i32) |
| 6 | 6 | ||
| 7 | const math = @import("index.zig"); | 7 | const std = @import("../index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const math = std.math; |
| 9 | const assert = std.debug.assert; | ||
| 9 | 10 | ||
| 10 | pub fn ilogb(x: var) -> i32 { | 11 | pub fn ilogb(x: var) -> i32 { |
| 11 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
std/math/index.zig+2-1| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const builtin = @import("builtin"); |
| 2 | const std = @import("../index.zig"); | ||
| 2 | const TypeId = builtin.TypeId; | 3 | const TypeId = builtin.TypeId; |
| 3 | const assert = @import("../debug.zig").assert; | 4 | const assert = std.debug.assert; |
| 4 | 5 | ||
| 5 | pub const e = 2.71828182845904523536028747135266249775724709369995; | 6 | pub const e = 2.71828182845904523536028747135266249775724709369995; |
| 6 | pub const pi = 3.14159265358979323846264338327950288419716939937510; | 7 | pub const pi = 3.14159265358979323846264338327950288419716939937510; |
std/math/inf.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub fn inf(comptime T: type) -> T { | 5 | pub fn inf(comptime T: type) -> T { |
| 5 | return switch (T) { | 6 | return switch (T) { |
std/math/isfinite.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub fn isFinite(x: var) -> bool { | 5 | pub fn isFinite(x: var) -> bool { |
| 5 | const T = @typeOf(x); | 6 | const T = @typeOf(x); |
std/math/isinf.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub fn isInf(x: var) -> bool { | 5 | pub fn isInf(x: var) -> bool { |
| 5 | const T = @typeOf(x); | 6 | const T = @typeOf(x); |
std/math/isnan.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub fn isNan(x: var) -> bool { | 5 | pub fn isNan(x: var) -> bool { |
| 5 | const T = @typeOf(x); | 6 | const T = @typeOf(x); |
std/math/isnormal.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub fn isNormal(x: var) -> bool { | 5 | pub fn isNormal(x: var) -> bool { |
| 5 | const T = @typeOf(x); | 6 | const T = @typeOf(x); |
std/math/ln.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - ln(x) = nan if x < 0 | 5 | // - ln(x) = nan if x < 0 |
| 6 | // - ln(nan) = nan | 6 | // - ln(nan) = nan |
| 7 | 7 | ||
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | const builtin = @import("builtin"); | 11 | const builtin = @import("builtin"); |
| 11 | const TypeId = builtin.TypeId; | 12 | const TypeId = builtin.TypeId; |
| 12 | 13 |
std/math/log.zig+3-2| ... | @@ -1,7 +1,8 @@ | ... | @@ -1,7 +1,8 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const math = std.math; | ||
| 2 | const builtin = @import("builtin"); | 3 | const builtin = @import("builtin"); |
| 3 | const TypeId = builtin.TypeId; | 4 | const TypeId = builtin.TypeId; |
| 4 | const assert = @import("../debug.zig").assert; | 5 | const assert = std.debug.assert; |
| 5 | 6 | ||
| 6 | pub fn log(comptime T: type, base: T, x: T) -> T { | 7 | pub fn log(comptime T: type, base: T, x: T) -> T { |
| 7 | if (base == 2) { | 8 | if (base == 2) { |
std/math/log10.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - log10(x) = nan if x < 0 | 5 | // - log10(x) = nan if x < 0 |
| 6 | // - log10(nan) = nan | 6 | // - log10(nan) = nan |
| 7 | 7 | ||
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | const builtin = @import("builtin"); | 11 | const builtin = @import("builtin"); |
| 11 | const TypeId = builtin.TypeId; | 12 | const TypeId = builtin.TypeId; |
| 12 | 13 |
std/math/log1p.zig+3-2| ... | @@ -6,8 +6,9 @@ | ... | @@ -6,8 +6,9 @@ |
| 6 | // - log1p(x) = nan if x < -1 | 6 | // - log1p(x) = nan if x < -1 |
| 7 | // - log1p(nan) = nan | 7 | // - log1p(nan) = nan |
| 8 | 8 | ||
| 9 | const math = @import("index.zig"); | 9 | const std = @import("../index.zig"); |
| 10 | const assert = @import("../debug.zig").assert; | 10 | const math = std.math; |
| 11 | const assert = std.debug.assert; | ||
| 11 | 12 | ||
| 12 | pub fn log1p(x: var) -> @typeOf(x) { | 13 | pub fn log1p(x: var) -> @typeOf(x) { |
| 13 | const T = @typeOf(x); | 14 | const T = @typeOf(x); |
std/math/log2.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - log2(x) = nan if x < 0 | 5 | // - log2(x) = nan if x < 0 |
| 6 | // - log2(nan) = nan | 6 | // - log2(nan) = nan |
| 7 | 7 | ||
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | const builtin = @import("builtin"); | 11 | const builtin = @import("builtin"); |
| 11 | const TypeId = builtin.TypeId; | 12 | const TypeId = builtin.TypeId; |
| 12 | 13 |
std/math/modf.zig+3-2| ... | @@ -3,8 +3,9 @@ | ... | @@ -3,8 +3,9 @@ |
| 3 | // - modf(+-inf) = +-inf, nan | 3 | // - modf(+-inf) = +-inf, nan |
| 4 | // - modf(nan) = nan, nan | 4 | // - modf(nan) = nan, nan |
| 5 | 5 | ||
| 6 | const math = @import("index.zig"); | 6 | const std = @import("../index.zig"); |
| 7 | const assert = @import("../debug.zig").assert; | 7 | const math = std.math; |
| 8 | const assert = std.debug.assert; | ||
| 8 | 9 | ||
| 9 | fn modf_result(comptime T: type) -> type { | 10 | fn modf_result(comptime T: type) -> type { |
| 10 | return struct { | 11 | return struct { |
std/math/pow.zig+3-2| ... | @@ -22,8 +22,9 @@ | ... | @@ -22,8 +22,9 @@ |
| 22 | // pow(x, y) = nan for finite x < 0 and finite non-integer y | 22 | // pow(x, y) = nan for finite x < 0 and finite non-integer y |
| 23 | 23 | ||
| 24 | const builtin = @import("builtin"); | 24 | const builtin = @import("builtin"); |
| 25 | const math = @import("index.zig"); | 25 | const std = @import("../index.zig"); |
| 26 | const assert = @import("../debug.zig").assert; | 26 | const math = std.math; |
| 27 | const assert = std.debug.assert; | ||
| 27 | 28 | ||
| 28 | // This implementation is taken from the go stlib, musl is a bit more complex. | 29 | // This implementation is taken from the go stlib, musl is a bit more complex. |
| 29 | pub fn pow(comptime T: type, x: T, y: T) -> T { | 30 | pub fn pow(comptime T: type, x: T, y: T) -> T { |
std/math/round.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - round(nan) = nan | 5 | // - round(nan) = nan |
| 6 | 6 | ||
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const assert = std.debug.assert; |
| 9 | const math = @import("index.zig"); | 9 | const std = @import("../index.zig"); |
| 10 | const math = std.math; | ||
| 10 | 11 | ||
| 11 | pub fn round(x: var) -> @typeOf(x) { | 12 | pub fn round(x: var) -> @typeOf(x) { |
| 12 | const T = @typeOf(x); | 13 | const T = @typeOf(x); |
std/math/scalbn.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub fn scalbn(x: var, n: i32) -> @typeOf(x) { | 5 | pub fn scalbn(x: var, n: i32) -> @typeOf(x) { |
| 5 | const T = @typeOf(x); | 6 | const T = @typeOf(x); |
std/math/signbit.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub fn signbit(x: var) -> bool { | 5 | pub fn signbit(x: var) -> bool { |
| 5 | const T = @typeOf(x); | 6 | const T = @typeOf(x); |
std/math/sin.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - sin(nan) = nan | 5 | // - sin(nan) = nan |
| 6 | 6 | ||
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | 11 | ||
| 11 | pub fn sin(x: var) -> @typeOf(x) { | 12 | pub fn sin(x: var) -> @typeOf(x) { |
| 12 | const T = @typeOf(x); | 13 | const T = @typeOf(x); |
std/math/sinh.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - sinh(nan) = nan | 5 | // - sinh(nan) = nan |
| 6 | 6 | ||
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | const expo2 = @import("expo2.zig").expo2; | 11 | const expo2 = @import("expo2.zig").expo2; |
| 11 | 12 | ||
| 12 | pub fn sinh(x: var) -> @typeOf(x) { | 13 | pub fn sinh(x: var) -> @typeOf(x) { |
std/math/sqrt.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - sqrt(x) = nan if x < 0 | 5 | // - sqrt(x) = nan if x < 0 |
| 6 | // - sqrt(nan) = nan | 6 | // - sqrt(nan) = nan |
| 7 | 7 | ||
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | const builtin = @import("builtin"); | 11 | const builtin = @import("builtin"); |
| 11 | const TypeId = builtin.TypeId; | 12 | const TypeId = builtin.TypeId; |
| 12 | 13 |
std/math/tan.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - tan(nan) = nan | 5 | // - tan(nan) = nan |
| 6 | 6 | ||
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | 11 | ||
| 11 | pub fn tan(x: var) -> @typeOf(x) { | 12 | pub fn tan(x: var) -> @typeOf(x) { |
| 12 | const T = @typeOf(x); | 13 | const T = @typeOf(x); |
std/math/tanh.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - sinh(nan) = nan | 5 | // - sinh(nan) = nan |
| 6 | 6 | ||
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | const expo2 = @import("expo2.zig").expo2; | 11 | const expo2 = @import("expo2.zig").expo2; |
| 11 | 12 | ||
| 12 | pub fn tanh(x: var) -> @typeOf(x) { | 13 | pub fn tanh(x: var) -> @typeOf(x) { |
std/math/trunc.zig+3-2| ... | @@ -4,8 +4,9 @@ | ... | @@ -4,8 +4,9 @@ |
| 4 | // - trunc(+-inf) = +-inf | 4 | // - trunc(+-inf) = +-inf |
| 5 | // - trunc(nan) = nan | 5 | // - trunc(nan) = nan |
| 6 | 6 | ||
| 7 | const math = @import("index.zig"); | 7 | const std = @import("../index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const math = std.math; |
| 9 | const assert = std.debug.assert; | ||
| 9 | 10 | ||
| 10 | pub fn trunc(x: var) -> @typeOf(x) { | 11 | pub fn trunc(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
std/mem.zig+3-2| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const debug = @import("debug.zig"); | 1 | const std = @import("index.zig"); |
| 2 | const debug = std.debug; | ||
| 2 | const assert = debug.assert; | 3 | const assert = debug.assert; |
| 3 | const math = @import("math/index.zig"); | 4 | const math = std.math; |
| 4 | const builtin = @import("builtin"); | 5 | const builtin = @import("builtin"); |
| 5 | 6 | ||
| 6 | error OutOfMemory; | 7 | error OutOfMemory; |
std/net.zig+4-3| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const linux = @import("os/linux.zig"); | 1 | const std = @import("index.zig"); |
| 2 | const assert = @import("debug.zig").assert; | 2 | const linux = std.os.linux; |
| 3 | const endian = @import("endian.zig"); | 3 | const assert = std.debug.assert; |
| 4 | const endian = std.endian; | ||
| 4 | 5 | ||
| 5 | error SigInterrupt; | 6 | error SigInterrupt; |
| 6 | error Io; | 7 | error Io; |
std/os/darwin.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const c = @import("../c/index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const c = std.c; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub use @import("darwin_errno.zig"); | 5 | pub use @import("darwin_errno.zig"); |
| 5 | 6 |
std/os/index.zig+11-10| ... | @@ -1,3 +1,4 @@ | ... | @@ -1,3 +1,4 @@ |
| 1 | const std = @import("../index.zig"); | ||
| 1 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 2 | const Os = builtin.Os; | 3 | const Os = builtin.Os; |
| 3 | const is_windows = builtin.os == Os.windows; | 4 | const is_windows = builtin.os == Os.windows; |
| ... | @@ -37,22 +38,22 @@ pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock; | ... | @@ -37,22 +38,22 @@ pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock; |
| 37 | 38 | ||
| 38 | pub const FileHandle = if (is_windows) windows.HANDLE else i32; | 39 | pub const FileHandle = if (is_windows) windows.HANDLE else i32; |
| 39 | 40 | ||
| 40 | const debug = @import("../debug.zig"); | 41 | const debug = std.debug; |
| 41 | const assert = debug.assert; | 42 | const assert = debug.assert; |
| 42 | 43 | ||
| 43 | const c = @import("../c/index.zig"); | 44 | const c = std.c; |
| 44 | 45 | ||
| 45 | const mem = @import("../mem.zig"); | 46 | const mem = std.mem; |
| 46 | const Allocator = mem.Allocator; | 47 | const Allocator = mem.Allocator; |
| 47 | 48 | ||
| 48 | const BufMap = @import("../buf_map.zig").BufMap; | 49 | const BufMap = std.BufMap; |
| 49 | const cstr = @import("../cstr.zig"); | 50 | const cstr = std.cstr; |
| 50 | 51 | ||
| 51 | const io = @import("../io.zig"); | 52 | const io = std.io; |
| 52 | const base64 = @import("../base64.zig"); | 53 | const base64 = std.base64; |
| 53 | const ArrayList = @import("../array_list.zig").ArrayList; | 54 | const ArrayList = std.ArrayList; |
| 54 | const Buffer = @import("../buffer.zig").Buffer; | 55 | const Buffer = std.Buffer; |
| 55 | const math = @import("../index.zig").math; | 56 | const math = std.math; |
| 56 | 57 | ||
| 57 | error SystemResources; | 58 | error SystemResources; |
| 58 | error AccessDenied; | 59 | error AccessDenied; |
std/os/linux.zig+2-1| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | const assert = @import("../debug.zig").assert; | 1 | const std = @import("../index.zig"); |
| 2 | const assert = std.debug.assert; | ||
| 2 | const builtin = @import("builtin"); | 3 | const builtin = @import("builtin"); |
| 3 | const arch = switch (builtin.arch) { | 4 | const arch = switch (builtin.arch) { |
| 4 | builtin.Arch.x86_64 => @import("linux_x86_64.zig"), | 5 | builtin.Arch.x86_64 => @import("linux_x86_64.zig"), |
std/os/path.zig+7-7| ... | @@ -1,16 +1,16 @@ | ... | @@ -1,16 +1,16 @@ |
| 1 | const std = @import("../index.zig"); | ||
| 1 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 2 | const Os = builtin.Os; | 3 | const Os = builtin.Os; |
| 3 | const debug = @import("../debug.zig"); | 4 | const debug = std.debug; |
| 4 | const assert = debug.assert; | 5 | const assert = debug.assert; |
| 5 | const mem = @import("../mem.zig"); | 6 | const mem = std.mem; |
| 6 | const fmt = @import("../fmt/index.zig"); | 7 | const fmt = std.fmt; |
| 7 | const Allocator = mem.Allocator; | 8 | const Allocator = mem.Allocator; |
| 8 | const os = @import("index.zig"); | 9 | const os = std.os; |
| 9 | const math = @import("../math/index.zig"); | 10 | const math = std.math; |
| 10 | const posix = os.posix; | 11 | const posix = os.posix; |
| 11 | const windows = os.windows; | 12 | const windows = os.windows; |
| 12 | const c = @import("../c/index.zig"); | 13 | const cstr = std.cstr; |
| 13 | const cstr = @import("../cstr.zig"); | ||
| 14 | 14 | ||
| 15 | pub const sep_windows = '\\'; | 15 | pub const sep_windows = '\\'; |
| 16 | pub const sep_posix = '/'; | 16 | pub const sep_posix = '/'; |
std/rand.zig+4-3| ... | @@ -1,8 +1,9 @@ | ... | @@ -1,8 +1,9 @@ |
| 1 | const std = @import("index.zig"); | ||
| 1 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 2 | const assert = @import("debug.zig").assert; | 3 | const assert = std.debug.assert; |
| 3 | const rand_test = @import("rand_test.zig"); | 4 | const rand_test = @import("rand_test.zig"); |
| 4 | const mem = @import("mem.zig"); | 5 | const mem = std.mem; |
| 5 | const math = @import("math/index.zig"); | 6 | const math = std.math; |
| 6 | 7 | ||
| 7 | pub const MT19937_32 = MersenneTwister( | 8 | pub const MT19937_32 = MersenneTwister( |
| 8 | u32, 624, 397, 31, | 9 | u32, 624, 397, 31, |
std/special/compiler_rt/fixunsdfdi_test.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi; | 1 | const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi; |
| 2 | const assert = @import("../../debug.zig").assert; | 2 | const assert = @import("../../index.zig").debug.assert; |
| 3 | 3 | ||
| 4 | fn test__fixunsdfdi(a: f64, expected: u64) { | 4 | fn test__fixunsdfdi(a: f64, expected: u64) { |
| 5 | const x = __fixunsdfdi(a); | 5 | const x = __fixunsdfdi(a); |
std/special/compiler_rt/fixunsdfsi_test.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi; | 1 | const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi; |
| 2 | const assert = @import("../../debug.zig").assert; | 2 | const assert = @import("../../index.zig").debug.assert; |
| 3 | 3 | ||
| 4 | fn test__fixunsdfsi(a: f64, expected: u32) { | 4 | fn test__fixunsdfsi(a: f64, expected: u32) { |
| 5 | const x = __fixunsdfsi(a); | 5 | const x = __fixunsdfsi(a); |
std/special/compiler_rt/fixunsdfti_test.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti; | 1 | const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti; |
| 2 | const assert = @import("../../debug.zig").assert; | 2 | const assert = @import("../../index.zig").debug.assert; |
| 3 | 3 | ||
| 4 | fn test__fixunsdfti(a: f64, expected: u128) { | 4 | fn test__fixunsdfti(a: f64, expected: u128) { |
| 5 | const x = __fixunsdfti(a); | 5 | const x = __fixunsdfti(a); |
std/special/compiler_rt/fixunssfdi_test.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi; | 1 | const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi; |
| 2 | const assert = @import("../../debug.zig").assert; | 2 | const assert = @import("../../index.zig").debug.assert; |
| 3 | 3 | ||
| 4 | fn test__fixunssfdi(a: f32, expected: u64) { | 4 | fn test__fixunssfdi(a: f32, expected: u64) { |
| 5 | const x = __fixunssfdi(a); | 5 | const x = __fixunssfdi(a); |
std/special/compiler_rt/fixunssfsi_test.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi; | 1 | const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi; |
| 2 | const assert = @import("../../debug.zig").assert; | 2 | const assert = @import("../../index.zig").debug.assert; |
| 3 | 3 | ||
| 4 | fn test__fixunssfsi(a: f32, expected: u32) { | 4 | fn test__fixunssfsi(a: f32, expected: u32) { |
| 5 | const x = __fixunssfsi(a); | 5 | const x = __fixunssfsi(a); |
std/special/compiler_rt/fixunssfti_test.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const __fixunssfti = @import("fixunssfti.zig").__fixunssfti; | 1 | const __fixunssfti = @import("fixunssfti.zig").__fixunssfti; |
| 2 | const assert = @import("../../debug.zig").assert; | 2 | const assert = @import("../../index.zig").debug.assert; |
| 3 | 3 | ||
| 4 | fn test__fixunssfti(a: f32, expected: u128) { | 4 | fn test__fixunssfti(a: f32, expected: u128) { |
| 5 | const x = __fixunssfti(a); | 5 | const x = __fixunssfti(a); |
std/special/compiler_rt/fixunstfdi_test.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi; | 1 | const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi; |
| 2 | const assert = @import("../../debug.zig").assert; | 2 | const assert = @import("../../index.zig").debug.assert; |
| 3 | 3 | ||
| 4 | fn test__fixunstfdi(a: f128, expected: u64) { | 4 | fn test__fixunstfdi(a: f128, expected: u64) { |
| 5 | const x = __fixunstfdi(a); | 5 | const x = __fixunstfdi(a); |
std/special/compiler_rt/fixunstfsi_test.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi; | 1 | const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi; |
| 2 | const assert = @import("../../debug.zig").assert; | 2 | const assert = @import("../../index.zig").debug.assert; |
| 3 | 3 | ||
| 4 | fn test__fixunstfsi(a: f128, expected: u32) { | 4 | fn test__fixunstfsi(a: f128, expected: u32) { |
| 5 | const x = __fixunstfsi(a); | 5 | const x = __fixunstfsi(a); |
std/special/compiler_rt/fixunstfti_test.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const __fixunstfti = @import("fixunstfti.zig").__fixunstfti; | 1 | const __fixunstfti = @import("fixunstfti.zig").__fixunstfti; |
| 2 | const assert = @import("../../debug.zig").assert; | 2 | const assert = @import("../../index.zig").debug.assert; |
| 3 | 3 | ||
| 4 | fn test__fixunstfti(a: f128, expected: u128) { | 4 | fn test__fixunstfti(a: f128, expected: u128) { |
| 5 | const x = __fixunstfti(a); | 5 | const x = __fixunstfti(a); |
std/special/compiler_rt/index.zig+1-1| ... | @@ -68,7 +68,7 @@ comptime { | ... | @@ -68,7 +68,7 @@ comptime { |
| 68 | } | 68 | } |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | const assert = @import("../../debug.zig").assert; | 71 | const assert = @import("../../index.zig").debug.assert; |
| 72 | 72 | ||
| 73 | const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4; | 73 | const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4; |
| 74 | 74 |