authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-11-19 14:33:42+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-11-20 10:42:21+00:00
log0f06b5b58387eacb53448835cbcbca10cca1559e
tree6284b2448c64ab11338600616317571ebe388197
parente1fa4011fbe812dc7d05326239a62388b591ba52
signaturelock-open Commit is signed but in an unrecognized format.

std.debug.MachOFile: handle 'path/to/archive.a(entry.o)' form


1 files changed, 60 insertions(+), 13 deletions(-)

lib/std/debug/MachOFile.zig+60-13
......@@ -356,11 +356,58 @@ test {
356356 _ = Symbol;
357357}
358358
359fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile {
360 const mapped_mem = try mapDebugInfoFile(o_file_path);
361 errdefer posix.munmap(mapped_mem);
359fn loadOFile(gpa: Allocator, o_file_name: []const u8) !OFile {
360 const all_mapped_memory, const mapped_ofile = map: {
361 const open_paren = paren: {
362 if (std.mem.endsWith(u8, o_file_name, ")")) {
363 if (std.mem.findScalarLast(u8, o_file_name, '(')) |i| {
364 break :paren i;
365 }
366 }
367 // Not an archive, just a normal path to a .o file
368 const m = try mapDebugInfoFile(o_file_name);
369 break :map .{ m, m };
370 };
371
372 // We have the form 'path/to/archive.a(entry.o)'. Map the archive and find the object file in question.
373
374 const archive_path = o_file_name[0..open_paren];
375 const target_name_in_archive = o_file_name[open_paren + 1 .. o_file_name.len - 1];
376 const mapped_archive = try mapDebugInfoFile(archive_path);
377 errdefer posix.munmap(mapped_archive);
378
379 var ar_reader: Io.Reader = .fixed(mapped_archive);
380 const ar_magic = ar_reader.take(8) catch return error.InvalidMachO;
381 if (!std.mem.eql(u8, ar_magic, "!<arch>\n")) return error.InvalidMachO;
382 while (true) {
383 if (ar_reader.seek == ar_reader.buffer.len) return error.MissingDebugInfo;
384
385 const raw_name = ar_reader.takeArray(16) catch return error.InvalidMachO;
386 ar_reader.discardAll(12 + 6 + 6 + 8) catch return error.InvalidMachO;
387 const raw_size = ar_reader.takeArray(10) catch return error.InvalidMachO;
388 const file_magic = ar_reader.takeArray(2) catch return error.InvalidMachO;
389 if (!std.mem.eql(u8, file_magic, "`\n")) return error.InvalidMachO;
390
391 const size = std.fmt.parseInt(u32, mem.sliceTo(raw_size, ' '), 10) catch return error.InvalidMachO;
392 const raw_data = ar_reader.take(size) catch return error.InvalidMachO;
393
394 const entry_name: []const u8, const entry_contents: []const u8 = entry: {
395 if (!std.mem.startsWith(u8, raw_name, "#1/")) {
396 break :entry .{ mem.sliceTo(raw_name, '/'), raw_data };
397 }
398 const len = std.fmt.parseInt(u32, mem.sliceTo(raw_name[3..], ' '), 10) catch return error.InvalidMachO;
399 if (len > size) return error.InvalidMachO;
400 break :entry .{ mem.sliceTo(raw_data[0..len], 0), raw_data[len..] };
401 };
402
403 if (std.mem.eql(u8, entry_name, target_name_in_archive)) {
404 break :map .{ mapped_archive, entry_contents };
405 }
406 }
407 };
408 errdefer posix.munmap(all_mapped_memory);
362409
363 var r: Io.Reader = .fixed(mapped_mem);
410 var r: Io.Reader = .fixed(mapped_ofile);
364411 const hdr = r.takeStruct(macho.mach_header_64, .little) catch |err| switch (err) {
365412 error.ReadFailed => unreachable,
366413 error.EndOfStream => return error.InvalidMachO,
......@@ -370,7 +417,7 @@ fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile {
370417 const seg_cmd: macho.LoadCommandIterator.LoadCommand, const symtab_cmd: macho.symtab_command = cmds: {
371418 var seg_cmd: ?macho.LoadCommandIterator.LoadCommand = null;
372419 var symtab_cmd: ?macho.symtab_command = null;
373 var it: macho.LoadCommandIterator = try .init(&hdr, mapped_mem[@sizeOf(macho.mach_header_64)..]);
420 var it: macho.LoadCommandIterator = try .init(&hdr, mapped_ofile[@sizeOf(macho.mach_header_64)..]);
374421 while (try it.next()) |lc| switch (lc.hdr.cmd) {
375422 .SEGMENT_64 => seg_cmd = lc,
376423 .SYMTAB => symtab_cmd = lc.cast(macho.symtab_command) orelse return error.InvalidMachO,
......@@ -382,13 +429,13 @@ fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile {
382429 };
383430 };
384431
385 if (mapped_mem.len < symtab_cmd.stroff + symtab_cmd.strsize) return error.InvalidMachO;
386 if (mapped_mem[symtab_cmd.stroff + symtab_cmd.strsize - 1] != 0) return error.InvalidMachO;
387 const strtab = mapped_mem[symtab_cmd.stroff..][0 .. symtab_cmd.strsize - 1];
432 if (mapped_ofile.len < symtab_cmd.stroff + symtab_cmd.strsize) return error.InvalidMachO;
433 if (mapped_ofile[symtab_cmd.stroff + symtab_cmd.strsize - 1] != 0) return error.InvalidMachO;
434 const strtab = mapped_ofile[symtab_cmd.stroff..][0 .. symtab_cmd.strsize - 1];
388435
389436 const n_sym_bytes = symtab_cmd.nsyms * @sizeOf(macho.nlist_64);
390 if (mapped_mem.len < symtab_cmd.symoff + n_sym_bytes) return error.InvalidMachO;
391 const symtab_raw: []align(1) const macho.nlist_64 = @ptrCast(mapped_mem[symtab_cmd.symoff..][0..n_sym_bytes]);
437 if (mapped_ofile.len < symtab_cmd.symoff + n_sym_bytes) return error.InvalidMachO;
438 const symtab_raw: []align(1) const macho.nlist_64 = @ptrCast(mapped_ofile[symtab_cmd.symoff..][0..n_sym_bytes]);
392439
393440 // TODO handle tentative (common) symbols
394441 var symbols_by_name: std.ArrayHashMapUnmanaged(u32, void, void, true) = .empty;
......@@ -423,8 +470,8 @@ fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile {
423470 if (mem.eql(u8, "__" ++ section.name, sect.sectName())) break i;
424471 } else continue;
425472
426 if (mapped_mem.len < sect.offset + sect.size) return error.InvalidMachO;
427 const section_bytes = mapped_mem[sect.offset..][0..sect.size];
473 if (mapped_ofile.len < sect.offset + sect.size) return error.InvalidMachO;
474 const section_bytes = mapped_ofile[sect.offset..][0..sect.size];
428475 sections[section_index] = .{
429476 .data = section_bytes,
430477 .owned = false,
......@@ -455,7 +502,7 @@ fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile {
455502 };
456503
457504 return .{
458 .mapped_memory = mapped_mem,
505 .mapped_memory = all_mapped_memory,
459506 .dwarf = dwarf,
460507 .strtab = strtab,
461508 .symtab_raw = symtab_raw,