Skip to content

Conversation

@mlugg
Copy link
Member

@mlugg mlugg commented Jan 5, 2025

No description provided.

@jacobly0
Copy link
Member

jacobly0 commented Jan 5, 2025

Using the change_line_number incremental test as a demonstration, the source code of the initial incremental update is:

const std = @import("std");
pub fn main() !void {
    try std.io.getStdOut().writeAll("foo\n");
}

After which we have a binary containing this debug info for main:

0x0000002d:     DW_TAG_subprogram
                  DW_AT_ZIG_parent      (0x0000000000000072)
                  DW_AT_decl_line       (2)
                  DW_AT_decl_column     (1)
                  DW_AT_accessibility   (DW_ACCESS_public)
                  DW_AT_name    ("main")
                  DW_AT_linkage_name    ("main.main")
                  DW_AT_type    (0x0000000000094be8 "std::@typeInfo(@typeInfo(@TypeOf(main.main)).@"fn".return_type.?).error_union.error_set!void")
                  DW_AT_low_pc  (0x0000000001014021)
                  DW_AT_high_pc (0x0000000001014090)
                  DW_AT_alignment       (16)
                  DW_AT_external        (0x00)
                  DW_AT_noreturn        (0x00)

0x00000053:       DW_TAG_lexical_block
                    DW_AT_low_pc        (0x0000000001014075)
                    DW_AT_high_pc       (0x000000000101407a)

0x00000060:       NULL

Which when debugged with a breakpoint on main.main displays:

* thread #1, name = 'main', stop reason = breakpoint 1.1
    frame #0: 0x0000000001014032 main`main.main at main.zig:3:25
   1   	const std = @import("std");
   2   	pub fn main() !void {
-> 3   	   try std.io.getStdOut().writeAll("foo\n");
   4   	}

The source code for the second incremental update is:

const std = @import("std");

pub fn main() !void {
    try std.io.getStdOut().writeAll("foo\n");
}

Which calls the following exhaustive list of dwarf update functions:

info: emit_digest included stderr:
debug(dwarf): updateLineNumber(main.zig:3:1 %4 = main)

Which directly modifies the debug info in the binary for main to:

0x0000002d:     DW_TAG_subprogram
                  DW_AT_ZIG_parent      (0x0000000000000072)
                  DW_AT_decl_line       (3)
                  DW_AT_decl_column     (1)
                  DW_AT_accessibility   (DW_ACCESS_public)
                  DW_AT_name    ("main")
                  DW_AT_linkage_name    ("main.main")
                  DW_AT_type    (0x0000000000094be8 "std::@typeInfo(@typeInfo(@TypeOf(main.main)).@"fn".return_type.?).error_union.error_set!void")
                  DW_AT_low_pc  (0x0000000001014021)
                  DW_AT_high_pc (0x0000000001014090)
                  DW_AT_alignment       (16)
                  DW_AT_external        (0x00)
                  DW_AT_noreturn        (0x00)

0x00000053:       DW_TAG_lexical_block
                    DW_AT_low_pc        (0x0000000001014075)
                    DW_AT_high_pc       (0x000000000101407a)

0x00000060:       NULL

Which when debugged again displays:

* thread #1, name = 'main', stop reason = breakpoint 1.1
    frame #0: 0x0000000001014032 main`main.main at main.zig:4:25
   1   	const std = @import("std");
   2   	
   3   	pub fn main() !void {
-> 4   	   try std.io.getStdOut().writeAll("foo\n");
   5   	}

@jacobly0
Copy link
Member

jacobly0 commented Jan 5, 2025

Using the change_generic_line_number incremental test as a demonstration, the source code of the initial incremental update is:

const std = @import("std");
fn Printer(message: []const u8) type {
    return struct {
        fn print() !void {
            try std.io.getStdOut().writeAll(message);
        }
    };
}
pub fn main() !void {
    try Printer("foo\n").print();
    try Printer("bar\n").print();
}

After which we have a binary containing this debug info for print:

0x0000002d:     DW_TAG_subprogram
                  DW_AT_ZIG_parent      (0x0000000000000111)
                  DW_AT_decl_line       (4)
                  DW_AT_decl_column     (9)
                  DW_AT_accessibility   (DW_ACCESS_private)
                  DW_AT_name    ("print")
                  DW_AT_declaration     (true)

