| ... | @@ -344,8 +344,11 @@ pub const File = struct { | ... | @@ -344,8 +344,11 @@ pub const File = struct { |
| 344 | text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = std.ArrayListUnmanaged(*TextBlock){}, | 344 | text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = std.ArrayListUnmanaged(*TextBlock){}, |
| 345 | last_text_block: ?*TextBlock = null, | 345 | last_text_block: ?*TextBlock = null, |
| 346 | | 346 | |
| 347 | first_dbg_line_file: ?*SrcFile = null, | 347 | /// A list of `SrcFn` whose Line Number Programs have surplus capacity. |
| 348 | last_dbg_line_file: ?*SrcFile = null, | 348 | /// This is the same concept as `text_block_free_list`; see those doc comments. |
| | 349 | dbg_line_fn_free_list: std.AutoHashMapUnmanaged(*SrcFn, void) = .{}, |
| | 350 | dbg_line_fn_first: ?*SrcFn = null, |
| | 351 | dbg_line_fn_last: ?*SrcFn = null, |
| 349 | | 352 | |
| 350 | /// `alloc_num / alloc_den` is the factor of padding when allocating. | 353 | /// `alloc_num / alloc_den` is the factor of padding when allocating. |
| 351 | const alloc_num = 4; | 354 | const alloc_num = 4; |
| ... | @@ -411,46 +414,20 @@ pub const File = struct { | ... | @@ -411,46 +414,20 @@ pub const File = struct { |
| 411 | }; | 414 | }; |
| 412 | | 415 | |
| 413 | pub const SrcFn = struct { | 416 | pub const SrcFn = struct { |
| 414 | /// Offset from the `SrcFile` that contains this function. | 417 | /// Offset from the beginning of the Debug Line Program header that contains this function. |
| 415 | off: u32, | 418 | off: u32, |
| 416 | /// Size of the line number program component belonging to this function, not | 419 | /// Size of the line number program component belonging to this function, not |
| 417 | /// including padding. | 420 | /// including padding. |
| 418 | len: u32, | 421 | len: u32, |
| 419 | | 422 | |
| 420 | pub const empty: SrcFn = .{ | | |
| 421 | .off = 0, | | |
| 422 | .len = 0, | | |
| 423 | }; | | |
| 424 | }; | | |
| 425 | | | |
| 426 | pub const SrcFile = struct { | | |
| 427 | /// Byte offset from the start of the Line Number Program that contains this file. | | |
| 428 | off: u32, | | |
| 429 | /// Length in bytes, not including padding, of this file component within the | | |
| 430 | /// Line Number Program that contains it. | | |
| 431 | len: u32, | | |
| 432 | | | |
| 433 | /// An ordered list of all the `SrcFn` in this file. This list is not redundant with | | |
| 434 | /// the source Decl list, for two reasons: | | |
| 435 | /// * Lazy decl analysis: some source functions do not correspond to any compiled functions. | | |
| 436 | /// * Generic functions: some source functions correspond to many compiled functions. | | |
| 437 | /// This list corresponds to the file data in the Line Number Program. When a new `SrcFn` | | |
| 438 | /// is inserted, the list must be shifted to accomodate it, and likewise the Line | | |
| 439 | /// Number Program data must be shifted within the ELF file to accomodate (if there is | | |
| 440 | /// not enough padding). | | |
| 441 | /// It is a hash map so that we can look up the index based on the `*SrcFn` and therefore | | |
| 442 | /// find the next and previous functions. | | |
| 443 | fns: std.AutoHashMapUnmanaged(*SrcFn, void), | | |
| 444 | | | |
| 445 | /// Points to the previous and next neighbors, based on the offset from .debug_line. | 423 | /// Points to the previous and next neighbors, based on the offset from .debug_line. |
| 446 | /// This can be used to find, for example, the capacity of this `SrcFile`. | 424 | /// This can be used to find, for example, the capacity of this `SrcFn`. |
| 447 | prev: ?*SrcFile, | 425 | prev: ?*SrcFn, |
| 448 | next: ?*SrcFile, | 426 | next: ?*SrcFn, |
| 449 | | 427 | |
| 450 | pub const empty: SrcFile = .{ | 428 | pub const empty: SrcFn = .{ |
| 451 | .off = 0, | 429 | .off = 0, |
| 452 | .len = 0, | 430 | .len = 0, |
| 453 | .fns = .{}, | | |
| 454 | .prev = null, | 431 | .prev = null, |
| 455 | .next = null, | 432 | .next = null, |
| 456 | }; | 433 | }; |
| ... | @@ -593,11 +570,11 @@ pub const File = struct { | ... | @@ -593,11 +570,11 @@ pub const File = struct { |
| 593 | } | 570 | } |
| 594 | | 571 | |
| 595 | fn getDebugLineProgramOff(self: Elf) u32 { | 572 | fn getDebugLineProgramOff(self: Elf) u32 { |
| 596 | return self.first_dbg_line_file.?.off; | 573 | return self.dbg_line_fn_first.?.off; |
| 597 | } | 574 | } |
| 598 | | 575 | |
| 599 | fn getDebugLineProgramEnd(self: Elf) u32 { | 576 | fn getDebugLineProgramEnd(self: Elf) u32 { |
| 600 | return self.last_dbg_line_file.?.off + self.last_dbg_line_file.?.len; | 577 | return self.dbg_line_fn_last.?.off + self.dbg_line_fn_last.?.len; |
| 601 | } | 578 | } |
| 602 | | 579 | |
| 603 | /// Returns end pos of collision, if any. | 580 | /// Returns end pos of collision, if any. |
| ... | @@ -1207,7 +1184,7 @@ pub const File = struct { | ... | @@ -1207,7 +1184,7 @@ pub const File = struct { |
| 1207 | | 1184 | |
| 1208 | // The size of this header is variable, depending on the number of directories, | 1185 | // The size of this header is variable, depending on the number of directories, |
| 1209 | // files, and padding. We have a function to compute the upper bound size, however, | 1186 | // files, and padding. We have a function to compute the upper bound size, however, |
| 1210 | // because it's needed for determining where to put the offset of the first `SrcFile`. | 1187 | // because it's needed for determining where to put the offset of the first `SrcFn`. |
| 1211 | try di_buf.ensureCapacity(self.dbgLineNeededHeaderBytes()); | 1188 | try di_buf.ensureCapacity(self.dbgLineNeededHeaderBytes()); |
| 1212 | | 1189 | |
| 1213 | // initial length - length of the .debug_line contribution for this compilation unit, | 1190 | // initial length - length of the .debug_line contribution for this compilation unit, |
| ... | @@ -1280,18 +1257,13 @@ pub const File = struct { | ... | @@ -1280,18 +1257,13 @@ pub const File = struct { |
| 1280 | }, | 1257 | }, |
| 1281 | } | 1258 | } |
| 1282 | | 1259 | |
| 1283 | // We use a NOP jmp because consumers empirically do not respect the header length field. | 1260 | // We use NOPs because consumers empirically do not respect the header length field. |
| 1284 | const after_jmp = di_buf.items.len + 6; | 1261 | if (di_buf.items.len > dbg_line_prg_off) { |
| 1285 | if (after_jmp > dbg_line_prg_off) { | | |
| 1286 | // Move the first N files to the end to make more padding for the header. | 1262 | // Move the first N files to the end to make more padding for the header. |
| 1287 | @panic("TODO: handle .debug_line header exceeding its padding"); | 1263 | @panic("TODO: handle .debug_line header exceeding its padding"); |
| 1288 | } | 1264 | } |
| 1289 | const jmp_amt = dbg_line_prg_off - after_jmp + 1; | 1265 | const jmp_amt = dbg_line_prg_off - di_buf.items.len; |
| 1290 | di_buf.appendAssumeCapacity(DW.LNS_extended_op); | 1266 | try self.pwriteWithNops(di_buf.items, jmp_amt, debug_line_sect.sh_offset); |
| 1291 | leb128.writeUnsignedFixed(4, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u28, jmp_amt)); | | |
| 1292 | di_buf.appendAssumeCapacity(DW.LNE_hi_user); | | |
| 1293 | | | |
| 1294 | try self.file.?.pwriteAll(di_buf.items, debug_line_sect.sh_offset); | | |
| 1295 | self.debug_line_header_dirty = false; | 1267 | self.debug_line_header_dirty = false; |
| 1296 | } | 1268 | } |
| 1297 | | 1269 | |
| ... | @@ -1826,6 +1798,16 @@ pub const File = struct { | ... | @@ -1826,6 +1798,16 @@ pub const File = struct { |
| 1826 | // For functions we need to add a prologue to the debug line program. | 1798 | // For functions we need to add a prologue to the debug line program. |
| 1827 | try dbg_line_buffer.ensureCapacity(26); | 1799 | try dbg_line_buffer.ensureCapacity(26); |
| 1828 | | 1800 | |
| | 1801 | const scope_file = decl.scope.cast(Module.Scope.File).?; |
| | 1802 | const tree = scope_file.contents.tree; |
| | 1803 | const file_ast_decls = tree.root_node.decls(); |
| | 1804 | // TODO Look into improving the performance here by adding a token-index-to-line |
| | 1805 | // lookup table. Currently this involves scanning over the source code for newlines. |
| | 1806 | const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?; |
| | 1807 | const block = fn_proto.body().?.castTag(.Block).?; |
| | 1808 | const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start); |
| | 1809 | const casted_line_off = @intCast(u28, line_delta); |
| | 1810 | |
| 1829 | const ptr_width_bytes = self.ptrWidthBytes(); | 1811 | const ptr_width_bytes = self.ptrWidthBytes(); |
| 1830 | dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{ | 1812 | dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{ |
| 1831 | DW.LNS_extended_op, | 1813 | DW.LNS_extended_op, |
| ... | @@ -1840,9 +1822,15 @@ pub const File = struct { | ... | @@ -1840,9 +1822,15 @@ pub const File = struct { |
| 1840 | // This is the "relocatable" relative line offset from the previous function's end curly | 1822 | // This is the "relocatable" relative line offset from the previous function's end curly |
| 1841 | // to this function's begin curly. | 1823 | // to this function's begin curly. |
| 1842 | assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len); | 1824 | assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len); |
| 1843 | // Here we allocate 4 bytes for the relocation. This field is a ULEB128, however, | 1825 | // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later. |
| 1844 | // it is possible to encode small values as still taking up 4 bytes. | 1826 | leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), casted_line_off); |
| 1845 | dbg_line_buffer.items.len += 4; | 1827 | |
| | 1828 | dbg_line_buffer.appendAssumeCapacity(DW.LNS_set_file); |
| | 1829 | assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len); |
| | 1830 | // Once we support more than one source file, this will have the ability to be more |
| | 1831 | // than one possible value. |
| | 1832 | const file_index = 1; |
| | 1833 | leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index); |
| 1846 | | 1834 | |
| 1847 | // Emit a line for the begin curly with prologue_end=false. The codegen will | 1835 | // Emit a line for the begin curly with prologue_end=false. The codegen will |
| 1848 | // do the work of setting prologue_end=true and epilogue_begin=true. | 1836 | // do the work of setting prologue_end=true and epilogue_begin=true. |
| ... | @@ -1916,14 +1904,6 @@ pub const File = struct { | ... | @@ -1916,14 +1904,6 @@ pub const File = struct { |
| 1916 | | 1904 | |
| 1917 | // If the Decl is a function, we need to update the .debug_line program. | 1905 | // If the Decl is a function, we need to update the .debug_line program. |
| 1918 | if (is_fn) { | 1906 | if (is_fn) { |
| 1919 | // For padding between functions, we terminate with `LNS_extended_op` with sub-op | | |
| 1920 | // `LNE_hi_user`, using a fixed 4-byte ULEB128 for the opcode size. This is always | | |
| 1921 | // found at the very end of the SrcFile's Line Number Program component. | | |
| 1922 | try dbg_line_buffer.ensureCapacity(dbg_line_buffer.items.len + 6); | | |
| 1923 | dbg_line_buffer.appendAssumeCapacity(DW.LNS_extended_op); | | |
| 1924 | leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), 1); | | |
| 1925 | dbg_line_buffer.appendAssumeCapacity(DW.LNE_hi_user); | | |
| 1926 | | | |
| 1927 | // Perform the relocation based on vaddr. | 1907 | // Perform the relocation based on vaddr. |
| 1928 | const target_endian = self.base.options.target.cpu.arch.endian(); | 1908 | const target_endian = self.base.options.target.cpu.arch.endian(); |
| 1929 | switch (self.ptr_width) { | 1909 | switch (self.ptr_width) { |
| ... | @@ -1937,94 +1917,53 @@ pub const File = struct { | ... | @@ -1937,94 +1917,53 @@ pub const File = struct { |
| 1937 | }, | 1917 | }, |
| 1938 | } | 1918 | } |
| 1939 | | 1919 | |
| 1940 | // Now we want to write the line offset relocation, however, first we must | 1920 | try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence }); |
| 1941 | // "plug in" the SrcFn into its parent SrcFile, so that we know what function the line | 1921 | |
| 1942 | // number is offset from. It must go in the same order as the functions are found | 1922 | // Now we have the full contents and may allocate a region to store it. |
| 1943 | // in the Zig source. When we insert a function before another one, the latter one | | |
| 1944 | // must have its line offset relocation updated. | | |
| 1945 | | 1923 | |
| 1946 | const debug_line_sect = &self.sections.items[self.debug_line_section_index.?]; | 1924 | const debug_line_sect = &self.sections.items[self.debug_line_section_index.?]; |
| 1947 | const scope_file = decl.scope.cast(Module.Scope.File).?; | | |
| 1948 | const src_file = &scope_file.link; | | |
| 1949 | const src_fn = &typed_value.val.cast(Value.Payload.Function).?.func.link; | 1925 | const src_fn = &typed_value.val.cast(Value.Payload.Function).?.func.link; |
| 1950 | var src_fn_index: usize = undefined; | 1926 | if (self.dbg_line_fn_last) |last| { |
| 1951 | if (src_file.len == 0) { | 1927 | if (src_fn.prev == null and src_fn.next == null) { |
| 1952 | // This is the first function of the SrcFile. | 1928 | // Append new function. |
| 1953 | assert(src_file.fns.entries.items.len == 0); | 1929 | src_fn.prev = last; |
| 1954 | src_fn_index = 0; | 1930 | last.next = src_fn; |
| 1955 | try src_file.fns.put(self.allocator, src_fn, {}); | 1931 | self.dbg_line_fn_last = src_fn; |
| 1956 | | 1932 | |
| 1957 | if (self.last_dbg_line_file) |last| { | 1933 | src_fn.off = last.off + (last.len * alloc_num / alloc_den); |
| 1958 | src_file.prev = last; | | |
| 1959 | self.last_dbg_line_file = src_file; | | |
| 1960 | | | |
| 1961 | // Update the previous last SrcFile's terminating NOP to skip to the start | | |
| 1962 | // of the new last SrcFile's start. | | |
| 1963 | @panic("TODO updateDecl for .debug_line: add new SrcFile: append"); | | |
| 1964 | } else { | | |
| 1965 | // This is the first file (and function) of the Line Number Program. | | |
| 1966 | self.first_dbg_line_file = src_file; | | |
| 1967 | self.last_dbg_line_file = src_file; | | |
| 1968 | | | |
| 1969 | src_fn.off = dbg_line_file_header_len; | | |
| 1970 | src_fn.len = @intCast(u32, dbg_line_buffer.items.len); | 1934 | src_fn.len = @intCast(u32, dbg_line_buffer.items.len); |
| 1971 | | 1935 | } else { |
| 1972 | src_file.off = self.dbgLineNeededHeaderBytes() * alloc_num / alloc_den; | 1936 | // Update existing function. |
| 1973 | src_file.len = src_fn.off + src_fn.len + dbg_line_file_trailer_len; | 1937 | @panic("TODO updateDecl for .debug_line: add new SrcFn: update"); |
| 1974 | | | |
| 1975 | const needed_size = src_file.off + src_file.len; | | |
| 1976 | if (needed_size > debug_line_sect.sh_size) { | | |
| 1977 | debug_line_sect.sh_offset = self.findFreeSpace(needed_size, 1); | | |
| 1978 | } | | |
| 1979 | debug_line_sect.sh_size = needed_size; | | |
| 1980 | self.shdr_table_dirty = true; // TODO look into making only the one section dirty | | |
| 1981 | self.debug_line_header_dirty = true; | | |
| 1982 | | | |
| 1983 | try self.updateDbgLineFile(src_file); | | |
| 1984 | } | 1938 | } |
| 1985 | } else { | 1939 | } else { |
| 1986 | @panic("TODO updateDecl for .debug_line: update existing SrcFile"); | 1940 | // This is the first function of the Line Number Program. |
| 1987 | //src_fn_index = @panic("TODO"); | 1941 | self.dbg_line_fn_first = src_fn; |
| | 1942 | self.dbg_line_fn_last = src_fn; |
| | 1943 | |
| | 1944 | src_fn.off = self.dbgLineNeededHeaderBytes() * alloc_num / alloc_den; |
| | 1945 | src_fn.len = @intCast(u32, dbg_line_buffer.items.len); |
| 1988 | } | 1946 | } |
| 1989 | const line_off: u28 = blk: { | | |
| 1990 | const tree = scope_file.contents.tree; | | |
| 1991 | const file_ast_decls = tree.root_node.decls(); | | |
| 1992 | // TODO Look into improving the performance here by adding a token-index-to-line | | |
| 1993 | // lookup table. Currently this involves scanning over the source code for newlines | | |
| 1994 | // (but only from the previous decl to the current one). | | |
| 1995 | if (src_fn_index == 0) { | | |
| 1996 | // Since it's the first function in the file, the line number delta is just the | | |
| 1997 | // line number of the open curly from the beginning of the file. | | |
| 1998 | const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?; | | |
| 1999 | const block = fn_proto.body().?.castTag(.Block).?; | | |
| 2000 | const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start); | | |
| 2001 | // No need to add one; this is a delta from DWARF's starting line number (1). | | |
| 2002 | break :blk @intCast(u28, line_delta); | | |
| 2003 | } else { | | |
| 2004 | const prev_src_fn = src_file.fns.entries.items[src_fn_index - 1].key; | | |
| 2005 | const mod_fn = @fieldParentPtr(Module.Fn, "link", prev_src_fn); | | |
| 2006 | const prev_fn_proto = file_ast_decls[mod_fn.owner_decl.src_index].castTag(.FnProto).?; | | |
| 2007 | const this_fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?; | | |
| 2008 | const prev_block = prev_fn_proto.body().?.castTag(.Block).?; | | |
| 2009 | const this_block = this_fn_proto.body().?.castTag(.Block).?; | | |
| 2010 | // Find the difference between prev decl end curly and this decl begin curly. | | |
| 2011 | const line_delta = std.zig.lineDelta(tree.source, | | |
| 2012 | tree.token_locs[prev_block.rbrace].start, | | |
| 2013 | tree.token_locs[this_block.lbrace].start, | | |
| 2014 | ); | | |
| 2015 | // No need to add one; this is a delta from the previous line number. | | |
| 2016 | break :blk @intCast(u28, line_delta); | | |
| 2017 | } | | |
| 2018 | }; | | |
| 2019 | | 1947 | |
| 2020 | // Here we use a ULEB128 but we write 4 bytes regardless (possibly wasting space) because | 1948 | const needed_size = src_fn.off + src_fn.len; |
| 2021 | // that is the amount of space we allocated for this field. | 1949 | if (needed_size != debug_line_sect.sh_size) { |
| 2022 | leb128.writeUnsignedFixed(4, dbg_line_buffer.items[self.getRelocDbgLineOff()..][0..4], line_off); | 1950 | if (needed_size > self.allocatedSize(debug_line_sect.sh_offset)) { |
| | 1951 | const new_offset = self.findFreeSpace(needed_size, 1); |
| | 1952 | const existing_size = src_fn.off; |
| | 1953 | const amt = try self.file.?.copyRangeAll(debug_line_sect.sh_offset, self.file.?, new_offset, existing_size); |
| | 1954 | if (amt != existing_size) return error.InputOutput; |
| | 1955 | debug_line_sect.sh_offset = new_offset; |
| | 1956 | } |
| | 1957 | debug_line_sect.sh_size = needed_size; |
| | 1958 | self.shdr_table_dirty = true; // TODO look into making only the one section dirty |
| | 1959 | self.debug_line_header_dirty = true; |
| | 1960 | } |
| | 1961 | const padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0; |
| 2023 | | 1962 | |
| 2024 | // We only have support for one compilation unit so far, so the offsets are directly | 1963 | // We only have support for one compilation unit so far, so the offsets are directly |
| 2025 | // from the .debug_line section. | 1964 | // from the .debug_line section. |
| 2026 | const file_pos = debug_line_sect.sh_offset + src_file.off + src_fn.off; | 1965 | const file_pos = debug_line_sect.sh_offset + src_fn.off; |
| 2027 | try self.file.?.pwriteAll(dbg_line_buffer.items, file_pos); | 1966 | try self.pwriteWithNops(dbg_line_buffer.items, padding_size, file_pos); |
| 2028 | } | 1967 | } |
| 2029 | | 1968 | |
| 2030 | // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated. | 1969 | // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated. |
| ... | @@ -2116,47 +2055,6 @@ pub const File = struct { | ... | @@ -2116,47 +2055,6 @@ pub const File = struct { |
| 2116 | self.global_symbols.items[sym_index].st_info = 0; | 2055 | self.global_symbols.items[sym_index].st_info = 0; |
| 2117 | } | 2056 | } |
| 2118 | | 2057 | |
| 2119 | const dbg_line_file_header_len = 5; // DW.LNS_set_file + ULEB128-fixed-4 file_index | | |
| 2120 | const dbg_line_file_trailer_len = 9; // DW.LNE_end_sequence + 6-byte terminating NOP | | |
| 2121 | | | |
| 2122 | fn updateDbgLineFile(self: *Elf, src_file: *SrcFile) !void { | | |
| 2123 | const target_endian = self.base.options.target.cpu.arch.endian(); | | |
| 2124 | const shdr = &self.sections.items[self.debug_line_section_index.?]; | | |
| 2125 | const header_off = shdr.sh_offset + src_file.off; | | |
| 2126 | { | | |
| 2127 | var header: [dbg_line_file_header_len]u8 = undefined; | | |
| 2128 | header[0] = DW.LNS_set_file; | | |
| 2129 | // Once we support more than one source file, this will have the ability to be more | | |
| 2130 | // than one possible value. | | |
| 2131 | const file_index = 1; | | |
| 2132 | leb128.writeUnsignedFixed(4, header[1..5], file_index); | | |
| 2133 | try self.file.?.pwriteAll(&header, header_off); | | |
| 2134 | } | | |
| 2135 | { | | |
| 2136 | const last_src_fn = src_file.fns.entries.items[src_file.fns.entries.items.len - 1].key; | | |
| 2137 | const trailer_off = header_off + last_src_fn.off + last_src_fn.len; | | |
| 2138 | const padding_to_next = blk: { | | |
| 2139 | if (src_file.next) |next| { | | |
| 2140 | break :blk next.off - (src_file.off + src_file.len); | | |
| 2141 | } else { | | |
| 2142 | // No need for padding after this one; we will add padding to it when a SrcFile | | |
| 2143 | // is added after it. | | |
| 2144 | break :blk 0; | | |
| 2145 | } | | |
| 2146 | }; | | |
| 2147 | var trailer: [dbg_line_file_trailer_len]u8 = undefined; | | |
| 2148 | | | |
| 2149 | trailer[0] = DW.LNS_extended_op; | | |
| 2150 | trailer[1] = 1; | | |
| 2151 | trailer[2] = DW.LNE_end_sequence; | | |
| 2152 | | | |
| 2153 | trailer[3] = DW.LNS_extended_op; | | |
| 2154 | leb128.writeUnsignedFixed(4, trailer[4..8], @intCast(u28, padding_to_next + 1)); | | |
| 2155 | trailer[8] = DW.LNE_hi_user; | | |
| 2156 | try self.file.?.pwriteAll(&trailer, trailer_off); | | |
| 2157 | } | | |
| 2158 | } | | |
| 2159 | | | |
| 2160 | fn writeProgHeader(self: *Elf, index: usize) !void { | 2058 | fn writeProgHeader(self: *Elf, index: usize) !void { |
| 2161 | const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); | 2059 | const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); |
| 2162 | const offset = self.program_headers.items[index].p_offset; | 2060 | const offset = self.program_headers.items[index].p_offset; |
| ... | @@ -2366,6 +2264,10 @@ pub const File = struct { | ... | @@ -2366,6 +2264,10 @@ pub const File = struct { |
| 2366 | return dbg_line_vaddr_reloc_index + self.ptrWidthBytes() + 1; | 2264 | return dbg_line_vaddr_reloc_index + self.ptrWidthBytes() + 1; |
| 2367 | } | 2265 | } |
| 2368 | | 2266 | |
| | 2267 | fn getRelocDbgFileIndex(self: Elf) usize { |
| | 2268 | return self.getRelocDbgLineOff() + 5; |
| | 2269 | } |
| | 2270 | |
| 2369 | fn dbgLineNeededHeaderBytes(self: Elf) u32 { | 2271 | fn dbgLineNeededHeaderBytes(self: Elf) u32 { |
| 2370 | const directory_entry_format_count = 1; | 2272 | const directory_entry_format_count = 1; |
| 2371 | const file_name_entry_format_count = 1; | 2273 | const file_name_entry_format_count = 1; |
| ... | @@ -2376,9 +2278,50 @@ pub const File = struct { | ... | @@ -2376,9 +2278,50 @@ pub const File = struct { |
| 2376 | // These are encoded as DW.FORM_string rather than DW.FORM_strp as we would like | 2278 | // These are encoded as DW.FORM_string rather than DW.FORM_strp as we would like |
| 2377 | // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly. | 2279 | // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly. |
| 2378 | self.base.options.root_pkg.root_src_dir_path.len + | 2280 | self.base.options.root_pkg.root_src_dir_path.len + |
| 2379 | self.base.options.root_pkg.root_src_path.len * 2); | 2281 | self.base.options.root_pkg.root_src_path.len); |
| 2380 | | 2282 | |
| 2381 | } | 2283 | } |
| | 2284 | |
| | 2285 | /// Writes to the file a buffer, followed by the specified number of bytes of NOPs. |
| | 2286 | /// Asserts `padding_size >= 2` and less than 126,976 bytes (if this limit is ever |
| | 2287 | /// reached, this function can be improved to make more than one pwritev call). |
| | 2288 | fn pwriteWithNops(self: *Elf, buf: []const u8, padding_size: usize, offset: usize) !void { |
| | 2289 | const page_of_nops = [1]u8{DW.LNS_negate_stmt} ** 4096; |
| | 2290 | const three_byte_nop = [3]u8{DW.LNS_advance_pc, 0b1000_0000, 0}; |
| | 2291 | var vecs: [32]std.os.iovec_const = undefined; |
| | 2292 | var vec_index: usize = 0; |
| | 2293 | vecs[vec_index] = .{ |
| | 2294 | .iov_base = buf.ptr, |
| | 2295 | .iov_len = buf.len, |
| | 2296 | }; |
| | 2297 | vec_index += 1; |
| | 2298 | var padding_left = padding_size; |
| | 2299 | if (padding_left % 2 != 0) { |
| | 2300 | vecs[vec_index] = .{ |
| | 2301 | .iov_base = &three_byte_nop, |
| | 2302 | .iov_len = three_byte_nop.len, |
| | 2303 | }; |
| | 2304 | vec_index += 1; |
| | 2305 | padding_left -= three_byte_nop.len; |
| | 2306 | } |
| | 2307 | while (padding_left > page_of_nops.len) { |
| | 2308 | vecs[vec_index] = .{ |
| | 2309 | .iov_base = &page_of_nops, |
| | 2310 | .iov_len = page_of_nops.len, |
| | 2311 | }; |
| | 2312 | vec_index += 1; |
| | 2313 | padding_left -= page_of_nops.len; |
| | 2314 | } |
| | 2315 | if (padding_left > 0) { |
| | 2316 | vecs[vec_index] = .{ |
| | 2317 | .iov_base = &page_of_nops, |
| | 2318 | .iov_len = padding_left, |
| | 2319 | }; |
| | 2320 | vec_index += 1; |
| | 2321 | } |
| | 2322 | try self.file.?.pwritevAll(vecs[0..vec_index], offset); |
| | 2323 | } |
| | 2324 | |
| 2382 | }; | 2325 | }; |
| 2383 | }; | 2326 | }; |
| 2384 | | 2327 | |