authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-03 21:01:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-03 21:01:06-07:00
logd624bf8059fa3a86a740f40a1ef763756edd91ce
treef9bd61eb3c321c269d60169abcd1f063df4d3979
parentac10841fa9321c71fa0e682521dd39872d43c132

stage2 .debug_line stepping with gdb is working


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,12 +43,19 @@ pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usi
43 return .{ .line = line, .column = column };43 return .{ .line = line, .column = column };
44}44}
4545
46pub fn lineDelta(source: []const u8, start: usize, end: usize) usize {46pub fn lineDelta(source: []const u8, start: usize, end: usize) isize {
47 var line: usize = 0;47 var line: isize = 0;
48 for (source[start..end]) |byte| switch (byte) {48 if (end >= start) {
49 '\n' => line += 1,49 for (source[start..end]) |byte| switch (byte) {
50 else => continue,50 '\n' => line += 1,
51 };51 else => continue,
52 };
53 } else {
54 for (source[end..start]) |byte| switch (byte) {
55 '\n' => line -= 1,
56 else => continue,
57 };
58 }
52 return line;59 return line;
53}60}
5461
src-self-hosted/Module.zig+3
...@@ -1484,6 +1484,9 @@ fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree {...@@ -1484,6 +1484,9 @@ fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree {
1484}1484}
14851485
1486fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {1486fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
1487 const tracy = trace(@src());
1488 defer tracy.end();
1489
1487 // We may be analyzing it for the first time, or this may be1490 // We may be analyzing it for the first time, or this may be
1488 // an incremental update. This code handles both cases.1491 // an incremental update. This code handles both cases.
1489 const tree = try self.getAstTree(root_scope);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,6 +225,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
225 prev_di_src: usize,225 prev_di_src: usize,
226 /// Relative to the beginning of `code`.226 /// Relative to the beginning of `code`.
227 prev_di_pc: usize,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 /// Used to find newlines and count line deltas.230 /// Used to find newlines and count line deltas.
229 source: []const u8,231 source: []const u8,
230 /// Byte offset within the source file of the ending curly.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,6 +422,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
420 .stack_align = undefined,422 .stack_align = undefined,
421 .prev_di_pc = 0,423 .prev_di_pc = 0,
422 .prev_di_src = lbrace_src,424 .prev_di_src = lbrace_src,
425 .prev_di_is_stmt = true,
423 .rbrace_src = rbrace_src,426 .rbrace_src = rbrace_src,
424 .source = tree.source,427 .source = tree.source,
425 };428 };
...@@ -523,7 +526,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -523,7 +526,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
523 },526 },
524 }527 }
525 // Drop them off at the rbrace.528 // Drop them off at the rbrace.
526 try self.dbgAdvancePCAndLine(self.rbrace_src);529 try self.dbgAdvancePCAndLine(self.rbrace_src, true);
527 }530 }
528531
529 fn genBody(self: *Self, body: ir.Body) InnerError!void {532 fn genBody(self: *Self, body: ir.Body) InnerError!void {
...@@ -542,15 +545,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -542,15 +545,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
542545
543 fn dbgSetPrologueEnd(self: *Self) InnerError!void {546 fn dbgSetPrologueEnd(self: *Self) InnerError!void {
544 try self.dbg_line.append(DW.LNS_set_prologue_end);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 }
547550
548 fn dbgSetEpilogueBegin(self: *Self) InnerError!void {551 fn dbgSetEpilogueBegin(self: *Self) InnerError!void {
549 try self.dbg_line.append(DW.LNS_set_epilogue_begin);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 }
552555
553 fn dbgAdvancePCAndLine(self: *Self, src: usize) InnerError!void {556 fn dbgAdvancePCAndLine(self: *Self, src: usize, is_stmt: bool) InnerError!void {
554 // TODO Look into improving the performance here by adding a token-index-to-line557 // TODO Look into improving the performance here by adding a token-index-to-line
555 // lookup table, and changing ir.Inst from storing byte offset to token. Currently558 // lookup table, and changing ir.Inst from storing byte offset to token. Currently
556 // this involves scanning over the source code for newlines559 // this involves scanning over the source code for newlines
...@@ -562,12 +565,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -562,12 +565,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
562 // TODO Look into using the DWARF special opcodes to compress this data. It lets you emit565 // TODO Look into using the DWARF special opcodes to compress this data. It lets you emit
563 // single-byte opcodes that add different numbers to both the PC and the line number566 // single-byte opcodes that add different numbers to both the PC and the line number
564 // at the same time.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 self.dbg_line.appendAssumeCapacity(DW.LNS_advance_pc);573 self.dbg_line.appendAssumeCapacity(DW.LNS_advance_pc);
567 leb128.writeULEB128(self.dbg_line.writer(), delta_pc) catch unreachable;574 leb128.writeULEB128(self.dbg_line.writer(), delta_pc) catch unreachable;
568 if (delta_line != 0) {575 if (delta_line != 0) {
569 self.dbg_line.appendAssumeCapacity(DW.LNS_advance_line);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 self.dbg_line.appendAssumeCapacity(DW.LNS_copy);579 self.dbg_line.appendAssumeCapacity(DW.LNS_copy);
573 }580 }
...@@ -1172,7 +1179,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1172,7 +1179,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1172 }1179 }
11731180
1174 fn genDbgStmt(self: *Self, inst: *ir.Inst.NoOp) !MCValue {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 return MCValue.none;1183 return MCValue.none;
1177 }1184 }
11781185
src-self-hosted/link.zig+70-31
...@@ -1263,7 +1263,7 @@ pub const File = struct {...@@ -1263,7 +1263,7 @@ pub const File = struct {
1263 @panic("TODO: handle .debug_line header exceeding its padding");1263 @panic("TODO: handle .debug_line header exceeding its padding");
1264 }1264 }
1265 const jmp_amt = dbg_line_prg_off - di_buf.items.len;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 self.debug_line_header_dirty = false;1267 self.debug_line_header_dirty = false;
1268 }1268 }
12691269
...@@ -1958,12 +1958,13 @@ pub const File = struct {...@@ -1958,12 +1958,13 @@ pub const File = struct {
1958 self.shdr_table_dirty = true; // TODO look into making only the one section dirty1958 self.shdr_table_dirty = true; // TODO look into making only the one section dirty
1959 self.debug_line_header_dirty = true;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;
19621963
1963 // We only have support for one compilation unit so far, so the offsets are directly1964 // We only have support for one compilation unit so far, so the offsets are directly
1964 // from the .debug_line section.1965 // from the .debug_line section.
1965 const file_pos = debug_line_sect.sh_offset + src_fn.off;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 }
19681969
1969 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.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,44 +2283,82 @@ pub const File = struct {
22822283
2283 }2284 }
22842285
2285 /// Writes to the file a buffer, followed by the specified number of bytes of NOPs.2286 /// Writes to the file a buffer, prefixed and suffixed by the specified number of
2286 /// Asserts `padding_size >= 2` and less than 126,976 bytes (if this limit is ever2287 /// bytes of NOPs. Asserts each padding size is at least two bytes and total padding bytes
2287 /// reached, this function can be improved to make more than one pwritev call).2288 /// are less than 126,976 bytes (if this limit is ever reached, this function can be
2288 fn pwriteWithNops(self: *Elf, buf: []const u8, padding_size: usize, offset: usize) !void {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 const page_of_nops = [1]u8{DW.LNS_negate_stmt} ** 4096;2298 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};2299 const three_byte_nop = [3]u8{DW.LNS_advance_pc, 0b1000_0000, 0};
2291 var vecs: [32]std.os.iovec_const = undefined;2300 var vecs: [32]std.os.iovec_const = undefined;
2292 var vec_index: usize = 0;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 vecs[vec_index] = .{2329 vecs[vec_index] = .{
2294 .iov_base = buf.ptr,2330 .iov_base = buf.ptr,
2295 .iov_len = buf.len,2331 .iov_len = buf.len,
2296 };2332 };
2297 vec_index += 1;2333 vec_index += 1;
2298 var padding_left = padding_size;2334
2299 if (padding_left % 2 != 0) {2335 {
2300 vecs[vec_index] = .{2336 var padding_left = next_padding_size;
2301 .iov_base = &three_byte_nop,2337 if (padding_left % 2 != 0) {
2302 .iov_len = three_byte_nop.len,2338 vecs[vec_index] = .{
2303 };2339 .iov_base = &three_byte_nop,
2304 vec_index += 1;2340 .iov_len = three_byte_nop.len,
2305 padding_left -= three_byte_nop.len;2341 };
2306 }2342 vec_index += 1;
2307 while (padding_left > page_of_nops.len) {2343 padding_left -= three_byte_nop.len;
2308 vecs[vec_index] = .{2344 }
2309 .iov_base = &page_of_nops,2345 while (padding_left > page_of_nops.len) {
2310 .iov_len = page_of_nops.len,2346 vecs[vec_index] = .{
2311 };2347 .iov_base = &page_of_nops,
2312 vec_index += 1;2348 .iov_len = page_of_nops.len,
2313 padding_left -= page_of_nops.len;2349 };
2314 }2350 vec_index += 1;
2315 if (padding_left > 0) {2351 padding_left -= page_of_nops.len;
2316 vecs[vec_index] = .{2352 }
2317 .iov_base = &page_of_nops,2353 if (padding_left > 0) {
2318 .iov_len = padding_left,2354 vecs[vec_index] = .{
2319 };2355 .iov_base = &page_of_nops,
2320 vec_index += 1;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 }
23242363
2325 };2364 };