Skip to content

Commit 6461b95

Browse files
committed
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 '_'.
1 parent d98e39f commit 6461b95

File tree

3 files changed

+53
-15
lines changed

3 files changed

+53
-15
lines changed

src/link/MachO.zig

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -362,8 +362,8 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
362362

363363
self.base.file = file;
364364

365-
// Create dSYM bundle.
366365
if (!options.strip and options.module != null) {
366+
// Create dSYM bundle.
367367
const dir = options.module.?.zig_cache_artifact_directory;
368368
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 {
12231223
self.shrinkTextBlock(&decl.link.macho, code.len);
12241224
}
12251225
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);
12271231
symbol.n_type = macho.N_SECT;
12281232
symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1;
12291233
symbol.n_desc = 0;
@@ -1232,7 +1236,9 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
12321236
if (self.d_sym) |*ds|
12331237
try ds.writeLocalSymbol(decl.link.macho.local_sym_index);
12341238
} 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+
12361242
const name_str_index = try self.makeString(decl_name);
12371243
const addr = try self.allocateTextBlock(&decl.link.macho, code.len, required_alignment);
12381244

@@ -1371,6 +1377,9 @@ pub fn updateDeclExports(
13711377
const decl_sym = &self.locals.items[decl.link.macho.local_sym_index];
13721378

13731379
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+
13741383
if (exp.options.section) |section_name| {
13751384
if (!mem.eql(u8, section_name, "__text")) {
13761385
try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
@@ -1398,7 +1407,7 @@ pub fn updateDeclExports(
13981407
// Otherwise, don't do anything since we already have all the flags
13991408
// set that we need for global (strong) linkage.
14001409
// n_type == N_SECT | N_EXT
1401-
if (mem.eql(u8, exp.options.name, "_main")) {
1410+
if (mem.eql(u8, exp_name, "_main")) {
14021411
self.entry_addr = decl_sym.n_value;
14031412
}
14041413
},
@@ -1420,14 +1429,14 @@ pub fn updateDeclExports(
14201429
if (exp.link.macho.sym_index) |i| {
14211430
const sym = &self.globals.items[i];
14221431
sym.* = .{
1423-
.n_strx = try self.updateString(sym.n_strx, exp.options.name),
1432+
.n_strx = try self.updateString(sym.n_strx, exp_name),
14241433
.n_type = n_type,
14251434
.n_sect = @intCast(u8, self.text_section_index.?) + 1,
14261435
.n_desc = n_desc,
14271436
.n_value = decl_sym.n_value,
14281437
};
14291438
} else {
1430-
const name_str_index = try self.makeString(exp.options.name);
1439+
const name_str_index = try self.makeString(exp_name);
14311440
const i = if (self.globals_free_list.popOrNull()) |i| i else blk: {
14321441
_ = self.globals.addOneAssumeCapacity();
14331442
self.export_info_dirty = true;
@@ -2230,9 +2239,12 @@ fn makeString(self: *MachO, bytes: []const u8) !u32 {
22302239

22312240
try self.string_table.ensureCapacity(self.base.allocator, self.string_table.items.len + bytes.len + 1);
22322241
const offset = @intCast(u32, self.string_table.items.len);
2242+
22332243
log.debug("writing new string '{s}' into string table at offset 0x{x}", .{ bytes, offset });
2244+
22342245
self.string_table.appendSliceAssumeCapacity(bytes);
22352246
self.string_table.appendAssumeCapacity(0);
2247+
22362248
try self.string_table_directory.putNoClobber(
22372249
self.base.allocator,
22382250
try self.base.allocator.dupe(u8, bytes),

src/link/MachO/DebugSymbols.zig

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -534,8 +534,8 @@ pub fn flushModule(self: *DebugSymbols, allocator: *Allocator, options: link.Opt
534534
mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), text_section.size);
535535

536536
// Sentinel.
537-
mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0);
538-
mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0);
537+
mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), 0);
538+
mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), 0);
539539

540540
// Go back and populate the initial length.
541541
const init_len = di_buf.items.len - after_init_len;
@@ -1075,6 +1075,32 @@ pub fn commitDeclDebugInfo(
10751075
mem.writeIntLittle(u32, ptr, @intCast(u32, text_block.size));
10761076
}
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+
10781104
try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence });
10791105

10801106
// Now we have the full contents and may allocate a region to store it.

test/stage2/darwin.zig

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub fn addCases(ctx: *TestContext) !void {
1717

1818
// Incorrect return type
1919
case.addError(
20-
\\export fn _main() noreturn {
20+
\\export fn main() noreturn {
2121
\\}
2222
, &[_][]const u8{":2:1: error: expected noreturn, found void"});
2323

@@ -26,7 +26,7 @@ pub fn addCases(ctx: *TestContext) !void {
2626
\\extern "c" fn write(usize, usize, usize) usize;
2727
\\extern "c" fn exit(usize) noreturn;
2828
\\
29-
\\export fn _main() noreturn {
29+
\\export fn main() noreturn {
3030
\\ print();
3131
\\
3232
\\ exit(0);
@@ -46,7 +46,7 @@ pub fn addCases(ctx: *TestContext) !void {
4646
\\extern "c" fn write(usize, usize, usize) usize;
4747
\\extern "c" fn exit(usize) noreturn;
4848
\\
49-
\\export fn _main() noreturn {
49+
\\export fn main() noreturn {
5050
\\ print();
5151
\\ print();
5252
\\ print();
@@ -73,7 +73,7 @@ pub fn addCases(ctx: *TestContext) !void {
7373
\\extern "c" fn write(usize, usize, usize) usize;
7474
\\extern "c" fn exit(usize) noreturn;
7575
\\
76-
\\export fn _main() noreturn {
76+
\\export fn main() noreturn {
7777
\\ print();
7878
\\
7979
\\ exit(0);
@@ -93,7 +93,7 @@ pub fn addCases(ctx: *TestContext) !void {
9393
\\extern "c" fn write(usize, usize, usize) usize;
9494
\\extern "c" fn exit(usize) noreturn;
9595
\\
96-
\\export fn _main() noreturn {
96+
\\export fn main() noreturn {
9797
\\ print();
9898
\\ print();
9999
\\
@@ -119,7 +119,7 @@ pub fn addCases(ctx: *TestContext) !void {
119119
case.addCompareOutput(
120120
\\extern "c" fn exit(usize) noreturn;
121121
\\
122-
\\export fn _main() noreturn {
122+
\\export fn main() noreturn {
123123
\\ exit(0);
124124
\\}
125125
,
@@ -130,7 +130,7 @@ pub fn addCases(ctx: *TestContext) !void {
130130
\\extern "c" fn exit(usize) noreturn;
131131
\\extern "c" fn write(usize, usize, usize) usize;
132132
\\
133-
\\export fn _main() noreturn {
133+
\\export fn main() noreturn {
134134
\\ _ = write(1, @ptrToInt("Hey!\n"), 5);
135135
\\ exit(0);
136136
\\}

0 commit comments

Comments
 (0)