From ab3931fa9581776ef3654b9b55ff447ad91e7949 Mon Sep 17 00:00:00 2001 From: Jonathan S Date: Fri, 27 Mar 2020 15:13:26 -0500 Subject: [PATCH] Prefer Files to paths in std.debug. Additionally [breaking] add a flags parameter to openSelfExe and stop exporting openElfDebugInfo. This should save a call to readlink in openSelfDebugInfo and support executables in overlong paths on Linux. --- lib/std/debug.zig | 46 +++++++++++++++++++++++---------------------- lib/std/fs.zig | 8 ++++---- lib/std/fs/test.zig | 2 +- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index aea9bcef51..462f4def1b 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -670,10 +670,11 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo { } } +/// This takes ownership of coff_file: users of this function should not close +/// it themselves, even on error. /// TODO resources https://github.com/ziglang/zig/issues/4353 -fn openCoffDebugInfo(allocator: *mem.Allocator, coff_file_path: [:0]const u16) !ModuleDebugInfo { +fn readCoffDebugInfo(allocator: *mem.Allocator, coff_file: File) !ModuleDebugInfo { nosuspend { - const coff_file = try std.fs.openFileAbsoluteW(coff_file_path, .{ .intended_io_mode = .blocking }); errdefer coff_file.close(); const coff_obj = try allocator.create(coff.Coff); @@ -851,10 +852,12 @@ fn chopSlice(ptr: []const u8, offset: u64, size: u64) ![]const u8 { return ptr[start..end]; } +/// This takes ownership of elf_file: users of this function should not close +/// it themselves, even on error. /// TODO resources https://github.com/ziglang/zig/issues/4353 -pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !ModuleDebugInfo { +pub fn readElfDebugInfo(allocator: *mem.Allocator, elf_file: File) !ModuleDebugInfo { nosuspend { - const mapped_mem = try mapWholeFile(elf_file_path); + const mapped_mem = try mapWholeFile(elf_file); 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; @@ -921,8 +924,10 @@ pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !M } /// TODO resources https://github.com/ziglang/zig/issues/4353 -fn openMachODebugInfo(allocator: *mem.Allocator, macho_file_path: []const u8) !ModuleDebugInfo { - const mapped_mem = try mapWholeFile(macho_file_path); +/// This takes ownership of coff_file: users of this function should not close +/// it themselves, even on error. +fn readMachODebugInfo(allocator: *mem.Allocator, macho_file: File) !ModuleDebugInfo { + const mapped_mem = try mapWholeFile(macho_file); const hdr = @ptrCast( *const macho.mach_header_64, @@ -1055,9 +1060,8 @@ const MachoSymbol = struct { } }; -fn mapWholeFile(path: []const u8) ![]align(mem.page_size) const u8 { +fn mapWholeFile(file: File) ![]align(mem.page_size) const u8 { nosuspend { - const file = try fs.cwd().openFile(path, .{ .intended_io_mode = .blocking }); defer file.close(); const file_len = try math.cast(usize, try file.getEndPos()); @@ -1140,10 +1144,11 @@ pub const DebugInfo = struct { errdefer self.allocator.destroy(obj_di); const macho_path = mem.spanZ(std.c._dyld_get_image_name(i)); - obj_di.* = openMachODebugInfo(self.allocator, macho_path) catch |err| switch (err) { + const macho_file = fs.cwd().openFile(macho_path, .{ .always_blocking = true }) catch |err| switch (err) { error.FileNotFound => return error.MissingDebugInfo, else => return err, }; + obj_di.* = try readMachODebugInfo(self.allocator, macho_file); obj_di.base_address = base_address; try self.address_map.putNoClobber(base_address, obj_di); @@ -1221,10 +1226,11 @@ pub const DebugInfo = struct { const obj_di = try self.allocator.create(ModuleDebugInfo); errdefer self.allocator.destroy(obj_di); - obj_di.* = openCoffDebugInfo(self.allocator, name_buffer[0 .. len + 4 :0]) catch |err| switch (err) { + const coff_file = fs.openFileAbsoluteW(name_buffer[0 .. len + 4 :0], .{}) catch |err| switch (err) { error.FileNotFound => return error.MissingDebugInfo, else => return err, }; + obj_di.* = try readCoffDebugInfo(self.allocator, coff_file); obj_di.base_address = seg_start; try self.address_map.putNoClobber(seg_start, obj_di); @@ -1280,23 +1286,18 @@ pub const DebugInfo = struct { return obj_di; } - const elf_path = if (ctx.name.len > 0) - ctx.name - else blk: { - // Use of MAX_PATH_BYTES here is valid as the resulting path is immediately - // opened with no modification. TODO: Use openSelfExe instead to avoid path - // length limitations - var buf: [fs.MAX_PATH_BYTES]u8 = undefined; - break :blk try fs.selfExePath(&buf); - }; - const obj_di = try self.allocator.create(ModuleDebugInfo); errdefer self.allocator.destroy(obj_di); - obj_di.* = openElfDebugInfo(self.allocator, elf_path) catch |err| switch (err) { + const elf_file = (if (ctx.name.len > 0) + fs.cwd().openFile(ctx.name, .{ .always_blocking = true }) + else + fs.openSelfExe(.{ .always_blocking = true })) catch |err| switch (err) { error.FileNotFound => return error.MissingDebugInfo, else => return err, }; + + obj_di.* = try readElfDebugInfo(self.allocator, elf_file); obj_di.base_address = ctx.base_address; try self.address_map.putNoClobber(ctx.base_address, obj_di); @@ -1332,7 +1333,8 @@ pub const ModuleDebugInfo = switch (builtin.os.tag) { } fn loadOFile(self: *@This(), o_file_path: []const u8) !DW.DwarfInfo { - const mapped_mem = try mapWholeFile(o_file_path); + const o_file = try fs.cwd().openFile(o_file_path, .{ .always_blocking = true }); + const mapped_mem = try mapWholeFile(o_file); const hdr = @ptrCast( *const macho.mach_header_64, diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 31953a805b..9e86d6a2fe 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -1778,21 +1778,21 @@ pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfExePathError || os.FlockError; -pub fn openSelfExe() OpenSelfExeError!File { +pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File { if (builtin.os.tag == .linux) { - return openFileAbsoluteZ("/proc/self/exe", .{}); + return openFileAbsoluteZ("/proc/self/exe", flags); } if (builtin.os.tag == .windows) { const wide_slice = selfExePathW(); const prefixed_path_w = try os.windows.wToPrefixedFileW(wide_slice); - return cwd().openFileW(prefixed_path_w.span(), .{}); + return cwd().openFileW(prefix_path_w.span(), flags); } // Use of MAX_PATH_BYTES here is valid as the resulting path is immediately // opened with no modification. var buf: [MAX_PATH_BYTES]u8 = undefined; const self_exe_path = try selfExePath(&buf); buf[self_exe_path.len] = 0; - return openFileAbsoluteZ(buf[0..self_exe_path.len :0].ptr, .{}); + return openFileAbsoluteZ(self_exe_path[0..self_exe_path.len :0].ptr, flags); } pub const SelfExePathError = os.ReadLinkError || os.SysCtlError; diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 2d979f5690..875565fc54 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -6,7 +6,7 @@ const File = std.fs.File; test "openSelfExe" { if (builtin.os.tag == .wasi) return error.SkipZigTest; - const self_exe_file = try std.fs.openSelfExe(); + const self_exe_file = try std.fs.openSelfExe(.{}); self_exe_file.close(); }