| ... | @@ -3,7 +3,8 @@ const DebugSymbols = @This(); | ... | @@ -3,7 +3,8 @@ const DebugSymbols = @This(); |
| 3 | const std = @import("std"); | 3 | const std = @import("std"); |
| 4 | const assert = std.debug.assert; | 4 | const assert = std.debug.assert; |
| 5 | const fs = std.fs; | 5 | const fs = std.fs; |
| 6 | const log = std.log.scoped(.dsym); | 6 | const log = std.log.scoped(.link); |
| | 7 | const leb128 = std.leb; |
| 7 | const macho = std.macho; | 8 | const macho = std.macho; |
| 8 | const math = std.math; | 9 | const math = std.math; |
| 9 | const mem = std.mem; | 10 | const mem = std.mem; |
| ... | @@ -22,8 +23,6 @@ const SrcFn = MachO.SrcFn; | ... | @@ -22,8 +23,6 @@ const SrcFn = MachO.SrcFn; |
| 22 | const makeStaticString = MachO.makeStaticString; | 23 | const makeStaticString = MachO.makeStaticString; |
| 23 | const padToIdeal = MachO.padToIdeal; | 24 | const padToIdeal = MachO.padToIdeal; |
| 24 | | 25 | |
| 25 | const page_size: u16 = 0x1000; | | |
| 26 | | | |
| 27 | base: *MachO, | 26 | base: *MachO, |
| 28 | file: fs.File, | 27 | file: fs.File, |
| 29 | | 28 | |
| ... | @@ -49,9 +48,6 @@ uuid_cmd_index: ?u16 = null, | ... | @@ -49,9 +48,6 @@ uuid_cmd_index: ?u16 = null, |
| 49 | /// Index into __TEXT,__text section. | 48 | /// Index into __TEXT,__text section. |
| 50 | text_section_index: ?u16 = null, | 49 | text_section_index: ?u16 = null, |
| 51 | | 50 | |
| 52 | linkedit_off: u16 = page_size, | | |
| 53 | linkedit_size: u16 = page_size, | | |
| 54 | | | |
| 55 | debug_info_section_index: ?u16 = null, | 51 | debug_info_section_index: ?u16 = null, |
| 56 | debug_abbrev_section_index: ?u16 = null, | 52 | debug_abbrev_section_index: ?u16 = null, |
| 57 | debug_str_section_index: ?u16 = null, | 53 | debug_str_section_index: ?u16 = null, |
| ... | @@ -76,7 +72,6 @@ dbg_info_decl_last: ?*TextBlock = null, | ... | @@ -76,7 +72,6 @@ dbg_info_decl_last: ?*TextBlock = null, |
| 76 | debug_string_table: std.ArrayListUnmanaged(u8) = .{}, | 72 | debug_string_table: std.ArrayListUnmanaged(u8) = .{}, |
| 77 | | 73 | |
| 78 | load_commands_dirty: bool = false, | 74 | load_commands_dirty: bool = false, |
| 79 | strtab_dirty: bool = false, | | |
| 80 | debug_string_table_dirty: bool = false, | 75 | debug_string_table_dirty: bool = false, |
| 81 | debug_abbrev_section_dirty: bool = false, | 76 | debug_abbrev_section_dirty: bool = false, |
| 82 | debug_aranges_section_dirty: bool = false, | 77 | debug_aranges_section_dirty: bool = false, |
| ... | @@ -87,8 +82,12 @@ const abbrev_compile_unit = 1; | ... | @@ -87,8 +82,12 @@ const abbrev_compile_unit = 1; |
| 87 | const abbrev_subprogram = 2; | 82 | const abbrev_subprogram = 2; |
| 88 | const abbrev_subprogram_retvoid = 3; | 83 | const abbrev_subprogram_retvoid = 3; |
| 89 | const abbrev_base_type = 4; | 84 | const abbrev_base_type = 4; |
| 90 | const abbrev_pad1 = 5; | 85 | const abbrev_ptr_type = 5; |
| 91 | const abbrev_parameter = 6; | 86 | const abbrev_struct_type = 6; |
| | 87 | const abbrev_anon_struct_type = 7; |
| | 88 | const abbrev_struct_member = 8; |
| | 89 | const abbrev_pad1 = 9; |
| | 90 | const abbrev_parameter = 10; |
| 92 | | 91 | |
| 93 | /// The reloc offset for the virtual address of a function in its Line Number Program. | 92 | /// The reloc offset for the virtual address of a function in its Line Number Program. |
| 94 | /// Size is a virtual address integer. | 93 | /// Size is a virtual address integer. |
| ... | @@ -108,30 +107,21 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void | ... | @@ -108,30 +107,21 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void |
| 108 | try self.load_commands.append(allocator, base_cmd); | 107 | try self.load_commands.append(allocator, base_cmd); |
| 109 | self.load_commands_dirty = true; | 108 | self.load_commands_dirty = true; |
| 110 | } | 109 | } |
| | 110 | |
| 111 | if (self.symtab_cmd_index == null) { | 111 | if (self.symtab_cmd_index == null) { |
| 112 | self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len); | 112 | self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 113 | const base_cmd = self.base.load_commands.items[self.base.symtab_cmd_index.?].symtab; | 113 | try self.load_commands.append(self.base.base.allocator, .{ |
| 114 | const symtab_size = base_cmd.nsyms * @sizeOf(macho.nlist_64); | | |
| 115 | const symtab_off = self.findFreeSpaceLinkedit(symtab_size, @sizeOf(macho.nlist_64)); | | |
| 116 | | | |
| 117 | log.debug("found symbol table free space 0x{x} to 0x{x}", .{ symtab_off, symtab_off + symtab_size }); | | |
| 118 | | | |
| 119 | const strtab_off = self.findFreeSpaceLinkedit(base_cmd.strsize, 1); | | |
| 120 | | | |
| 121 | log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + base_cmd.strsize }); | | |
| 122 | | | |
| 123 | try self.load_commands.append(allocator, .{ | | |
| 124 | .symtab = .{ | 114 | .symtab = .{ |
| 125 | .cmdsize = @sizeOf(macho.symtab_command), | 115 | .cmdsize = @sizeOf(macho.symtab_command), |
| 126 | .symoff = @intCast(u32, symtab_off), | 116 | .symoff = 0, |
| 127 | .nsyms = base_cmd.nsyms, | 117 | .nsyms = 0, |
| 128 | .stroff = @intCast(u32, strtab_off), | 118 | .stroff = 0, |
| 129 | .strsize = base_cmd.strsize, | 119 | .strsize = 0, |
| 130 | }, | 120 | }, |
| 131 | }); | 121 | }); |
| 132 | self.load_commands_dirty = true; | 122 | self.load_commands_dirty = true; |
| 133 | self.strtab_dirty = true; | | |
| 134 | } | 123 | } |
| | 124 | |
| 135 | if (self.pagezero_segment_cmd_index == null) { | 125 | if (self.pagezero_segment_cmd_index == null) { |
| 136 | self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 126 | self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 137 | const base_cmd = self.base.load_commands.items[self.base.pagezero_segment_cmd_index.?].segment; | 127 | const base_cmd = self.base.load_commands.items[self.base.pagezero_segment_cmd_index.?].segment; |
| ... | @@ -139,6 +129,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void | ... | @@ -139,6 +129,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void |
| 139 | try self.load_commands.append(allocator, .{ .segment = cmd }); | 129 | try self.load_commands.append(allocator, .{ .segment = cmd }); |
| 140 | self.load_commands_dirty = true; | 130 | self.load_commands_dirty = true; |
| 141 | } | 131 | } |
| | 132 | |
| 142 | if (self.text_segment_cmd_index == null) { | 133 | if (self.text_segment_cmd_index == null) { |
| 143 | self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 134 | self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 144 | const base_cmd = self.base.load_commands.items[self.base.text_segment_cmd_index.?].segment; | 135 | const base_cmd = self.base.load_commands.items[self.base.text_segment_cmd_index.?].segment; |
| ... | @@ -146,6 +137,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void | ... | @@ -146,6 +137,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void |
| 146 | try self.load_commands.append(allocator, .{ .segment = cmd }); | 137 | try self.load_commands.append(allocator, .{ .segment = cmd }); |
| 147 | self.load_commands_dirty = true; | 138 | self.load_commands_dirty = true; |
| 148 | } | 139 | } |
| | 140 | |
| 149 | if (self.data_const_segment_cmd_index == null) outer: { | 141 | if (self.data_const_segment_cmd_index == null) outer: { |
| 150 | if (self.base.data_const_segment_cmd_index == null) break :outer; // __DATA_CONST is optional | 142 | if (self.base.data_const_segment_cmd_index == null) break :outer; // __DATA_CONST is optional |
| 151 | self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 143 | self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | @@ -154,6 +146,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void | ... | @@ -154,6 +146,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void |
| 154 | try self.load_commands.append(allocator, .{ .segment = cmd }); | 146 | try self.load_commands.append(allocator, .{ .segment = cmd }); |
| 155 | self.load_commands_dirty = true; | 147 | self.load_commands_dirty = true; |
| 156 | } | 148 | } |
| | 149 | |
| 157 | if (self.data_segment_cmd_index == null) outer: { | 150 | if (self.data_segment_cmd_index == null) outer: { |
| 158 | if (self.base.data_segment_cmd_index == null) break :outer; // __DATA is optional | 151 | if (self.base.data_segment_cmd_index == null) break :outer; // __DATA is optional |
| 159 | self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 152 | self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | @@ -162,26 +155,29 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void | ... | @@ -162,26 +155,29 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void |
| 162 | try self.load_commands.append(allocator, .{ .segment = cmd }); | 155 | try self.load_commands.append(allocator, .{ .segment = cmd }); |
| 163 | self.load_commands_dirty = true; | 156 | self.load_commands_dirty = true; |
| 164 | } | 157 | } |
| | 158 | |
| 165 | if (self.linkedit_segment_cmd_index == null) { | 159 | if (self.linkedit_segment_cmd_index == null) { |
| 166 | self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 160 | self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 167 | const base_cmd = self.base.load_commands.items[self.base.linkedit_segment_cmd_index.?].segment; | 161 | const base_cmd = self.base.load_commands.items[self.base.linkedit_segment_cmd_index.?].segment; |
| 168 | var cmd = try self.copySegmentCommand(allocator, base_cmd); | 162 | var cmd = try self.copySegmentCommand(allocator, base_cmd); |
| 169 | cmd.inner.vmsize = self.linkedit_size; | 163 | // TODO this needs reworking |
| 170 | cmd.inner.fileoff = self.linkedit_off; | 164 | cmd.inner.vmsize = self.base.page_size; |
| 171 | cmd.inner.filesize = self.linkedit_size; | 165 | cmd.inner.fileoff = self.base.page_size; |
| | 166 | cmd.inner.filesize = self.base.page_size; |
| 172 | try self.load_commands.append(allocator, .{ .segment = cmd }); | 167 | try self.load_commands.append(allocator, .{ .segment = cmd }); |
| 173 | self.load_commands_dirty = true; | 168 | self.load_commands_dirty = true; |
| 174 | } | 169 | } |
| | 170 | |
| 175 | if (self.dwarf_segment_cmd_index == null) { | 171 | if (self.dwarf_segment_cmd_index == null) { |
| 176 | self.dwarf_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 172 | self.dwarf_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 177 | | 173 | |
| 178 | const linkedit = self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; | 174 | const linkedit = self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 179 | const ideal_size: u16 = 200 + 128 + 160 + 250; | 175 | const ideal_size: u16 = 200 + 128 + 160 + 250; |
| 180 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), page_size); | 176 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.base.page_size); |
| 181 | const off = linkedit.inner.fileoff + linkedit.inner.filesize; | 177 | const fileoff = linkedit.inner.fileoff + linkedit.inner.filesize; |
| 182 | const vmaddr = linkedit.inner.vmaddr + linkedit.inner.vmsize; | 178 | const vmaddr = linkedit.inner.vmaddr + linkedit.inner.vmsize; |
| 183 | | 179 | |
| 184 | log.debug("found __DWARF segment free space 0x{x} to 0x{x}", .{ off, off + needed_size }); | 180 | log.debug("found __DWARF segment free space 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size }); |
| 185 | | 181 | |
| 186 | try self.load_commands.append(allocator, .{ | 182 | try self.load_commands.append(allocator, .{ |
| 187 | .segment = .{ | 183 | .segment = .{ |
| ... | @@ -189,13 +185,14 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void | ... | @@ -189,13 +185,14 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void |
| 189 | .segname = makeStaticString("__DWARF"), | 185 | .segname = makeStaticString("__DWARF"), |
| 190 | .vmaddr = vmaddr, | 186 | .vmaddr = vmaddr, |
| 191 | .vmsize = needed_size, | 187 | .vmsize = needed_size, |
| 192 | .fileoff = off, | 188 | .fileoff = fileoff, |
| 193 | .filesize = needed_size, | 189 | .filesize = needed_size, |
| 194 | }, | 190 | }, |
| 195 | }, | 191 | }, |
| 196 | }); | 192 | }); |
| 197 | self.load_commands_dirty = true; | 193 | self.load_commands_dirty = true; |
| 198 | } | 194 | } |
| | 195 | |
| 199 | if (self.debug_str_section_index == null) { | 196 | if (self.debug_str_section_index == null) { |
| 200 | assert(self.debug_string_table.items.len == 0); | 197 | assert(self.debug_string_table.items.len == 0); |
| 201 | self.debug_str_section_index = try self.allocateSection( | 198 | self.debug_str_section_index = try self.allocateSection( |
| ... | @@ -205,18 +202,22 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void | ... | @@ -205,18 +202,22 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void |
| 205 | ); | 202 | ); |
| 206 | self.debug_string_table_dirty = true; | 203 | self.debug_string_table_dirty = true; |
| 207 | } | 204 | } |
| | 205 | |
| 208 | if (self.debug_info_section_index == null) { | 206 | if (self.debug_info_section_index == null) { |
| 209 | self.debug_info_section_index = try self.allocateSection("__debug_info", 200, 0); | 207 | self.debug_info_section_index = try self.allocateSection("__debug_info", 200, 0); |
| 210 | self.debug_info_header_dirty = true; | 208 | self.debug_info_header_dirty = true; |
| 211 | } | 209 | } |
| | 210 | |
| 212 | if (self.debug_abbrev_section_index == null) { | 211 | if (self.debug_abbrev_section_index == null) { |
| 213 | self.debug_abbrev_section_index = try self.allocateSection("__debug_abbrev", 128, 0); | 212 | self.debug_abbrev_section_index = try self.allocateSection("__debug_abbrev", 128, 0); |
| 214 | self.debug_abbrev_section_dirty = true; | 213 | self.debug_abbrev_section_dirty = true; |
| 215 | } | 214 | } |
| | 215 | |
| 216 | if (self.debug_aranges_section_index == null) { | 216 | if (self.debug_aranges_section_index == null) { |
| 217 | self.debug_aranges_section_index = try self.allocateSection("__debug_aranges", 160, 4); | 217 | self.debug_aranges_section_index = try self.allocateSection("__debug_aranges", 160, 4); |
| 218 | self.debug_aranges_section_dirty = true; | 218 | self.debug_aranges_section_dirty = true; |
| 219 | } | 219 | } |
| | 220 | |
| 220 | if (self.debug_line_section_index == null) { | 221 | if (self.debug_line_section_index == null) { |
| 221 | self.debug_line_section_index = try self.allocateSection("__debug_line", 250, 0); | 222 | self.debug_line_section_index = try self.allocateSection("__debug_line", 250, 0); |
| 222 | self.debug_line_header_dirty = true; | 223 | self.debug_line_header_dirty = true; |
| ... | @@ -300,41 +301,91 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti | ... | @@ -300,41 +301,91 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti |
| 300 | // we can simply append these bytes. | 301 | // we can simply append these bytes. |
| 301 | const abbrev_buf = [_]u8{ | 302 | const abbrev_buf = [_]u8{ |
| 302 | abbrev_compile_unit, DW.TAG.compile_unit, DW.CHILDREN.yes, // header | 303 | abbrev_compile_unit, DW.TAG.compile_unit, DW.CHILDREN.yes, // header |
| 303 | DW.AT.stmt_list, DW.FORM.sec_offset, // offset | 304 | DW.AT.stmt_list, DW.FORM.sec_offset, DW.AT.low_pc, |
| 304 | DW.AT.low_pc, DW.FORM.addr, | 305 | DW.FORM.addr, DW.AT.high_pc, DW.FORM.addr, |
| 305 | DW.AT.high_pc, DW.FORM.addr, | 306 | DW.AT.name, DW.FORM.strp, DW.AT.comp_dir, |
| 306 | DW.AT.name, DW.FORM.strp, | 307 | DW.FORM.strp, DW.AT.producer, DW.FORM.strp, |
| 307 | DW.AT.comp_dir, DW.FORM.strp, | 308 | DW.AT.language, DW.FORM.data2, 0, |
| 308 | DW.AT.producer, DW.FORM.strp, | 309 | 0, // table sentinel |
| 309 | DW.AT.language, DW.FORM.data2, | 310 | abbrev_subprogram, |
| 310 | 0, 0, // table sentinel | 311 | DW.TAG.subprogram, |
| 311 | abbrev_subprogram, DW.TAG.subprogram, DW.CHILDREN.yes, // header | 312 | DW.CHILDREN.yes, // header |
| 312 | DW.AT.low_pc, DW.FORM.addr, // start VM address | 313 | DW.AT.low_pc, |
| 313 | DW.AT.high_pc, DW.FORM.data4, | 314 | DW.FORM.addr, |
| 314 | DW.AT.type, DW.FORM.ref4, | 315 | DW.AT.high_pc, |
| 315 | DW.AT.name, DW.FORM.string, | 316 | DW.FORM.data4, |
| 316 | DW.AT.decl_line, DW.FORM.data4, | 317 | DW.AT.type, |
| 317 | DW.AT.decl_file, DW.FORM.data1, | 318 | DW.FORM.ref4, |
| | 319 | DW.AT.name, |
| | 320 | DW.FORM.string, |
| 318 | 0, 0, // table sentinel | 321 | 0, 0, // table sentinel |
| 319 | abbrev_subprogram_retvoid, | 322 | abbrev_subprogram_retvoid, |
| 320 | DW.TAG.subprogram, DW.CHILDREN.yes, // header | 323 | DW.TAG.subprogram, DW.CHILDREN.yes, // header |
| 321 | DW.AT.low_pc, DW.FORM.addr, | 324 | DW.AT.low_pc, DW.FORM.addr, |
| 322 | DW.AT.high_pc, DW.FORM.data4, | 325 | DW.AT.high_pc, DW.FORM.data4, |
| 323 | DW.AT.name, DW.FORM.string, | 326 | DW.AT.name, DW.FORM.string, |
| 324 | DW.AT.decl_line, DW.FORM.data4, | 327 | 0, |
| 325 | DW.AT.decl_file, DW.FORM.data1, | 328 | 0, // table sentinel |
| 326 | 0, 0, // table sentinel | 329 | abbrev_base_type, |
| 327 | abbrev_base_type, DW.TAG.base_type, DW.CHILDREN.no, // header | 330 | DW.TAG.base_type, |
| 328 | DW.AT.encoding, DW.FORM.data1, DW.AT.byte_size, | 331 | DW.CHILDREN.no, // header |
| 329 | DW.FORM.data1, DW.AT.name, DW.FORM.string, | 332 | DW.AT.encoding, |
| 330 | 0, 0, // table sentinel | 333 | DW.FORM.data1, |
| 331 | abbrev_pad1, DW.TAG.unspecified_type, DW.CHILDREN.no, // header | 334 | DW.AT.byte_size, |
| 332 | 0, 0, // table sentinel | 335 | DW.FORM.data1, |
| 333 | abbrev_parameter, DW.TAG.formal_parameter, DW.CHILDREN.no, // header | 336 | DW.AT.name, |
| 334 | DW.AT.location, DW.FORM.exprloc, DW.AT.type, | 337 | DW.FORM.string, |
| 335 | DW.FORM.ref4, DW.AT.name, DW.FORM.string, | 338 | 0, |
| 336 | 0, 0, // table sentinel | 339 | 0, // table sentinel |
| 337 | 0, 0, 0, // section sentinel | 340 | abbrev_ptr_type, |
| | 341 | DW.TAG.pointer_type, |
| | 342 | DW.CHILDREN.no, // header |
| | 343 | DW.AT.type, |
| | 344 | DW.FORM.ref4, |
| | 345 | 0, |
| | 346 | 0, // table sentinel |
| | 347 | abbrev_struct_type, |
| | 348 | DW.TAG.structure_type, |
| | 349 | DW.CHILDREN.yes, // header |
| | 350 | DW.AT.byte_size, |
| | 351 | DW.FORM.sdata, |
| | 352 | DW.AT.name, |
| | 353 | DW.FORM.string, |
| | 354 | 0, |
| | 355 | 0, // table sentinel |
| | 356 | abbrev_anon_struct_type, |
| | 357 | DW.TAG.structure_type, |
| | 358 | DW.CHILDREN.yes, // header |
| | 359 | DW.AT.byte_size, |
| | 360 | DW.FORM.sdata, |
| | 361 | 0, |
| | 362 | 0, // table sentinel |
| | 363 | abbrev_struct_member, |
| | 364 | DW.TAG.member, |
| | 365 | DW.CHILDREN.no, // header |
| | 366 | DW.AT.name, |
| | 367 | DW.FORM.string, |
| | 368 | DW.AT.type, |
| | 369 | DW.FORM.ref4, |
| | 370 | DW.AT.data_member_location, |
| | 371 | DW.FORM.sdata, |
| | 372 | 0, |
| | 373 | 0, // table sentinel |
| | 374 | abbrev_pad1, |
| | 375 | DW.TAG.unspecified_type, |
| | 376 | DW.CHILDREN.no, // header |
| | 377 | 0, |
| | 378 | 0, // table sentinel |
| | 379 | abbrev_parameter, |
| | 380 | DW.TAG.formal_parameter, DW.CHILDREN.no, // header |
| | 381 | DW.AT.location, DW.FORM.exprloc, |
| | 382 | DW.AT.type, DW.FORM.ref4, |
| | 383 | DW.AT.name, DW.FORM.string, |
| | 384 | 0, |
| | 385 | 0, // table sentinel |
| | 386 | 0, |
| | 387 | 0, |
| | 388 | 0, // section sentinel |
| 338 | }; | 389 | }; |
| 339 | | 390 | |
| 340 | const needed_size = abbrev_buf.len; | 391 | const needed_size = abbrev_buf.len; |
| ... | @@ -583,13 +634,12 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti | ... | @@ -583,13 +634,12 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti |
| 583 | } | 634 | } |
| 584 | } | 635 | } |
| 585 | | 636 | |
| 586 | try self.writeStringTable(); | 637 | try self.writeLinkeditSegment(); |
| 587 | self.updateDwarfSegment(); | 638 | self.updateDwarfSegment(); |
| 588 | try self.writeLoadCommands(allocator); | 639 | try self.writeLoadCommands(allocator); |
| 589 | try self.writeHeader(); | 640 | try self.writeHeader(); |
| 590 | | 641 | |
| 591 | assert(!self.load_commands_dirty); | 642 | assert(!self.load_commands_dirty); |
| 592 | assert(!self.strtab_dirty); | | |
| 593 | assert(!self.debug_abbrev_section_dirty); | 643 | assert(!self.debug_abbrev_section_dirty); |
| 594 | assert(!self.debug_aranges_section_dirty); | 644 | assert(!self.debug_aranges_section_dirty); |
| 595 | assert(!self.debug_string_table_dirty); | 645 | assert(!self.debug_string_table_dirty); |
| ... | @@ -663,7 +713,7 @@ fn updateDwarfSegment(self: *DebugSymbols) void { | ... | @@ -663,7 +713,7 @@ fn updateDwarfSegment(self: *DebugSymbols) void { |
| 663 | if (file_size != dwarf_segment.inner.filesize) { | 713 | if (file_size != dwarf_segment.inner.filesize) { |
| 664 | dwarf_segment.inner.filesize = file_size; | 714 | dwarf_segment.inner.filesize = file_size; |
| 665 | if (dwarf_segment.inner.vmsize < dwarf_segment.inner.filesize) { | 715 | if (dwarf_segment.inner.vmsize < dwarf_segment.inner.filesize) { |
| 666 | dwarf_segment.inner.vmsize = mem.alignForwardGeneric(u64, dwarf_segment.inner.filesize, page_size); | 716 | dwarf_segment.inner.vmsize = mem.alignForwardGeneric(u64, dwarf_segment.inner.filesize, self.base.page_size); |
| 667 | } | 717 | } |
| 668 | self.load_commands_dirty = true; | 718 | self.load_commands_dirty = true; |
| 669 | } | 719 | } |
| ... | @@ -719,23 +769,10 @@ fn writeHeader(self: *DebugSymbols) !void { | ... | @@ -719,23 +769,10 @@ fn writeHeader(self: *DebugSymbols) !void { |
| 719 | try self.file.pwriteAll(mem.asBytes(&header), 0); | 769 | try self.file.pwriteAll(mem.asBytes(&header), 0); |
| 720 | } | 770 | } |
| 721 | | 771 | |
| 722 | fn allocatedSizeLinkedit(self: *DebugSymbols, start: u64) u64 { | | |
| 723 | assert(start > 0); | | |
| 724 | var min_pos: u64 = std.math.maxInt(u64); | | |
| 725 | | | |
| 726 | if (self.symtab_cmd_index) |idx| { | | |
| 727 | const symtab = self.load_commands.items[idx].symtab; | | |
| 728 | if (symtab.symoff >= start and symtab.symoff < min_pos) min_pos = symtab.symoff; | | |
| 729 | if (symtab.stroff >= start and symtab.stroff < min_pos) min_pos = symtab.stroff; | | |
| 730 | } | | |
| 731 | | | |
| 732 | return min_pos - start; | | |
| 733 | } | | |
| 734 | | | |
| 735 | fn allocatedSize(self: *DebugSymbols, start: u64) u64 { | 772 | fn allocatedSize(self: *DebugSymbols, start: u64) u64 { |
| 736 | const seg = self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; | 773 | const seg = self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; |
| 737 | assert(start >= seg.inner.fileoff); | 774 | assert(start >= seg.inner.fileoff); |
| 738 | var min_pos: u64 = seg.inner.fileoff + seg.inner.filesize; | 775 | var min_pos: u64 = std.math.maxInt(u64); |
| 739 | for (seg.sections.items) |section| { | 776 | for (seg.sections.items) |section| { |
| 740 | if (section.offset <= start) continue; | 777 | if (section.offset <= start) continue; |
| 741 | if (section.offset < min_pos) min_pos = section.offset; | 778 | if (section.offset < min_pos) min_pos = section.offset; |
| ... | @@ -743,102 +780,72 @@ fn allocatedSize(self: *DebugSymbols, start: u64) u64 { | ... | @@ -743,102 +780,72 @@ fn allocatedSize(self: *DebugSymbols, start: u64) u64 { |
| 743 | return min_pos - start; | 780 | return min_pos - start; |
| 744 | } | 781 | } |
| 745 | | 782 | |
| 746 | fn detectAllocCollisionLinkedit(self: *DebugSymbols, start: u64, size: u64) ?u64 { | 783 | fn writeLinkeditSegment(self: *DebugSymbols) !void { |
| 747 | const end = start + padToIdeal(size); | 784 | const tracy = trace(@src()); |
| | 785 | defer tracy.end(); |
| 748 | | 786 | |
| 749 | if (self.symtab_cmd_index) |idx| outer: { | 787 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 750 | if (self.load_commands.items.len == idx) break :outer; | 788 | seg.inner.filesize = 0; |
| 751 | const symtab = self.load_commands.items[idx].symtab; | | |
| 752 | { | | |
| 753 | // Symbol table | | |
| 754 | const symsize = symtab.nsyms * @sizeOf(macho.nlist_64); | | |
| 755 | const increased_size = padToIdeal(symsize); | | |
| 756 | const test_end = symtab.symoff + increased_size; | | |
| 757 | if (end > symtab.symoff and start < test_end) { | | |
| 758 | return test_end; | | |
| 759 | } | | |
| 760 | } | | |
| 761 | { | | |
| 762 | // String table | | |
| 763 | const increased_size = padToIdeal(symtab.strsize); | | |
| 764 | const test_end = symtab.stroff + increased_size; | | |
| 765 | if (end > symtab.stroff and start < test_end) { | | |
| 766 | return test_end; | | |
| 767 | } | | |
| 768 | } | | |
| 769 | } | | |
| 770 | | 789 | |
| 771 | return null; | 790 | try self.writeSymbolTable(); |
| | 791 | try self.writeStringTable(); |
| 772 | } | 792 | } |
| 773 | | 793 | |
| 774 | fn findFreeSpaceLinkedit(self: *DebugSymbols, object_size: u64, min_alignment: u16) u64 { | 794 | fn writeSymbolTable(self: *DebugSymbols) !void { |
| 775 | var start: u64 = self.linkedit_off; | 795 | const tracy = trace(@src()); |
| 776 | while (self.detectAllocCollisionLinkedit(start, object_size)) |item_end| { | 796 | defer tracy.end(); |
| 777 | start = mem.alignForwardGeneric(u64, item_end, min_alignment); | | |
| 778 | } | | |
| 779 | return start; | | |
| 780 | } | | |
| 781 | | 797 | |
| 782 | fn relocateSymbolTable(self: *DebugSymbols) !void { | 798 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 783 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab; | 799 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab; |
| 784 | const nlocals = self.base.locals.items.len; | 800 | symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); |
| 785 | const nglobals = self.base.globals.items.len; | | |
| 786 | const nsyms = nlocals + nglobals; | | |
| 787 | | | |
| 788 | if (symtab.nsyms < nsyms) { | | |
| 789 | const needed_size = nsyms * @sizeOf(macho.nlist_64); | | |
| 790 | if (needed_size > self.allocatedSizeLinkedit(symtab.symoff)) { | | |
| 791 | // Move the entire symbol table to a new location | | |
| 792 | const new_symoff = self.findFreeSpaceLinkedit(needed_size, @alignOf(macho.nlist_64)); | | |
| 793 | const existing_size = symtab.nsyms * @sizeOf(macho.nlist_64); | | |
| 794 | | | |
| 795 | assert(new_symoff + existing_size <= self.linkedit_off + self.linkedit_size); // TODO expand LINKEDIT segment. | | |
| 796 | log.debug("relocating symbol table from 0x{x}-0x{x} to 0x{x}-0x{x}", .{ | | |
| 797 | symtab.symoff, | | |
| 798 | symtab.symoff + existing_size, | | |
| 799 | new_symoff, | | |
| 800 | new_symoff + existing_size, | | |
| 801 | }); | | |
| 802 | | 801 | |
| 803 | const amt = try self.file.copyRangeAll(symtab.symoff, self.file, new_symoff, existing_size); | 802 | var locals = std.ArrayList(macho.nlist_64).init(self.base.base.allocator); |
| 804 | if (amt != existing_size) return error.InputOutput; | 803 | defer locals.deinit(); |
| 805 | symtab.symoff = @intCast(u32, new_symoff); | 804 | |
| 806 | } | 805 | for (self.base.locals.items) |sym| { |
| 807 | symtab.nsyms = @intCast(u32, nsyms); | 806 | if (sym.n_strx == 0) continue; |
| 808 | self.load_commands_dirty = true; | 807 | if (self.base.symbol_resolver.get(sym.n_strx)) |_| continue; |
| | 808 | try locals.append(sym); |
| 809 | } | 809 | } |
| 810 | } | | |
| 811 | | 810 | |
| 812 | pub fn writeLocalSymbol(self: *DebugSymbols, index: usize) !void { | 811 | const nlocals = locals.items.len; |
| 813 | const tracy = trace(@src()); | 812 | const nexports = self.base.globals.items.len; |
| 814 | defer tracy.end(); | 813 | |
| 815 | try self.relocateSymbolTable(); | 814 | const locals_off = symtab.symoff; |
| 816 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab; | 815 | const locals_size = nlocals * @sizeOf(macho.nlist_64); |
| 817 | const off = symtab.symoff + @sizeOf(macho.nlist_64) * index; | 816 | log.debug("writing local symbols from 0x{x} to 0x{x}", .{ locals_off, locals_size + locals_off }); |
| 818 | log.debug("writing local symbol {} at 0x{x}", .{ index, off }); | 817 | try self.file.pwriteAll(mem.sliceAsBytes(locals.items), locals_off); |
| 819 | try self.file.pwriteAll(mem.asBytes(&self.base.locals.items[index]), off); | 818 | |
| | 819 | const exports_off = locals_off + locals_size; |
| | 820 | const exports_size = nexports * @sizeOf(macho.nlist_64); |
| | 821 | log.debug("writing exported symbols from 0x{x} to 0x{x}", .{ exports_off, exports_size + exports_off }); |
| | 822 | try self.file.pwriteAll(mem.sliceAsBytes(self.base.globals.items), exports_off); |
| | 823 | |
| | 824 | symtab.nsyms = @intCast(u32, nlocals + nexports); |
| | 825 | seg.inner.filesize += locals_size + exports_size; |
| | 826 | |
| | 827 | self.load_commands_dirty = true; |
| 820 | } | 828 | } |
| 821 | | 829 | |
| 822 | fn writeStringTable(self: *DebugSymbols) !void { | 830 | fn writeStringTable(self: *DebugSymbols) !void { |
| 823 | if (!self.strtab_dirty) return; | | |
| 824 | | | |
| 825 | const tracy = trace(@src()); | 831 | const tracy = trace(@src()); |
| 826 | defer tracy.end(); | 832 | defer tracy.end(); |
| 827 | | 833 | |
| | 834 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 828 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab; | 835 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab; |
| 829 | const allocated_size = self.allocatedSizeLinkedit(symtab.stroff); | 836 | symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); |
| 830 | const needed_size = mem.alignForwardGeneric(u64, self.base.strtab.items.len, @alignOf(u64)); | 837 | symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.base.strtab.items.len, @alignOf(u64))); |
| | 838 | seg.inner.filesize += symtab.strsize; |
| 831 | | 839 | |
| 832 | if (needed_size > allocated_size) { | | |
| 833 | symtab.strsize = 0; | | |
| 834 | symtab.stroff = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1)); | | |
| 835 | } | | |
| 836 | symtab.strsize = @intCast(u32, needed_size); | | |
| 837 | log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize }); | 840 | log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize }); |
| 838 | | 841 | |
| 839 | try self.file.pwriteAll(self.base.strtab.items, symtab.stroff); | 842 | try self.file.pwriteAll(self.base.strtab.items, symtab.stroff); |
| | 843 | |
| | 844 | if (symtab.strsize > self.base.strtab.items.len) { |
| | 845 | // This is potentially the last section, so we need to pad it out. |
| | 846 | try self.file.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1); |
| | 847 | } |
| 840 | self.load_commands_dirty = true; | 848 | self.load_commands_dirty = true; |
| 841 | self.strtab_dirty = false; | | |
| 842 | } | 849 | } |
| 843 | | 850 | |
| 844 | pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const Module.Decl) !void { | 851 | pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const Module.Decl) !void { |
| ... | @@ -846,14 +853,21 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M | ... | @@ -846,14 +853,21 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M |
| 846 | const tracy = trace(@src()); | 853 | const tracy = trace(@src()); |
| 847 | defer tracy.end(); | 854 | defer tracy.end(); |
| 848 | | 855 | |
| | 856 | log.debug("updateDeclLineNumber {s}{*}", .{ decl.name, decl }); |
| | 857 | |
| 849 | const func = decl.val.castTag(.function).?.data; | 858 | const func = decl.val.castTag(.function).?.data; |
| 850 | const line_off = @intCast(u28, decl.src_line + func.lbrace_line); | 859 | log.debug(" (decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d})", .{ |
| | 860 | decl.src_line, |
| | 861 | func.lbrace_line, |
| | 862 | func.rbrace_line, |
| | 863 | }); |
| | 864 | const line = @intCast(u28, decl.src_line + func.lbrace_line); |
| 851 | | 865 | |
| 852 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; | 866 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; |
| 853 | const shdr = &dwarf_segment.sections.items[self.debug_line_section_index.?]; | 867 | const shdr = &dwarf_segment.sections.items[self.debug_line_section_index.?]; |
| 854 | const file_pos = shdr.offset + decl.fn_link.macho.off + getRelocDbgLineOff(); | 868 | const file_pos = shdr.offset + decl.fn_link.macho.off + getRelocDbgLineOff(); |
| 855 | var data: [4]u8 = undefined; | 869 | var data: [4]u8 = undefined; |
| 856 | leb.writeUnsignedFixed(4, &data, line_off); | 870 | leb.writeUnsignedFixed(4, &data, line); |
| 857 | try self.file.pwriteAll(&data, file_pos); | 871 | try self.file.pwriteAll(&data, file_pos); |
| 858 | } | 872 | } |
| 859 | | 873 | |
| ... | @@ -886,7 +900,13 @@ pub fn initDeclDebugBuffers( | ... | @@ -886,7 +900,13 @@ pub fn initDeclDebugBuffers( |
| 886 | try dbg_line_buffer.ensureTotalCapacity(26); | 900 | try dbg_line_buffer.ensureTotalCapacity(26); |
| 887 | | 901 | |
| 888 | const func = decl.val.castTag(.function).?.data; | 902 | const func = decl.val.castTag(.function).?.data; |
| 889 | const line_off = @intCast(u28, decl.src_line + func.lbrace_line); | 903 | log.debug("updateFunc {s}{*}", .{ decl.name, func.owner_decl }); |
| | 904 | log.debug(" (decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d})", .{ |
| | 905 | decl.src_line, |
| | 906 | func.lbrace_line, |
| | 907 | func.rbrace_line, |
| | 908 | }); |
| | 909 | const line = @intCast(u28, decl.src_line + func.lbrace_line); |
| 890 | | 910 | |
| 891 | dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{ | 911 | dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{ |
| 892 | DW.LNS.extended_op, | 912 | DW.LNS.extended_op, |
| ... | @@ -902,7 +922,7 @@ pub fn initDeclDebugBuffers( | ... | @@ -902,7 +922,7 @@ pub fn initDeclDebugBuffers( |
| 902 | // to this function's begin curly. | 922 | // to this function's begin curly. |
| 903 | assert(getRelocDbgLineOff() == dbg_line_buffer.items.len); | 923 | assert(getRelocDbgLineOff() == dbg_line_buffer.items.len); |
| 904 | // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later. | 924 | // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later. |
| 905 | leb.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line_off); | 925 | leb.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line); |
| 906 | | 926 | |
| 907 | dbg_line_buffer.appendAssumeCapacity(DW.LNS.set_file); | 927 | dbg_line_buffer.appendAssumeCapacity(DW.LNS.set_file); |
| 908 | assert(getRelocDbgFileIndex() == dbg_line_buffer.items.len); | 928 | assert(getRelocDbgFileIndex() == dbg_line_buffer.items.len); |
| ... | @@ -917,7 +937,7 @@ pub fn initDeclDebugBuffers( | ... | @@ -917,7 +937,7 @@ pub fn initDeclDebugBuffers( |
| 917 | | 937 | |
| 918 | // .debug_info subprogram | 938 | // .debug_info subprogram |
| 919 | const decl_name_with_null = decl.name[0 .. mem.sliceTo(decl.name, 0).len + 1]; | 939 | const decl_name_with_null = decl.name[0 .. mem.sliceTo(decl.name, 0).len + 1]; |
| 920 | try dbg_info_buffer.ensureUnusedCapacity(27 + decl_name_with_null.len); | 940 | try dbg_info_buffer.ensureUnusedCapacity(25 + decl_name_with_null.len); |
| 921 | | 941 | |
| 922 | const fn_ret_type = decl.ty.fnReturnType(); | 942 | const fn_ret_type = decl.ty.fnReturnType(); |
| 923 | const fn_ret_has_bits = fn_ret_type.hasRuntimeBits(); | 943 | const fn_ret_has_bits = fn_ret_type.hasRuntimeBits(); |
| ... | @@ -945,8 +965,6 @@ pub fn initDeclDebugBuffers( | ... | @@ -945,8 +965,6 @@ pub fn initDeclDebugBuffers( |
| 945 | dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4 | 965 | dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4 |
| 946 | } | 966 | } |
| 947 | dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT.name, DW.FORM.string | 967 | dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT.name, DW.FORM.string |
| 948 | mem.writeIntLittle(u32, dbg_info_buffer.addManyAsArrayAssumeCapacity(4), line_off + 1); // DW.AT.decl_line, DW.FORM.data4 | | |
| 949 | dbg_info_buffer.appendAssumeCapacity(file_index); // DW.AT.decl_file, DW.FORM.data1 | | |
| 950 | }, | 968 | }, |
| 951 | else => { | 969 | else => { |
| 952 | // TODO implement .debug_info for global variables | 970 | // TODO implement .debug_info for global variables |
| ... | @@ -966,7 +984,6 @@ pub fn commitDeclDebugInfo( | ... | @@ -966,7 +984,6 @@ pub fn commitDeclDebugInfo( |
| 966 | module: *Module, | 984 | module: *Module, |
| 967 | decl: *Module.Decl, | 985 | decl: *Module.Decl, |
| 968 | debug_buffers: *DeclDebugBuffers, | 986 | debug_buffers: *DeclDebugBuffers, |
| 969 | target: std.Target, | | |
| 970 | ) !void { | 987 | ) !void { |
| 971 | const tracy = trace(@src()); | 988 | const tracy = trace(@src()); |
| 972 | defer tracy.end(); | 989 | defer tracy.end(); |
| ... | @@ -1097,14 +1114,26 @@ pub fn commitDeclDebugInfo( | ... | @@ -1097,14 +1114,26 @@ pub fn commitDeclDebugInfo( |
| 1097 | if (dbg_info_buffer.items.len == 0) | 1114 | if (dbg_info_buffer.items.len == 0) |
| 1098 | return; | 1115 | return; |
| 1099 | | 1116 | |
| | 1117 | // We need this for the duration of this function only so that for composite |
| | 1118 | // types such as []const u32, if the type *u32 is non-existent, we create |
| | 1119 | // it synthetically and store the backing bytes in this arena. After we are |
| | 1120 | // done with the relocations, we can safely deinit the entire memory slab. |
| | 1121 | // TODO currently, we do not store the relocations for future use, however, |
| | 1122 | // if that is the case, we should move memory management to a higher scope, |
| | 1123 | // such as linker scope, or whatnot. |
| | 1124 | var dbg_type_arena = std.heap.ArenaAllocator.init(allocator); |
| | 1125 | defer dbg_type_arena.deinit(); |
| | 1126 | |
| 1100 | { | 1127 | { |
| 1101 | // Now we emit the .debug_info types of the Decl. These will count towards the size of | 1128 | // Now we emit the .debug_info types of the Decl. These will count towards the size of |
| 1102 | // the buffer, so we have to do it before computing the offset, and we can't perform the actual | 1129 | // the buffer, so we have to do it before computing the offset, and we can't perform the actual |
| 1103 | // relocations yet. | 1130 | // relocations yet. |
| 1104 | var it = dbg_info_type_relocs.iterator(); | 1131 | var it: usize = 0; |
| 1105 | while (it.next()) |entry| { | 1132 | while (it < dbg_info_type_relocs.count()) : (it += 1) { |
| 1106 | entry.value_ptr.off = @intCast(u32, dbg_info_buffer.items.len); | 1133 | const ty = dbg_info_type_relocs.keys()[it]; |
| 1107 | try self.addDbgInfoType(entry.key_ptr.*, dbg_info_buffer, target); | 1134 | const value_ptr = dbg_info_type_relocs.getPtr(ty).?; |
| | 1135 | value_ptr.off = @intCast(u32, dbg_info_buffer.items.len); |
| | 1136 | try self.addDbgInfoType(dbg_type_arena.allocator(), ty, dbg_info_buffer, dbg_info_type_relocs); |
| 1108 | } | 1137 | } |
| 1109 | } | 1138 | } |
| 1110 | | 1139 | |
| ... | @@ -1129,24 +1158,25 @@ pub fn commitDeclDebugInfo( | ... | @@ -1129,24 +1158,25 @@ pub fn commitDeclDebugInfo( |
| 1129 | /// Asserts the type has codegen bits. | 1158 | /// Asserts the type has codegen bits. |
| 1130 | fn addDbgInfoType( | 1159 | fn addDbgInfoType( |
| 1131 | self: *DebugSymbols, | 1160 | self: *DebugSymbols, |
| | 1161 | arena: Allocator, |
| 1132 | ty: Type, | 1162 | ty: Type, |
| 1133 | dbg_info_buffer: *std.ArrayList(u8), | 1163 | dbg_info_buffer: *std.ArrayList(u8), |
| 1134 | target: std.Target, | 1164 | dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable, |
| 1135 | ) !void { | 1165 | ) !void { |
| 1136 | _ = self; | 1166 | const target = self.base.base.options.target; |
| | 1167 | var relocs = std.ArrayList(struct { ty: Type, reloc: u32 }).init(arena); |
| | 1168 | |
| 1137 | switch (ty.zigTypeTag()) { | 1169 | switch (ty.zigTypeTag()) { |
| 1138 | .Void => unreachable, | | |
| 1139 | .NoReturn => unreachable, | 1170 | .NoReturn => unreachable, |
| | 1171 | .Void => { |
| | 1172 | try dbg_info_buffer.append(abbrev_pad1); |
| | 1173 | }, |
| 1140 | .Bool => { | 1174 | .Bool => { |
| 1141 | try dbg_info_buffer.appendSlice(&[_]u8{ | 1175 | try dbg_info_buffer.appendSlice(&[_]u8{ |
| 1142 | abbrev_base_type, | 1176 | abbrev_base_type, |
| 1143 | DW.ATE.boolean, // DW.AT.encoding , DW.FORM.data1 | 1177 | DW.ATE.boolean, // DW.AT.encoding , DW.FORM.data1 |
| 1144 | 1, // DW.AT.byte_size, DW.FORM.data1 | 1178 | 1, // DW.AT.byte_size, DW.FORM.data1 |
| 1145 | 'b', | 1179 | 'b', 'o', 'o', 'l', 0, // DW.AT.name, DW.FORM.string |
| 1146 | 'o', | | |
| 1147 | 'o', | | |
| 1148 | 'l', | | |
| 1149 | 0, // DW.AT.name, DW.FORM.string | | |
| 1150 | }); | 1180 | }); |
| 1151 | }, | 1181 | }, |
| 1152 | .Int => { | 1182 | .Int => { |
| ... | @@ -1163,11 +1193,120 @@ fn addDbgInfoType( | ... | @@ -1163,11 +1193,120 @@ fn addDbgInfoType( |
| 1163 | // DW.AT.name, DW.FORM.string | 1193 | // DW.AT.name, DW.FORM.string |
| 1164 | try dbg_info_buffer.writer().print("{}\x00", .{ty}); | 1194 | try dbg_info_buffer.writer().print("{}\x00", .{ty}); |
| 1165 | }, | 1195 | }, |
| | 1196 | .Optional => { |
| | 1197 | if (ty.isPtrLikeOptional()) { |
| | 1198 | try dbg_info_buffer.ensureUnusedCapacity(12); |
| | 1199 | dbg_info_buffer.appendAssumeCapacity(abbrev_base_type); |
| | 1200 | // DW.AT.encoding, DW.FORM.data1 |
| | 1201 | dbg_info_buffer.appendAssumeCapacity(DW.ATE.address); |
| | 1202 | // DW.AT.byte_size, DW.FORM.data1 |
| | 1203 | dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(target))); |
| | 1204 | // DW.AT.name, DW.FORM.string |
| | 1205 | try dbg_info_buffer.writer().print("{}\x00", .{ty}); |
| | 1206 | } else { |
| | 1207 | log.debug("TODO implement .debug_info for type '{}'", .{ty}); |
| | 1208 | try dbg_info_buffer.append(abbrev_pad1); |
| | 1209 | } |
| | 1210 | }, |
| | 1211 | .Pointer => { |
| | 1212 | if (ty.isSlice()) { |
| | 1213 | // Slices are anonymous structs: struct { .ptr = *, .len = N } |
| | 1214 | try dbg_info_buffer.ensureUnusedCapacity(23); |
| | 1215 | // DW.AT.structure_type |
| | 1216 | dbg_info_buffer.appendAssumeCapacity(abbrev_anon_struct_type); |
| | 1217 | // DW.AT.byte_size, DW.FORM.sdata |
| | 1218 | dbg_info_buffer.appendAssumeCapacity(16); |
| | 1219 | // DW.AT.member |
| | 1220 | dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); |
| | 1221 | // DW.AT.name, DW.FORM.string |
| | 1222 | dbg_info_buffer.appendSliceAssumeCapacity("ptr"); |
| | 1223 | dbg_info_buffer.appendAssumeCapacity(0); |
| | 1224 | // DW.AT.type, DW.FORM.ref4 |
| | 1225 | var index = dbg_info_buffer.items.len; |
| | 1226 | try dbg_info_buffer.resize(index + 4); |
| | 1227 | var buf = try arena.create(Type.SlicePtrFieldTypeBuffer); |
| | 1228 | const ptr_ty = ty.slicePtrFieldType(buf); |
| | 1229 | try relocs.append(.{ .ty = ptr_ty, .reloc = @intCast(u32, index) }); |
| | 1230 | // DW.AT.data_member_location, DW.FORM.sdata |
| | 1231 | dbg_info_buffer.appendAssumeCapacity(0); |
| | 1232 | // DW.AT.member |
| | 1233 | dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); |
| | 1234 | // DW.AT.name, DW.FORM.string |
| | 1235 | dbg_info_buffer.appendSliceAssumeCapacity("len"); |
| | 1236 | dbg_info_buffer.appendAssumeCapacity(0); |
| | 1237 | // DW.AT.type, DW.FORM.ref4 |
| | 1238 | index = dbg_info_buffer.items.len; |
| | 1239 | try dbg_info_buffer.resize(index + 4); |
| | 1240 | try relocs.append(.{ .ty = Type.initTag(.usize), .reloc = @intCast(u32, index) }); |
| | 1241 | // DW.AT.data_member_location, DW.FORM.sdata |
| | 1242 | dbg_info_buffer.appendAssumeCapacity(8); |
| | 1243 | // DW.AT.structure_type delimit children |
| | 1244 | dbg_info_buffer.appendAssumeCapacity(0); |
| | 1245 | } else { |
| | 1246 | try dbg_info_buffer.ensureUnusedCapacity(5); |
| | 1247 | dbg_info_buffer.appendAssumeCapacity(abbrev_ptr_type); |
| | 1248 | // DW.AT.type, DW.FORM.ref4 |
| | 1249 | const index = dbg_info_buffer.items.len; |
| | 1250 | try dbg_info_buffer.resize(index + 4); |
| | 1251 | try relocs.append(.{ .ty = ty.childType(), .reloc = @intCast(u32, index) }); |
| | 1252 | } |
| | 1253 | }, |
| | 1254 | .Struct => blk: { |
| | 1255 | // try dbg_info_buffer.ensureUnusedCapacity(23); |
| | 1256 | // DW.AT.structure_type |
| | 1257 | try dbg_info_buffer.append(abbrev_struct_type); |
| | 1258 | // DW.AT.byte_size, DW.FORM.sdata |
| | 1259 | const abi_size = ty.abiSize(target); |
| | 1260 | try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); |
| | 1261 | // DW.AT.name, DW.FORM.string |
| | 1262 | const struct_name = try ty.nameAlloc(arena); |
| | 1263 | try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1); |
| | 1264 | dbg_info_buffer.appendSliceAssumeCapacity(struct_name); |
| | 1265 | dbg_info_buffer.appendAssumeCapacity(0); |
| | 1266 | |
| | 1267 | const struct_obj = ty.castTag(.@"struct").?.data; |
| | 1268 | if (struct_obj.layout == .Packed) { |
| | 1269 | log.debug("TODO implement .debug_info for packed structs", .{}); |
| | 1270 | break :blk; |
| | 1271 | } |
| | 1272 | |
| | 1273 | const fields = ty.structFields(); |
| | 1274 | for (fields.keys()) |field_name, field_index| { |
| | 1275 | const field = fields.get(field_name).?; |
| | 1276 | // DW.AT.member |
| | 1277 | try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); |
| | 1278 | dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); |
| | 1279 | // DW.AT.name, DW.FORM.string |
| | 1280 | dbg_info_buffer.appendSliceAssumeCapacity(field_name); |
| | 1281 | dbg_info_buffer.appendAssumeCapacity(0); |
| | 1282 | // DW.AT.type, DW.FORM.ref4 |
| | 1283 | var index = dbg_info_buffer.items.len; |
| | 1284 | try dbg_info_buffer.resize(index + 4); |
| | 1285 | try relocs.append(.{ .ty = field.ty, .reloc = @intCast(u32, index) }); |
| | 1286 | // DW.AT.data_member_location, DW.FORM.sdata |
| | 1287 | const field_off = ty.structFieldOffset(field_index, target); |
| | 1288 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); |
| | 1289 | } |
| | 1290 | |
| | 1291 | // DW.AT.structure_type delimit children |
| | 1292 | try dbg_info_buffer.append(0); |
| | 1293 | }, |
| 1166 | else => { | 1294 | else => { |
| 1167 | std.log.scoped(.compiler).err("TODO implement .debug_info for type '{}'", .{ty}); | 1295 | log.debug("TODO implement .debug_info for type '{}'", .{ty}); |
| 1168 | try dbg_info_buffer.append(abbrev_pad1); | 1296 | try dbg_info_buffer.append(abbrev_pad1); |
| 1169 | }, | 1297 | }, |
| 1170 | } | 1298 | } |
| | 1299 | |
| | 1300 | for (relocs.items) |rel| { |
| | 1301 | const gop = try dbg_info_type_relocs.getOrPut(self.base.base.allocator, rel.ty); |
| | 1302 | if (!gop.found_existing) { |
| | 1303 | gop.value_ptr.* = .{ |
| | 1304 | .off = undefined, |
| | 1305 | .relocs = .{}, |
| | 1306 | }; |
| | 1307 | } |
| | 1308 | try gop.value_ptr.relocs.append(self.base.base.allocator, rel.reloc); |
| | 1309 | } |
| 1171 | } | 1310 | } |
| 1172 | | 1311 | |
| 1173 | fn updateDeclDebugInfoAllocation( | 1312 | fn updateDeclDebugInfoAllocation( |