From 62f7276501bee7460cd004c17fdc1545487ad99b Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 19 Aug 2024 14:56:17 -0400 Subject: Dwarf: emit info about inline call sites --- src/Zcu/PerThread.zig | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/Zcu/PerThread.zig') diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 0db30bfdbd..6d17051c34 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -1241,7 +1241,10 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult { } const nav_already_populated, const queue_linker_work = switch (ip.indexToKey(decl_val.toIntern())) { - .func => |f| .{ f.owner_nav == nav_index, false }, + .func => |f| status: { + const func_type = ip.indexToKey(f.ty).func_type; + break :status .{ f.owner_nav == nav_index, func_type.is_generic or func_type.cc == .Inline }; + }, .variable => |v| .{ false, v.owner_nav == nav_index }, .@"extern" => .{ false, false }, else => .{ false, true }, @@ -2158,7 +2161,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError! .name = if (inner_block.ownerModule().strip) .none else - @enumFromInt(try sema.appendAirString(sema.code.nullTerminatedString(param_name))), + try sema.appendAirString(sema.code.nullTerminatedString(param_name)), } }, }); } -- cgit v1.2.3 From eaa227449c894a9205d63c2e963b967d13446591 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 19 Aug 2024 22:16:20 -0400 Subject: Dwarf: fix issues with inline call sites --- src/Zcu/PerThread.zig | 29 ++-- src/arch/x86_64/CodeGen.zig | 4 + src/link/C.zig | 12 +- src/link/Coff.zig | 3 +- src/link/Dwarf.zig | 346 +++++++++++++++++++++++++++---------------- src/link/Elf/ZigObject.zig | 12 +- src/link/MachO/ZigObject.zig | 13 +- src/link/Plan9.zig | 3 +- src/link/Wasm/ZigObject.zig | 2 +- test/src/Debugger.zig | 86 +++++++++-- 10 files changed, 337 insertions(+), 173 deletions(-) (limited to 'src/Zcu/PerThread.zig') diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 6d17051c34..291518f5f0 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -1240,14 +1240,11 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult { }; } - const nav_already_populated, const queue_linker_work = switch (ip.indexToKey(decl_val.toIntern())) { - .func => |f| status: { - const func_type = ip.indexToKey(f.ty).func_type; - break :status .{ f.owner_nav == nav_index, func_type.is_generic or func_type.cc == .Inline }; - }, - .variable => |v| .{ false, v.owner_nav == nav_index }, - .@"extern" => .{ false, false }, - else => .{ false, true }, + const nav_already_populated, const queue_linker_work, const resolve_type = switch (ip.indexToKey(decl_val.toIntern())) { + .func => |f| .{ f.owner_nav == nav_index, true, false }, + .variable => |v| .{ false, v.owner_nav == nav_index, true }, + .@"extern" => .{ false, false, false }, + else => .{ false, true, true }, }; if (nav_already_populated) { @@ -1320,14 +1317,16 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult { queue_codegen: { if (!queue_linker_work) break :queue_codegen; - // Needed for codegen_nav which will call updateDecl and then the - // codegen backend wants full access to the Decl Type. - // We also need this for the `isFnOrHasRuntimeBits` check below. - // TODO: we could make the language more lenient by deferring this work - // to the `codegen_nav` job. - try decl_ty.resolveFully(pt); + if (resolve_type) { + // Needed for codegen_nav which will call updateDecl and then the + // codegen backend wants full access to the Decl Type. + // We also need this for the `isFnOrHasRuntimeBits` check below. + // TODO: we could make the language more lenient by deferring this work + // to the `codegen_nav` job. + try decl_ty.resolveFully(pt); + } - if (!decl_ty.isFnOrHasRuntimeBits(pt)) { + if (!resolve_type or !decl_ty.hasRuntimeBits(pt)) { if (zcu.comp.config.use_llvm) break :queue_codegen; if (file.mod.strip) break :queue_codegen; } diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 45399620f0..3f64d77aba 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -12033,6 +12033,10 @@ fn genLocalDebugInfo( .disp = sym_off.off, } }, }), + .lea_direct, .lea_got, .lea_tlv => |sym| try self.asmAirMemory(.dbg_local, inst, .{ + .base = .{ .reloc = .{ .atom_index = undefined, .sym_index = sym } }, + .mod = .{ .rm = .{ .size = .qword } }, + }), }, } } diff --git a/src/link/C.zig b/src/link/C.zig index a704175865..585389aa3f 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -317,8 +317,18 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ! defer tracy.end(); const gpa = self.base.comp.gpa; - const zcu = pt.zcu; + const ip = &zcu.intern_pool; + + const nav = ip.getNav(nav_index); + const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) { + .func => return, + .@"extern" => .none, + .variable => |variable| variable.init, + else => nav.status.resolved.val, + }; + if (nav_init != .none and !Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(pt)) return; + const gop = try self.navs.getOrPut(gpa, nav_index); errdefer _ = self.navs.pop(); if (!gop.found_existing) gop.value_ptr.* = .{}; diff --git a/src/link/Coff.zig b/src/link/Coff.zig index f2359d503f..d6ebcc278e 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1207,6 +1207,7 @@ pub fn updateNav( const nav_val = zcu.navValue(nav_index); const nav_init = switch (ip.indexToKey(nav_val.toIntern())) { + .func => return, .variable => |variable| Value.fromInterned(variable.init), .@"extern" => |@"extern"| { if (ip.isFunctionType(@"extern".ty)) return; @@ -1220,7 +1221,7 @@ pub fn updateNav( else => nav_val, }; - if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) { + if (nav_init.typeOf(zcu).hasRuntimeBits(pt)) { const atom_index = try self.getOrCreateAtomForNav(nav_index); Atom.freeRelocations(self, atom_index); const atom = self.getAtom(atom_index); diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index c8ab5609a3..60c0bac4a8 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -21,8 +21,9 @@ pub const UpdateError = std.fs.File.OpenError || std.fs.File.SetEndPosError || std.fs.File.CopyRangeError || + std.fs.File.PReadError || std.fs.File.PWriteError || - error{ Overflow, Underflow, UnexpectedEndOfFile }; + error{ EndOfStream, Overflow, Underflow, UnexpectedEndOfFile }; pub const FlushError = UpdateError || @@ -253,10 +254,8 @@ const Section = struct { .trailer_len = trailer_len, .len = header_len + trailer_len, .entries = .{}, - .cross_entry_relocs = .{}, .cross_unit_relocs = .{}, .cross_section_relocs = .{}, - .external_relocs = .{}, }; if (sec.last.unwrap()) |last_unit| { const last_unit_ptr = sec.getUnit(last_unit); @@ -358,10 +357,8 @@ const Unit = struct { /// data length in bytes len: u32, entries: std.ArrayListUnmanaged(Entry), - cross_entry_relocs: std.ArrayListUnmanaged(CrossEntryReloc), cross_unit_relocs: std.ArrayListUnmanaged(CrossUnitReloc), cross_section_relocs: std.ArrayListUnmanaged(CrossSectionReloc), - external_relocs: std.ArrayListUnmanaged(ExternalReloc), const Index = enum(u32) { main, @@ -381,12 +378,16 @@ const Unit = struct { } }; + fn clear(unit: *Unit) void { + unit.cross_unit_relocs.clearRetainingCapacity(); + unit.cross_section_relocs.clearRetainingCapacity(); + } + fn deinit(unit: *Unit, gpa: std.mem.Allocator) void { + for (unit.entries.items) |*entry| entry.deinit(gpa); unit.entries.deinit(gpa); - unit.cross_entry_relocs.deinit(gpa); unit.cross_unit_relocs.deinit(gpa); unit.cross_section_relocs.deinit(gpa); - unit.external_relocs.deinit(gpa); unit.* = undefined; } @@ -398,6 +399,10 @@ const Unit = struct { .next = .none, .off = 0, .len = 0, + .cross_entry_relocs = .{}, + .cross_unit_relocs = .{}, + .cross_section_relocs = .{}, + .external_relocs = .{}, }; if (unit.last.unwrap()) |last_entry| { const last_entry_ptr = unit.getEntry(last_entry); @@ -451,6 +456,14 @@ const Unit = struct { unit_ptr.len = len; } + fn trim(unit: *Unit) void { + const len = unit.getEntry(unit.first.unwrap() orelse return).off; + if (len == 0) return; + for (unit.entries.items) |*entry| entry.off -= len; + unit.off += len; + unit.len -= len; + } + fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void { if (unit.off == new_off) return; if (try dwarf.getFile().?.copyRangeAll( @@ -463,6 +476,7 @@ const Unit = struct { } fn resizeHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) UpdateError!void { + unit.trim(); if (unit.header_len == len) return; const available_len = if (unit.prev.unwrap()) |prev_unit| prev_excess: { const prev_unit_ptr = sec.getUnit(prev_unit); @@ -535,23 +549,11 @@ const Unit = struct { } fn resolveRelocs(unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void { - for (unit.cross_entry_relocs.items) |reloc| { - try dwarf.resolveReloc( - sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry| - unit.header_len + unit.getEntry(source_entry).off - else - 0) + reloc.source_off, - unit.off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sec, dwarf).off + reloc.target_off, - dwarf.sectionOffsetBytes(), - ); - } + const unit_off = sec.off + unit.off; for (unit.cross_unit_relocs.items) |reloc| { const target_unit = sec.getUnit(reloc.target_unit); try dwarf.resolveReloc( - sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry| - unit.header_len + unit.getEntry(source_entry).off - else - 0) + reloc.source_off, + unit_off + reloc.source_off, target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry| target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off else @@ -565,10 +567,7 @@ const Unit = struct { }; const target_unit = target_sec.getUnit(reloc.target_unit); try dwarf.resolveReloc( - sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry| - unit.header_len + unit.getEntry(source_entry).off - else - 0) + reloc.source_off, + unit_off + reloc.source_off, target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry| target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off else @@ -576,57 +575,8 @@ const Unit = struct { dwarf.sectionOffsetBytes(), ); } - if (dwarf.bin_file.cast(.elf)) |elf_file| { - const zo = elf_file.zigObjectPtr().?; - for (unit.external_relocs.items) |reloc| { - const symbol = zo.symbol(reloc.target_sym); - try dwarf.resolveReloc( - sec.off + unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off, - @bitCast(symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off)) - - if (symbol.flags.is_tls) elf_file.dtpAddress() else 0), - @intFromEnum(dwarf.address_size), - ); - } - } else if (dwarf.bin_file.cast(.macho)) |macho_file| { - const zo = macho_file.getZigObject().?; - for (unit.external_relocs.items) |reloc| { - const ref = zo.getSymbolRef(reloc.target_sym, macho_file); - try dwarf.resolveReloc( - sec.off + unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off, - ref.getSymbol(macho_file).?.getAddress(.{}, macho_file), - @intFromEnum(dwarf.address_size), - ); - } - } + for (unit.entries.items) |*entry| try entry.resolveRelocs(unit, sec, dwarf); } - - const CrossEntryReloc = struct { - source_entry: Entry.Index.Optional = .none, - source_off: u32 = 0, - target_entry: Entry.Index, - target_off: u32 = 0, - }; - const CrossUnitReloc = struct { - source_entry: Entry.Index.Optional = .none, - source_off: u32 = 0, - target_unit: Unit.Index, - target_entry: Entry.Index.Optional = .none, - target_off: u32 = 0, - }; - const CrossSectionReloc = struct { - source_entry: Entry.Index.Optional = .none, - source_off: u32 = 0, - target_sec: Section.Index, - target_unit: Unit.Index, - target_entry: Entry.Index.Optional = .none, - target_off: u32 = 0, - }; - const ExternalReloc = struct { - source_entry: Entry.Index, - source_off: u32 = 0, - target_sym: u32, - target_off: u64 = 0, - }; }; /// An indivisible entry within a `Unit` containing section-specific data. @@ -637,6 +587,25 @@ const Entry = struct { off: u32, /// data length in bytes len: u32, + cross_entry_relocs: std.ArrayListUnmanaged(CrossEntryReloc), + cross_unit_relocs: std.ArrayListUnmanaged(CrossUnitReloc), + cross_section_relocs: std.ArrayListUnmanaged(CrossSectionReloc), + external_relocs: std.ArrayListUnmanaged(ExternalReloc), + + fn clear(entry: *Entry) void { + entry.cross_entry_relocs.clearRetainingCapacity(); + entry.cross_unit_relocs.clearRetainingCapacity(); + entry.cross_section_relocs.clearRetainingCapacity(); + entry.external_relocs.clearRetainingCapacity(); + } + + fn deinit(entry: *Entry, gpa: std.mem.Allocator) void { + entry.cross_entry_relocs.deinit(gpa); + entry.cross_unit_relocs.deinit(gpa); + entry.cross_section_relocs.deinit(gpa); + entry.external_relocs.deinit(gpa); + entry.* = undefined; + } const Index = enum(u32) { _, @@ -803,6 +772,88 @@ const Entry = struct { } @panic("missing dwarf relocation target"); } + + fn resolveRelocs(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void { + const entry_off = sec.off + unit.off + unit.header_len + entry.off; + for (entry.cross_entry_relocs.items) |reloc| { + try dwarf.resolveReloc( + entry_off + reloc.source_off, + unit.off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sec, dwarf).off + reloc.target_off, + dwarf.sectionOffsetBytes(), + ); + } + for (entry.cross_unit_relocs.items) |reloc| { + const target_unit = sec.getUnit(reloc.target_unit); + try dwarf.resolveReloc( + entry_off + reloc.source_off, + target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry| + target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off + else + 0) + reloc.target_off, + dwarf.sectionOffsetBytes(), + ); + } + for (entry.cross_section_relocs.items) |reloc| { + const target_sec = switch (reloc.target_sec) { + inline else => |target_sec| &@field(dwarf, @tagName(target_sec)).section, + }; + const target_unit = target_sec.getUnit(reloc.target_unit); + try dwarf.resolveReloc( + entry_off + reloc.source_off, + target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry| + target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off + else + 0) + reloc.target_off, + dwarf.sectionOffsetBytes(), + ); + } + if (dwarf.bin_file.cast(.elf)) |elf_file| { + const zo = elf_file.zigObjectPtr().?; + for (entry.external_relocs.items) |reloc| { + const symbol = zo.symbol(reloc.target_sym); + try dwarf.resolveReloc( + entry_off + reloc.source_off, + @bitCast(symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off)) - + if (symbol.flags.is_tls) elf_file.dtpAddress() else 0), + @intFromEnum(dwarf.address_size), + ); + } + } else if (dwarf.bin_file.cast(.macho)) |macho_file| { + const zo = macho_file.getZigObject().?; + for (entry.external_relocs.items) |reloc| { + const ref = zo.getSymbolRef(reloc.target_sym, macho_file); + try dwarf.resolveReloc( + entry_off + reloc.source_off, + ref.getSymbol(macho_file).?.getAddress(.{}, macho_file), + @intFromEnum(dwarf.address_size), + ); + } + } + } +}; + +const CrossEntryReloc = struct { + source_off: u32 = 0, + target_entry: Entry.Index, + target_off: u32 = 0, +}; +const CrossUnitReloc = struct { + source_off: u32 = 0, + target_unit: Unit.Index, + target_entry: Entry.Index.Optional = .none, + target_off: u32 = 0, +}; +const CrossSectionReloc = struct { + source_off: u32 = 0, + target_sec: Section.Index, + target_unit: Unit.Index, + target_entry: Entry.Index.Optional = .none, + target_off: u32 = 0, +}; +const ExternalReloc = struct { + source_off: u32 = 0, + target_sym: u32, + target_off: u64 = 0, }; pub const Loc = union(enum) { @@ -1087,14 +1138,13 @@ pub const WipNav = struct { const diw = wip_nav.debug_info.writer(dwarf.gpa); try wip_nav.inlined_funcs_high_reloc.ensureUnusedCapacity(dwarf.gpa, 1); - const external_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs; - try external_relocs.ensureUnusedCapacity(dwarf.gpa, 2); try uleb128(diw, @intFromEnum(AbbrevCode.inlined_func)); try wip_nav.refNav(zcu.funcInfo(func).owner_nav); try uleb128(diw, zcu.navSrcLine(zcu.funcInfo(wip_nav.func).owner_nav) + line + 1); - try uleb128(diw, column); + try uleb128(diw, column + 1); + const external_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs; + try external_relocs.ensureUnusedCapacity(dwarf.gpa, 2); external_relocs.appendAssumeCapacity(.{ - .source_entry = wip_nav.entry, .source_off = @intCast(wip_nav.debug_info.items.len), .target_sym = wip_nav.func_sym_index, .target_off = code_off, @@ -1102,7 +1152,6 @@ pub const WipNav = struct { try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size)); wip_nav.inlined_funcs_high_reloc.appendAssumeCapacity(@intCast(external_relocs.items.len)); external_relocs.appendAssumeCapacity(.{ - .source_entry = wip_nav.entry, .source_off = @intCast(wip_nav.debug_info.items.len), .target_sym = wip_nav.func_sym_index, .target_off = undefined, @@ -1112,7 +1161,7 @@ pub const WipNav = struct { } pub fn leaveInlineFunc(wip_nav: *WipNav, func: InternPool.Index, code_off: u64) UpdateError!void { - const external_relocs = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs; + const external_relocs = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs; external_relocs.items[wip_nav.inlined_funcs_high_reloc.pop()].target_off = code_off; try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), @intFromEnum(AbbrevCode.null)); try wip_nav.setInlineFunc(func); @@ -1137,8 +1186,7 @@ pub const WipNav = struct { try dlw.writeByte(DW.LNS.extended_op); try uleb128(dlw, 1 + dwarf.sectionOffsetBytes()); try dlw.writeByte(DW.LNE.ZIG_set_decl); - try dwarf.debug_line.section.getUnit(wip_nav.unit).cross_section_relocs.append(dwarf.gpa, .{ - .source_entry = wip_nav.entry.toOptional(), + try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{ .source_off = @intCast(wip_nav.debug_line.items.len), .target_sec = .debug_info, .target_unit = new_unit, @@ -1174,9 +1222,9 @@ pub const WipNav = struct { fn infoSectionOffset(wip_nav: *WipNav, sec: Section.Index, unit: Unit.Index, entry: Entry.Index, off: u32) UpdateError!void { const dwarf = wip_nav.dwarf; const gpa = dwarf.gpa; + const entry_ptr = dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry); if (sec != .debug_info) { - try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_section_relocs.append(gpa, .{ - .source_entry = wip_nav.entry.toOptional(), + try entry_ptr.cross_section_relocs.append(gpa, .{ .source_off = @intCast(wip_nav.debug_info.items.len), .target_sec = sec, .target_unit = unit, @@ -1184,16 +1232,14 @@ pub const WipNav = struct { .target_off = off, }); } else if (unit != wip_nav.unit) { - try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_unit_relocs.append(gpa, .{ - .source_entry = wip_nav.entry.toOptional(), + try entry_ptr.cross_unit_relocs.append(gpa, .{ .source_off = @intCast(wip_nav.debug_info.items.len), .target_unit = unit, .target_entry = entry.toOptional(), .target_off = off, }); } else { - try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs.append(gpa, .{ - .source_entry = wip_nav.entry.toOptional(), + try entry_ptr.cross_entry_relocs.append(gpa, .{ .source_off = @intCast(wip_nav.debug_info.items.len), .target_entry = entry, .target_off = off, @@ -1208,8 +1254,7 @@ pub const WipNav = struct { fn addrSym(wip_nav: *WipNav, sym_index: u32) UpdateError!void { const dwarf = wip_nav.dwarf; - try dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{ - .source_entry = wip_nav.entry, + try dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{ .source_off = @intCast(wip_nav.debug_info.items.len), .target_sym = sym_index, }); @@ -1269,10 +1314,9 @@ pub const WipNav = struct { fn refForward(wip_nav: *WipNav) std.mem.Allocator.Error!u32 { const dwarf = wip_nav.dwarf; - const cross_entry_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs; + const cross_entry_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs; const reloc_index: u32 = @intCast(cross_entry_relocs.items.len); try cross_entry_relocs.append(dwarf.gpa, .{ - .source_entry = wip_nav.entry.toOptional(), .source_off = @intCast(wip_nav.debug_info.items.len), .target_entry = undefined, .target_off = undefined, @@ -1282,7 +1326,7 @@ pub const WipNav = struct { } fn finishForward(wip_nav: *WipNav, reloc_index: u32) void { - const reloc = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs.items[reloc_index]; + const reloc = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs.items[reloc_index]; reloc.target_entry = wip_nav.entry; reloc.target_off = @intCast(wip_nav.debug_info.items.len); } @@ -1595,7 +1639,15 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In const unit = try dwarf.getUnit(file.mod); const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index); errdefer _ = dwarf.navs.pop(); - if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit); + if (nav_gop.found_existing) { + for ([_]*Section{ + &dwarf.debug_aranges.section, + &dwarf.debug_info.section, + &dwarf.debug_line.section, + &dwarf.debug_loclists.section, + &dwarf.debug_rnglists.section, + }) |sec| sec.getUnit(unit).getEntry(nav_gop.value_ptr.*).clear(); + } else nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit); const nav_val = zcu.navValue(nav_index); var wip_nav: WipNav = .{ .dwarf = dwarf, @@ -1759,17 +1811,15 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In try wip_nav.strp(nav.name.toSlice(ip)); try wip_nav.strp(nav.fqn.toSlice(ip)); try wip_nav.refType(Type.fromInterned(func_type.return_type)); - const external_relocs = &dwarf.debug_info.section.getUnit(unit).external_relocs; + const external_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs; try external_relocs.ensureUnusedCapacity(dwarf.gpa, 2); external_relocs.appendAssumeCapacity(.{ - .source_entry = wip_nav.entry, .source_off = @intCast(wip_nav.debug_info.items.len), .target_sym = sym_index, }); try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size)); wip_nav.func_high_reloc = @intCast(external_relocs.items.len); external_relocs.appendAssumeCapacity(.{ - .source_entry = wip_nav.entry, .source_off = @intCast(wip_nav.debug_info.items.len), .target_sym = sym_index, .target_off = undefined, @@ -1785,8 +1835,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In if (dwarf.incremental()) { try uleb128(dlw, 1 + dwarf.sectionOffsetBytes()); try dlw.writeByte(DW.LNE.ZIG_set_decl); - try dwarf.debug_line.section.getUnit(wip_nav.unit).cross_section_relocs.append(dwarf.gpa, .{ - .source_entry = wip_nav.entry.toOptional(), + try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{ .source_off = @intCast(wip_nav.debug_line.items.len), .target_sec = .debug_info, .target_unit = wip_nav.unit, @@ -1801,8 +1850,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In } else { try uleb128(dlw, 1 + @intFromEnum(dwarf.address_size)); try dlw.writeByte(DW.LNE.set_address); - try dwarf.debug_line.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{ - .source_entry = wip_nav.entry, + try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{ .source_off = @intCast(wip_nav.debug_line.items.len), .target_sym = sym_index, }); @@ -1835,7 +1883,7 @@ pub fn finishWipNav( log.debug("finishWipNav({})", .{nav.fqn.fmt(ip)}); if (wip_nav.func != .none) { - const external_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs; + const external_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs; external_relocs.items[wip_nav.func_high_reloc].target_off = sym.size; if (wip_nav.any_children) { const diw = wip_nav.debug_info.writer(dwarf.gpa); @@ -1847,8 +1895,7 @@ pub fn finishWipNav( ); var aranges_entry = [1]u8{0} ** (8 + 8); - try dwarf.debug_aranges.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{ - .source_entry = wip_nav.entry, + try dwarf.debug_aranges.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{ .target_sym = sym.index, }); dwarf.writeInt(aranges_entry[0..@intFromEnum(dwarf.address_size)], 0); @@ -1862,14 +1909,12 @@ pub fn finishWipNav( aranges_entry[0 .. @intFromEnum(dwarf.address_size) * 2], ); - try dwarf.debug_rnglists.section.getUnit(wip_nav.unit).external_relocs.appendSlice(dwarf.gpa, &.{ + try dwarf.debug_rnglists.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.appendSlice(dwarf.gpa, &.{ .{ - .source_entry = wip_nav.entry, .source_off = 1, .target_sym = sym.index, }, .{ - .source_entry = wip_nav.entry, .source_off = 1 + @intFromEnum(dwarf.address_size), .target_sym = sym.index, .target_off = sym.size, @@ -1935,6 +1980,29 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool errdefer _ = dwarf.navs.pop(); switch (ip.indexToKey(nav_val.toIntern())) { .func => |func| { + if (nav_gop.found_existing) { + const unit_ptr = dwarf.debug_info.section.getUnit(unit); + const entry_ptr = unit_ptr.getEntry(nav_gop.value_ptr.*); + if (entry_ptr.len >= AbbrevCode.decl_bytes) { + var abbrev_code_buf: [AbbrevCode.decl_bytes]u8 = undefined; + if (try dwarf.getFile().?.preadAll( + &abbrev_code_buf, + dwarf.debug_info.section.off + unit_ptr.off + unit_ptr.header_len + entry_ptr.off, + ) != abbrev_code_buf.len) return error.InputOutput; + var abbrev_code_fbs = std.io.fixedBufferStream(&abbrev_code_buf); + const abbrev_code: AbbrevCode = @enumFromInt( + try std.leb.readUleb128(@typeInfo(AbbrevCode).Enum.tag_type, abbrev_code_fbs.reader()), + ); + switch (abbrev_code) { + else => unreachable, + .decl_func, .decl_func_empty => return, + .decl_func_generic, .decl_func_generic_empty => {}, + } + } + entry_ptr.clear(); + } else nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit); + wip_nav.entry = nav_gop.value_ptr.*; + const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: { const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace); break :parent .{ @@ -1948,12 +2016,9 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool }; } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private }; - if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit); - wip_nav.entry = nav_gop.value_ptr.*; - const func_type = ip.indexToKey(func.ty).func_type; const diw = wip_nav.debug_info.writer(dwarf.gpa); - try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (func_type.param_types.len > 0 and func_type.is_var_args) .decl_func_generic else .decl_func_generic_empty))); + try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (func_type.param_types.len > 0 or func_type.is_var_args) .decl_func_generic else .decl_func_generic_empty))); try wip_nav.refType(Type.fromInterned(parent_type)); assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); @@ -1961,12 +2026,14 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool try diw.writeByte(accessibility); try wip_nav.strp(nav.name.toSlice(ip)); try wip_nav.refType(Type.fromInterned(func_type.return_type)); - for (0..func_type.param_types.len) |param_index| { - try uleb128(diw, @intFromEnum(AbbrevCode.func_type_param)); - try wip_nav.refType(Type.fromInterned(func_type.param_types.get(ip)[param_index])); + if (func_type.param_types.len > 0 or func_type.is_var_args) { + for (0..func_type.param_types.len) |param_index| { + try uleb128(diw, @intFromEnum(AbbrevCode.func_type_param)); + try wip_nav.refType(Type.fromInterned(func_type.param_types.get(ip)[param_index])); + } + if (func_type.is_var_args) try uleb128(diw, @intFromEnum(AbbrevCode.is_var_args)); + try uleb128(diw, @intFromEnum(AbbrevCode.null)); } - if (func_type.is_var_args) try uleb128(diw, @intFromEnum(AbbrevCode.is_var_args)); - try uleb128(diw, @intFromEnum(AbbrevCode.null)); }, .struct_type => done: { const loaded_struct = ip.loadStructType(nav_val.toIntern()); @@ -2535,13 +2602,25 @@ fn updateType( .error_union_type => |error_union_type| { const error_union_error_set_type = Type.fromInterned(error_union_type.error_set_type); const error_union_payload_type = Type.fromInterned(error_union_type.payload_type); - const error_union_error_set_offset = codegen.errUnionErrorOffset(error_union_payload_type, pt); - const error_union_payload_offset = codegen.errUnionPayloadOffset(error_union_payload_type, pt); + const error_union_error_set_offset, const error_union_payload_offset = switch (error_union_type.payload_type) { + .generic_poison_type => .{ 0, 0 }, + else => .{ + codegen.errUnionErrorOffset(error_union_payload_type, pt), + codegen.errUnionPayloadOffset(error_union_payload_type, pt), + }, + }; try uleb128(diw, @intFromEnum(AbbrevCode.union_type)); try wip_nav.strp(name); - try uleb128(diw, ty.abiSize(pt)); - try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?); + if (error_union_type.error_set_type != .generic_poison_type and + error_union_type.payload_type != .generic_poison_type) + { + try uleb128(diw, ty.abiSize(pt)); + try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?); + } else { + try uleb128(diw, 0); + try uleb128(diw, 1); + } { try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union)); try wip_nav.infoSectionOffset( @@ -2723,10 +2802,16 @@ fn updateType( } if (error_set_type.names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null)); }, - .inferred_error_set_type => |func| { - try uleb128(diw, @intFromEnum(AbbrevCode.inferred_error_set_type)); - try wip_nav.strp(name); - try wip_nav.refType(Type.fromInterned(ip.funcIesResolvedUnordered(func))); + .inferred_error_set_type => |func| switch (ip.funcIesResolvedUnordered(func)) { + .none => { + try uleb128(diw, @intFromEnum(AbbrevCode.void_type)); + try wip_nav.strp(name); + }, + else => |ies| { + try uleb128(diw, @intFromEnum(AbbrevCode.inferred_error_set_type)); + try wip_nav.strp(name); + try wip_nav.refType(Type.fromInterned(ies)); + }, }, // values, not types @@ -3072,7 +3157,8 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { if (dwarf.debug_aranges.section.dirty) { for (dwarf.debug_aranges.section.units.items, 0..) |*unit_ptr, unit_index| { const unit: Unit.Index = @enumFromInt(unit_index); - try unit_ptr.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 1); + unit_ptr.clear(); + try unit_ptr.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 1); header.clearRetainingCapacity(); try header.ensureTotalCapacity(unit_ptr.header_len); const unit_len = (if (unit_ptr.next.unwrap()) |next_unit| @@ -3103,8 +3189,9 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { if (dwarf.debug_info.section.dirty) { 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); + unit_ptr.clear(); + try unit_ptr.cross_unit_relocs.ensureTotalCapacity(dwarf.gpa, 1); + try unit_ptr.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 7); header.clearRetainingCapacity(); try header.ensureTotalCapacity(unit_ptr.header_len); const unit_len = (if (unit_ptr.next.unwrap()) |next_unit| @@ -3195,7 +3282,8 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { 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.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())); + unit.clear(); + try unit.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 2 * (1 + mod_info.files.count())); header.clearRetainingCapacity(); try header.ensureTotalCapacity(unit.header_len); const unit_len = (if (unit.next.unwrap()) |next_unit| diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index d592f6e9d3..a6a6f76d04 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -1122,9 +1122,9 @@ pub fn updateNav( log.debug("updateNav {}({d})", .{ nav.fqn.fmt(ip), nav_index }); - const nav_val = zcu.navValue(nav_index); - const nav_init = switch (ip.indexToKey(nav_val.toIntern())) { - .variable => |variable| Value.fromInterned(variable.init), + const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) { + .func => .none, + .variable => |variable| variable.init, .@"extern" => |@"extern"| { if (ip.isFunctionType(@"extern".ty)) return; const sym_index = try self.getGlobalSymbol( @@ -1135,10 +1135,10 @@ pub fn updateNav( self.symbol(sym_index).flags.is_extern_ptr = true; return; }, - else => nav_val, + else => nav.status.resolved.val, }; - if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) { + if (nav_init != .none and Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(pt)) { const sym_index = try self.getOrCreateMetadataForNav(elf_file, nav_index); self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file); @@ -1153,7 +1153,7 @@ pub fn updateNav( &elf_file.base, pt, zcu.navSrcLoc(nav_index), - nav_init, + Value.fromInterned(nav_init), &code_buffer, if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none, .{ .parent_atom_index = sym_index }, diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index 4827dae268..d6b77243a1 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -869,10 +869,11 @@ pub fn updateNav( const zcu = pt.zcu; const ip = &zcu.intern_pool; + const nav = ip.getNav(nav_index); - const nav_val = zcu.navValue(nav_index); - const nav_init = switch (ip.indexToKey(nav_val.toIntern())) { - .variable => |variable| Value.fromInterned(variable.init), + const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) { + .func => .none, + .variable => |variable| variable.init, .@"extern" => |@"extern"| { if (ip.isFunctionType(@"extern".ty)) return; // Extern variable gets a __got entry only @@ -883,10 +884,10 @@ pub fn updateNav( sym.flags.is_extern_ptr = true; return; }, - else => nav_val, + else => nav.status.resolved.val, }; - if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) { + if (nav_init != .none and Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(pt)) { const sym_index = try self.getOrCreateMetadataForNav(macho_file, nav_index); self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file); @@ -900,7 +901,7 @@ pub fn updateNav( &macho_file.base, pt, zcu.navSrcLoc(nav_index), - nav_init, + Value.fromInterned(nav_init), &code_buffer, if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none, .{ .parent_atom_index = sym_index }, diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index eeba9ad61b..27a3bf7bc8 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -448,6 +448,7 @@ pub fn updateNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde const nav = ip.getNav(nav_index); const nav_val = zcu.navValue(nav_index); const nav_init = switch (ip.indexToKey(nav_val.toIntern())) { + .func => return, .variable => |variable| Value.fromInterned(variable.init), .@"extern" => { log.debug("found extern decl: {}", .{nav.name.fmt(ip)}); @@ -456,7 +457,7 @@ pub fn updateNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde else => nav_val, }; - if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) { + if (nav_init.typeOf(zcu).hasRuntimeBits(pt)) { const atom_idx = try self.seeNav(pt, nav_index); var code_buffer = std.ArrayList(u8).init(gpa); diff --git a/src/link/Wasm/ZigObject.zig b/src/link/Wasm/ZigObject.zig index 0f73edefab..05c15f0732 100644 --- a/src/link/Wasm/ZigObject.zig +++ b/src/link/Wasm/ZigObject.zig @@ -259,7 +259,7 @@ pub fn updateNav( else => .{ false, .none, nav_val }, }; - if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) { + if (nav_init.typeOf(zcu).hasRuntimeBits(pt)) { const gpa = wasm_file.base.comp.gpa; const atom_index = try zig_object.getOrCreateAtomForNav(wasm_file, pt, nav_index); const atom = wasm_file.getAtomPtr(atom_index); diff --git a/test/src/Debugger.zig b/test/src/Debugger.zig index 2ff141dd84..f92f7f8a95 100644 --- a/test/src/Debugger.zig +++ b/test/src/Debugger.zig @@ -587,7 +587,7 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void { }, ); db.addLldbTest( - "cross_module_call", + "inline_call", target, &.{ .{ @@ -595,8 +595,18 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void { .source = \\const module = @import("module"); \\pub fn main() void { - \\ module.foo(123); - \\ module.bar(456); + \\ fa(12); + \\ fb(34); + \\ module.fc(56); + \\ module.fd(78); + \\} + \\fn fa(pa: u32) void { + \\ const la = ~pa; + \\ _ = la; + \\} + \\inline fn fb(pb: u32) void { + \\ const lb = ~pb; + \\ _ = lb; \\} \\ , @@ -605,34 +615,84 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void { .import = "module", .path = "module.zig", .source = - \\pub fn foo(x: u32) void { - \\ _ = x; + \\pub fn fc(pc: u32) void { + \\ const lc = ~pc; + \\ _ = lc; \\} - \\pub inline fn bar(y: u32) void { - \\ _ = y; + \\pub inline fn fd(pd: u32) void { + \\ const ld = ~pd; + \\ _ = ld; \\} \\ , }, }, - \\breakpoint set --file module.zig --source-pattern-regexp '_ = x;' + \\settings set frame-format 'frame #${frame.index}:{ ${module.file.basename}{\`${function.name-with-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${line.file.basename}:${line.number}{:${line.column}}}{${function.is-optimized} [opt]}{${frame.is-artificial} [artificial]}\n' + \\ + \\breakpoint set --file main.zig --source-pattern-regexp '_ = la;' \\process launch - \\source info + \\frame variable pa la + \\thread backtrace --count 2 \\breakpoint delete --force 1 \\ - \\breakpoint set --file module.zig --line 5 + \\breakpoint set --file main.zig --source-pattern-regexp '_ = lb;' \\process continue - \\source info + \\frame variable pb lb + \\thread backtrace --count 2 \\breakpoint delete --force 2 + \\ + \\breakpoint set --file module.zig --source-pattern-regexp '_ = lc;' + \\process continue + \\frame variable pc lc + \\thread backtrace --count 2 + \\breakpoint delete --force 3 + \\ + \\breakpoint set --file module.zig --line 7 + \\process continue + \\frame variable pd ld + \\thread backtrace --count 2 + \\breakpoint delete --force 4 , &.{ - \\/module.zig:2:5 + \\(lldb) frame variable pa la + \\(u32) pa = 12 + \\(u32) la = 4294967283 + \\(lldb) thread backtrace --count 2 + \\* thread #1, name = 'inline_call', stop reason = breakpoint 1.1 + \\ * frame #0: inline_call`main.fa(pa=12) at main.zig:10:5 + \\ frame #1: inline_call`main.main at main.zig:3:7 \\(lldb) breakpoint delete --force 1 \\1 breakpoints deleted; 0 breakpoint locations disabled. , - \\/module.zig:5:5 + \\(lldb) frame variable pb lb + \\(u32) pb = 34 + \\(u32) lb = 4294967261 + \\(lldb) thread backtrace --count 2 + \\* thread #1, name = 'inline_call', stop reason = breakpoint 2.1 + \\ * frame #0: inline_call`main.main [inlined] fb(pb=34) at main.zig:14:5 + \\ frame #1: inline_call`main.main at main.zig:4:7 \\(lldb) breakpoint delete --force 2 \\1 breakpoints deleted; 0 breakpoint locations disabled. + , + \\(lldb) frame variable pc lc + \\(u32) pc = 56 + \\(u32) lc = 4294967239 + \\(lldb) thread backtrace --count 2 + \\* thread #1, name = 'inline_call', stop reason = breakpoint 3.1 + \\ * frame #0: inline_call`module.fc(pc=56) at module.zig:3:5 + \\ frame #1: inline_call`main.main at main.zig:5:14 + \\(lldb) breakpoint delete --force 3 + \\1 breakpoints deleted; 0 breakpoint locations disabled. + , + \\(lldb) frame variable pd ld + \\(u32) pd = 78 + \\(u32) ld = 4294967217 + \\(lldb) thread backtrace --count 2 + \\* thread #1, name = 'inline_call', stop reason = breakpoint 4.1 + \\ * frame #0: inline_call`main.main [inlined] fd(pd=78) at module.zig:7:5 + \\ frame #1: inline_call`main.main at main.zig:6:14 + \\(lldb) breakpoint delete --force 4 + \\1 breakpoints deleted; 0 breakpoint locations disabled. }, ); } -- cgit v1.2.3