authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-07-03 10:11:58+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-07-22 16:58:20+02:00
logb81c48d9856141a4a380bd8569825919e5bd8cfc
tree065f0f2e75d192255e00e2ce2b22c67675bd1825
parent7ec9a4f382fb73950e4b4c5f7e005c154f6ec294

macho: read the entire file contents into memory at once


4 files changed, 105 insertions(+), 125 deletions(-)

src/link/MachO.zig+2-2
...@@ -2895,7 +2895,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {...@@ -2895,7 +2895,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
28952895
2896 log.debug("resolving symbols in '{s}'", .{object.name});2896 log.debug("resolving symbols in '{s}'", .{object.name});
28972897
2898 for (object.symtab.items) |sym, id| {2898 for (object.symtab) |sym, id| {
2899 const sym_id = @intCast(u32, id);2899 const sym_id = @intCast(u32, id);
2900 const sym_name = object.getString(sym.n_strx);2900 const sym_name = object.getString(sym.n_strx);
29012901
...@@ -6600,7 +6600,7 @@ pub fn symbolIsTemp(sym: macho.nlist_64, sym_name: []const u8) bool {...@@ -6600,7 +6600,7 @@ pub fn symbolIsTemp(sym: macho.nlist_64, sym_name: []const u8) bool {
6600 return mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L");6600 return mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L");
6601}6601}
66026602
6603pub fn findFirst(comptime T: type, haystack: []T, start: usize, predicate: anytype) usize {6603pub fn findFirst(comptime T: type, haystack: []const T, start: usize, predicate: anytype) usize {
6604 if (!@hasDecl(@TypeOf(predicate), "predicate"))6604 if (!@hasDecl(@TypeOf(predicate), "predicate"))
6605 @compileError("Predicate is required to define fn predicate(@This(), T) bool");6605 @compileError("Predicate is required to define fn predicate(@This(), T) bool");
66066606
src/link/MachO/Atom.zig+3-3
...@@ -241,7 +241,7 @@ const RelocContext = struct {...@@ -241,7 +241,7 @@ const RelocContext = struct {
241 macho_file: *MachO,241 macho_file: *MachO,
242};242};
243243
244pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocContext) !void {244pub fn parseRelocs(self: *Atom, relocs: []const macho.relocation_info, context: RelocContext) !void {
245 const tracy = trace(@src());245 const tracy = trace(@src());
246 defer tracy.end();246 defer tracy.end();
247247
...@@ -284,7 +284,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC...@@ -284,7 +284,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC
284 }284 }
285285
286 assert(subtractor == null);286 assert(subtractor == null);
287 const sym = context.object.symtab.items[rel.r_symbolnum];287 const sym = context.object.symtab[rel.r_symbolnum];
288 if (sym.sect() and !sym.ext()) {288 if (sym.sect() and !sym.ext()) {
289 subtractor = context.object.symbol_mapping.get(rel.r_symbolnum).?;289 subtractor = context.object.symbol_mapping.get(rel.r_symbolnum).?;
290 } else {290 } else {
...@@ -350,7 +350,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC...@@ -350,7 +350,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC
350 break :target Relocation.Target{ .local = local_sym_index };350 break :target Relocation.Target{ .local = local_sym_index };
351 }351 }
352352
353 const sym = context.object.symtab.items[rel.r_symbolnum];353 const sym = context.object.symtab[rel.r_symbolnum];
354 const sym_name = context.object.getString(sym.n_strx);354 const sym_name = context.object.getString(sym.n_strx);
355355
356 if (sym.sect() and !sym.ext()) {356 if (sym.sect() and !sym.ext()) {
src/link/MachO/Object.zig+99-119
...@@ -20,9 +20,14 @@ const MachO = @import("../MachO.zig");...@@ -20,9 +20,14 @@ const MachO = @import("../MachO.zig");
20file: fs.File,20file: fs.File,
21name: []const u8,21name: []const u8,
2222
23/// Data contents of the file. Includes sections, and data of load commands.
24/// Excludes the backing memory for the header and load commands.
25/// Initialized in `parse`.
26contents: []const u8 = undefined,
27
23file_offset: ?u32 = null,28file_offset: ?u32 = null,
2429
25header: ?macho.mach_header_64 = null,30header: macho.mach_header_64 = undefined,
2631
27load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{},32load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{},
2833
...@@ -41,9 +46,9 @@ dwarf_debug_line_index: ?u16 = null,...@@ -41,9 +46,9 @@ dwarf_debug_line_index: ?u16 = null,
41dwarf_debug_line_str_index: ?u16 = null,46dwarf_debug_line_str_index: ?u16 = null,
42dwarf_debug_ranges_index: ?u16 = null,47dwarf_debug_ranges_index: ?u16 = null,
4348
44symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},49symtab: []const macho.nlist_64 = &.{},
45strtab: std.ArrayListUnmanaged(u8) = .{},50strtab: []const u8 = &.{},
46data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},51data_in_code_entries: []const macho.data_in_code_entry = &.{},
4752
48// Debug info53// Debug info
49debug_info: ?DebugInfo = null,54debug_info: ?DebugInfo = null,
...@@ -65,41 +70,41 @@ analyzed: bool = false,...@@ -65,41 +70,41 @@ analyzed: bool = false,
6570
66const DebugInfo = struct {71const DebugInfo = struct {
67 inner: dwarf.DwarfInfo,72 inner: dwarf.DwarfInfo,
68 debug_info: []u8,73 debug_info: []const u8,
69 debug_abbrev: []u8,74 debug_abbrev: []const u8,
70 debug_str: []u8,75 debug_str: []const u8,
71 debug_line: []u8,76 debug_line: []const u8,
72 debug_line_str: []u8,77 debug_line_str: []const u8,
73 debug_ranges: []u8,78 debug_ranges: []const u8,
7479
75 pub fn parseFromObject(allocator: Allocator, object: *const Object) !?DebugInfo {80 pub fn parseFromObject(allocator: Allocator, object: *const Object) !?DebugInfo {
76 var debug_info = blk: {81 var debug_info = blk: {
77 const index = object.dwarf_debug_info_index orelse return null;82 const index = object.dwarf_debug_info_index orelse return null;
78 break :blk try object.readSection(allocator, index);83 break :blk object.getSectionContents(index);
79 };84 };
80 var debug_abbrev = blk: {85 var debug_abbrev = blk: {
81 const index = object.dwarf_debug_abbrev_index orelse return null;86 const index = object.dwarf_debug_abbrev_index orelse return null;
82 break :blk try object.readSection(allocator, index);87 break :blk object.getSectionContents(index);
83 };88 };
84 var debug_str = blk: {89 var debug_str = blk: {
85 const index = object.dwarf_debug_str_index orelse return null;90 const index = object.dwarf_debug_str_index orelse return null;
86 break :blk try object.readSection(allocator, index);91 break :blk object.getSectionContents(index);
87 };92 };
88 var debug_line = blk: {93 var debug_line = blk: {
89 const index = object.dwarf_debug_line_index orelse return null;94 const index = object.dwarf_debug_line_index orelse return null;
90 break :blk try object.readSection(allocator, index);95 break :blk object.getSectionContents(index);
91 };96 };
92 var debug_line_str = blk: {97 var debug_line_str = blk: {
93 if (object.dwarf_debug_line_str_index) |ind| {98 if (object.dwarf_debug_line_str_index) |ind| {
94 break :blk try object.readSection(allocator, ind);99 break :blk object.getSectionContents(ind);
95 }100 }
96 break :blk try allocator.alloc(u8, 0);101 break :blk &[0]u8{};
97 };102 };
98 var debug_ranges = blk: {103 var debug_ranges = blk: {
99 if (object.dwarf_debug_ranges_index) |ind| {104 if (object.dwarf_debug_ranges_index) |ind| {
100 break :blk try object.readSection(allocator, ind);105 break :blk object.getSectionContents(ind);
101 }106 }
102 break :blk try allocator.alloc(u8, 0);107 break :blk &[0]u8{};
103 };108 };
104109
105 var inner: dwarf.DwarfInfo = .{110 var inner: dwarf.DwarfInfo = .{
...@@ -125,12 +130,6 @@ const DebugInfo = struct {...@@ -125,12 +130,6 @@ const DebugInfo = struct {
125 }130 }
126131
127 pub fn deinit(self: *DebugInfo, allocator: Allocator) void {132 pub fn deinit(self: *DebugInfo, allocator: Allocator) void {
128 allocator.free(self.debug_info);
129 allocator.free(self.debug_abbrev);
130 allocator.free(self.debug_str);
131 allocator.free(self.debug_line);
132 allocator.free(self.debug_line_str);
133 allocator.free(self.debug_ranges);
134 self.inner.deinit(allocator);133 self.inner.deinit(allocator);
135 }134 }
136};135};
...@@ -140,9 +139,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void {...@@ -140,9 +139,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
140 lc.deinit(allocator);139 lc.deinit(allocator);
141 }140 }
142 self.load_commands.deinit(allocator);141 self.load_commands.deinit(allocator);
143 self.data_in_code_entries.deinit(allocator);142 allocator.free(self.contents);
144 self.symtab.deinit(allocator);
145 self.strtab.deinit(allocator);
146 self.sections_as_symbols.deinit(allocator);143 self.sections_as_symbols.deinit(allocator);
147 self.symbol_mapping.deinit(allocator);144 self.symbol_mapping.deinit(allocator);
148 self.reverse_symbol_mapping.deinit(allocator);145 self.reverse_symbol_mapping.deinit(allocator);
...@@ -155,14 +152,6 @@ pub fn deinit(self: *Object, allocator: Allocator) void {...@@ -155,14 +152,6 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
155 if (self.debug_info) |*db| {152 if (self.debug_info) |*db| {
156 db.deinit(allocator);153 db.deinit(allocator);
157 }154 }
158
159 if (self.tu_name) |n| {
160 allocator.free(n);
161 }
162
163 if (self.tu_comp_dir) |n| {
164 allocator.free(n);
165 }
166}155}
167156
168pub fn free(self: *Object, allocator: Allocator, macho_file: *MachO) void {157pub fn free(self: *Object, allocator: Allocator, macho_file: *MachO) void {
...@@ -233,21 +222,28 @@ fn freeAtoms(self: *Object, macho_file: *MachO) void {...@@ -233,21 +222,28 @@ fn freeAtoms(self: *Object, macho_file: *MachO) void {
233}222}
234223
235pub fn parse(self: *Object, allocator: Allocator, target: std.Target) !void {224pub fn parse(self: *Object, allocator: Allocator, target: std.Target) !void {
236 const reader = self.file.reader();225 const file_stat = try self.file.stat();
237 if (self.file_offset) |offset| {226 const file_size = math.cast(usize, file_stat.size) orelse return error.Overflow;
238 try reader.context.seekTo(offset);227 self.contents = try self.file.readToEndAlloc(allocator, file_size);
228
229 var stream = std.io.fixedBufferStream(self.contents);
230 const reader = stream.reader();
231
232 const file_offset = self.file_offset orelse 0;
233 if (file_offset > 0) {
234 try reader.context.seekTo(file_offset);
239 }235 }
240236
241 const header = try reader.readStruct(macho.mach_header_64);237 self.header = try reader.readStruct(macho.mach_header_64);
242 if (header.filetype != macho.MH_OBJECT) {238 if (self.header.filetype != macho.MH_OBJECT) {
243 log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{239 log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{
244 macho.MH_OBJECT,240 macho.MH_OBJECT,
245 header.filetype,241 self.header.filetype,
246 });242 });
247 return error.NotObject;243 return error.NotObject;
248 }244 }
249245
250 const this_arch: std.Target.Cpu.Arch = switch (header.cputype) {246 const this_arch: std.Target.Cpu.Arch = switch (self.header.cputype) {
251 macho.CPU_TYPE_ARM64 => .aarch64,247 macho.CPU_TYPE_ARM64 => .aarch64,
252 macho.CPU_TYPE_X86_64 => .x86_64,248 macho.CPU_TYPE_X86_64 => .x86_64,
253 else => |value| {249 else => |value| {
...@@ -260,22 +256,10 @@ pub fn parse(self: *Object, allocator: Allocator, target: std.Target) !void {...@@ -260,22 +256,10 @@ pub fn parse(self: *Object, allocator: Allocator, target: std.Target) !void {
260 return error.MismatchedCpuArchitecture;256 return error.MismatchedCpuArchitecture;
261 }257 }
262258
263 self.header = header;259 try self.load_commands.ensureUnusedCapacity(allocator, self.header.ncmds);
264
265 try self.readLoadCommands(allocator, reader);
266 try self.parseSymtab(allocator);
267 try self.parseDataInCode(allocator);
268 try self.parseDebugInfo(allocator);
269}
270
271pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !void {
272 const header = self.header orelse unreachable; // Unreachable here signifies a fatal unexplored condition.
273 const offset = self.file_offset orelse 0;
274
275 try self.load_commands.ensureUnusedCapacity(allocator, header.ncmds);
276260
277 var i: u16 = 0;261 var i: u16 = 0;
278 while (i < header.ncmds) : (i += 1) {262 while (i < self.header.ncmds) : (i += 1) {
279 var cmd = try macho.LoadCommand.read(allocator, reader);263 var cmd = try macho.LoadCommand.read(allocator, reader);
280 switch (cmd.cmd()) {264 switch (cmd.cmd()) {
281 .SEGMENT_64 => {265 .SEGMENT_64 => {
...@@ -305,18 +289,18 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v...@@ -305,18 +289,18 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v
305 }289 }
306 }290 }
307291
308 sect.offset += offset;292 sect.offset += file_offset;
309 if (sect.reloff > 0) {293 if (sect.reloff > 0) {
310 sect.reloff += offset;294 sect.reloff += file_offset;
311 }295 }
312 }296 }
313297
314 seg.inner.fileoff += offset;298 seg.inner.fileoff += file_offset;
315 },299 },
316 .SYMTAB => {300 .SYMTAB => {
317 self.symtab_cmd_index = i;301 self.symtab_cmd_index = i;
318 cmd.symtab.symoff += offset;302 cmd.symtab.symoff += file_offset;
319 cmd.symtab.stroff += offset;303 cmd.symtab.stroff += file_offset;
320 },304 },
321 .DYSYMTAB => {305 .DYSYMTAB => {
322 self.dysymtab_cmd_index = i;306 self.dysymtab_cmd_index = i;
...@@ -326,7 +310,7 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v...@@ -326,7 +310,7 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v
326 },310 },
327 .DATA_IN_CODE => {311 .DATA_IN_CODE => {
328 self.data_in_code_cmd_index = i;312 self.data_in_code_cmd_index = i;
329 cmd.linkedit_data.dataoff += offset;313 cmd.linkedit_data.dataoff += file_offset;
330 },314 },
331 else => {315 else => {
332 log.debug("Unknown load command detected: 0x{x}.", .{cmd.cmd()});316 log.debug("Unknown load command detected: 0x{x}.", .{cmd.cmd()});
...@@ -334,6 +318,10 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v...@@ -334,6 +318,10 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v
334 }318 }
335 self.load_commands.appendAssumeCapacity(cmd);319 self.load_commands.appendAssumeCapacity(cmd);
336 }320 }
321
322 self.parseSymtab();
323 self.parseDataInCode();
324 try self.parseDebugInfo(allocator);
337}325}
338326
339const NlistWithIndex = struct {327const NlistWithIndex = struct {
...@@ -373,7 +361,11 @@ const NlistWithIndex = struct {...@@ -373,7 +361,11 @@ const NlistWithIndex = struct {
373 }361 }
374};362};
375363
376fn filterDice(dices: []macho.data_in_code_entry, start_addr: u64, end_addr: u64) []macho.data_in_code_entry {364fn filterDice(
365 dices: []const macho.data_in_code_entry,
366 start_addr: u64,
367 end_addr: u64,
368) []const macho.data_in_code_entry {
377 const Predicate = struct {369 const Predicate = struct {
378 addr: u64,370 addr: u64,
379371
...@@ -400,10 +392,10 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !...@@ -400,10 +392,10 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
400 // local < extern defined < undefined. Unfortunately, this is not guaranteed! For instance,392 // local < extern defined < undefined. Unfortunately, this is not guaranteed! For instance,
401 // the GO compiler does not necessarily respect that therefore we sort immediately by type393 // the GO compiler does not necessarily respect that therefore we sort immediately by type
402 // and address within.394 // and address within.
403 var sorted_all_nlists = try std.ArrayList(NlistWithIndex).initCapacity(allocator, self.symtab.items.len);395 var sorted_all_nlists = try std.ArrayList(NlistWithIndex).initCapacity(allocator, self.symtab.len);
404 defer sorted_all_nlists.deinit();396 defer sorted_all_nlists.deinit();
405397
406 for (self.symtab.items) |nlist, index| {398 for (self.symtab) |nlist, index| {
407 sorted_all_nlists.appendAssumeCapacity(.{399 sorted_all_nlists.appendAssumeCapacity(.{
408 .nlist = nlist,400 .nlist = nlist,
409 .index = @intCast(u32, index),401 .index = @intCast(u32, index),
...@@ -439,16 +431,20 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !...@@ -439,16 +431,20 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
439 continue;431 continue;
440 };432 };
441433
434 const is_zerofill = blk: {
435 const section_type = sect.type_();
436 break :blk section_type == macho.S_ZEROFILL or section_type == macho.S_THREAD_LOCAL_ZEROFILL;
437 };
438
442 // Read section's code439 // Read section's code
443 var code = try allocator.alloc(u8, @intCast(usize, sect.size));440 const code: ?[]const u8 = if (!is_zerofill) self.getSectionContents(sect_id) else null;
444 defer allocator.free(code);
445 _ = try self.file.preadAll(code, sect.offset);
446441
447 // Read section's list of relocations442 // Read section's list of relocations
448 var raw_relocs = try allocator.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info));443 const raw_relocs = self.contents[sect.reloff..][0 .. sect.nreloc * @sizeOf(macho.relocation_info)];
449 defer allocator.free(raw_relocs);444 const relocs = mem.bytesAsSlice(
450 _ = try self.file.preadAll(raw_relocs, sect.reloff);445 macho.relocation_info,
451 const relocs = mem.bytesAsSlice(macho.relocation_info, raw_relocs);446 @alignCast(@alignOf(macho.relocation_info), raw_relocs),
447 );
452448
453 // Symbols within this section only.449 // Symbols within this section only.
454 const filtered_nlists = NlistWithIndex.filterInSection(sorted_nlists, sect);450 const filtered_nlists = NlistWithIndex.filterInSection(sorted_nlists, sect);
...@@ -456,7 +452,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !...@@ -456,7 +452,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
456 macho_file.has_dices = macho_file.has_dices or blk: {452 macho_file.has_dices = macho_file.has_dices or blk: {
457 if (self.text_section_index) |index| {453 if (self.text_section_index) |index| {
458 if (index != id) break :blk false;454 if (index != id) break :blk false;
459 if (self.data_in_code_entries.items.len == 0) break :blk false;455 if (self.data_in_code_entries.len == 0) break :blk false;
460 break :blk true;456 break :blk true;
461 }457 }
462 break :blk false;458 break :blk false;
...@@ -482,16 +478,12 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !...@@ -482,16 +478,12 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
482 const aligned_size = mem.alignForwardGeneric(u64, sect.size, alignment);478 const aligned_size = mem.alignForwardGeneric(u64, sect.size, alignment);
483 const atom = try macho_file.createEmptyAtom(atom_local_sym_index, aligned_size, sect.@"align");479 const atom = try macho_file.createEmptyAtom(atom_local_sym_index, aligned_size, sect.@"align");
484480
485 const is_zerofill = blk: {481 if (code) |cc| {
486 const section_type = sect.type_();482 assert(!is_zerofill);
487 break :blk section_type == macho.S_ZEROFILL or section_type == macho.S_THREAD_LOCAL_ZEROFILL;483 mem.copy(u8, atom.code.items, cc);
488 };
489 if (!is_zerofill) {
490 mem.copy(u8, atom.code.items, code);
491 }484 }
492485
493 // TODO stage2 bug: @alignCast shouldn't be needed486 try atom.parseRelocs(relocs, .{
494 try atom.parseRelocs(@alignCast(@alignOf(macho.relocation_info), relocs), .{
495 .base_addr = sect.addr,487 .base_addr = sect.addr,
496 .allocator = allocator,488 .allocator = allocator,
497 .object = self,489 .object = self,
...@@ -499,7 +491,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !...@@ -499,7 +491,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
499 });491 });
500492
501 if (macho_file.has_dices) {493 if (macho_file.has_dices) {
502 const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + sect.size);494 const dices = filterDice(self.data_in_code_entries, sect.addr, sect.addr + sect.size);
503 try atom.dices.ensureTotalCapacity(allocator, dices.len);495 try atom.dices.ensureTotalCapacity(allocator, dices.len);
504496
505 for (dices) |dice| {497 for (dices) |dice| {
...@@ -562,20 +554,13 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !...@@ -562,20 +554,13 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
562 }554 }
563}555}
564556
565fn parseSymtab(self: *Object, allocator: Allocator) !void {557fn parseSymtab(self: *Object) void {
566 const index = self.symtab_cmd_index orelse return;558 const index = self.symtab_cmd_index orelse return;
567 const symtab_cmd = self.load_commands.items[index].symtab;559 const symtab = self.load_commands.items[index].symtab;
568560 const symtab_size = @sizeOf(macho.nlist_64) * symtab.nsyms;
569 var symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);561 const raw_symtab = self.contents[symtab.symoff..][0..symtab_size];
570 defer allocator.free(symtab);562 self.symtab = mem.bytesAsSlice(macho.nlist_64, @alignCast(@alignOf(macho.nlist_64), raw_symtab));
571 _ = try self.file.preadAll(symtab, symtab_cmd.symoff);563 self.strtab = self.contents[symtab.stroff..][0..symtab.strsize];
572 const slice = @alignCast(@alignOf(macho.nlist_64), mem.bytesAsSlice(macho.nlist_64, symtab));
573 try self.symtab.appendSlice(allocator, slice);
574
575 var strtab = try allocator.alloc(u8, symtab_cmd.strsize);
576 defer allocator.free(strtab);
577 _ = try self.file.preadAll(strtab, symtab_cmd.stroff);
578 try self.strtab.appendSlice(allocator, strtab);
579}564}
580565
581pub fn parseDebugInfo(self: *Object, allocator: Allocator) !void {566pub fn parseDebugInfo(self: *Object, allocator: Allocator) !void {
...@@ -599,8 +584,8 @@ pub fn parseDebugInfo(self: *Object, allocator: Allocator) !void {...@@ -599,8 +584,8 @@ pub fn parseDebugInfo(self: *Object, allocator: Allocator) !void {
599 const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT.comp_dir);584 const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT.comp_dir);
600585
601 self.debug_info = debug_info;586 self.debug_info = debug_info;
602 self.tu_name = try allocator.dupe(u8, name);587 self.tu_name = name;
603 self.tu_comp_dir = try allocator.dupe(u8, comp_dir);588 self.tu_comp_dir = comp_dir;
604589
605 if (self.mtime == null) {590 if (self.mtime == null) {
606 self.mtime = mtime: {591 self.mtime = mtime: {
...@@ -610,34 +595,29 @@ pub fn parseDebugInfo(self: *Object, allocator: Allocator) !void {...@@ -610,34 +595,29 @@ pub fn parseDebugInfo(self: *Object, allocator: Allocator) !void {
610 }595 }
611}596}
612597
613pub fn parseDataInCode(self: *Object, allocator: Allocator) !void {598pub fn parseDataInCode(self: *Object) void {
614 const index = self.data_in_code_cmd_index orelse return;599 const index = self.data_in_code_cmd_index orelse return;
615 const data_in_code = self.load_commands.items[index].linkedit_data;600 const data_in_code = self.load_commands.items[index].linkedit_data;
616601 const raw_dice = self.contents[data_in_code.dataoff..][0..data_in_code.datasize];
617 var buffer = try allocator.alloc(u8, data_in_code.datasize);602 self.data_in_code_entries = mem.bytesAsSlice(
618 defer allocator.free(buffer);603 macho.data_in_code_entry,
619604 @alignCast(@alignOf(macho.data_in_code_entry), raw_dice),
620 _ = try self.file.preadAll(buffer, data_in_code.dataoff);605 );
621
622 var stream = io.fixedBufferStream(buffer);
623 var reader = stream.reader();
624 while (true) {
625 const dice = reader.readStruct(macho.data_in_code_entry) catch |err| switch (err) {
626 error.EndOfStream => break,
627 };
628 try self.data_in_code_entries.append(allocator, dice);
629 }
630}606}
631607
632fn readSection(self: Object, allocator: Allocator, index: u16) ![]u8 {608fn getSectionContents(self: Object, sect_id: u16) []const u8 {
633 const seg = self.load_commands.items[self.segment_cmd_index.?].segment;609 const seg = self.load_commands.items[self.segment_cmd_index.?].segment;
634 const sect = seg.sections.items[index];610 const sect = seg.sections.items[sect_id];
635 var buffer = try allocator.alloc(u8, @intCast(usize, sect.size));611 log.debug("getting {s},{s} data at 0x{x} - 0x{x}", .{
636 _ = try self.file.preadAll(buffer, sect.offset);612 sect.segName(),
637 return buffer;613 sect.sectName(),
614 sect.offset,
615 sect.offset + sect.size,
616 });
617 return self.contents[sect.offset..][0..sect.size];
638}618}
639619
640pub fn getString(self: Object, off: u32) []const u8 {620pub fn getString(self: Object, off: u32) []const u8 {
641 assert(off < self.strtab.items.len);621 assert(off < self.strtab.len);
642 return mem.sliceTo(@ptrCast([*:0]const u8, self.strtab.items.ptr + off), 0);622 return mem.sliceTo(@ptrCast([*:0]const u8, self.strtab.ptr + off), 0);
643}623}
test/cases/recursive_inline_function.0.zig+1-1
...@@ -9,5 +9,5 @@ inline fn fibonacci(n: usize) usize {...@@ -9,5 +9,5 @@ inline fn fibonacci(n: usize) usize {
9}9}
1010
11// run11// run
12// target=x86_64-linux,arm-linux,x86_64-macos,wasm32-wasi12// target=x86_64-linux,arm-linux,wasm32-wasi
13//13//