0x00000041:     DW_TAG_subprogram
                  DW_AT_ZIG_parent      (0x000000000000013a)
                  DW_AT_abstract_origin (0x000000000000002d "print")
                  DW_AT_linkage_name    ("main.Printer(\"foo\\n\"[0..4]).print")
                  DW_AT_type    (0x0000000000094d89 "std::@typeInfo(@typeInfo(@TypeOf(main.Printer("foo\n"[0..4]).print)).@"fn".return_type.?).error_union.error_set!void")
                  DW_AT_low_pc  (0x0000000001014021)
                  DW_AT_high_pc (0x0000000001014090)
                  DW_AT_alignment       (16)
                  DW_AT_external        (0x00)
                  DW_AT_noreturn        (0x00)

0x00000061:       DW_TAG_lexical_block
                    DW_AT_low_pc        (0x0000000001014075)
                    DW_AT_high_pc       (0x000000000101407a)

0x0000006e:       NULL

0x0000007e:     DW_TAG_subprogram
                  DW_AT_ZIG_parent      (0x000000000000015c)
                  DW_AT_abstract_origin (0x000000000000002d "print")
                  DW_AT_linkage_name    ("main.Printer(\"bar\\n\"[0..4]).print")
                  DW_AT_type    (0x0000000000094e7d "std::@typeInfo(@typeInfo(@TypeOf(main.Printer("bar\n"[0..4]).print)).@"fn".return_type.?).error_union.error_set!void")
                  DW_AT_low_pc  (0x00000000010140b5)
                  DW_AT_high_pc (0x0000000001014124)
                  DW_AT_alignment       (16)
                  DW_AT_external        (0x00)
                  DW_AT_noreturn        (0x00)

0x0000009e:       DW_TAG_lexical_block
                    DW_AT_low_pc        (0x0000000001014109)
                    DW_AT_high_pc       (0x000000000101410e)

0x000000ab:       NULL

Which when debugged displays:

* thread #1, name = 'main', stop reason = breakpoint 1.1
    frame #0: 0x000000000101415a main`main.main at main.zig:10:31
   7   	   };
   8   	}
   9   	pub fn main() !void {
-> 10  	   try Printer("foo\n").print();
   11  	   try Printer("bar\n").print();
   12  	}
(lldb) s
Process 366773 stopped
* thread #1, name = 'main', stop reason = step in
    frame #0: 0x0000000001014032 main`main.Printer("foo\n"[0..4]).print at main.zig:5:33
   2   	fn Printer(message: []const u8) type {
   3   	   return struct {
   4   	       fn print() !void {
-> 5   	           try std.io.getStdOut().writeAll(message);
   6   	       }
   7   	   };
   8   	}
(lldb) n
foo
Process 366773 stopped
* thread #1, name = 'main', stop reason = step over
    frame #0: 0x000000000101415f main`main.main at main.zig:10:31
   7   	   };
   8   	}
   9   	pub fn main() !void {
-> 10  	   try Printer("foo\n").print();
   11  	   try Printer("bar\n").print();
   12  	}
(lldb) s
Process 366773 stopped
* thread #1, name = 'main', stop reason = step in
    frame #0: 0x0000000001014177 main`main.main at main.zig:11:31
   8   	}
   9   	pub fn main() !void {
   10  	   try Printer("foo\n").print();
-> 11  	   try Printer("bar\n").print();
   12  	}
(lldb) s
Process 366773 stopped
* thread #1, name = 'main', stop reason = step in
    frame #0: 0x00000000010140c6 main`main.Printer("bar\n"[0..4]).print at main.zig:5:33
   2   	fn Printer(message: []const u8) type {
   3   	   return struct {
   4   	       fn print() !void {
-> 5   	           try std.io.getStdOut().writeAll(message);
   6   	       }
   7   	   };
   8   	}
(lldb) n
bar
Process 366773 stopped
* thread #1, name = 'main', stop reason = step over
    frame #0: 0x000000000101417c main`main.main at main.zig:11:31
   8   	}
   9   	pub fn main() !void {
   10  	   try Printer("foo\n").print();
-> 11  	   try Printer("bar\n").print();
   12  	}

The source code for the second incremental update is:

const std = @import("std");

fn Printer(message: []const u8) type {
    return struct {
        fn print() !void {
            try std.io.getStdOut().writeAll(message);
        }
    };
}
pub fn main() !void {
    try Printer("foo\n").print();
    try Printer("bar\n").print();
}

Which calls the following exhaustive list of dwarf update functions:

debug(dwarf): updateLineNumber(main.zig:3:1 %4 = Printer)
debug(dwarf): updateLineNumber(main.zig:10:1 %37 = main)
debug(dwarf): updateLineNumber(main.zig:5:9 %10 = print)

Which directly modifies the debug info in the binary for the generic origin of print to:

