| ... | ... | @@ -1,2884 +1,3820 @@ |
| 1 | | allocator: Allocator, |
| 2 | | bin_file: *File, |
| 3 | | format: Format, |
| 4 | | ptr_width: PtrWidth, |
| 5 | | |
| 6 | | /// A list of `Atom`s whose Line Number Programs have surplus capacity. |
| 7 | | /// This is the same concept as `Section.free_list` in Elf; see those doc comments. |
| 8 | | src_fn_free_list: std.AutoHashMapUnmanaged(Atom.Index, void) = .{}, |
| 9 | | src_fn_first_index: ?Atom.Index = null, |
| 10 | | src_fn_last_index: ?Atom.Index = null, |
| 11 | | src_fns: std.ArrayListUnmanaged(Atom) = .{}, |
| 12 | | src_fn_navs: AtomTable = .{}, |
| 13 | | |
| 14 | | /// A list of `Atom`s whose corresponding .debug_info tags have surplus capacity. |
| 15 | | /// This is the same concept as `text_block_free_list`; see those doc comments. |
| 16 | | di_atom_free_list: std.AutoHashMapUnmanaged(Atom.Index, void) = .{}, |
| 17 | | di_atom_first_index: ?Atom.Index = null, |
| 18 | | di_atom_last_index: ?Atom.Index = null, |
| 19 | | di_atoms: std.ArrayListUnmanaged(Atom) = .{}, |
| 20 | | di_atom_navs: AtomTable = .{}, |
| 21 | | |
| 22 | | dbg_line_header: DbgLineHeader, |
| 23 | | |
| 24 | | abbrev_table_offset: ?u64 = null, |
| 25 | | |
| 26 | | /// TODO replace with InternPool |
| 27 | | /// Table of debug symbol names. |
| 28 | | strtab: StringTable = .{}, |
| 29 | | |
| 30 | | /// Quick lookup array of all defined source files referenced by at least one Nav. |
| 31 | | /// They will end up in the DWARF debug_line header as two lists: |
| 32 | | /// * []include_directory |
| 33 | | /// * []file_names |
| 34 | | di_files: std.AutoArrayHashMapUnmanaged(*const Zcu.File, void) = .{}, |
| 35 | | |
| 36 | | global_abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{}, |
| 37 | | |
| 38 | | const AtomTable = std.AutoHashMapUnmanaged(InternPool.Nav.Index, Atom.Index); |
| 39 | | |
| 40 | | const Atom = struct { |
| 41 | | /// Offset into .debug_info pointing to the tag for this Nav, or |
| 42 | | /// offset from the beginning of the Debug Line Program header that contains this function. |
| 43 | | off: u32, |
| 44 | | /// Size of the .debug_info tag for this Nav, not including padding, or |
| 45 | | /// size of the line number program component belonging to this function, not |
| 46 | | /// including padding. |
| 47 | | len: u32, |
| 1 | gpa: std.mem.Allocator, |
| 2 | bin_file: *link.File, |
| 3 | format: DW.Format, |
| 4 | endian: std.builtin.Endian, |
| 5 | address_size: AddressSize, |
| 6 | |
| 7 | mods: std.AutoArrayHashMapUnmanaged(*Module, ModInfo), |
| 8 | types: std.AutoArrayHashMapUnmanaged(InternPool.Index, Entry.Index), |
| 9 | navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Entry.Index), |
| 10 | |
| 11 | debug_abbrev: DebugAbbrev, |
| 12 | debug_aranges: DebugAranges, |
| 13 | debug_info: DebugInfo, |
| 14 | debug_line: DebugLine, |
| 15 | debug_line_str: StringSection, |
| 16 | debug_loclists: DebugLocLists, |
| 17 | debug_rnglists: DebugRngLists, |
| 18 | debug_str: StringSection, |
| 19 | |
| 20 | pub const UpdateError = |
| 21 | std.fs.File.OpenError || |
| 22 | std.fs.File.SetEndPosError || |
| 23 | std.fs.File.CopyRangeError || |
| 24 | std.fs.File.PWriteError || |
| 25 | error{ Overflow, Underflow, UnexpectedEndOfFile }; |
| 26 | |
| 27 | pub const FlushError = |
| 28 | UpdateError || |
| 29 | std.process.GetCwdError; |
| 30 | |
| 31 | pub const RelocError = |
| 32 | std.fs.File.PWriteError; |
| 33 | |
| 34 | pub const AddressSize = enum(u8) { |
| 35 | @"32" = 4, |
| 36 | @"64" = 8, |
| 37 | _, |
| 38 | }; |
| 39 | |
| 40 | const ModInfo = struct { |
| 41 | root_dir_path: Entry.Index, |
| 42 | dirs: std.AutoArrayHashMapUnmanaged(Unit.Index, void), |
| 43 | files: Files, |
| 48 | 44 | |
| 49 | | prev_index: ?Index, |
| 50 | | next_index: ?Index, |
| 45 | const Files = std.AutoArrayHashMapUnmanaged(Zcu.File.Index, void); |
| 51 | 46 | |
| 52 | | pub const Index = u32; |
| 47 | fn deinit(mod_info: *ModInfo, gpa: std.mem.Allocator) void { |
| 48 | mod_info.dirs.deinit(gpa); |
| 49 | mod_info.files.deinit(gpa); |
| 50 | mod_info.* = undefined; |
| 51 | } |
| 53 | 52 | }; |
| 54 | 53 | |
| 55 | | const DbgLineHeader = struct { |
| 56 | | minimum_instruction_length: u8, |
| 57 | | maximum_operations_per_instruction: u8, |
| 58 | | default_is_stmt: bool, |
| 59 | | line_base: i8, |
| 60 | | line_range: u8, |
| 61 | | opcode_base: u8, |
| 54 | const DebugAbbrev = struct { |
| 55 | section: Section, |
| 56 | const unit: Unit.Index = @enumFromInt(0); |
| 57 | const entry: Entry.Index = @enumFromInt(0); |
| 62 | 58 | }; |
| 63 | 59 | |
| 64 | | /// Represents state of the analysed Nav. |
| 65 | | /// Includes Nav's abbrev table of type Types, matching arena |
| 66 | | /// and a set of relocations that will be resolved once this |
| 67 | | /// Nav's inner Atom is assigned an offset within the DWARF section. |
| 68 | | pub const NavState = struct { |
| 69 | | dwarf: *Dwarf, |
| 70 | | pt: Zcu.PerThread, |
| 71 | | di_atom_navs: *const AtomTable, |
| 72 | | dbg_line_func: InternPool.Index, |
| 73 | | dbg_line: std.ArrayList(u8), |
| 74 | | dbg_info: std.ArrayList(u8), |
| 75 | | abbrev_type_arena: std.heap.ArenaAllocator, |
| 76 | | abbrev_table: std.ArrayListUnmanaged(AbbrevEntry), |
| 77 | | abbrev_resolver: std.AutoHashMapUnmanaged(InternPool.Index, u32), |
| 78 | | abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation), |
| 79 | | exprloc_relocs: std.ArrayListUnmanaged(ExprlocRelocation), |
| 80 | | |
| 81 | | pub fn deinit(ns: *NavState) void { |
| 82 | | const gpa = ns.dwarf.allocator; |
| 83 | | ns.dbg_line.deinit(); |
| 84 | | ns.dbg_info.deinit(); |
| 85 | | ns.abbrev_type_arena.deinit(); |
| 86 | | ns.abbrev_table.deinit(gpa); |
| 87 | | ns.abbrev_resolver.deinit(gpa); |
| 88 | | ns.abbrev_relocs.deinit(gpa); |
| 89 | | ns.exprloc_relocs.deinit(gpa); |
| 90 | | } |
| 91 | | |
| 92 | | /// Adds local type relocation of the form: @offset => @this + addend |
| 93 | | /// @this signifies the offset within the .debug_abbrev section of the containing atom. |
| 94 | | fn addTypeRelocLocal(self: *NavState, atom_index: Atom.Index, offset: u32, addend: u32) !void { |
| 95 | | log.debug("{x}: @this + {x}", .{ offset, addend }); |
| 96 | | try self.abbrev_relocs.append(self.dwarf.allocator, .{ |
| 97 | | .target = null, |
| 98 | | .atom_index = atom_index, |
| 99 | | .offset = offset, |
| 100 | | .addend = addend, |
| 101 | | }); |
| 60 | const DebugAranges = struct { |
| 61 | section: Section, |
| 62 | |
| 63 | fn headerBytes(dwarf: *Dwarf) u32 { |
| 64 | return std.mem.alignForwardAnyAlign( |
| 65 | u32, |
| 66 | dwarf.unitLengthBytes() + 2 + dwarf.sectionOffsetBytes() + 1 + 1, |
| 67 | @intFromEnum(dwarf.address_size) * 2, |
| 68 | ); |
| 102 | 69 | } |
| 103 | 70 | |
| 104 | | /// Adds global type relocation of the form: @offset => @symbol + 0 |
| 105 | | /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section |
| 106 | | /// which we use as our target of the relocation. |
| 107 | | fn addTypeRelocGlobal(self: *NavState, atom_index: Atom.Index, ty: Type, offset: u32) !void { |
| 108 | | const gpa = self.dwarf.allocator; |
| 109 | | const resolv = self.abbrev_resolver.get(ty.toIntern()) orelse blk: { |
| 110 | | const sym_index: u32 = @intCast(self.abbrev_table.items.len); |
| 111 | | try self.abbrev_table.append(gpa, .{ |
| 112 | | .atom_index = atom_index, |
| 113 | | .type = ty, |
| 114 | | .offset = undefined, |
| 115 | | }); |
| 116 | | log.debug("%{d}: {}", .{ sym_index, ty.fmt(self.pt) }); |
| 117 | | try self.abbrev_resolver.putNoClobber(gpa, ty.toIntern(), sym_index); |
| 118 | | break :blk sym_index; |
| 119 | | }; |
| 120 | | log.debug("{x}: %{d} + 0", .{ offset, resolv }); |
| 121 | | try self.abbrev_relocs.append(gpa, .{ |
| 122 | | .target = resolv, |
| 123 | | .atom_index = atom_index, |
| 124 | | .offset = offset, |
| 125 | | .addend = 0, |
| 126 | | }); |
| 71 | fn trailerBytes(dwarf: *Dwarf) u32 { |
| 72 | return @intFromEnum(dwarf.address_size) * 2; |
| 127 | 73 | } |
| 74 | }; |
| 128 | 75 | |
| 129 | | fn addDbgInfoType( |
| 130 | | self: *NavState, |
| 131 | | pt: Zcu.PerThread, |
| 132 | | atom_index: Atom.Index, |
| 133 | | ty: Type, |
| 134 | | ) error{OutOfMemory}!void { |
| 135 | | const zcu = pt.zcu; |
| 136 | | const dbg_info_buffer = &self.dbg_info; |
| 137 | | const target = zcu.getTarget(); |
| 138 | | const target_endian = target.cpu.arch.endian(); |
| 139 | | const ip = &zcu.intern_pool; |
| 76 | const DebugInfo = struct { |
| 77 | section: Section, |
| 140 | 78 | |
| 141 | | switch (ty.zigTypeTag(zcu)) { |
| 142 | | .NoReturn => unreachable, |
| 143 | | .Void => { |
| 144 | | try dbg_info_buffer.append(@intFromEnum(AbbrevCode.zero_bit_type)); |
| 145 | | }, |
| 146 | | .Bool => { |
| 147 | | try dbg_info_buffer.ensureUnusedCapacity(12); |
| 148 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.base_type)); |
| 149 | | // DW.AT.encoding, DW.FORM.data1 |
| 150 | | dbg_info_buffer.appendAssumeCapacity(DW.ATE.boolean); |
| 151 | | // DW.AT.byte_size, DW.FORM.udata |
| 152 | | try leb128.writeUleb128(dbg_info_buffer.writer(), ty.abiSize(pt)); |
| 153 | | // DW.AT.name, DW.FORM.string |
| 154 | | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(pt)}); |
| 155 | | }, |
| 156 | | .Int => { |
| 157 | | const info = ty.intInfo(zcu); |
| 158 | | try dbg_info_buffer.ensureUnusedCapacity(12); |
| 159 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.base_type)); |
| 160 | | // DW.AT.encoding, DW.FORM.data1 |
| 161 | | dbg_info_buffer.appendAssumeCapacity(switch (info.signedness) { |
| 162 | | .signed => DW.ATE.signed, |
| 163 | | .unsigned => DW.ATE.unsigned, |
| 164 | | }); |
| 165 | | // DW.AT.byte_size, DW.FORM.udata |
| 166 | | try leb128.writeUleb128(dbg_info_buffer.writer(), ty.abiSize(pt)); |
| 167 | | // DW.AT.name, DW.FORM.string |
| 168 | | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(pt)}); |
| 169 | | }, |
| 170 | | .Optional => { |
| 171 | | if (ty.isPtrLikeOptional(zcu)) { |
| 172 | | try dbg_info_buffer.ensureUnusedCapacity(12); |
| 173 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.base_type)); |
| 174 | | // DW.AT.encoding, DW.FORM.data1 |
| 175 | | dbg_info_buffer.appendAssumeCapacity(DW.ATE.address); |
| 176 | | // DW.AT.byte_size, DW.FORM.udata |
| 177 | | try leb128.writeUleb128(dbg_info_buffer.writer(), ty.abiSize(pt)); |
| 178 | | // DW.AT.name, DW.FORM.string |
| 179 | | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(pt)}); |
| 180 | | } else { |
| 181 | | // Non-pointer optionals are structs: struct { .maybe = *, .val = * } |
| 182 | | const payload_ty = ty.optionalChild(zcu); |
| 183 | | // DW.AT.structure_type |
| 184 | | try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_type)); |
| 185 | | // DW.AT.byte_size, DW.FORM.udata |
| 186 | | const abi_size = ty.abiSize(pt); |
| 187 | | try leb128.writeUleb128(dbg_info_buffer.writer(), abi_size); |
| 188 | | // DW.AT.name, DW.FORM.string |
| 189 | | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(pt)}); |
| 190 | | // DW.AT.member |
| 191 | | try dbg_info_buffer.ensureUnusedCapacity(21); |
| 192 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member)); |
| 193 | | // DW.AT.name, DW.FORM.string |
| 194 | | dbg_info_buffer.appendSliceAssumeCapacity("maybe"); |
| 195 | | dbg_info_buffer.appendAssumeCapacity(0); |
| 196 | | // DW.AT.type, DW.FORM.ref4 |
| 197 | | var index = dbg_info_buffer.items.len; |
| 198 | | dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); |
| 199 | | try self.addTypeRelocGlobal(atom_index, Type.bool, @intCast(index)); |
| 200 | | // DW.AT.data_member_location, DW.FORM.udata |
| 201 | | dbg_info_buffer.appendAssumeCapacity(0); |
| 202 | | // DW.AT.member |
| 203 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member)); |
| 204 | | // DW.AT.name, DW.FORM.string |
| 205 | | dbg_info_buffer.appendSliceAssumeCapacity("val"); |
| 206 | | dbg_info_buffer.appendAssumeCapacity(0); |
| 207 | | // DW.AT.type, DW.FORM.ref4 |
| 208 | | index = dbg_info_buffer.items.len; |
| 209 | | dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); |
| 210 | | try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(index)); |
| 211 | | // DW.AT.data_member_location, DW.FORM.udata |
| 212 | | const offset = abi_size - payload_ty.abiSize(pt); |
| 213 | | try leb128.writeUleb128(dbg_info_buffer.writer(), offset); |
| 214 | | // DW.AT.structure_type delimit children |
| 215 | | try dbg_info_buffer.append(0); |
| 216 | | } |
| 217 | | }, |
| 218 | | .Pointer => { |
| 219 | | if (ty.isSlice(zcu)) { |
| 220 | | // Slices are structs: struct { .ptr = *, .len = N } |
| 221 | | const ptr_bits = target.ptrBitWidth(); |
| 222 | | const ptr_bytes: u8 = @intCast(@divExact(ptr_bits, 8)); |
| 223 | | // DW.AT.structure_type |
| 224 | | try dbg_info_buffer.ensureUnusedCapacity(2); |
| 225 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_type)); |
| 226 | | // DW.AT.byte_size, DW.FORM.udata |
| 227 | | try leb128.writeUleb128(dbg_info_buffer.writer(), ty.abiSize(pt)); |
| 228 | | // DW.AT.name, DW.FORM.string |
| 229 | | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(pt)}); |
| 230 | | // DW.AT.member |
| 231 | | try dbg_info_buffer.ensureUnusedCapacity(21); |
| 232 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member)); |
| 233 | | // DW.AT.name, DW.FORM.string |
| 234 | | dbg_info_buffer.appendSliceAssumeCapacity("ptr"); |
| 235 | | dbg_info_buffer.appendAssumeCapacity(0); |
| 236 | | // DW.AT.type, DW.FORM.ref4 |
| 237 | | var index = dbg_info_buffer.items.len; |
| 238 | | dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); |
| 239 | | const ptr_ty = ty.slicePtrFieldType(zcu); |
| 240 | | try self.addTypeRelocGlobal(atom_index, ptr_ty, @intCast(index)); |
| 241 | | // DW.AT.data_member_location, DW.FORM.udata |
| 242 | | dbg_info_buffer.appendAssumeCapacity(0); |
| 243 | | // DW.AT.member |
| 244 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member)); |
| 245 | | // DW.AT.name, DW.FORM.string |
| 246 | | dbg_info_buffer.appendSliceAssumeCapacity("len"); |
| 247 | | dbg_info_buffer.appendAssumeCapacity(0); |
| 248 | | // DW.AT.type, DW.FORM.ref4 |
| 249 | | index = dbg_info_buffer.items.len; |
| 250 | | dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); |
| 251 | | try self.addTypeRelocGlobal(atom_index, Type.usize, @intCast(index)); |
| 252 | | // DW.AT.data_member_location, DW.FORM.udata |
| 253 | | dbg_info_buffer.appendAssumeCapacity(ptr_bytes); |
| 254 | | // DW.AT.structure_type delimit children |
| 255 | | dbg_info_buffer.appendAssumeCapacity(0); |
| 256 | | } else { |
| 257 | | try dbg_info_buffer.ensureUnusedCapacity(9); |
| 258 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.ptr_type)); |
| 259 | | // DW.AT.type, DW.FORM.ref4 |
| 260 | | const index = dbg_info_buffer.items.len; |
| 261 | | dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); |
| 262 | | try self.addTypeRelocGlobal(atom_index, ty.childType(zcu), @intCast(index)); |
| 263 | | } |
| 264 | | }, |
| 265 | | .Array => { |
| 266 | | // DW.AT.array_type |
| 267 | | try dbg_info_buffer.append(@intFromEnum(AbbrevCode.array_type)); |
| 268 | | // DW.AT.name, DW.FORM.string |
| 269 | | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(pt)}); |
| 270 | | // DW.AT.type, DW.FORM.ref4 |
| 271 | | var index = dbg_info_buffer.items.len; |
| 272 | | try dbg_info_buffer.ensureUnusedCapacity(9); |
| 273 | | dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); |
| 274 | | try self.addTypeRelocGlobal(atom_index, ty.childType(zcu), @intCast(index)); |
| 275 | | // DW.AT.subrange_type |
| 276 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.array_dim)); |
| 277 | | // DW.AT.type, DW.FORM.ref4 |
| 278 | | index = dbg_info_buffer.items.len; |
| 279 | | dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); |
| 280 | | try self.addTypeRelocGlobal(atom_index, Type.usize, @intCast(index)); |
| 281 | | // DW.AT.count, DW.FORM.udata |
| 282 | | const len = ty.arrayLenIncludingSentinel(pt.zcu); |
| 283 | | try leb128.writeUleb128(dbg_info_buffer.writer(), len); |
| 284 | | // DW.AT.array_type delimit children |
| 285 | | try dbg_info_buffer.append(0); |
| 286 | | }, |
| 287 | | .Struct => { |
| 288 | | // DW.AT.structure_type |
| 289 | | try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_type)); |
| 290 | | // DW.AT.byte_size, DW.FORM.udata |
| 291 | | try leb128.writeUleb128(dbg_info_buffer.writer(), ty.abiSize(pt)); |
| 292 | | |
| 293 | | blk: { |
| 294 | | switch (ip.indexToKey(ty.ip_index)) { |
| 295 | | .anon_struct_type => |fields| { |
| 296 | | // DW.AT.name, DW.FORM.string |
| 297 | | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(pt)}); |
| 298 | | |
| 299 | | for (fields.types.get(ip), 0..) |field_ty, field_index| { |
| 300 | | // DW.AT.member |
| 301 | | try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_member)); |
| 302 | | // DW.AT.name, DW.FORM.string |
| 303 | | try dbg_info_buffer.writer().print("{d}\x00", .{field_index}); |
| 304 | | // DW.AT.type, DW.FORM.ref4 |
| 305 | | const index = dbg_info_buffer.items.len; |
| 306 | | try dbg_info_buffer.appendNTimes(0, 4); |
| 307 | | try self.addTypeRelocGlobal(atom_index, Type.fromInterned(field_ty), @intCast(index)); |
| 308 | | // DW.AT.data_member_location, DW.FORM.udata |
| 309 | | const field_off = ty.structFieldOffset(field_index, pt); |
| 310 | | try leb128.writeUleb128(dbg_info_buffer.writer(), field_off); |
| 311 | | } |
| 312 | | }, |
| 313 | | .struct_type => { |
| 314 | | const struct_type = ip.loadStructType(ty.toIntern()); |
| 315 | | // DW.AT.name, DW.FORM.string |
| 316 | | try ty.print(dbg_info_buffer.writer(), pt); |
| 317 | | try dbg_info_buffer.append(0); |
| 318 | | |
| 319 | | if (struct_type.layout == .@"packed") { |
| 320 | | log.debug("TODO implement .debug_info for packed structs", .{}); |
| 321 | | break :blk; |
| 322 | | } |
| 79 | fn headerBytes(dwarf: *Dwarf) u32 { |
| 80 | return dwarf.unitLengthBytes() + 2 + 1 + 1 + dwarf.sectionOffsetBytes() + |
| 81 | uleb128Bytes(@intFromEnum(AbbrevCode.compile_unit)) + 1 + dwarf.sectionOffsetBytes() * 6 + uleb128Bytes(0) + |
| 82 | uleb128Bytes(@intFromEnum(AbbrevCode.module)) + dwarf.sectionOffsetBytes() + uleb128Bytes(0); |
| 83 | } |
| 323 | 84 | |
| 324 | | if (struct_type.isTuple(ip)) { |
| 325 | | for (struct_type.field_types.get(ip), struct_type.offsets.get(ip), 0..) |field_ty, field_off, field_index| { |
| 326 | | if (!Type.fromInterned(field_ty).hasRuntimeBits(pt)) continue; |
| 327 | | // DW.AT.member |
| 328 | | try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_member)); |
| 329 | | // DW.AT.name, DW.FORM.string |
| 330 | | try dbg_info_buffer.writer().print("{d}\x00", .{field_index}); |
| 331 | | // DW.AT.type, DW.FORM.ref4 |
| 332 | | const index = dbg_info_buffer.items.len; |
| 333 | | try dbg_info_buffer.appendNTimes(0, 4); |
| 334 | | try self.addTypeRelocGlobal(atom_index, Type.fromInterned(field_ty), @intCast(index)); |
| 335 | | // DW.AT.data_member_location, DW.FORM.udata |
| 336 | | try leb128.writeUleb128(dbg_info_buffer.writer(), field_off); |
| 337 | | } |
| 338 | | } else { |
| 339 | | for ( |
| 340 | | struct_type.field_names.get(ip), |
| 341 | | struct_type.field_types.get(ip), |
| 342 | | struct_type.offsets.get(ip), |
| 343 | | ) |field_name, field_ty, field_off| { |
| 344 | | if (!Type.fromInterned(field_ty).hasRuntimeBits(pt)) continue; |
| 345 | | const field_name_slice = field_name.toSlice(ip); |
| 346 | | // DW.AT.member |
| 347 | | try dbg_info_buffer.ensureUnusedCapacity(field_name_slice.len + 2); |
| 348 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member)); |
| 349 | | // DW.AT.name, DW.FORM.string |
| 350 | | dbg_info_buffer.appendSliceAssumeCapacity(field_name_slice[0 .. field_name_slice.len + 1]); |
| 351 | | // DW.AT.type, DW.FORM.ref4 |
| 352 | | const index = dbg_info_buffer.items.len; |
| 353 | | try dbg_info_buffer.appendNTimes(0, 4); |
| 354 | | try self.addTypeRelocGlobal(atom_index, Type.fromInterned(field_ty), @intCast(index)); |
| 355 | | // DW.AT.data_member_location, DW.FORM.udata |
| 356 | | try leb128.writeUleb128(dbg_info_buffer.writer(), field_off); |
| 357 | | } |
| 358 | | } |
| 359 | | }, |
| 360 | | else => unreachable, |
| 361 | | } |
| 362 | | } |
| 85 | fn declEntryLineOff(dwarf: *Dwarf) u32 { |
| 86 | return AbbrevCode.decl_bytes + dwarf.sectionOffsetBytes(); |
| 87 | } |
| 363 | 88 | |
| 364 | | // DW.AT.structure_type delimit children |
| 365 | | try dbg_info_buffer.append(0); |
| 366 | | }, |
| 367 | | .Enum => { |
| 368 | | // DW.AT.enumeration_type |
| 369 | | try dbg_info_buffer.append(@intFromEnum(AbbrevCode.enum_type)); |
| 370 | | // DW.AT.byte_size, DW.FORM.udata |
| 371 | | try leb128.writeUleb128(dbg_info_buffer.writer(), ty.abiSize(pt)); |
| 372 | | // DW.AT.name, DW.FORM.string |
| 373 | | try ty.print(dbg_info_buffer.writer(), pt); |
| 374 | | try dbg_info_buffer.append(0); |
| 375 | | |
| 376 | | const enum_type = ip.loadEnumType(ty.ip_index); |
| 377 | | for (enum_type.names.get(ip), 0..) |field_name, field_i| { |
| 378 | | const field_name_slice = field_name.toSlice(ip); |
| 379 | | // DW.AT.enumerator |
| 380 | | try dbg_info_buffer.ensureUnusedCapacity(field_name_slice.len + 2 + @sizeOf(u64)); |
| 381 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.enum_variant)); |
| 382 | | // DW.AT.name, DW.FORM.string |
| 383 | | dbg_info_buffer.appendSliceAssumeCapacity(field_name_slice[0 .. field_name_slice.len + 1]); |
| 384 | | // DW.AT.const_value, DW.FORM.data8 |
| 385 | | const value: u64 = value: { |
| 386 | | if (enum_type.values.len == 0) break :value field_i; // auto-numbered |
| 387 | | const value = enum_type.values.get(ip)[field_i]; |
| 388 | | // TODO do not assume a 64bit enum value - could be bigger. |
| 389 | | // See https://github.com/ziglang/zig/issues/645 |
| 390 | | const field_int_val = try Value.fromInterned(value).intFromEnum(ty, pt); |
| 391 | | break :value @bitCast(field_int_val.toSignedInt(pt)); |
| 392 | | }; |
| 393 | | mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian); |
| 394 | | } |
| 89 | const trailer_bytes = 1 + 1; |
| 90 | }; |
| 395 | 91 | |
| 396 | | // DW.AT.enumeration_type delimit children |
| 397 | | try dbg_info_buffer.append(0); |
| 398 | | }, |
| 399 | | .Union => { |
| 400 | | const union_obj = zcu.typeToUnion(ty).?; |
| 401 | | const layout = pt.getUnionLayout(union_obj); |
| 402 | | const payload_offset = if (layout.tag_align.compare(.gte, layout.payload_align)) layout.tag_size else 0; |
| 403 | | const tag_offset = if (layout.tag_align.compare(.gte, layout.payload_align)) 0 else layout.payload_size; |
| 404 | | // TODO this is temporary to match current state of unions in Zig - we don't yet have |
| 405 | | // safety checks implemented meaning the implicit tag is not yet stored and generated |
| 406 | | // for untagged unions. |
| 407 | | const is_tagged = layout.tag_size > 0; |
| 408 | | if (is_tagged) { |
| 409 | | // DW.AT.structure_type |
| 410 | | try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_type)); |
| 411 | | // DW.AT.byte_size, DW.FORM.udata |
| 412 | | try leb128.writeUleb128(dbg_info_buffer.writer(), layout.abi_size); |
| 413 | | // DW.AT.name, DW.FORM.string |
| 414 | | try ty.print(dbg_info_buffer.writer(), pt); |
| 415 | | try dbg_info_buffer.append(0); |
| 416 | | |
| 417 | | // DW.AT.member |
| 418 | | try dbg_info_buffer.ensureUnusedCapacity(13); |
| 419 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member)); |
| 420 | | // DW.AT.name, DW.FORM.string |
| 421 | | dbg_info_buffer.appendSliceAssumeCapacity("payload"); |
| 422 | | dbg_info_buffer.appendAssumeCapacity(0); |
| 423 | | // DW.AT.type, DW.FORM.ref4 |
| 424 | | const inner_union_index = dbg_info_buffer.items.len; |
| 425 | | dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); |
| 426 | | try self.addTypeRelocLocal(atom_index, @intCast(inner_union_index), 5); |
| 427 | | // DW.AT.data_member_location, DW.FORM.udata |
| 428 | | try leb128.writeUleb128(dbg_info_buffer.writer(), payload_offset); |
| 429 | | } |
| 92 | const DebugLine = struct { |
| 93 | header: Header, |
| 94 | section: Section, |
| 95 | |
| 96 | const Header = struct { |
| 97 | minimum_instruction_length: u8, |
| 98 | maximum_operations_per_instruction: u8, |
| 99 | default_is_stmt: bool, |
| 100 | line_base: i8, |
| 101 | line_range: u8, |
| 102 | opcode_base: u8, |
| 103 | }; |
| 430 | 104 | |
| 431 | | // DW.AT.union_type |
| 432 | | try dbg_info_buffer.append(@intFromEnum(AbbrevCode.union_type)); |
| 433 | | // DW.AT.byte_size, DW.FORM.udata, |
| 434 | | try leb128.writeUleb128(dbg_info_buffer.writer(), layout.payload_size); |
| 435 | | // DW.AT.name, DW.FORM.string |
| 436 | | if (is_tagged) { |
| 437 | | try dbg_info_buffer.writer().print("AnonUnion\x00", .{}); |
| 438 | | } else { |
| 439 | | try ty.print(dbg_info_buffer.writer(), pt); |
| 440 | | try dbg_info_buffer.append(0); |
| 441 | | } |
| 105 | fn dirIndexInfo(dir_count: u32) struct { bytes: u8, form: DeclValEnum(DW.FORM) } { |
| 106 | return if (dir_count <= 1 << 8) |
| 107 | .{ .bytes = 1, .form = .data1 } |
| 108 | else if (dir_count <= 1 << 16) |
| 109 | .{ .bytes = 2, .form = .data2 } |
| 110 | else |
| 111 | unreachable; |
| 112 | } |
| 442 | 113 | |
| 443 | | for (union_obj.field_types.get(ip), union_obj.loadTagType(ip).names.get(ip)) |field_ty, field_name| { |
| 444 | | if (!Type.fromInterned(field_ty).hasRuntimeBits(pt)) continue; |
| 445 | | const field_name_slice = field_name.toSlice(ip); |
| 446 | | // DW.AT.member |
| 447 | | try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_member)); |
| 448 | | // DW.AT.name, DW.FORM.string |
| 449 | | try dbg_info_buffer.appendSlice(field_name_slice[0 .. field_name_slice.len + 1]); |
| 450 | | // DW.AT.type, DW.FORM.ref4 |
| 451 | | const index = dbg_info_buffer.items.len; |
| 452 | | try dbg_info_buffer.appendNTimes(0, 4); |
| 453 | | try self.addTypeRelocGlobal(atom_index, Type.fromInterned(field_ty), @intCast(index)); |
| 454 | | // DW.AT.data_member_location, DW.FORM.udata |
| 455 | | try dbg_info_buffer.append(0); |
| 456 | | } |
| 457 | | // DW.AT.union_type delimit children |
| 458 | | try dbg_info_buffer.append(0); |
| 459 | | |
| 460 | | if (is_tagged) { |
| 461 | | // DW.AT.member |
| 462 | | try dbg_info_buffer.ensureUnusedCapacity(9); |
| 463 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member)); |
| 464 | | // DW.AT.name, DW.FORM.string |
| 465 | | dbg_info_buffer.appendSliceAssumeCapacity("tag"); |
| 466 | | dbg_info_buffer.appendAssumeCapacity(0); |
| 467 | | // DW.AT.type, DW.FORM.ref4 |
| 468 | | const index = dbg_info_buffer.items.len; |
| 469 | | dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); |
| 470 | | try self.addTypeRelocGlobal(atom_index, Type.fromInterned(union_obj.enum_tag_ty), @intCast(index)); |
| 471 | | // DW.AT.data_member_location, DW.FORM.udata |
| 472 | | try leb128.writeUleb128(dbg_info_buffer.writer(), tag_offset); |
| 473 | | |
| 474 | | // DW.AT.structure_type delimit children |
| 475 | | try dbg_info_buffer.append(0); |
| 476 | | } |
| 477 | | }, |
| 478 | | .ErrorSet => try addDbgInfoErrorSet(pt, ty, target, &self.dbg_info), |
| 479 | | .ErrorUnion => { |
| 480 | | const error_ty = ty.errorUnionSet(zcu); |
| 481 | | const payload_ty = ty.errorUnionPayload(zcu); |
| 482 | | const payload_align = if (payload_ty.isNoReturn(zcu)) .none else payload_ty.abiAlignment(pt); |
| 483 | | const error_align = Type.anyerror.abiAlignment(pt); |
| 484 | | const abi_size = ty.abiSize(pt); |
| 485 | | const payload_off = if (error_align.compare(.gte, payload_align)) Type.anyerror.abiSize(pt) else 0; |
| 486 | | const error_off = if (error_align.compare(.gte, payload_align)) 0 else payload_ty.abiSize(pt); |
| 487 | | |
| 488 | | // DW.AT.structure_type |
| 489 | | try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_type)); |
| 490 | | // DW.AT.byte_size, DW.FORM.udata |
| 491 | | try leb128.writeUleb128(dbg_info_buffer.writer(), abi_size); |
| 492 | | // DW.AT.name, DW.FORM.string |
| 493 | | try ty.print(dbg_info_buffer.writer(), pt); |
| 494 | | try dbg_info_buffer.append(0); |
| 495 | | |
| 496 | | if (!payload_ty.isNoReturn(zcu)) { |
| 497 | | // DW.AT.member |
| 498 | | try dbg_info_buffer.ensureUnusedCapacity(11); |
| 499 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member)); |
| 500 | | // DW.AT.name, DW.FORM.string |
| 501 | | dbg_info_buffer.appendSliceAssumeCapacity("value"); |
| 502 | | dbg_info_buffer.appendAssumeCapacity(0); |
| 503 | | // DW.AT.type, DW.FORM.ref4 |
| 504 | | const index = dbg_info_buffer.items.len; |
| 505 | | dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); |
| 506 | | try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(index)); |
| 507 | | // DW.AT.data_member_location, DW.FORM.udata |
| 508 | | try leb128.writeUleb128(dbg_info_buffer.writer(), payload_off); |
| 509 | | } |
| 114 | fn headerBytes(dwarf: *Dwarf, dir_count: u32, file_count: u32) u32 { |
| 115 | const dir_index_info = dirIndexInfo(dir_count); |
| 116 | return dwarf.unitLengthBytes() + 2 + 1 + 1 + dwarf.sectionOffsetBytes() + 1 + 1 + 1 + 1 + 1 + 1 + 1 * (dwarf.debug_line.header.opcode_base - 1) + |
| 117 | 1 + uleb128Bytes(DW.LNCT.path) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(dir_count) + (dwarf.sectionOffsetBytes()) * dir_count + |
| 118 | 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; |
| 119 | } |
| 510 | 120 | |
| 511 | | { |
| 512 | | // DW.AT.member |
| 513 | | try dbg_info_buffer.ensureUnusedCapacity(9); |
| 514 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member)); |
| 515 | | // DW.AT.name, DW.FORM.string |
| 516 | | dbg_info_buffer.appendSliceAssumeCapacity("err"); |
| 517 | | dbg_info_buffer.appendAssumeCapacity(0); |
| 518 | | // DW.AT.type, DW.FORM.ref4 |
| 519 | | const index = dbg_info_buffer.items.len; |
| 520 | | dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); |
| 521 | | try self.addTypeRelocGlobal(atom_index, error_ty, @intCast(index)); |
| 522 | | // DW.AT.data_member_location, DW.FORM.udata |
| 523 | | try leb128.writeUleb128(dbg_info_buffer.writer(), error_off); |
| 524 | | } |
| 121 | const trailer_bytes = 1 + uleb128Bytes(0) + |
| 122 | 1 + uleb128Bytes(1) + 1; |
| 123 | }; |
| 525 | 124 | |
| 526 | | // DW.AT.structure_type delimit children |
| 527 | | try dbg_info_buffer.append(0); |
| 528 | | }, |
| 529 | | else => { |
| 530 | | log.debug("TODO implement .debug_info for type '{}'", .{ty.fmt(pt)}); |
| 531 | | try dbg_info_buffer.append(@intFromEnum(AbbrevCode.zero_bit_type)); |
| 532 | | }, |
| 533 | | } |
| 125 | const DebugLocLists = struct { |
| 126 | section: Section, |
| 127 | |
| 128 | fn baseOffset(dwarf: *Dwarf) u32 { |
| 129 | return dwarf.unitLengthBytes() + 2 + 1 + 1 + 4; |
| 534 | 130 | } |
| 535 | 131 | |
| 536 | | pub const DbgInfoLoc = union(enum) { |
| 537 | | register: u8, |
| 538 | | register_pair: [2]u8, |
| 539 | | stack: struct { |
| 540 | | fp_register: u8, |
| 541 | | offset: i32, |
| 542 | | }, |
| 543 | | wasm_local: u32, |
| 544 | | memory: u64, |
| 545 | | linker_load: LinkerLoad, |
| 546 | | immediate: u64, |
| 547 | | undef, |
| 548 | | none, |
| 549 | | nop, |
| 550 | | }; |
| 132 | fn headerBytes(dwarf: *Dwarf) u32 { |
| 133 | return baseOffset(dwarf); |
| 134 | } |
| 551 | 135 | |
| 552 | | pub fn genArgDbgInfo( |
| 553 | | self: *NavState, |
| 554 | | name: [:0]const u8, |
| 555 | | ty: Type, |
| 556 | | owner_nav: InternPool.Nav.Index, |
| 557 | | loc: DbgInfoLoc, |
| 558 | | ) error{OutOfMemory}!void { |
| 559 | | const pt = self.pt; |
| 560 | | const dbg_info = &self.dbg_info; |
| 561 | | const atom_index = self.di_atom_navs.get(owner_nav).?; |
| 562 | | const name_with_null = name.ptr[0 .. name.len + 1]; |
| 136 | const trailer_bytes = 0; |
| 137 | }; |
| 563 | 138 | |
| 564 | | switch (loc) { |
| 565 | | .register => |reg| { |
| 566 | | try dbg_info.ensureUnusedCapacity(4); |
| 567 | | dbg_info.appendAssumeCapacity(@intFromEnum(AbbrevCode.parameter)); |
| 568 | | // DW.AT.location, DW.FORM.exprloc |
| 569 | | var expr_len = std.io.countingWriter(std.io.null_writer); |
| 570 | | if (reg < 32) { |
| 571 | | expr_len.writer().writeByte(DW.OP.reg0 + reg) catch unreachable; |
| 572 | | } else { |
| 573 | | expr_len.writer().writeByte(DW.OP.regx) catch unreachable; |
| 574 | | leb128.writeUleb128(expr_len.writer(), reg) catch unreachable; |
| 575 | | } |
| 576 | | leb128.writeUleb128(dbg_info.writer(), expr_len.bytes_written) catch unreachable; |
| 577 | | if (reg < 32) { |
| 578 | | dbg_info.appendAssumeCapacity(DW.OP.reg0 + reg); |
| 579 | | } else { |
| 580 | | dbg_info.appendAssumeCapacity(DW.OP.regx); |
| 581 | | leb128.writeUleb128(dbg_info.writer(), reg) catch unreachable; |
| 582 | | } |
| 583 | | }, |
| 584 | | .register_pair => |regs| { |
| 585 | | const reg_bits = pt.zcu.getTarget().ptrBitWidth(); |
| 586 | | const reg_bytes: u8 = @intCast(@divExact(reg_bits, 8)); |
| 587 | | const abi_size = ty.abiSize(pt); |
| 588 | | try dbg_info.ensureUnusedCapacity(10); |
| 589 | | dbg_info.appendAssumeCapacity(@intFromEnum(AbbrevCode.parameter)); |
| 590 | | // DW.AT.location, DW.FORM.exprloc |
| 591 | | var expr_len = std.io.countingWriter(std.io.null_writer); |
| 592 | | for (regs, 0..) |reg, reg_i| { |
| 593 | | if (reg < 32) { |
| 594 | | expr_len.writer().writeByte(DW.OP.reg0 + reg) catch unreachable; |
| 595 | | } else { |
| 596 | | expr_len.writer().writeByte(DW.OP.regx) catch unreachable; |
| 597 | | leb128.writeUleb128(expr_len.writer(), reg) catch unreachable; |
| 598 | | } |
| 599 | | expr_len.writer().writeByte(DW.OP.piece) catch unreachable; |
| 600 | | leb128.writeUleb128( |
| 601 | | expr_len.writer(), |
| 602 | | @min(abi_size - reg_i * reg_bytes, reg_bytes), |
| 603 | | ) catch unreachable; |
| 604 | | } |
| 605 | | leb128.writeUleb128(dbg_info.writer(), expr_len.bytes_written) catch unreachable; |
| 606 | | for (regs, 0..) |reg, reg_i| { |
| 607 | | if (reg < 32) { |
| 608 | | dbg_info.appendAssumeCapacity(DW.OP.reg0 + reg); |
| 609 | | } else { |
| 610 | | dbg_info.appendAssumeCapacity(DW.OP.regx); |
| 611 | | leb128.writeUleb128(dbg_info.writer(), reg) catch unreachable; |
| 612 | | } |
| 613 | | dbg_info.appendAssumeCapacity(DW.OP.piece); |
| 614 | | leb128.writeUleb128( |
| 615 | | dbg_info.writer(), |
| 616 | | @min(abi_size - reg_i * reg_bytes, reg_bytes), |
| 617 | | ) catch unreachable; |
| 618 | | } |
| 619 | | }, |
| 620 | | .stack => |info| { |
| 621 | | try dbg_info.ensureUnusedCapacity(9); |
| 622 | | dbg_info.appendAssumeCapacity(@intFromEnum(AbbrevCode.parameter)); |
| 623 | | // DW.AT.location, DW.FORM.exprloc |
| 624 | | var expr_len = std.io.countingWriter(std.io.null_writer); |
| 625 | | if (info.fp_register < 32) { |
| 626 | | expr_len.writer().writeByte(DW.OP.breg0 + info.fp_register) catch unreachable; |
| 627 | | } else { |
| 628 | | expr_len.writer().writeByte(DW.OP.bregx) catch unreachable; |
| 629 | | leb128.writeUleb128(expr_len.writer(), info.fp_register) catch unreachable; |
| 630 | | } |
| 631 | | leb128.writeIleb128(expr_len.writer(), info.offset) catch unreachable; |
| 632 | | leb128.writeUleb128(dbg_info.writer(), expr_len.bytes_written) catch unreachable; |
| 633 | | if (info.fp_register < 32) { |
| 634 | | dbg_info.appendAssumeCapacity(DW.OP.breg0 + info.fp_register); |
| 635 | | } else { |
| 636 | | dbg_info.appendAssumeCapacity(DW.OP.bregx); |
| 637 | | leb128.writeUleb128(dbg_info.writer(), info.fp_register) catch unreachable; |
| 638 | | } |
| 639 | | leb128.writeIleb128(dbg_info.writer(), info.offset) catch unreachable; |
| 640 | | }, |
| 641 | | .wasm_local => |value| { |
| 642 | | @import("../dev.zig").check(.wasm_linker); |
| 643 | | const leb_size = link.File.Wasm.getUleb128Size(value); |
| 644 | | try dbg_info.ensureUnusedCapacity(3 + leb_size); |
| 645 | | // wasm locations are encoded as follow: |
| 646 | | // DW_OP_WASM_location wasm-op |
| 647 | | // where wasm-op is defined as |
| 648 | | // wasm-op := wasm-local | wasm-global | wasm-operand_stack |
| 649 | | // where each argument is encoded as |
| 650 | | // <opcode> i:uleb128 |
| 651 | | dbg_info.appendSliceAssumeCapacity(&.{ |
| 652 | | @intFromEnum(AbbrevCode.parameter), |
| 653 | | DW.OP.WASM_location, |
| 654 | | DW.OP.WASM_local, |
| 655 | | }); |
| 656 | | leb128.writeUleb128(dbg_info.writer(), value) catch unreachable; |
| 657 | | }, |
| 658 | | else => unreachable, |
| 659 | | } |
| 139 | const DebugRngLists = struct { |
| 140 | section: Section, |
| 660 | 141 | |
| 661 | | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); |
| 662 | | const index = dbg_info.items.len; |
| 663 | | dbg_info.appendNTimesAssumeCapacity(0, 4); |
| 664 | | try self.addTypeRelocGlobal(atom_index, ty, @intCast(index)); // DW.AT.type, DW.FORM.ref4 |
| 665 | | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string |
| 666 | | } |
| 142 | const baseOffset = DebugLocLists.baseOffset; |
| 667 | 143 | |
| 668 | | pub fn genVarDbgInfo( |
| 669 | | self: *NavState, |
| 670 | | name: [:0]const u8, |
| 671 | | ty: Type, |
| 672 | | owner_nav: InternPool.Nav.Index, |
| 673 | | is_ptr: bool, |
| 674 | | loc: DbgInfoLoc, |
| 675 | | ) error{OutOfMemory}!void { |
| 676 | | const dbg_info = &self.dbg_info; |
| 677 | | const atom_index = self.di_atom_navs.get(owner_nav).?; |
| 678 | | const name_with_null = name.ptr[0 .. name.len + 1]; |
| 679 | | try dbg_info.append(@intFromEnum(AbbrevCode.variable)); |
| 680 | | const gpa = self.dwarf.allocator; |
| 681 | | const pt = self.pt; |
| 682 | | const target = pt.zcu.getTarget(); |
| 683 | | const endian = target.cpu.arch.endian(); |
| 684 | | const child_ty = if (is_ptr) ty.childType(pt.zcu) else ty; |
| 144 | fn headerBytes(dwarf: *Dwarf) u32 { |
| 145 | return baseOffset(dwarf) + dwarf.sectionOffsetBytes() * 1; |
| 146 | } |
| 685 | 147 | |
| 686 | | switch (loc) { |
| 687 | | .register => |reg| { |
| 688 | | try dbg_info.ensureUnusedCapacity(3); |
| 689 | | // DW.AT.location, DW.FORM.exprloc |
| 690 | | var expr_len = std.io.countingWriter(std.io.null_writer); |
| 691 | | if (reg < 32) { |
| 692 | | expr_len.writer().writeByte(DW.OP.reg0 + reg) catch unreachable; |
| 693 | | } else { |
| 694 | | expr_len.writer().writeByte(DW.OP.regx) catch unreachable; |
| 695 | | leb128.writeUleb128(expr_len.writer(), reg) catch unreachable; |
| 696 | | } |
| 697 | | leb128.writeUleb128(dbg_info.writer(), expr_len.bytes_written) catch unreachable; |
| 698 | | if (reg < 32) { |
| 699 | | dbg_info.appendAssumeCapacity(DW.OP.reg0 + reg); |
| 700 | | } else { |
| 701 | | dbg_info.appendAssumeCapacity(DW.OP.regx); |
| 702 | | leb128.writeUleb128(dbg_info.writer(), reg) catch unreachable; |
| 703 | | } |
| 704 | | }, |
| 148 | const trailer_bytes = 1; |
| 149 | }; |
| 705 | 150 | |
| 706 | | .register_pair => |regs| { |
| 707 | | const reg_bits = pt.zcu.getTarget().ptrBitWidth(); |
| 708 | | const reg_bytes: u8 = @intCast(@divExact(reg_bits, 8)); |
| 709 | | const abi_size = child_ty.abiSize(pt); |
| 710 | | try dbg_info.ensureUnusedCapacity(9); |
| 711 | | // DW.AT.location, DW.FORM.exprloc |
| 712 | | var expr_len = std.io.countingWriter(std.io.null_writer); |
| 713 | | for (regs, 0..) |reg, reg_i| { |
| 714 | | if (reg < 32) { |
| 715 | | expr_len.writer().writeByte(DW.OP.reg0 + reg) catch unreachable; |
| 716 | | } else { |
| 717 | | expr_len.writer().writeByte(DW.OP.regx) catch unreachable; |
| 718 | | leb128.writeUleb128(expr_len.writer(), reg) catch unreachable; |
| 719 | | } |
| 720 | | expr_len.writer().writeByte(DW.OP.piece) catch unreachable; |
| 721 | | leb128.writeUleb128( |
| 722 | | expr_len.writer(), |
| 723 | | @min(abi_size - reg_i * reg_bytes, reg_bytes), |
| 724 | | ) catch unreachable; |
| 725 | | } |
| 726 | | leb128.writeUleb128(dbg_info.writer(), expr_len.bytes_written) catch unreachable; |
| 727 | | for (regs, 0..) |reg, reg_i| { |
| 728 | | if (reg < 32) { |
| 729 | | dbg_info.appendAssumeCapacity(DW.OP.reg0 + reg); |
| 730 | | } else { |
| 731 | | dbg_info.appendAssumeCapacity(DW.OP.regx); |
| 732 | | leb128.writeUleb128(dbg_info.writer(), reg) catch unreachable; |
| 733 | | } |
| 734 | | dbg_info.appendAssumeCapacity(DW.OP.piece); |
| 735 | | leb128.writeUleb128( |
| 736 | | dbg_info.writer(), |
| 737 | | @min(abi_size - reg_i * reg_bytes, reg_bytes), |
| 738 | | ) catch unreachable; |
| 739 | | } |
| 740 | | }, |
| 151 | const StringSection = struct { |
| 152 | contents: std.ArrayListUnmanaged(u8), |
| 153 | map: std.AutoArrayHashMapUnmanaged(void, void), |
| 154 | section: Section, |
| 741 | 155 | |
| 742 | | .stack => |info| { |
| 743 | | try dbg_info.ensureUnusedCapacity(9); |
| 744 | | // DW.AT.location, DW.FORM.exprloc |
| 745 | | var expr_len = std.io.countingWriter(std.io.null_writer); |
| 746 | | if (info.fp_register < 32) { |
| 747 | | expr_len.writer().writeByte(DW.OP.breg0 + info.fp_register) catch unreachable; |
| 748 | | } else { |
| 749 | | expr_len.writer().writeByte(DW.OP.bregx) catch unreachable; |
| 750 | | leb128.writeUleb128(expr_len.writer(), info.fp_register) catch unreachable; |
| 751 | | } |
| 752 | | leb128.writeIleb128(expr_len.writer(), info.offset) catch unreachable; |
| 753 | | leb128.writeUleb128(dbg_info.writer(), expr_len.bytes_written) catch unreachable; |
| 754 | | if (info.fp_register < 32) { |
| 755 | | dbg_info.appendAssumeCapacity(DW.OP.breg0 + info.fp_register); |
| 756 | | } else { |
| 757 | | dbg_info.appendAssumeCapacity(DW.OP.bregx); |
| 758 | | leb128.writeUleb128(dbg_info.writer(), info.fp_register) catch unreachable; |
| 759 | | } |
| 760 | | leb128.writeIleb128(dbg_info.writer(), info.offset) catch unreachable; |
| 761 | | }, |
| 762 | | |
| 763 | | .wasm_local => |value| { |
| 764 | | const leb_size = link.File.Wasm.getUleb128Size(value); |
| 765 | | try dbg_info.ensureUnusedCapacity(2 + leb_size); |
| 766 | | // wasm locals are encoded as follow: |
| 767 | | // DW_OP_WASM_location wasm-op |
| 768 | | // where wasm-op is defined as |
| 769 | | // wasm-op := wasm-local | wasm-global | wasm-operand_stack |
| 770 | | // where wasm-local is encoded as |
| 771 | | // wasm-local := 0x00 i:uleb128 |
| 772 | | dbg_info.appendSliceAssumeCapacity(&.{ |
| 773 | | DW.OP.WASM_location, |
| 774 | | DW.OP.WASM_local, |
| 775 | | }); |
| 776 | | leb128.writeUleb128(dbg_info.writer(), value) catch unreachable; |
| 777 | | }, |
| 156 | const unit: Unit.Index = @enumFromInt(0); |
| 778 | 157 | |
| 779 | | .memory, |
| 780 | | .linker_load, |
| 781 | | => { |
| 782 | | const ptr_width: u8 = @intCast(@divExact(target.ptrBitWidth(), 8)); |
| 783 | | try dbg_info.ensureUnusedCapacity(2 + ptr_width); |
| 784 | | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc |
| 785 | | 1 + ptr_width + @intFromBool(is_ptr), |
| 786 | | DW.OP.addr, // literal address |
| 787 | | }); |
| 788 | | const offset: u32 = @intCast(dbg_info.items.len); |
| 789 | | const addr = switch (loc) { |
| 790 | | .memory => |x| x, |
| 791 | | else => 0, |
| 792 | | }; |
| 793 | | switch (ptr_width) { |
| 794 | | 0...4 => { |
| 795 | | try dbg_info.writer().writeInt(u32, @intCast(addr), endian); |
| 796 | | }, |
| 797 | | 5...8 => { |
| 798 | | try dbg_info.writer().writeInt(u64, addr, endian); |
| 799 | | }, |
| 800 | | else => unreachable, |
| 801 | | } |
| 802 | | if (is_ptr) { |
| 803 | | // We need deref the address as we point to the value via GOT entry. |
| 804 | | try dbg_info.append(DW.OP.deref); |
| 805 | | } |
| 806 | | switch (loc) { |
| 807 | | .linker_load => |load_struct| switch (load_struct.type) { |
| 808 | | .direct => { |
| 809 | | log.debug("{x}: target sym %{d}", .{ offset, load_struct.sym_index }); |
| 810 | | try self.exprloc_relocs.append(gpa, .{ |
| 811 | | .type = .direct_load, |
| 812 | | .target = load_struct.sym_index, |
| 813 | | .offset = offset, |
| 814 | | }); |
| 815 | | }, |
| 816 | | .got => { |
| 817 | | log.debug("{x}: target sym %{d} via GOT", .{ offset, load_struct.sym_index }); |
| 818 | | try self.exprloc_relocs.append(gpa, .{ |
| 819 | | .type = .got_load, |
| 820 | | .target = load_struct.sym_index, |
| 821 | | .offset = offset, |
| 822 | | }); |
| 823 | | }, |
| 824 | | else => {}, // TODO |
| 825 | | }, |
| 826 | | else => {}, |
| 827 | | } |
| 828 | | }, |
| 158 | const init: StringSection = .{ |
| 159 | .contents = .{}, |
| 160 | .map = .{}, |
| 161 | .section = Section.init, |
| 162 | }; |
| 829 | 163 | |
| 830 | | .immediate => |x| { |
| 831 | | try dbg_info.ensureUnusedCapacity(2); |
| 832 | | const fixup = dbg_info.items.len; |
| 833 | | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc |
| 834 | | 1, |
| 835 | | if (child_ty.isSignedInt(pt.zcu)) DW.OP.consts else DW.OP.constu, |
| 836 | | }); |
| 837 | | if (child_ty.isSignedInt(pt.zcu)) { |
| 838 | | try leb128.writeIleb128(dbg_info.writer(), @as(i64, @bitCast(x))); |
| 839 | | } else { |
| 840 | | try leb128.writeUleb128(dbg_info.writer(), x); |
| 841 | | } |
| 842 | | try dbg_info.append(DW.OP.stack_value); |
| 843 | | dbg_info.items[fixup] += @intCast(dbg_info.items.len - fixup - 2); |
| 844 | | }, |
| 845 | | |
| 846 | | .undef => { |
| 847 | | // DW.AT.location, DW.FORM.exprloc |
| 848 | | // uleb128(exprloc_len) |
| 849 | | // DW.OP.implicit_value uleb128(len_of_bytes) bytes |
| 850 | | const abi_size: u32 = @intCast(child_ty.abiSize(self.pt)); |
| 851 | | var implicit_value_len = std.ArrayList(u8).init(gpa); |
| 852 | | defer implicit_value_len.deinit(); |
| 853 | | try leb128.writeUleb128(implicit_value_len.writer(), abi_size); |
| 854 | | const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size; |
| 855 | | try leb128.writeUleb128(dbg_info.writer(), total_exprloc_len); |
| 856 | | try dbg_info.ensureUnusedCapacity(total_exprloc_len); |
| 857 | | dbg_info.appendAssumeCapacity(DW.OP.implicit_value); |
| 858 | | dbg_info.appendSliceAssumeCapacity(implicit_value_len.items); |
| 859 | | dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size); |
| 860 | | }, |
| 861 | | |
| 862 | | .none => { |
| 863 | | try dbg_info.ensureUnusedCapacity(3); |
| 864 | | dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc |
| 865 | | 2, DW.OP.lit0, DW.OP.stack_value, |
| 866 | | }); |
| 867 | | }, |
| 164 | fn deinit(str_sec: *StringSection, gpa: std.mem.Allocator) void { |
| 165 | str_sec.contents.deinit(gpa); |
| 166 | str_sec.map.deinit(gpa); |
| 167 | str_sec.section.deinit(gpa); |
| 168 | } |
| 868 | 169 | |
| 869 | | .nop => { |
| 870 | | try dbg_info.ensureUnusedCapacity(2); |
| 871 | | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc |
| 872 | | 1, DW.OP.nop, |
| 873 | | }); |
| 874 | | }, |
| 170 | fn addString(str_sec: *StringSection, dwarf: *Dwarf, str: []const u8) UpdateError!Entry.Index { |
| 171 | const gop = try str_sec.map.getOrPutAdapted(dwarf.gpa, str, Adapter{ .str_sec = str_sec }); |
| 172 | errdefer _ = str_sec.map.pop(); |
| 173 | const entry: Entry.Index = @enumFromInt(gop.index); |
| 174 | if (!gop.found_existing) { |
| 175 | assert(try str_sec.section.addEntry(unit, dwarf) == entry); |
| 176 | errdefer _ = str_sec.section.getUnit(unit).entries.pop(); |
| 177 | const entry_ptr = str_sec.section.getUnit(unit).getEntry(entry); |
| 178 | assert(entry_ptr.off == str_sec.contents.items.len); |
| 179 | entry_ptr.len = @intCast(str.len + 1); |
| 180 | try str_sec.contents.ensureUnusedCapacity(dwarf.gpa, str.len + 1); |
| 181 | str_sec.contents.appendSliceAssumeCapacity(str); |
| 182 | str_sec.contents.appendAssumeCapacity(0); |
| 183 | str_sec.section.dirty = true; |
| 875 | 184 | } |
| 876 | | |
| 877 | | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); |
| 878 | | const index = dbg_info.items.len; |
| 879 | | dbg_info.appendNTimesAssumeCapacity(0, 4); // dw.at.type, dw.form.ref4 |
| 880 | | try self.addTypeRelocGlobal(atom_index, child_ty, @intCast(index)); |
| 881 | | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string |
| 185 | return entry; |
| 882 | 186 | } |
| 883 | 187 | |
| 884 | | pub fn advancePCAndLine( |
| 885 | | self: *NavState, |
| 886 | | delta_line: i33, |
| 887 | | delta_pc: u64, |
| 888 | | ) error{OutOfMemory}!void { |
| 889 | | const dbg_line = &self.dbg_line; |
| 890 | | try dbg_line.ensureUnusedCapacity(5 + 5 + 1); |
| 188 | const Adapter = struct { |
| 189 | str_sec: *StringSection, |
| 891 | 190 | |
| 892 | | const header = self.dwarf.dbg_line_header; |
| 893 | | assert(header.maximum_operations_per_instruction == 1); |
| 894 | | const delta_op: u64 = 0; |
| 191 | pub fn hash(_: Adapter, key: []const u8) u32 { |
| 192 | return @truncate(std.hash.Wyhash.hash(0, key)); |
| 193 | } |
| 895 | 194 | |
| 896 | | const remaining_delta_line: i9 = @intCast(if (delta_line < header.line_base or |
| 897 | | delta_line - header.line_base >= header.line_range) |
| 898 | | remaining: { |
| 899 | | assert(delta_line != 0); |
| 900 | | dbg_line.appendAssumeCapacity(DW.LNS.advance_line); |
| 901 | | leb128.writeIleb128(dbg_line.writer(), delta_line) catch unreachable; |
| 902 | | break :remaining 0; |
| 903 | | } else delta_line); |
| 195 | pub fn eql(adapter: Adapter, key: []const u8, _: void, rhs_index: usize) bool { |
| 196 | const entry = adapter.str_sec.section.getUnit(unit).getEntry(@enumFromInt(rhs_index)); |
| 197 | return std.mem.eql(u8, key, adapter.str_sec.contents.items[entry.off..][0 .. entry.len - 1 :0]); |
| 198 | } |
| 199 | }; |
| 200 | }; |
| 904 | 201 | |
| 905 | | const op_advance = @divExact(delta_pc, header.minimum_instruction_length) * |
| 906 | | header.maximum_operations_per_instruction + delta_op; |
| 907 | | const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range; |
| 908 | | const remaining_op_advance: u8 = @intCast(if (op_advance >= 2 * max_op_advance) remaining: { |
| 909 | | dbg_line.appendAssumeCapacity(DW.LNS.advance_pc); |
| 910 | | leb128.writeUleb128(dbg_line.writer(), op_advance) catch unreachable; |
| 911 | | break :remaining 0; |
| 912 | | } else if (op_advance >= max_op_advance) remaining: { |
| 913 | | dbg_line.appendAssumeCapacity(DW.LNS.const_add_pc); |
| 914 | | break :remaining op_advance - max_op_advance; |
| 915 | | } else op_advance); |
| 202 | /// A linker section containing a sequence of `Unit`s. |
| 203 | const Section = struct { |
| 204 | dirty: bool, |
| 205 | pad_to_ideal: bool, |
| 206 | alignment: InternPool.Alignment, |
| 207 | index: u32, |
| 208 | first: Unit.Index.Optional, |
| 209 | last: Unit.Index.Optional, |
| 210 | off: u64, |
| 211 | len: u64, |
| 212 | units: std.ArrayListUnmanaged(Unit), |
| 213 | |
| 214 | const Index = enum { |
| 215 | debug_abbrev, |
| 216 | debug_info, |
| 217 | debug_line, |
| 218 | debug_line_str, |
| 219 | debug_loclists, |
| 220 | debug_rnglists, |
| 221 | debug_str, |
| 222 | }; |
| 916 | 223 | |
| 917 | | if (remaining_delta_line == 0 and remaining_op_advance == 0) { |
| 918 | | dbg_line.appendAssumeCapacity(DW.LNS.copy); |
| 919 | | } else { |
| 920 | | dbg_line.appendAssumeCapacity(@intCast((remaining_delta_line - header.line_base) + |
| 921 | | (header.line_range * remaining_op_advance) + header.opcode_base)); |
| 922 | | } |
| 224 | const init: Section = .{ |
| 225 | .dirty = true, |
| 226 | .pad_to_ideal = true, |
| 227 | .alignment = .@"1", |
| 228 | .index = std.math.maxInt(u32), |
| 229 | .first = .none, |
| 230 | .last = .none, |
| 231 | .off = 0, |
| 232 | .len = 0, |
| 233 | .units = .{}, |
| 234 | }; |
| 235 | |
| 236 | fn deinit(sec: *Section, gpa: std.mem.Allocator) void { |
| 237 | for (sec.units.items) |*unit| unit.deinit(gpa); |
| 238 | sec.units.deinit(gpa); |
| 239 | sec.* = undefined; |
| 923 | 240 | } |
| 924 | 241 | |
| 925 | | pub fn setColumn(self: *NavState, column: u32) error{OutOfMemory}!void { |
| 926 | | try self.dbg_line.ensureUnusedCapacity(1 + 5); |
| 927 | | self.dbg_line.appendAssumeCapacity(DW.LNS.set_column); |
| 928 | | leb128.writeUleb128(self.dbg_line.writer(), column + 1) catch unreachable; |
| 242 | fn addUnit(sec: *Section, header_len: u32, trailer_len: u32, dwarf: *Dwarf) UpdateError!Unit.Index { |
| 243 | const unit: Unit.Index = @enumFromInt(sec.units.items.len); |
| 244 | const unit_ptr = try sec.units.addOne(dwarf.gpa); |
| 245 | errdefer sec.popUnit(); |
| 246 | unit_ptr.* = .{ |
| 247 | .prev = sec.last, |
| 248 | .next = .none, |
| 249 | .first = .none, |
| 250 | .last = .none, |
| 251 | .off = 0, |
| 252 | .header_len = header_len, |
| 253 | .trailer_len = trailer_len, |
| 254 | .len = header_len + trailer_len, |
| 255 | .entries = .{}, |
| 256 | .cross_entry_relocs = .{}, |
| 257 | .cross_unit_relocs = .{}, |
| 258 | .cross_section_relocs = .{}, |
| 259 | .external_relocs = .{}, |
| 260 | }; |
| 261 | if (sec.last.unwrap()) |last_unit| { |
| 262 | const last_unit_ptr = sec.getUnit(last_unit); |
| 263 | last_unit_ptr.next = unit.toOptional(); |
| 264 | unit_ptr.off = last_unit_ptr.off + sec.padToIdeal(last_unit_ptr.len); |
| 265 | } |
| 266 | if (sec.first == .none) |
| 267 | sec.first = unit.toOptional(); |
| 268 | sec.last = unit.toOptional(); |
| 269 | try sec.resize(dwarf, unit_ptr.off + sec.padToIdeal(unit_ptr.len)); |
| 270 | return unit; |
| 929 | 271 | } |
| 930 | 272 | |
| 931 | | pub fn setPrologueEnd(self: *NavState) error{OutOfMemory}!void { |
| 932 | | try self.dbg_line.append(DW.LNS.set_prologue_end); |
| 273 | fn unlinkUnit(sec: *Section, unit: Unit.Index) void { |
| 274 | const unit_ptr = sec.getUnit(unit); |
| 275 | if (unit_ptr.prev.unwrap()) |prev_unit| sec.getUnit(prev_unit).next = unit_ptr.next; |
| 276 | if (unit_ptr.next.unwrap()) |next_unit| sec.getUnit(next_unit).prev = unit_ptr.prev; |
| 277 | if (sec.first.unwrap().? == unit) sec.first = unit_ptr.next; |
| 278 | if (sec.last.unwrap().? == unit) sec.last = unit_ptr.prev; |
| 933 | 279 | } |
| 934 | 280 | |
| 935 | | pub fn setEpilogueBegin(self: *NavState) error{OutOfMemory}!void { |
| 936 | | try self.dbg_line.append(DW.LNS.set_epilogue_begin); |
| 281 | fn popUnit(sec: *Section) void { |
| 282 | const unit: Unit.Index = @enumFromInt(sec.units.items.len - 1); |
| 283 | sec.unlinkUnit(unit); |
| 284 | _ = sec.units.pop(); |
| 937 | 285 | } |
| 938 | 286 | |
| 939 | | pub fn setInlineFunc(self: *NavState, func: InternPool.Index) error{OutOfMemory}!void { |
| 940 | | const zcu = self.pt.zcu; |
| 941 | | if (self.dbg_line_func == func) return; |
| 287 | fn addEntry(sec: *Section, unit: Unit.Index, dwarf: *Dwarf) UpdateError!Entry.Index { |
| 288 | return sec.getUnit(unit).addEntry(sec, dwarf); |
| 289 | } |
| 942 | 290 | |
| 943 | | try self.dbg_line.ensureUnusedCapacity((1 + 4) + (1 + 5)); |
| 291 | fn getUnit(sec: *Section, unit: Unit.Index) *Unit { |
| 292 | return &sec.units.items[@intFromEnum(unit)]; |
| 293 | } |
| 944 | 294 | |
| 945 | | const old_func_info = zcu.funcInfo(self.dbg_line_func); |
| 946 | | const new_func_info = zcu.funcInfo(func); |
| 295 | fn replaceEntry(sec: *Section, unit: Unit.Index, entry: Entry.Index, dwarf: *Dwarf, contents: []const u8) UpdateError!void { |
| 296 | const unit_ptr = sec.getUnit(unit); |
| 297 | try unit_ptr.getEntry(entry).replace(unit_ptr, sec, dwarf, contents); |
| 298 | } |
| 947 | 299 | |
| 948 | | const old_file = try self.dwarf.addDIFile(zcu, old_func_info.owner_nav); |
| 949 | | const new_file = try self.dwarf.addDIFile(zcu, new_func_info.owner_nav); |
| 950 | | if (old_file != new_file) { |
| 951 | | self.dbg_line.appendAssumeCapacity(DW.LNS.set_file); |
| 952 | | leb128.writeUnsignedFixed(4, self.dbg_line.addManyAsArrayAssumeCapacity(4), new_file); |
| 300 | fn resize(sec: *Section, dwarf: *Dwarf, len: u64) UpdateError!void { |
| 301 | if (dwarf.bin_file.cast(.elf)) |elf_file| { |
| 302 | try elf_file.growNonAllocSection(sec.index, len, @intCast(sec.alignment.toByteUnits().?), true); |
| 303 | const shdr = &elf_file.shdrs.items[sec.index]; |
| 304 | sec.off = shdr.sh_offset; |
| 305 | sec.len = shdr.sh_size; |
| 306 | } else if (dwarf.bin_file.cast(.macho)) |macho_file| { |
| 307 | const header = if (macho_file.d_sym) |*d_sym| header: { |
| 308 | try d_sym.growSection(@intCast(sec.index), len, true, macho_file); |
| 309 | break :header &d_sym.sections.items[sec.index]; |
| 310 | } else header: { |
| 311 | try macho_file.growSection(@intCast(sec.index), len); |
| 312 | break :header &macho_file.sections.items(.header)[sec.index]; |
| 313 | }; |
| 314 | sec.off = header.offset; |
| 315 | sec.len = header.size; |
| 953 | 316 | } |
| 317 | } |
| 954 | 318 | |
| 955 | | const old_src_line: i33 = zcu.navSrcLine(old_func_info.owner_nav); |
| 956 | | const new_src_line: i33 = zcu.navSrcLine(new_func_info.owner_nav); |
| 957 | | if (new_src_line != old_src_line) { |
| 958 | | self.dbg_line.appendAssumeCapacity(DW.LNS.advance_line); |
| 959 | | leb128.writeSignedFixed(5, self.dbg_line.addManyAsArrayAssumeCapacity(5), new_src_line - old_src_line); |
| 319 | fn trim(sec: *Section, dwarf: *Dwarf) void { |
| 320 | const len = sec.getUnit(sec.first.unwrap() orelse return).off; |
| 321 | if (len == 0) return; |
| 322 | for (sec.units.items) |*unit| unit.off -= len; |
| 323 | sec.off += len; |
| 324 | sec.len -= len; |
| 325 | if (dwarf.bin_file.cast(.elf)) |elf_file| { |
| 326 | const shdr = &elf_file.shdrs.items[sec.index]; |
| 327 | shdr.sh_offset = sec.off; |
| 328 | shdr.sh_size = sec.len; |
| 329 | } else if (dwarf.bin_file.cast(.macho)) |macho_file| { |
| 330 | const header = if (macho_file.d_sym) |*d_sym| |
| 331 | &d_sym.sections.items[sec.index] |
| 332 | else |
| 333 | &macho_file.sections.items(.header)[sec.index]; |
| 334 | header.offset = @intCast(sec.off); |
| 335 | header.size = sec.len; |
| 960 | 336 | } |
| 961 | | |
| 962 | | self.dbg_line_func = func; |
| 963 | 337 | } |
| 964 | | }; |
| 965 | 338 | |
| 966 | | pub const AbbrevEntry = struct { |
| 967 | | atom_index: Atom.Index, |
| 968 | | type: Type, |
| 969 | | offset: u32, |
| 970 | | }; |
| 339 | fn resolveRelocs(sec: *Section, dwarf: *Dwarf) RelocError!void { |
| 340 | for (sec.units.items) |*unit| try unit.resolveRelocs(sec, dwarf); |
| 341 | } |
| 971 | 342 | |
| 972 | | pub const AbbrevRelocation = struct { |
| 973 | | /// If target is null, we deal with a local relocation that is based on simple offset + addend |
| 974 | | /// only. |
| 975 | | target: ?u32, |
| 976 | | atom_index: Atom.Index, |
| 977 | | offset: u32, |
| 978 | | addend: u32, |
| 343 | fn padToIdeal(sec: *Section, actual_size: anytype) @TypeOf(actual_size) { |
| 344 | return if (sec.pad_to_ideal) Dwarf.padToIdeal(actual_size) else actual_size; |
| 345 | } |
| 979 | 346 | }; |
| 980 | 347 | |
| 981 | | pub const ExprlocRelocation = struct { |
| 982 | | /// Type of the relocation: direct load ref, or GOT load ref (via GOT table) |
| 983 | | type: enum { |
| 984 | | direct_load, |
| 985 | | got_load, |
| 986 | | }, |
| 987 | | /// Index of the target in the linker's locals symbol table. |
| 988 | | target: u32, |
| 989 | | /// Offset within the debug info buffer where to patch up the address value. |
| 990 | | offset: u32, |
| 991 | | }; |
| 348 | /// A unit within a `Section` containing a sequence of `Entry`s. |
| 349 | const Unit = struct { |
| 350 | prev: Index.Optional, |
| 351 | next: Index.Optional, |
| 352 | first: Entry.Index.Optional, |
| 353 | last: Entry.Index.Optional, |
| 354 | /// offset within containing section |
| 355 | off: u32, |
| 356 | header_len: u32, |
| 357 | trailer_len: u32, |
| 358 | /// data length in bytes |
| 359 | len: u32, |
| 360 | entries: std.ArrayListUnmanaged(Entry), |
| 361 | cross_entry_relocs: std.ArrayListUnmanaged(CrossEntryReloc), |
| 362 | cross_unit_relocs: std.ArrayListUnmanaged(CrossUnitReloc), |
| 363 | cross_section_relocs: std.ArrayListUnmanaged(CrossSectionReloc), |
| 364 | external_relocs: std.ArrayListUnmanaged(ExternalReloc), |
| 365 | |
| 366 | const Index = enum(u32) { |
| 367 | main, |
| 368 | _, |
| 369 | |
| 370 | const Optional = enum(u32) { |
| 371 | none = std.math.maxInt(u32), |
| 372 | _, |
| 373 | |
| 374 | fn unwrap(uio: Optional) ?Index { |
| 375 | return if (uio != .none) @enumFromInt(@intFromEnum(uio)) else null; |
| 376 | } |
| 377 | }; |
| 992 | 378 | |
| 993 | | pub const PtrWidth = enum { p32, p64 }; |
| 379 | fn toOptional(ui: Index) Optional { |
| 380 | return @enumFromInt(@intFromEnum(ui)); |
| 381 | } |
| 382 | }; |
| 994 | 383 | |
| 995 | | pub const AbbrevCode = enum(u8) { |
| 996 | | null, |
| 997 | | padding, |
| 998 | | compile_unit, |
| 999 | | subprogram, |
| 1000 | | subprogram_retvoid, |
| 1001 | | base_type, |
| 1002 | | ptr_type, |
| 1003 | | struct_type, |
| 1004 | | struct_member, |
| 1005 | | enum_type, |
| 1006 | | enum_variant, |
| 1007 | | union_type, |
| 1008 | | zero_bit_type, |
| 1009 | | parameter, |
| 1010 | | variable, |
| 1011 | | array_type, |
| 1012 | | array_dim, |
| 1013 | | }; |
| 384 | fn deinit(unit: *Unit, gpa: std.mem.Allocator) void { |
| 385 | unit.entries.deinit(gpa); |
| 386 | unit.cross_entry_relocs.deinit(gpa); |
| 387 | unit.cross_unit_relocs.deinit(gpa); |
| 388 | unit.cross_section_relocs.deinit(gpa); |
| 389 | unit.external_relocs.deinit(gpa); |
| 390 | unit.* = undefined; |
| 391 | } |
| 1014 | 392 | |
| 1015 | | /// The reloc offset for the virtual address of a function in its Line Number Program. |
| 1016 | | /// Size is a virtual address integer. |
| 1017 | | const dbg_line_vaddr_reloc_index = 3; |
| 1018 | | /// The reloc offset for the virtual address of a function in its .debug_info TAG.subprogram. |
| 1019 | | /// Size is a virtual address integer. |
| 1020 | | const dbg_info_low_pc_reloc_index = 1; |
| 393 | fn addEntry(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!Entry.Index { |
| 394 | const entry: Entry.Index = @enumFromInt(unit.entries.items.len); |
| 395 | const entry_ptr = try unit.entries.addOne(dwarf.gpa); |
| 396 | entry_ptr.* = .{ |
| 397 | .prev = unit.last, |
| 398 | .next = .none, |
| 399 | .off = 0, |
| 400 | .len = 0, |
| 401 | }; |
| 402 | if (unit.last.unwrap()) |last_entry| { |
| 403 | const last_entry_ptr = unit.getEntry(last_entry); |
| 404 | last_entry_ptr.next = entry.toOptional(); |
| 405 | entry_ptr.off = last_entry_ptr.off + sec.padToIdeal(last_entry_ptr.len); |
| 406 | } |
| 407 | if (unit.first == .none) |
| 408 | unit.first = entry.toOptional(); |
| 409 | unit.last = entry.toOptional(); |
| 410 | return entry; |
| 411 | } |
| 1021 | 412 | |
| 1022 | | const min_nop_size = 2; |
| 413 | fn getEntry(unit: *Unit, entry: Entry.Index) *Entry { |
| 414 | return &unit.entries.items[@intFromEnum(entry)]; |
| 415 | } |
| 1023 | 416 | |
| 1024 | | /// When allocating, the ideal_capacity is calculated by |
| 1025 | | /// actual_capacity + (actual_capacity / ideal_factor) |
| 1026 | | const ideal_factor = 3; |
| 417 | fn resize(unit_ptr: *Unit, sec: *Section, dwarf: *Dwarf, extra_header_len: u32, len: u32) UpdateError!void { |
| 418 | const end = if (unit_ptr.next.unwrap()) |next_unit| |
| 419 | sec.getUnit(next_unit).off |
| 420 | else |
| 421 | sec.len; |
| 422 | if (extra_header_len > 0 or unit_ptr.off + len > end) { |
| 423 | unit_ptr.len = @min(unit_ptr.len, len); |
| 424 | var new_off = unit_ptr.off; |
| 425 | if (unit_ptr.next.unwrap()) |next_unit| { |
| 426 | const next_unit_ptr = sec.getUnit(next_unit); |
| 427 | if (unit_ptr.prev.unwrap()) |prev_unit| |
| 428 | sec.getUnit(prev_unit).next = unit_ptr.next |
| 429 | else |
| 430 | sec.first = unit_ptr.next; |
| 431 | const unit = next_unit_ptr.prev; |
| 432 | next_unit_ptr.prev = unit_ptr.prev; |
| 433 | const last_unit_ptr = sec.getUnit(sec.last.unwrap().?); |
| 434 | last_unit_ptr.next = unit; |
| 435 | unit_ptr.prev = sec.last; |
| 436 | unit_ptr.next = .none; |
| 437 | new_off = last_unit_ptr.off + sec.padToIdeal(last_unit_ptr.len); |
| 438 | sec.last = unit; |
| 439 | sec.dirty = true; |
| 440 | } else if (extra_header_len > 0) { |
| 441 | // `copyRangeAll` in `move` does not support overlapping ranges |
| 442 | // so make sure new location is disjoint from current location. |
| 443 | new_off += unit_ptr.len -| extra_header_len; |
| 444 | } |
| 445 | try sec.resize(dwarf, new_off + len); |
| 446 | try unit_ptr.move(sec, dwarf, new_off + extra_header_len); |
| 447 | unit_ptr.off -= extra_header_len; |
| 448 | unit_ptr.header_len += extra_header_len; |
| 449 | sec.trim(dwarf); |
| 450 | } |
| 451 | unit_ptr.len = len; |
| 452 | } |
| 1027 | 453 | |
| 1028 | | pub fn init(lf: *File, format: Format) Dwarf { |
| 1029 | | const comp = lf.comp; |
| 1030 | | const gpa = comp.gpa; |
| 1031 | | const target = comp.root_mod.resolved_target.result; |
| 1032 | | const ptr_width: PtrWidth = switch (target.ptrBitWidth()) { |
| 1033 | | 0...32 => .p32, |
| 1034 | | 33...64 => .p64, |
| 1035 | | else => unreachable, |
| 1036 | | }; |
| 1037 | | return .{ |
| 1038 | | .allocator = gpa, |
| 1039 | | .bin_file = lf, |
| 1040 | | .format = format, |
| 1041 | | .ptr_width = ptr_width, |
| 1042 | | .dbg_line_header = switch (target.cpu.arch) { |
| 1043 | | .x86_64, .aarch64 => .{ |
| 1044 | | .minimum_instruction_length = 1, |
| 1045 | | .maximum_operations_per_instruction = 1, |
| 1046 | | .default_is_stmt = true, |
| 1047 | | .line_base = -5, |
| 1048 | | .line_range = 14, |
| 1049 | | .opcode_base = DW.LNS.set_isa + 1, |
| 1050 | | }, |
| 1051 | | else => .{ |
| 1052 | | .minimum_instruction_length = 1, |
| 1053 | | .maximum_operations_per_instruction = 1, |
| 1054 | | .default_is_stmt = true, |
| 1055 | | .line_base = 1, |
| 1056 | | .line_range = 1, |
| 1057 | | .opcode_base = DW.LNS.set_isa + 1, |
| 1058 | | }, |
| 1059 | | }, |
| 1060 | | }; |
| 1061 | | } |
| 454 | fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void { |
| 455 | if (unit.off == new_off) return; |
| 456 | if (try dwarf.getFile().?.copyRangeAll( |
| 457 | sec.off + unit.off, |
| 458 | dwarf.getFile().?, |
| 459 | sec.off + new_off, |
| 460 | unit.len, |
| 461 | ) != unit.len) return error.InputOutput; |
| 462 | unit.off = new_off; |
| 463 | } |
| 1062 | 464 | |
| 1063 | | pub fn deinit(self: *Dwarf) void { |
| 1064 | | const gpa = self.allocator; |
| 465 | fn resizeHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) UpdateError!void { |
| 466 | if (unit.header_len == len) return; |
| 467 | const available_len = if (unit.prev.unwrap()) |prev_unit| prev_excess: { |
| 468 | const prev_unit_ptr = sec.getUnit(prev_unit); |
| 469 | break :prev_excess unit.off - prev_unit_ptr.off - prev_unit_ptr.len; |
| 470 | } else 0; |
| 471 | if (available_len + unit.header_len < len) |
| 472 | try unit.resize(sec, dwarf, len - unit.header_len, unit.len - unit.header_len + len); |
| 473 | if (unit.header_len > len) { |
| 474 | const excess_header_len = unit.header_len - len; |
| 475 | unit.off += excess_header_len; |
| 476 | unit.header_len -= excess_header_len; |
| 477 | unit.len -= excess_header_len; |
| 478 | } else if (unit.header_len < len) { |
| 479 | const needed_header_len = len - unit.header_len; |
| 480 | unit.off -= needed_header_len; |
| 481 | unit.header_len += needed_header_len; |
| 482 | unit.len += needed_header_len; |
| 483 | } |
| 484 | assert(unit.header_len == len); |
| 485 | sec.trim(dwarf); |
| 486 | } |
| 1065 | 487 | |
| 1066 | | self.src_fn_free_list.deinit(gpa); |
| 1067 | | self.src_fns.deinit(gpa); |
| 1068 | | self.src_fn_navs.deinit(gpa); |
| 488 | fn replaceHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void { |
| 489 | assert(contents.len == unit.header_len); |
| 490 | try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off); |
| 491 | } |
| 1069 | 492 | |
| 1070 | | self.di_atom_free_list.deinit(gpa); |
| 1071 | | self.di_atoms.deinit(gpa); |
| 1072 | | self.di_atom_navs.deinit(gpa); |
| 493 | fn writeTrailer(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void { |
| 494 | const start = unit.off + unit.header_len + if (unit.last.unwrap()) |last_entry| end: { |
| 495 | const last_entry_ptr = unit.getEntry(last_entry); |
| 496 | break :end last_entry_ptr.off + last_entry_ptr.len; |
| 497 | } else 0; |
| 498 | const end = if (unit.next.unwrap()) |next_unit| |
| 499 | sec.getUnit(next_unit).off |
| 500 | else |
| 501 | sec.len; |
| 502 | const trailer_len: usize = @intCast(end - start); |
| 503 | assert(trailer_len >= unit.trailer_len); |
| 504 | var trailer = try std.ArrayList(u8).initCapacity(dwarf.gpa, trailer_len); |
| 505 | defer trailer.deinit(); |
| 506 | const fill_byte: u8 = if (sec == &dwarf.debug_aranges.section) fill: { |
| 507 | trailer.appendNTimesAssumeCapacity(0, @intFromEnum(dwarf.address_size) * 2); |
| 508 | break :fill 0; |
| 509 | } else if (sec == &dwarf.debug_info.section) fill: { |
| 510 | assert(uleb128Bytes(@intFromEnum(AbbrevCode.null)) == 1); |
| 511 | trailer.appendNTimesAssumeCapacity(@intFromEnum(AbbrevCode.null), 2); |
| 512 | break :fill @intFromEnum(AbbrevCode.null); |
| 513 | } else if (sec == &dwarf.debug_line.section) fill: { |
| 514 | unit.len -= unit.trailer_len; |
| 515 | const extra_len: u32 = @intCast((trailer_len - DebugLine.trailer_bytes) & 1); |
| 516 | unit.trailer_len = DebugLine.trailer_bytes + extra_len; |
| 517 | unit.len += unit.trailer_len; |
| 518 | |
| 519 | // prevent end sequence from emitting an invalid file index |
| 520 | trailer.appendAssumeCapacity(DW.LNS.set_file); |
| 521 | uleb128(trailer.fixedWriter(), 0) catch unreachable; |
| 522 | |
| 523 | trailer.appendAssumeCapacity(DW.LNS.extended_op); |
| 524 | std.leb.writeUnsignedExtended(trailer.addManyAsSliceAssumeCapacity(uleb128Bytes(1) + extra_len), 1); |
| 525 | trailer.appendAssumeCapacity(DW.LNE.end_sequence); |
| 526 | break :fill DW.LNS.extended_op; |
| 527 | } else if (sec == &dwarf.debug_rnglists.section) fill: { |
| 528 | trailer.appendAssumeCapacity(DW.RLE.end_of_list); |
| 529 | break :fill DW.RLE.end_of_list; |
| 530 | } else unreachable; |
| 531 | assert(trailer.items.len == unit.trailer_len); |
| 532 | trailer.appendNTimesAssumeCapacity(fill_byte, trailer_len - trailer.items.len); |
| 533 | assert(trailer.items.len == trailer_len); |
| 534 | try dwarf.getFile().?.pwriteAll(trailer.items, sec.off + start); |
| 535 | } |
| 1073 | 536 | |
| 1074 | | self.strtab.deinit(gpa); |
| 1075 | | self.di_files.deinit(gpa); |
| 1076 | | self.global_abbrev_relocs.deinit(gpa); |
| 1077 | | } |
| 537 | fn resolveRelocs(unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void { |
| 538 | for (unit.cross_entry_relocs.items) |reloc| { |
| 539 | try dwarf.resolveReloc( |
| 540 | sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry| |
| 541 | unit.header_len + unit.getEntry(source_entry).off |
| 542 | else |
| 543 | 0) + reloc.source_off, |
| 544 | unit.off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sec, dwarf).off + reloc.target_off, |
| 545 | dwarf.sectionOffsetBytes(), |
| 546 | ); |
| 547 | } |
| 548 | for (unit.cross_unit_relocs.items) |reloc| { |
| 549 | const target_unit = sec.getUnit(reloc.target_unit); |
| 550 | try dwarf.resolveReloc( |
| 551 | sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry| |
| 552 | unit.header_len + unit.getEntry(source_entry).off |
| 553 | else |
| 554 | 0) + reloc.source_off, |
| 555 | target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry| |
| 556 | target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off |
| 557 | else |
| 558 | 0) + reloc.target_off, |
| 559 | dwarf.sectionOffsetBytes(), |
| 560 | ); |
| 561 | } |
| 562 | for (unit.cross_section_relocs.items) |reloc| { |
| 563 | const target_sec = switch (reloc.target_sec) { |
| 564 | inline else => |target_sec| &@field(dwarf, @tagName(target_sec)).section, |
| 565 | }; |
| 566 | const target_unit = target_sec.getUnit(reloc.target_unit); |
| 567 | try dwarf.resolveReloc( |
| 568 | sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry| |
| 569 | unit.header_len + unit.getEntry(source_entry).off |
| 570 | else |
| 571 | 0) + reloc.source_off, |
| 572 | target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry| |
| 573 | target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off |
| 574 | else |
| 575 | 0) + reloc.target_off, |
| 576 | dwarf.sectionOffsetBytes(), |
| 577 | ); |
| 578 | } |
| 579 | if (dwarf.bin_file.cast(.elf)) |elf_file| { |
| 580 | const zo = elf_file.zigObjectPtr().?; |
| 581 | for (unit.external_relocs.items) |reloc| { |
| 582 | const symbol = zo.symbol(reloc.target_sym); |
| 583 | try dwarf.resolveReloc( |
| 584 | sec.off + unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off, |
| 585 | @bitCast(symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off)) - |
| 586 | if (symbol.flags.is_tls) elf_file.dtpAddress() else 0), |
| 587 | @intFromEnum(dwarf.address_size), |
| 588 | ); |
| 589 | } |
| 590 | } else if (dwarf.bin_file.cast(.macho)) |macho_file| { |
| 591 | const zo = macho_file.getZigObject().?; |
| 592 | for (unit.external_relocs.items) |reloc| { |
| 593 | const ref = zo.getSymbolRef(reloc.target_sym, macho_file); |
| 594 | try dwarf.resolveReloc( |
| 595 | sec.off + unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off, |
| 596 | ref.getSymbol(macho_file).?.getAddress(.{}, macho_file), |
| 597 | @intFromEnum(dwarf.address_size), |
| 598 | ); |
| 599 | } |
| 600 | } |
| 601 | } |
| 1078 | 602 | |
| 1079 | | /// Initializes Nav's state and its matching output buffers. |
| 1080 | | /// Call this before `commitNavState`. |
| 1081 | | pub fn initNavState(self: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !NavState { |
| 1082 | | const tracy = trace(@src()); |
| 1083 | | defer tracy.end(); |
| 603 | const CrossEntryReloc = struct { |
| 604 | source_entry: Entry.Index.Optional = .none, |
| 605 | source_off: u32 = 0, |
| 606 | target_entry: Entry.Index, |
| 607 | target_off: u32 = 0, |
| 608 | }; |
| 609 | const CrossUnitReloc = struct { |
| 610 | source_entry: Entry.Index.Optional = .none, |
| 611 | source_off: u32 = 0, |
| 612 | target_unit: Unit.Index, |
| 613 | target_entry: Entry.Index.Optional = .none, |
| 614 | target_off: u32 = 0, |
| 615 | }; |
| 616 | const CrossSectionReloc = struct { |
| 617 | source_entry: Entry.Index.Optional = .none, |
| 618 | source_off: u32 = 0, |
| 619 | target_sec: Section.Index, |
| 620 | target_unit: Unit.Index, |
| 621 | target_entry: Entry.Index.Optional = .none, |
| 622 | target_off: u32 = 0, |
| 623 | }; |
| 624 | const ExternalReloc = struct { |
| 625 | source_entry: Entry.Index, |
| 626 | source_off: u32 = 0, |
| 627 | target_sym: u32, |
| 628 | target_off: u64 = 0, |
| 629 | }; |
| 630 | }; |
| 1084 | 631 | |
| 1085 | | const nav = pt.zcu.intern_pool.getNav(nav_index); |
| 1086 | | log.debug("initNavState {}", .{nav.fqn.fmt(&pt.zcu.intern_pool)}); |
| 632 | /// An indivisible entry within a `Unit` containing section-specific data. |
| 633 | const Entry = struct { |
| 634 | prev: Index.Optional, |
| 635 | next: Index.Optional, |
| 636 | /// offset from end of containing unit header |
| 637 | off: u32, |
| 638 | /// data length in bytes |
| 639 | len: u32, |
| 1087 | 640 | |
| 1088 | | const gpa = self.allocator; |
| 1089 | | var nav_state: NavState = .{ |
| 1090 | | .dwarf = self, |
| 1091 | | .pt = pt, |
| 1092 | | .di_atom_navs = &self.di_atom_navs, |
| 1093 | | .dbg_line_func = undefined, |
| 1094 | | .dbg_line = std.ArrayList(u8).init(gpa), |
| 1095 | | .dbg_info = std.ArrayList(u8).init(gpa), |
| 1096 | | .abbrev_type_arena = std.heap.ArenaAllocator.init(gpa), |
| 1097 | | .abbrev_table = .{}, |
| 1098 | | .abbrev_resolver = .{}, |
| 1099 | | .abbrev_relocs = .{}, |
| 1100 | | .exprloc_relocs = .{}, |
| 1101 | | }; |
| 1102 | | errdefer nav_state.deinit(); |
| 1103 | | const dbg_line_buffer = &nav_state.dbg_line; |
| 1104 | | const dbg_info_buffer = &nav_state.dbg_info; |
| 641 | const Index = enum(u32) { |
| 642 | _, |
| 1105 | 643 | |
| 1106 | | const di_atom_index = try self.getOrCreateAtomForNav(.di_atom, nav_index); |
| 644 | const Optional = enum(u32) { |
| 645 | none = std.math.maxInt(u32), |
| 646 | _, |
| 1107 | 647 | |
| 1108 | | const nav_val = Value.fromInterned(nav.status.resolved.val); |
| 648 | fn unwrap(eio: Optional) ?Index { |
| 649 | return if (eio != .none) @enumFromInt(@intFromEnum(eio)) else null; |
| 650 | } |
| 651 | }; |
| 1109 | 652 | |
| 1110 | | switch (nav_val.typeOf(pt.zcu).zigTypeTag(pt.zcu)) { |
| 1111 | | .Fn => { |
| 1112 | | _ = try self.getOrCreateAtomForNav(.src_fn, nav_index); |
| 653 | fn toOptional(ei: Index) Optional { |
| 654 | return @enumFromInt(@intFromEnum(ei)); |
| 655 | } |
| 656 | }; |
| 1113 | 657 | |
| 1114 | | // For functions we need to add a prologue to the debug line program. |
| 1115 | | const ptr_width_bytes = self.ptrWidthBytes(); |
| 1116 | | try dbg_line_buffer.ensureTotalCapacity((3 + ptr_width_bytes) + (1 + 4) + (1 + 4) + (1 + 5) + 1); |
| 658 | fn pad(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void { |
| 659 | const start = entry.off + entry.len; |
| 660 | const len = unit.getEntry(entry.next.unwrap() orelse return).off - start; |
| 661 | if (sec == &dwarf.debug_info.section) { |
| 662 | var buf: [ |
| 663 | @max( |
| 664 | uleb128Bytes(@intFromEnum(AbbrevCode.pad_1)), |
| 665 | uleb128Bytes(@intFromEnum(AbbrevCode.pad_n)) + uleb128Bytes(std.math.maxInt(u32)), |
| 666 | ) |
| 667 | ]u8 = undefined; |
| 668 | var fbs = std.io.fixedBufferStream(&buf); |
| 669 | switch (len) { |
| 670 | 0 => {}, |
| 671 | 1 => uleb128(fbs.writer(), @intFromEnum(AbbrevCode.pad_1)) catch unreachable, |
| 672 | else => { |
| 673 | uleb128(fbs.writer(), @intFromEnum(AbbrevCode.pad_n)) catch unreachable; |
| 674 | const abbrev_code_bytes = fbs.pos; |
| 675 | var block_len_bytes: u5 = 1; |
| 676 | while (true) switch (std.math.order(len - abbrev_code_bytes - block_len_bytes, @as(u32, 1) << 7 * block_len_bytes)) { |
| 677 | .lt => break uleb128(fbs.writer(), len - abbrev_code_bytes - block_len_bytes) catch unreachable, |
| 678 | .eq => { |
| 679 | // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte |
| 680 | block_len_bytes += 1; |
| 681 | std.leb.writeUnsignedExtended(buf[fbs.pos..][0..block_len_bytes], len - abbrev_code_bytes - block_len_bytes); |
| 682 | fbs.pos += block_len_bytes; |
| 683 | break; |
| 684 | }, |
| 685 | .gt => block_len_bytes += 1, |
| 686 | }; |
| 687 | assert(fbs.pos == abbrev_code_bytes + block_len_bytes); |
| 688 | }, |
| 689 | } |
| 690 | assert(fbs.pos <= len); |
| 691 | try dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + unit.off + unit.header_len + start); |
| 692 | } else if (sec == &dwarf.debug_line.section) { |
| 693 | const buf = try dwarf.gpa.alloc(u8, len); |
| 694 | defer dwarf.gpa.free(buf); |
| 695 | @memset(buf, DW.LNS.const_add_pc); |
| 696 | try dwarf.getFile().?.pwriteAll(buf, sec.off + unit.off + unit.header_len + start); |
| 697 | } else assert(!sec.pad_to_ideal and len == 0); |
| 698 | } |
| 1117 | 699 | |
| 1118 | | nav_state.dbg_line_func = nav_val.toIntern(); |
| 1119 | | const func = nav_val.getFunction(pt.zcu).?; |
| 1120 | | log.debug("src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{ |
| 1121 | | pt.zcu.navSrcLine(nav_index), |
| 1122 | | func.lbrace_line, |
| 1123 | | func.rbrace_line, |
| 700 | fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void { |
| 701 | const end = if (entry_ptr.next.unwrap()) |next_entry| |
| 702 | unit.getEntry(next_entry).off |
| 703 | else |
| 704 | unit.len -| (unit.header_len + unit.trailer_len); |
| 705 | if (entry_ptr.off + contents.len > end) { |
| 706 | if (entry_ptr.next.unwrap()) |next_entry| { |
| 707 | if (entry_ptr.prev.unwrap()) |prev_entry| { |
| 708 | const prev_entry_ptr = unit.getEntry(prev_entry); |
| 709 | prev_entry_ptr.next = entry_ptr.next; |
| 710 | try prev_entry_ptr.pad(unit, sec, dwarf); |
| 711 | } else unit.first = entry_ptr.next; |
| 712 | const next_entry_ptr = unit.getEntry(next_entry); |
| 713 | const entry = next_entry_ptr.prev; |
| 714 | next_entry_ptr.prev = entry_ptr.prev; |
| 715 | const last_entry_ptr = unit.getEntry(unit.last.unwrap().?); |
| 716 | last_entry_ptr.next = entry; |
| 717 | entry_ptr.prev = unit.last; |
| 718 | entry_ptr.next = .none; |
| 719 | entry_ptr.off = last_entry_ptr.off + sec.padToIdeal(last_entry_ptr.len); |
| 720 | unit.last = entry; |
| 721 | } |
| 722 | try unit.resize(sec, dwarf, 0, @intCast(unit.header_len + entry_ptr.off + sec.padToIdeal(contents.len) + unit.trailer_len)); |
| 723 | } |
| 724 | entry_ptr.len = @intCast(contents.len); |
| 725 | { |
| 726 | var prev_entry_ptr = entry_ptr; |
| 727 | while (prev_entry_ptr.prev.unwrap()) |prev_entry| { |
| 728 | prev_entry_ptr = unit.getEntry(prev_entry); |
| 729 | if (prev_entry_ptr.len == 0) continue; |
| 730 | try prev_entry_ptr.pad(unit, sec, dwarf); |
| 731 | break; |
| 732 | } |
| 733 | } |
| 734 | try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off + unit.header_len + entry_ptr.off); |
| 735 | try entry_ptr.pad(unit, sec, dwarf); |
| 736 | if (false) { |
| 737 | const buf = try dwarf.gpa.alloc(u8, sec.len); |
| 738 | defer dwarf.gpa.free(buf); |
| 739 | _ = try dwarf.getFile().?.preadAll(buf, sec.off); |
| 740 | log.info("Section{{ .first = {}, .last = {}, .off = 0x{x}, .len = 0x{x} }}", .{ |
| 741 | @intFromEnum(sec.first), |
| 742 | @intFromEnum(sec.last), |
| 743 | sec.off, |
| 744 | sec.len, |
| 1124 | 745 | }); |
| 1125 | | const line: u28 = @intCast(pt.zcu.navSrcLine(nav_index) + func.lbrace_line); |
| 746 | for (sec.units.items) |*unit_ptr| { |
| 747 | log.info(" Unit{{ .prev = {}, .next = {}, .first = {}, .last = {}, .off = 0x{x}, .header_len = 0x{x}, .trailer_len = 0x{x}, .len = 0x{x} }}", .{ |
| 748 | @intFromEnum(unit_ptr.prev), |
| 749 | @intFromEnum(unit_ptr.next), |
| 750 | @intFromEnum(unit_ptr.first), |
| 751 | @intFromEnum(unit_ptr.last), |
| 752 | unit_ptr.off, |
| 753 | unit_ptr.header_len, |
| 754 | unit_ptr.trailer_len, |
| 755 | unit_ptr.len, |
| 756 | }); |
| 757 | for (unit_ptr.entries.items) |*entry| { |
| 758 | log.info(" Entry{{ .prev = {}, .next = {}, .off = 0x{x}, .len = 0x{x} }}", .{ |
| 759 | @intFromEnum(entry.prev), |
| 760 | @intFromEnum(entry.next), |
| 761 | entry.off, |
| 762 | entry.len, |
| 763 | }); |
| 764 | } |
| 765 | } |
| 766 | std.debug.dumpHex(buf); |
| 767 | } |
| 768 | } |
| 1126 | 769 | |
| 1127 | | dbg_line_buffer.appendSliceAssumeCapacity(&.{ |
| 1128 | | DW.LNS.extended_op, |
| 1129 | | ptr_width_bytes + 1, |
| 1130 | | DW.LNE.set_address, |
| 770 | fn assertNonEmpty(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) *Entry { |
| 771 | if (entry.len > 0) return entry; |
| 772 | if (std.debug.runtime_safety) { |
| 773 | log.err("missing {} from {s}", .{ |
| 774 | @as(Entry.Index, @enumFromInt(entry - unit.entries.items.ptr)), |
| 775 | std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file| |
| 776 | elf_file.shstrtab.items[elf_file.shdrs.items[sec.index].sh_name..] |
| 777 | else if (dwarf.bin_file.cast(.macho)) |macho_file| |
| 778 | if (macho_file.d_sym) |*d_sym| |
| 779 | &d_sym.sections.items[sec.index].segname |
| 780 | else |
| 781 | &macho_file.sections.items(.header)[sec.index].segname |
| 782 | else |
| 783 | "?", 0), |
| 1131 | 784 | }); |
| 1132 | | // This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`. |
| 1133 | | assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len); |
| 1134 | | dbg_line_buffer.appendNTimesAssumeCapacity(0, ptr_width_bytes); |
| 1135 | | |
| 1136 | | dbg_line_buffer.appendAssumeCapacity(DW.LNS.advance_line); |
| 1137 | | // This is the "relocatable" relative line offset from the previous function's end curly |
| 1138 | | // to this function's begin curly. |
| 1139 | | assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len); |
| 1140 | | // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later. |
| 1141 | | leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line); |
| 1142 | | |
| 1143 | | dbg_line_buffer.appendAssumeCapacity(DW.LNS.set_file); |
| 1144 | | assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len); |
| 1145 | | // Once we support more than one source file, this will have the ability to be more |
| 1146 | | // than one possible value. |
| 1147 | | const file_index = try self.addDIFile(pt.zcu, nav_index); |
| 1148 | | leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index); |
| 1149 | | |
| 1150 | | dbg_line_buffer.appendAssumeCapacity(DW.LNS.set_column); |
| 1151 | | leb128.writeUleb128(dbg_line_buffer.writer(), func.lbrace_column + 1) catch unreachable; |
| 1152 | | |
| 1153 | | // Emit a line for the begin curly with prologue_end=false. The codegen will |
| 1154 | | // do the work of setting prologue_end=true and epilogue_begin=true. |
| 1155 | | dbg_line_buffer.appendAssumeCapacity(DW.LNS.copy); |
| 1156 | | |
| 1157 | | // .debug_info subprogram |
| 1158 | | const nav_name_slice = nav.name.toSlice(&pt.zcu.intern_pool); |
| 1159 | | const nav_linkage_name_slice = nav.fqn.toSlice(&pt.zcu.intern_pool); |
| 1160 | | try dbg_info_buffer.ensureUnusedCapacity(1 + ptr_width_bytes + 4 + 4 + |
| 1161 | | (nav_name_slice.len + 1) + (nav_linkage_name_slice.len + 1)); |
| 1162 | | |
| 1163 | | const fn_ret_type = nav_val.typeOf(pt.zcu).fnReturnType(pt.zcu); |
| 1164 | | const fn_ret_has_bits = fn_ret_type.hasRuntimeBits(pt); |
| 1165 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum( |
| 1166 | | @as(AbbrevCode, if (fn_ret_has_bits) .subprogram else .subprogram_retvoid), |
| 1167 | | )); |
| 1168 | | // These get overwritten after generating the machine code. These values are |
| 1169 | | // "relocations" and have to be in this fixed place so that functions can be |
| 1170 | | // moved in virtual address space. |
| 1171 | | assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len); |
| 1172 | | dbg_info_buffer.appendNTimesAssumeCapacity(0, ptr_width_bytes); // DW.AT.low_pc, DW.FORM.addr |
| 1173 | | assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len); |
| 1174 | | dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); // DW.AT.high_pc, DW.FORM.data4 |
| 1175 | | if (fn_ret_has_bits) { |
| 1176 | | try nav_state.addTypeRelocGlobal(di_atom_index, fn_ret_type, @intCast(dbg_info_buffer.items.len)); |
| 1177 | | dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); // DW.AT.type, DW.FORM.ref4 |
| 785 | const zcu = dwarf.bin_file.comp.module.?; |
| 786 | const ip = &zcu.intern_pool; |
| 787 | for (dwarf.types.keys(), dwarf.types.values()) |ty, other_entry| { |
| 788 | const ty_unit: Unit.Index = if (Type.fromInterned(ty).typeDeclInst(zcu)) |inst_index| |
| 789 | dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFull(ip).file).mod) catch unreachable |
| 790 | else |
| 791 | .main; |
| 792 | if (sec.getUnit(ty_unit) == unit and unit.getEntry(other_entry) == entry) |
| 793 | log.err("missing Type({}({d}))", .{ |
| 794 | Type.fromInterned(ty).fmt(.{ .tid = .main, .zcu = zcu }), |
| 795 | @intFromEnum(ty), |
| 796 | }); |
| 1178 | 797 | } |
| 1179 | | dbg_info_buffer.appendSliceAssumeCapacity( |
| 1180 | | nav_name_slice[0 .. nav_name_slice.len + 1], |
| 1181 | | ); // DW.AT.name, DW.FORM.string |
| 1182 | | dbg_info_buffer.appendSliceAssumeCapacity( |
| 1183 | | nav_linkage_name_slice[0 .. nav_linkage_name_slice.len + 1], |
| 1184 | | ); // DW.AT.linkage_name, DW.FORM.string |
| 1185 | | }, |
| 1186 | | else => { |
| 1187 | | // TODO implement .debug_info for global variables |
| 1188 | | }, |
| 798 | for (dwarf.navs.keys(), dwarf.navs.values()) |nav, other_entry| { |
| 799 | const nav_unit = dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav).srcInst(ip).resolveFull(ip).file).mod) catch unreachable; |
| 800 | if (sec.getUnit(nav_unit) == unit and unit.getEntry(other_entry) == entry) |
| 801 | log.err("missing Nav({}({d}))", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }); |
| 802 | } |
| 803 | } |
| 804 | @panic("missing dwarf relocation target"); |
| 1189 | 805 | } |
| 806 | }; |
| 1190 | 807 | |
| 1191 | | return nav_state; |
| 1192 | | } |
| 808 | pub const Loc = union(enum) { |
| 809 | empty, |
| 810 | addr: union(enum) { sym: u32 }, |
| 811 | constu: u64, |
| 812 | consts: i64, |
| 813 | plus: Bin, |
| 814 | reg: u32, |
| 815 | breg: u32, |
| 816 | push_object_address, |
| 817 | form_tls_address: *const Loc, |
| 818 | implicit_value: []const u8, |
| 819 | stack_value: *const Loc, |
| 820 | wasm_ext: union(enum) { |
| 821 | local: u32, |
| 822 | global: u32, |
| 823 | operand_stack: u32, |
| 824 | }, |
| 1193 | 825 | |
| 1194 | | pub fn commitNavState( |
| 1195 | | self: *Dwarf, |
| 1196 | | pt: Zcu.PerThread, |
| 1197 | | nav_index: InternPool.Nav.Index, |
| 1198 | | sym_addr: u64, |
| 1199 | | sym_size: u64, |
| 1200 | | nav_state: *NavState, |
| 1201 | | ) !void { |
| 1202 | | const tracy = trace(@src()); |
| 1203 | | defer tracy.end(); |
| 1204 | | |
| 1205 | | const gpa = self.allocator; |
| 1206 | | const zcu = pt.zcu; |
| 1207 | | const ip = &zcu.intern_pool; |
| 1208 | | const nav = ip.getNav(nav_index); |
| 1209 | | const target = zcu.navFileScope(nav_index).mod.resolved_target.result; |
| 1210 | | const target_endian = target.cpu.arch.endian(); |
| 826 | pub const Bin = struct { *const Loc, *const Loc }; |
| 1211 | 827 | |
| 1212 | | var dbg_line_buffer = &nav_state.dbg_line; |
| 1213 | | var dbg_info_buffer = &nav_state.dbg_info; |
| 828 | fn getConst(loc: Loc, comptime Int: type) ?Int { |
| 829 | return switch (loc) { |
| 830 | .constu => |constu| std.math.cast(Int, constu), |
| 831 | .consts => |consts| std.math.cast(Int, consts), |
| 832 | else => null, |
| 833 | }; |
| 834 | } |
| 1214 | 835 | |
| 1215 | | const nav_val = Value.fromInterned(nav.status.resolved.val); |
| 1216 | | switch (nav_val.typeOf(zcu).zigTypeTag(zcu)) { |
| 1217 | | .Fn => { |
| 1218 | | try nav_state.setInlineFunc(nav_val.toIntern()); |
| 836 | fn getBaseReg(loc: Loc) ?u32 { |
| 837 | return switch (loc) { |
| 838 | .breg => |breg| breg, |
| 839 | else => null, |
| 840 | }; |
| 841 | } |
| 1219 | 842 | |
| 1220 | | // Since the Nav is a function, we need to update the .debug_line program. |
| 1221 | | // Perform the relocations based on vaddr. |
| 1222 | | switch (self.ptr_width) { |
| 1223 | | .p32 => { |
| 1224 | | { |
| 1225 | | const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4]; |
| 1226 | | mem.writeInt(u32, ptr, @intCast(sym_addr), target_endian); |
| 1227 | | } |
| 1228 | | { |
| 1229 | | const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..4]; |
| 1230 | | mem.writeInt(u32, ptr, @intCast(sym_addr), target_endian); |
| 1231 | | } |
| 1232 | | }, |
| 1233 | | .p64 => { |
| 1234 | | { |
| 1235 | | const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..8]; |
| 1236 | | mem.writeInt(u64, ptr, sym_addr, target_endian); |
| 1237 | | } |
| 1238 | | { |
| 1239 | | const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..8]; |
| 1240 | | mem.writeInt(u64, ptr, sym_addr, target_endian); |
| 1241 | | } |
| 1242 | | }, |
| 1243 | | } |
| 1244 | | { |
| 1245 | | log.debug("relocating subprogram high PC value: {x} => {x}", .{ |
| 1246 | | self.getRelocDbgInfoSubprogramHighPC(), |
| 1247 | | sym_size, |
| 1248 | | }); |
| 1249 | | const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4]; |
| 1250 | | mem.writeInt(u32, ptr, @intCast(sym_size), target_endian); |
| 1251 | | } |
| 843 | fn writeReg(reg: u32, op0: u8, opx: u8, writer: anytype) @TypeOf(writer).Error!void { |
| 844 | if (std.math.cast(u5, reg)) |small_reg| { |
| 845 | try writer.writeByte(op0 + small_reg); |
| 846 | } else { |
| 847 | try writer.writeByte(opx); |
| 848 | try uleb128(writer, reg); |
| 849 | } |
| 850 | } |
| 1252 | 851 | |
| 1253 | | try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS.extended_op, 1, DW.LNE.end_sequence }); |
| 1254 | | |
| 1255 | | // Now we have the full contents and may allocate a region to store it. |
| 1256 | | |
| 1257 | | // This logic is nearly identical to the logic below in `updateNavDebugInfo` for |
| 1258 | | // `TextBlock` and the .debug_info. If you are editing this logic, you |
| 1259 | | // probably need to edit that logic too. |
| 1260 | | const src_fn_index = self.src_fn_navs.get(nav_index).?; |
| 1261 | | const src_fn = self.getAtomPtr(.src_fn, src_fn_index); |
| 1262 | | src_fn.len = @intCast(dbg_line_buffer.items.len); |
| 1263 | | |
| 1264 | | if (self.src_fn_last_index) |last_index| blk: { |
| 1265 | | if (src_fn_index == last_index) break :blk; |
| 1266 | | if (src_fn.next_index) |next_index| { |
| 1267 | | const next = self.getAtomPtr(.src_fn, next_index); |
| 1268 | | // Update existing function - non-last item. |
| 1269 | | if (src_fn.off + src_fn.len + min_nop_size > next.off) { |
| 1270 | | // It grew too big, so we move it to a new location. |
| 1271 | | if (src_fn.prev_index) |prev_index| { |
| 1272 | | self.src_fn_free_list.put(gpa, prev_index, {}) catch {}; |
| 1273 | | self.getAtomPtr(.src_fn, prev_index).next_index = src_fn.next_index; |
| 1274 | | } |
| 1275 | | next.prev_index = src_fn.prev_index; |
| 1276 | | src_fn.next_index = null; |
| 1277 | | // Populate where it used to be with NOPs. |
| 1278 | | if (self.bin_file.cast(.elf)) |elf_file| { |
| 1279 | | const debug_line_sect = &elf_file.shdrs.items[elf_file.debug_line_section_index.?]; |
| 1280 | | const file_pos = debug_line_sect.sh_offset + src_fn.off; |
| 1281 | | try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len); |
| 1282 | | } else if (self.bin_file.cast(.macho)) |macho_file| { |
| 1283 | | if (macho_file.base.isRelocatable()) { |
| 1284 | | const debug_line_sect = &macho_file.sections.items(.header)[macho_file.debug_line_sect_index.?]; |
| 1285 | | const file_pos = debug_line_sect.offset + src_fn.off; |
| 1286 | | try pwriteDbgLineNops(macho_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len); |
| 1287 | | } else { |
| 1288 | | const d_sym = macho_file.getDebugSymbols().?; |
| 1289 | | const debug_line_sect = d_sym.getSectionPtr(d_sym.debug_line_section_index.?); |
| 1290 | | const file_pos = debug_line_sect.offset + src_fn.off; |
| 1291 | | try pwriteDbgLineNops(d_sym.file, file_pos, 0, &[0]u8{}, src_fn.len); |
| 1292 | | } |
| 1293 | | } else if (self.bin_file.cast(.wasm)) |wasm_file| { |
| 1294 | | _ = wasm_file; |
| 1295 | | // const debug_line = wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code; |
| 1296 | | // writeDbgLineNopsBuffered(debug_line.items, src_fn.off, 0, &.{}, src_fn.len); |
| 1297 | | } else unreachable; |
| 1298 | | // TODO Look at the free list before appending at the end. |
| 1299 | | src_fn.prev_index = last_index; |
| 1300 | | const last = self.getAtomPtr(.src_fn, last_index); |
| 1301 | | last.next_index = src_fn_index; |
| 1302 | | self.src_fn_last_index = src_fn_index; |
| 1303 | | |
| 1304 | | src_fn.off = last.off + padToIdeal(last.len); |
| 1305 | | } |
| 1306 | | } else if (src_fn.prev_index == null) { |
| 1307 | | // Append new function. |
| 1308 | | // TODO Look at the free list before appending at the end. |
| 1309 | | src_fn.prev_index = last_index; |
| 1310 | | const last = self.getAtomPtr(.src_fn, last_index); |
| 1311 | | last.next_index = src_fn_index; |
| 1312 | | self.src_fn_last_index = src_fn_index; |
| 1313 | | |
| 1314 | | src_fn.off = last.off + padToIdeal(last.len); |
| 852 | fn write(loc: Loc, wip: anytype) UpdateError!void { |
| 853 | const writer = wip.infoWriter(); |
| 854 | switch (loc) { |
| 855 | .empty => unreachable, |
| 856 | .addr => |addr| { |
| 857 | try writer.writeByte(DW.OP.addr); |
| 858 | switch (addr) { |
| 859 | .sym => |sym_index| try wip.addrSym(sym_index), |
| 1315 | 860 | } |
| 861 | }, |
| 862 | .constu => |constu| if (std.math.cast(u5, constu)) |lit| { |
| 863 | try writer.writeByte(@as(u8, DW.OP.lit0) + lit); |
| 864 | } else if (std.math.cast(u8, constu)) |const1u| { |
| 865 | try writer.writeAll(&.{ DW.OP.const1u, const1u }); |
| 866 | } else if (std.math.cast(u16, constu)) |const2u| { |
| 867 | try writer.writeByte(DW.OP.const2u); |
| 868 | try writer.writeInt(u16, const2u, wip.dwarf.endian); |
| 869 | } else if (std.math.cast(u21, constu)) |const3u| { |
| 870 | try writer.writeByte(DW.OP.constu); |
| 871 | try uleb128(writer, const3u); |
| 872 | } else if (std.math.cast(u32, constu)) |const4u| { |
| 873 | try writer.writeByte(DW.OP.const4u); |
| 874 | try writer.writeInt(u32, const4u, wip.dwarf.endian); |
| 875 | } else if (std.math.cast(u49, constu)) |const7u| { |
| 876 | try writer.writeByte(DW.OP.constu); |
| 877 | try uleb128(writer, const7u); |
| 1316 | 878 | } else { |
| 1317 | | // This is the first function of the Line Number Program. |
| 1318 | | self.src_fn_first_index = src_fn_index; |
| 1319 | | self.src_fn_last_index = src_fn_index; |
| 1320 | | |
| 1321 | | src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes(&[0][]u8{}, &[0][]u8{})); |
| 1322 | | } |
| 1323 | | |
| 1324 | | const last_src_fn_index = self.src_fn_last_index.?; |
| 1325 | | const last_src_fn = self.getAtom(.src_fn, last_src_fn_index); |
| 1326 | | const needed_size = last_src_fn.off + last_src_fn.len; |
| 1327 | | const prev_padding_size: u32 = if (src_fn.prev_index) |prev_index| blk: { |
| 1328 | | const prev = self.getAtom(.src_fn, prev_index); |
| 1329 | | break :blk src_fn.off - (prev.off + prev.len); |
| 1330 | | } else 0; |
| 1331 | | const next_padding_size: u32 = if (src_fn.next_index) |next_index| blk: { |
| 1332 | | const next = self.getAtom(.src_fn, next_index); |
| 1333 | | break :blk next.off - (src_fn.off + src_fn.len); |
| 1334 | | } else 0; |
| 1335 | | |
| 1336 | | // We only have support for one compilation unit so far, so the offsets are directly |
| 1337 | | // from the .debug_line section. |
| 1338 | | if (self.bin_file.cast(.elf)) |elf_file| { |
| 1339 | | const shdr_index = elf_file.debug_line_section_index.?; |
| 1340 | | try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true); |
| 1341 | | const debug_line_sect = elf_file.shdrs.items[shdr_index]; |
| 1342 | | const file_pos = debug_line_sect.sh_offset + src_fn.off; |
| 1343 | | try pwriteDbgLineNops( |
| 1344 | | elf_file.base.file.?, |
| 1345 | | file_pos, |
| 1346 | | prev_padding_size, |
| 1347 | | dbg_line_buffer.items, |
| 1348 | | next_padding_size, |
| 1349 | | ); |
| 1350 | | } else if (self.bin_file.cast(.macho)) |macho_file| { |
| 1351 | | if (macho_file.base.isRelocatable()) { |
| 1352 | | const sect_index = macho_file.debug_line_sect_index.?; |
| 1353 | | try macho_file.growSection(sect_index, needed_size); |
| 1354 | | const sect = macho_file.sections.items(.header)[sect_index]; |
| 1355 | | const file_pos = sect.offset + src_fn.off; |
| 1356 | | try pwriteDbgLineNops( |
| 1357 | | macho_file.base.file.?, |
| 1358 | | file_pos, |
| 1359 | | prev_padding_size, |
| 1360 | | dbg_line_buffer.items, |
| 1361 | | next_padding_size, |
| 1362 | | ); |
| 1363 | | } else { |
| 1364 | | const d_sym = macho_file.getDebugSymbols().?; |
| 1365 | | const sect_index = d_sym.debug_line_section_index.?; |
| 1366 | | try d_sym.growSection(sect_index, needed_size, true, macho_file); |
| 1367 | | const sect = d_sym.getSection(sect_index); |
| 1368 | | const file_pos = sect.offset + src_fn.off; |
| 1369 | | try pwriteDbgLineNops( |
| 1370 | | d_sym.file, |
| 1371 | | file_pos, |
| 1372 | | prev_padding_size, |
| 1373 | | dbg_line_buffer.items, |
| 1374 | | next_padding_size, |
| 1375 | | ); |
| 879 | try writer.writeByte(DW.OP.const8u); |
| 880 | try writer.writeInt(u64, constu, wip.dwarf.endian); |
| 881 | }, |
| 882 | .consts => |consts| if (std.math.cast(i8, consts)) |const1s| { |
| 883 | try writer.writeAll(&.{ DW.OP.const1s, @bitCast(const1s) }); |
| 884 | } else if (std.math.cast(i16, consts)) |const2s| { |
| 885 | try writer.writeByte(DW.OP.const2s); |
| 886 | try writer.writeInt(i16, const2s, wip.dwarf.endian); |
| 887 | } else if (std.math.cast(i21, consts)) |const3s| { |
| 888 | try writer.writeByte(DW.OP.consts); |
| 889 | try sleb128(writer, const3s); |
| 890 | } else if (std.math.cast(i32, consts)) |const4s| { |
| 891 | try writer.writeByte(DW.OP.const4s); |
| 892 | try writer.writeInt(i32, const4s, wip.dwarf.endian); |
| 893 | } else if (std.math.cast(i49, consts)) |const7s| { |
| 894 | try writer.writeByte(DW.OP.consts); |
| 895 | try sleb128(writer, const7s); |
| 896 | } else { |
| 897 | try writer.writeByte(DW.OP.const8s); |
| 898 | try writer.writeInt(i64, consts, wip.dwarf.endian); |
| 899 | }, |
| 900 | .plus => |plus| done: { |
| 901 | if (plus[0].getConst(u0)) |_| { |
| 902 | try plus[1].write(wip); |
| 903 | break :done; |
| 904 | } |
| 905 | if (plus[1].getConst(u0)) |_| { |
| 906 | try plus[0].write(wip); |
| 907 | break :done; |
| 908 | } |
| 909 | if (plus[0].getBaseReg()) |breg| { |
| 910 | if (plus[1].getConst(i65)) |offset| { |
| 911 | try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer); |
| 912 | try sleb128(writer, offset); |
| 913 | break :done; |
| 914 | } |
| 915 | } |
| 916 | if (plus[1].getBaseReg()) |breg| { |
| 917 | if (plus[0].getConst(i65)) |offset| { |
| 918 | try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer); |
| 919 | try sleb128(writer, offset); |
| 920 | break :done; |
| 921 | } |
| 922 | } |
| 923 | if (plus[0].getConst(u64)) |uconst| { |
| 924 | try plus[1].write(wip); |
| 925 | try writer.writeByte(DW.OP.plus_uconst); |
| 926 | try uleb128(writer, uconst); |
| 927 | break :done; |
| 928 | } |
| 929 | if (plus[1].getConst(u64)) |uconst| { |
| 930 | try plus[0].write(wip); |
| 931 | try writer.writeByte(DW.OP.plus_uconst); |
| 932 | try uleb128(writer, uconst); |
| 933 | break :done; |
| 934 | } |
| 935 | try plus[0].write(wip); |
| 936 | try plus[1].write(wip); |
| 937 | try writer.writeByte(DW.OP.plus); |
| 938 | }, |
| 939 | .reg => |reg| try writeReg(reg, DW.OP.reg0, DW.OP.regx, writer), |
| 940 | .breg => |breg| { |
| 941 | try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer); |
| 942 | try sleb128(writer, 0); |
| 943 | }, |
| 944 | .push_object_address => try writer.writeByte(DW.OP.push_object_address), |
| 945 | .form_tls_address => |addr| { |
| 946 | try addr.write(wip); |
| 947 | try writer.writeByte(DW.OP.form_tls_address); |
| 948 | }, |
| 949 | .implicit_value => |value| { |
| 950 | try writer.writeByte(DW.OP.implicit_value); |
| 951 | try uleb128(writer, value.len); |
| 952 | try writer.writeAll(value); |
| 953 | }, |
| 954 | .stack_value => |value| { |
| 955 | try value.write(wip); |
| 956 | try writer.writeByte(DW.OP.stack_value); |
| 957 | }, |
| 958 | .wasm_ext => |wasm_ext| { |
| 959 | try writer.writeByte(DW.OP.WASM_location); |
| 960 | switch (wasm_ext) { |
| 961 | .local => |local| { |
| 962 | try writer.writeByte(DW.OP.WASM_local); |
| 963 | try uleb128(writer, local); |
| 964 | }, |
| 965 | .global => |global| if (std.math.cast(u21, global)) |global_u21| { |
| 966 | try writer.writeByte(DW.OP.WASM_global); |
| 967 | try uleb128(writer, global_u21); |
| 968 | } else { |
| 969 | try writer.writeByte(DW.OP.WASM_global_u32); |
| 970 | try writer.writeInt(u32, global, wip.dwarf.endian); |
| 971 | }, |
| 972 | .operand_stack => |operand_stack| { |
| 973 | try writer.writeByte(DW.OP.WASM_operand_stack); |
| 974 | try uleb128(writer, operand_stack); |
| 975 | }, |
| 1376 | 976 | } |
| 1377 | | } else if (self.bin_file.cast(.wasm)) |wasm_file| { |
| 1378 | | _ = wasm_file; |
| 1379 | | // const atom = wasm_file.getAtomPtr(wasm_file.debug_line_atom.?); |
| 1380 | | // const debug_line = &atom.code; |
| 1381 | | // const segment_size = debug_line.items.len; |
| 1382 | | // if (needed_size != segment_size) { |
| 1383 | | // log.debug(" needed size does not equal allocated size: {d}", .{needed_size}); |
| 1384 | | // if (needed_size > segment_size) { |
| 1385 | | // log.debug(" allocating {d} bytes for 'debug line' information", .{needed_size - segment_size}); |
| 1386 | | // try debug_line.resize(self.allocator, needed_size); |
| 1387 | | // @memset(debug_line.items[segment_size..], 0); |
| 1388 | | // } |
| 1389 | | // debug_line.items.len = needed_size; |
| 1390 | | // } |
| 1391 | | // writeDbgLineNopsBuffered( |
| 1392 | | // debug_line.items, |
| 1393 | | // src_fn.off, |
| 1394 | | // prev_padding_size, |
| 1395 | | // dbg_line_buffer.items, |
| 1396 | | // next_padding_size, |
| 1397 | | // ); |
| 1398 | | } else unreachable; |
| 1399 | | |
| 1400 | | // .debug_info - End the TAG.subprogram children. |
| 1401 | | try dbg_info_buffer.append(0); |
| 1402 | | }, |
| 1403 | | else => {}, |
| 1404 | | } |
| 1405 | | |
| 1406 | | if (dbg_info_buffer.items.len == 0) |
| 1407 | | return; |
| 1408 | | |
| 1409 | | const di_atom_index = self.di_atom_navs.get(nav_index).?; |
| 1410 | | if (nav_state.abbrev_table.items.len > 0) { |
| 1411 | | // Now we emit the .debug_info types of the Nav. These will count towards the size of |
| 1412 | | // the buffer, so we have to do it before computing the offset, and we can't perform the actual |
| 1413 | | // relocations yet. |
| 1414 | | var sym_index: usize = 0; |
| 1415 | | while (sym_index < nav_state.abbrev_table.items.len) : (sym_index += 1) { |
| 1416 | | const symbol = &nav_state.abbrev_table.items[sym_index]; |
| 1417 | | const ty = symbol.type; |
| 1418 | | if (ip.isErrorSetType(ty.toIntern())) continue; |
| 1419 | | |
| 1420 | | symbol.offset = @intCast(dbg_info_buffer.items.len); |
| 1421 | | try nav_state.addDbgInfoType(pt, di_atom_index, ty); |
| 977 | }, |
| 1422 | 978 | } |
| 1423 | 979 | } |
| 980 | }; |
| 1424 | 981 | |
| 1425 | | try self.updateNavDebugInfoAllocation(di_atom_index, @intCast(dbg_info_buffer.items.len)); |
| 982 | pub const WipNav = struct { |
| 983 | dwarf: *Dwarf, |
| 984 | pt: Zcu.PerThread, |
| 985 | unit: Unit.Index, |
| 986 | entry: Entry.Index, |
| 987 | any_children: bool, |
| 988 | func: InternPool.Index, |
| 989 | func_high_reloc: u32, |
| 990 | debug_info: std.ArrayListUnmanaged(u8), |
| 991 | debug_line: std.ArrayListUnmanaged(u8), |
| 992 | debug_loclists: std.ArrayListUnmanaged(u8), |
| 993 | pending_types: std.ArrayListUnmanaged(InternPool.Index), |
| 994 | |
| 995 | pub fn deinit(wip_nav: *WipNav) void { |
| 996 | const gpa = wip_nav.dwarf.gpa; |
| 997 | wip_nav.debug_info.deinit(gpa); |
| 998 | wip_nav.debug_line.deinit(gpa); |
| 999 | wip_nav.debug_loclists.deinit(gpa); |
| 1000 | wip_nav.pending_types.deinit(gpa); |
| 1001 | } |
| 1426 | 1002 | |
| 1427 | | while (nav_state.abbrev_relocs.popOrNull()) |reloc| { |
| 1428 | | if (reloc.target) |reloc_target| { |
| 1429 | | const symbol = nav_state.abbrev_table.items[reloc_target]; |
| 1430 | | const ty = symbol.type; |
| 1431 | | if (ip.isErrorSetType(ty.toIntern())) { |
| 1432 | | log.debug("resolving %{d} deferred until flush", .{reloc_target}); |
| 1433 | | try self.global_abbrev_relocs.append(gpa, .{ |
| 1434 | | .target = null, |
| 1435 | | .offset = reloc.offset, |
| 1436 | | .atom_index = reloc.atom_index, |
| 1437 | | .addend = reloc.addend, |
| 1438 | | }); |
| 1439 | | } else { |
| 1440 | | const atom = self.getAtom(.di_atom, symbol.atom_index); |
| 1441 | | const value = atom.off + symbol.offset + reloc.addend; |
| 1442 | | log.debug("{x}: [() => {x}] (%{d}, '{}')", .{ |
| 1443 | | reloc.offset, |
| 1444 | | value, |
| 1445 | | reloc_target, |
| 1446 | | ty.fmt(pt), |
| 1447 | | }); |
| 1448 | | mem.writeInt( |
| 1449 | | u32, |
| 1450 | | dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)], |
| 1451 | | value, |
| 1452 | | target_endian, |
| 1453 | | ); |
| 1454 | | } |
| 1455 | | } else { |
| 1456 | | const atom = self.getAtom(.di_atom, reloc.atom_index); |
| 1457 | | mem.writeInt( |
| 1458 | | u32, |
| 1459 | | dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)], |
| 1460 | | atom.off + reloc.offset + reloc.addend, |
| 1461 | | target_endian, |
| 1462 | | ); |
| 1463 | | } |
| 1003 | pub fn infoWriter(wip_nav: *WipNav) std.ArrayListUnmanaged(u8).Writer { |
| 1004 | return wip_nav.debug_info.writer(wip_nav.dwarf.gpa); |
| 1464 | 1005 | } |
| 1465 | 1006 | |
| 1466 | | while (nav_state.exprloc_relocs.popOrNull()) |reloc| { |
| 1467 | | if (self.bin_file.cast(.elf)) |elf_file| { |
| 1468 | | _ = elf_file; // TODO |
| 1469 | | } else if (self.bin_file.cast(.macho)) |macho_file| { |
| 1470 | | if (macho_file.base.isRelocatable()) { |
| 1471 | | // TODO |
| 1472 | | } else { |
| 1473 | | const d_sym = macho_file.getDebugSymbols().?; |
| 1474 | | try d_sym.relocs.append(d_sym.allocator, .{ |
| 1475 | | .type = switch (reloc.type) { |
| 1476 | | .direct_load => .direct_load, |
| 1477 | | .got_load => .got_load, |
| 1478 | | }, |
| 1479 | | .target = reloc.target, |
| 1480 | | .offset = reloc.offset + self.getAtom(.di_atom, di_atom_index).off, |
| 1481 | | .addend = 0, |
| 1482 | | }); |
| 1483 | | } |
| 1484 | | } else unreachable; |
| 1007 | pub const VarTag = enum { local_arg, local_var }; |
| 1008 | pub fn genVarDebugInfo( |
| 1009 | wip_nav: *WipNav, |
| 1010 | tag: VarTag, |
| 1011 | name: []const u8, |
| 1012 | ty: Type, |
| 1013 | loc: Loc, |
| 1014 | ) UpdateError!void { |
| 1015 | wip_nav.any_children = true; |
| 1016 | assert(wip_nav.func != .none); |
| 1017 | const diw = wip_nav.debug_info.writer(wip_nav.dwarf.gpa); |
| 1018 | try uleb128(diw, @intFromEnum(switch (tag) { |
| 1019 | inline else => |ct_tag| @field(AbbrevCode, @tagName(ct_tag)), |
| 1020 | })); |
| 1021 | try wip_nav.strp(name); |
| 1022 | try wip_nav.refType(ty); |
| 1023 | try wip_nav.exprloc(loc); |
| 1485 | 1024 | } |
| 1486 | 1025 | |
| 1487 | | try self.writeNavDebugInfo(di_atom_index, dbg_info_buffer.items); |
| 1488 | | } |
| 1026 | pub fn advancePCAndLine( |
| 1027 | wip_nav: *WipNav, |
| 1028 | delta_line: i33, |
| 1029 | delta_pc: u64, |
| 1030 | ) error{OutOfMemory}!void { |
| 1031 | const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa); |
| 1489 | 1032 | |
| 1490 | | fn updateNavDebugInfoAllocation(self: *Dwarf, atom_index: Atom.Index, len: u32) !void { |
| 1491 | | const tracy = trace(@src()); |
| 1492 | | defer tracy.end(); |
| 1493 | | |
| 1494 | | // This logic is nearly identical to the logic above in `updateNav` for |
| 1495 | | // `SrcFn` and the line number programs. If you are editing this logic, you |
| 1496 | | // probably need to edit that logic too. |
| 1497 | | const gpa = self.allocator; |
| 1498 | | |
| 1499 | | const atom = self.getAtomPtr(.di_atom, atom_index); |
| 1500 | | atom.len = len; |
| 1501 | | if (self.di_atom_last_index) |last_index| blk: { |
| 1502 | | if (atom_index == last_index) break :blk; |
| 1503 | | if (atom.next_index) |next_index| { |
| 1504 | | const next = self.getAtomPtr(.di_atom, next_index); |
| 1505 | | // Update existing Nav - non-last item. |
| 1506 | | if (atom.off + atom.len + min_nop_size > next.off) { |
| 1507 | | // It grew too big, so we move it to a new location. |
| 1508 | | if (atom.prev_index) |prev_index| { |
| 1509 | | self.di_atom_free_list.put(gpa, prev_index, {}) catch {}; |
| 1510 | | self.getAtomPtr(.di_atom, prev_index).next_index = atom.next_index; |
| 1511 | | } |
| 1512 | | next.prev_index = atom.prev_index; |
| 1513 | | atom.next_index = null; |
| 1514 | | // Populate where it used to be with NOPs. |
| 1515 | | if (self.bin_file.cast(.elf)) |elf_file| { |
| 1516 | | const debug_info_sect = &elf_file.shdrs.items[elf_file.debug_info_section_index.?]; |
| 1517 | | const file_pos = debug_info_sect.sh_offset + atom.off; |
| 1518 | | try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false); |
| 1519 | | } else if (self.bin_file.cast(.macho)) |macho_file| { |
| 1520 | | if (macho_file.base.isRelocatable()) { |
| 1521 | | const debug_info_sect = macho_file.sections.items(.header)[macho_file.debug_info_sect_index.?]; |
| 1522 | | const file_pos = debug_info_sect.offset + atom.off; |
| 1523 | | try pwriteDbgInfoNops(macho_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false); |
| 1524 | | } else { |
| 1525 | | const d_sym = macho_file.getDebugSymbols().?; |
| 1526 | | const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?); |
| 1527 | | const file_pos = debug_info_sect.offset + atom.off; |
| 1528 | | try pwriteDbgInfoNops(d_sym.file, file_pos, 0, &[0]u8{}, atom.len, false); |
| 1529 | | } |
| 1530 | | } else if (self.bin_file.cast(.wasm)) |wasm_file| { |
| 1531 | | _ = wasm_file; |
| 1532 | | // const debug_info_index = wasm_file.debug_info_atom.?; |
| 1533 | | // const debug_info = &wasm_file.getAtomPtr(debug_info_index).code; |
| 1534 | | // try writeDbgInfoNopsToArrayList(gpa, debug_info, atom.off, 0, &.{0}, atom.len, false); |
| 1535 | | } else unreachable; |
| 1536 | | // TODO Look at the free list before appending at the end. |
| 1537 | | atom.prev_index = last_index; |
| 1538 | | const last = self.getAtomPtr(.di_atom, last_index); |
| 1539 | | last.next_index = atom_index; |
| 1540 | | self.di_atom_last_index = atom_index; |
| 1541 | | |
| 1542 | | atom.off = last.off + padToIdeal(last.len); |
| 1543 | | } |
| 1544 | | } else if (atom.prev_index == null) { |
| 1545 | | // Append new Nav. |
| 1546 | | // TODO Look at the free list before appending at the end. |
| 1547 | | atom.prev_index = last_index; |
| 1548 | | const last = self.getAtomPtr(.di_atom, last_index); |
| 1549 | | last.next_index = atom_index; |
| 1550 | | self.di_atom_last_index = atom_index; |
| 1551 | | |
| 1552 | | atom.off = last.off + padToIdeal(last.len); |
| 1553 | | } |
| 1554 | | } else { |
| 1555 | | // This is the first Nav of the .debug_info |
| 1556 | | self.di_atom_first_index = atom_index; |
| 1557 | | self.di_atom_last_index = atom_index; |
| 1033 | const header = wip_nav.dwarf.debug_line.header; |
| 1034 | assert(header.maximum_operations_per_instruction == 1); |
| 1035 | const delta_op: u64 = 0; |
| 1558 | 1036 | |
| 1559 | | atom.off = @intCast(padToIdeal(self.dbgInfoHeaderBytes())); |
| 1037 | const remaining_delta_line: i9 = @intCast(if (delta_line < header.line_base or |
| 1038 | delta_line - header.line_base >= header.line_range) |
| 1039 | remaining: { |
| 1040 | assert(delta_line != 0); |
| 1041 | try dlw.writeByte(DW.LNS.advance_line); |
| 1042 | try sleb128(dlw, delta_line); |
| 1043 | break :remaining 0; |
| 1044 | } else delta_line); |
| 1045 | |
| 1046 | const op_advance = @divExact(delta_pc, header.minimum_instruction_length) * |
| 1047 | header.maximum_operations_per_instruction + delta_op; |
| 1048 | const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range; |
| 1049 | const remaining_op_advance: u8 = @intCast(if (op_advance >= 2 * max_op_advance) remaining: { |
| 1050 | try dlw.writeByte(DW.LNS.advance_pc); |
| 1051 | try uleb128(dlw, op_advance); |
| 1052 | break :remaining 0; |
| 1053 | } else if (op_advance >= max_op_advance) remaining: { |
| 1054 | try dlw.writeByte(DW.LNS.const_add_pc); |
| 1055 | break :remaining op_advance - max_op_advance; |
| 1056 | } else op_advance); |
| 1057 | |
| 1058 | if (remaining_delta_line == 0 and remaining_op_advance == 0) |
| 1059 | try dlw.writeByte(DW.LNS.copy) |
| 1060 | else |
| 1061 | try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) + |
| 1062 | (header.line_range * remaining_op_advance) + header.opcode_base)); |
| 1560 | 1063 | } |
| 1561 | | } |
| 1562 | 1064 | |
| 1563 | | fn writeNavDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []const u8) !void { |
| 1564 | | const tracy = trace(@src()); |
| 1565 | | defer tracy.end(); |
| 1566 | | |
| 1567 | | // This logic is nearly identical to the logic above in `updateNav` for |
| 1568 | | // `SrcFn` and the line number programs. If you are editing this logic, you |
| 1569 | | // probably need to edit that logic too. |
| 1570 | | |
| 1571 | | const atom = self.getAtom(.di_atom, atom_index); |
| 1572 | | const last_nav_index = self.di_atom_last_index.?; |
| 1573 | | const last_nav = self.getAtom(.di_atom, last_nav_index); |
| 1574 | | // +1 for a trailing zero to end the children of the nav tag. |
| 1575 | | const needed_size = last_nav.off + last_nav.len + 1; |
| 1576 | | const prev_padding_size: u32 = if (atom.prev_index) |prev_index| blk: { |
| 1577 | | const prev = self.getAtom(.di_atom, prev_index); |
| 1578 | | break :blk atom.off - (prev.off + prev.len); |
| 1579 | | } else 0; |
| 1580 | | const next_padding_size: u32 = if (atom.next_index) |next_index| blk: { |
| 1581 | | const next = self.getAtom(.di_atom, next_index); |
| 1582 | | break :blk next.off - (atom.off + atom.len); |
| 1583 | | } else 0; |
| 1584 | | |
| 1585 | | // To end the children of the nav tag. |
| 1586 | | const trailing_zero = atom.next_index == null; |
| 1587 | | |
| 1588 | | // We only have support for one compilation unit so far, so the offsets are directly |
| 1589 | | // from the .debug_info section. |
| 1590 | | if (self.bin_file.cast(.elf)) |elf_file| { |
| 1591 | | const shdr_index = elf_file.debug_info_section_index.?; |
| 1592 | | try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true); |
| 1593 | | const debug_info_sect = &elf_file.shdrs.items[shdr_index]; |
| 1594 | | const file_pos = debug_info_sect.sh_offset + atom.off; |
| 1595 | | try pwriteDbgInfoNops( |
| 1596 | | elf_file.base.file.?, |
| 1597 | | file_pos, |
| 1598 | | prev_padding_size, |
| 1599 | | dbg_info_buf, |
| 1600 | | next_padding_size, |
| 1601 | | trailing_zero, |
| 1602 | | ); |
| 1603 | | } else if (self.bin_file.cast(.macho)) |macho_file| { |
| 1604 | | if (macho_file.base.isRelocatable()) { |
| 1605 | | const sect_index = macho_file.debug_info_sect_index.?; |
| 1606 | | try macho_file.growSection(sect_index, needed_size); |
| 1607 | | const sect = macho_file.sections.items(.header)[sect_index]; |
| 1608 | | const file_pos = sect.offset + atom.off; |
| 1609 | | try pwriteDbgInfoNops( |
| 1610 | | macho_file.base.file.?, |
| 1611 | | file_pos, |
| 1612 | | prev_padding_size, |
| 1613 | | dbg_info_buf, |
| 1614 | | next_padding_size, |
| 1615 | | trailing_zero, |
| 1616 | | ); |
| 1617 | | } else { |
| 1618 | | const d_sym = macho_file.getDebugSymbols().?; |
| 1619 | | const sect_index = d_sym.debug_info_section_index.?; |
| 1620 | | try d_sym.growSection(sect_index, needed_size, true, macho_file); |
| 1621 | | const sect = d_sym.getSection(sect_index); |
| 1622 | | const file_pos = sect.offset + atom.off; |
| 1623 | | try pwriteDbgInfoNops( |
| 1624 | | d_sym.file, |
| 1625 | | file_pos, |
| 1626 | | prev_padding_size, |
| 1627 | | dbg_info_buf, |
| 1628 | | next_padding_size, |
| 1629 | | trailing_zero, |
| 1630 | | ); |
| 1631 | | } |
| 1632 | | } else if (self.bin_file.cast(.wasm)) |wasm_file| { |
| 1633 | | _ = wasm_file; |
| 1634 | | // const info_atom = wasm_file.debug_info_atom.?; |
| 1635 | | // const debug_info = &wasm_file.getAtomPtr(info_atom).code; |
| 1636 | | // const segment_size = debug_info.items.len; |
| 1637 | | // if (needed_size != segment_size) { |
| 1638 | | // log.debug(" needed size does not equal allocated size: {d}", .{needed_size}); |
| 1639 | | // if (needed_size > segment_size) { |
| 1640 | | // log.debug(" allocating {d} bytes for 'debug info' information", .{needed_size - segment_size}); |
| 1641 | | // try debug_info.resize(self.allocator, needed_size); |
| 1642 | | // @memset(debug_info.items[segment_size..], 0); |
| 1643 | | // } |
| 1644 | | // debug_info.items.len = needed_size; |
| 1645 | | // } |
| 1646 | | // log.debug(" writeDbgInfoNopsToArrayList debug_info_len={d} offset={d} content_len={d} next_padding_size={d}", .{ |
| 1647 | | // debug_info.items.len, atom.off, dbg_info_buf.len, next_padding_size, |
| 1648 | | // }); |
| 1649 | | // try writeDbgInfoNopsToArrayList( |
| 1650 | | // gpa, |
| 1651 | | // debug_info, |
| 1652 | | // atom.off, |
| 1653 | | // prev_padding_size, |
| 1654 | | // dbg_info_buf, |
| 1655 | | // next_padding_size, |
| 1656 | | // trailing_zero, |
| 1657 | | // ); |
| 1658 | | } else unreachable; |
| 1659 | | } |
| 1065 | pub fn setColumn(wip_nav: *WipNav, column: u32) error{OutOfMemory}!void { |
| 1066 | const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa); |
| 1067 | try dlw.writeByte(DW.LNS.set_column); |
| 1068 | try uleb128(dlw, column + 1); |
| 1069 | } |
| 1660 | 1070 | |
| 1661 | | pub fn updateNavLineNumber(self: *Dwarf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !void { |
| 1662 | | const tracy = trace(@src()); |
| 1663 | | defer tracy.end(); |
| 1664 | | |
| 1665 | | const atom_index = try self.getOrCreateAtomForNav(.src_fn, nav_index); |
| 1666 | | const atom = self.getAtom(.src_fn, atom_index); |
| 1667 | | if (atom.len == 0) return; |
| 1668 | | |
| 1669 | | const nav = zcu.intern_pool.getNav(nav_index); |
| 1670 | | const nav_val = Value.fromInterned(nav.status.resolved.val); |
| 1671 | | const func = nav_val.getFunction(zcu).?; |
| 1672 | | log.debug("src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{ |
| 1673 | | zcu.navSrcLine(nav_index), |
| 1674 | | func.lbrace_line, |
| 1675 | | func.rbrace_line, |
| 1676 | | }); |
| 1677 | | const line: u28 = @intCast(zcu.navSrcLine(nav_index) + func.lbrace_line); |
| 1678 | | var data: [4]u8 = undefined; |
| 1679 | | leb128.writeUnsignedFixed(4, &data, line); |
| 1680 | | |
| 1681 | | switch (self.bin_file.tag) { |
| 1682 | | .elf => { |
| 1683 | | const elf_file = self.bin_file.cast(File.Elf).?; |
| 1684 | | const shdr = elf_file.shdrs.items[elf_file.debug_line_section_index.?]; |
| 1685 | | const file_pos = shdr.sh_offset + atom.off + self.getRelocDbgLineOff(); |
| 1686 | | try elf_file.base.file.?.pwriteAll(&data, file_pos); |
| 1687 | | }, |
| 1688 | | .macho => { |
| 1689 | | const macho_file = self.bin_file.cast(File.MachO).?; |
| 1690 | | if (macho_file.base.isRelocatable()) { |
| 1691 | | const sect = macho_file.sections.items(.header)[macho_file.debug_line_sect_index.?]; |
| 1692 | | const file_pos = sect.offset + atom.off + self.getRelocDbgLineOff(); |
| 1693 | | try macho_file.base.file.?.pwriteAll(&data, file_pos); |
| 1694 | | } else { |
| 1695 | | const d_sym = macho_file.getDebugSymbols().?; |
| 1696 | | const sect = d_sym.getSection(d_sym.debug_line_section_index.?); |
| 1697 | | const file_pos = sect.offset + atom.off + self.getRelocDbgLineOff(); |
| 1698 | | try d_sym.file.pwriteAll(&data, file_pos); |
| 1699 | | } |
| 1700 | | }, |
| 1701 | | .wasm => { |
| 1702 | | // const wasm_file = self.bin_file.cast(File.Wasm).?; |
| 1703 | | // const offset = atom.off + self.getRelocDbgLineOff(); |
| 1704 | | // const line_atom_index = wasm_file.debug_line_atom.?; |
| 1705 | | // wasm_file.getAtomPtr(line_atom_index).code.items[offset..][0..data.len].* = data; |
| 1706 | | }, |
| 1707 | | else => unreachable, |
| 1071 | pub fn setPrologueEnd(wip_nav: *WipNav) error{OutOfMemory}!void { |
| 1072 | const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa); |
| 1073 | try dlw.writeByte(DW.LNS.set_prologue_end); |
| 1708 | 1074 | } |
| 1709 | | } |
| 1710 | 1075 | |
| 1711 | | pub fn freeNav(self: *Dwarf, nav_index: InternPool.Nav.Index) void { |
| 1712 | | const gpa = self.allocator; |
| 1713 | | |
| 1714 | | // Free SrcFn atom |
| 1715 | | if (self.src_fn_navs.fetchRemove(nav_index)) |kv| { |
| 1716 | | const src_fn_index = kv.value; |
| 1717 | | const src_fn = self.getAtom(.src_fn, src_fn_index); |
| 1718 | | _ = self.src_fn_free_list.remove(src_fn_index); |
| 1719 | | |
| 1720 | | if (src_fn.prev_index) |prev_index| { |
| 1721 | | self.src_fn_free_list.put(gpa, prev_index, {}) catch {}; |
| 1722 | | const prev = self.getAtomPtr(.src_fn, prev_index); |
| 1723 | | prev.next_index = src_fn.next_index; |
| 1724 | | if (src_fn.next_index) |next_index| { |
| 1725 | | self.getAtomPtr(.src_fn, next_index).prev_index = prev_index; |
| 1726 | | } else { |
| 1727 | | self.src_fn_last_index = prev_index; |
| 1728 | | } |
| 1729 | | } else if (src_fn.next_index) |next_index| { |
| 1730 | | self.src_fn_first_index = next_index; |
| 1731 | | self.getAtomPtr(.src_fn, next_index).prev_index = null; |
| 1732 | | } |
| 1733 | | if (self.src_fn_first_index == src_fn_index) { |
| 1734 | | self.src_fn_first_index = src_fn.next_index; |
| 1735 | | } |
| 1736 | | if (self.src_fn_last_index == src_fn_index) { |
| 1737 | | self.src_fn_last_index = src_fn.prev_index; |
| 1738 | | } |
| 1076 | pub fn setEpilogueBegin(wip_nav: *WipNav) error{OutOfMemory}!void { |
| 1077 | const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa); |
| 1078 | try dlw.writeByte(DW.LNS.set_epilogue_begin); |
| 1739 | 1079 | } |
| 1740 | 1080 | |
| 1741 | | // Free DI atom |
| 1742 | | if (self.di_atom_navs.fetchRemove(nav_index)) |kv| { |
| 1743 | | const di_atom_index = kv.value; |
| 1744 | | const di_atom = self.getAtomPtr(.di_atom, di_atom_index); |
| 1081 | pub fn setInlineFunc(wip_nav: *WipNav, func: InternPool.Index) UpdateError!void { |
| 1082 | const zcu = wip_nav.pt.zcu; |
| 1083 | const dwarf = wip_nav.dwarf; |
| 1084 | if (wip_nav.func == func) return; |
| 1745 | 1085 | |
| 1746 | | if (self.di_atom_first_index == di_atom_index) { |
| 1747 | | self.di_atom_first_index = di_atom.next_index; |
| 1748 | | } |
| 1749 | | if (self.di_atom_last_index == di_atom_index) { |
| 1750 | | // TODO shrink the .debug_info section size here |
| 1751 | | self.di_atom_last_index = di_atom.prev_index; |
| 1086 | const new_func_info = zcu.funcInfo(func); |
| 1087 | const new_file = zcu.navFileScopeIndex(new_func_info.owner_nav); |
| 1088 | const new_unit = try dwarf.getUnit(zcu.fileByIndex(new_file).mod); |
| 1089 | |
| 1090 | const dlw = wip_nav.debug_line.writer(dwarf.gpa); |
| 1091 | if (dwarf.incremental()) { |
| 1092 | const new_nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, new_func_info.owner_nav); |
| 1093 | errdefer _ = dwarf.navs.pop(); |
| 1094 | if (!new_nav_gop.found_existing) new_nav_gop.value_ptr.* = try dwarf.addCommonEntry(new_unit); |
| 1095 | |
| 1096 | try dlw.writeByte(DW.LNS.extended_op); |
| 1097 | try uleb128(dlw, 1 + dwarf.sectionOffsetBytes()); |
| 1098 | try dlw.writeByte(DW.LNE.ZIG_set_decl); |
| 1099 | try dwarf.debug_line.section.getUnit(wip_nav.unit).cross_section_relocs.append(dwarf.gpa, .{ |
| 1100 | .source_entry = wip_nav.entry.toOptional(), |
| 1101 | .source_off = @intCast(wip_nav.debug_line.items.len), |
| 1102 | .target_sec = .debug_info, |
| 1103 | .target_unit = new_unit, |
| 1104 | .target_entry = new_nav_gop.value_ptr.toOptional(), |
| 1105 | }); |
| 1106 | try dlw.writeByteNTimes(0, dwarf.sectionOffsetBytes()); |
| 1107 | return; |
| 1752 | 1108 | } |
| 1753 | 1109 | |
| 1754 | | if (di_atom.prev_index) |prev_index| { |
| 1755 | | self.getAtomPtr(.di_atom, prev_index).next_index = di_atom.next_index; |
| 1756 | | // TODO the free list logic like we do for SrcFn above |
| 1757 | | } else { |
| 1758 | | di_atom.prev_index = null; |
| 1110 | const old_func_info = zcu.funcInfo(wip_nav.func); |
| 1111 | const old_file = zcu.navFileScopeIndex(old_func_info.owner_nav); |
| 1112 | if (old_file != new_file) { |
| 1113 | const mod_info = dwarf.getModInfo(wip_nav.unit); |
| 1114 | const mod_gop = try mod_info.dirs.getOrPut(dwarf.gpa, new_unit); |
| 1115 | errdefer _ = if (!mod_gop.found_existing) mod_info.dirs.pop(); |
| 1116 | const file_gop = try mod_info.files.getOrPut(dwarf.gpa, new_file); |
| 1117 | errdefer _ = if (!file_gop.found_existing) mod_info.files.pop(); |
| 1118 | |
| 1119 | try dlw.writeByte(DW.LNS.set_file); |
| 1120 | try uleb128(dlw, file_gop.index); |
| 1759 | 1121 | } |
| 1760 | 1122 | |
| 1761 | | if (di_atom.next_index) |next_index| { |
| 1762 | | self.getAtomPtr(.di_atom, next_index).prev_index = di_atom.prev_index; |
| 1763 | | } else { |
| 1764 | | di_atom.next_index = null; |
| 1123 | const old_src_line: i33 = zcu.navSrcLine(old_func_info.owner_nav); |
| 1124 | const new_src_line: i33 = zcu.navSrcLine(new_func_info.owner_nav); |
| 1125 | if (new_src_line != old_src_line) { |
| 1126 | try dlw.writeByte(DW.LNS.advance_line); |
| 1127 | try sleb128(dlw, new_src_line - old_src_line); |
| 1765 | 1128 | } |
| 1129 | |
| 1130 | wip_nav.func = func; |
| 1766 | 1131 | } |
| 1767 | | } |
| 1768 | 1132 | |
| 1769 | | pub fn writeDbgAbbrev(self: *Dwarf) !void { |
| 1770 | | // These are LEB encoded but since the values are all less than 127 |
| 1771 | | // we can simply append these bytes. |
| 1772 | | // zig fmt: off |
| 1773 | | const abbrev_buf = [_]u8{ |
| 1774 | | @intFromEnum(AbbrevCode.padding), |
| 1775 | | @as(u8, 0x80) | @as(u7, @truncate(DW.TAG.ZIG_padding >> 0)), |
| 1776 | | @as(u8, 0x80) | @as(u7, @truncate(DW.TAG.ZIG_padding >> 7)), |
| 1777 | | @as(u8, 0x00) | @as(u7, @intCast(DW.TAG.ZIG_padding >> 14)), |
| 1778 | | DW.CHILDREN.no, |
| 1779 | | 0, 0, |
| 1780 | | |
| 1781 | | @intFromEnum(AbbrevCode.compile_unit), |
| 1782 | | DW.TAG.compile_unit, |
| 1783 | | DW.CHILDREN.yes, |
| 1784 | | DW.AT.stmt_list, DW.FORM.sec_offset, |
| 1785 | | DW.AT.low_pc, DW.FORM.addr, |
| 1786 | | DW.AT.high_pc, DW.FORM.addr, |
| 1787 | | DW.AT.name, DW.FORM.strp, |
| 1788 | | DW.AT.comp_dir, DW.FORM.strp, |
| 1789 | | DW.AT.producer, DW.FORM.strp, |
| 1790 | | DW.AT.language, DW.FORM.data2, |
| 1791 | | 0, 0, |
| 1792 | | |
| 1793 | | @intFromEnum(AbbrevCode.subprogram), |
| 1794 | | DW.TAG.subprogram, |
| 1795 | | DW.CHILDREN.yes, |
| 1796 | | DW.AT.low_pc, DW.FORM.addr, |
| 1797 | | DW.AT.high_pc, DW.FORM.data4, |
| 1798 | | DW.AT.type, DW.FORM.ref4, |
| 1799 | | DW.AT.name, DW.FORM.string, |
| 1800 | | DW.AT.linkage_name, DW.FORM.string, |
| 1801 | | 0, 0, |
| 1802 | | |
| 1803 | | @intFromEnum(AbbrevCode.subprogram_retvoid), |
| 1804 | | DW.TAG.subprogram, |
| 1805 | | DW.CHILDREN.yes, |
| 1806 | | DW.AT.low_pc, DW.FORM.addr, |
| 1807 | | DW.AT.high_pc, DW.FORM.data4, |
| 1808 | | DW.AT.name, DW.FORM.string, |
| 1809 | | DW.AT.linkage_name, DW.FORM.string, |
| 1810 | | 0, 0, |
| 1811 | | |
| 1812 | | @intFromEnum(AbbrevCode.base_type), |
| 1813 | | DW.TAG.base_type, DW.CHILDREN.no, |
| 1814 | | DW.AT.encoding, DW.FORM.data1, |
| 1815 | | DW.AT.byte_size, DW.FORM.udata, |
| 1816 | | DW.AT.name, DW.FORM.string, |
| 1817 | | 0, 0, |
| 1818 | | |
| 1819 | | @intFromEnum(AbbrevCode.ptr_type), |
| 1820 | | DW.TAG.pointer_type, DW.CHILDREN.no, |
| 1821 | | DW.AT.type, DW.FORM.ref4, |
| 1822 | | 0, 0, |
| 1823 | | |
| 1824 | | @intFromEnum(AbbrevCode.struct_type), |
| 1825 | | DW.TAG.structure_type, DW.CHILDREN.yes, |
| 1826 | | DW.AT.byte_size, DW.FORM.udata, |
| 1827 | | DW.AT.name, DW.FORM.string, |
| 1828 | | 0, 0, |
| 1829 | | |
| 1830 | | @intFromEnum(AbbrevCode.struct_member), |
| 1831 | | DW.TAG.member, |
| 1832 | | DW.CHILDREN.no, |
| 1833 | | DW.AT.name, DW.FORM.string, |
| 1834 | | DW.AT.type, DW.FORM.ref4, |
| 1835 | | DW.AT.data_member_location, DW.FORM.udata, |
| 1836 | | 0, 0, |
| 1837 | | |
| 1838 | | @intFromEnum(AbbrevCode.enum_type), |
| 1839 | | DW.TAG.enumeration_type, |
| 1840 | | DW.CHILDREN.yes, |
| 1841 | | DW.AT.byte_size, DW.FORM.udata, |
| 1842 | | DW.AT.name, DW.FORM.string, |
| 1843 | | 0, 0, |
| 1844 | | |
| 1845 | | @intFromEnum(AbbrevCode.enum_variant), |
| 1846 | | DW.TAG.enumerator, DW.CHILDREN.no, |
| 1847 | | DW.AT.name, DW.FORM.string, |
| 1848 | | DW.AT.const_value, DW.FORM.data8, |
| 1849 | | 0, 0, |
| 1850 | | |
| 1851 | | @intFromEnum(AbbrevCode.union_type), |
| 1852 | | DW.TAG.union_type, DW.CHILDREN.yes, |
| 1853 | | DW.AT.byte_size, DW.FORM.udata, |
| 1854 | | DW.AT.name, DW.FORM.string, |
| 1855 | | 0, 0, |
| 1856 | | |
| 1857 | | @intFromEnum(AbbrevCode.zero_bit_type), |
| 1858 | | DW.TAG.unspecified_type, |
| 1859 | | DW.CHILDREN.no, |
| 1860 | | 0, 0, |
| 1861 | | |
| 1862 | | @intFromEnum(AbbrevCode.parameter), |
| 1863 | | DW.TAG.formal_parameter, |
| 1864 | | DW.CHILDREN.no, |
| 1865 | | DW.AT.location, DW.FORM.exprloc, |
| 1866 | | DW.AT.type, DW.FORM.ref4, |
| 1867 | | DW.AT.name, DW.FORM.string, |
| 1868 | | 0, 0, |
| 1869 | | |
| 1870 | | @intFromEnum(AbbrevCode.variable), |
| 1871 | | DW.TAG.variable, |
| 1872 | | DW.CHILDREN.no, |
| 1873 | | DW.AT.location, DW.FORM.exprloc, |
| 1874 | | DW.AT.type, DW.FORM.ref4, |
| 1875 | | DW.AT.name, DW.FORM.string, |
| 1876 | | 0, 0, |
| 1877 | | |
| 1878 | | @intFromEnum(AbbrevCode.array_type), |
| 1879 | | DW.TAG.array_type, |
| 1880 | | DW.CHILDREN.yes, |
| 1881 | | DW.AT.name, DW.FORM.string, |
| 1882 | | DW.AT.type, DW.FORM.ref4, |
| 1883 | | 0, 0, |
| 1884 | | |
| 1885 | | @intFromEnum(AbbrevCode.array_dim), |
| 1886 | | DW.TAG.subrange_type, |
| 1887 | | DW.CHILDREN.no, |
| 1888 | | DW.AT.type, DW.FORM.ref4, |
| 1889 | | DW.AT.count, DW.FORM.udata, |
| 1890 | | 0, 0, |
| 1891 | | |
| 1892 | | 0, |
| 1893 | | }; |
| 1894 | | // zig fmt: on |
| 1895 | | const abbrev_offset = 0; |
| 1896 | | self.abbrev_table_offset = abbrev_offset; |
| 1897 | | |
| 1898 | | const needed_size = abbrev_buf.len; |
| 1899 | | if (self.bin_file.cast(.elf)) |elf_file| { |
| 1900 | | const shdr_index = elf_file.debug_abbrev_section_index.?; |
| 1901 | | try elf_file.growNonAllocSection(shdr_index, needed_size, 1, false); |
| 1902 | | const debug_abbrev_sect = &elf_file.shdrs.items[shdr_index]; |
| 1903 | | const file_pos = debug_abbrev_sect.sh_offset + abbrev_offset; |
| 1904 | | try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos); |
| 1905 | | } else if (self.bin_file.cast(.macho)) |macho_file| { |
| 1906 | | if (macho_file.base.isRelocatable()) { |
| 1907 | | const sect_index = macho_file.debug_abbrev_sect_index.?; |
| 1908 | | try macho_file.growSection(sect_index, needed_size); |
| 1909 | | const sect = macho_file.sections.items(.header)[sect_index]; |
| 1910 | | const file_pos = sect.offset + abbrev_offset; |
| 1911 | | try macho_file.base.file.?.pwriteAll(&abbrev_buf, file_pos); |
| 1133 | fn infoSectionOffset(wip_nav: *WipNav, sec: Section.Index, unit: Unit.Index, entry: Entry.Index, off: u32) UpdateError!void { |
| 1134 | const dwarf = wip_nav.dwarf; |
| 1135 | const gpa = dwarf.gpa; |
| 1136 | if (sec != .debug_info) { |
| 1137 | try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_section_relocs.append(gpa, .{ |
| 1138 | .source_entry = wip_nav.entry.toOptional(), |
| 1139 | .source_off = @intCast(wip_nav.debug_info.items.len), |
| 1140 | .target_sec = sec, |
| 1141 | .target_unit = unit, |
| 1142 | .target_entry = entry.toOptional(), |
| 1143 | .target_off = off, |
| 1144 | }); |
| 1145 | } else if (unit != wip_nav.unit) { |
| 1146 | try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_unit_relocs.append(gpa, .{ |
| 1147 | .source_entry = wip_nav.entry.toOptional(), |
| 1148 | .source_off = @intCast(wip_nav.debug_info.items.len), |
| 1149 | .target_unit = unit, |
| 1150 | .target_entry = entry.toOptional(), |
| 1151 | .target_off = off, |
| 1152 | }); |
| 1912 | 1153 | } else { |
| 1913 | | const d_sym = macho_file.getDebugSymbols().?; |
| 1914 | | const sect_index = d_sym.debug_abbrev_section_index.?; |
| 1915 | | try d_sym.growSection(sect_index, needed_size, false, macho_file); |
| 1916 | | const sect = d_sym.getSection(sect_index); |
| 1917 | | const file_pos = sect.offset + abbrev_offset; |
| 1918 | | try d_sym.file.pwriteAll(&abbrev_buf, file_pos); |
| 1154 | try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs.append(gpa, .{ |
| 1155 | .source_entry = wip_nav.entry.toOptional(), |
| 1156 | .source_off = @intCast(wip_nav.debug_info.items.len), |
| 1157 | .target_entry = entry, |
| 1158 | .target_off = off, |
| 1159 | }); |
| 1919 | 1160 | } |
| 1920 | | } else if (self.bin_file.cast(.wasm)) |wasm_file| { |
| 1921 | | _ = wasm_file; |
| 1922 | | // const debug_abbrev = &wasm_file.getAtomPtr(wasm_file.debug_abbrev_atom.?).code; |
| 1923 | | // try debug_abbrev.resize(gpa, needed_size); |
| 1924 | | // debug_abbrev.items[0..abbrev_buf.len].* = abbrev_buf; |
| 1925 | | } else unreachable; |
| 1926 | | } |
| 1927 | | |
| 1928 | | fn dbgInfoHeaderBytes(self: *Dwarf) usize { |
| 1929 | | _ = self; |
| 1930 | | return 120; |
| 1931 | | } |
| 1161 | try wip_nav.debug_info.appendNTimes(gpa, 0, dwarf.sectionOffsetBytes()); |
| 1162 | } |
| 1932 | 1163 | |
| 1933 | | pub fn writeDbgInfoHeader(self: *Dwarf, zcu: *Zcu, low_pc: u64, high_pc: u64) !void { |
| 1934 | | // If this value is null it means there is an error in the module; |
| 1935 | | // leave debug_info_header_dirty=true. |
| 1936 | | const first_dbg_info_off = self.getDebugInfoOff() orelse return; |
| 1164 | fn strp(wip_nav: *WipNav, str: []const u8) UpdateError!void { |
| 1165 | try wip_nav.infoSectionOffset(.debug_str, StringSection.unit, try wip_nav.dwarf.debug_str.addString(wip_nav.dwarf, str), 0); |
| 1166 | } |
| 1937 | 1167 | |
| 1938 | | // We have a function to compute the upper bound size, because it's needed |
| 1939 | | // for determining where to put the offset of the first `LinkBlock`. |
| 1940 | | const needed_bytes = self.dbgInfoHeaderBytes(); |
| 1941 | | var di_buf = try std.ArrayList(u8).initCapacity(self.allocator, needed_bytes); |
| 1942 | | defer di_buf.deinit(); |
| 1168 | fn addrSym(wip_nav: *WipNav, sym_index: u32) UpdateError!void { |
| 1169 | const dwarf = wip_nav.dwarf; |
| 1170 | try dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{ |
| 1171 | .source_entry = wip_nav.entry, |
| 1172 | .source_off = @intCast(wip_nav.debug_info.items.len), |
| 1173 | .target_sym = sym_index, |
| 1174 | }); |
| 1175 | try wip_nav.debug_info.appendNTimes(dwarf.gpa, 0, @intFromEnum(dwarf.address_size)); |
| 1176 | } |
| 1943 | 1177 | |
| 1944 | | const comp = self.bin_file.comp; |
| 1945 | | const target = comp.root_mod.resolved_target.result; |
| 1946 | | const target_endian = target.cpu.arch.endian(); |
| 1947 | | const init_len_size: usize = switch (self.format) { |
| 1948 | | .dwarf32 => 4, |
| 1949 | | .dwarf64 => 12, |
| 1950 | | }; |
| 1178 | fn exprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void { |
| 1179 | if (loc == .empty) return; |
| 1180 | var wip: struct { |
| 1181 | const Info = std.io.CountingWriter(std.io.NullWriter); |
| 1182 | dwarf: *Dwarf, |
| 1183 | debug_info: Info, |
| 1184 | fn infoWriter(wip: *@This()) Info.Writer { |
| 1185 | return wip.debug_info.writer(); |
| 1186 | } |
| 1187 | fn addrSym(wip: *@This(), _: u32) error{}!void { |
| 1188 | wip.debug_info.bytes_written += @intFromEnum(wip.dwarf.address_size); |
| 1189 | } |
| 1190 | } = .{ |
| 1191 | .dwarf = wip_nav.dwarf, |
| 1192 | .debug_info = std.io.countingWriter(std.io.null_writer), |
| 1193 | }; |
| 1194 | try loc.write(&wip); |
| 1195 | try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), wip.debug_info.bytes_written); |
| 1196 | try loc.write(wip_nav); |
| 1197 | } |
| 1951 | 1198 | |
| 1952 | | // initial length - length of the .debug_info contribution for this compilation unit, |
| 1953 | | // not including the initial length itself. |
| 1954 | | // We have to come back and write it later after we know the size. |
| 1955 | | const after_init_len = di_buf.items.len + init_len_size; |
| 1956 | | const dbg_info_end = self.getDebugInfoEnd().?; |
| 1957 | | const init_len = dbg_info_end - after_init_len + 1; |
| 1958 | | |
| 1959 | | if (self.format == .dwarf64) di_buf.appendNTimesAssumeCapacity(0xff, 4); |
| 1960 | | self.writeOffsetAssumeCapacity(&di_buf, init_len); |
| 1961 | | |
| 1962 | | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version |
| 1963 | | const abbrev_offset = self.abbrev_table_offset.?; |
| 1964 | | |
| 1965 | | self.writeOffsetAssumeCapacity(&di_buf, abbrev_offset); |
| 1966 | | di_buf.appendAssumeCapacity(self.ptrWidthBytes()); // address size |
| 1967 | | |
| 1968 | | // Write the form for the compile unit, which must match the abbrev table above. |
| 1969 | | const name_strp = try self.strtab.insert(self.allocator, zcu.root_mod.root_src_path); |
| 1970 | | var compile_unit_dir_buffer: [std.fs.max_path_bytes]u8 = undefined; |
| 1971 | | const compile_unit_dir = resolveCompilationDir(zcu, &compile_unit_dir_buffer); |
| 1972 | | const comp_dir_strp = try self.strtab.insert(self.allocator, compile_unit_dir); |
| 1973 | | const producer_strp = try self.strtab.insert(self.allocator, link.producer_string); |
| 1974 | | |
| 1975 | | di_buf.appendAssumeCapacity(@intFromEnum(AbbrevCode.compile_unit)); |
| 1976 | | self.writeOffsetAssumeCapacity(&di_buf, 0); // DW.AT.stmt_list, DW.FORM.sec_offset |
| 1977 | | self.writeAddrAssumeCapacity(&di_buf, low_pc); |
| 1978 | | self.writeAddrAssumeCapacity(&di_buf, high_pc); |
| 1979 | | self.writeOffsetAssumeCapacity(&di_buf, name_strp); |
| 1980 | | self.writeOffsetAssumeCapacity(&di_buf, comp_dir_strp); |
| 1981 | | self.writeOffsetAssumeCapacity(&di_buf, producer_strp); |
| 1982 | | |
| 1983 | | // We are still waiting on dwarf-std.org to assign DW_LANG_Zig a number: |
| 1984 | | // http://dwarfstd.org/ShowIssue.php?issue=171115.1 |
| 1985 | | // Until then we say it is C99. |
| 1986 | | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), DW.LANG.C99, target_endian); |
| 1987 | | |
| 1988 | | if (di_buf.items.len > first_dbg_info_off) { |
| 1989 | | // Move the first N navs to the end to make more padding for the header. |
| 1990 | | @panic("TODO: handle .debug_info header exceeding its padding"); |
| 1991 | | } |
| 1992 | | const jmp_amt = first_dbg_info_off - di_buf.items.len; |
| 1993 | | if (self.bin_file.cast(.elf)) |elf_file| { |
| 1994 | | const debug_info_sect = &elf_file.shdrs.items[elf_file.debug_info_section_index.?]; |
| 1995 | | const file_pos = debug_info_sect.sh_offset; |
| 1996 | | try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false); |
| 1997 | | } else if (self.bin_file.cast(.macho)) |macho_file| { |
| 1998 | | if (macho_file.base.isRelocatable()) { |
| 1999 | | const debug_info_sect = macho_file.sections.items(.header)[macho_file.debug_info_sect_index.?]; |
| 2000 | | const file_pos = debug_info_sect.offset; |
| 2001 | | try pwriteDbgInfoNops(macho_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false); |
| 2002 | | } else { |
| 2003 | | const d_sym = macho_file.getDebugSymbols().?; |
| 2004 | | const debug_info_sect = d_sym.getSection(d_sym.debug_info_section_index.?); |
| 2005 | | const file_pos = debug_info_sect.offset; |
| 2006 | | try pwriteDbgInfoNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt, false); |
| 2007 | | } |
| 2008 | | } else if (self.bin_file.cast(.wasm)) |wasm_file| { |
| 2009 | | _ = wasm_file; |
| 2010 | | // const debug_info = &wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code; |
| 2011 | | // try writeDbgInfoNopsToArrayList(self.allocator, debug_info, 0, 0, di_buf.items, jmp_amt, false); |
| 2012 | | } else unreachable; |
| 2013 | | } |
| 1199 | fn getTypeEntry(wip_nav: *WipNav, ty: Type) UpdateError!struct { Unit.Index, Entry.Index } { |
| 1200 | const zcu = wip_nav.pt.zcu; |
| 1201 | const ip = &zcu.intern_pool; |
| 1202 | const maybe_inst_index = ty.typeDeclInst(zcu); |
| 1203 | const unit = if (maybe_inst_index) |inst_index| |
| 1204 | try wip_nav.dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFull(ip).file).mod) |
| 1205 | else |
| 1206 | .main; |
| 1207 | const gop = try wip_nav.dwarf.types.getOrPut(wip_nav.dwarf.gpa, ty.toIntern()); |
| 1208 | if (gop.found_existing) return .{ unit, gop.value_ptr.* }; |
| 1209 | const entry = try wip_nav.dwarf.addCommonEntry(unit); |
| 1210 | gop.value_ptr.* = entry; |
| 1211 | if (maybe_inst_index == null) try wip_nav.pending_types.append(wip_nav.dwarf.gpa, ty.toIntern()); |
| 1212 | return .{ unit, entry }; |
| 1213 | } |
| 2014 | 1214 | |
| 2015 | | fn resolveCompilationDir(zcu: *Zcu, buffer: *[std.fs.max_path_bytes]u8) []const u8 { |
| 2016 | | // We fully resolve all paths at this point to avoid lack of source line info in stack |
| 2017 | | // traces or lack of debugging information which, if relative paths were used, would |
| 2018 | | // be very location dependent. |
| 2019 | | // TODO: the only concern I have with this is WASI as either host or target, should |
| 2020 | | // we leave the paths as relative then? |
| 2021 | | const root_dir_path = zcu.root_mod.root.root_dir.path orelse "."; |
| 2022 | | const sub_path = zcu.root_mod.root.sub_path; |
| 2023 | | const realpath = if (std.fs.path.isAbsolute(root_dir_path)) r: { |
| 2024 | | @memcpy(buffer[0..root_dir_path.len], root_dir_path); |
| 2025 | | break :r root_dir_path; |
| 2026 | | } else std.fs.realpath(root_dir_path, buffer) catch return root_dir_path; |
| 2027 | | const len = realpath.len + 1 + sub_path.len; |
| 2028 | | if (buffer.len < len) return root_dir_path; |
| 2029 | | buffer[realpath.len] = '/'; |
| 2030 | | @memcpy(buffer[realpath.len + 1 ..][0..sub_path.len], sub_path); |
| 2031 | | return buffer[0..len]; |
| 2032 | | } |
| 1215 | fn refType(wip_nav: *WipNav, ty: Type) UpdateError!void { |
| 1216 | const unit, const entry = try wip_nav.getTypeEntry(ty); |
| 1217 | try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0); |
| 1218 | } |
| 2033 | 1219 | |
| 2034 | | fn writeAddrAssumeCapacity(self: *Dwarf, buf: *std.ArrayList(u8), addr: u64) void { |
| 2035 | | const comp = self.bin_file.comp; |
| 2036 | | const target = comp.root_mod.resolved_target.result; |
| 2037 | | const target_endian = target.cpu.arch.endian(); |
| 2038 | | switch (self.ptr_width) { |
| 2039 | | .p32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @intCast(addr), target_endian), |
| 2040 | | .p64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), addr, target_endian), |
| 1220 | fn refForward(wip_nav: *WipNav) std.mem.Allocator.Error!u32 { |
| 1221 | const dwarf = wip_nav.dwarf; |
| 1222 | const cross_entry_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs; |
| 1223 | const reloc_index: u32 = @intCast(cross_entry_relocs.items.len); |
| 1224 | try cross_entry_relocs.append(dwarf.gpa, .{ |
| 1225 | .source_entry = wip_nav.entry.toOptional(), |
| 1226 | .source_off = @intCast(wip_nav.debug_info.items.len), |
| 1227 | .target_entry = undefined, |
| 1228 | .target_off = undefined, |
| 1229 | }); |
| 1230 | try wip_nav.debug_info.appendNTimes(dwarf.gpa, 0, dwarf.sectionOffsetBytes()); |
| 1231 | return reloc_index; |
| 2041 | 1232 | } |
| 2042 | | } |
| 2043 | 1233 | |
| 2044 | | fn writeOffsetAssumeCapacity(self: *Dwarf, buf: *std.ArrayList(u8), off: u64) void { |
| 2045 | | const comp = self.bin_file.comp; |
| 2046 | | const target = comp.root_mod.resolved_target.result; |
| 2047 | | const target_endian = target.cpu.arch.endian(); |
| 2048 | | switch (self.format) { |
| 2049 | | .dwarf32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @intCast(off), target_endian), |
| 2050 | | .dwarf64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), off, target_endian), |
| 1234 | fn finishForward(wip_nav: *WipNav, reloc_index: u32) void { |
| 1235 | const reloc = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs.items[reloc_index]; |
| 1236 | reloc.target_entry = wip_nav.entry; |
| 1237 | reloc.target_off = @intCast(wip_nav.debug_info.items.len); |
| 2051 | 1238 | } |
| 2052 | | } |
| 2053 | 1239 | |
| 2054 | | /// Writes to the file a buffer, prefixed and suffixed by the specified number of |
| 2055 | | /// bytes of NOPs. Asserts each padding size is at least `min_nop_size` and total padding bytes |
| 2056 | | /// are less than 1044480 bytes (if this limit is ever reached, this function can be |
| 2057 | | /// improved to make more than one pwritev call, or the limit can be raised by a fixed |
| 2058 | | /// amount by increasing the length of `vecs`). |
| 2059 | | fn pwriteDbgLineNops( |
| 2060 | | file: fs.File, |
| 2061 | | offset: u64, |
| 2062 | | prev_padding_size: usize, |
| 2063 | | buf: []const u8, |
| 2064 | | next_padding_size: usize, |
| 2065 | | ) !void { |
| 2066 | | const tracy = trace(@src()); |
| 2067 | | defer tracy.end(); |
| 2068 | | |
| 2069 | | const page_of_nops = [1]u8{DW.LNS.negate_stmt} ** 4096; |
| 2070 | | const three_byte_nop = [3]u8{ DW.LNS.advance_pc, 0b1000_0000, 0 }; |
| 2071 | | var vecs: [512]std.posix.iovec_const = undefined; |
| 2072 | | var vec_index: usize = 0; |
| 2073 | | { |
| 2074 | | var padding_left = prev_padding_size; |
| 2075 | | if (padding_left % 2 != 0) { |
| 2076 | | vecs[vec_index] = .{ |
| 2077 | | .base = &three_byte_nop, |
| 2078 | | .len = three_byte_nop.len, |
| 2079 | | }; |
| 2080 | | vec_index += 1; |
| 2081 | | padding_left -= three_byte_nop.len; |
| 2082 | | } |
| 2083 | | while (padding_left > page_of_nops.len) { |
| 2084 | | vecs[vec_index] = .{ |
| 2085 | | .base = &page_of_nops, |
| 2086 | | .len = page_of_nops.len, |
| 2087 | | }; |
| 2088 | | vec_index += 1; |
| 2089 | | padding_left -= page_of_nops.len; |
| 2090 | | } |
| 2091 | | if (padding_left > 0) { |
| 2092 | | vecs[vec_index] = .{ |
| 2093 | | .base = &page_of_nops, |
| 2094 | | .len = padding_left, |
| 2095 | | }; |
| 2096 | | vec_index += 1; |
| 1240 | fn enumConstValue( |
| 1241 | wip_nav: *WipNav, |
| 1242 | loaded_enum: InternPool.LoadedEnumType, |
| 1243 | abbrev_code: std.enums.EnumFieldStruct(std.builtin.Signedness, AbbrevCode, null), |
| 1244 | field_index: usize, |
| 1245 | ) std.mem.Allocator.Error!void { |
| 1246 | const zcu = wip_nav.pt.zcu; |
| 1247 | const ip = &zcu.intern_pool; |
| 1248 | const diw = wip_nav.debug_info.writer(wip_nav.dwarf.gpa); |
| 1249 | const signedness = switch (loaded_enum.tag_ty) { |
| 1250 | .comptime_int_type => .signed, |
| 1251 | else => Type.fromInterned(loaded_enum.tag_ty).intInfo(zcu).signedness, |
| 1252 | }; |
| 1253 | try uleb128(diw, @intFromEnum(switch (signedness) { |
| 1254 | inline .signed, .unsigned => |ct_signedness| @field(abbrev_code, @tagName(ct_signedness)), |
| 1255 | })); |
| 1256 | if (loaded_enum.values.len > 0) switch (ip.indexToKey(loaded_enum.values.get(ip)[field_index]).int.storage) { |
| 1257 | .u64 => |value| switch (signedness) { |
| 1258 | .signed => try sleb128(diw, value), |
| 1259 | .unsigned => try uleb128(diw, value), |
| 1260 | }, |
| 1261 | .i64 => |value| switch (signedness) { |
| 1262 | .signed => try sleb128(diw, value), |
| 1263 | .unsigned => unreachable, |
| 1264 | }, |
| 1265 | .big_int => |big_int| { |
| 1266 | const bits = big_int.bitCountTwosCompForSignedness(signedness); |
| 1267 | try wip_nav.debug_info.ensureUnusedCapacity(wip_nav.dwarf.gpa, std.math.divCeil(usize, bits, 7) catch unreachable); |
| 1268 | var bit: usize = 0; |
| 1269 | var carry: u1 = 1; |
| 1270 | while (bit < bits) : (bit += 7) { |
| 1271 | const limb_bits = @typeInfo(std.math.big.Limb).Int.bits; |
| 1272 | const limb_index = bit / limb_bits; |
| 1273 | const limb_shift: std.math.Log2Int(std.math.big.Limb) = @intCast(bit % limb_bits); |
| 1274 | const low_abs_part: u7 = @truncate(big_int.limbs[limb_index] >> limb_shift); |
| 1275 | const abs_part = if (limb_shift > limb_bits - 7) abs_part: { |
| 1276 | const next_limb: std.math.big.Limb = if (limb_index + 1 < big_int.limbs.len) |
| 1277 | big_int.limbs[limb_index + 1] |
| 1278 | else if (big_int.positive) 0 else std.math.maxInt(std.math.big.Limb); |
| 1279 | const high_abs_part: u7 = @truncate(next_limb << -%limb_shift); |
| 1280 | break :abs_part high_abs_part | low_abs_part; |
| 1281 | } else low_abs_part; |
| 1282 | const twos_comp_part = if (big_int.positive) abs_part else twos_comp_part: { |
| 1283 | const twos_comp_part, carry = @addWithOverflow(~abs_part, carry); |
| 1284 | break :twos_comp_part twos_comp_part; |
| 1285 | }; |
| 1286 | wip_nav.debug_info.appendAssumeCapacity(@as(u8, if (bit + 7 < bits) 0x80 else 0x00) | twos_comp_part); |
| 1287 | } |
| 1288 | }, |
| 1289 | .lazy_align, .lazy_size => unreachable, |
| 1290 | } else switch (signedness) { |
| 1291 | .signed => try sleb128(diw, field_index), |
| 1292 | .unsigned => try uleb128(diw, field_index), |
| 2097 | 1293 | } |
| 2098 | 1294 | } |
| 2099 | 1295 | |
| 2100 | | vecs[vec_index] = .{ |
| 2101 | | .base = buf.ptr, |
| 2102 | | .len = buf.len, |
| 1296 | fn flush(wip_nav: *WipNav) UpdateError!void { |
| 1297 | while (wip_nav.pending_types.popOrNull()) |ty| try wip_nav.dwarf.updateType(wip_nav.pt, ty, &wip_nav.pending_types); |
| 1298 | } |
| 1299 | }; |
| 1300 | |
| 1301 | /// When allocating, the ideal_capacity is calculated by |
| 1302 | /// actual_capacity + (actual_capacity / ideal_factor) |
| 1303 | const ideal_factor = 3; |
| 1304 | |
| 1305 | fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { |
| 1306 | return actual_size +| (actual_size / ideal_factor); |
| 1307 | } |
| 1308 | |
| 1309 | pub fn init(lf: *link.File, format: DW.Format) Dwarf { |
| 1310 | const comp = lf.comp; |
| 1311 | const gpa = comp.gpa; |
| 1312 | const target = comp.root_mod.resolved_target.result; |
| 1313 | return .{ |
| 1314 | .gpa = gpa, |
| 1315 | .bin_file = lf, |
| 1316 | .format = format, |
| 1317 | .address_size = switch (target.ptrBitWidth()) { |
| 1318 | 0...32 => .@"32", |
| 1319 | 33...64 => .@"64", |
| 1320 | else => unreachable, |
| 1321 | }, |
| 1322 | .endian = target.cpu.arch.endian(), |
| 1323 | |
| 1324 | .mods = .{}, |
| 1325 | .types = .{}, |
| 1326 | .navs = .{}, |
| 1327 | |
| 1328 | .debug_abbrev = .{ .section = Section.init }, |
| 1329 | .debug_aranges = .{ .section = Section.init }, |
| 1330 | .debug_info = .{ .section = Section.init }, |
| 1331 | .debug_line = .{ |
| 1332 | .header = switch (target.cpu.arch) { |
| 1333 | .x86_64, .aarch64 => .{ |
| 1334 | .minimum_instruction_length = 1, |
| 1335 | .maximum_operations_per_instruction = 1, |
| 1336 | .default_is_stmt = true, |
| 1337 | .line_base = -5, |
| 1338 | .line_range = 14, |
| 1339 | .opcode_base = DW.LNS.set_isa + 1, |
| 1340 | }, |
| 1341 | else => .{ |
| 1342 | .minimum_instruction_length = 1, |
| 1343 | .maximum_operations_per_instruction = 1, |
| 1344 | .default_is_stmt = true, |
| 1345 | .line_base = 0, |
| 1346 | .line_range = 1, |
| 1347 | .opcode_base = DW.LNS.set_isa + 1, |
| 1348 | }, |
| 1349 | }, |
| 1350 | .section = Section.init, |
| 1351 | }, |
| 1352 | .debug_line_str = StringSection.init, |
| 1353 | .debug_loclists = .{ .section = Section.init }, |
| 1354 | .debug_rnglists = .{ .section = Section.init }, |
| 1355 | .debug_str = StringSection.init, |
| 2103 | 1356 | }; |
| 2104 | | if (buf.len > 0) vec_index += 1; |
| 1357 | } |
| 2105 | 1358 | |
| 2106 | | { |
| 2107 | | var padding_left = next_padding_size; |
| 2108 | | if (padding_left % 2 != 0) { |
| 2109 | | vecs[vec_index] = .{ |
| 2110 | | .base = &three_byte_nop, |
| 2111 | | .len = three_byte_nop.len, |
| 2112 | | }; |
| 2113 | | vec_index += 1; |
| 2114 | | padding_left -= three_byte_nop.len; |
| 2115 | | } |
| 2116 | | while (padding_left > page_of_nops.len) { |
| 2117 | | vecs[vec_index] = .{ |
| 2118 | | .base = &page_of_nops, |
| 2119 | | .len = page_of_nops.len, |
| 2120 | | }; |
| 2121 | | vec_index += 1; |
| 2122 | | padding_left -= page_of_nops.len; |
| 1359 | pub fn reloadSectionMetadata(dwarf: *Dwarf) void { |
| 1360 | if (dwarf.bin_file.cast(.elf)) |elf_file| { |
| 1361 | for ([_]*Section{ |
| 1362 | &dwarf.debug_abbrev.section, |
| 1363 | &dwarf.debug_aranges.section, |
| 1364 | &dwarf.debug_info.section, |
| 1365 | &dwarf.debug_line.section, |
| 1366 | &dwarf.debug_line_str.section, |
| 1367 | &dwarf.debug_loclists.section, |
| 1368 | &dwarf.debug_rnglists.section, |
| 1369 | &dwarf.debug_str.section, |
| 1370 | }, [_]u32{ |
| 1371 | elf_file.debug_abbrev_section_index.?, |
| 1372 | elf_file.debug_aranges_section_index.?, |
| 1373 | elf_file.debug_info_section_index.?, |
| 1374 | elf_file.debug_line_section_index.?, |
| 1375 | elf_file.debug_line_str_section_index.?, |
| 1376 | elf_file.debug_loclists_section_index.?, |
| 1377 | elf_file.debug_rnglists_section_index.?, |
| 1378 | elf_file.debug_str_section_index.?, |
| 1379 | }) |sec, section_index| { |
| 1380 | const shdr = &elf_file.shdrs.items[section_index]; |
| 1381 | sec.index = section_index; |
| 1382 | sec.off = shdr.sh_offset; |
| 1383 | sec.len = shdr.sh_size; |
| 2123 | 1384 | } |
| 2124 | | if (padding_left > 0) { |
| 2125 | | vecs[vec_index] = .{ |
| 2126 | | .base = &page_of_nops, |
| 2127 | | .len = padding_left, |
| 2128 | | }; |
| 2129 | | vec_index += 1; |
| 1385 | } else if (dwarf.bin_file.cast(.macho)) |macho_file| { |
| 1386 | if (macho_file.d_sym) |*d_sym| { |
| 1387 | for ([_]*Section{ |
| 1388 | &dwarf.debug_abbrev.section, |
| 1389 | &dwarf.debug_aranges.section, |
| 1390 | &dwarf.debug_info.section, |
| 1391 | &dwarf.debug_line.section, |
| 1392 | &dwarf.debug_line_str.section, |
| 1393 | &dwarf.debug_loclists.section, |
| 1394 | &dwarf.debug_rnglists.section, |
| 1395 | &dwarf.debug_str.section, |
| 1396 | }, [_]u8{ |
| 1397 | d_sym.debug_abbrev_section_index.?, |
| 1398 | d_sym.debug_aranges_section_index.?, |
| 1399 | d_sym.debug_info_section_index.?, |
| 1400 | d_sym.debug_line_section_index.?, |
| 1401 | d_sym.debug_line_str_section_index.?, |
| 1402 | d_sym.debug_loclists_section_index.?, |
| 1403 | d_sym.debug_rnglists_section_index.?, |
| 1404 | d_sym.debug_str_section_index.?, |
| 1405 | }) |sec, sect_index| { |
| 1406 | const header = &d_sym.sections.items[sect_index]; |
| 1407 | sec.index = sect_index; |
| 1408 | sec.off = header.offset; |
| 1409 | sec.len = header.size; |
| 1410 | } |
| 1411 | } else { |
| 1412 | for ([_]*Section{ |
| 1413 | &dwarf.debug_abbrev.section, |
| 1414 | &dwarf.debug_aranges.section, |
| 1415 | &dwarf.debug_info.section, |
| 1416 | &dwarf.debug_line.section, |
| 1417 | &dwarf.debug_line_str.section, |
| 1418 | &dwarf.debug_loclists.section, |
| 1419 | &dwarf.debug_rnglists.section, |
| 1420 | &dwarf.debug_str.section, |
| 1421 | }, [_]u8{ |
| 1422 | macho_file.debug_abbrev_sect_index.?, |
| 1423 | macho_file.debug_aranges_sect_index.?, |
| 1424 | macho_file.debug_info_sect_index.?, |
| 1425 | macho_file.debug_line_sect_index.?, |
| 1426 | macho_file.debug_line_str_sect_index.?, |
| 1427 | macho_file.debug_loclists_sect_index.?, |
| 1428 | macho_file.debug_rnglists_sect_index.?, |
| 1429 | macho_file.debug_str_sect_index.?, |
| 1430 | }) |sec, sect_index| { |
| 1431 | const header = &macho_file.sections.items(.header)[sect_index]; |
| 1432 | sec.index = sect_index; |
| 1433 | sec.off = header.offset; |
| 1434 | sec.len = header.size; |
| 1435 | } |
| 2130 | 1436 | } |
| 2131 | 1437 | } |
| 2132 | | try file.pwritevAll(vecs[0..vec_index], offset - prev_padding_size); |
| 2133 | 1438 | } |
| 2134 | 1439 | |
| 2135 | | fn writeDbgLineNopsBuffered( |
| 2136 | | buf: []u8, |
| 2137 | | offset: u32, |
| 2138 | | prev_padding_size: usize, |
| 2139 | | content: []const u8, |
| 2140 | | next_padding_size: usize, |
| 2141 | | ) void { |
| 2142 | | assert(buf.len >= content.len + prev_padding_size + next_padding_size); |
| 2143 | | const tracy = trace(@src()); |
| 2144 | | defer tracy.end(); |
| 2145 | | |
| 2146 | | const three_byte_nop = [3]u8{ DW.LNS.advance_pc, 0b1000_0000, 0 }; |
| 2147 | | { |
| 2148 | | var padding_left = prev_padding_size; |
| 2149 | | if (padding_left % 2 != 0) { |
| 2150 | | buf[offset - padding_left ..][0..3].* = three_byte_nop; |
| 2151 | | padding_left -= 3; |
| 2152 | | } |
| 1440 | pub fn initMetadata(dwarf: *Dwarf) UpdateError!void { |
| 1441 | dwarf.reloadSectionMetadata(); |
| 2153 | 1442 | |
| 2154 | | while (padding_left > 0) : (padding_left -= 1) { |
| 2155 | | buf[offset - padding_left] = DW.LNS.negate_stmt; |
| 2156 | | } |
| 2157 | | } |
| 1443 | dwarf.debug_abbrev.section.pad_to_ideal = false; |
| 1444 | assert(try dwarf.debug_abbrev.section.addUnit(0, 0, dwarf) == DebugAbbrev.unit); |
| 1445 | errdefer dwarf.debug_abbrev.section.popUnit(); |
| 1446 | assert(try dwarf.debug_abbrev.section.addEntry(DebugAbbrev.unit, dwarf) == DebugAbbrev.entry); |
| 2158 | 1447 | |
| 2159 | | @memcpy(buf[offset..][0..content.len], content); |
| 1448 | dwarf.debug_aranges.section.pad_to_ideal = false; |
| 1449 | dwarf.debug_aranges.section.alignment = InternPool.Alignment.fromNonzeroByteUnits(@intFromEnum(dwarf.address_size) * 2); |
| 2160 | 1450 | |
| 2161 | | { |
| 2162 | | var padding_left = next_padding_size; |
| 2163 | | if (padding_left % 2 != 0) { |
| 2164 | | buf[offset + content.len + padding_left ..][0..3].* = three_byte_nop; |
| 2165 | | padding_left -= 3; |
| 2166 | | } |
| 1451 | dwarf.debug_line_str.section.pad_to_ideal = false; |
| 1452 | assert(try dwarf.debug_line_str.section.addUnit(0, 0, dwarf) == StringSection.unit); |
| 1453 | errdefer dwarf.debug_line_str.section.popUnit(); |
| 2167 | 1454 | |
| 2168 | | while (padding_left > 0) : (padding_left -= 1) { |
| 2169 | | buf[offset + content.len + padding_left] = DW.LNS.negate_stmt; |
| 2170 | | } |
| 2171 | | } |
| 2172 | | } |
| 1455 | dwarf.debug_str.section.pad_to_ideal = false; |
| 1456 | assert(try dwarf.debug_str.section.addUnit(0, 0, dwarf) == StringSection.unit); |
| 1457 | errdefer dwarf.debug_str.section.popUnit(); |
| 2173 | 1458 | |
| 2174 | | /// Writes to the file a buffer, prefixed and suffixed by the specified number of |
| 2175 | | /// bytes of padding. |
| 2176 | | fn pwriteDbgInfoNops( |
| 2177 | | file: fs.File, |
| 2178 | | offset: u64, |
| 2179 | | prev_padding_size: usize, |
| 2180 | | buf: []const u8, |
| 2181 | | next_padding_size: usize, |
| 2182 | | trailing_zero: bool, |
| 2183 | | ) !void { |
| 2184 | | const tracy = trace(@src()); |
| 2185 | | defer tracy.end(); |
| 2186 | | |
| 2187 | | const page_of_nops = [1]u8{@intFromEnum(AbbrevCode.padding)} ** 4096; |
| 2188 | | var vecs: [32]std.posix.iovec_const = undefined; |
| 2189 | | var vec_index: usize = 0; |
| 2190 | | { |
| 2191 | | var padding_left = prev_padding_size; |
| 2192 | | while (padding_left > page_of_nops.len) { |
| 2193 | | vecs[vec_index] = .{ |
| 2194 | | .base = &page_of_nops, |
| 2195 | | .len = page_of_nops.len, |
| 2196 | | }; |
| 2197 | | vec_index += 1; |
| 2198 | | padding_left -= page_of_nops.len; |
| 2199 | | } |
| 2200 | | if (padding_left > 0) { |
| 2201 | | vecs[vec_index] = .{ |
| 2202 | | .base = &page_of_nops, |
| 2203 | | .len = padding_left, |
| 2204 | | }; |
| 2205 | | vec_index += 1; |
| 2206 | | } |
| 2207 | | } |
| 1459 | dwarf.debug_loclists.section.pad_to_ideal = false; |
| 2208 | 1460 | |
| 2209 | | vecs[vec_index] = .{ |
| 2210 | | .base = buf.ptr, |
| 2211 | | .len = buf.len, |
| 2212 | | }; |
| 2213 | | if (buf.len > 0) vec_index += 1; |
| 1461 | dwarf.debug_rnglists.section.pad_to_ideal = false; |
| 1462 | } |
| 2214 | 1463 | |
| 2215 | | { |
| 2216 | | var padding_left = next_padding_size; |
| 2217 | | while (padding_left > page_of_nops.len) { |
| 2218 | | vecs[vec_index] = .{ |
| 2219 | | .base = &page_of_nops, |
| 2220 | | .len = page_of_nops.len, |
| 2221 | | }; |
| 2222 | | vec_index += 1; |
| 2223 | | padding_left -= page_of_nops.len; |
| 2224 | | } |
| 2225 | | if (padding_left > 0) { |
| 2226 | | vecs[vec_index] = .{ |
| 2227 | | .base = &page_of_nops, |
| 2228 | | .len = padding_left, |
| 2229 | | }; |
| 2230 | | vec_index += 1; |
| 2231 | | } |
| 2232 | | } |
| 1464 | pub fn deinit(dwarf: *Dwarf) void { |
| 1465 | const gpa = dwarf.gpa; |
| 1466 | for (dwarf.mods.values()) |*mod_info| mod_info.deinit(gpa); |
| 1467 | dwarf.mods.deinit(gpa); |
| 1468 | dwarf.types.deinit(gpa); |
| 1469 | dwarf.navs.deinit(gpa); |
| 1470 | dwarf.debug_abbrev.section.deinit(gpa); |
| 1471 | dwarf.debug_aranges.section.deinit(gpa); |
| 1472 | dwarf.debug_info.section.deinit(gpa); |
| 1473 | dwarf.debug_line.section.deinit(gpa); |
| 1474 | dwarf.debug_line_str.deinit(gpa); |
| 1475 | dwarf.debug_loclists.section.deinit(gpa); |
| 1476 | dwarf.debug_rnglists.section.deinit(gpa); |
| 1477 | dwarf.debug_str.deinit(gpa); |
| 1478 | dwarf.* = undefined; |
| 1479 | } |
| 2233 | 1480 | |
| 2234 | | if (trailing_zero) { |
| 2235 | | var zbuf = [1]u8{0}; |
| 2236 | | vecs[vec_index] = .{ |
| 2237 | | .base = &zbuf, |
| 2238 | | .len = zbuf.len, |
| 1481 | fn getUnit(dwarf: *Dwarf, mod: *Module) UpdateError!Unit.Index { |
| 1482 | const mod_gop = try dwarf.mods.getOrPut(dwarf.gpa, mod); |
| 1483 | const unit: Unit.Index = @enumFromInt(mod_gop.index); |
| 1484 | if (!mod_gop.found_existing) { |
| 1485 | errdefer _ = dwarf.mods.pop(); |
| 1486 | mod_gop.value_ptr.* = .{ |
| 1487 | .root_dir_path = undefined, |
| 1488 | .dirs = .{}, |
| 1489 | .files = .{}, |
| 2239 | 1490 | }; |
| 2240 | | vec_index += 1; |
| 1491 | errdefer mod_gop.value_ptr.dirs.deinit(dwarf.gpa); |
| 1492 | try mod_gop.value_ptr.dirs.putNoClobber(dwarf.gpa, unit, {}); |
| 1493 | assert(try dwarf.debug_aranges.section.addUnit( |
| 1494 | DebugAranges.headerBytes(dwarf), |
| 1495 | DebugAranges.trailerBytes(dwarf), |
| 1496 | dwarf, |
| 1497 | ) == unit); |
| 1498 | errdefer dwarf.debug_aranges.section.popUnit(); |
| 1499 | assert(try dwarf.debug_info.section.addUnit( |
| 1500 | DebugInfo.headerBytes(dwarf), |
| 1501 | DebugInfo.trailer_bytes, |
| 1502 | dwarf, |
| 1503 | ) == unit); |
| 1504 | errdefer dwarf.debug_info.section.popUnit(); |
| 1505 | assert(try dwarf.debug_line.section.addUnit( |
| 1506 | DebugLine.headerBytes(dwarf, 5, 25), |
| 1507 | DebugLine.trailer_bytes, |
| 1508 | dwarf, |
| 1509 | ) == unit); |
| 1510 | errdefer dwarf.debug_line.section.popUnit(); |
| 1511 | assert(try dwarf.debug_loclists.section.addUnit( |
| 1512 | DebugLocLists.headerBytes(dwarf), |
| 1513 | DebugLocLists.trailer_bytes, |
| 1514 | dwarf, |
| 1515 | ) == unit); |
| 1516 | errdefer dwarf.debug_loclists.section.popUnit(); |
| 1517 | assert(try dwarf.debug_rnglists.section.addUnit( |
| 1518 | DebugRngLists.headerBytes(dwarf), |
| 1519 | DebugRngLists.trailer_bytes, |
| 1520 | dwarf, |
| 1521 | ) == unit); |
| 1522 | errdefer dwarf.debug_rnglists.section.popUnit(); |
| 2241 | 1523 | } |
| 2242 | | |
| 2243 | | try file.pwritevAll(vecs[0..vec_index], offset - prev_padding_size); |
| 1524 | return unit; |
| 2244 | 1525 | } |
| 2245 | 1526 | |
| 2246 | | fn writeDbgInfoNopsToArrayList( |
| 2247 | | gpa: Allocator, |
| 2248 | | buffer: *std.ArrayListUnmanaged(u8), |
| 2249 | | offset: u32, |
| 2250 | | prev_padding_size: usize, |
| 2251 | | content: []const u8, |
| 2252 | | next_padding_size: usize, |
| 2253 | | trailing_zero: bool, |
| 2254 | | ) Allocator.Error!void { |
| 2255 | | try buffer.resize(gpa, @max( |
| 2256 | | buffer.items.len, |
| 2257 | | offset + content.len + next_padding_size + 1, |
| 2258 | | )); |
| 2259 | | @memset(buffer.items[offset - prev_padding_size .. offset], @intFromEnum(AbbrevCode.padding)); |
| 2260 | | @memcpy(buffer.items[offset..][0..content.len], content); |
| 2261 | | @memset(buffer.items[offset + content.len ..][0..next_padding_size], @intFromEnum(AbbrevCode.padding)); |
| 2262 | | |
| 2263 | | if (trailing_zero) { |
| 2264 | | buffer.items[offset + content.len + next_padding_size] = 0; |
| 2265 | | } |
| 1527 | fn getUnitIfExists(dwarf: *const Dwarf, mod: *Module) ?Unit.Index { |
| 1528 | return @enumFromInt(dwarf.mods.getIndex(mod) orelse return null); |
| 2266 | 1529 | } |
| 2267 | 1530 | |
| 2268 | | pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void { |
| 2269 | | const comp = self.bin_file.comp; |
| 2270 | | const target = comp.root_mod.resolved_target.result; |
| 2271 | | const target_endian = target.cpu.arch.endian(); |
| 2272 | | const ptr_width_bytes = self.ptrWidthBytes(); |
| 2273 | | |
| 2274 | | // Enough for all the data without resizing. When support for more compilation units |
| 2275 | | // is added, the size of this section will become more variable. |
| 2276 | | var di_buf = try std.ArrayList(u8).initCapacity(self.allocator, 100); |
| 2277 | | defer di_buf.deinit(); |
| 2278 | | |
| 2279 | | // initial length - length of the .debug_aranges contribution for this compilation unit, |
| 2280 | | // not including the initial length itself. |
| 2281 | | // We have to come back and write it later after we know the size. |
| 2282 | | if (self.format == .dwarf64) di_buf.appendNTimesAssumeCapacity(0xff, 4); |
| 2283 | | const init_len_index = di_buf.items.len; |
| 2284 | | self.writeOffsetAssumeCapacity(&di_buf, 0); |
| 2285 | | const after_init_len = di_buf.items.len; |
| 2286 | | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 2, target_endian); // version |
| 2287 | | |
| 2288 | | // When more than one compilation unit is supported, this will be the offset to it. |
| 2289 | | // For now it is always at offset 0 in .debug_info. |
| 2290 | | self.writeOffsetAssumeCapacity(&di_buf, 0); // .debug_info offset |
| 2291 | | di_buf.appendAssumeCapacity(ptr_width_bytes); // address_size |
| 2292 | | di_buf.appendAssumeCapacity(0); // segment_selector_size |
| 2293 | | |
| 2294 | | const end_header_offset = di_buf.items.len; |
| 2295 | | const begin_entries_offset = mem.alignForward(usize, end_header_offset, ptr_width_bytes * 2); |
| 2296 | | di_buf.appendNTimesAssumeCapacity(0, begin_entries_offset - end_header_offset); |
| 2297 | | |
| 2298 | | // Currently only one compilation unit is supported, so the address range is simply |
| 2299 | | // identical to the main program header virtual address and memory size. |
| 2300 | | self.writeAddrAssumeCapacity(&di_buf, addr); |
| 2301 | | self.writeAddrAssumeCapacity(&di_buf, size); |
| 2302 | | |
| 2303 | | // Sentinel. |
| 2304 | | self.writeAddrAssumeCapacity(&di_buf, 0); |
| 2305 | | self.writeAddrAssumeCapacity(&di_buf, 0); |
| 2306 | | |
| 2307 | | // Go back and populate the initial length. |
| 2308 | | const init_len = di_buf.items.len - after_init_len; |
| 2309 | | switch (self.format) { |
| 2310 | | .dwarf32 => mem.writeInt(u32, di_buf.items[init_len_index..][0..4], @intCast(init_len), target_endian), |
| 2311 | | .dwarf64 => mem.writeInt(u64, di_buf.items[init_len_index..][0..8], init_len, target_endian), |
| 2312 | | } |
| 2313 | | |
| 2314 | | const needed_size: u32 = @intCast(di_buf.items.len); |
| 2315 | | if (self.bin_file.cast(.elf)) |elf_file| { |
| 2316 | | const shdr_index = elf_file.debug_aranges_section_index.?; |
| 2317 | | try elf_file.growNonAllocSection(shdr_index, needed_size, 16, false); |
| 2318 | | const debug_aranges_sect = &elf_file.shdrs.items[shdr_index]; |
| 2319 | | const file_pos = debug_aranges_sect.sh_offset; |
| 2320 | | try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos); |
| 2321 | | } else if (self.bin_file.cast(.macho)) |macho_file| { |
| 2322 | | if (macho_file.base.isRelocatable()) { |
| 2323 | | const sect_index = macho_file.debug_aranges_sect_index.?; |
| 2324 | | try macho_file.growSection(sect_index, needed_size); |
| 2325 | | const sect = macho_file.sections.items(.header)[sect_index]; |
| 2326 | | const file_pos = sect.offset; |
| 2327 | | try macho_file.base.file.?.pwriteAll(di_buf.items, file_pos); |
| 2328 | | } else { |
| 2329 | | const d_sym = macho_file.getDebugSymbols().?; |
| 2330 | | const sect_index = d_sym.debug_aranges_section_index.?; |
| 2331 | | try d_sym.growSection(sect_index, needed_size, false, macho_file); |
| 2332 | | const sect = d_sym.getSection(sect_index); |
| 2333 | | const file_pos = sect.offset; |
| 2334 | | try d_sym.file.pwriteAll(di_buf.items, file_pos); |
| 2335 | | } |
| 2336 | | } else if (self.bin_file.cast(.wasm)) |wasm_file| { |
| 2337 | | _ = wasm_file; |
| 2338 | | // const debug_ranges = &wasm_file.getAtomPtr(wasm_file.debug_ranges_atom.?).code; |
| 2339 | | // try debug_ranges.resize(gpa, needed_size); |
| 2340 | | // @memcpy(debug_ranges.items[0..di_buf.items.len], di_buf.items); |
| 2341 | | } else unreachable; |
| 1531 | fn getModInfo(dwarf: *Dwarf, unit: Unit.Index) *ModInfo { |
| 1532 | return &dwarf.mods.values()[@intFromEnum(unit)]; |
| 2342 | 1533 | } |
| 2343 | 1534 | |
| 2344 | | pub fn writeDbgLineHeader(self: *Dwarf) !void { |
| 2345 | | const comp = self.bin_file.comp; |
| 2346 | | const gpa = self.allocator; |
| 2347 | | const target = comp.root_mod.resolved_target.result; |
| 2348 | | const target_endian = target.cpu.arch.endian(); |
| 2349 | | const init_len_size: usize = switch (self.format) { |
| 2350 | | .dwarf32 => 4, |
| 2351 | | .dwarf64 => 12, |
| 1535 | pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, sym_index: u32) UpdateError!?WipNav { |
| 1536 | const zcu = pt.zcu; |
| 1537 | const ip = &zcu.intern_pool; |
| 1538 | |
| 1539 | const nav = ip.getNav(nav_index); |
| 1540 | log.debug("initWipNav({})", .{nav.fqn.fmt(ip)}); |
| 1541 | |
| 1542 | const inst_info = nav.srcInst(ip).resolveFull(ip); |
| 1543 | const file = zcu.fileByIndex(inst_info.file); |
| 1544 | |
| 1545 | const unit = try dwarf.getUnit(file.mod); |
| 1546 | const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index); |
| 1547 | errdefer _ = dwarf.navs.pop(); |
| 1548 | if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit); |
| 1549 | const nav_val = zcu.navValue(nav_index); |
| 1550 | var wip_nav: WipNav = .{ |
| 1551 | .dwarf = dwarf, |
| 1552 | .pt = pt, |
| 1553 | .unit = unit, |
| 1554 | .entry = nav_gop.value_ptr.*, |
| 1555 | .any_children = false, |
| 1556 | .func = .none, |
| 1557 | .func_high_reloc = undefined, |
| 1558 | .debug_info = .{}, |
| 1559 | .debug_line = .{}, |
| 1560 | .debug_loclists = .{}, |
| 1561 | .pending_types = .{}, |
| 2352 | 1562 | }; |
| 1563 | errdefer wip_nav.deinit(); |
| 2353 | 1564 | |
| 2354 | | const dbg_line_prg_off = self.getDebugLineProgramOff() orelse return; |
| 2355 | | assert(self.getDebugLineProgramEnd().? != 0); |
| 2356 | | |
| 2357 | | // Convert all input DI files into a set of include dirs and file names. |
| 2358 | | var arena = std.heap.ArenaAllocator.init(gpa); |
| 2359 | | defer arena.deinit(); |
| 2360 | | const paths = try self.genIncludeDirsAndFileNames(arena.allocator()); |
| 2361 | | |
| 2362 | | // The size of this header is variable, depending on the number of directories, |
| 2363 | | // files, and padding. We have a function to compute the upper bound size, however, |
| 2364 | | // because it's needed for determining where to put the offset of the first `SrcFn`. |
| 2365 | | const needed_bytes = self.dbgLineNeededHeaderBytes(paths.dirs, paths.files); |
| 2366 | | var di_buf = try std.ArrayList(u8).initCapacity(gpa, needed_bytes); |
| 2367 | | defer di_buf.deinit(); |
| 2368 | | |
| 2369 | | if (self.format == .dwarf64) di_buf.appendNTimesAssumeCapacity(0xff, 4); |
| 2370 | | self.writeOffsetAssumeCapacity(&di_buf, 0); |
| 2371 | | |
| 2372 | | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // version |
| 2373 | | |
| 2374 | | // Empirically, debug info consumers do not respect this field, or otherwise |
| 2375 | | // consider it to be an error when it does not point exactly to the end of the header. |
| 2376 | | // Therefore we rely on the NOP jump at the beginning of the Line Number Program for |
| 2377 | | // padding rather than this field. |
| 2378 | | const before_header_len = di_buf.items.len; |
| 2379 | | self.writeOffsetAssumeCapacity(&di_buf, 0); // We will come back and write this. |
| 2380 | | const after_header_len = di_buf.items.len; |
| 2381 | | |
| 2382 | | assert(self.dbg_line_header.opcode_base == DW.LNS.set_isa + 1); |
| 2383 | | di_buf.appendSliceAssumeCapacity(&[_]u8{ |
| 2384 | | self.dbg_line_header.minimum_instruction_length, |
| 2385 | | self.dbg_line_header.maximum_operations_per_instruction, |
| 2386 | | @intFromBool(self.dbg_line_header.default_is_stmt), |
| 2387 | | @bitCast(self.dbg_line_header.line_base), |
| 2388 | | self.dbg_line_header.line_range, |
| 2389 | | self.dbg_line_header.opcode_base, |
| 2390 | | |
| 2391 | | // Standard opcode lengths. The number of items here is based on `opcode_base`. |
| 2392 | | // The value is the number of LEB128 operands the instruction takes. |
| 2393 | | 0, // `DW.LNS.copy` |
| 2394 | | 1, // `DW.LNS.advance_pc` |
| 2395 | | 1, // `DW.LNS.advance_line` |
| 2396 | | 1, // `DW.LNS.set_file` |
| 2397 | | 1, // `DW.LNS.set_column` |
| 2398 | | 0, // `DW.LNS.negate_stmt` |
| 2399 | | 0, // `DW.LNS.set_basic_block` |
| 2400 | | 0, // `DW.LNS.const_add_pc` |
| 2401 | | 1, // `DW.LNS.fixed_advance_pc` |
| 2402 | | 0, // `DW.LNS.set_prologue_end` |
| 2403 | | 0, // `DW.LNS.set_epilogue_begin` |
| 2404 | | 1, // `DW.LNS.set_isa` |
| 2405 | | }); |
| 2406 | | |
| 2407 | | for (paths.dirs, 0..) |dir, i| { |
| 2408 | | log.debug("adding new include dir at {d} of '{s}'", .{ i + 1, dir }); |
| 2409 | | di_buf.appendSliceAssumeCapacity(dir); |
| 2410 | | di_buf.appendAssumeCapacity(0); |
| 2411 | | } |
| 2412 | | di_buf.appendAssumeCapacity(0); // include directories sentinel |
| 2413 | | |
| 2414 | | for (paths.files, 0..) |file, i| { |
| 2415 | | const dir_index = paths.files_dirs_indexes[i]; |
| 2416 | | log.debug("adding new file name at {d} of '{s}' referencing directory {d}", .{ |
| 2417 | | i + 1, |
| 2418 | | file, |
| 2419 | | dir_index + 1, |
| 2420 | | }); |
| 2421 | | di_buf.appendSliceAssumeCapacity(file); |
| 2422 | | di_buf.appendSliceAssumeCapacity(&[_]u8{ |
| 2423 | | 0, // null byte for the relative path name |
| 2424 | | @intCast(dir_index), // directory_index |
| 2425 | | 0, // mtime (TODO supply this) |
| 2426 | | 0, // file size bytes (TODO supply this) |
| 2427 | | }); |
| 2428 | | } |
| 2429 | | di_buf.appendAssumeCapacity(0); // file names sentinel |
| 1565 | switch (ip.indexToKey(nav_val.toIntern())) { |
| 1566 | else => { |
| 1567 | assert(file.zir_loaded); |
| 1568 | const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst)); |
| 1569 | assert(decl_inst.tag == .declaration); |
| 1570 | const tree = try file.getTree(dwarf.gpa); |
| 1571 | const loc = tree.tokenLocation(0, tree.nodes.items(.main_token)[decl_inst.data.declaration.src_node]); |
| 1572 | assert(loc.line == zcu.navSrcLine(nav_index)); |
| 1573 | |
| 1574 | const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: { |
| 1575 | const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index).data; |
| 1576 | const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace); |
| 1577 | break :parent .{ |
| 1578 | parent_namespace_ptr.owner_type, |
| 1579 | switch (decl_extra.name) { |
| 1580 | .@"comptime", |
| 1581 | .@"usingnamespace", |
| 1582 | .unnamed_test, |
| 1583 | .decltest, |
| 1584 | => DW.ACCESS.private, |
| 1585 | _ => if (decl_extra.name.isNamedTest(file.zir)) |
| 1586 | DW.ACCESS.private |
| 1587 | else if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu })) |
| 1588 | DW.ACCESS.public |
| 1589 | else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu })) |
| 1590 | DW.ACCESS.private |
| 1591 | else |
| 1592 | unreachable, |
| 1593 | }, |
| 1594 | }; |
| 1595 | } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private }; |
| 1596 | |
| 1597 | const diw = wip_nav.debug_info.writer(dwarf.gpa); |
| 1598 | try uleb128(diw, @intFromEnum(AbbrevCode.decl_var)); |
| 1599 | try wip_nav.refType(Type.fromInterned(parent_type)); |
| 1600 | assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); |
| 1601 | try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); |
| 1602 | try uleb128(diw, loc.column + 1); |
| 1603 | try diw.writeByte(accessibility); |
| 1604 | try wip_nav.strp(nav.name.toSlice(ip)); |
| 1605 | try wip_nav.strp(nav.fqn.toSlice(ip)); |
| 1606 | const ty = nav_val.typeOf(zcu); |
| 1607 | const ty_reloc_index = try wip_nav.refForward(); |
| 1608 | try wip_nav.exprloc(.{ .addr = .{ .sym = sym_index } }); |
| 1609 | try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse |
| 1610 | ty.abiAlignment(pt).toByteUnits().?); |
| 1611 | const func_unit = InternPool.AnalUnit.wrap(.{ .func = nav_val.toIntern() }); |
| 1612 | try diw.writeByte(@intFromBool(for (if (zcu.single_exports.get(func_unit)) |export_index| |
| 1613 | zcu.all_exports.items[export_index..][0..1] |
| 1614 | else if (zcu.multi_exports.get(func_unit)) |export_range| |
| 1615 | zcu.all_exports.items[export_range.index..][0..export_range.len] |
| 1616 | else |
| 1617 | &.{}) |@"export"| |
| 1618 | { |
| 1619 | if (@"export".exported == .nav and @"export".exported.nav == nav_index) break true; |
| 1620 | } else false)); |
| 1621 | wip_nav.finishForward(ty_reloc_index); |
| 1622 | try uleb128(diw, @intFromEnum(AbbrevCode.is_const)); |
| 1623 | try wip_nav.refType(ty); |
| 1624 | }, |
| 1625 | .variable => |variable| { |
| 1626 | assert(file.zir_loaded); |
| 1627 | const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst)); |
| 1628 | assert(decl_inst.tag == .declaration); |
| 1629 | const tree = try file.getTree(dwarf.gpa); |
| 1630 | const loc = tree.tokenLocation(0, tree.nodes.items(.main_token)[decl_inst.data.declaration.src_node]); |
| 1631 | assert(loc.line == zcu.navSrcLine(nav_index)); |
| 1632 | |
| 1633 | const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: { |
| 1634 | const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index).data; |
| 1635 | const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace); |
| 1636 | break :parent .{ |
| 1637 | parent_namespace_ptr.owner_type, |
| 1638 | switch (decl_extra.name) { |
| 1639 | .@"comptime", |
| 1640 | .@"usingnamespace", |
| 1641 | .unnamed_test, |
| 1642 | .decltest, |
| 1643 | => DW.ACCESS.private, |
| 1644 | _ => if (decl_extra.name.isNamedTest(file.zir)) |
| 1645 | DW.ACCESS.private |
| 1646 | else if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu })) |
| 1647 | DW.ACCESS.public |
| 1648 | else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu })) |
| 1649 | DW.ACCESS.private |
| 1650 | else |
| 1651 | unreachable, |
| 1652 | }, |
| 1653 | }; |
| 1654 | } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private }; |
| 1655 | |
| 1656 | const diw = wip_nav.debug_info.writer(dwarf.gpa); |
| 1657 | try uleb128(diw, @intFromEnum(AbbrevCode.decl_var)); |
| 1658 | try wip_nav.refType(Type.fromInterned(parent_type)); |
| 1659 | assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); |
| 1660 | try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); |
| 1661 | try uleb128(diw, loc.column + 1); |
| 1662 | try diw.writeByte(accessibility); |
| 1663 | try wip_nav.strp(nav.name.toSlice(ip)); |
| 1664 | try wip_nav.strp(nav.fqn.toSlice(ip)); |
| 1665 | const ty = Type.fromInterned(variable.ty); |
| 1666 | try wip_nav.refType(ty); |
| 1667 | const addr: Loc = .{ .addr = .{ .sym = sym_index } }; |
| 1668 | try wip_nav.exprloc(if (variable.is_threadlocal) .{ .form_tls_address = &addr } else addr); |
| 1669 | try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse |
| 1670 | ty.abiAlignment(pt).toByteUnits().?); |
| 1671 | const func_unit = InternPool.AnalUnit.wrap(.{ .func = nav_val.toIntern() }); |
| 1672 | try diw.writeByte(@intFromBool(for (if (zcu.single_exports.get(func_unit)) |export_index| |
| 1673 | zcu.all_exports.items[export_index..][0..1] |
| 1674 | else if (zcu.multi_exports.get(func_unit)) |export_range| |
| 1675 | zcu.all_exports.items[export_range.index..][0..export_range.len] |
| 1676 | else |
| 1677 | &.{}) |@"export"| |
| 1678 | { |
| 1679 | if (@"export".exported == .nav and @"export".exported.nav == nav_index) break true; |
| 1680 | } else false)); |
| 1681 | }, |
| 1682 | .func => |func| { |
| 1683 | assert(file.zir_loaded); |
| 1684 | const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst)); |
| 1685 | assert(decl_inst.tag == .declaration); |
| 1686 | const tree = try file.getTree(dwarf.gpa); |
| 1687 | const loc = tree.tokenLocation(0, tree.nodes.items(.main_token)[decl_inst.data.declaration.src_node]); |
| 1688 | assert(loc.line == zcu.navSrcLine(nav_index)); |
| 1689 | |
| 1690 | const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: { |
| 1691 | const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index).data; |
| 1692 | const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace); |
| 1693 | break :parent .{ |
| 1694 | parent_namespace_ptr.owner_type, |
| 1695 | switch (decl_extra.name) { |
| 1696 | .@"comptime", |
| 1697 | .@"usingnamespace", |
| 1698 | .unnamed_test, |
| 1699 | .decltest, |
| 1700 | => DW.ACCESS.private, |
| 1701 | _ => if (decl_extra.name.isNamedTest(file.zir)) |
| 1702 | DW.ACCESS.private |
| 1703 | else if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu })) |
| 1704 | DW.ACCESS.public |
| 1705 | else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu })) |
| 1706 | DW.ACCESS.private |
| 1707 | else |
| 1708 | unreachable, |
| 1709 | }, |
| 1710 | }; |
| 1711 | } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private }; |
| 1712 | |
| 1713 | const func_type = ip.indexToKey(func.ty).func_type; |
| 1714 | wip_nav.func = nav_val.toIntern(); |
| 1715 | |
| 1716 | const diw = wip_nav.debug_info.writer(dwarf.gpa); |
| 1717 | try uleb128(diw, @intFromEnum(AbbrevCode.decl_func)); |
| 1718 | try wip_nav.refType(Type.fromInterned(parent_type)); |
| 1719 | assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); |
| 1720 | try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); |
| 1721 | try uleb128(diw, loc.column + 1); |
| 1722 | try diw.writeByte(accessibility); |
| 1723 | try wip_nav.strp(nav.name.toSlice(ip)); |
| 1724 | try wip_nav.strp(nav.fqn.toSlice(ip)); |
| 1725 | try wip_nav.refType(Type.fromInterned(func_type.return_type)); |
| 1726 | const external_relocs = &dwarf.debug_info.section.getUnit(unit).external_relocs; |
| 1727 | try external_relocs.append(dwarf.gpa, .{ |
| 1728 | .source_entry = wip_nav.entry, |
| 1729 | .source_off = @intCast(wip_nav.debug_info.items.len), |
| 1730 | .target_sym = sym_index, |
| 1731 | }); |
| 1732 | try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size)); |
| 1733 | wip_nav.func_high_reloc = @intCast(external_relocs.items.len); |
| 1734 | try external_relocs.append(dwarf.gpa, .{ |
| 1735 | .source_entry = wip_nav.entry, |
| 1736 | .source_off = @intCast(wip_nav.debug_info.items.len), |
| 1737 | .target_sym = sym_index, |
| 1738 | }); |
| 1739 | try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size)); |
| 1740 | try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse |
| 1741 | target_info.defaultFunctionAlignment(file.mod.resolved_target.result).toByteUnits().?); |
| 1742 | const func_unit = InternPool.AnalUnit.wrap(.{ .func = nav_val.toIntern() }); |
| 1743 | try diw.writeByte(@intFromBool(for (if (zcu.single_exports.get(func_unit)) |export_index| |
| 1744 | zcu.all_exports.items[export_index..][0..1] |
| 1745 | else if (zcu.multi_exports.get(func_unit)) |export_range| |
| 1746 | zcu.all_exports.items[export_range.index..][0..export_range.len] |
| 1747 | else |
| 1748 | &.{}) |@"export"| |
| 1749 | { |
| 1750 | if (@"export".exported == .nav and @"export".exported.nav == nav_index) break true; |
| 1751 | } else false)); |
| 1752 | try diw.writeByte(@intFromBool(func_type.return_type == .noreturn_type)); |
| 1753 | |
| 1754 | const dlw = wip_nav.debug_line.writer(dwarf.gpa); |
| 1755 | try dlw.writeByte(DW.LNS.extended_op); |
| 1756 | if (dwarf.incremental()) { |
| 1757 | try uleb128(dlw, 1 + dwarf.sectionOffsetBytes()); |
| 1758 | try dlw.writeByte(DW.LNE.ZIG_set_decl); |
| 1759 | try dwarf.debug_line.section.getUnit(wip_nav.unit).cross_section_relocs.append(dwarf.gpa, .{ |
| 1760 | .source_entry = wip_nav.entry.toOptional(), |
| 1761 | .source_off = @intCast(wip_nav.debug_line.items.len), |
| 1762 | .target_sec = .debug_info, |
| 1763 | .target_unit = wip_nav.unit, |
| 1764 | .target_entry = wip_nav.entry.toOptional(), |
| 1765 | }); |
| 1766 | try dlw.writeByteNTimes(0, dwarf.sectionOffsetBytes()); |
| 2430 | 1767 | |
| 2431 | | const header_len = di_buf.items.len - after_header_len; |
| 2432 | | switch (self.format) { |
| 2433 | | .dwarf32 => mem.writeInt(u32, di_buf.items[before_header_len..][0..4], @intCast(header_len), target_endian), |
| 2434 | | .dwarf64 => mem.writeInt(u64, di_buf.items[before_header_len..][0..8], header_len, target_endian), |
| 2435 | | } |
| 1768 | try dlw.writeByte(DW.LNS.set_column); |
| 1769 | try uleb128(dlw, func.lbrace_column + 1); |
| 2436 | 1770 | |
| 2437 | | assert(needed_bytes == di_buf.items.len); |
| 1771 | try wip_nav.advancePCAndLine(func.lbrace_line, 0); |
| 1772 | } else { |
| 1773 | try uleb128(dlw, 1 + @intFromEnum(dwarf.address_size)); |
| 1774 | try dlw.writeByte(DW.LNE.set_address); |
| 1775 | try dwarf.debug_line.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{ |
| 1776 | .source_entry = wip_nav.entry, |
| 1777 | .source_off = @intCast(wip_nav.debug_line.items.len), |
| 1778 | .target_sym = sym_index, |
| 1779 | }); |
| 1780 | try dlw.writeByteNTimes(0, @intFromEnum(dwarf.address_size)); |
| 2438 | 1781 | |
| 2439 | | if (di_buf.items.len > dbg_line_prg_off) { |
| 2440 | | const needed_with_padding = padToIdeal(needed_bytes); |
| 2441 | | const delta = needed_with_padding - dbg_line_prg_off; |
| 1782 | const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file); |
| 1783 | try dlw.writeByte(DW.LNS.set_file); |
| 1784 | try uleb128(dlw, file_gop.index); |
| 2442 | 1785 | |
| 2443 | | const first_fn_index = self.src_fn_first_index.?; |
| 2444 | | const first_fn = self.getAtom(.src_fn, first_fn_index); |
| 2445 | | const last_fn_index = self.src_fn_last_index.?; |
| 2446 | | const last_fn = self.getAtom(.src_fn, last_fn_index); |
| 1786 | try dlw.writeByte(DW.LNS.set_column); |
| 1787 | try uleb128(dlw, func.lbrace_column + 1); |
| 2447 | 1788 | |
| 2448 | | var src_fn_index = first_fn_index; |
| 1789 | try wip_nav.advancePCAndLine(@intCast(loc.line + func.lbrace_line), 0); |
| 1790 | } |
| 1791 | }, |
| 1792 | } |
| 1793 | return wip_nav; |
| 1794 | } |
| 2449 | 1795 | |
| 2450 | | const buffer = try gpa.alloc(u8, last_fn.off + last_fn.len - first_fn.off); |
| 2451 | | defer gpa.free(buffer); |
| 1796 | pub fn finishWipNav( |
| 1797 | dwarf: *Dwarf, |
| 1798 | pt: Zcu.PerThread, |
| 1799 | nav_index: InternPool.Nav.Index, |
| 1800 | sym: struct { index: u32, addr: u64, size: u64 }, |
| 1801 | wip_nav: *WipNav, |
| 1802 | ) UpdateError!void { |
| 1803 | const zcu = pt.zcu; |
| 1804 | const ip = &zcu.intern_pool; |
| 1805 | const nav = ip.getNav(nav_index); |
| 1806 | log.debug("finishWipNav({})", .{nav.fqn.fmt(ip)}); |
| 1807 | |
| 1808 | if (wip_nav.func != .none) { |
| 1809 | dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs.items[wip_nav.func_high_reloc].target_off = sym.size; |
| 1810 | if (wip_nav.any_children) { |
| 1811 | const diw = wip_nav.debug_info.writer(dwarf.gpa); |
| 1812 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 1813 | } else std.leb.writeUnsignedFixed( |
| 1814 | AbbrevCode.decl_bytes, |
| 1815 | wip_nav.debug_info.items[0..AbbrevCode.decl_bytes], |
| 1816 | @intFromEnum(AbbrevCode.decl_func_empty), |
| 1817 | ); |
| 2452 | 1818 | |
| 2453 | | if (self.bin_file.cast(.elf)) |elf_file| { |
| 2454 | | const shdr_index = elf_file.debug_line_section_index.?; |
| 2455 | | const needed_size = elf_file.shdrs.items[shdr_index].sh_size + delta; |
| 2456 | | try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true); |
| 2457 | | const file_pos = elf_file.shdrs.items[shdr_index].sh_offset + first_fn.off; |
| 1819 | var aranges_entry = [1]u8{0} ** (8 + 8); |
| 1820 | try dwarf.debug_aranges.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{ |
| 1821 | .source_entry = wip_nav.entry, |
| 1822 | .target_sym = sym.index, |
| 1823 | }); |
| 1824 | dwarf.writeInt(aranges_entry[0..@intFromEnum(dwarf.address_size)], 0); |
| 1825 | dwarf.writeInt(aranges_entry[@intFromEnum(dwarf.address_size)..][0..@intFromEnum(dwarf.address_size)], sym.size); |
| 1826 | |
| 1827 | @memset(aranges_entry[0..@intFromEnum(dwarf.address_size)], 0); |
| 1828 | try dwarf.debug_aranges.section.replaceEntry( |
| 1829 | wip_nav.unit, |
| 1830 | wip_nav.entry, |
| 1831 | dwarf, |
| 1832 | aranges_entry[0 .. @intFromEnum(dwarf.address_size) * 2], |
| 1833 | ); |
| 2458 | 1834 | |
| 2459 | | const amt = try elf_file.base.file.?.preadAll(buffer, file_pos); |
| 2460 | | if (amt != buffer.len) return error.InputOutput; |
| 1835 | try dwarf.debug_rnglists.section.getUnit(wip_nav.unit).external_relocs.appendSlice(dwarf.gpa, &.{ |
| 1836 | .{ |
| 1837 | .source_entry = wip_nav.entry, |
| 1838 | .source_off = 1, |
| 1839 | .target_sym = sym.index, |
| 1840 | }, |
| 1841 | .{ |
| 1842 | .source_entry = wip_nav.entry, |
| 1843 | .source_off = 1 + @intFromEnum(dwarf.address_size), |
| 1844 | .target_sym = sym.index, |
| 1845 | .target_off = sym.size, |
| 1846 | }, |
| 1847 | }); |
| 1848 | try dwarf.debug_rnglists.section.replaceEntry( |
| 1849 | wip_nav.unit, |
| 1850 | wip_nav.entry, |
| 1851 | dwarf, |
| 1852 | ([1]u8{DW.RLE.start_end} ++ [1]u8{0} ** (8 + 8))[0 .. 1 + @intFromEnum(dwarf.address_size) + @intFromEnum(dwarf.address_size)], |
| 1853 | ); |
| 1854 | } |
| 2461 | 1855 | |
| 2462 | | try elf_file.base.file.?.pwriteAll(buffer, file_pos + delta); |
| 2463 | | } else if (self.bin_file.cast(.macho)) |macho_file| { |
| 2464 | | if (macho_file.base.isRelocatable()) { |
| 2465 | | const sect_index = macho_file.debug_line_sect_index.?; |
| 2466 | | const needed_size: u32 = @intCast(macho_file.sections.items(.header)[sect_index].size + delta); |
| 2467 | | try macho_file.growSection(sect_index, needed_size); |
| 2468 | | const file_pos = macho_file.sections.items(.header)[sect_index].offset + first_fn.off; |
| 1856 | try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); |
| 1857 | if (wip_nav.debug_line.items.len > 0) { |
| 1858 | const dlw = wip_nav.debug_line.writer(dwarf.gpa); |
| 1859 | try dlw.writeByte(DW.LNS.extended_op); |
| 1860 | try uleb128(dlw, 1); |
| 1861 | try dlw.writeByte(DW.LNE.end_sequence); |
| 1862 | try dwarf.debug_line.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_line.items); |
| 1863 | } |
| 1864 | try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.items); |
| 2469 | 1865 | |
| 2470 | | const amt = try macho_file.base.file.?.preadAll(buffer, file_pos); |
| 2471 | | if (amt != buffer.len) return error.InputOutput; |
| 1866 | try wip_nav.flush(); |
| 1867 | } |
| 2472 | 1868 | |
| 2473 | | try macho_file.base.file.?.pwriteAll(buffer, file_pos + delta); |
| 2474 | | } else { |
| 2475 | | const d_sym = macho_file.getDebugSymbols().?; |
| 2476 | | const sect_index = d_sym.debug_line_section_index.?; |
| 2477 | | const needed_size: u32 = @intCast(d_sym.getSection(sect_index).size + delta); |
| 2478 | | try d_sym.growSection(sect_index, needed_size, true, macho_file); |
| 2479 | | const file_pos = d_sym.getSection(sect_index).offset + first_fn.off; |
| 1869 | pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateError!void { |
| 1870 | const zcu = pt.zcu; |
| 1871 | const ip = &zcu.intern_pool; |
| 1872 | const nav_val = zcu.navValue(nav_index); |
| 2480 | 1873 | |
| 2481 | | const amt = try d_sym.file.preadAll(buffer, file_pos); |
| 2482 | | if (amt != buffer.len) return error.InputOutput; |
| 1874 | const nav = ip.getNav(nav_index); |
| 1875 | log.debug("updateComptimeNav({})", .{nav.fqn.fmt(ip)}); |
| 1876 | |
| 1877 | const inst_info = nav.srcInst(ip).resolveFull(ip); |
| 1878 | const file = zcu.fileByIndex(inst_info.file); |
| 1879 | assert(file.zir_loaded); |
| 1880 | const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst)); |
| 1881 | assert(decl_inst.tag == .declaration); |
| 1882 | const tree = try file.getTree(dwarf.gpa); |
| 1883 | const loc = tree.tokenLocation(0, tree.nodes.items(.main_token)[decl_inst.data.declaration.src_node]); |
| 1884 | assert(loc.line == zcu.navSrcLine(nav_index)); |
| 1885 | |
| 1886 | const unit = try dwarf.getUnit(file.mod); |
| 1887 | var wip_nav: WipNav = .{ |
| 1888 | .dwarf = dwarf, |
| 1889 | .pt = pt, |
| 1890 | .unit = unit, |
| 1891 | .entry = undefined, |
| 1892 | .any_children = false, |
| 1893 | .func = .none, |
| 1894 | .func_high_reloc = undefined, |
| 1895 | .debug_info = .{}, |
| 1896 | .debug_line = .{}, |
| 1897 | .debug_loclists = .{}, |
| 1898 | .pending_types = .{}, |
| 1899 | }; |
| 1900 | defer wip_nav.deinit(); |
| 1901 | |
| 1902 | const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index); |
| 1903 | errdefer _ = dwarf.navs.pop(); |
| 1904 | switch (ip.indexToKey(nav_val.toIntern())) { |
| 1905 | .struct_type => done: { |
| 1906 | const loaded_struct = ip.loadStructType(nav_val.toIntern()); |
| 1907 | |
| 1908 | const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: { |
| 1909 | const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace); |
| 1910 | break :parent .{ |
| 1911 | parent_namespace_ptr.owner_type, |
| 1912 | if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu })) |
| 1913 | DW.ACCESS.public |
| 1914 | else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu })) |
| 1915 | DW.ACCESS.private |
| 1916 | else |
| 1917 | unreachable, |
| 1918 | }; |
| 1919 | } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private }; |
| 1920 | |
| 1921 | decl_struct: { |
| 1922 | if (loaded_struct.zir_index == .none) break :decl_struct; |
| 1923 | |
| 1924 | const value_inst = value_inst: { |
| 1925 | const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index); |
| 1926 | const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body; |
| 1927 | const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1])); |
| 1928 | if (break_inst.tag != .break_inline) break :value_inst null; |
| 1929 | assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst); |
| 1930 | var value_inst = break_inst.data.@"break".operand.toIndex(); |
| 1931 | while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) { |
| 1932 | else => break, |
| 1933 | .as_node => value_inst = file.zir.extraData( |
| 1934 | Zir.Inst.As, |
| 1935 | file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index, |
| 1936 | ).data.operand.toIndex(), |
| 1937 | }; |
| 1938 | break :value_inst value_inst; |
| 1939 | }; |
| 1940 | const type_inst_info = loaded_struct.zir_index.unwrap().?.resolveFull(ip); |
| 1941 | if (type_inst_info.inst != value_inst) break :decl_struct; |
| 2483 | 1942 | |
| 2484 | | try d_sym.file.pwriteAll(buffer, file_pos + delta); |
| 1943 | const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); |
| 1944 | if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else { |
| 1945 | if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit); |
| 1946 | type_gop.value_ptr.* = nav_gop.value_ptr.*; |
| 1947 | } |
| 1948 | wip_nav.entry = nav_gop.value_ptr.*; |
| 1949 | const diw = wip_nav.debug_info.writer(dwarf.gpa); |
| 1950 | |
| 1951 | switch (loaded_struct.layout) { |
| 1952 | .auto, .@"extern" => { |
| 1953 | try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0) |
| 1954 | .decl_namespace_struct |
| 1955 | else |
| 1956 | .decl_struct))); |
| 1957 | try wip_nav.refType(Type.fromInterned(parent_type)); |
| 1958 | assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); |
| 1959 | try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); |
| 1960 | try uleb128(diw, loc.column + 1); |
| 1961 | try diw.writeByte(accessibility); |
| 1962 | try wip_nav.strp(nav.name.toSlice(ip)); |
| 1963 | if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else { |
| 1964 | try uleb128(diw, nav_val.toType().abiSize(pt)); |
| 1965 | try uleb128(diw, nav_val.toType().abiAlignment(pt).toByteUnits().?); |
| 1966 | for (0..loaded_struct.field_types.len) |field_index| { |
| 1967 | const is_comptime = loaded_struct.fieldIsComptime(ip, field_index); |
| 1968 | try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_comptime) .struct_field_comptime else .struct_field))); |
| 1969 | if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else { |
| 1970 | const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index}); |
| 1971 | defer dwarf.gpa.free(field_name); |
| 1972 | try wip_nav.strp(field_name); |
| 1973 | } |
| 1974 | const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]); |
| 1975 | try wip_nav.refType(field_type); |
| 1976 | if (!is_comptime) { |
| 1977 | try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]); |
| 1978 | try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse |
| 1979 | field_type.abiAlignment(pt).toByteUnits().?); |
| 1980 | } |
| 1981 | } |
| 1982 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 1983 | } |
| 1984 | }, |
| 1985 | .@"packed" => { |
| 1986 | try uleb128(diw, @intFromEnum(AbbrevCode.decl_packed_struct)); |
| 1987 | try wip_nav.refType(Type.fromInterned(parent_type)); |
| 1988 | assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); |
| 1989 | try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); |
| 1990 | try uleb128(diw, loc.column + 1); |
| 1991 | try diw.writeByte(accessibility); |
| 1992 | try wip_nav.strp(nav.name.toSlice(ip)); |
| 1993 | try wip_nav.refType(Type.fromInterned(loaded_struct.backingIntTypeUnordered(ip))); |
| 1994 | var field_bit_offset: u16 = 0; |
| 1995 | for (0..loaded_struct.field_types.len) |field_index| { |
| 1996 | try uleb128(diw, @intFromEnum(@as(AbbrevCode, .packed_struct_field))); |
| 1997 | try wip_nav.strp(loaded_struct.fieldName(ip, field_index).unwrap().?.toSlice(ip)); |
| 1998 | const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]); |
| 1999 | try wip_nav.refType(field_type); |
| 2000 | try uleb128(diw, field_bit_offset); |
| 2001 | field_bit_offset += @intCast(field_type.bitSize(pt)); |
| 2002 | } |
| 2003 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2004 | }, |
| 2005 | } |
| 2006 | break :done; |
| 2485 | 2007 | } |
| 2486 | | } else if (self.bin_file.cast(.wasm)) |wasm_file| { |
| 2487 | | _ = wasm_file; |
| 2488 | | // const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code; |
| 2489 | | // { |
| 2490 | | // const src = debug_line.items[first_fn.off..]; |
| 2491 | | // @memcpy(buffer[0..src.len], src); |
| 2492 | | // } |
| 2493 | | // try debug_line.resize(self.allocator, debug_line.items.len + delta); |
| 2494 | | // @memcpy(debug_line.items[first_fn.off + delta ..][0..buffer.len], buffer); |
| 2495 | | } else unreachable; |
| 2496 | | |
| 2497 | | while (true) { |
| 2498 | | const src_fn = self.getAtomPtr(.src_fn, src_fn_index); |
| 2499 | | src_fn.off += delta; |
| 2500 | | |
| 2501 | | if (src_fn.next_index) |next_index| { |
| 2502 | | src_fn_index = next_index; |
| 2503 | | } else break; |
| 2504 | | } |
| 2505 | | } |
| 2506 | 2008 | |
| 2507 | | // Backpatch actual length of the debug line program |
| 2508 | | const init_len = self.getDebugLineProgramEnd().? - init_len_size; |
| 2509 | | switch (self.format) { |
| 2510 | | .dwarf32 => { |
| 2511 | | mem.writeInt(u32, di_buf.items[0..4], @intCast(init_len), target_endian); |
| 2512 | | }, |
| 2513 | | .dwarf64 => { |
| 2514 | | mem.writeInt(u64, di_buf.items[4..][0..8], init_len, target_endian); |
| 2009 | if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit); |
| 2010 | wip_nav.entry = nav_gop.value_ptr.*; |
| 2011 | const diw = wip_nav.debug_info.writer(dwarf.gpa); |
| 2012 | try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias)); |
| 2013 | try wip_nav.refType(Type.fromInterned(parent_type)); |
| 2014 | assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); |
| 2015 | try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); |
| 2016 | try uleb128(diw, loc.column + 1); |
| 2017 | try diw.writeByte(accessibility); |
| 2018 | try wip_nav.strp(nav.name.toSlice(ip)); |
| 2019 | try wip_nav.refType(nav_val.toType()); |
| 2515 | 2020 | }, |
| 2516 | | } |
| 2021 | .enum_type => done: { |
| 2022 | const loaded_enum = ip.loadEnumType(nav_val.toIntern()); |
| 2023 | |
| 2024 | const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: { |
| 2025 | const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace); |
| 2026 | break :parent .{ |
| 2027 | parent_namespace_ptr.owner_type, |
| 2028 | if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu })) |
| 2029 | DW.ACCESS.public |
| 2030 | else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu })) |
| 2031 | DW.ACCESS.private |
| 2032 | else |
| 2033 | unreachable, |
| 2034 | }; |
| 2035 | } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private }; |
| 2036 | |
| 2037 | decl_enum: { |
| 2038 | if (loaded_enum.zir_index == .none) break :decl_enum; |
| 2039 | |
| 2040 | const value_inst = value_inst: { |
| 2041 | const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index); |
| 2042 | const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body; |
| 2043 | const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1])); |
| 2044 | if (break_inst.tag != .break_inline) break :value_inst null; |
| 2045 | assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst); |
| 2046 | var value_inst = break_inst.data.@"break".operand.toIndex(); |
| 2047 | while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) { |
| 2048 | else => break, |
| 2049 | .as_node => value_inst = file.zir.extraData( |
| 2050 | Zir.Inst.As, |
| 2051 | file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index, |
| 2052 | ).data.operand.toIndex(), |
| 2053 | }; |
| 2054 | break :value_inst value_inst; |
| 2055 | }; |
| 2056 | const type_inst_info = loaded_enum.zir_index.unwrap().?.resolveFull(ip); |
| 2057 | if (type_inst_info.inst != value_inst) break :decl_enum; |
| 2517 | 2058 | |
| 2518 | | // We use NOPs because consumers empirically do not respect the header length field. |
| 2519 | | const jmp_amt = self.getDebugLineProgramOff().? - di_buf.items.len; |
| 2520 | | if (self.bin_file.cast(.elf)) |elf_file| { |
| 2521 | | const debug_line_sect = &elf_file.shdrs.items[elf_file.debug_line_section_index.?]; |
| 2522 | | const file_pos = debug_line_sect.sh_offset; |
| 2523 | | try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt); |
| 2524 | | } else if (self.bin_file.cast(.macho)) |macho_file| { |
| 2525 | | if (macho_file.base.isRelocatable()) { |
| 2526 | | const debug_line_sect = macho_file.sections.items(.header)[macho_file.debug_line_sect_index.?]; |
| 2527 | | const file_pos = debug_line_sect.offset; |
| 2528 | | try pwriteDbgLineNops(macho_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt); |
| 2529 | | } else { |
| 2530 | | const d_sym = macho_file.getDebugSymbols().?; |
| 2531 | | const debug_line_sect = d_sym.getSection(d_sym.debug_line_section_index.?); |
| 2532 | | const file_pos = debug_line_sect.offset; |
| 2533 | | try pwriteDbgLineNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt); |
| 2534 | | } |
| 2535 | | } else if (self.bin_file.cast(.wasm)) |wasm_file| { |
| 2536 | | _ = wasm_file; |
| 2537 | | // const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code; |
| 2538 | | // writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt); |
| 2539 | | } else unreachable; |
| 2540 | | } |
| 2059 | const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); |
| 2060 | if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else { |
| 2061 | if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit); |
| 2062 | type_gop.value_ptr.* = nav_gop.value_ptr.*; |
| 2063 | } |
| 2064 | wip_nav.entry = nav_gop.value_ptr.*; |
| 2065 | const diw = wip_nav.debug_info.writer(dwarf.gpa); |
| 2066 | try uleb128(diw, @intFromEnum(AbbrevCode.decl_enum)); |
| 2067 | try wip_nav.refType(Type.fromInterned(parent_type)); |
| 2068 | assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); |
| 2069 | try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); |
| 2070 | try uleb128(diw, loc.column + 1); |
| 2071 | try diw.writeByte(accessibility); |
| 2072 | try wip_nav.strp(nav.name.toSlice(ip)); |
| 2073 | try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty)); |
| 2074 | for (0..loaded_enum.names.len) |field_index| { |
| 2075 | try wip_nav.enumConstValue(loaded_enum, .{ |
| 2076 | .signed = .signed_enum_field, |
| 2077 | .unsigned = .unsigned_enum_field, |
| 2078 | }, field_index); |
| 2079 | try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip)); |
| 2080 | } |
| 2081 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2082 | break :done; |
| 2083 | } |
| 2541 | 2084 | |
| 2542 | | fn getDebugInfoOff(self: Dwarf) ?u32 { |
| 2543 | | const first_index = self.di_atom_first_index orelse return null; |
| 2544 | | const first = self.getAtom(.di_atom, first_index); |
| 2545 | | return first.off; |
| 2546 | | } |
| 2085 | if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit); |
| 2086 | wip_nav.entry = nav_gop.value_ptr.*; |
| 2087 | const diw = wip_nav.debug_info.writer(dwarf.gpa); |
| 2088 | try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias)); |
| 2089 | try wip_nav.refType(Type.fromInterned(parent_type)); |
| 2090 | assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); |
| 2091 | try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); |
| 2092 | try uleb128(diw, loc.column + 1); |
| 2093 | try diw.writeByte(accessibility); |
| 2094 | try wip_nav.strp(nav.name.toSlice(ip)); |
| 2095 | try wip_nav.refType(nav_val.toType()); |
| 2096 | }, |
| 2097 | .union_type => done: { |
| 2098 | const loaded_union = ip.loadUnionType(nav_val.toIntern()); |
| 2099 | |
| 2100 | const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: { |
| 2101 | const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace); |
| 2102 | break :parent .{ |
| 2103 | parent_namespace_ptr.owner_type, |
| 2104 | if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu })) |
| 2105 | DW.ACCESS.public |
| 2106 | else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu })) |
| 2107 | DW.ACCESS.private |
| 2108 | else |
| 2109 | unreachable, |
| 2110 | }; |
| 2111 | } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private }; |
| 2112 | |
| 2113 | decl_union: { |
| 2114 | const value_inst = value_inst: { |
| 2115 | const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index); |
| 2116 | const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body; |
| 2117 | const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1])); |
| 2118 | if (break_inst.tag != .break_inline) break :value_inst null; |
| 2119 | assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst); |
| 2120 | var value_inst = break_inst.data.@"break".operand.toIndex(); |
| 2121 | while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) { |
| 2122 | else => break, |
| 2123 | .as_node => value_inst = file.zir.extraData( |
| 2124 | Zir.Inst.As, |
| 2125 | file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index, |
| 2126 | ).data.operand.toIndex(), |
| 2127 | }; |
| 2128 | break :value_inst value_inst; |
| 2129 | }; |
| 2130 | const type_inst_info = loaded_union.zir_index.resolveFull(ip); |
| 2131 | if (type_inst_info.inst != value_inst) break :decl_union; |
| 2547 | 2132 | |
| 2548 | | fn getDebugInfoEnd(self: Dwarf) ?u32 { |
| 2549 | | const last_index = self.di_atom_last_index orelse return null; |
| 2550 | | const last = self.getAtom(.di_atom, last_index); |
| 2551 | | return last.off + last.len; |
| 2552 | | } |
| 2133 | const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); |
| 2134 | if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else { |
| 2135 | if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit); |
| 2136 | type_gop.value_ptr.* = nav_gop.value_ptr.*; |
| 2137 | } |
| 2138 | wip_nav.entry = nav_gop.value_ptr.*; |
| 2139 | const diw = wip_nav.debug_info.writer(dwarf.gpa); |
| 2140 | try uleb128(diw, @intFromEnum(AbbrevCode.decl_union)); |
| 2141 | try wip_nav.refType(Type.fromInterned(parent_type)); |
| 2142 | assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); |
| 2143 | try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); |
| 2144 | try uleb128(diw, loc.column + 1); |
| 2145 | try diw.writeByte(accessibility); |
| 2146 | try wip_nav.strp(nav.name.toSlice(ip)); |
| 2147 | const union_layout = pt.getUnionLayout(loaded_union); |
| 2148 | try uleb128(diw, union_layout.abi_size); |
| 2149 | try uleb128(diw, union_layout.abi_align.toByteUnits().?); |
| 2150 | const loaded_tag = loaded_union.loadTagType(ip); |
| 2151 | if (loaded_union.hasTag(ip)) { |
| 2152 | try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union)); |
| 2153 | try wip_nav.infoSectionOffset( |
| 2154 | .debug_info, |
| 2155 | wip_nav.unit, |
| 2156 | wip_nav.entry, |
| 2157 | @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()), |
| 2158 | ); |
| 2159 | { |
| 2160 | try uleb128(diw, @intFromEnum(AbbrevCode.generated_field)); |
| 2161 | try wip_nav.strp("tag"); |
| 2162 | try wip_nav.refType(Type.fromInterned(loaded_union.enum_tag_ty)); |
| 2163 | try uleb128(diw, union_layout.tagOffset()); |
| 2164 | |
| 2165 | for (0..loaded_union.field_types.len) |field_index| { |
| 2166 | try wip_nav.enumConstValue(loaded_tag, .{ |
| 2167 | .signed = .signed_tagged_union_field, |
| 2168 | .unsigned = .unsigned_tagged_union_field, |
| 2169 | }, field_index); |
| 2170 | { |
| 2171 | try uleb128(diw, @intFromEnum(AbbrevCode.struct_field)); |
| 2172 | try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip)); |
| 2173 | const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]); |
| 2174 | try wip_nav.refType(field_type); |
| 2175 | try uleb128(diw, union_layout.payloadOffset()); |
| 2176 | try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse |
| 2177 | if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(pt).toByteUnits().?); |
| 2178 | } |
| 2179 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2180 | } |
| 2181 | } |
| 2182 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2183 | |
| 2184 | if (ip.indexToKey(loaded_union.enum_tag_ty).enum_type == .generated_tag) |
| 2185 | try wip_nav.pending_types.append(dwarf.gpa, loaded_union.enum_tag_ty); |
| 2186 | } else for (0..loaded_union.field_types.len) |field_index| { |
| 2187 | try uleb128(diw, @intFromEnum(AbbrevCode.untagged_union_field)); |
| 2188 | try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip)); |
| 2189 | const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]); |
| 2190 | try wip_nav.refType(field_type); |
| 2191 | try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse |
| 2192 | field_type.abiAlignment(pt).toByteUnits().?); |
| 2193 | } |
| 2194 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2195 | break :done; |
| 2196 | } |
| 2553 | 2197 | |
| 2554 | | fn getDebugLineProgramOff(self: Dwarf) ?u32 { |
| 2555 | | const first_index = self.src_fn_first_index orelse return null; |
| 2556 | | const first = self.getAtom(.src_fn, first_index); |
| 2557 | | return first.off; |
| 2558 | | } |
| 2198 | if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit); |
| 2199 | wip_nav.entry = nav_gop.value_ptr.*; |
| 2200 | const diw = wip_nav.debug_info.writer(dwarf.gpa); |
| 2201 | try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias)); |
| 2202 | try wip_nav.refType(Type.fromInterned(parent_type)); |
| 2203 | assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); |
| 2204 | try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); |
| 2205 | try uleb128(diw, loc.column + 1); |
| 2206 | try diw.writeByte(accessibility); |
| 2207 | try wip_nav.strp(nav.name.toSlice(ip)); |
| 2208 | try wip_nav.refType(nav_val.toType()); |
| 2209 | }, |
| 2210 | .opaque_type => done: { |
| 2211 | const loaded_opaque = ip.loadOpaqueType(nav_val.toIntern()); |
| 2212 | |
| 2213 | const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: { |
| 2214 | const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace); |
| 2215 | break :parent .{ |
| 2216 | parent_namespace_ptr.owner_type, |
| 2217 | if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu })) |
| 2218 | DW.ACCESS.public |
| 2219 | else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu })) |
| 2220 | DW.ACCESS.private |
| 2221 | else |
| 2222 | unreachable, |
| 2223 | }; |
| 2224 | } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private }; |
| 2225 | |
| 2226 | decl_opaque: { |
| 2227 | const value_inst = value_inst: { |
| 2228 | const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index); |
| 2229 | const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body; |
| 2230 | const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1])); |
| 2231 | if (break_inst.tag != .break_inline) break :value_inst null; |
| 2232 | assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst); |
| 2233 | var value_inst = break_inst.data.@"break".operand.toIndex(); |
| 2234 | while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) { |
| 2235 | else => break, |
| 2236 | .as_node => value_inst = file.zir.extraData( |
| 2237 | Zir.Inst.As, |
| 2238 | file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index, |
| 2239 | ).data.operand.toIndex(), |
| 2240 | }; |
| 2241 | break :value_inst value_inst; |
| 2242 | }; |
| 2243 | const type_inst_info = loaded_opaque.zir_index.resolveFull(ip); |
| 2244 | if (type_inst_info.inst != value_inst) break :decl_opaque; |
| 2559 | 2245 | |
| 2560 | | fn getDebugLineProgramEnd(self: Dwarf) ?u32 { |
| 2561 | | const last_index = self.src_fn_last_index orelse return null; |
| 2562 | | const last = self.getAtom(.src_fn, last_index); |
| 2563 | | return last.off + last.len; |
| 2564 | | } |
| 2246 | const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); |
| 2247 | if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else { |
| 2248 | if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit); |
| 2249 | type_gop.value_ptr.* = nav_gop.value_ptr.*; |
| 2250 | } |
| 2251 | wip_nav.entry = nav_gop.value_ptr.*; |
| 2252 | const diw = wip_nav.debug_info.writer(dwarf.gpa); |
| 2253 | try uleb128(diw, @intFromEnum(AbbrevCode.decl_namespace_struct)); |
| 2254 | try wip_nav.refType(Type.fromInterned(parent_type)); |
| 2255 | assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); |
| 2256 | try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); |
| 2257 | try uleb128(diw, loc.column + 1); |
| 2258 | try diw.writeByte(accessibility); |
| 2259 | try wip_nav.strp(nav.name.toSlice(ip)); |
| 2260 | try diw.writeByte(@intFromBool(false)); |
| 2261 | break :done; |
| 2262 | } |
| 2565 | 2263 | |
| 2566 | | /// Always 4 or 8 depending on whether this is 32-bit or 64-bit format. |
| 2567 | | fn ptrWidthBytes(self: Dwarf) u8 { |
| 2568 | | return switch (self.ptr_width) { |
| 2569 | | .p32 => 4, |
| 2570 | | .p64 => 8, |
| 2571 | | }; |
| 2264 | if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit); |
| 2265 | wip_nav.entry = nav_gop.value_ptr.*; |
| 2266 | const diw = wip_nav.debug_info.writer(dwarf.gpa); |
| 2267 | try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias)); |
| 2268 | try wip_nav.refType(Type.fromInterned(parent_type)); |
| 2269 | assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); |
| 2270 | try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); |
| 2271 | try uleb128(diw, loc.column + 1); |
| 2272 | try diw.writeByte(accessibility); |
| 2273 | try wip_nav.strp(nav.name.toSlice(ip)); |
| 2274 | try wip_nav.refType(nav_val.toType()); |
| 2275 | }, |
| 2276 | else => { |
| 2277 | _ = dwarf.navs.pop(); |
| 2278 | return; |
| 2279 | }, |
| 2280 | } |
| 2281 | try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); |
| 2282 | try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.items); |
| 2283 | try wip_nav.flush(); |
| 2572 | 2284 | } |
| 2573 | 2285 | |
| 2574 | | fn dbgLineNeededHeaderBytes(self: Dwarf, dirs: []const []const u8, files: []const []const u8) u32 { |
| 2575 | | var size: usize = switch (self.format) { // length field |
| 2576 | | .dwarf32 => 4, |
| 2577 | | .dwarf64 => 12, |
| 2578 | | }; |
| 2579 | | size += @sizeOf(u16); // version field |
| 2580 | | size += switch (self.format) { // offset to end-of-header |
| 2581 | | .dwarf32 => 4, |
| 2582 | | .dwarf64 => 8, |
| 2583 | | }; |
| 2584 | | size += 18; // opcodes |
| 2585 | | |
| 2586 | | for (dirs) |dir| { // include dirs |
| 2587 | | size += dir.len + 1; |
| 2286 | fn updateType( |
| 2287 | dwarf: *Dwarf, |
| 2288 | pt: Zcu.PerThread, |
| 2289 | type_index: InternPool.Index, |
| 2290 | pending_types: *std.ArrayListUnmanaged(InternPool.Index), |
| 2291 | ) UpdateError!void { |
| 2292 | const zcu = pt.zcu; |
| 2293 | const ip = &zcu.intern_pool; |
| 2294 | const ty = Type.fromInterned(type_index); |
| 2295 | switch (type_index) { |
| 2296 | .generic_poison_type => log.debug("updateType({s})", .{"anytype"}), |
| 2297 | else => log.debug("updateType({})", .{ty.fmt(pt)}), |
| 2588 | 2298 | } |
| 2589 | | size += 1; // include dirs sentinel |
| 2590 | 2299 | |
| 2591 | | for (files) |file| { // file names |
| 2592 | | size += file.len + 1 + 1 + 1 + 1; |
| 2300 | var wip_nav: WipNav = .{ |
| 2301 | .dwarf = dwarf, |
| 2302 | .pt = pt, |
| 2303 | .unit = .main, |
| 2304 | .entry = dwarf.types.get(type_index).?, |
| 2305 | .any_children = false, |
| 2306 | .func = .none, |
| 2307 | .func_high_reloc = undefined, |
| 2308 | .debug_info = .{}, |
| 2309 | .debug_line = .{}, |
| 2310 | .debug_loclists = .{}, |
| 2311 | .pending_types = pending_types.*, |
| 2312 | }; |
| 2313 | defer { |
| 2314 | pending_types.* = wip_nav.pending_types; |
| 2315 | wip_nav.pending_types = .{}; |
| 2316 | wip_nav.deinit(); |
| 2593 | 2317 | } |
| 2594 | | size += 1; // file names sentinel |
| 2595 | | |
| 2596 | | return @intCast(size); |
| 2597 | | } |
| 2318 | const diw = wip_nav.debug_info.writer(dwarf.gpa); |
| 2319 | const name = switch (type_index) { |
| 2320 | .generic_poison_type => "", |
| 2321 | else => try std.fmt.allocPrint(dwarf.gpa, "{}", .{ty.fmt(pt)}), |
| 2322 | }; |
| 2323 | defer dwarf.gpa.free(name); |
| 2324 | |
| 2325 | switch (ip.indexToKey(type_index)) { |
| 2326 | .int_type => |int_type| { |
| 2327 | try uleb128(diw, @intFromEnum(AbbrevCode.numeric_type)); |
| 2328 | try wip_nav.strp(name); |
| 2329 | try diw.writeByte(switch (int_type.signedness) { |
| 2330 | inline .signed, .unsigned => |signedness| @field(DW.ATE, @tagName(signedness)), |
| 2331 | }); |
| 2332 | try uleb128(diw, int_type.bits); |
| 2333 | try uleb128(diw, ty.abiSize(pt)); |
| 2334 | try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?); |
| 2335 | }, |
| 2336 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { |
| 2337 | .One, .Many, .C => { |
| 2338 | const ptr_child_type = Type.fromInterned(ptr_type.child); |
| 2339 | try uleb128(diw, @intFromEnum(AbbrevCode.ptr_type)); |
| 2340 | try wip_nav.strp(name); |
| 2341 | try diw.writeByte(@intFromBool(ptr_type.flags.is_allowzero)); |
| 2342 | try uleb128(diw, ptr_type.flags.alignment.toByteUnits() orelse |
| 2343 | ptr_child_type.abiAlignment(pt).toByteUnits().?); |
| 2344 | try diw.writeByte(@intFromEnum(ptr_type.flags.address_space)); |
| 2345 | if (ptr_type.flags.is_const or ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset( |
| 2346 | .debug_info, |
| 2347 | wip_nav.unit, |
| 2348 | wip_nav.entry, |
| 2349 | @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()), |
| 2350 | ) else try wip_nav.refType(ptr_child_type); |
| 2351 | if (ptr_type.flags.is_const) { |
| 2352 | try uleb128(diw, @intFromEnum(AbbrevCode.is_const)); |
| 2353 | if (ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset( |
| 2354 | .debug_info, |
| 2355 | wip_nav.unit, |
| 2356 | wip_nav.entry, |
| 2357 | @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()), |
| 2358 | ) else try wip_nav.refType(ptr_child_type); |
| 2359 | } |
| 2360 | if (ptr_type.flags.is_volatile) { |
| 2361 | try uleb128(diw, @intFromEnum(AbbrevCode.is_volatile)); |
| 2362 | try wip_nav.refType(ptr_child_type); |
| 2363 | } |
| 2364 | }, |
| 2365 | .Slice => { |
| 2366 | try uleb128(diw, @intFromEnum(AbbrevCode.struct_type)); |
| 2367 | try wip_nav.strp(name); |
| 2368 | try uleb128(diw, ty.abiSize(pt)); |
| 2369 | try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?); |
| 2370 | try uleb128(diw, @intFromEnum(AbbrevCode.generated_field)); |
| 2371 | try wip_nav.strp("ptr"); |
| 2372 | const ptr_field_type = ty.slicePtrFieldType(zcu); |
| 2373 | try wip_nav.refType(ptr_field_type); |
| 2374 | try uleb128(diw, 0); |
| 2375 | try uleb128(diw, @intFromEnum(AbbrevCode.generated_field)); |
| 2376 | try wip_nav.strp("len"); |
| 2377 | const len_field_type = Type.usize; |
| 2378 | try wip_nav.refType(len_field_type); |
| 2379 | try uleb128(diw, len_field_type.abiAlignment(pt).forward(ptr_field_type.abiSize(pt))); |
| 2380 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2381 | }, |
| 2382 | }, |
| 2383 | inline .array_type, .vector_type => |array_type, ty_tag| { |
| 2384 | try uleb128(diw, @intFromEnum(AbbrevCode.array_type)); |
| 2385 | try wip_nav.strp(name); |
| 2386 | try wip_nav.refType(Type.fromInterned(array_type.child)); |
| 2387 | try diw.writeByte(@intFromBool(ty_tag == .vector_type)); |
| 2388 | try uleb128(diw, @intFromEnum(AbbrevCode.array_index)); |
| 2389 | try wip_nav.refType(Type.usize); |
| 2390 | try uleb128(diw, array_type.len); |
| 2391 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2392 | }, |
| 2393 | .opt_type => |opt_child_type_index| { |
| 2394 | const opt_child_type = Type.fromInterned(opt_child_type_index); |
| 2395 | try uleb128(diw, @intFromEnum(AbbrevCode.union_type)); |
| 2396 | try wip_nav.strp(name); |
| 2397 | try uleb128(diw, ty.abiSize(pt)); |
| 2398 | try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?); |
| 2399 | if (opt_child_type.isNoReturn(zcu)) { |
| 2400 | try uleb128(diw, @intFromEnum(AbbrevCode.generated_field)); |
| 2401 | try wip_nav.strp("null"); |
| 2402 | try wip_nav.refType(Type.null); |
| 2403 | try uleb128(diw, 0); |
| 2404 | } else { |
| 2405 | try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union)); |
| 2406 | try wip_nav.infoSectionOffset( |
| 2407 | .debug_info, |
| 2408 | wip_nav.unit, |
| 2409 | wip_nav.entry, |
| 2410 | @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()), |
| 2411 | ); |
| 2412 | { |
| 2413 | try uleb128(diw, @intFromEnum(AbbrevCode.generated_field)); |
| 2414 | try wip_nav.strp("has_value"); |
| 2415 | const repr: enum { unpacked, error_set, pointer } = switch (opt_child_type_index) { |
| 2416 | .anyerror_type => .error_set, |
| 2417 | else => switch (ip.indexToKey(opt_child_type_index)) { |
| 2418 | else => .unpacked, |
| 2419 | .error_set_type, .inferred_error_set_type => .error_set, |
| 2420 | .ptr_type => |ptr_type| if (ptr_type.flags.is_allowzero) .unpacked else .pointer, |
| 2421 | }, |
| 2422 | }; |
| 2423 | switch (repr) { |
| 2424 | .unpacked => { |
| 2425 | try wip_nav.refType(Type.bool); |
| 2426 | try uleb128(diw, if (opt_child_type.hasRuntimeBits(pt)) |
| 2427 | opt_child_type.abiSize(pt) |
| 2428 | else |
| 2429 | 0); |
| 2430 | }, |
| 2431 | .error_set => { |
| 2432 | try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{ |
| 2433 | .signedness = .unsigned, |
| 2434 | .bits = pt.zcu.errorSetBits(), |
| 2435 | } }))); |
| 2436 | try uleb128(diw, 0); |
| 2437 | }, |
| 2438 | .pointer => { |
| 2439 | try wip_nav.refType(Type.usize); |
| 2440 | try uleb128(diw, 0); |
| 2441 | }, |
| 2442 | } |
| 2598 | 2443 | |
| 2599 | | /// The reloc offset for the line offset of a function from the previous function's line. |
| 2600 | | /// It's a fixed-size 4-byte ULEB128. |
| 2601 | | fn getRelocDbgLineOff(self: Dwarf) usize { |
| 2602 | | return dbg_line_vaddr_reloc_index + self.ptrWidthBytes() + 1; |
| 2603 | | } |
| 2444 | try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_tagged_union_field)); |
| 2445 | try uleb128(diw, 0); |
| 2446 | { |
| 2447 | try uleb128(diw, @intFromEnum(AbbrevCode.generated_field)); |
| 2448 | try wip_nav.strp("null"); |
| 2449 | try wip_nav.refType(Type.null); |
| 2450 | try uleb128(diw, 0); |
| 2451 | } |
| 2452 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2604 | 2453 | |
| 2605 | | fn getRelocDbgFileIndex(self: Dwarf) usize { |
| 2606 | | return self.getRelocDbgLineOff() + 5; |
| 2607 | | } |
| 2454 | try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union_default_field)); |
| 2455 | { |
| 2456 | try uleb128(diw, @intFromEnum(AbbrevCode.generated_field)); |
| 2457 | try wip_nav.strp("?"); |
| 2458 | try wip_nav.refType(opt_child_type); |
| 2459 | try uleb128(diw, 0); |
| 2460 | } |
| 2461 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2462 | } |
| 2463 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2464 | } |
| 2465 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2466 | }, |
| 2467 | .anyframe_type => unreachable, |
| 2468 | .error_union_type => |error_union_type| { |
| 2469 | const error_union_error_set_type = Type.fromInterned(error_union_type.error_set_type); |
| 2470 | const error_union_payload_type = Type.fromInterned(error_union_type.payload_type); |
| 2471 | const error_union_error_set_offset = codegen.errUnionErrorOffset(error_union_payload_type, pt); |
| 2472 | const error_union_payload_offset = codegen.errUnionPayloadOffset(error_union_payload_type, pt); |
| 2473 | |
| 2474 | try uleb128(diw, @intFromEnum(AbbrevCode.union_type)); |
| 2475 | try wip_nav.strp(name); |
| 2476 | try uleb128(diw, ty.abiSize(pt)); |
| 2477 | try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?); |
| 2478 | { |
| 2479 | try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union)); |
| 2480 | try wip_nav.infoSectionOffset( |
| 2481 | .debug_info, |
| 2482 | wip_nav.unit, |
| 2483 | wip_nav.entry, |
| 2484 | @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()), |
| 2485 | ); |
| 2486 | { |
| 2487 | try uleb128(diw, @intFromEnum(AbbrevCode.generated_field)); |
| 2488 | try wip_nav.strp("is_error"); |
| 2489 | const is_error_field_type = Type.fromInterned(try pt.intern(.{ |
| 2490 | .opt_type = error_union_type.error_set_type, |
| 2491 | })); |
| 2492 | try wip_nav.refType(is_error_field_type); |
| 2493 | try uleb128(diw, error_union_error_set_offset); |
| 2494 | |
| 2495 | try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_tagged_union_field)); |
| 2496 | try uleb128(diw, 0); |
| 2497 | { |
| 2498 | try uleb128(diw, @intFromEnum(AbbrevCode.generated_field)); |
| 2499 | try wip_nav.strp("value"); |
| 2500 | try wip_nav.refType(error_union_payload_type); |
| 2501 | try uleb128(diw, error_union_payload_offset); |
| 2502 | } |
| 2503 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2608 | 2504 | |
| 2609 | | fn getRelocDbgInfoSubprogramHighPC(self: Dwarf) u32 { |
| 2610 | | return dbg_info_low_pc_reloc_index + self.ptrWidthBytes(); |
| 2611 | | } |
| 2505 | try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union_default_field)); |
| 2506 | { |
| 2507 | try uleb128(diw, @intFromEnum(AbbrevCode.generated_field)); |
| 2508 | try wip_nav.strp("error"); |
| 2509 | try wip_nav.refType(error_union_error_set_type); |
| 2510 | try uleb128(diw, error_union_error_set_offset); |
| 2511 | } |
| 2512 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2513 | } |
| 2514 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2515 | } |
| 2516 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2517 | }, |
| 2518 | .simple_type => |simple_type| switch (simple_type) { |
| 2519 | .f16, |
| 2520 | .f32, |
| 2521 | .f64, |
| 2522 | .f80, |
| 2523 | .f128, |
| 2524 | .usize, |
| 2525 | .isize, |
| 2526 | .c_char, |
| 2527 | .c_short, |
| 2528 | .c_ushort, |
| 2529 | .c_int, |
| 2530 | .c_uint, |
| 2531 | .c_long, |
| 2532 | .c_ulong, |
| 2533 | .c_longlong, |
| 2534 | .c_ulonglong, |
| 2535 | .c_longdouble, |
| 2536 | .bool, |
| 2537 | => { |
| 2538 | try uleb128(diw, @intFromEnum(AbbrevCode.numeric_type)); |
| 2539 | try wip_nav.strp(name); |
| 2540 | try diw.writeByte(if (type_index == .bool_type) |
| 2541 | DW.ATE.boolean |
| 2542 | else if (ty.isRuntimeFloat()) |
| 2543 | DW.ATE.float |
| 2544 | else if (ty.isSignedInt(zcu)) |
| 2545 | DW.ATE.signed |
| 2546 | else if (ty.isUnsignedInt(zcu)) |
| 2547 | DW.ATE.unsigned |
| 2548 | else |
| 2549 | unreachable); |
| 2550 | try uleb128(diw, ty.bitSize(pt)); |
| 2551 | try uleb128(diw, ty.abiSize(pt)); |
| 2552 | try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?); |
| 2553 | }, |
| 2554 | .anyopaque, |
| 2555 | .void, |
| 2556 | .type, |
| 2557 | .comptime_int, |
| 2558 | .comptime_float, |
| 2559 | .noreturn, |
| 2560 | .null, |
| 2561 | .undefined, |
| 2562 | .enum_literal, |
| 2563 | .generic_poison, |
| 2564 | => { |
| 2565 | try uleb128(diw, @intFromEnum(AbbrevCode.void_type)); |
| 2566 | try wip_nav.strp(if (type_index == .generic_poison_type) "anytype" else name); |
| 2567 | }, |
| 2568 | .anyerror => return, // delay until flush |
| 2569 | .atomic_order, |
| 2570 | .atomic_rmw_op, |
| 2571 | .calling_convention, |
| 2572 | .address_space, |
| 2573 | .float_mode, |
| 2574 | .reduce_op, |
| 2575 | .call_modifier, |
| 2576 | .prefetch_options, |
| 2577 | .export_options, |
| 2578 | .extern_options, |
| 2579 | .type_info, |
| 2580 | .adhoc_inferred_error_set, |
| 2581 | => unreachable, |
| 2582 | }, |
| 2583 | .struct_type, |
| 2584 | .union_type, |
| 2585 | .opaque_type, |
| 2586 | => unreachable, |
| 2587 | .anon_struct_type => |anon_struct_type| { |
| 2588 | try uleb128(diw, @intFromEnum(AbbrevCode.struct_type)); |
| 2589 | try wip_nav.strp(name); |
| 2590 | try uleb128(diw, ty.abiSize(pt)); |
| 2591 | try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?); |
| 2592 | var field_byte_offset: u64 = 0; |
| 2593 | for (0..anon_struct_type.types.len) |field_index| { |
| 2594 | const comptime_value = anon_struct_type.values.get(ip)[field_index]; |
| 2595 | try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (comptime_value != .none) .struct_field_comptime else .struct_field))); |
| 2596 | if (anon_struct_type.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else { |
| 2597 | const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index}); |
| 2598 | defer dwarf.gpa.free(field_name); |
| 2599 | try wip_nav.strp(field_name); |
| 2600 | } |
| 2601 | const field_type = Type.fromInterned(anon_struct_type.types.get(ip)[field_index]); |
| 2602 | try wip_nav.refType(field_type); |
| 2603 | if (comptime_value == .none) { |
| 2604 | const field_align = field_type.abiAlignment(pt); |
| 2605 | field_byte_offset = field_align.forward(field_byte_offset); |
| 2606 | try uleb128(diw, field_byte_offset); |
| 2607 | try uleb128(diw, field_type.abiAlignment(pt).toByteUnits().?); |
| 2608 | field_byte_offset += field_type.abiSize(pt); |
| 2609 | } |
| 2610 | } |
| 2611 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2612 | }, |
| 2613 | .enum_type => { |
| 2614 | const loaded_enum = ip.loadEnumType(type_index); |
| 2615 | try uleb128(diw, @intFromEnum(AbbrevCode.enum_type)); |
| 2616 | try wip_nav.strp(name); |
| 2617 | try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty)); |
| 2618 | for (0..loaded_enum.names.len) |field_index| { |
| 2619 | try wip_nav.enumConstValue(loaded_enum, .{ |
| 2620 | .signed = .signed_enum_field, |
| 2621 | .unsigned = .unsigned_enum_field, |
| 2622 | }, field_index); |
| 2623 | try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip)); |
| 2624 | } |
| 2625 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2626 | }, |
| 2627 | .func_type => |func_type| { |
| 2628 | const is_nullary = func_type.param_types.len == 0 and !func_type.is_var_args; |
| 2629 | try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_nullary) .nullary_func_type else .func_type))); |
| 2630 | try wip_nav.strp(name); |
| 2631 | try diw.writeByte(@intFromEnum(@as(DW.CC, switch (func_type.cc) { |
| 2632 | .Unspecified, .C => .normal, |
| 2633 | .Naked, .Async, .Inline => .nocall, |
| 2634 | .Interrupt, .Signal => .nocall, |
| 2635 | .Stdcall => .BORLAND_stdcall, |
| 2636 | .Fastcall => .BORLAND_fastcall, |
| 2637 | .Vectorcall => .LLVM_vectorcall, |
| 2638 | .Thiscall => .BORLAND_thiscall, |
| 2639 | .APCS => .nocall, |
| 2640 | .AAPCS => .LLVM_AAPCS, |
| 2641 | .AAPCSVFP => .LLVM_AAPCS_VFP, |
| 2642 | .SysV => .LLVM_X86_64SysV, |
| 2643 | .Win64 => .LLVM_Win64, |
| 2644 | .Kernel, .Fragment, .Vertex => .nocall, |
| 2645 | }))); |
| 2646 | try wip_nav.refType(Type.fromInterned(func_type.return_type)); |
| 2647 | if (!is_nullary) { |
| 2648 | for (0..func_type.param_types.len) |param_index| { |
| 2649 | try uleb128(diw, @intFromEnum(AbbrevCode.func_type_param)); |
| 2650 | try wip_nav.refType(Type.fromInterned(func_type.param_types.get(ip)[param_index])); |
| 2651 | } |
| 2652 | if (func_type.is_var_args) try uleb128(diw, @intFromEnum(AbbrevCode.is_var_args)); |
| 2653 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2654 | } |
| 2655 | }, |
| 2656 | .error_set_type => |error_set_type| { |
| 2657 | try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (error_set_type.names.len > 0) .enum_type else .empty_enum_type))); |
| 2658 | try wip_nav.strp(name); |
| 2659 | try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{ |
| 2660 | .signedness = .unsigned, |
| 2661 | .bits = pt.zcu.errorSetBits(), |
| 2662 | } }))); |
| 2663 | for (0..error_set_type.names.len) |field_index| { |
| 2664 | const field_name = error_set_type.names.get(ip)[field_index]; |
| 2665 | try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_enum_field)); |
| 2666 | try uleb128(diw, ip.getErrorValueIfExists(field_name).?); |
| 2667 | try wip_nav.strp(field_name.toSlice(ip)); |
| 2668 | } |
| 2669 | if (error_set_type.names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2670 | }, |
| 2671 | .inferred_error_set_type => |func| { |
| 2672 | try uleb128(diw, @intFromEnum(AbbrevCode.inferred_error_set_type)); |
| 2673 | try wip_nav.strp(name); |
| 2674 | try wip_nav.refType(Type.fromInterned(ip.funcIesResolvedUnordered(func))); |
| 2675 | }, |
| 2612 | 2676 | |
| 2613 | | fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { |
| 2614 | | return actual_size +| (actual_size / ideal_factor); |
| 2677 | // values, not types |
| 2678 | .undef, |
| 2679 | .simple_value, |
| 2680 | .variable, |
| 2681 | .@"extern", |
| 2682 | .func, |
| 2683 | .int, |
| 2684 | .err, |
| 2685 | .error_union, |
| 2686 | .enum_literal, |
| 2687 | .enum_tag, |
| 2688 | .empty_enum_value, |
| 2689 | .float, |
| 2690 | .ptr, |
| 2691 | .slice, |
| 2692 | .opt, |
| 2693 | .aggregate, |
| 2694 | .un, |
| 2695 | // memoization, not types |
| 2696 | .memoized_call, |
| 2697 | => unreachable, |
| 2698 | } |
| 2699 | try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); |
| 2615 | 2700 | } |
| 2616 | 2701 | |
| 2617 | | pub fn flushModule(self: *Dwarf, pt: Zcu.PerThread) !void { |
| 2618 | | const comp = self.bin_file.comp; |
| 2619 | | const target = comp.root_mod.resolved_target.result; |
| 2620 | | |
| 2621 | | if (self.global_abbrev_relocs.items.len > 0) { |
| 2622 | | const gpa = self.allocator; |
| 2623 | | var arena_alloc = std.heap.ArenaAllocator.init(gpa); |
| 2624 | | defer arena_alloc.deinit(); |
| 2625 | | const arena = arena_alloc.allocator(); |
| 2626 | | |
| 2627 | | var dbg_info_buffer = std.ArrayList(u8).init(arena); |
| 2628 | | try addDbgInfoErrorSetNames( |
| 2629 | | pt, |
| 2630 | | Type.anyerror, |
| 2631 | | pt.zcu.intern_pool.global_error_set.getNamesFromMainThread(), |
| 2632 | | target, |
| 2633 | | &dbg_info_buffer, |
| 2634 | | ); |
| 2635 | | |
| 2636 | | const di_atom_index = try self.createAtom(.di_atom); |
| 2637 | | log.debug("updateNavDebugInfoAllocation in flushModule", .{}); |
| 2638 | | try self.updateNavDebugInfoAllocation(di_atom_index, @intCast(dbg_info_buffer.items.len)); |
| 2639 | | log.debug("writeNavDebugInfo in flushModule", .{}); |
| 2640 | | try self.writeNavDebugInfo(di_atom_index, dbg_info_buffer.items); |
| 2641 | | |
| 2642 | | const file_pos = if (self.bin_file.cast(.elf)) |elf_file| pos: { |
| 2643 | | const debug_info_sect = &elf_file.shdrs.items[elf_file.debug_info_section_index.?]; |
| 2644 | | break :pos debug_info_sect.sh_offset; |
| 2645 | | } else if (self.bin_file.cast(.macho)) |macho_file| pos: { |
| 2646 | | if (macho_file.base.isRelocatable()) { |
| 2647 | | const debug_info_sect = &macho_file.sections.items(.header)[macho_file.debug_info_sect_index.?]; |
| 2648 | | break :pos debug_info_sect.offset; |
| 2649 | | } else { |
| 2650 | | const d_sym = macho_file.getDebugSymbols().?; |
| 2651 | | const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?); |
| 2652 | | break :pos debug_info_sect.offset; |
| 2702 | pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternPool.Index) UpdateError!void { |
| 2703 | const zcu = pt.zcu; |
| 2704 | const ip = &zcu.intern_pool; |
| 2705 | const ty = Type.fromInterned(type_index); |
| 2706 | log.debug("updateContainerType({}({d}))", .{ ty.fmt(pt), @intFromEnum(type_index) }); |
| 2707 | |
| 2708 | const inst_info = ty.typeDeclInst(zcu).?.resolveFull(ip); |
| 2709 | const file = zcu.fileByIndex(inst_info.file); |
| 2710 | if (inst_info.inst == .main_struct_inst) { |
| 2711 | const unit = try dwarf.getUnit(file.mod); |
| 2712 | const type_gop = try dwarf.types.getOrPut(dwarf.gpa, type_index); |
| 2713 | if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(unit); |
| 2714 | var wip_nav: WipNav = .{ |
| 2715 | .dwarf = dwarf, |
| 2716 | .pt = pt, |
| 2717 | .unit = unit, |
| 2718 | .entry = type_gop.value_ptr.*, |
| 2719 | .any_children = false, |
| 2720 | .func = .none, |
| 2721 | .func_high_reloc = undefined, |
| 2722 | .debug_info = .{}, |
| 2723 | .debug_line = .{}, |
| 2724 | .debug_loclists = .{}, |
| 2725 | .pending_types = .{}, |
| 2726 | }; |
| 2727 | defer wip_nav.deinit(); |
| 2728 | |
| 2729 | const loaded_struct = ip.loadStructType(type_index); |
| 2730 | |
| 2731 | const diw = wip_nav.debug_info.writer(dwarf.gpa); |
| 2732 | try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0) .namespace_file else .file))); |
| 2733 | const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file); |
| 2734 | try uleb128(diw, file_gop.index); |
| 2735 | try wip_nav.strp(loaded_struct.name.toSlice(ip)); |
| 2736 | if (loaded_struct.field_types.len > 0) { |
| 2737 | try uleb128(diw, ty.abiSize(pt)); |
| 2738 | try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?); |
| 2739 | for (0..loaded_struct.field_types.len) |field_index| { |
| 2740 | const is_comptime = loaded_struct.fieldIsComptime(ip, field_index); |
| 2741 | try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_comptime) .struct_field_comptime else .struct_field))); |
| 2742 | if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else { |
| 2743 | const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index}); |
| 2744 | defer dwarf.gpa.free(field_name); |
| 2745 | try wip_nav.strp(field_name); |
| 2746 | } |
| 2747 | const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]); |
| 2748 | try wip_nav.refType(field_type); |
| 2749 | if (!is_comptime) { |
| 2750 | try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]); |
| 2751 | try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse |
| 2752 | field_type.abiAlignment(pt).toByteUnits().?); |
| 2753 | } |
| 2653 | 2754 | } |
| 2654 | | } else if (self.bin_file.cast(.wasm)) |_| |
| 2655 | | // for wasm, the offset is always 0 as we write to memory first |
| 2656 | | 0 |
| 2657 | | else |
| 2658 | | unreachable; |
| 2755 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2756 | } |
| 2659 | 2757 | |
| 2660 | | var buf: [@sizeOf(u32)]u8 = undefined; |
| 2661 | | mem.writeInt(u32, &buf, self.getAtom(.di_atom, di_atom_index).off, target.cpu.arch.endian()); |
| 2662 | | |
| 2663 | | while (self.global_abbrev_relocs.popOrNull()) |reloc| { |
| 2664 | | const atom = self.getAtom(.di_atom, reloc.atom_index); |
| 2665 | | if (self.bin_file.cast(.elf)) |elf_file| { |
| 2666 | | try elf_file.base.file.?.pwriteAll(&buf, file_pos + atom.off + reloc.offset); |
| 2667 | | } else if (self.bin_file.cast(.macho)) |macho_file| { |
| 2668 | | if (macho_file.base.isRelocatable()) { |
| 2669 | | try macho_file.base.file.?.pwriteAll(&buf, file_pos + atom.off + reloc.offset); |
| 2670 | | } else { |
| 2671 | | const d_sym = macho_file.getDebugSymbols().?; |
| 2672 | | try d_sym.file.pwriteAll(&buf, file_pos + atom.off + reloc.offset); |
| 2758 | try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); |
| 2759 | try wip_nav.flush(); |
| 2760 | } else { |
| 2761 | const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst)); |
| 2762 | assert(decl_inst.tag == .extended); |
| 2763 | if (switch (decl_inst.data.extended.opcode) { |
| 2764 | .struct_decl => @as(Zir.Inst.StructDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy, |
| 2765 | .enum_decl => @as(Zir.Inst.EnumDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy, |
| 2766 | .union_decl => @as(Zir.Inst.UnionDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy, |
| 2767 | .opaque_decl => @as(Zir.Inst.OpaqueDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy, |
| 2768 | .reify => @as(Zir.Inst.NameStrategy, @enumFromInt(decl_inst.data.extended.small)), |
| 2769 | else => unreachable, |
| 2770 | } == .parent) return; |
| 2771 | |
| 2772 | const unit = try dwarf.getUnit(file.mod); |
| 2773 | const type_gop = try dwarf.types.getOrPut(dwarf.gpa, type_index); |
| 2774 | if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(unit); |
| 2775 | var wip_nav: WipNav = .{ |
| 2776 | .dwarf = dwarf, |
| 2777 | .pt = pt, |
| 2778 | .unit = unit, |
| 2779 | .entry = type_gop.value_ptr.*, |
| 2780 | .any_children = false, |
| 2781 | .func = .none, |
| 2782 | .func_high_reloc = undefined, |
| 2783 | .debug_info = .{}, |
| 2784 | .debug_line = .{}, |
| 2785 | .debug_loclists = .{}, |
| 2786 | .pending_types = .{}, |
| 2787 | }; |
| 2788 | defer wip_nav.deinit(); |
| 2789 | const diw = wip_nav.debug_info.writer(dwarf.gpa); |
| 2790 | const name = try std.fmt.allocPrint(dwarf.gpa, "{}", .{ty.fmt(pt)}); |
| 2791 | defer dwarf.gpa.free(name); |
| 2792 | |
| 2793 | switch (ip.indexToKey(type_index)) { |
| 2794 | .struct_type => { |
| 2795 | const loaded_struct = ip.loadStructType(type_index); |
| 2796 | switch (loaded_struct.layout) { |
| 2797 | .auto, .@"extern" => { |
| 2798 | try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0) |
| 2799 | .namespace_struct_type |
| 2800 | else |
| 2801 | .struct_type))); |
| 2802 | try wip_nav.strp(name); |
| 2803 | if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else { |
| 2804 | try uleb128(diw, ty.abiSize(pt)); |
| 2805 | try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?); |
| 2806 | for (0..loaded_struct.field_types.len) |field_index| { |
| 2807 | const is_comptime = loaded_struct.fieldIsComptime(ip, field_index); |
| 2808 | try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_comptime) .struct_field_comptime else .struct_field))); |
| 2809 | if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else { |
| 2810 | const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index}); |
| 2811 | defer dwarf.gpa.free(field_name); |
| 2812 | try wip_nav.strp(field_name); |
| 2813 | } |
| 2814 | const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]); |
| 2815 | try wip_nav.refType(field_type); |
| 2816 | if (!is_comptime) { |
| 2817 | try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]); |
| 2818 | try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse |
| 2819 | field_type.abiAlignment(pt).toByteUnits().?); |
| 2820 | } |
| 2821 | } |
| 2822 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2823 | } |
| 2824 | }, |
| 2825 | .@"packed" => { |
| 2826 | try uleb128(diw, @intFromEnum(AbbrevCode.packed_struct_type)); |
| 2827 | try wip_nav.strp(name); |
| 2828 | try wip_nav.refType(Type.fromInterned(loaded_struct.backingIntTypeUnordered(ip))); |
| 2829 | var field_bit_offset: u16 = 0; |
| 2830 | for (0..loaded_struct.field_types.len) |field_index| { |
| 2831 | try uleb128(diw, @intFromEnum(@as(AbbrevCode, .packed_struct_field))); |
| 2832 | try wip_nav.strp(loaded_struct.fieldName(ip, field_index).unwrap().?.toSlice(ip)); |
| 2833 | const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]); |
| 2834 | try wip_nav.refType(field_type); |
| 2835 | try uleb128(diw, field_bit_offset); |
| 2836 | field_bit_offset += @intCast(field_type.bitSize(pt)); |
| 2837 | } |
| 2838 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2839 | }, |
| 2840 | } |
| 2841 | }, |
| 2842 | .enum_type => { |
| 2843 | const loaded_enum = ip.loadEnumType(type_index); |
| 2844 | try uleb128(diw, @intFromEnum(AbbrevCode.enum_type)); |
| 2845 | try wip_nav.strp(name); |
| 2846 | try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty)); |
| 2847 | for (0..loaded_enum.names.len) |field_index| { |
| 2848 | try wip_nav.enumConstValue(loaded_enum, .{ |
| 2849 | .signed = .signed_enum_field, |
| 2850 | .unsigned = .unsigned_enum_field, |
| 2851 | }, field_index); |
| 2852 | try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip)); |
| 2673 | 2853 | } |
| 2674 | | } else if (self.bin_file.cast(.wasm)) |wasm_file| { |
| 2675 | | _ = wasm_file; |
| 2676 | | // const debug_info = wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code; |
| 2677 | | // debug_info.items[atom.off + reloc.offset ..][0..buf.len].* = buf; |
| 2678 | | } else unreachable; |
| 2854 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2855 | }, |
| 2856 | .union_type => { |
| 2857 | const loaded_union = ip.loadUnionType(type_index); |
| 2858 | try uleb128(diw, @intFromEnum(AbbrevCode.union_type)); |
| 2859 | try wip_nav.strp(name); |
| 2860 | const union_layout = pt.getUnionLayout(loaded_union); |
| 2861 | try uleb128(diw, union_layout.abi_size); |
| 2862 | try uleb128(diw, union_layout.abi_align.toByteUnits().?); |
| 2863 | const loaded_tag = loaded_union.loadTagType(ip); |
| 2864 | if (loaded_union.hasTag(ip)) { |
| 2865 | try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union)); |
| 2866 | try wip_nav.infoSectionOffset( |
| 2867 | .debug_info, |
| 2868 | wip_nav.unit, |
| 2869 | wip_nav.entry, |
| 2870 | @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()), |
| 2871 | ); |
| 2872 | { |
| 2873 | try uleb128(diw, @intFromEnum(AbbrevCode.generated_field)); |
| 2874 | try wip_nav.strp("tag"); |
| 2875 | try wip_nav.refType(Type.fromInterned(loaded_union.enum_tag_ty)); |
| 2876 | try uleb128(diw, union_layout.tagOffset()); |
| 2877 | |
| 2878 | for (0..loaded_union.field_types.len) |field_index| { |
| 2879 | try wip_nav.enumConstValue(loaded_tag, .{ |
| 2880 | .signed = .signed_tagged_union_field, |
| 2881 | .unsigned = .unsigned_tagged_union_field, |
| 2882 | }, field_index); |
| 2883 | { |
| 2884 | try uleb128(diw, @intFromEnum(AbbrevCode.struct_field)); |
| 2885 | try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip)); |
| 2886 | const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]); |
| 2887 | try wip_nav.refType(field_type); |
| 2888 | try uleb128(diw, union_layout.payloadOffset()); |
| 2889 | try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse |
| 2890 | if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(pt).toByteUnits().?); |
| 2891 | } |
| 2892 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2893 | } |
| 2894 | } |
| 2895 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2896 | |
| 2897 | if (ip.indexToKey(loaded_union.enum_tag_ty).enum_type == .generated_tag) |
| 2898 | try wip_nav.pending_types.append(dwarf.gpa, loaded_union.enum_tag_ty); |
| 2899 | } else for (0..loaded_union.field_types.len) |field_index| { |
| 2900 | try uleb128(diw, @intFromEnum(AbbrevCode.untagged_union_field)); |
| 2901 | try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip)); |
| 2902 | const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]); |
| 2903 | try wip_nav.refType(field_type); |
| 2904 | try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse |
| 2905 | field_type.abiAlignment(pt).toByteUnits().?); |
| 2906 | } |
| 2907 | try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2908 | }, |
| 2909 | .opaque_type => { |
| 2910 | try uleb128(diw, @intFromEnum(AbbrevCode.namespace_struct_type)); |
| 2911 | try wip_nav.strp(name); |
| 2912 | try diw.writeByte(@intFromBool(true)); |
| 2913 | }, |
| 2914 | else => unreachable, |
| 2679 | 2915 | } |
| 2916 | try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); |
| 2917 | try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.items); |
| 2918 | try wip_nav.flush(); |
| 2680 | 2919 | } |
| 2681 | 2920 | } |
| 2682 | 2921 | |
| 2683 | | fn addDIFile(self: *Dwarf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !u28 { |
| 2684 | | const file_scope = zcu.navFileScope(nav_index); |
| 2685 | | const gop = try self.di_files.getOrPut(self.allocator, file_scope); |
| 2686 | | if (!gop.found_existing) { |
| 2687 | | if (self.bin_file.cast(.elf)) |elf_file| { |
| 2688 | | elf_file.markDirty(elf_file.debug_line_section_index.?); |
| 2689 | | } else if (self.bin_file.cast(.macho)) |macho_file| { |
| 2690 | | if (macho_file.base.isRelocatable()) { |
| 2691 | | macho_file.markDirty(macho_file.debug_line_sect_index.?); |
| 2692 | | } else { |
| 2693 | | const d_sym = macho_file.getDebugSymbols().?; |
| 2694 | | d_sym.markDirty(d_sym.debug_line_section_index.?, macho_file); |
| 2695 | | } |
| 2696 | | } else if (self.bin_file.cast(.wasm)) |_| {} else unreachable; |
| 2697 | | } |
| 2698 | | return @intCast(gop.index + 1); |
| 2922 | pub fn updateNavLineNumber(dwarf: *Dwarf, zcu: *Zcu, nav_index: InternPool.Nav.Index) UpdateError!void { |
| 2923 | const ip = &zcu.intern_pool; |
| 2924 | |
| 2925 | const zir_index = ip.getCau(ip.getNav(nav_index).analysis_owner.unwrap() orelse return).zir_index; |
| 2926 | const inst_info = zir_index.resolveFull(ip); |
| 2927 | assert(inst_info.inst != .main_struct_inst); |
| 2928 | const file = zcu.fileByIndex(inst_info.file); |
| 2929 | |
| 2930 | const inst = file.zir.instructions.get(@intFromEnum(inst_info.inst)); |
| 2931 | assert(inst.tag == .declaration); |
| 2932 | const line = file.zir.extraData(Zir.Inst.Declaration, inst.data.declaration.payload_index).data.src_line; |
| 2933 | var line_buf: [4]u8 = undefined; |
| 2934 | std.mem.writeInt(u32, &line_buf, line, dwarf.endian); |
| 2935 | |
| 2936 | const unit = dwarf.debug_line.section.getUnit(dwarf.mods.get(file.mod).?); |
| 2937 | const entry = unit.getEntry(dwarf.navs.get(nav_index).?); |
| 2938 | try dwarf.getFile().?.pwriteAll(&line, dwarf.debug_line.section.off + unit.off + unit.header_len + entry.off + DebugInfo.declEntryLineOff(dwarf)); |
| 2699 | 2939 | } |
| 2700 | 2940 | |
| 2701 | | fn genIncludeDirsAndFileNames(self: *Dwarf, arena: Allocator) !struct { |
| 2702 | | dirs: []const []const u8, |
| 2703 | | files: []const []const u8, |
| 2704 | | files_dirs_indexes: []u28, |
| 2705 | | } { |
| 2706 | | var dirs = std.StringArrayHashMap(void).init(arena); |
| 2707 | | try dirs.ensureTotalCapacity(self.di_files.count()); |
| 2708 | | |
| 2709 | | var files = std.ArrayList([]const u8).init(arena); |
| 2710 | | try files.ensureTotalCapacityPrecise(self.di_files.count()); |
| 2711 | | |
| 2712 | | var files_dir_indexes = std.ArrayList(u28).init(arena); |
| 2713 | | try files_dir_indexes.ensureTotalCapacity(self.di_files.count()); |
| 2714 | | |
| 2715 | | for (self.di_files.keys()) |dif| { |
| 2716 | | const full_path = try dif.mod.root.joinString(arena, dif.sub_file_path); |
| 2717 | | const dir_path = std.fs.path.dirname(full_path) orelse "."; |
| 2718 | | const sub_file_path = std.fs.path.basename(full_path); |
| 2719 | | // https://github.com/ziglang/zig/issues/19353 |
| 2720 | | var buffer: [std.fs.max_path_bytes]u8 = undefined; |
| 2721 | | const resolved = if (!std.fs.path.isAbsolute(dir_path)) |
| 2722 | | std.posix.realpath(dir_path, &buffer) catch dir_path |
| 2723 | | else |
| 2724 | | dir_path; |
| 2941 | pub fn freeNav(dwarf: *Dwarf, nav_index: InternPool.Nav.Index) void { |
| 2942 | _ = dwarf; |
| 2943 | _ = nav_index; |
| 2944 | } |
| 2725 | 2945 | |
| 2726 | | const dir_index: u28 = index: { |
| 2727 | | const dirs_gop = dirs.getOrPutAssumeCapacity(try arena.dupe(u8, resolved)); |
| 2728 | | break :index @intCast(dirs_gop.index + 1); |
| 2946 | pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { |
| 2947 | const ip = &pt.zcu.intern_pool; |
| 2948 | if (dwarf.types.get(.anyerror_type)) |entry| { |
| 2949 | var wip_nav: WipNav = .{ |
| 2950 | .dwarf = dwarf, |
| 2951 | .pt = pt, |
| 2952 | .unit = .main, |
| 2953 | .entry = entry, |
| 2954 | .any_children = false, |
| 2955 | .func = .none, |
| 2956 | .func_high_reloc = undefined, |
| 2957 | .debug_info = .{}, |
| 2958 | .debug_line = .{}, |
| 2959 | .debug_loclists = .{}, |
| 2960 | .pending_types = .{}, |
| 2729 | 2961 | }; |
| 2962 | defer wip_nav.deinit(); |
| 2963 | const diw = wip_nav.debug_info.writer(dwarf.gpa); |
| 2964 | const global_error_set_names = ip.global_error_set.getNamesFromMainThread(); |
| 2965 | try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (global_error_set_names.len > 0) .enum_type else .empty_enum_type))); |
| 2966 | try wip_nav.strp("anyerror"); |
| 2967 | try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{ |
| 2968 | .signedness = .unsigned, |
| 2969 | .bits = pt.zcu.errorSetBits(), |
| 2970 | } }))); |
| 2971 | for (global_error_set_names, 1..) |name, value| { |
| 2972 | try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_enum_field)); |
| 2973 | try uleb128(diw, value); |
| 2974 | try wip_nav.strp(name.toSlice(ip)); |
| 2975 | } |
| 2976 | if (global_error_set_names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null)); |
| 2977 | try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); |
| 2978 | } |
| 2730 | 2979 | |
| 2731 | | files_dir_indexes.appendAssumeCapacity(dir_index); |
| 2732 | | files.appendAssumeCapacity(sub_file_path); |
| 2980 | { |
| 2981 | const cwd = try std.process.getCwdAlloc(dwarf.gpa); |
| 2982 | defer dwarf.gpa.free(cwd); |
| 2983 | for (dwarf.mods.keys(), dwarf.mods.values()) |mod, *mod_info| { |
| 2984 | const root_dir_path = try std.fs.path.resolve(dwarf.gpa, &.{ |
| 2985 | cwd, |
| 2986 | mod.root.root_dir.path orelse "", |
| 2987 | mod.root.sub_path, |
| 2988 | }); |
| 2989 | defer dwarf.gpa.free(root_dir_path); |
| 2990 | mod_info.root_dir_path = try dwarf.debug_line_str.addString(dwarf, root_dir_path); |
| 2991 | } |
| 2733 | 2992 | } |
| 2734 | 2993 | |
| 2735 | | return .{ |
| 2736 | | .dirs = dirs.keys(), |
| 2737 | | .files = files.items, |
| 2738 | | .files_dirs_indexes = files_dir_indexes.items, |
| 2739 | | }; |
| 2994 | var header = std.ArrayList(u8).init(dwarf.gpa); |
| 2995 | defer header.deinit(); |
| 2996 | if (dwarf.debug_abbrev.section.dirty) { |
| 2997 | for (1.., &AbbrevCode.abbrevs) |code, *abbrev| { |
| 2998 | try uleb128(header.writer(), code); |
| 2999 | try uleb128(header.writer(), @intFromEnum(abbrev.tag)); |
| 3000 | try header.append(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no); |
| 3001 | for (abbrev.attrs) |*attr| { |
| 3002 | try uleb128(header.writer(), @intFromEnum(attr[0])); |
| 3003 | try uleb128(header.writer(), @intFromEnum(attr[1])); |
| 3004 | } |
| 3005 | try header.appendSlice(&.{ 0, 0 }); |
| 3006 | } |
| 3007 | try header.append(@intFromEnum(AbbrevCode.null)); |
| 3008 | try dwarf.debug_abbrev.section.replaceEntry(DebugAbbrev.unit, DebugAbbrev.entry, dwarf, header.items); |
| 3009 | dwarf.debug_abbrev.section.dirty = false; |
| 3010 | } |
| 3011 | if (dwarf.debug_aranges.section.dirty) { |
| 3012 | for (dwarf.debug_aranges.section.units.items, 0..) |*unit_ptr, unit_index| { |
| 3013 | const unit: Unit.Index = @enumFromInt(unit_index); |
| 3014 | try unit_ptr.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 1); |
| 3015 | header.clearRetainingCapacity(); |
| 3016 | try header.ensureTotalCapacity(unit_ptr.header_len); |
| 3017 | const unit_len = (if (unit_ptr.next.unwrap()) |next_unit| |
| 3018 | dwarf.debug_aranges.section.getUnit(next_unit).off |
| 3019 | else |
| 3020 | dwarf.debug_aranges.section.len) - unit_ptr.off - dwarf.unitLengthBytes(); |
| 3021 | switch (dwarf.format) { |
| 3022 | .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian), |
| 3023 | .@"64" => { |
| 3024 | std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian); |
| 3025 | std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian); |
| 3026 | }, |
| 3027 | } |
| 3028 | std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 2, dwarf.endian); |
| 3029 | unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ |
| 3030 | .source_off = @intCast(header.items.len), |
| 3031 | .target_sec = .debug_info, |
| 3032 | .target_unit = unit, |
| 3033 | }); |
| 3034 | header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); |
| 3035 | header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 }); |
| 3036 | header.appendNTimesAssumeCapacity(0, unit_ptr.header_len - header.items.len); |
| 3037 | try unit_ptr.replaceHeader(&dwarf.debug_aranges.section, dwarf, header.items); |
| 3038 | try unit_ptr.writeTrailer(&dwarf.debug_aranges.section, dwarf); |
| 3039 | } |
| 3040 | dwarf.debug_aranges.section.dirty = false; |
| 3041 | } |
| 3042 | if (dwarf.debug_info.section.dirty) { |
| 3043 | for (dwarf.mods.keys(), dwarf.mods.values(), dwarf.debug_info.section.units.items, 0..) |mod, mod_info, *unit_ptr, unit_index| { |
| 3044 | const unit: Unit.Index = @enumFromInt(unit_index); |
| 3045 | try unit_ptr.cross_unit_relocs.ensureUnusedCapacity(dwarf.gpa, 1); |
| 3046 | try unit_ptr.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 7); |
| 3047 | header.clearRetainingCapacity(); |
| 3048 | try header.ensureTotalCapacity(unit_ptr.header_len); |
| 3049 | const unit_len = (if (unit_ptr.next.unwrap()) |next_unit| |
| 3050 | dwarf.debug_info.section.getUnit(next_unit).off |
| 3051 | else |
| 3052 | dwarf.debug_info.section.len) - unit_ptr.off - dwarf.unitLengthBytes(); |
| 3053 | switch (dwarf.format) { |
| 3054 | .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian), |
| 3055 | .@"64" => { |
| 3056 | std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian); |
| 3057 | std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian); |
| 3058 | }, |
| 3059 | } |
| 3060 | std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian); |
| 3061 | header.appendSliceAssumeCapacity(&.{ DW.UT.compile, @intFromEnum(dwarf.address_size) }); |
| 3062 | unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ |
| 3063 | .source_off = @intCast(header.items.len), |
| 3064 | .target_sec = .debug_abbrev, |
| 3065 | .target_unit = DebugAbbrev.unit, |
| 3066 | .target_entry = DebugAbbrev.entry.toOptional(), |
| 3067 | }); |
| 3068 | header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); |
| 3069 | const compile_unit_off: u32 = @intCast(header.items.len); |
| 3070 | uleb128(header.fixedWriter(), @intFromEnum(AbbrevCode.compile_unit)) catch unreachable; |
| 3071 | header.appendAssumeCapacity(DW.LANG.Zig); |
| 3072 | unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ |
| 3073 | .source_off = @intCast(header.items.len), |
| 3074 | .target_sec = .debug_line_str, |
| 3075 | .target_unit = StringSection.unit, |
| 3076 | .target_entry = (try dwarf.debug_line_str.addString(dwarf, "zig " ++ @import("build_options").version)).toOptional(), |
| 3077 | }); |
| 3078 | header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); |
| 3079 | unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ |
| 3080 | .source_off = @intCast(header.items.len), |
| 3081 | .target_sec = .debug_line_str, |
| 3082 | .target_unit = StringSection.unit, |
| 3083 | .target_entry = mod_info.root_dir_path.toOptional(), |
| 3084 | }); |
| 3085 | header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); |
| 3086 | unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ |
| 3087 | .source_off = @intCast(header.items.len), |
| 3088 | .target_sec = .debug_line_str, |
| 3089 | .target_unit = StringSection.unit, |
| 3090 | .target_entry = (try dwarf.debug_line_str.addString(dwarf, mod.root_src_path)).toOptional(), |
| 3091 | }); |
| 3092 | header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); |
| 3093 | unit_ptr.cross_unit_relocs.appendAssumeCapacity(.{ |
| 3094 | .source_off = @intCast(header.items.len), |
| 3095 | .target_unit = .main, |
| 3096 | .target_off = compile_unit_off, |
| 3097 | }); |
| 3098 | header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); |
| 3099 | unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ |
| 3100 | .source_off = @intCast(header.items.len), |
| 3101 | .target_sec = .debug_line, |
| 3102 | .target_unit = unit, |
| 3103 | }); |
| 3104 | header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); |
| 3105 | unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ |
| 3106 | .source_off = @intCast(header.items.len), |
| 3107 | .target_sec = .debug_rnglists, |
| 3108 | .target_unit = unit, |
| 3109 | .target_off = DebugRngLists.baseOffset(dwarf), |
| 3110 | }); |
| 3111 | header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); |
| 3112 | uleb128(header.fixedWriter(), 0) catch unreachable; |
| 3113 | uleb128(header.fixedWriter(), @intFromEnum(AbbrevCode.module)) catch unreachable; |
| 3114 | unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ |
| 3115 | .source_off = @intCast(header.items.len), |
| 3116 | .target_sec = .debug_str, |
| 3117 | .target_unit = StringSection.unit, |
| 3118 | .target_entry = (try dwarf.debug_str.addString(dwarf, mod.fully_qualified_name)).toOptional(), |
| 3119 | }); |
| 3120 | header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); |
| 3121 | uleb128(header.fixedWriter(), 0) catch unreachable; |
| 3122 | try unit_ptr.replaceHeader(&dwarf.debug_info.section, dwarf, header.items); |
| 3123 | try unit_ptr.writeTrailer(&dwarf.debug_info.section, dwarf); |
| 3124 | } |
| 3125 | dwarf.debug_info.section.dirty = false; |
| 3126 | } |
| 3127 | if (dwarf.debug_str.section.dirty) { |
| 3128 | const contents = dwarf.debug_str.contents.items; |
| 3129 | try dwarf.debug_str.section.resize(dwarf, contents.len); |
| 3130 | try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_str.section.off); |
| 3131 | dwarf.debug_str.section.dirty = false; |
| 3132 | } |
| 3133 | if (dwarf.debug_line.section.dirty) { |
| 3134 | for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| |
| 3135 | try unit.resizeHeader(&dwarf.debug_line.section, dwarf, DebugLine.headerBytes(dwarf, @intCast(mod_info.dirs.count()), @intCast(mod_info.files.count()))); |
| 3136 | for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| { |
| 3137 | try unit.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 2 * (1 + mod_info.files.count())); |
| 3138 | header.clearRetainingCapacity(); |
| 3139 | try header.ensureTotalCapacity(unit.header_len); |
| 3140 | const unit_len = (if (unit.next.unwrap()) |next_unit| |
| 3141 | dwarf.debug_line.section.getUnit(next_unit).off |
| 3142 | else |
| 3143 | dwarf.debug_line.section.len) - unit.off - dwarf.unitLengthBytes(); |
| 3144 | switch (dwarf.format) { |
| 3145 | .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian), |
| 3146 | .@"64" => { |
| 3147 | std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian); |
| 3148 | std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian); |
| 3149 | }, |
| 3150 | } |
| 3151 | std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian); |
| 3152 | header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 }); |
| 3153 | switch (dwarf.format) { |
| 3154 | inline .@"32", .@"64" => |format| std.mem.writeInt( |
| 3155 | SectionOffset(format), |
| 3156 | header.addManyAsArrayAssumeCapacity(@sizeOf(SectionOffset(format))), |
| 3157 | @intCast(unit.header_len - header.items.len), |
| 3158 | dwarf.endian, |
| 3159 | ), |
| 3160 | } |
| 3161 | const StandardOpcode = DeclValEnum(DW.LNS); |
| 3162 | header.appendSliceAssumeCapacity(&[_]u8{ |
| 3163 | dwarf.debug_line.header.minimum_instruction_length, |
| 3164 | dwarf.debug_line.header.maximum_operations_per_instruction, |
| 3165 | @intFromBool(dwarf.debug_line.header.default_is_stmt), |
| 3166 | @bitCast(dwarf.debug_line.header.line_base), |
| 3167 | dwarf.debug_line.header.line_range, |
| 3168 | dwarf.debug_line.header.opcode_base, |
| 3169 | }); |
| 3170 | header.appendSliceAssumeCapacity(std.enums.EnumArray(StandardOpcode, u8).init(.{ |
| 3171 | .extended_op = undefined, |
| 3172 | .copy = 0, |
| 3173 | .advance_pc = 1, |
| 3174 | .advance_line = 1, |
| 3175 | .set_file = 1, |
| 3176 | .set_column = 1, |
| 3177 | .negate_stmt = 0, |
| 3178 | .set_basic_block = 0, |
| 3179 | .const_add_pc = 0, |
| 3180 | .fixed_advance_pc = 1, |
| 3181 | .set_prologue_end = 0, |
| 3182 | .set_epilogue_begin = 0, |
| 3183 | .set_isa = 1, |
| 3184 | }).values[1..dwarf.debug_line.header.opcode_base]); |
| 3185 | header.appendAssumeCapacity(1); |
| 3186 | uleb128(header.fixedWriter(), DW.LNCT.path) catch unreachable; |
| 3187 | uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable; |
| 3188 | uleb128(header.fixedWriter(), mod_info.dirs.count()) catch unreachable; |
| 3189 | for (mod_info.dirs.keys()) |dir_unit| { |
| 3190 | unit.cross_section_relocs.appendAssumeCapacity(.{ |
| 3191 | .source_off = @intCast(header.items.len), |
| 3192 | .target_sec = .debug_line_str, |
| 3193 | .target_unit = StringSection.unit, |
| 3194 | .target_entry = dwarf.getModInfo(dir_unit).root_dir_path.toOptional(), |
| 3195 | }); |
| 3196 | header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); |
| 3197 | } |
| 3198 | const dir_index_info = DebugLine.dirIndexInfo(@intCast(mod_info.dirs.count())); |
| 3199 | header.appendAssumeCapacity(3); |
| 3200 | uleb128(header.fixedWriter(), DW.LNCT.path) catch unreachable; |
| 3201 | uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable; |
| 3202 | uleb128(header.fixedWriter(), DW.LNCT.directory_index) catch unreachable; |
| 3203 | uleb128(header.fixedWriter(), @intFromEnum(dir_index_info.form)) catch unreachable; |
| 3204 | uleb128(header.fixedWriter(), DW.LNCT.LLVM_source) catch unreachable; |
| 3205 | uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable; |
| 3206 | uleb128(header.fixedWriter(), mod_info.files.count()) catch unreachable; |
| 3207 | for (mod_info.files.keys()) |file_index| { |
| 3208 | const file = pt.zcu.fileByIndex(file_index); |
| 3209 | unit.cross_section_relocs.appendAssumeCapacity(.{ |
| 3210 | .source_off = @intCast(header.items.len), |
| 3211 | .target_sec = .debug_line_str, |
| 3212 | .target_unit = StringSection.unit, |
| 3213 | .target_entry = (try dwarf.debug_line_str.addString(dwarf, file.sub_file_path)).toOptional(), |
| 3214 | }); |
| 3215 | header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); |
| 3216 | dwarf.writeInt( |
| 3217 | header.addManyAsSliceAssumeCapacity(dir_index_info.bytes), |
| 3218 | mod_info.dirs.getIndex(dwarf.getUnitIfExists(file.mod).?).?, |
| 3219 | ); |
| 3220 | unit.cross_section_relocs.appendAssumeCapacity(.{ |
| 3221 | .source_off = @intCast(header.items.len), |
| 3222 | .target_sec = .debug_line_str, |
| 3223 | .target_unit = StringSection.unit, |
| 3224 | .target_entry = (try dwarf.debug_line_str.addString( |
| 3225 | dwarf, |
| 3226 | if (file.mod.builtin_file == file) file.source else "", |
| 3227 | )).toOptional(), |
| 3228 | }); |
| 3229 | header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); |
| 3230 | } |
| 3231 | try unit.replaceHeader(&dwarf.debug_line.section, dwarf, header.items); |
| 3232 | try unit.writeTrailer(&dwarf.debug_line.section, dwarf); |
| 3233 | } |
| 3234 | dwarf.debug_line.section.dirty = false; |
| 3235 | } |
| 3236 | if (dwarf.debug_line_str.section.dirty) { |
| 3237 | const contents = dwarf.debug_line_str.contents.items; |
| 3238 | try dwarf.debug_line_str.section.resize(dwarf, contents.len); |
| 3239 | try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_line_str.section.off); |
| 3240 | dwarf.debug_line_str.section.dirty = false; |
| 3241 | } |
| 3242 | if (dwarf.debug_rnglists.section.dirty) { |
| 3243 | for (dwarf.debug_rnglists.section.units.items) |*unit| { |
| 3244 | header.clearRetainingCapacity(); |
| 3245 | try header.ensureTotalCapacity(unit.header_len); |
| 3246 | const unit_len = (if (unit.next.unwrap()) |next_unit| |
| 3247 | dwarf.debug_rnglists.section.getUnit(next_unit).off |
| 3248 | else |
| 3249 | dwarf.debug_rnglists.section.len) - unit.off - dwarf.unitLengthBytes(); |
| 3250 | switch (dwarf.format) { |
| 3251 | .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian), |
| 3252 | .@"64" => { |
| 3253 | std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian); |
| 3254 | std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian); |
| 3255 | }, |
| 3256 | } |
| 3257 | std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian); |
| 3258 | header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 }); |
| 3259 | std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), 1, dwarf.endian); |
| 3260 | switch (dwarf.format) { |
| 3261 | inline .@"32", .@"64" => |format| std.mem.writeInt( |
| 3262 | SectionOffset(format), |
| 3263 | header.addManyAsArrayAssumeCapacity(@sizeOf(SectionOffset(format))), |
| 3264 | @sizeOf(SectionOffset(format)), |
| 3265 | dwarf.endian, |
| 3266 | ), |
| 3267 | } |
| 3268 | try unit.replaceHeader(&dwarf.debug_rnglists.section, dwarf, header.items); |
| 3269 | try unit.writeTrailer(&dwarf.debug_rnglists.section, dwarf); |
| 3270 | } |
| 3271 | dwarf.debug_rnglists.section.dirty = false; |
| 3272 | } |
| 2740 | 3273 | } |
| 2741 | 3274 | |
| 2742 | | fn addDbgInfoErrorSet( |
| 2743 | | pt: Zcu.PerThread, |
| 2744 | | ty: Type, |
| 2745 | | target: std.Target, |
| 2746 | | dbg_info_buffer: *std.ArrayList(u8), |
| 2747 | | ) !void { |
| 2748 | | return addDbgInfoErrorSetNames(pt, ty, ty.errorSetNames(pt.zcu).get(&pt.zcu.intern_pool), target, dbg_info_buffer); |
| 3275 | pub fn resolveRelocs(dwarf: *Dwarf) RelocError!void { |
| 3276 | for ([_]*Section{ |
| 3277 | &dwarf.debug_abbrev.section, |
| 3278 | &dwarf.debug_aranges.section, |
| 3279 | &dwarf.debug_info.section, |
| 3280 | &dwarf.debug_line.section, |
| 3281 | &dwarf.debug_line_str.section, |
| 3282 | &dwarf.debug_loclists.section, |
| 3283 | &dwarf.debug_rnglists.section, |
| 3284 | &dwarf.debug_str.section, |
| 3285 | }) |sec| try sec.resolveRelocs(dwarf); |
| 2749 | 3286 | } |
| 2750 | 3287 | |
| 2751 | | fn addDbgInfoErrorSetNames( |
| 2752 | | pt: Zcu.PerThread, |
| 2753 | | /// Used for printing the type name only. |
| 2754 | | ty: Type, |
| 2755 | | error_names: []const InternPool.NullTerminatedString, |
| 2756 | | target: std.Target, |
| 2757 | | dbg_info_buffer: *std.ArrayList(u8), |
| 2758 | | ) !void { |
| 2759 | | const target_endian = target.cpu.arch.endian(); |
| 2760 | | |
| 2761 | | // DW.AT.enumeration_type |
| 2762 | | try dbg_info_buffer.append(@intFromEnum(AbbrevCode.enum_type)); |
| 2763 | | // DW.AT.byte_size, DW.FORM.udata |
| 2764 | | const abi_size = Type.anyerror.abiSize(pt); |
| 2765 | | try leb128.writeUleb128(dbg_info_buffer.writer(), abi_size); |
| 2766 | | // DW.AT.name, DW.FORM.string |
| 2767 | | try ty.print(dbg_info_buffer.writer(), pt); |
| 2768 | | try dbg_info_buffer.append(0); |
| 2769 | | |
| 2770 | | // DW.AT.enumerator |
| 2771 | | const no_error = "(no error)"; |
| 2772 | | try dbg_info_buffer.ensureUnusedCapacity(no_error.len + 2 + @sizeOf(u64)); |
| 2773 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.enum_variant)); |
| 2774 | | // DW.AT.name, DW.FORM.string |
| 2775 | | dbg_info_buffer.appendSliceAssumeCapacity(no_error); |
| 2776 | | dbg_info_buffer.appendAssumeCapacity(0); |
| 2777 | | // DW.AT.const_value, DW.FORM.data8 |
| 2778 | | mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), 0, target_endian); |
| 2779 | | |
| 2780 | | for (error_names) |error_name| { |
| 2781 | | const int = try pt.getErrorValue(error_name); |
| 2782 | | const error_name_slice = error_name.toSlice(&pt.zcu.intern_pool); |
| 2783 | | // DW.AT.enumerator |
| 2784 | | try dbg_info_buffer.ensureUnusedCapacity(error_name_slice.len + 2 + @sizeOf(u64)); |
| 2785 | | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.enum_variant)); |
| 2786 | | // DW.AT.name, DW.FORM.string |
| 2787 | | dbg_info_buffer.appendSliceAssumeCapacity(error_name_slice[0 .. error_name_slice.len + 1]); |
| 2788 | | // DW.AT.const_value, DW.FORM.data8 |
| 2789 | | mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), int, target_endian); |
| 2790 | | } |
| 2791 | | |
| 2792 | | // DW.AT.enumeration_type delimit children |
| 2793 | | try dbg_info_buffer.append(0); |
| 3288 | fn DeclValEnum(comptime T: type) type { |
| 3289 | const decls = @typeInfo(T).Struct.decls; |
| 3290 | @setEvalBranchQuota(7 * decls.len); |
| 3291 | var fields: [decls.len]std.builtin.Type.EnumField = undefined; |
| 3292 | var fields_len = 0; |
| 3293 | var min_value: ?comptime_int = null; |
| 3294 | var max_value: ?comptime_int = null; |
| 3295 | for (decls) |decl| { |
| 3296 | if (std.mem.startsWith(u8, decl.name, "HP_") or std.mem.endsWith(u8, decl.name, "_user")) continue; |
| 3297 | const value = @field(T, decl.name); |
| 3298 | fields[fields_len] = .{ .name = decl.name, .value = value }; |
| 3299 | fields_len += 1; |
| 3300 | if (min_value == null or min_value.? > value) min_value = value; |
| 3301 | if (max_value == null or max_value.? < value) max_value = value; |
| 3302 | } |
| 3303 | return @Type(.{ .Enum = .{ |
| 3304 | .tag_type = std.math.IntFittingRange(min_value orelse 0, max_value orelse 0), |
| 3305 | .fields = fields[0..fields_len], |
| 3306 | .decls = &.{}, |
| 3307 | .is_exhaustive = true, |
| 3308 | } }); |
| 2794 | 3309 | } |
| 2795 | 3310 | |
| 2796 | | const Kind = enum { src_fn, di_atom }; |
| 3311 | const AbbrevCode = enum(u8) { |
| 3312 | null, |
| 3313 | // padding codes must be one byte uleb128 values to function |
| 3314 | pad_1, |
| 3315 | pad_n, |
| 3316 | // decl codes are assumed to all have the same uleb128 length |
| 3317 | decl_alias, |
| 3318 | decl_enum, |
| 3319 | decl_namespace_struct, |
| 3320 | decl_struct, |
| 3321 | decl_packed_struct, |
| 3322 | decl_union, |
| 3323 | decl_var, |
| 3324 | decl_func, |
| 3325 | decl_func_empty, |
| 3326 | // the rest are unrestricted |
| 3327 | compile_unit, |
| 3328 | module, |
| 3329 | namespace_file, |
| 3330 | file, |
| 3331 | signed_enum_field, |
| 3332 | unsigned_enum_field, |
| 3333 | generated_field, |
| 3334 | struct_field, |
| 3335 | struct_field_comptime, |
| 3336 | packed_struct_field, |
| 3337 | untagged_union_field, |
| 3338 | tagged_union, |
| 3339 | signed_tagged_union_field, |
| 3340 | unsigned_tagged_union_field, |
| 3341 | tagged_union_default_field, |
| 3342 | void_type, |
| 3343 | numeric_type, |
| 3344 | inferred_error_set_type, |
| 3345 | ptr_type, |
| 3346 | is_const, |
| 3347 | is_volatile, |
| 3348 | array_type, |
| 3349 | array_index, |
| 3350 | nullary_func_type, |
| 3351 | func_type, |
| 3352 | func_type_param, |
| 3353 | is_var_args, |
| 3354 | enum_type, |
| 3355 | empty_enum_type, |
| 3356 | namespace_struct_type, |
| 3357 | struct_type, |
| 3358 | packed_struct_type, |
| 3359 | union_type, |
| 3360 | local_arg, |
| 3361 | local_var, |
| 2797 | 3362 | |
| 2798 | | fn createAtom(self: *Dwarf, comptime kind: Kind) !Atom.Index { |
| 2799 | | const index = blk: { |
| 2800 | | switch (kind) { |
| 2801 | | .src_fn => { |
| 2802 | | const index: Atom.Index = @intCast(self.src_fns.items.len); |
| 2803 | | _ = try self.src_fns.addOne(self.allocator); |
| 2804 | | break :blk index; |
| 2805 | | }, |
| 2806 | | .di_atom => { |
| 2807 | | const index: Atom.Index = @intCast(self.di_atoms.items.len); |
| 2808 | | _ = try self.di_atoms.addOne(self.allocator); |
| 2809 | | break :blk index; |
| 2810 | | }, |
| 2811 | | } |
| 3363 | const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_func_empty)); |
| 3364 | |
| 3365 | const Attr = struct { |
| 3366 | DeclValEnum(DW.AT), |
| 3367 | DeclValEnum(DW.FORM), |
| 2812 | 3368 | }; |
| 2813 | | const atom = self.getAtomPtr(kind, index); |
| 2814 | | atom.* = .{ |
| 2815 | | .off = 0, |
| 2816 | | .len = 0, |
| 2817 | | .prev_index = null, |
| 2818 | | .next_index = null, |
| 3369 | const decl_abbrev_common_attrs = &[_]Attr{ |
| 3370 | .{ .ZIG_parent, .ref_addr }, |
| 3371 | .{ .decl_line, .data4 }, |
| 3372 | .{ .decl_column, .udata }, |
| 3373 | .{ .accessibility, .data1 }, |
| 3374 | .{ .name, .strp }, |
| 2819 | 3375 | }; |
| 2820 | | return index; |
| 2821 | | } |
| 2822 | | |
| 2823 | | fn getOrCreateAtomForNav(self: *Dwarf, comptime kind: Kind, nav_index: InternPool.Nav.Index) !Atom.Index { |
| 2824 | | switch (kind) { |
| 2825 | | .src_fn => { |
| 2826 | | const gop = try self.src_fn_navs.getOrPut(self.allocator, nav_index); |
| 2827 | | if (!gop.found_existing) { |
| 2828 | | gop.value_ptr.* = try self.createAtom(kind); |
| 2829 | | } |
| 2830 | | return gop.value_ptr.*; |
| 3376 | const abbrevs = std.EnumArray(AbbrevCode, struct { |
| 3377 | tag: DeclValEnum(DW.TAG), |
| 3378 | children: bool = false, |
| 3379 | attrs: []const Attr = &.{}, |
| 3380 | }).init(.{ |
| 3381 | .pad_1 = .{ |
| 3382 | .tag = .ZIG_padding, |
| 2831 | 3383 | }, |
| 2832 | | .di_atom => { |
| 2833 | | const gop = try self.di_atom_navs.getOrPut(self.allocator, nav_index); |
| 2834 | | if (!gop.found_existing) { |
| 2835 | | gop.value_ptr.* = try self.createAtom(kind); |
| 2836 | | } |
| 2837 | | return gop.value_ptr.*; |
| 3384 | .pad_n = .{ |
| 3385 | .tag = .ZIG_padding, |
| 3386 | .attrs = &.{ |
| 3387 | .{ .ZIG_padding, .block }, |
| 3388 | }, |
| 3389 | }, |
| 3390 | .decl_alias = .{ |
| 3391 | .tag = .imported_declaration, |
| 3392 | .attrs = decl_abbrev_common_attrs ++ .{ |
| 3393 | .{ .import, .ref_addr }, |
| 3394 | }, |
| 3395 | }, |
| 3396 | .decl_enum = .{ |
| 3397 | .tag = .enumeration_type, |
| 3398 | .children = true, |
| 3399 | .attrs = decl_abbrev_common_attrs ++ .{ |
| 3400 | .{ .type, .ref_addr }, |
| 3401 | }, |
| 3402 | }, |
| 3403 | .decl_namespace_struct = .{ |
| 3404 | .tag = .structure_type, |
| 3405 | .attrs = decl_abbrev_common_attrs ++ .{ |
| 3406 | .{ .declaration, .flag }, |
| 3407 | }, |
| 3408 | }, |
| 3409 | .decl_struct = .{ |
| 3410 | .tag = .structure_type, |
| 3411 | .children = true, |
| 3412 | .attrs = decl_abbrev_common_attrs ++ .{ |
| 3413 | .{ .byte_size, .udata }, |
| 3414 | .{ .alignment, .udata }, |
| 3415 | }, |
| 3416 | }, |
| 3417 | .decl_packed_struct = .{ |
| 3418 | .tag = .structure_type, |
| 3419 | .children = true, |
| 3420 | .attrs = decl_abbrev_common_attrs ++ .{ |
| 3421 | .{ .type, .ref_addr }, |
| 3422 | }, |
| 3423 | }, |
| 3424 | .decl_union = .{ |
| 3425 | .tag = .union_type, |
| 3426 | .children = true, |
| 3427 | .attrs = decl_abbrev_common_attrs ++ .{ |
| 3428 | .{ .byte_size, .udata }, |
| 3429 | .{ .alignment, .udata }, |
| 3430 | }, |
| 3431 | }, |
| 3432 | .decl_var = .{ |
| 3433 | .tag = .variable, |
| 3434 | .attrs = decl_abbrev_common_attrs ++ .{ |
| 3435 | .{ .linkage_name, .strp }, |
| 3436 | .{ .type, .ref_addr }, |
| 3437 | .{ .location, .exprloc }, |
| 3438 | .{ .alignment, .udata }, |
| 3439 | .{ .external, .flag }, |
| 3440 | }, |
| 3441 | }, |
| 3442 | .decl_func = .{ |
| 3443 | .tag = .subprogram, |
| 3444 | .children = true, |
| 3445 | .attrs = decl_abbrev_common_attrs ++ .{ |
| 3446 | .{ .linkage_name, .strp }, |
| 3447 | .{ .type, .ref_addr }, |
| 3448 | .{ .low_pc, .addr }, |
| 3449 | .{ .high_pc, .addr }, |
| 3450 | .{ .alignment, .udata }, |
| 3451 | .{ .external, .flag }, |
| 3452 | .{ .noreturn, .flag }, |
| 3453 | }, |
| 3454 | }, |
| 3455 | .decl_func_empty = .{ |
| 3456 | .tag = .subprogram, |
| 3457 | .attrs = decl_abbrev_common_attrs ++ .{ |
| 3458 | .{ .linkage_name, .strp }, |
| 3459 | .{ .type, .ref_addr }, |
| 3460 | .{ .low_pc, .addr }, |
| 3461 | .{ .high_pc, .addr }, |
| 3462 | .{ .alignment, .udata }, |
| 3463 | .{ .external, .flag }, |
| 3464 | .{ .noreturn, .flag }, |
| 3465 | }, |
| 3466 | }, |
| 3467 | .compile_unit = .{ |
| 3468 | .tag = .compile_unit, |
| 3469 | .children = true, |
| 3470 | .attrs = &.{ |
| 3471 | .{ .language, .data1 }, |
| 3472 | .{ .producer, .line_strp }, |
| 3473 | .{ .comp_dir, .line_strp }, |
| 3474 | .{ .name, .line_strp }, |
| 3475 | .{ .base_types, .ref_addr }, |
| 3476 | .{ .stmt_list, .sec_offset }, |
| 3477 | .{ .rnglists_base, .sec_offset }, |
| 3478 | .{ .ranges, .rnglistx }, |
| 3479 | }, |
| 3480 | }, |
| 3481 | .module = .{ |
| 3482 | .tag = .module, |
| 3483 | .children = true, |
| 3484 | .attrs = &.{ |
| 3485 | .{ .name, .strp }, |
| 3486 | .{ .ranges, .rnglistx }, |
| 3487 | }, |
| 3488 | }, |
| 3489 | .namespace_file = .{ |
| 3490 | .tag = .structure_type, |
| 3491 | .attrs = &.{ |
| 3492 | .{ .decl_file, .udata }, |
| 3493 | .{ .name, .strp }, |
| 3494 | }, |
| 3495 | }, |
| 3496 | .file = .{ |
| 3497 | .tag = .structure_type, |
| 3498 | .children = true, |
| 3499 | .attrs = &.{ |
| 3500 | .{ .decl_file, .udata }, |
| 3501 | .{ .name, .strp }, |
| 3502 | .{ .byte_size, .udata }, |
| 3503 | .{ .alignment, .udata }, |
| 3504 | }, |
| 3505 | }, |
| 3506 | .signed_enum_field = .{ |
| 3507 | .tag = .enumerator, |
| 3508 | .attrs = &.{ |
| 3509 | .{ .const_value, .sdata }, |
| 3510 | .{ .name, .strp }, |
| 3511 | }, |
| 3512 | }, |
| 3513 | .unsigned_enum_field = .{ |
| 3514 | .tag = .enumerator, |
| 3515 | .attrs = &.{ |
| 3516 | .{ .const_value, .udata }, |
| 3517 | .{ .name, .strp }, |
| 3518 | }, |
| 3519 | }, |
| 3520 | .generated_field = .{ |
| 3521 | .tag = .member, |
| 3522 | .attrs = &.{ |
| 3523 | .{ .name, .strp }, |
| 3524 | .{ .type, .ref_addr }, |
| 3525 | .{ .data_member_location, .udata }, |
| 3526 | .{ .artificial, .flag_present }, |
| 3527 | }, |
| 3528 | }, |
| 3529 | .struct_field = .{ |
| 3530 | .tag = .member, |
| 3531 | .attrs = &.{ |
| 3532 | .{ .name, .strp }, |
| 3533 | .{ .type, .ref_addr }, |
| 3534 | .{ .data_member_location, .udata }, |
| 3535 | .{ .alignment, .udata }, |
| 3536 | }, |
| 3537 | }, |
| 3538 | .struct_field_comptime = .{ |
| 3539 | .tag = .member, |
| 3540 | .attrs = &.{ |
| 3541 | .{ .name, .strp }, |
| 3542 | .{ .type, .ref_addr }, |
| 3543 | .{ .const_expr, .flag_present }, |
| 3544 | }, |
| 3545 | }, |
| 3546 | .packed_struct_field = .{ |
| 3547 | .tag = .member, |
| 3548 | .attrs = &.{ |
| 3549 | .{ .name, .strp }, |
| 3550 | .{ .type, .ref_addr }, |
| 3551 | .{ .data_bit_offset, .udata }, |
| 3552 | }, |
| 3553 | }, |
| 3554 | .untagged_union_field = .{ |
| 3555 | .tag = .member, |
| 3556 | .attrs = &.{ |
| 3557 | .{ .name, .strp }, |
| 3558 | .{ .type, .ref_addr }, |
| 3559 | .{ .alignment, .udata }, |
| 3560 | }, |
| 3561 | }, |
| 3562 | .tagged_union = .{ |
| 3563 | .tag = .variant_part, |
| 3564 | .children = true, |
| 3565 | .attrs = &.{ |
| 3566 | .{ .discr, .ref_addr }, |
| 3567 | }, |
| 3568 | }, |
| 3569 | .signed_tagged_union_field = .{ |
| 3570 | .tag = .variant, |
| 3571 | .children = true, |
| 3572 | .attrs = &.{ |
| 3573 | .{ .discr_value, .sdata }, |
| 3574 | }, |
| 3575 | }, |
| 3576 | .unsigned_tagged_union_field = .{ |
| 3577 | .tag = .variant, |
| 3578 | .children = true, |
| 3579 | .attrs = &.{ |
| 3580 | .{ .discr_value, .udata }, |
| 3581 | }, |
| 3582 | }, |
| 3583 | .tagged_union_default_field = .{ |
| 3584 | .tag = .variant, |
| 3585 | .children = true, |
| 3586 | .attrs = &.{}, |
| 3587 | }, |
| 3588 | .void_type = .{ |
| 3589 | .tag = .unspecified_type, |
| 3590 | .attrs = &.{ |
| 3591 | .{ .name, .strp }, |
| 3592 | }, |
| 3593 | }, |
| 3594 | .numeric_type = .{ |
| 3595 | .tag = .base_type, |
| 3596 | .attrs = &.{ |
| 3597 | .{ .name, .strp }, |
| 3598 | .{ .encoding, .data1 }, |
| 3599 | .{ .bit_size, .udata }, |
| 3600 | .{ .byte_size, .udata }, |
| 3601 | .{ .alignment, .udata }, |
| 3602 | }, |
| 3603 | }, |
| 3604 | .inferred_error_set_type = .{ |
| 3605 | .tag = .typedef, |
| 3606 | .attrs = &.{ |
| 3607 | .{ .name, .strp }, |
| 3608 | .{ .type, .ref_addr }, |
| 3609 | }, |
| 3610 | }, |
| 3611 | .ptr_type = .{ |
| 3612 | .tag = .pointer_type, |
| 3613 | .attrs = &.{ |
| 3614 | .{ .name, .strp }, |
| 3615 | .{ .ZIG_is_allowzero, .flag }, |
| 3616 | .{ .alignment, .udata }, |
| 3617 | .{ .address_class, .data1 }, |
| 3618 | .{ .type, .ref_addr }, |
| 3619 | }, |
| 3620 | }, |
| 3621 | .is_const = .{ |
| 3622 | .tag = .const_type, |
| 3623 | .attrs = &.{ |
| 3624 | .{ .type, .ref_addr }, |
| 3625 | }, |
| 3626 | }, |
| 3627 | .is_volatile = .{ |
| 3628 | .tag = .volatile_type, |
| 3629 | .attrs = &.{ |
| 3630 | .{ .type, .ref_addr }, |
| 3631 | }, |
| 3632 | }, |
| 3633 | .array_type = .{ |
| 3634 | .tag = .array_type, |
| 3635 | .children = true, |
| 3636 | .attrs = &.{ |
| 3637 | .{ .name, .strp }, |
| 3638 | .{ .type, .ref_addr }, |
| 3639 | .{ .GNU_vector, .flag }, |
| 3640 | }, |
| 3641 | }, |
| 3642 | .array_index = .{ |
| 3643 | .tag = .subrange_type, |
| 3644 | .attrs = &.{ |
| 3645 | .{ .type, .ref_addr }, |
| 3646 | .{ .count, .udata }, |
| 3647 | }, |
| 3648 | }, |
| 3649 | .nullary_func_type = .{ |
| 3650 | .tag = .subroutine_type, |
| 3651 | .attrs = &.{ |
| 3652 | .{ .name, .strp }, |
| 3653 | .{ .calling_convention, .data1 }, |
| 3654 | .{ .type, .ref_addr }, |
| 3655 | }, |
| 3656 | }, |
| 3657 | .func_type = .{ |
| 3658 | .tag = .subroutine_type, |
| 3659 | .children = true, |
| 3660 | .attrs = &.{ |
| 3661 | .{ .name, .strp }, |
| 3662 | .{ .calling_convention, .data1 }, |
| 3663 | .{ .type, .ref_addr }, |
| 3664 | }, |
| 2838 | 3665 | }, |
| 3666 | .func_type_param = .{ |
| 3667 | .tag = .formal_parameter, |
| 3668 | .attrs = &.{ |
| 3669 | .{ .type, .ref_addr }, |
| 3670 | }, |
| 3671 | }, |
| 3672 | .is_var_args = .{ |
| 3673 | .tag = .unspecified_parameters, |
| 3674 | }, |
| 3675 | .enum_type = .{ |
| 3676 | .tag = .enumeration_type, |
| 3677 | .children = true, |
| 3678 | .attrs = &.{ |
| 3679 | .{ .name, .strp }, |
| 3680 | .{ .type, .ref_addr }, |
| 3681 | }, |
| 3682 | }, |
| 3683 | .empty_enum_type = .{ |
| 3684 | .tag = .enumeration_type, |
| 3685 | .attrs = &.{ |
| 3686 | .{ .name, .strp }, |
| 3687 | .{ .type, .ref_addr }, |
| 3688 | }, |
| 3689 | }, |
| 3690 | .namespace_struct_type = .{ |
| 3691 | .tag = .structure_type, |
| 3692 | .attrs = &.{ |
| 3693 | .{ .name, .strp }, |
| 3694 | .{ .declaration, .flag }, |
| 3695 | }, |
| 3696 | }, |
| 3697 | .struct_type = .{ |
| 3698 | .tag = .structure_type, |
| 3699 | .children = true, |
| 3700 | .attrs = &.{ |
| 3701 | .{ .name, .strp }, |
| 3702 | .{ .byte_size, .udata }, |
| 3703 | .{ .alignment, .udata }, |
| 3704 | }, |
| 3705 | }, |
| 3706 | .packed_struct_type = .{ |
| 3707 | .tag = .structure_type, |
| 3708 | .children = true, |
| 3709 | .attrs = &.{ |
| 3710 | .{ .name, .strp }, |
| 3711 | .{ .type, .ref_addr }, |
| 3712 | }, |
| 3713 | }, |
| 3714 | .union_type = .{ |
| 3715 | .tag = .union_type, |
| 3716 | .children = true, |
| 3717 | .attrs = &.{ |
| 3718 | .{ .name, .strp }, |
| 3719 | .{ .byte_size, .udata }, |
| 3720 | .{ .alignment, .udata }, |
| 3721 | }, |
| 3722 | }, |
| 3723 | .local_arg = .{ |
| 3724 | .tag = .formal_parameter, |
| 3725 | .attrs = &.{ |
| 3726 | .{ .name, .strp }, |
| 3727 | .{ .type, .ref_addr }, |
| 3728 | .{ .location, .exprloc }, |
| 3729 | }, |
| 3730 | }, |
| 3731 | .local_var = .{ |
| 3732 | .tag = .variable, |
| 3733 | .attrs = &.{ |
| 3734 | .{ .name, .strp }, |
| 3735 | .{ .type, .ref_addr }, |
| 3736 | .{ .location, .exprloc }, |
| 3737 | }, |
| 3738 | }, |
| 3739 | .null = undefined, |
| 3740 | }).values[1..].*; |
| 3741 | }; |
| 3742 | |
| 3743 | fn getFile(dwarf: *Dwarf) ?std.fs.File { |
| 3744 | if (dwarf.bin_file.cast(.macho)) |macho_file| if (macho_file.d_sym) |*d_sym| return d_sym.file; |
| 3745 | return dwarf.bin_file.file; |
| 3746 | } |
| 3747 | |
| 3748 | fn addCommonEntry(dwarf: *Dwarf, unit: Unit.Index) UpdateError!Entry.Index { |
| 3749 | const entry = try dwarf.debug_aranges.section.addEntry(unit, dwarf); |
| 3750 | assert(try dwarf.debug_info.section.addEntry(unit, dwarf) == entry); |
| 3751 | assert(try dwarf.debug_line.section.addEntry(unit, dwarf) == entry); |
| 3752 | assert(try dwarf.debug_loclists.section.addEntry(unit, dwarf) == entry); |
| 3753 | assert(try dwarf.debug_rnglists.section.addEntry(unit, dwarf) == entry); |
| 3754 | return entry; |
| 3755 | } |
| 3756 | |
| 3757 | fn writeInt(dwarf: *Dwarf, buf: []u8, int: u64) void { |
| 3758 | switch (buf.len) { |
| 3759 | inline 0...8 => |len| std.mem.writeInt(@Type(.{ .Int = .{ |
| 3760 | .signedness = .unsigned, |
| 3761 | .bits = len * 8, |
| 3762 | } }), buf[0..len], @intCast(int), dwarf.endian), |
| 3763 | else => unreachable, |
| 2839 | 3764 | } |
| 2840 | 3765 | } |
| 2841 | 3766 | |
| 2842 | | fn getAtom(self: *const Dwarf, comptime kind: Kind, index: Atom.Index) Atom { |
| 2843 | | return switch (kind) { |
| 2844 | | .src_fn => self.src_fns.items[index], |
| 2845 | | .di_atom => self.di_atoms.items[index], |
| 2846 | | }; |
| 3767 | fn resolveReloc(dwarf: *Dwarf, source: u64, target: u64, size: u32) RelocError!void { |
| 3768 | var buf: [8]u8 = undefined; |
| 3769 | dwarf.writeInt(buf[0..size], target); |
| 3770 | try dwarf.getFile().?.pwriteAll(buf[0..size], source); |
| 2847 | 3771 | } |
| 2848 | 3772 | |
| 2849 | | fn getAtomPtr(self: *Dwarf, comptime kind: Kind, index: Atom.Index) *Atom { |
| 2850 | | return switch (kind) { |
| 2851 | | .src_fn => &self.src_fns.items[index], |
| 2852 | | .di_atom => &self.di_atoms.items[index], |
| 3773 | fn unitLengthBytes(dwarf: *Dwarf) u32 { |
| 3774 | return switch (dwarf.format) { |
| 3775 | .@"32" => 4, |
| 3776 | .@"64" => 4 + 8, |
| 2853 | 3777 | }; |
| 2854 | 3778 | } |
| 2855 | 3779 | |
| 2856 | | pub const Format = enum { |
| 2857 | | dwarf32, |
| 2858 | | dwarf64, |
| 2859 | | }; |
| 3780 | fn sectionOffsetBytes(dwarf: *Dwarf) u32 { |
| 3781 | return switch (dwarf.format) { |
| 3782 | .@"32" => 4, |
| 3783 | .@"64" => 8, |
| 3784 | }; |
| 3785 | } |
| 2860 | 3786 | |
| 2861 | | const Dwarf = @This(); |
| 3787 | fn SectionOffset(comptime format: DW.Format) type { |
| 3788 | return switch (format) { |
| 3789 | .@"32" => u32, |
| 3790 | .@"64" => u64, |
| 3791 | }; |
| 3792 | } |
| 2862 | 3793 | |
| 2863 | | const std = @import("std"); |
| 2864 | | const builtin = @import("builtin"); |
| 2865 | | const assert = std.debug.assert; |
| 2866 | | const fs = std.fs; |
| 2867 | | const leb128 = std.leb; |
| 2868 | | const log = std.log.scoped(.dwarf); |
| 2869 | | const mem = std.mem; |
| 3794 | fn uleb128Bytes(value: anytype) u32 { |
| 3795 | var cw = std.io.countingWriter(std.io.null_writer); |
| 3796 | try uleb128(cw.writer(), value); |
| 3797 | return @intCast(cw.bytes_written); |
| 3798 | } |
| 2870 | 3799 | |
| 2871 | | const link = @import("../link.zig"); |
| 2872 | | const trace = @import("../tracy.zig").trace; |
| 3800 | /// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional |
| 3801 | const force_incremental = false; |
| 3802 | inline fn incremental(dwarf: Dwarf) bool { |
| 3803 | return force_incremental or dwarf.bin_file.comp.incremental; |
| 3804 | } |
| 2873 | 3805 | |
| 2874 | | const Allocator = mem.Allocator; |
| 2875 | 3806 | const DW = std.dwarf; |
| 2876 | | const File = link.File; |
| 2877 | | const LinkBlock = File.LinkBlock; |
| 2878 | | const LinkFn = File.LinkFn; |
| 2879 | | const LinkerLoad = @import("../codegen.zig").LinkerLoad; |
| 2880 | | const Zcu = @import("../Zcu.zig"); |
| 3807 | const Dwarf = @This(); |
| 2881 | 3808 | const InternPool = @import("../InternPool.zig"); |
| 2882 | | const StringTable = @import("StringTable.zig"); |
| 3809 | const Module = @import("../Package.zig").Module; |
| 2883 | 3810 | const Type = @import("../Type.zig"); |
| 2884 | | const Value = @import("../Value.zig"); |
| 3811 | const Zcu = @import("../Zcu.zig"); |
| 3812 | const Zir = std.zig.Zir; |
| 3813 | const assert = std.debug.assert; |
| 3814 | const codegen = @import("../codegen.zig"); |
| 3815 | const link = @import("../link.zig"); |
| 3816 | const log = std.log.scoped(.dwarf); |
| 3817 | const sleb128 = std.leb.writeIleb128; |
| 3818 | const std = @import("std"); |
| 3819 | const target_info = @import("../target.zig"); |
| 3820 | const uleb128 = std.leb.writeUleb128; |