diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-03-10 15:27:45 -0400 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-03-10 15:32:32 -0400 |
| commit | ba0e3be5cfa2f60f2f9d2a4eb319408f972796c2 (patch) | |
| tree | da35c17d0067a463b521163f624f3d109b8050f4 /lib/std/debug.zig | |
| parent | 1ad831a0ef22f354d4e1dd5073456a0683249846 (diff) | |
| download | zig-ba0e3be5cfa2f60f2f9d2a4eb319408f972796c2.tar.gz zig-ba0e3be5cfa2f60f2f9d2a4eb319408f972796c2.zip | |
(breaking) rework stream abstractions
The main goal here is to make the function pointers comptime, so that we
don't have to do the crazy stuff with async function frames.
Since InStream, OutStream, and SeekableStream are already generic
across error sets, it's not really worse to make them generic across the
vtable as well.
See #764 for the open issue acknowledging that using generics for these
abstractions is a design flaw.
See #130 for the efforts to make these abstractions non-generic.
This commit also changes the OutStream API so that `write` returns
number of bytes written, and `writeAll` is the one that loops until the
whole buffer is written.
Diffstat (limited to 'lib/std/debug.zig')
| -rw-r--r-- | lib/std/debug.zig | 233 |
1 files changed, 128 insertions, 105 deletions
diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 558b7e0513..5c56490519 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -55,7 +55,7 @@ pub const LineInfo = struct { var stderr_file: File = undefined; var stderr_file_out_stream: File.OutStream = undefined; -var stderr_stream: ?*io.OutStream(File.WriteError) = null; +var stderr_stream: ?*File.OutStream = null; var stderr_mutex = std.Mutex.init(); pub fn warn(comptime fmt: []const u8, args: var) void { @@ -65,13 +65,13 @@ pub fn warn(comptime fmt: []const u8, args: var) void { noasync stderr.print(fmt, args) catch return; } -pub fn getStderrStream() *io.OutStream(File.WriteError) { +pub fn getStderrStream() *File.OutStream { if (stderr_stream) |st| { return st; } else { stderr_file = io.getStdErr(); stderr_file_out_stream = stderr_file.outStream(); - const st = &stderr_file_out_stream.stream; + const st = &stderr_file_out_stream; stderr_stream = st; return st; } @@ -408,15 +408,15 @@ pub const TTY = struct { windows_api, fn setColor(conf: Config, out_stream: var, color: Color) void { - switch (conf) { + noasync switch (conf) { .no_color => return, .escape_codes => switch (color) { - .Red => noasync out_stream.write(RED) catch return, - .Green => noasync out_stream.write(GREEN) catch return, - .Cyan => noasync out_stream.write(CYAN) catch return, - .White, .Bold => noasync out_stream.write(WHITE) catch return, - .Dim => noasync out_stream.write(DIM) catch return, - .Reset => noasync out_stream.write(RESET) catch return, + .Red => out_stream.writeAll(RED) catch return, + .Green => out_stream.writeAll(GREEN) catch return, + .Cyan => out_stream.writeAll(CYAN) catch return, + .White, .Bold => out_stream.writeAll(WHITE) catch return, + .Dim => out_stream.writeAll(DIM) catch return, + .Reset => out_stream.writeAll(RESET) catch return, }, .windows_api => if (builtin.os.tag == .windows) { const S = struct { @@ -455,7 +455,7 @@ pub const TTY = struct { } else { unreachable; }, - } + }; } }; }; @@ -565,38 +565,40 @@ fn printLineInfo( tty_config: TTY.Config, comptime printLineFromFile: var, ) !void { - tty_config.setColor(out_stream, .White); + noasync { + tty_config.setColor(out_stream, .White); - if (line_info) |*li| { - try noasync out_stream.print("{}:{}:{}", .{ li.file_name, li.line, li.column }); - } else { - try noasync out_stream.write("???:?:?"); - } + if (line_info) |*li| { + try out_stream.print("{}:{}:{}", .{ li.file_name, li.line, li.column }); + } else { + try out_stream.writeAll("???:?:?"); + } - tty_config.setColor(out_stream, .Reset); - try noasync out_stream.write(": "); - tty_config.setColor(out_stream, .Dim); - try noasync out_stream.print("0x{x} in {} ({})", .{ address, symbol_name, compile_unit_name }); - tty_config.setColor(out_stream, .Reset); - try noasync out_stream.write("\n"); - - // Show the matching source code line if possible - if (line_info) |li| { - if (noasync printLineFromFile(out_stream, li)) { - if (li.column > 0) { - // The caret already takes one char - const space_needed = @intCast(usize, li.column - 1); - - try noasync out_stream.writeByteNTimes(' ', space_needed); - tty_config.setColor(out_stream, .Green); - try noasync out_stream.write("^"); - tty_config.setColor(out_stream, .Reset); + tty_config.setColor(out_stream, .Reset); + try out_stream.writeAll(": "); + tty_config.setColor(out_stream, .Dim); + try out_stream.print("0x{x} in {} ({})", .{ address, symbol_name, compile_unit_name }); + tty_config.setColor(out_stream, .Reset); + try out_stream.writeAll("\n"); + + // Show the matching source code line if possible + if (line_info) |li| { + if (printLineFromFile(out_stream, li)) { + if (li.column > 0) { + // The caret already takes one char + const space_needed = @intCast(usize, li.column - 1); + + try out_stream.writeByteNTimes(' ', space_needed); + tty_config.setColor(out_stream, .Green); + try out_stream.writeAll("^"); + tty_config.setColor(out_stream, .Reset); + } + try out_stream.writeAll("\n"); + } else |err| switch (err) { + error.EndOfFile, error.FileNotFound => {}, + error.BadPathName => {}, + else => return err, } - try noasync out_stream.write("\n"); - } else |err| switch (err) { - error.EndOfFile, error.FileNotFound => {}, - error.BadPathName => {}, - else => return err, } } } @@ -609,21 +611,21 @@ pub const OpenSelfDebugInfoError = error{ }; /// TODO resources https://github.com/ziglang/zig/issues/4353 -/// TODO once https://github.com/ziglang/zig/issues/3157 is fully implemented, -/// make this `noasync fn` and remove the individual noasync calls. pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo { - if (builtin.strip_debug_info) - return error.MissingDebugInfo; - if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) { - return noasync root.os.debug.openSelfDebugInfo(allocator); - } - switch (builtin.os.tag) { - .linux, - .freebsd, - .macosx, - .windows, - => return DebugInfo.init(allocator), - else => @compileError("openSelfDebugInfo unsupported for this platform"), + noasync { + if (builtin.strip_debug_info) + return error.MissingDebugInfo; + if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) { + return root.os.debug.openSelfDebugInfo(allocator); + } + switch (builtin.os.tag) { + .linux, + .freebsd, + .macosx, + .windows, + => return DebugInfo.init(allocator), + else => @compileError("openSelfDebugInfo unsupported for this platform"), + } } } @@ -808,45 +810,64 @@ fn chopSlice(ptr: []const u8, offset: u64, size: u64) ![]const u8 { /// TODO resources https://github.com/ziglang/zig/issues/4353 pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !ModuleDebugInfo { - const mapped_mem = try mapWholeFile(elf_file_path); - - var seekable_stream = io.SliceSeekableInStream.init(mapped_mem); - var efile = try noasync elf.Elf.openStream( - allocator, - @ptrCast(*DW.DwarfSeekableStream, &seekable_stream.seekable_stream), - @ptrCast(*DW.DwarfInStream, &seekable_stream.stream), - ); - defer noasync efile.close(); + noasync { + const mapped_mem = try mapWholeFile(elf_file_path); + const hdr = @ptrCast(*const elf.Ehdr, &mapped_mem[0]); + if (!mem.eql(u8, hdr.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic; + if (hdr.e_ident[elf.EI_VERSION] != 1) return error.InvalidElfVersion; + + const endian: builtin.Endian = switch (hdr.e_ident[elf.EI_DATA]) { + elf.ELFDATA2LSB => .Little, + elf.ELFDATA2MSB => .Big, + else => return error.InvalidElfEndian, + }; + assert(endian == std.builtin.endian); // this is our own debug info + + const shoff = hdr.e_shoff; + const str_section_off = shoff + @as(u64, hdr.e_shentsize) * @as(u64, hdr.e_shstrndx); + const header_strings = mapped_mem[str_section_off..str_section_off + hdr.e_shentsize]; + const shdrs = @ptrCast([*]const elf.Shdr, @alignCast(@alignOf(elf.Shdr), &mapped_mem[shoff]))[0..hdr.e_shnum]; + + var opt_debug_info: ?[]const u8 = null; + var opt_debug_abbrev: ?[]const u8 = null; + var opt_debug_str: ?[]const u8 = null; + var opt_debug_line: ?[]const u8 = null; + var opt_debug_ranges: ?[]const u8 = null; + + for (shdrs) |*shdr| { + if (shdr.sh_type == elf.SHT_NULL) continue; + + const name = std.mem.span(@ptrCast([*:0]const u8, header_strings[shdr.sh_name..].ptr)); + if (mem.eql(u8, name, ".debug_info")) { + opt_debug_info = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size); + } else if (mem.eql(u8, name, ".debug_abbrev")) { + opt_debug_abbrev = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size); + } else if (mem.eql(u8, name, ".debug_str")) { + opt_debug_str = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size); + } else if (mem.eql(u8, name, ".debug_line")) { + opt_debug_line = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size); + } else if (mem.eql(u8, name, ".debug_ranges")) { + opt_debug_ranges = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size); + } + } - const debug_info = (try noasync efile.findSection(".debug_info")) orelse - return error.MissingDebugInfo; - const debug_abbrev = (try noasync efile.findSection(".debug_abbrev")) orelse - return error.MissingDebugInfo; - const debug_str = (try noasync efile.findSection(".debug_str")) orelse - return error.MissingDebugInfo; - const debug_line = (try noasync efile.findSection(".debug_line")) orelse - return error.MissingDebugInfo; - const opt_debug_ranges = try noasync efile.findSection(".debug_ranges"); - - var di = DW.DwarfInfo{ - .endian = efile.endian, - .debug_info = try chopSlice(mapped_mem, debug_info.sh_offset, debug_info.sh_size), - .debug_abbrev = try chopSlice(mapped_mem, debug_abbrev.sh_offset, debug_abbrev.sh_size), - .debug_str = try chopSlice(mapped_mem, debug_str.sh_offset, debug_str.sh_size), - .debug_line = try chopSlice(mapped_mem, debug_line.sh_offset, debug_line.sh_size), - .debug_ranges = if (opt_debug_ranges) |debug_ranges| - try chopSlice(mapped_mem, debug_ranges.sh_offset, debug_ranges.sh_size) - else - null, - }; + var di = DW.DwarfInfo{ + .endian = endian, + .debug_info = opt_debug_info orelse return error.MissingDebugInfo, + .debug_abbrev = opt_debug_abbrev orelse return error.MissingDebugInfo, + .debug_str = opt_debug_str orelse return error.MissingDebugInfo, + .debug_line = opt_debug_line orelse return error.MissingDebugInfo, + .debug_ranges = opt_debug_ranges, + }; - try noasync DW.openDwarfDebugInfo(&di, allocator); + try DW.openDwarfDebugInfo(&di, allocator); - return ModuleDebugInfo{ - .base_address = undefined, - .dwarf = di, - .mapped_memory = mapped_mem, - }; + return ModuleDebugInfo{ + .base_address = undefined, + .dwarf = di, + .mapped_memory = mapped_mem, + }; + } } /// TODO resources https://github.com/ziglang/zig/issues/4353 @@ -982,22 +1003,24 @@ const MachoSymbol = struct { } }; -fn mapWholeFile(path: []const u8) ![]const u8 { - const file = try noasync fs.openFileAbsolute(path, .{ .always_blocking = true }); - defer noasync file.close(); - - const file_len = try math.cast(usize, try file.getEndPos()); - const mapped_mem = try os.mmap( - null, - file_len, - os.PROT_READ, - os.MAP_SHARED, - file.handle, - 0, - ); - errdefer os.munmap(mapped_mem); +fn mapWholeFile(path: []const u8) ![]align(mem.page_size) const u8 { + noasync { + const file = try fs.openFileAbsolute(path, .{ .always_blocking = true }); + defer file.close(); - return mapped_mem; + const file_len = try math.cast(usize, try file.getEndPos()); + const mapped_mem = try os.mmap( + null, + file_len, + os.PROT_READ, + os.MAP_SHARED, + file.handle, + 0, + ); + errdefer os.munmap(mapped_mem); + + return mapped_mem; + } } pub const DebugInfo = struct { |
