| ... | @@ -59,41 +59,24 @@ pub const Reloc = struct { | ... | @@ -59,41 +59,24 @@ pub const Reloc = struct { |
| 59 | | 59 | |
| 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. |
| 62 | pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void { | 62 | pub 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); |
| 83 | | 65 | |
| 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 | ); |
| 89 | | 73 | |
| 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 }); |
| 91 | | 75 | |
| 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 | } |
| 132 | | 125 | |
| 133 | fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignment: u16) !u8 { | 126 | fn 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); |
| 155 | | 150 | |
| 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; |
| 160 | | 155 | |
| ... | @@ -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; |
| 284 | | 279 | |
| 285 | self.updateDwarfSegment(); | 280 | self.updateLinkeditSegment(); |
| 286 | try self.writeLinkeditSegmentData(&ncmds, lc_writer); | 281 | try self.writeLinkeditSegmentData(&ncmds, lc_writer); |
| 287 | self.updateDwarfSegment(); | | |
| 288 | | 282 | |
| 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 | } |
| 329 | | 323 | |
| 330 | fn updateDwarfSegment(self: *DebugSymbols) void { | 324 | fn 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.?]; |
| 333 | | 330 | 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; |
| 340 | | 337 | 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 | } |
| 365 | | 352 | |
| 366 | fn writeSegmentHeaders(self: *DebugSymbols, ncmds: *u32, writer: anytype) !void { | 353 | fn 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 | } |
| 408 | | 396 | |
| 409 | fn writeHeader(self: *DebugSymbols, ncmds: u32, sizeofcmds: u32) !void { | 397 | fn 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(); |
| 447 | | 435 | |
| 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; |
| 463 | | 447 | |
| | 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 | } |
| 468 | | 452 | |
| ... | @@ -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); |
| 506 | | 490 | 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 | } | | |
| 538 | | 491 | |
| 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); | | |
| 565 | | 515 | |
| 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 | } | | |
| 597 | | 519 | |
| 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 }); |
| 599 | | 521 | |
| 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 | } |
| 602 | | 529 | |
| 603 | fn copyRangeAllOverlappingAlloc( | 530 | fn 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 | |
| | 543 | pub 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 | |
| | 552 | pub fn getLinkeditSegmentPtr(self: *DebugSymbols) *macho.segment_command_64 { |
| | 553 | const index = self.linkedit_segment_cmd_index.?; |
| | 554 | return &self.segments.items[index]; |
| | 555 | } |