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