diff options
| author | Jacob Young <jacobly0@users.noreply.github.com> | 2024-08-16 12:36:43 -0400 |
|---|---|---|
| committer | Jacob Young <jacobly0@users.noreply.github.com> | 2024-08-16 15:22:56 -0400 |
| commit | 7a0acc8be6792c188649f490f8ee8b03af134a75 (patch) | |
| tree | 45c6b158ef5de04ba9d29aad20d55ce47b3fd800 | |
| parent | ef11bc9899002620d67cfce9c79b6c0dc0f5ea61 (diff) | |
| download | zig-7a0acc8be6792c188649f490f8ee8b03af134a75.tar.gz zig-7a0acc8be6792c188649f490f8ee8b03af134a75.zip | |
Dwarf: fix cross-module inline function line info
| -rw-r--r-- | src/link/Dwarf.zig | 130 | ||||
| -rw-r--r-- | test/src/Debugger.zig | 76 |
2 files changed, 153 insertions, 53 deletions
diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 8c89e9c3f3..923ced8e65 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -4,9 +4,7 @@ format: DW.Format, endian: std.builtin.Endian, address_size: AddressSize, -mods: std.AutoArrayHashMapUnmanaged(*Module, struct { - files: Files, -}), +mods: std.AutoArrayHashMapUnmanaged(*Module, ModInfo), types: std.AutoArrayHashMapUnmanaged(InternPool.Index, Entry.Index), navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Entry.Index), @@ -39,7 +37,19 @@ pub const AddressSize = enum(u8) { _, }; -const Files = std.AutoArrayHashMapUnmanaged(Zcu.File.Index, void); +const ModInfo = struct { + root_dir_path: Entry.Index, + dirs: std.AutoArrayHashMapUnmanaged(Unit.Index, void), + files: Files, + + const Files = std.AutoArrayHashMapUnmanaged(Zcu.File.Index, void); + + fn deinit(mod_info: *ModInfo, gpa: std.mem.Allocator) void { + mod_info.dirs.deinit(gpa); + mod_info.files.deinit(gpa); + mod_info.* = undefined; + } +}; const DebugAbbrev = struct { section: Section, @@ -92,10 +102,20 @@ const DebugLine = struct { opcode_base: u8, }; - fn headerBytes(dwarf: *Dwarf, file_count: u32) u32 { + fn dirIndexInfo(dir_count: u32) struct { bytes: u8, form: DeclValEnum(DW.FORM) } { + return if (dir_count <= 1 << 8) + .{ .bytes = 1, .form = .data1 } + else if (dir_count <= 1 << 16) + .{ .bytes = 2, .form = .data2 } + else + unreachable; + } + + fn headerBytes(dwarf: *Dwarf, dir_count: u32, file_count: u32) u32 { + const dir_index_info = dirIndexInfo(dir_count); return dwarf.unitLengthBytes() + 2 + 1 + 1 + dwarf.sectionOffsetBytes() + 1 + 1 + 1 + 1 + 1 + 1 + 1 * (dwarf.debug_line.header.opcode_base - 1) + - 1 + uleb128Bytes(DW.LNCT.path) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(1) + (dwarf.sectionOffsetBytes()) * 1 + - 1 + uleb128Bytes(DW.LNCT.path) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(DW.LNCT.LLVM_source) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(file_count) + (dwarf.sectionOffsetBytes() + dwarf.sectionOffsetBytes()) * file_count; + 1 + uleb128Bytes(DW.LNCT.path) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(dir_count) + (dwarf.sectionOffsetBytes()) * dir_count + + 1 + uleb128Bytes(DW.LNCT.path) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(DW.LNCT.directory_index) + uleb128Bytes(@intFromEnum(dir_index_info.form)) + uleb128Bytes(DW.LNCT.LLVM_source) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(file_count) + (dwarf.sectionOffsetBytes() + dir_index_info.bytes + dwarf.sectionOffsetBytes()) * file_count; } const trailer_bytes = 1 + uleb128Bytes(0) + @@ -1066,6 +1086,7 @@ pub const WipNav = struct { const new_func_info = zcu.funcInfo(func); const new_file = zcu.navFileScopeIndex(new_func_info.owner_nav); const new_unit = try dwarf.getUnit(zcu.fileByIndex(new_file).mod); + const dlw = wip_nav.debug_line.writer(dwarf.gpa); if (dwarf.incremental()) { const new_nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, new_func_info.owner_nav); @@ -1089,9 +1110,14 @@ pub const WipNav = struct { const old_func_info = zcu.funcInfo(wip_nav.func); const old_file = zcu.navFileScopeIndex(old_func_info.owner_nav); if (old_file != new_file) { - const new_file_gop = try dwarf.getUnitFiles(new_unit).getOrPut(dwarf.gpa, new_file); + const mod_info = dwarf.getModInfo(wip_nav.unit); + const mod_gop = try mod_info.dirs.getOrPut(dwarf.gpa, new_unit); + errdefer _ = if (!mod_gop.found_existing) mod_info.dirs.pop(); + const file_gop = try mod_info.files.getOrPut(dwarf.gpa, new_file); + errdefer _ = if (!file_gop.found_existing) mod_info.files.pop(); + try dlw.writeByte(DW.LNS.set_file); - try uleb128(dlw, new_file_gop.index); + try uleb128(dlw, file_gop.index); } const old_src_line: i33 = zcu.navSrcLine(old_func_info.owner_nav); @@ -1437,7 +1463,7 @@ pub fn initMetadata(dwarf: *Dwarf) UpdateError!void { pub fn deinit(dwarf: *Dwarf) void { const gpa = dwarf.gpa; - for (dwarf.mods.values()) |*mod_info| mod_info.files.deinit(gpa); + for (dwarf.mods.values()) |*mod_info| mod_info.deinit(gpa); dwarf.mods.deinit(gpa); dwarf.types.deinit(gpa); dwarf.navs.deinit(gpa); @@ -1458,8 +1484,12 @@ fn getUnit(dwarf: *Dwarf, mod: *Module) UpdateError!Unit.Index { if (!mod_gop.found_existing) { errdefer _ = dwarf.mods.pop(); mod_gop.value_ptr.* = .{ + .root_dir_path = undefined, + .dirs = .{}, .files = .{}, }; + errdefer mod_gop.value_ptr.dirs.deinit(dwarf.gpa); + try mod_gop.value_ptr.dirs.putNoClobber(dwarf.gpa, unit, {}); assert(try dwarf.debug_aranges.section.addUnit( DebugAranges.headerBytes(dwarf), DebugAranges.trailerBytes(dwarf), @@ -1473,7 +1503,7 @@ fn getUnit(dwarf: *Dwarf, mod: *Module) UpdateError!Unit.Index { ) == unit); errdefer dwarf.debug_info.section.popUnit(); assert(try dwarf.debug_line.section.addUnit( - DebugLine.headerBytes(dwarf, 25), + DebugLine.headerBytes(dwarf, 5, 25), DebugLine.trailer_bytes, dwarf, ) == unit); @@ -1494,8 +1524,12 @@ fn getUnit(dwarf: *Dwarf, mod: *Module) UpdateError!Unit.Index { return unit; } -fn getUnitFiles(dwarf: *Dwarf, unit: Unit.Index) *Files { - return &dwarf.mods.values()[@intFromEnum(unit)].files; +fn getUnitIfExists(dwarf: *const Dwarf, mod: *Module) ?Unit.Index { + return @enumFromInt(dwarf.mods.getIndex(mod) orelse return null); +} + +fn getModInfo(dwarf: *Dwarf, unit: Unit.Index) *ModInfo { + return &dwarf.mods.values()[@intFromEnum(unit)]; } pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, sym_index: u32) UpdateError!?WipNav { @@ -1745,7 +1779,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In }); try dlw.writeByteNTimes(0, @intFromEnum(dwarf.address_size)); - const file_gop = try dwarf.getUnitFiles(unit).getOrPut(dwarf.gpa, inst_info.file); + const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file); try dlw.writeByte(DW.LNS.set_file); try uleb128(dlw, file_gop.index); @@ -2698,7 +2732,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP const diw = wip_nav.debug_info.writer(dwarf.gpa); try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0) .namespace_file else .file))); - const file_gop = try dwarf.getUnitFiles(unit).getOrPut(dwarf.gpa, inst_info.file); + const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file); try uleb128(diw, file_gop.index); try wip_nav.strp(loaded_struct.name.toSlice(ip)); if (loaded_struct.field_types.len > 0) { @@ -2945,8 +2979,19 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); } - const cwd = try std.process.getCwdAlloc(dwarf.gpa); - defer dwarf.gpa.free(cwd); + { + const cwd = try std.process.getCwdAlloc(dwarf.gpa); + defer dwarf.gpa.free(cwd); + for (dwarf.mods.keys(), dwarf.mods.values()) |mod, *mod_info| { + const root_dir_path = try std.fs.path.resolve(dwarf.gpa, &.{ + cwd, + mod.root.root_dir.path orelse "", + mod.root.sub_path, + }); + defer dwarf.gpa.free(root_dir_path); + mod_info.root_dir_path = try dwarf.debug_line_str.addString(dwarf, root_dir_path); + } + } var header = std.ArrayList(u8).init(dwarf.gpa); defer header.deinit(); @@ -2997,7 +3042,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { dwarf.debug_aranges.section.dirty = false; } if (dwarf.debug_info.section.dirty) { - for (dwarf.mods.keys(), dwarf.debug_info.section.units.items, 0..) |mod, *unit_ptr, unit_index| { + for (dwarf.mods.keys(), dwarf.mods.values(), dwarf.debug_info.section.units.items, 0..) |mod, mod_info, *unit_ptr, unit_index| { const unit: Unit.Index = @enumFromInt(unit_index); try unit_ptr.cross_unit_relocs.ensureUnusedCapacity(dwarf.gpa, 1); try unit_ptr.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 7); @@ -3032,22 +3077,14 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { .target_unit = StringSection.unit, .target_entry = (try dwarf.debug_line_str.addString(dwarf, "zig " ++ @import("build_options").version)).toOptional(), }); - { - const mod_root_path = try std.fs.path.resolve(dwarf.gpa, &.{ - cwd, - mod.root.root_dir.path orelse "", - mod.root.sub_path, - }); - defer dwarf.gpa.free(mod_root_path); - header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); - unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ - .source_off = @intCast(header.items.len), - .target_sec = .debug_line_str, - .target_unit = StringSection.unit, - .target_entry = (try dwarf.debug_line_str.addString(dwarf, mod_root_path)).toOptional(), - }); - header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); - } + header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); + unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ + .source_off = @intCast(header.items.len), + .target_sec = .debug_line_str, + .target_unit = StringSection.unit, + .target_entry = mod_info.root_dir_path.toOptional(), + }); + header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ .source_off = @intCast(header.items.len), .target_sec = .debug_line_str, @@ -3097,8 +3134,8 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { } if (dwarf.debug_line.section.dirty) { for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| - try unit.resizeHeader(&dwarf.debug_line.section, dwarf, DebugLine.headerBytes(dwarf, @intCast(mod_info.files.count()))); - for (dwarf.mods.keys(), dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod, mod_info, *unit| { + try unit.resizeHeader(&dwarf.debug_line.section, dwarf, DebugLine.headerBytes(dwarf, @intCast(mod_info.dirs.count()), @intCast(mod_info.files.count()))); + for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| { try unit.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 2 * (1 + mod_info.files.count())); header.clearRetainingCapacity(); try header.ensureTotalCapacity(unit.header_len); @@ -3150,25 +3187,22 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { header.appendAssumeCapacity(1); uleb128(header.fixedWriter(), DW.LNCT.path) catch unreachable; uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable; - uleb128(header.fixedWriter(), 1) catch unreachable; - { - const mod_root_path = try std.fs.path.resolve(dwarf.gpa, &.{ - cwd, - mod.root.root_dir.path orelse "", - mod.root.sub_path, - }); - defer dwarf.gpa.free(mod_root_path); + uleb128(header.fixedWriter(), mod_info.dirs.count()) catch unreachable; + for (mod_info.dirs.keys()) |dir_unit| { unit.cross_section_relocs.appendAssumeCapacity(.{ .source_off = @intCast(header.items.len), .target_sec = .debug_line_str, .target_unit = StringSection.unit, - .target_entry = (try dwarf.debug_line_str.addString(dwarf, mod_root_path)).toOptional(), + .target_entry = dwarf.getModInfo(dir_unit).root_dir_path.toOptional(), }); header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); } - header.appendAssumeCapacity(2); + const dir_index_info = DebugLine.dirIndexInfo(@intCast(mod_info.dirs.count())); + header.appendAssumeCapacity(3); uleb128(header.fixedWriter(), DW.LNCT.path) catch unreachable; uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable; + uleb128(header.fixedWriter(), DW.LNCT.directory_index) catch unreachable; + uleb128(header.fixedWriter(), @intFromEnum(dir_index_info.form)) catch unreachable; uleb128(header.fixedWriter(), DW.LNCT.LLVM_source) catch unreachable; uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable; uleb128(header.fixedWriter(), mod_info.files.count()) catch unreachable; @@ -3181,6 +3215,10 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { .target_entry = (try dwarf.debug_line_str.addString(dwarf, file.sub_file_path)).toOptional(), }); header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); + dwarf.writeInt( + header.addManyAsSliceAssumeCapacity(dir_index_info.bytes), + mod_info.dirs.getIndex(dwarf.getUnitIfExists(file.mod).?).?, + ); unit.cross_section_relocs.appendAssumeCapacity(.{ .source_off = @intCast(header.items.len), .target_sec = .debug_line_str, diff --git a/test/src/Debugger.zig b/test/src/Debugger.zig index 53ae99e30c..7360f77851 100644 --- a/test/src/Debugger.zig +++ b/test/src/Debugger.zig @@ -108,7 +108,7 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void { \\breakpoint set --file basic.zig --source-pattern-regexp '_ = basic;' \\process launch \\frame variable --show-types basic - \\breakpoint delete --force + \\breakpoint delete --force 1 , &.{ \\(lldb) frame variable --show-types basic @@ -178,6 +178,8 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void { \\ (f80) f80_-91625968981.3330078125 = -91625968981.3330078125 \\ (f128) f128_384307168202282325.333332061767578125 = 384307168202282325.333332061767578125 \\} + \\(lldb) breakpoint delete --force 1 + \\1 breakpoints deleted; 0 breakpoint locations disabled. }, ); db.addLldbTest( @@ -228,7 +230,7 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void { \\process launch \\target variable --show-types --format hex global_const global_var global_threadlocal1 global_threadlocal2 \\frame variable --show-types --format hex param1 param2 param3 param4 param5 param6 param7 param8 local_comptime_val local_comptime_ptr.0 local_const local_var - \\breakpoint delete --force + \\breakpoint delete --force 1 , &.{ \\(lldb) target variable --show-types --format hex global_const global_var global_threadlocal1 global_threadlocal2 @@ -249,6 +251,8 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void { \\(u64) local_comptime_ptr.0 = 0x82e834dae74767a1 \\(u64) local_const = 0xdffceb8b2f41e205 \\(u64) local_var = 0x5d14df51c80685a4 + \\(lldb) breakpoint delete --force 1 + \\1 breakpoints deleted; 0 breakpoint locations disabled. }, ); db.addLldbTest( @@ -272,7 +276,7 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void { \\breakpoint set --file slices.zig --source-pattern-regexp '_ = slice;' \\process launch \\frame variable --show-types array slice - \\breakpoint delete --force + \\breakpoint delete --force 1 , &.{ \\(lldb) frame variable --show-types array slice @@ -288,6 +292,8 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void { \\ (u32) [2] = 4 \\ (u32) [3] = 8 \\} + \\(lldb) breakpoint delete --force 1 + \\1 breakpoints deleted; 0 breakpoint locations disabled. }, ); db.addLldbTest( @@ -313,18 +319,20 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void { \\breakpoint set --file optionals.zig --source-pattern-regexp 'maybe_u32 = 123;' \\process launch \\frame variable null_u32 maybe_u32 nonnull_u32 - \\breakpoint delete --force + \\breakpoint delete --force 1 \\ \\breakpoint set --file optionals.zig --source-pattern-regexp '_ = .{ &null_u32, &nonnull_u32 };' \\process continue \\frame variable --show-types null_u32 maybe_u32 nonnull_u32 - \\breakpoint delete --force + \\breakpoint delete --force 2 , &.{ \\(lldb) frame variable null_u32 maybe_u32 nonnull_u32 \\(?u32) null_u32 = null \\(?u32) maybe_u32 = null \\(?u32) nonnull_u32 = (nonnull_u32.? = 456) + \\(lldb) breakpoint delete --force 1 + \\1 breakpoints deleted; 0 breakpoint locations disabled. , \\(lldb) frame variable --show-types null_u32 maybe_u32 nonnull_u32 \\(?u32) null_u32 = null @@ -334,11 +342,60 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void { \\(?u32) nonnull_u32 = { \\ (u32) nonnull_u32.? = 456 \\} + \\(lldb) breakpoint delete --force 2 + \\1 breakpoints deleted; 0 breakpoint locations disabled. + }, + ); + db.addLldbTest( + "cross_module_call", + target, + &.{ + .{ + .path = "main.zig", + .source = + \\const module = @import("module"); + \\pub fn main() void { + \\ module.foo(123); + \\ module.bar(456); + \\} + , + }, + .{ + .import = "module", + .path = "module.zig", + .source = + \\pub fn foo(x: u32) void { + \\ _ = x; + \\} + \\pub inline fn bar(y: u32) void { + \\ _ = y; + \\} + , + }, + }, + \\breakpoint set --file module.zig --source-pattern-regexp '_ = x;' + \\process launch + \\source info + \\breakpoint delete --force 1 + \\ + \\breakpoint set --file module.zig --line 5 + \\process continue + \\source info + \\breakpoint delete --force 2 + , + &.{ + \\/module.zig:2:5 + \\(lldb) breakpoint delete --force 1 + \\1 breakpoints deleted; 0 breakpoint locations disabled. + , + \\/module.zig:5:5 + \\(lldb) breakpoint delete --force 2 + \\1 breakpoints deleted; 0 breakpoint locations disabled. }, ); } -const File = struct { path: []const u8, source: []const u8 }; +const File = struct { import: ?[]const u8 = null, path: []const u8, source: []const u8 }; fn addGdbTest( db: *Debugger, @@ -421,7 +478,12 @@ fn addTest( .use_llvm = false, .use_lld = false, }); - for (files[1..]) |file| _ = files_wf.add(file.path, file.source); + for (files[1..]) |file| { + const path = files_wf.add(file.path, file.source); + if (file.import) |import| exe.root_module.addImport(import, db.b.createModule(.{ + .root_source_file = path, + })); + } const commands_wf = db.b.addWriteFiles(); const run = std.Build.Step.Run.create(db.b, db.b.fmt("run {s} {s}", .{ name, target.test_name_suffix })); run.addArgs(db_argv1); |
