authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-11 19:02:21-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-11 19:02:21-07:00
loga2a5cea286e87356b32a304853233e47a9fe70a7
tree46e1c3dc67751e6c52b1bc2cdb9b5fbb65c0d931
parent7612931c8020592a8c78b15339c696590579e03c

stage2: emit DW_TAG_subprogram for function Decls

these have the virtual address range, return type, and name.

2 files changed, 163 insertions(+), 13 deletions(-)

src-self-hosted/link.zig+162-12
...@@ -14,6 +14,7 @@ const trace = @import("tracy.zig").trace;...@@ -14,6 +14,7 @@ const trace = @import("tracy.zig").trace;
14const leb128 = std.debug.leb;14const leb128 = std.debug.leb;
15const Package = @import("Package.zig");15const Package = @import("Package.zig");
16const Value = @import("value.zig").Value;16const Value = @import("value.zig").Value;
17const Type = @import("type.zig").Type;
1718
18// TODO Turn back on zig fmt when https://github.com/ziglang/zig/issues/5948 is implemented.19// TODO Turn back on zig fmt when https://github.com/ziglang/zig/issues/5948 is implemented.
19// zig fmt: off20// zig fmt: off
...@@ -985,6 +986,12 @@ pub const File = struct {...@@ -985,6 +986,12 @@ pub const File = struct {
985 }986 }
986 }987 }
987988
989 pub const abbrev_compile_unit = 1;
990 pub const abbrev_subprogram = 2;
991 pub const abbrev_subprogram_retvoid = 3;
992 pub const abbrev_base_type = 4;
993 pub const abbrev_pad1 = 5;
994
988 /// Commit pending changes and write headers.995 /// Commit pending changes and write headers.
989 pub fn flush(self: *Elf) !void {996 pub fn flush(self: *Elf) !void {
990 const target_endian = self.base.options.target.cpu.arch.endian();997 const target_endian = self.base.options.target.cpu.arch.endian();
...@@ -1005,7 +1012,7 @@ pub const File = struct {...@@ -1005,7 +1012,7 @@ pub const File = struct {
1005 // These are LEB encoded but since the values are all less than 1271012 // These are LEB encoded but since the values are all less than 127
1006 // we can simply append these bytes.1013 // we can simply append these bytes.
1007 const abbrev_buf = [_]u8{1014 const abbrev_buf = [_]u8{
1008 1, DW.TAG_compile_unit, DW.CHILDREN_no, // header1015 abbrev_compile_unit, DW.TAG_compile_unit, DW.CHILDREN_yes, // header
1009 DW.AT_stmt_list, DW.FORM_sec_offset,1016 DW.AT_stmt_list, DW.FORM_sec_offset,
1010 DW.AT_low_pc , DW.FORM_addr,1017 DW.AT_low_pc , DW.FORM_addr,
1011 DW.AT_high_pc , DW.FORM_addr,1018 DW.AT_high_pc , DW.FORM_addr,
...@@ -1015,6 +1022,28 @@ pub const File = struct {...@@ -1015,6 +1022,28 @@ pub const File = struct {
1015 DW.AT_language , DW.FORM_data2,1022 DW.AT_language , DW.FORM_data2,
1016 0, 0, // table sentinel1023 0, 0, // table sentinel
10171024
1025 abbrev_subprogram, DW.TAG_subprogram, DW.CHILDREN_yes, // header
1026 DW.AT_low_pc , DW.FORM_addr,
1027 DW.AT_high_pc , DW.FORM_data4,
1028 DW.AT_type , DW.FORM_ref4,
1029 DW.AT_name , DW.FORM_string,
1030 0, 0, // table sentinel
1031
1032 abbrev_subprogram_retvoid, DW.TAG_subprogram, DW.CHILDREN_yes, // header
1033 DW.AT_low_pc , DW.FORM_addr,
1034 DW.AT_high_pc , DW.FORM_data4,
1035 DW.AT_name , DW.FORM_string,
1036 0, 0, // table sentinel
1037
1038 abbrev_base_type, DW.TAG_base_type, DW.CHILDREN_no, // header
1039 DW.AT_encoding , DW.FORM_data1,
1040 DW.AT_byte_size, DW.FORM_data1,
1041 DW.AT_name , DW.FORM_string,
1042 0, 0, // table sentinel
1043
1044 abbrev_pad1, DW.TAG_unspecified_type, DW.CHILDREN_no, // header
1045 0, 0, // table sentinel
1046
1018 0, 0, 0, // section sentinel1047 0, 0, 0, // section sentinel
1019 };1048 };
10201049
...@@ -1092,7 +1121,7 @@ pub const File = struct {...@@ -1092,7 +1121,7 @@ pub const File = struct {
1092 const low_pc = text_phdr.p_vaddr;1121 const low_pc = text_phdr.p_vaddr;
1093 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;1122 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
10941123
1095 di_buf.appendAssumeCapacity(1); // abbrev tag, matching the value from the abbrev table header1124 di_buf.appendAssumeCapacity(abbrev_compile_unit);
1096 self.writeDwarfAddrAssumeCapacity(&di_buf, 0); // DW.AT_stmt_list, DW.FORM_sec_offset1125 self.writeDwarfAddrAssumeCapacity(&di_buf, 0); // DW.AT_stmt_list, DW.FORM_sec_offset
1097 self.writeDwarfAddrAssumeCapacity(&di_buf, low_pc);1126 self.writeDwarfAddrAssumeCapacity(&di_buf, low_pc);
1098 self.writeDwarfAddrAssumeCapacity(&di_buf, high_pc);1127 self.writeDwarfAddrAssumeCapacity(&di_buf, high_pc);
...@@ -1834,6 +1863,7 @@ pub const File = struct {...@@ -1834,6 +1863,7 @@ pub const File = struct {
1834 .Fn => true,1863 .Fn => true,
1835 else => false,1864 else => false,
1836 };1865 };
1866 var fn_ret_has_bits: bool = undefined;
1837 if (is_fn) {1867 if (is_fn) {
1838 // For functions we need to add a prologue to the debug line program.1868 // For functions we need to add a prologue to the debug line program.
1839 try dbg_line_buffer.ensureCapacity(26);1869 try dbg_line_buffer.ensureCapacity(26);
...@@ -1884,6 +1914,31 @@ pub const File = struct {...@@ -1884,6 +1914,31 @@ pub const File = struct {
1884 // Emit a line for the begin curly with prologue_end=false. The codegen will1914 // Emit a line for the begin curly with prologue_end=false. The codegen will
1885 // do the work of setting prologue_end=true and epilogue_begin=true.1915 // do the work of setting prologue_end=true and epilogue_begin=true.
1886 dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy);1916 dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy);
1917
1918 // .debug_info subprogram
1919 const decl_name_with_null = decl.name[0..mem.lenZ(decl.name) + 1];
1920 try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 25 + decl_name_with_null.len);
1921
1922 fn_ret_has_bits = typed_value.ty.fnReturnType().hasCodeGenBits();
1923 if (fn_ret_has_bits) {
1924 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
1925 } else {
1926 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram_retvoid);
1927 }
1928 // These get overwritten after generating the machine code. These values are
1929 // "relocations" and have to be in this fixed place so that functions can be
1930 // moved in virtual address space.
1931 assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len);
1932 dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT_low_pc, DW.FORM_addr
1933 assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len);
1934 dbg_info_buffer.items.len += 4; // DW.AT_high_pc, DW.FORM_data4
1935 if (fn_ret_has_bits) {
1936 assert(self.getRelocDbgInfoSubprogramRetType() == dbg_info_buffer.items.len);
1937 dbg_info_buffer.items.len += 4; // DW.AT_type, DW.FORM_ref4
1938 }
1939 dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT_name, DW.FORM_string
1940 } else {
1941 // TODO implement .debug_info for global variables
1887 }1942 }
1888 const res = try codegen.generateSymbol(self, decl.src(), typed_value, &code_buffer, &dbg_line_buffer, &dbg_info_buffer);1943 const res = try codegen.generateSymbol(self, decl.src(), typed_value, &code_buffer, &dbg_line_buffer, &dbg_info_buffer);
1889 const code = switch (res) {1944 const code = switch (res) {
...@@ -1951,22 +2006,40 @@ pub const File = struct {...@@ -1951,22 +2006,40 @@ pub const File = struct {
1951 const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset;2006 const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset;
1952 try self.base.file.?.pwriteAll(code, file_offset);2007 try self.base.file.?.pwriteAll(code, file_offset);
19532008
1954 try self.updateDeclDebugInfo(module, decl, dbg_info_buffer.items);2009 const target_endian = self.base.options.target.cpu.arch.endian();
2010
2011 const text_block = &decl.link.elf;
19552012
1956 // If the Decl is a function, we need to update the .debug_line program.2013 // If the Decl is a function, we need to update the .debug_line program.
2014 var fn_ret_type_index: usize = undefined;
1957 if (is_fn) {2015 if (is_fn) {
1958 // Perform the relocation based on vaddr.2016 // Perform the relocations based on vaddr.
1959 const target_endian = self.base.options.target.cpu.arch.endian();
1960 switch (self.ptr_width) {2017 switch (self.ptr_width) {
1961 .p32 => {2018 .p32 => {
1962 const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4];2019 {
1963 mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);2020 const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4];
2021 mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);
2022 }
2023 {
2024 const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..4];
2025 mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);
2026 }
1964 },2027 },
1965 .p64 => {2028 .p64 => {
1966 const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..8];2029 {
1967 mem.writeInt(u64, ptr, local_sym.st_value, target_endian);2030 const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..8];
2031 mem.writeInt(u64, ptr, local_sym.st_value, target_endian);
2032 }
2033 {
2034 const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..8];
2035 mem.writeInt(u64, ptr, local_sym.st_value, target_endian);
2036 }
1968 },2037 },
1969 }2038 }
2039 {
2040 const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4];
2041 mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_size), target_endian);
2042 }
19702043
1971 try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence });2044 try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence });
19722045
...@@ -2043,14 +2116,69 @@ pub const File = struct {...@@ -2043,14 +2116,69 @@ pub const File = struct {
2043 // from the .debug_line section.2116 // from the .debug_line section.
2044 const file_pos = debug_line_sect.sh_offset + src_fn.off;2117 const file_pos = debug_line_sect.sh_offset + src_fn.off;
2045 try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos);2118 try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos);
2119
2120 // .debug_info
2121 try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 2);
2122 // End the TAG_subprogram children.
2123 dbg_info_buffer.appendAssumeCapacity(0);
2124 if (fn_ret_has_bits) {
2125 // Now we do the return type of the function. The relocation must be performed
2126 // later after the offset for this subprogram is computed.
2127 fn_ret_type_index = dbg_info_buffer.items.len;
2128 try self.addDbgInfoType(typed_value.ty.fnReturnType(), &dbg_info_buffer);
2129 }
2046 }2130 }
20472131
2132 try self.updateDeclDebugInfoAllocation(text_block, @intCast(u32, dbg_info_buffer.items.len));
2133
2134 if (is_fn and fn_ret_has_bits) {
2135 // Perform function return type relocation.
2136 mem.writeInt(
2137 u32,
2138 dbg_info_buffer.items[self.getRelocDbgInfoSubprogramRetType()..][0..4],
2139 text_block.dbg_info_off + @intCast(u32, fn_ret_type_index),
2140 target_endian,
2141 );
2142 }
2143
2144 try self.writeDeclDebugInfo(text_block, dbg_info_buffer.items);
2145
2048 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.2146 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
2049 const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{};2147 const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{};
2050 return self.updateDeclExports(module, decl, decl_exports);2148 return self.updateDeclExports(module, decl, decl_exports);
2051 }2149 }
20522150
2053 pub fn updateDeclDebugInfo(self: *Elf, module: *Module, decl: *Module.Decl, dbg_info_buf: []const u8) !void {2151 /// Asserts the type has codegen bits.
2152 fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !void {
2153 switch (ty.zigTypeTag()) {
2154 .Void, .NoReturn => unreachable,
2155 .Bool => {
2156 try dbg_info_buffer.appendSlice(&[_]u8{
2157 abbrev_base_type,
2158 DW.ATE_boolean, // DW.AT_encoding , DW.FORM_data1
2159 1, // DW.AT_byte_size, DW.FORM_data1
2160 'b', 'o', 'o', 'l', 0, // DW.AT_name, DW.FORM_string
2161 });
2162 },
2163 .Int => {
2164 const info = ty.intInfo(self.base.options.target);
2165 try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 12);
2166 dbg_info_buffer.appendAssumeCapacity(abbrev_base_type);
2167 // DW.AT_encoding, DW.FORM_data1
2168 dbg_info_buffer.appendAssumeCapacity(if (info.signed) DW.ATE_signed else DW.ATE_unsigned);
2169 // DW.AT_byte_size, DW.FORM_data1
2170 dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(self.base.options.target)));
2171 // DW.AT_name, DW.FORM_string
2172 try dbg_info_buffer.writer().print("{}\x00", .{ty});
2173 },
2174 else => {
2175 log.err(.compiler, "TODO implement .debug_info for type '{}'", .{ty});
2176 try dbg_info_buffer.append(abbrev_pad1);
2177 },
2178 }
2179 }
2180
2181 fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) !void {
2054 const tracy = trace(@src());2182 const tracy = trace(@src());
2055 defer tracy.end();2183 defer tracy.end();
20562184
...@@ -2059,7 +2187,7 @@ pub const File = struct {...@@ -2059,7 +2187,7 @@ pub const File = struct {
2059 // probably need to edit that logic too.2187 // probably need to edit that logic too.
20602188
2061 const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];2189 const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];
2062 const text_block = &decl.link.elf;2190 text_block.dbg_info_len = len;
2063 if (self.dbg_info_decl_last) |last| {2191 if (self.dbg_info_decl_last) |last| {
2064 if (text_block.dbg_info_next) |next| {2192 if (text_block.dbg_info_next) |next| {
2065 // Update existing Decl - non-last item.2193 // Update existing Decl - non-last item.
...@@ -2097,6 +2225,17 @@ pub const File = struct {...@@ -2097,6 +2225,17 @@ pub const File = struct {
20972225
2098 text_block.dbg_info_off = self.dbgInfoNeededHeaderBytes() * alloc_num / alloc_den;2226 text_block.dbg_info_off = self.dbgInfoNeededHeaderBytes() * alloc_num / alloc_den;
2099 }2227 }
2228 }
2229
2230 fn writeDeclDebugInfo(self: *Elf, text_block: *TextBlock, dbg_info_buf: []const u8) !void {
2231 const tracy = trace(@src());
2232 defer tracy.end();
2233
2234 // This logic is nearly identical to the logic above in `updateDecl` for
2235 // `SrcFn` and the line number programs. If you are editing this logic, you
2236 // probably need to edit that logic too.
2237
2238 const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];
21002239
2101 const last_decl = self.dbg_info_decl_last.?;2240 const last_decl = self.dbg_info_decl_last.?;
2102 const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len;2241 const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len;
...@@ -2441,6 +2580,9 @@ pub const File = struct {...@@ -2441,6 +2580,9 @@ pub const File = struct {
2441 /// The reloc offset for the virtual address of a function in its Line Number Program.2580 /// The reloc offset for the virtual address of a function in its Line Number Program.
2442 /// Size is a virtual address integer.2581 /// Size is a virtual address integer.
2443 const dbg_line_vaddr_reloc_index = 3;2582 const dbg_line_vaddr_reloc_index = 3;
2583 /// The reloc offset for the virtual address of a function in its .debug_info TAG_subprogram.
2584 /// Size is a virtual address integer.
2585 const dbg_info_low_pc_reloc_index = 1;
24442586
2445 /// The reloc offset for the line offset of a function from the previous function's line.2587 /// The reloc offset for the line offset of a function from the previous function's line.
2446 /// It's a fixed-size 4-byte ULEB128.2588 /// It's a fixed-size 4-byte ULEB128.
...@@ -2452,6 +2594,14 @@ pub const File = struct {...@@ -2452,6 +2594,14 @@ pub const File = struct {
2452 return self.getRelocDbgLineOff() + 5;2594 return self.getRelocDbgLineOff() + 5;
2453 }2595 }
24542596
2597 fn getRelocDbgInfoSubprogramHighPC(self: Elf) u32 {
2598 return dbg_info_low_pc_reloc_index + self.ptrWidthBytes();
2599 }
2600
2601 fn getRelocDbgInfoSubprogramRetType(self: Elf) u32 {
2602 return self.getRelocDbgInfoSubprogramHighPC() + 4;
2603 }
2604
2455 fn dbgLineNeededHeaderBytes(self: Elf) u32 {2605 fn dbgLineNeededHeaderBytes(self: Elf) u32 {
2456 const directory_entry_format_count = 1;2606 const directory_entry_format_count = 1;
2457 const file_name_entry_format_count = 1;2607 const file_name_entry_format_count = 1;
...@@ -2565,7 +2715,7 @@ pub const File = struct {...@@ -2565,7 +2715,7 @@ pub const File = struct {
2565 const tracy = trace(@src());2715 const tracy = trace(@src());
2566 defer tracy.end();2716 defer tracy.end();
25672717
2568 const page_of_nops = [1]u8{0} ** 4096;2718 const page_of_nops = [1]u8{abbrev_pad1} ** 4096;
2569 var vecs: [32]std.os.iovec_const = undefined;2719 var vecs: [32]std.os.iovec_const = undefined;
2570 var vec_index: usize = 0;2720 var vec_index: usize = 0;
2571 {2721 {
src-self-hosted/main.zig+1-1
...@@ -59,7 +59,7 @@ pub fn log(...@@ -59,7 +59,7 @@ pub fn log(
59 const prefix = "[" ++ @tagName(level) ++ "] " ++ "(" ++ @tagName(scope) ++ "): ";59 const prefix = "[" ++ @tagName(level) ++ "] " ++ "(" ++ @tagName(scope) ++ "): ";
6060
61 // Print the message to stderr, silently ignoring any errors61 // Print the message to stderr, silently ignoring any errors
62 std.debug.print(prefix ++ format, args);62 std.debug.print(prefix ++ format ++ "\n", args);
63}63}
6464
65var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};65var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};