authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-12-04 11:06:17+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-12-04 16:58:45+01:00
log278426b851dc5e9eefc6b5be2dda3500f9d6d1d2
tree721b22cebbdae59c535dac03a00b4e7d69baadf9
parente361740669e95b198cfbbcb7a600edc3a0de273a

dsym: make sure DWARF segment comes before LINKEDIT

This will greatly simplify incremental updates to DWARF sections within the bundle.

1 files changed, 79 insertions(+), 138 deletions(-)

src/link/MachO/DebugSymbols.zig+79-138
...@@ -59,41 +59,24 @@ pub const Reloc = struct {...@@ -59,41 +59,24 @@ pub const Reloc = struct {
5959
60/// You must call this function *after* `MachO.populateMissingMetadata()`60/// You must call this function *after* `MachO.populateMissingMetadata()`
61/// has been called to get a viable debug symbols output.61/// has been called to get a viable debug symbols output.
62pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void {62pub fn populateMissingMetadata(self: *DebugSymbols, gpa: Allocator) !void {
63 if (self.linkedit_segment_cmd_index == null) {
64 self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len);
65 const fileoff = @intCast(u64, self.base.page_size);
66 const needed_size = @intCast(u64, self.base.page_size) * 2;
67 log.debug("found __LINKEDIT segment free space 0x{x} to 0x{x}", .{ fileoff, needed_size });
68 // TODO this needs reworking
69 try self.segments.append(allocator, .{
70 .segname = makeStaticString("__LINKEDIT"),
71 .vmaddr = fileoff,
72 .vmsize = needed_size,
73 .fileoff = fileoff,
74 .filesize = needed_size,
75 .maxprot = macho.PROT.READ,
76 .initprot = macho.PROT.READ,
77 .cmdsize = @sizeOf(macho.segment_command_64),
78 });
79 }
80
81 if (self.dwarf_segment_cmd_index == null) {63 if (self.dwarf_segment_cmd_index == null) {
82 self.dwarf_segment_cmd_index = @intCast(u8, self.segments.items.len);64 self.dwarf_segment_cmd_index = @intCast(u8, self.segments.items.len);
8365
84 const linkedit = self.segments.items[self.linkedit_segment_cmd_index.?];66 const off = @intCast(u64, self.base.page_size);
85 const ideal_size: u16 = 200 + 128 + 160 + 250;67 const ideal_size: u16 = 200 + 128 + 160 + 250;
86 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.base.page_size);68 const needed_size = mem.alignForwardGeneric(
87 const fileoff = linkedit.fileoff + linkedit.filesize;69 u64,
88 const vmaddr = linkedit.vmaddr + linkedit.vmsize;70 padToIdeal(ideal_size),
71 self.base.page_size,
72 );
8973
90 log.debug("found __DWARF segment free space 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size });74 log.debug("found __DWARF segment free space 0x{x} to 0x{x}", .{ off, off + needed_size });
9175
92 try self.segments.append(allocator, .{76 try self.segments.append(gpa, .{
93 .segname = makeStaticString("__DWARF"),77 .segname = makeStaticString("__DWARF"),
94 .vmaddr = vmaddr,
95 .vmsize = needed_size,78 .vmsize = needed_size,
96 .fileoff = fileoff,79 .fileoff = off,
97 .filesize = needed_size,80 .filesize = needed_size,
98 .cmdsize = @sizeOf(macho.segment_command_64),81 .cmdsize = @sizeOf(macho.segment_command_64),
99 });82 });
...@@ -128,9 +111,21 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void...@@ -128,9 +111,21 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
128 self.debug_line_section_index = try self.allocateSection("__debug_line", 250, 0);111 self.debug_line_section_index = try self.allocateSection("__debug_line", 250, 0);
129 self.debug_line_header_dirty = true;112 self.debug_line_header_dirty = true;
130 }113 }
114
115 if (self.linkedit_segment_cmd_index == null) {
116 self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len);
117 try self.segments.append(gpa, .{
118 .segname = makeStaticString("__LINKEDIT"),
119 .maxprot = macho.PROT.READ,
120 .initprot = macho.PROT.READ,
121 .cmdsize = @sizeOf(macho.segment_command_64),
122 });
123 }
131}124}
132125
133fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignment: u16) !u8 {126fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignment: u16) !u8 {
127 const gpa = self.base.base.allocator;
128
134 const segment = &self.segments.items[self.dwarf_segment_cmd_index.?];129 const segment = &self.segments.items[self.dwarf_segment_cmd_index.?];
135 var sect = macho.section_64{130 var sect = macho.section_64{
136 .sectname = makeStaticString(sectname),131 .sectname = makeStaticString(sectname),
...@@ -154,7 +149,7 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme...@@ -154,7 +149,7 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme
154 sect.offset = @intCast(u32, off);149 sect.offset = @intCast(u32, off);
155150
156 const index = @intCast(u8, self.sections.items.len);151 const index = @intCast(u8, self.sections.items.len);
157 try self.sections.append(self.base.base.allocator, sect);152 try self.sections.append(gpa, sect);
158 segment.cmdsize += @sizeOf(macho.section_64);153 segment.cmdsize += @sizeOf(macho.section_64);
159 segment.nsects += 1;154 segment.nsects += 1;
160155
...@@ -282,9 +277,8 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -282,9 +277,8 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
282 const lc_writer = lc_buffer.writer();277 const lc_writer = lc_buffer.writer();
283 var ncmds: u32 = 0;278 var ncmds: u32 = 0;
284279
285 self.updateDwarfSegment();280 self.updateLinkeditSegment();
286 try self.writeLinkeditSegmentData(&ncmds, lc_writer);281 try self.writeLinkeditSegmentData(&ncmds, lc_writer);
287 self.updateDwarfSegment();
288282
289 {283 {
290 try lc_writer.writeStruct(self.base.uuid);284 try lc_writer.writeStruct(self.base.uuid);
...@@ -327,40 +321,33 @@ pub fn swapRemoveRelocs(self: *DebugSymbols, target: u32) void {...@@ -327,40 +321,33 @@ pub fn swapRemoveRelocs(self: *DebugSymbols, target: u32) void {
327 }321 }
328}322}
329323
330fn updateDwarfSegment(self: *DebugSymbols) void {324fn updateLinkeditSegment(self: *DebugSymbols) void {
331 const linkedit = self.segments.items[self.linkedit_segment_cmd_index.?];325 const base_vmaddr = blk: {
326 const last_seg = self.base.segments.items[self.base.segments.items.len - 1];
327 break :blk last_seg.vmaddr + last_seg.vmsize;
328 };
332 const dwarf_segment = &self.segments.items[self.dwarf_segment_cmd_index.?];329 const dwarf_segment = &self.segments.items[self.dwarf_segment_cmd_index.?];
333330 const aligned_size = mem.alignForwardGeneric(
334 const new_start_aligned = linkedit.vmaddr + linkedit.vmsize;331 u64,
335 const old_start_aligned = dwarf_segment.vmaddr;332 dwarf_segment.filesize,
336 const diff = new_start_aligned - old_start_aligned;333 self.base.page_size,
337 if (diff > 0) {334 );
338 dwarf_segment.vmaddr = new_start_aligned;335 dwarf_segment.vmaddr = base_vmaddr;
339 }336 dwarf_segment.filesize = aligned_size;
340337 dwarf_segment.vmsize = aligned_size;
341 var max_offset: u64 = 0;338
342 for (self.sections.items) |*sect| {339 const linkedit = self.getLinkeditSegmentPtr();
343 sect.addr += diff;340 linkedit.vmaddr = mem.alignForwardGeneric(
344 log.debug(" {s},{s} - 0x{x}-0x{x} - 0x{x}-0x{x}", .{341 u64,
345 sect.segName(),342 dwarf_segment.vmaddr + aligned_size,
346 sect.sectName(),343 self.base.page_size,
347 sect.offset,344 );
348 sect.offset + sect.size,345 linkedit.fileoff = mem.alignForwardGeneric(
349 sect.addr,346 u64,
350 sect.addr + sect.size,347 dwarf_segment.fileoff + aligned_size,
351 });348 self.base.page_size,
352 if (sect.offset + sect.size > max_offset) {349 );
353 max_offset = sect.offset + sect.size;350 log.debug("found __LINKEDIT segment free space at 0x{x}", .{linkedit.fileoff});
354 }
355 }
356
357 const file_size = max_offset - dwarf_segment.fileoff;
358 log.debug("__DWARF size 0x{x}", .{file_size});
359
360 if (file_size != dwarf_segment.filesize) {
361 dwarf_segment.filesize = file_size;
362 dwarf_segment.vmsize = mem.alignForwardGeneric(u64, dwarf_segment.filesize, self.base.page_size);
363 }
364}351}
365352
366fn writeSegmentHeaders(self: *DebugSymbols, ncmds: *u32, writer: anytype) !void {353fn writeSegmentHeaders(self: *DebugSymbols, ncmds: *u32, writer: anytype) !void {
...@@ -397,13 +384,14 @@ fn writeSegmentHeaders(self: *DebugSymbols, ncmds: *u32, writer: anytype) !void...@@ -397,13 +384,14 @@ fn writeSegmentHeaders(self: *DebugSymbols, ncmds: *u32, writer: anytype) !void
397 ncmds.* += 1;384 ncmds.* += 1;
398 }385 }
399 // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.386 // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.
400 for (self.segments.items) |seg| {387 for (self.segments.items) |seg, i| {
388 const indexes = self.getSectionIndexes(@intCast(u8, i));
401 try writer.writeStruct(seg);389 try writer.writeStruct(seg);
390 for (self.sections.items[indexes.start..indexes.end]) |header| {
391 try writer.writeStruct(header);
392 }
402 ncmds.* += 1;393 ncmds.* += 1;
403 }394 }
404 for (self.sections.items) |header| {
405 try writer.writeStruct(header);
406 }
407}395}
408396
409fn writeHeader(self: *DebugSymbols, ncmds: u32, sizeofcmds: u32) !void {397fn writeHeader(self: *DebugSymbols, ncmds: u32, sizeofcmds: u32) !void {
...@@ -445,10 +433,6 @@ fn writeLinkeditSegmentData(self: *DebugSymbols, ncmds: *u32, lc_writer: anytype...@@ -445,10 +433,6 @@ fn writeLinkeditSegmentData(self: *DebugSymbols, ncmds: *u32, lc_writer: anytype
445 const tracy = trace(@src());433 const tracy = trace(@src());
446 defer tracy.end();434 defer tracy.end();
447435
448 const source_vmaddr = self.base.segments.items[self.base.linkedit_segment_cmd_index.?].vmaddr;
449 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
450 seg.vmaddr = source_vmaddr;
451
452 var symtab_cmd = macho.symtab_command{436 var symtab_cmd = macho.symtab_command{
453 .cmdsize = @sizeOf(macho.symtab_command),437 .cmdsize = @sizeOf(macho.symtab_command),
454 .symoff = 0,438 .symoff = 0,
...@@ -461,8 +445,8 @@ fn writeLinkeditSegmentData(self: *DebugSymbols, ncmds: *u32, lc_writer: anytype...@@ -461,8 +445,8 @@ fn writeLinkeditSegmentData(self: *DebugSymbols, ncmds: *u32, lc_writer: anytype
461 try lc_writer.writeStruct(symtab_cmd);445 try lc_writer.writeStruct(symtab_cmd);
462 ncmds.* += 1;446 ncmds.* += 1;
463447
448 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
464 const aligned_size = mem.alignForwardGeneric(u64, seg.filesize, self.base.page_size);449 const aligned_size = mem.alignForwardGeneric(u64, seg.filesize, self.base.page_size);
465 seg.filesize = aligned_size;
466 seg.vmsize = aligned_size;450 seg.vmsize = aligned_size;
467}451}
468452
...@@ -503,38 +487,7 @@ fn writeSymtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {...@@ -503,38 +487,7 @@ fn writeSymtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {
503 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];487 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
504 const offset = mem.alignForwardGeneric(u64, seg.fileoff, @alignOf(macho.nlist_64));488 const offset = mem.alignForwardGeneric(u64, seg.fileoff, @alignOf(macho.nlist_64));
505 const needed_size = nsyms * @sizeOf(macho.nlist_64);489 const needed_size = nsyms * @sizeOf(macho.nlist_64);
506490 seg.filesize = offset + needed_size - seg.fileoff;
507 if (needed_size > seg.filesize) {
508 const aligned_size = mem.alignForwardGeneric(u64, needed_size, self.base.page_size);
509 const diff = @intCast(u32, aligned_size - seg.filesize);
510 const dwarf_seg = &self.segments.items[self.dwarf_segment_cmd_index.?];
511 seg.filesize = aligned_size;
512
513 try copyRangeAllOverlappingAlloc(
514 self.base.base.allocator,
515 self.file,
516 dwarf_seg.fileoff,
517 dwarf_seg.fileoff + diff,
518 math.cast(usize, dwarf_seg.filesize) orelse return error.Overflow,
519 );
520
521 const old_seg_fileoff = dwarf_seg.fileoff;
522 dwarf_seg.fileoff += diff;
523
524 log.debug(" (moving __DWARF segment from 0x{x} to 0x{x})", .{ old_seg_fileoff, dwarf_seg.fileoff });
525
526 for (self.sections.items) |*sect| {
527 const old_offset = sect.offset;
528 sect.offset += diff;
529
530 log.debug(" (moving {s},{s} from 0x{x} to 0x{x})", .{
531 sect.segName(),
532 sect.sectName(),
533 old_offset,
534 sect.offset,
535 });
536 }
537 }
538491
539 lc.symoff = @intCast(u32, offset);492 lc.symoff = @intCast(u32, offset);
540 lc.nsyms = @intCast(u32, nsyms);493 lc.nsyms = @intCast(u32, nsyms);
...@@ -558,46 +511,20 @@ fn writeStrtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {...@@ -558,46 +511,20 @@ fn writeStrtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {
558 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];511 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
559 const symtab_size = @intCast(u32, lc.nsyms * @sizeOf(macho.nlist_64));512 const symtab_size = @intCast(u32, lc.nsyms * @sizeOf(macho.nlist_64));
560 const offset = mem.alignForwardGeneric(u64, lc.symoff + symtab_size, @alignOf(u64));513 const offset = mem.alignForwardGeneric(u64, lc.symoff + symtab_size, @alignOf(u64));
561 lc.stroff = @intCast(u32, offset);
562
563 const needed_size = mem.alignForwardGeneric(u64, self.strtab.buffer.items.len, @alignOf(u64));514 const needed_size = mem.alignForwardGeneric(u64, self.strtab.buffer.items.len, @alignOf(u64));
564 lc.strsize = @intCast(u32, needed_size);
565515
566 if (symtab_size + needed_size > seg.filesize) {516 seg.filesize = offset + needed_size - seg.fileoff;
567 const aligned_size = mem.alignForwardGeneric(u64, offset + needed_size, self.base.page_size);517 lc.stroff = @intCast(u32, offset);
568 const diff = @intCast(u32, aligned_size - seg.filesize);518 lc.strsize = @intCast(u32, needed_size);
569 const dwarf_seg = &self.segments.items[self.dwarf_segment_cmd_index.?];
570 seg.filesize = aligned_size;
571
572 try copyRangeAllOverlappingAlloc(
573 self.base.base.allocator,
574 self.file,
575 dwarf_seg.fileoff,
576 dwarf_seg.fileoff + diff,
577 math.cast(usize, dwarf_seg.filesize) orelse return error.Overflow,
578 );
579
580 const old_seg_fileoff = dwarf_seg.fileoff;
581 dwarf_seg.fileoff += diff;
582
583 log.debug(" (moving __DWARF segment from 0x{x} to 0x{x})", .{ old_seg_fileoff, dwarf_seg.fileoff });
584
585 for (self.sections.items) |*sect| {
586 const old_offset = sect.offset;
587 sect.offset += diff;
588
589 log.debug(" (moving {s},{s} from 0x{x} to 0x{x})", .{
590 sect.segName(),
591 sect.sectName(),
592 old_offset,
593 sect.offset,
594 });
595 }
596 }
597519
598 log.debug("writing string table from 0x{x} to 0x{x}", .{ lc.stroff, lc.stroff + lc.strsize });520 log.debug("writing string table from 0x{x} to 0x{x}", .{ lc.stroff, lc.stroff + lc.strsize });
599521
600 try self.file.pwriteAll(self.strtab.buffer.items, lc.stroff);522 try self.file.pwriteAll(self.strtab.buffer.items, lc.stroff);
523
524 if (self.strtab.buffer.items.len < needed_size) {
525 // Ensure we are always padded to the actual length of the file.
526 try self.file.pwriteAll(&[_]u8{0}, lc.stroff + lc.strsize);
527 }
601}528}
602529
603fn copyRangeAllOverlappingAlloc(530fn copyRangeAllOverlappingAlloc(
...@@ -612,3 +539,17 @@ fn copyRangeAllOverlappingAlloc(...@@ -612,3 +539,17 @@ fn copyRangeAllOverlappingAlloc(
612 const amt = try file.preadAll(buf, in_offset);539 const amt = try file.preadAll(buf, in_offset);
613 try file.pwriteAll(buf[0..amt], out_offset);540 try file.pwriteAll(buf[0..amt], out_offset);
614}541}
542
543pub fn getSectionIndexes(self: *DebugSymbols, segment_index: u8) struct { start: u8, end: u8 } {
544 var start: u8 = 0;
545 const nsects = for (self.segments.items) |seg, i| {
546 if (i == segment_index) break @intCast(u8, seg.nsects);
547 start += @intCast(u8, seg.nsects);
548 } else 0;
549 return .{ .start = start, .end = start + nsects };
550}
551
552pub fn getLinkeditSegmentPtr(self: *DebugSymbols) *macho.segment_command_64 {
553 const index = self.linkedit_segment_cmd_index.?;
554 return &self.segments.items[index];
555}