| ... | @@ -356,11 +356,58 @@ test { | ... | @@ -356,11 +356,58 @@ test { |
| 356 | _ = Symbol; | 356 | _ = Symbol; |
| 357 | } | 357 | } |
| 358 | | 358 | |
| 359 | fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile { | 359 | fn loadOFile(gpa: Allocator, o_file_name: []const u8) !OFile { |
| 360 | const mapped_mem = try mapDebugInfoFile(o_file_path); | 360 | const all_mapped_memory, const mapped_ofile = map: { |
| 361 | errdefer posix.munmap(mapped_mem); | 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); |
| 362 | | 409 | |
| 363 | var r: Io.Reader = .fixed(mapped_mem); | 410 | var r: Io.Reader = .fixed(mapped_ofile); |
| 364 | const hdr = r.takeStruct(macho.mach_header_64, .little) catch |err| switch (err) { | 411 | const hdr = r.takeStruct(macho.mach_header_64, .little) catch |err| switch (err) { |
| 365 | error.ReadFailed => unreachable, | 412 | error.ReadFailed => unreachable, |
| 366 | error.EndOfStream => return error.InvalidMachO, | 413 | error.EndOfStream => return error.InvalidMachO, |
| ... | @@ -370,7 +417,7 @@ fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile { | ... | @@ -370,7 +417,7 @@ fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile { |
| 370 | const seg_cmd: macho.LoadCommandIterator.LoadCommand, const symtab_cmd: macho.symtab_command = cmds: { | 417 | const seg_cmd: macho.LoadCommandIterator.LoadCommand, const symtab_cmd: macho.symtab_command = cmds: { |
| 371 | var seg_cmd: ?macho.LoadCommandIterator.LoadCommand = null; | 418 | var seg_cmd: ?macho.LoadCommandIterator.LoadCommand = null; |
| 372 | var symtab_cmd: ?macho.symtab_command = null; | 419 | 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)..]); |
| 374 | while (try it.next()) |lc| switch (lc.hdr.cmd) { | 421 | while (try it.next()) |lc| switch (lc.hdr.cmd) { |
| 375 | .SEGMENT_64 => seg_cmd = lc, | 422 | .SEGMENT_64 => seg_cmd = lc, |
| 376 | .SYMTAB => symtab_cmd = lc.cast(macho.symtab_command) orelse return error.InvalidMachO, | 423 | .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 { | ... | @@ -382,13 +429,13 @@ fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile { |
| 382 | }; | 429 | }; |
| 383 | }; | 430 | }; |
| 384 | | 431 | |
| 385 | if (mapped_mem.len < symtab_cmd.stroff + symtab_cmd.strsize) return error.InvalidMachO; | 432 | if (mapped_ofile.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; | 433 | if (mapped_ofile[symtab_cmd.stroff + symtab_cmd.strsize - 1] != 0) return error.InvalidMachO; |
| 387 | const strtab = mapped_mem[symtab_cmd.stroff..][0 .. symtab_cmd.strsize - 1]; | 434 | const strtab = mapped_ofile[symtab_cmd.stroff..][0 .. symtab_cmd.strsize - 1]; |
| 388 | | 435 | |
| 389 | const n_sym_bytes = symtab_cmd.nsyms * @sizeOf(macho.nlist_64); | 436 | 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; | 437 | if (mapped_ofile.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]); | 438 | const symtab_raw: []align(1) const macho.nlist_64 = @ptrCast(mapped_ofile[symtab_cmd.symoff..][0..n_sym_bytes]); |
| 392 | | 439 | |
| 393 | // TODO handle tentative (common) symbols | 440 | // TODO handle tentative (common) symbols |
| 394 | var symbols_by_name: std.ArrayHashMapUnmanaged(u32, void, void, true) = .empty; | 441 | 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 { | ... | @@ -423,8 +470,8 @@ fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile { |
| 423 | if (mem.eql(u8, "__" ++ section.name, sect.sectName())) break i; | 470 | if (mem.eql(u8, "__" ++ section.name, sect.sectName())) break i; |
| 424 | } else continue; | 471 | } else continue; |
| 425 | | 472 | |
| 426 | if (mapped_mem.len < sect.offset + sect.size) return error.InvalidMachO; | 473 | if (mapped_ofile.len < sect.offset + sect.size) return error.InvalidMachO; |
| 427 | const section_bytes = mapped_mem[sect.offset..][0..sect.size]; | 474 | const section_bytes = mapped_ofile[sect.offset..][0..sect.size]; |
| 428 | sections[section_index] = .{ | 475 | sections[section_index] = .{ |
| 429 | .data = section_bytes, | 476 | .data = section_bytes, |
| 430 | .owned = false, | 477 | .owned = false, |
| ... | @@ -455,7 +502,7 @@ fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile { | ... | @@ -455,7 +502,7 @@ fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile { |
| 455 | }; | 502 | }; |
| 456 | | 503 | |
| 457 | return .{ | 504 | return .{ |
| 458 | .mapped_memory = mapped_mem, | 505 | .mapped_memory = all_mapped_memory, |
| 459 | .dwarf = dwarf, | 506 | .dwarf = dwarf, |
| 460 | .strtab = strtab, | 507 | .strtab = strtab, |
| 461 | .symtab_raw = symtab_raw, | 508 | .symtab_raw = symtab_raw, |