authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-05-14 19:20:21+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-05-16 08:12:29+02:00
log6461b9516371d22d347c27b5fcd2e8c22fafd03d
tree4d11bd6cfeca70ff1f82b1318ef75c8722695278
parentd98e39fa6864f287bc50f265f98b7195849afa68

macho: fix DWARF in dSYM and sym naming more consistent

* Advance line and PC prior to ending sequence in debug line program for a fn_decl. This is equivalent to closing scope in the debugger and without it, the debugger will not map source-to-address info as a result will not print the source when breaking at a symbol. * Fix debug aranges sentinels to be of the size as the actual tuple descriptor (assuming segment selector to be ommitted). In summary, the sentinels were 32bit 0s, whereas they ought to be 64bit 0s. * Make naming of symbols in the binary more consistent by prefixing each symbol name with an underscore '_'.

3 files changed, 53 insertions(+), 15 deletions(-)

src/link/MachO.zig+18-6
...@@ -362,8 +362,8 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -362,8 +362,8 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
362362
363 self.base.file = file;363 self.base.file = file;
364364
365 // Create dSYM bundle.
366 if (!options.strip and options.module != null) {365 if (!options.strip and options.module != null) {
366 // Create dSYM bundle.
367 const dir = options.module.?.zig_cache_artifact_directory;367 const dir = options.module.?.zig_cache_artifact_directory;
368 log.debug("creating {s}.dSYM bundle in {s}", .{ sub_path, dir.path });368 log.debug("creating {s}.dSYM bundle in {s}", .{ sub_path, dir.path });
369369
...@@ -1223,7 +1223,11 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1223,7 +1223,11 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1223 self.shrinkTextBlock(&decl.link.macho, code.len);1223 self.shrinkTextBlock(&decl.link.macho, code.len);
1224 }1224 }
1225 decl.link.macho.size = code.len;1225 decl.link.macho.size = code.len;
1226 symbol.n_strx = try self.updateString(symbol.n_strx, mem.spanZ(decl.name));1226
1227 const new_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{mem.spanZ(decl.name)});
1228 defer self.base.allocator.free(new_name);
1229
1230 symbol.n_strx = try self.updateString(symbol.n_strx, new_name);
1227 symbol.n_type = macho.N_SECT;1231 symbol.n_type = macho.N_SECT;
1228 symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1;1232 symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1;
1229 symbol.n_desc = 0;1233 symbol.n_desc = 0;
...@@ -1232,7 +1236,9 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1232,7 +1236,9 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1232 if (self.d_sym) |*ds|1236 if (self.d_sym) |*ds|
1233 try ds.writeLocalSymbol(decl.link.macho.local_sym_index);1237 try ds.writeLocalSymbol(decl.link.macho.local_sym_index);
1234 } else {1238 } else {
1235 const decl_name = mem.spanZ(decl.name);1239 const decl_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{mem.spanZ(decl.name)});
1240 defer self.base.allocator.free(decl_name);
1241
1236 const name_str_index = try self.makeString(decl_name);1242 const name_str_index = try self.makeString(decl_name);
1237 const addr = try self.allocateTextBlock(&decl.link.macho, code.len, required_alignment);1243 const addr = try self.allocateTextBlock(&decl.link.macho, code.len, required_alignment);
12381244
...@@ -1371,6 +1377,9 @@ pub fn updateDeclExports(...@@ -1371,6 +1377,9 @@ pub fn updateDeclExports(
1371 const decl_sym = &self.locals.items[decl.link.macho.local_sym_index];1377 const decl_sym = &self.locals.items[decl.link.macho.local_sym_index];
13721378
1373 for (exports) |exp| {1379 for (exports) |exp| {
1380 const exp_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{exp.options.name});
1381 defer self.base.allocator.free(exp_name);
1382
1374 if (exp.options.section) |section_name| {1383 if (exp.options.section) |section_name| {
1375 if (!mem.eql(u8, section_name, "__text")) {1384 if (!mem.eql(u8, section_name, "__text")) {
1376 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);1385 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
...@@ -1398,7 +1407,7 @@ pub fn updateDeclExports(...@@ -1398,7 +1407,7 @@ pub fn updateDeclExports(
1398 // Otherwise, don't do anything since we already have all the flags1407 // Otherwise, don't do anything since we already have all the flags
1399 // set that we need for global (strong) linkage.1408 // set that we need for global (strong) linkage.
1400 // n_type == N_SECT | N_EXT1409 // n_type == N_SECT | N_EXT
1401 if (mem.eql(u8, exp.options.name, "_main")) {1410 if (mem.eql(u8, exp_name, "_main")) {
1402 self.entry_addr = decl_sym.n_value;1411 self.entry_addr = decl_sym.n_value;
1403 }1412 }
1404 },1413 },
...@@ -1420,14 +1429,14 @@ pub fn updateDeclExports(...@@ -1420,14 +1429,14 @@ pub fn updateDeclExports(
1420 if (exp.link.macho.sym_index) |i| {1429 if (exp.link.macho.sym_index) |i| {
1421 const sym = &self.globals.items[i];1430 const sym = &self.globals.items[i];
1422 sym.* = .{1431 sym.* = .{
1423 .n_strx = try self.updateString(sym.n_strx, exp.options.name),1432 .n_strx = try self.updateString(sym.n_strx, exp_name),
1424 .n_type = n_type,1433 .n_type = n_type,
1425 .n_sect = @intCast(u8, self.text_section_index.?) + 1,1434 .n_sect = @intCast(u8, self.text_section_index.?) + 1,
1426 .n_desc = n_desc,1435 .n_desc = n_desc,
1427 .n_value = decl_sym.n_value,1436 .n_value = decl_sym.n_value,
1428 };1437 };
1429 } else {1438 } else {
1430 const name_str_index = try self.makeString(exp.options.name);1439 const name_str_index = try self.makeString(exp_name);
1431 const i = if (self.globals_free_list.popOrNull()) |i| i else blk: {1440 const i = if (self.globals_free_list.popOrNull()) |i| i else blk: {
1432 _ = self.globals.addOneAssumeCapacity();1441 _ = self.globals.addOneAssumeCapacity();
1433 self.export_info_dirty = true;1442 self.export_info_dirty = true;
...@@ -2230,9 +2239,12 @@ fn makeString(self: *MachO, bytes: []const u8) !u32 {...@@ -2230,9 +2239,12 @@ fn makeString(self: *MachO, bytes: []const u8) !u32 {
22302239
2231 try self.string_table.ensureCapacity(self.base.allocator, self.string_table.items.len + bytes.len + 1);2240 try self.string_table.ensureCapacity(self.base.allocator, self.string_table.items.len + bytes.len + 1);
2232 const offset = @intCast(u32, self.string_table.items.len);2241 const offset = @intCast(u32, self.string_table.items.len);
2242
2233 log.debug("writing new string '{s}' into string table at offset 0x{x}", .{ bytes, offset });2243 log.debug("writing new string '{s}' into string table at offset 0x{x}", .{ bytes, offset });
2244
2234 self.string_table.appendSliceAssumeCapacity(bytes);2245 self.string_table.appendSliceAssumeCapacity(bytes);
2235 self.string_table.appendAssumeCapacity(0);2246 self.string_table.appendAssumeCapacity(0);
2247
2236 try self.string_table_directory.putNoClobber(2248 try self.string_table_directory.putNoClobber(
2237 self.base.allocator,2249 self.base.allocator,
2238 try self.base.allocator.dupe(u8, bytes),2250 try self.base.allocator.dupe(u8, bytes),
src/link/MachO/DebugSymbols.zig+28-2
...@@ -534,8 +534,8 @@ pub fn flushModule(self: *DebugSymbols, allocator: *Allocator, options: link.Opt...@@ -534,8 +534,8 @@ pub fn flushModule(self: *DebugSymbols, allocator: *Allocator, options: link.Opt
534 mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), text_section.size);534 mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), text_section.size);
535535
536 // Sentinel.536 // Sentinel.
537 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0);537 mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), 0);
538 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0);538 mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), 0);
539539
540 // Go back and populate the initial length.540 // Go back and populate the initial length.
541 const init_len = di_buf.items.len - after_init_len;541 const init_len = di_buf.items.len - after_init_len;
...@@ -1075,6 +1075,32 @@ pub fn commitDeclDebugInfo(...@@ -1075,6 +1075,32 @@ pub fn commitDeclDebugInfo(
1075 mem.writeIntLittle(u32, ptr, @intCast(u32, text_block.size));1075 mem.writeIntLittle(u32, ptr, @intCast(u32, text_block.size));
1076 }1076 }
10771077
1078 {
1079 // Advance line and PC.
1080 // TODO encapsulate logic in a helper function.
1081 try dbg_line_buffer.append(DW.LNS_advance_pc);
1082 try leb.writeULEB128(dbg_line_buffer.writer(), text_block.size);
1083
1084 try dbg_line_buffer.append(DW.LNS_advance_line);
1085 const line_off: u28 = blk: {
1086 const tree = decl.container.file_scope.tree;
1087 const node_tags = tree.nodes.items(.tag);
1088 const node_datas = tree.nodes.items(.data);
1089 const token_starts = tree.tokens.items(.start);
1090
1091 // TODO Look into improving the performance here by adding a token-index-to-line
1092 // lookup table. Currently this involves scanning over the source code for newlines.
1093 const fn_decl = decl.src_node;
1094 assert(node_tags[fn_decl] == .fn_decl);
1095 const block = node_datas[fn_decl].rhs;
1096 const lbrace = tree.firstToken(block);
1097 const rbrace = tree.lastToken(block);
1098 const line_delta = std.zig.lineDelta(tree.source, token_starts[lbrace], token_starts[rbrace]);
1099 break :blk @intCast(u28, line_delta);
1100 };
1101 try leb.writeULEB128(dbg_line_buffer.writer(), line_off);
1102 }
1103
1078 try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence });1104 try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence });
10791105
1080 // Now we have the full contents and may allocate a region to store it.1106 // Now we have the full contents and may allocate a region to store it.
test/stage2/darwin.zig+7-7
...@@ -17,7 +17,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -17,7 +17,7 @@ pub fn addCases(ctx: *TestContext) !void {
1717
18 // Incorrect return type18 // Incorrect return type
19 case.addError(19 case.addError(
20 \\export fn _main() noreturn {20 \\export fn main() noreturn {
21 \\}21 \\}
22 , &[_][]const u8{":2:1: error: expected noreturn, found void"});22 , &[_][]const u8{":2:1: error: expected noreturn, found void"});
2323
...@@ -26,7 +26,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -26,7 +26,7 @@ pub fn addCases(ctx: *TestContext) !void {
26 \\extern "c" fn write(usize, usize, usize) usize;26 \\extern "c" fn write(usize, usize, usize) usize;
27 \\extern "c" fn exit(usize) noreturn;27 \\extern "c" fn exit(usize) noreturn;
28 \\28 \\
29 \\export fn _main() noreturn {29 \\export fn main() noreturn {
30 \\ print();30 \\ print();
31 \\31 \\
32 \\ exit(0);32 \\ exit(0);
...@@ -46,7 +46,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -46,7 +46,7 @@ pub fn addCases(ctx: *TestContext) !void {
46 \\extern "c" fn write(usize, usize, usize) usize;46 \\extern "c" fn write(usize, usize, usize) usize;
47 \\extern "c" fn exit(usize) noreturn;47 \\extern "c" fn exit(usize) noreturn;
48 \\48 \\
49 \\export fn _main() noreturn {49 \\export fn main() noreturn {
50 \\ print();50 \\ print();
51 \\ print();51 \\ print();
52 \\ print();52 \\ print();
...@@ -73,7 +73,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -73,7 +73,7 @@ pub fn addCases(ctx: *TestContext) !void {
73 \\extern "c" fn write(usize, usize, usize) usize;73 \\extern "c" fn write(usize, usize, usize) usize;
74 \\extern "c" fn exit(usize) noreturn;74 \\extern "c" fn exit(usize) noreturn;
75 \\75 \\
76 \\export fn _main() noreturn {76 \\export fn main() noreturn {
77 \\ print();77 \\ print();
78 \\78 \\
79 \\ exit(0);79 \\ exit(0);
...@@ -93,7 +93,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -93,7 +93,7 @@ pub fn addCases(ctx: *TestContext) !void {
93 \\extern "c" fn write(usize, usize, usize) usize;93 \\extern "c" fn write(usize, usize, usize) usize;
94 \\extern "c" fn exit(usize) noreturn;94 \\extern "c" fn exit(usize) noreturn;
95 \\95 \\
96 \\export fn _main() noreturn {96 \\export fn main() noreturn {
97 \\ print();97 \\ print();
98 \\ print();98 \\ print();
99 \\99 \\
...@@ -119,7 +119,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -119,7 +119,7 @@ pub fn addCases(ctx: *TestContext) !void {
119 case.addCompareOutput(119 case.addCompareOutput(
120 \\extern "c" fn exit(usize) noreturn;120 \\extern "c" fn exit(usize) noreturn;
121 \\121 \\
122 \\export fn _main() noreturn {122 \\export fn main() noreturn {
123 \\ exit(0);123 \\ exit(0);
124 \\}124 \\}
125 ,125 ,
...@@ -130,7 +130,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -130,7 +130,7 @@ pub fn addCases(ctx: *TestContext) !void {
130 \\extern "c" fn exit(usize) noreturn;130 \\extern "c" fn exit(usize) noreturn;
131 \\extern "c" fn write(usize, usize, usize) usize;131 \\extern "c" fn write(usize, usize, usize) usize;
132 \\132 \\
133 \\export fn _main() noreturn {133 \\export fn main() noreturn {
134 \\ _ = write(1, @ptrToInt("Hey!\n"), 5);134 \\ _ = write(1, @ptrToInt("Hey!\n"), 5);
135 \\ exit(0);135 \\ exit(0);
136 \\}136 \\}