| author | |
| committer | |
| log | d624bf8059fa3a86a740f40a1ef763756edd91ce |
| tree | f9bd61eb3c321c269d60169abcd1f063df4d3979 |
| parent | ac10841fa9321c71fa0e682521dd39872d43c132 |
4 files changed, 100 insertions(+), 44 deletions(-)
lib/std/zig.zig+13-6| ... | ... | @@ -43,12 +43,19 @@ pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usi |
| 43 | 43 | return .{ .line = line, .column = column }; |
| 44 | 44 | } |
| 45 | 45 | |
| 46 | pub fn lineDelta(source: []const u8, start: usize, end: usize) usize { | |
| 47 | var line: usize = 0; | |
| 48 | for (source[start..end]) |byte| switch (byte) { | |
| 49 | '\n' => line += 1, | |
| 50 | else => continue, | |
| 51 | }; | |
| 46 | pub fn lineDelta(source: []const u8, start: usize, end: usize) isize { | |
| 47 | var line: isize = 0; | |
| 48 | if (end >= start) { | |
| 49 | for (source[start..end]) |byte| switch (byte) { | |
| 50 | '\n' => line += 1, | |
| 51 | else => continue, | |
| 52 | }; | |
| 53 | } else { | |
| 54 | for (source[end..start]) |byte| switch (byte) { | |
| 55 | '\n' => line -= 1, | |
| 56 | else => continue, | |
| 57 | }; | |
| 58 | } | |
| 52 | 59 | return line; |
| 53 | 60 | } |
| 54 | 61 |
src-self-hosted/Module.zig+3| ... | ... | @@ -1484,6 +1484,9 @@ fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree { |
| 1484 | 1484 | } |
| 1485 | 1485 | |
| 1486 | 1486 | fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { |
| 1487 | const tracy = trace(@src()); | |
| 1488 | defer tracy.end(); | |
| 1489 | ||
| 1487 | 1490 | // We may be analyzing it for the first time, or this may be |
| 1488 | 1491 | // an incremental update. This code handles both cases. |
| 1489 | 1492 | const tree = try self.getAstTree(root_scope); |
src-self-hosted/codegen.zig+14-7| ... | ... | @@ -225,6 +225,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 225 | 225 | prev_di_src: usize, |
| 226 | 226 | /// Relative to the beginning of `code`. |
| 227 | 227 | prev_di_pc: usize, |
| 228 | /// The is_stmt register value, used to avoid redundant LNS_negate_stmt ops. | |
| 229 | prev_di_is_stmt: bool, | |
| 228 | 230 | /// Used to find newlines and count line deltas. |
| 229 | 231 | source: []const u8, |
| 230 | 232 | /// Byte offset within the source file of the ending curly. |
| ... | ... | @@ -420,6 +422,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 420 | 422 | .stack_align = undefined, |
| 421 | 423 | .prev_di_pc = 0, |
| 422 | 424 | .prev_di_src = lbrace_src, |
| 425 | .prev_di_is_stmt = true, | |
| 423 | 426 | .rbrace_src = rbrace_src, |
| 424 | 427 | .source = tree.source, |
| 425 | 428 | }; |
| ... | ... | @@ -523,7 +526,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 523 | 526 | }, |
| 524 | 527 | } |
| 525 | 528 | // Drop them off at the rbrace. |
| 526 | try self.dbgAdvancePCAndLine(self.rbrace_src); | |
| 529 | try self.dbgAdvancePCAndLine(self.rbrace_src, true); | |
| 527 | 530 | } |
| 528 | 531 | |
| 529 | 532 | fn genBody(self: *Self, body: ir.Body) InnerError!void { |
| ... | ... | @@ -542,15 +545,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 542 | 545 | |
| 543 | 546 | fn dbgSetPrologueEnd(self: *Self) InnerError!void { |
| 544 | 547 | try self.dbg_line.append(DW.LNS_set_prologue_end); |
| 545 | try self.dbgAdvancePCAndLine(self.prev_di_src); | |
| 548 | try self.dbgAdvancePCAndLine(self.prev_di_src, true); | |
| 546 | 549 | } |
| 547 | 550 | |
| 548 | 551 | fn dbgSetEpilogueBegin(self: *Self) InnerError!void { |
| 549 | 552 | try self.dbg_line.append(DW.LNS_set_epilogue_begin); |
| 550 | try self.dbgAdvancePCAndLine(self.prev_di_src); | |
| 553 | try self.dbgAdvancePCAndLine(self.prev_di_src, true); | |
| 551 | 554 | } |
| 552 | 555 | |
| 553 | fn dbgAdvancePCAndLine(self: *Self, src: usize) InnerError!void { | |
| 556 | fn dbgAdvancePCAndLine(self: *Self, src: usize, is_stmt: bool) InnerError!void { | |
| 554 | 557 | // TODO Look into improving the performance here by adding a token-index-to-line |
| 555 | 558 | // lookup table, and changing ir.Inst from storing byte offset to token. Currently |
| 556 | 559 | // this involves scanning over the source code for newlines |
| ... | ... | @@ -562,12 +565,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 562 | 565 | // TODO Look into using the DWARF special opcodes to compress this data. It lets you emit |
| 563 | 566 | // single-byte opcodes that add different numbers to both the PC and the line number |
| 564 | 567 | // at the same time. |
| 565 | try self.dbg_line.ensureCapacity(self.dbg_line.items.len + 11); | |
| 568 | try self.dbg_line.ensureCapacity(self.dbg_line.items.len + 12); | |
| 569 | if (self.prev_di_is_stmt != is_stmt) { | |
| 570 | self.dbg_line.appendAssumeCapacity(DW.LNS_negate_stmt); | |
| 571 | self.prev_di_is_stmt = is_stmt; | |
| 572 | } | |
| 566 | 573 | self.dbg_line.appendAssumeCapacity(DW.LNS_advance_pc); |
| 567 | 574 | leb128.writeULEB128(self.dbg_line.writer(), delta_pc) catch unreachable; |
| 568 | 575 | if (delta_line != 0) { |
| 569 | 576 | self.dbg_line.appendAssumeCapacity(DW.LNS_advance_line); |
| 570 | leb128.writeULEB128(self.dbg_line.writer(), delta_line) catch unreachable; | |
| 577 | leb128.writeILEB128(self.dbg_line.writer(), delta_line) catch unreachable; | |
| 571 | 578 | } |
| 572 | 579 | self.dbg_line.appendAssumeCapacity(DW.LNS_copy); |
| 573 | 580 | } |
| ... | ... | @@ -1172,7 +1179,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1172 | 1179 | } |
| 1173 | 1180 | |
| 1174 | 1181 | fn genDbgStmt(self: *Self, inst: *ir.Inst.NoOp) !MCValue { |
| 1175 | try self.dbgAdvancePCAndLine(inst.base.src); | |
| 1182 | try self.dbgAdvancePCAndLine(inst.base.src, true); | |
| 1176 | 1183 | return MCValue.none; |
| 1177 | 1184 | } |
| 1178 | 1185 |
src-self-hosted/link.zig+70-31| ... | ... | @@ -1263,7 +1263,7 @@ pub const File = struct { |
| 1263 | 1263 | @panic("TODO: handle .debug_line header exceeding its padding"); |
| 1264 | 1264 | } |
| 1265 | 1265 | const jmp_amt = dbg_line_prg_off - di_buf.items.len; |
| 1266 | try self.pwriteWithNops(di_buf.items, jmp_amt, debug_line_sect.sh_offset); | |
| 1266 | try self.pwriteWithNops(0, di_buf.items, jmp_amt, debug_line_sect.sh_offset); | |
| 1267 | 1267 | self.debug_line_header_dirty = false; |
| 1268 | 1268 | } |
| 1269 | 1269 | |
| ... | ... | @@ -1958,12 +1958,13 @@ pub const File = struct { |
| 1958 | 1958 | self.shdr_table_dirty = true; // TODO look into making only the one section dirty |
| 1959 | 1959 | self.debug_line_header_dirty = true; |
| 1960 | 1960 | } |
| 1961 | const padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0; | |
| 1961 | const prev_padding_size: u32 = if (src_fn.prev) |prev| src_fn.off - (prev.off + prev.len) else 0; | |
| 1962 | const next_padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0; | |
| 1962 | 1963 | |
| 1963 | 1964 | // We only have support for one compilation unit so far, so the offsets are directly |
| 1964 | 1965 | // from the .debug_line section. |
| 1965 | 1966 | const file_pos = debug_line_sect.sh_offset + src_fn.off; |
| 1966 | try self.pwriteWithNops(dbg_line_buffer.items, padding_size, file_pos); | |
| 1967 | try self.pwriteWithNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos); | |
| 1967 | 1968 | } |
| 1968 | 1969 | |
| 1969 | 1970 | // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated. |
| ... | ... | @@ -2282,44 +2283,82 @@ pub const File = struct { |
| 2282 | 2283 | |
| 2283 | 2284 | } |
| 2284 | 2285 | |
| 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 { | |
| 2286 | /// Writes to the file a buffer, prefixed and suffixed by the specified number of | |
| 2287 | /// bytes of NOPs. Asserts each padding size is at least two bytes and total padding bytes | |
| 2288 | /// are less than 126,976 bytes (if this limit is ever reached, this function can be | |
| 2289 | /// improved to make more than one pwritev call, or the limit can be raised by a fixed | |
| 2290 | /// amount by increasing the length of `vecs`). | |
| 2291 | fn pwriteWithNops( | |
| 2292 | self: *Elf, | |
| 2293 | prev_padding_size: usize, | |
| 2294 | buf: []const u8, | |
| 2295 | next_padding_size: usize, | |
| 2296 | offset: usize, | |
| 2297 | ) !void { | |
| 2289 | 2298 | const page_of_nops = [1]u8{DW.LNS_negate_stmt} ** 4096; |
| 2290 | 2299 | const three_byte_nop = [3]u8{DW.LNS_advance_pc, 0b1000_0000, 0}; |
| 2291 | 2300 | var vecs: [32]std.os.iovec_const = undefined; |
| 2292 | 2301 | var vec_index: usize = 0; |
| 2302 | { | |
| 2303 | var padding_left = prev_padding_size; | |
| 2304 | if (padding_left % 2 != 0) { | |
| 2305 | vecs[vec_index] = .{ | |
| 2306 | .iov_base = &three_byte_nop, | |
| 2307 | .iov_len = three_byte_nop.len, | |
| 2308 | }; | |
| 2309 | vec_index += 1; | |
| 2310 | padding_left -= three_byte_nop.len; | |
| 2311 | } | |
| 2312 | while (padding_left > page_of_nops.len) { | |
| 2313 | vecs[vec_index] = .{ | |
| 2314 | .iov_base = &page_of_nops, | |
| 2315 | .iov_len = page_of_nops.len, | |
| 2316 | }; | |
| 2317 | vec_index += 1; | |
| 2318 | padding_left -= page_of_nops.len; | |
| 2319 | } | |
| 2320 | if (padding_left > 0) { | |
| 2321 | vecs[vec_index] = .{ | |
| 2322 | .iov_base = &page_of_nops, | |
| 2323 | .iov_len = padding_left, | |
| 2324 | }; | |
| 2325 | vec_index += 1; | |
| 2326 | } | |
| 2327 | } | |
| 2328 | ||
| 2293 | 2329 | vecs[vec_index] = .{ |
| 2294 | 2330 | .iov_base = buf.ptr, |
| 2295 | 2331 | .iov_len = buf.len, |
| 2296 | 2332 | }; |
| 2297 | 2333 | 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; | |
| 2334 | ||
| 2335 | { | |
| 2336 | var padding_left = next_padding_size; | |
| 2337 | if (padding_left % 2 != 0) { | |
| 2338 | vecs[vec_index] = .{ | |
| 2339 | .iov_base = &three_byte_nop, | |
| 2340 | .iov_len = three_byte_nop.len, | |
| 2341 | }; | |
| 2342 | vec_index += 1; | |
| 2343 | padding_left -= three_byte_nop.len; | |
| 2344 | } | |
| 2345 | while (padding_left > page_of_nops.len) { | |
| 2346 | vecs[vec_index] = .{ | |
| 2347 | .iov_base = &page_of_nops, | |
| 2348 | .iov_len = page_of_nops.len, | |
| 2349 | }; | |
| 2350 | vec_index += 1; | |
| 2351 | padding_left -= page_of_nops.len; | |
| 2352 | } | |
| 2353 | if (padding_left > 0) { | |
| 2354 | vecs[vec_index] = .{ | |
| 2355 | .iov_base = &page_of_nops, | |
| 2356 | .iov_len = padding_left, | |
| 2357 | }; | |
| 2358 | vec_index += 1; | |
| 2359 | } | |
| 2321 | 2360 | } |
| 2322 | try self.file.?.pwritevAll(vecs[0..vec_index], offset); | |
| 2361 | try self.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size); | |
| 2323 | 2362 | } |
| 2324 | 2363 | |
| 2325 | 2364 | }; |