0x0000002d:     DW_TAG_subprogram
                  DW_AT_ZIG_parent      (0x0000000000000111)
                  DW_AT_decl_line       (5)
                  DW_AT_decl_column     (9)
                  DW_AT_accessibility   (DW_ACCESS_private)
                  DW_AT_name    ("print")
                  DW_AT_declaration     (true)

0x00000041:     DW_TAG_subprogram
                  DW_AT_ZIG_parent      (0x000000000000013a)
                  DW_AT_abstract_origin (0x000000000000002d "print")
                  DW_AT_linkage_name    ("main.Printer(\"foo\\n\"[0..4]).print")
                  DW_AT_type    (0x0000000000094d89 "std::@typeInfo(@typeInfo(@TypeOf(main.Printer("foo\n"[0..4]).print)).@"fn".return_type.?).error_union.error_set!void")
                  DW_AT_low_pc  (0x0000000001014021)
                  DW_AT_high_pc (0x0000000001014090)
                  DW_AT_alignment       (16)
                  DW_AT_external        (0x00)
                  DW_AT_noreturn        (0x00)

0x00000061:       DW_TAG_lexical_block
                    DW_AT_low_pc        (0x0000000001014075)
                    DW_AT_high_pc       (0x000000000101407a)

0x0000006e:       NULL

0x0000007e:     DW_TAG_subprogram
                  DW_AT_ZIG_parent      (0x000000000000015c)
                  DW_AT_abstract_origin (0x000000000000002d "print")
                  DW_AT_linkage_name    ("main.Printer(\"bar\\n\"[0..4]).print")
                  DW_AT_type    (0x0000000000094e7d "std::@typeInfo(@typeInfo(@TypeOf(main.Printer("bar\n"[0..4]).print)).@"fn".return_type.?).error_union.error_set!void")
                  DW_AT_low_pc  (0x00000000010140b5)
                  DW_AT_high_pc (0x0000000001014124)
                  DW_AT_alignment       (16)
                  DW_AT_external        (0x00)
                  DW_AT_noreturn        (0x00)

0x0000009e:       DW_TAG_lexical_block
                    DW_AT_low_pc        (0x0000000001014109)
                    DW_AT_high_pc       (0x000000000101410e)

0x000000ab:       NULL

Which when debugged again displays:

* thread #1, name = 'main', stop reason = breakpoint 1.1
    frame #0: 0x000000000101415a main`main.main at main.zig:11:31
   8   	   };
   9   	}
   10  	pub fn main() !void {
-> 11  	   try Printer("foo\n").print();
   12  	   try Printer("bar\n").print();
   13  	}
(lldb) s
Process 366903 stopped
* thread #1, name = 'main', stop reason = step in
    frame #0: 0x0000000001014032 main`main.Printer("foo\n"[0..4]).print at main.zig:6:33
   3   	fn Printer(message: []const u8) type {
   4   	   return struct {
   5   	       fn print() !void {
-> 6   	           try std.io.getStdOut().writeAll(message);
   7   	       }
   8   	   };
   9   	}
(lldb) n
foo
Process 366903 stopped
* thread #1, name = 'main', stop reason = step over
    frame #0: 0x000000000101415f main`main.main at main.zig:11:31
   8   	   };
   9   	}
   10  	pub fn main() !void {
-> 11  	   try Printer("foo\n").print();
   12  	   try Printer("bar\n").print();
   13  	}
(lldb) s
Process 366903 stopped
* thread #1, name = 'main', stop reason = step in
    frame #0: 0x0000000001014177 main`main.main at main.zig:12:31
   9   	}
   10  	pub fn main() !void {
   11  	   try Printer("foo\n").print();
-> 12  	   try Printer("bar\n").print();
   13  	}
(lldb) s
Process 366903 stopped
* thread #1, name = 'main', stop reason = step in
    frame #0: 0x00000000010140c6 main`main.Printer("bar\n"[0..4]).print at main.zig:6:33
   3   	fn Printer(message: []const u8) type {
   4   	   return struct {
   5   	       fn print() !void {
-> 6   	           try std.io.getStdOut().writeAll(message);
   7   	       }
   8   	   };
   9   	}
(lldb) n
bar
Process 366903 stopped
* thread #1, name = 'main', stop reason = step over
    frame #0: 0x000000000101417c main`main.main at main.zig:12:31
   9   	}
   10  	pub fn main() !void {
   11  	   try Printer("foo\n").print();
-> 12  	   try Printer("bar\n").print();
   13  	}

@mlugg mlugg merged commit 41786fa into ziglang:master Jan 5, 2025
10 checks passed
@mlugg mlugg deleted the line-number-incremental branch May 18, 2025 20:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants