| ... | @@ -10,20 +10,22 @@ const macho = std.macho; | ... | @@ -10,20 +10,22 @@ const macho = std.macho; |
| 10 | const math = std.math; | 10 | const math = std.math; |
| 11 | const mem = std.mem; | 11 | const mem = std.mem; |
| 12 | const sort = std.sort; | 12 | const sort = std.sort; |
| | 13 | const commands = @import("commands.zig"); |
| | 14 | const segmentName = commands.segmentName; |
| | 15 | const sectionName = commands.sectionName; |
| 13 | | 16 | |
| 14 | const Allocator = mem.Allocator; | 17 | const Allocator = mem.Allocator; |
| 15 | const Arch = std.Target.Cpu.Arch; | 18 | const Arch = std.Target.Cpu.Arch; |
| | 19 | const LoadCommand = commands.LoadCommand; |
| 16 | const MachO = @import("../MachO.zig"); | 20 | const MachO = @import("../MachO.zig"); |
| 17 | const TextBlock = @import("TextBlock.zig"); | 21 | const TextBlock = @import("TextBlock.zig"); |
| 18 | | 22 | |
| 19 | usingnamespace @import("commands.zig"); | 23 | file: fs.File, |
| | 24 | name: []const u8, |
| 20 | | 25 | |
| 21 | allocator: *Allocator, | | |
| 22 | arch: ?Arch = null, | | |
| 23 | header: ?macho.mach_header_64 = null, | | |
| 24 | file: ?fs.File = null, | | |
| 25 | file_offset: ?u32 = null, | 26 | file_offset: ?u32 = null, |
| 26 | name: ?[]const u8 = null, | 27 | |
| | 28 | header: ?macho.mach_header_64 = null, |
| 27 | | 29 | |
| 28 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, | 30 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, |
| 29 | | 31 | |
| ... | @@ -139,15 +141,13 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u | ... | @@ -139,15 +141,13 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u |
| 139 | errdefer allocator.free(name); | 141 | errdefer allocator.free(name); |
| 140 | | 142 | |
| 141 | object.* = .{ | 143 | object.* = .{ |
| 142 | .allocator = allocator, | | |
| 143 | .arch = arch, | | |
| 144 | .name = name, | 144 | .name = name, |
| 145 | .file = file, | 145 | .file = file, |
| 146 | }; | 146 | }; |
| 147 | | 147 | |
| 148 | object.parse() catch |err| switch (err) { | 148 | object.parse(allocator, arch) catch |err| switch (err) { |
| 149 | error.EndOfStream, error.NotObject => { | 149 | error.EndOfStream, error.NotObject => { |
| 150 | object.deinit(); | 150 | object.deinit(allocator); |
| 151 | allocator.destroy(object); | 151 | allocator.destroy(object); |
| 152 | return null; | 152 | return null; |
| 153 | }, | 153 | }, |
| ... | @@ -157,44 +157,35 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u | ... | @@ -157,44 +157,35 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u |
| 157 | return object; | 157 | return object; |
| 158 | } | 158 | } |
| 159 | | 159 | |
| 160 | pub fn deinit(self: *Object) void { | 160 | pub fn deinit(self: *Object, allocator: *Allocator) void { |
| 161 | for (self.load_commands.items) |*lc| { | 161 | for (self.load_commands.items) |*lc| { |
| 162 | lc.deinit(self.allocator); | 162 | lc.deinit(allocator); |
| 163 | } | 163 | } |
| 164 | self.load_commands.deinit(self.allocator); | 164 | self.load_commands.deinit(allocator); |
| 165 | self.data_in_code_entries.deinit(self.allocator); | 165 | self.data_in_code_entries.deinit(allocator); |
| 166 | self.symtab.deinit(self.allocator); | 166 | self.symtab.deinit(allocator); |
| 167 | self.strtab.deinit(self.allocator); | 167 | self.strtab.deinit(allocator); |
| 168 | self.text_blocks.deinit(self.allocator); | 168 | self.text_blocks.deinit(allocator); |
| 169 | self.sections_as_symbols.deinit(self.allocator); | 169 | self.sections_as_symbols.deinit(allocator); |
| 170 | self.symbol_mapping.deinit(self.allocator); | 170 | self.symbol_mapping.deinit(allocator); |
| 171 | self.reverse_symbol_mapping.deinit(self.allocator); | 171 | self.reverse_symbol_mapping.deinit(allocator); |
| | 172 | allocator.free(self.name); |
| 172 | | 173 | |
| 173 | if (self.debug_info) |*db| { | 174 | if (self.debug_info) |*db| { |
| 174 | db.deinit(self.allocator); | 175 | db.deinit(allocator); |
| 175 | } | 176 | } |
| 176 | | 177 | |
| 177 | if (self.tu_name) |n| { | 178 | if (self.tu_name) |n| { |
| 178 | self.allocator.free(n); | 179 | allocator.free(n); |
| 179 | } | 180 | } |
| 180 | | 181 | |
| 181 | if (self.tu_comp_dir) |n| { | 182 | if (self.tu_comp_dir) |n| { |
| 182 | self.allocator.free(n); | 183 | allocator.free(n); |
| 183 | } | | |
| 184 | | | |
| 185 | if (self.name) |n| { | | |
| 186 | self.allocator.free(n); | | |
| 187 | } | | |
| 188 | } | | |
| 189 | | | |
| 190 | pub fn closeFile(self: Object) void { | | |
| 191 | if (self.file) |f| { | | |
| 192 | f.close(); | | |
| 193 | } | 184 | } |
| 194 | } | 185 | } |
| 195 | | 186 | |
| 196 | pub fn parse(self: *Object) !void { | 187 | pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void { |
| 197 | var reader = self.file.?.reader(); | 188 | var reader = self.file.reader(); |
| 198 | if (self.file_offset) |offset| { | 189 | if (self.file_offset) |offset| { |
| 199 | try reader.context.seekTo(offset); | 190 | try reader.context.seekTo(offset); |
| 200 | } | 191 | } |
| ... | @@ -214,26 +205,28 @@ pub fn parse(self: *Object) !void { | ... | @@ -214,26 +205,28 @@ pub fn parse(self: *Object) !void { |
| 214 | return error.UnsupportedCpuArchitecture; | 205 | return error.UnsupportedCpuArchitecture; |
| 215 | }, | 206 | }, |
| 216 | }; | 207 | }; |
| 217 | if (this_arch != self.arch.?) { | 208 | if (this_arch != arch) { |
| 218 | log.err("mismatched cpu architecture: expected {s}, found {s}", .{ self.arch.?, this_arch }); | 209 | log.err("mismatched cpu architecture: expected {s}, found {s}", .{ arch, this_arch }); |
| 219 | return error.MismatchedCpuArchitecture; | 210 | return error.MismatchedCpuArchitecture; |
| 220 | } | 211 | } |
| 221 | | 212 | |
| 222 | self.header = header; | 213 | self.header = header; |
| 223 | | 214 | |
| 224 | try self.readLoadCommands(reader); | 215 | try self.readLoadCommands(allocator, reader); |
| 225 | try self.parseSymtab(); | 216 | try self.parseSymtab(allocator); |
| 226 | try self.parseDataInCode(); | 217 | try self.parseDataInCode(allocator); |
| 227 | try self.parseDebugInfo(); | 218 | try self.parseDebugInfo(allocator); |
| 228 | } | 219 | } |
| 229 | | 220 | |
| 230 | pub fn readLoadCommands(self: *Object, reader: anytype) !void { | 221 | pub fn readLoadCommands(self: *Object, allocator: *Allocator, reader: anytype) !void { |
| | 222 | const header = self.header orelse unreachable; // Unreachable here signifies a fatal unexplored condition. |
| 231 | const offset = self.file_offset orelse 0; | 223 | const offset = self.file_offset orelse 0; |
| 232 | try self.load_commands.ensureCapacity(self.allocator, self.header.?.ncmds); | 224 | |
| | 225 | try self.load_commands.ensureCapacity(allocator, header.ncmds); |
| 233 | | 226 | |
| 234 | var i: u16 = 0; | 227 | var i: u16 = 0; |
| 235 | while (i < self.header.?.ncmds) : (i += 1) { | 228 | while (i < header.ncmds) : (i += 1) { |
| 236 | var cmd = try LoadCommand.read(self.allocator, reader); | 229 | var cmd = try LoadCommand.read(allocator, reader); |
| 237 | switch (cmd.cmd()) { | 230 | switch (cmd.cmd()) { |
| 238 | macho.LC_SEGMENT_64 => { | 231 | macho.LC_SEGMENT_64 => { |
| 239 | self.segment_cmd_index = i; | 232 | self.segment_cmd_index = i; |
| ... | @@ -347,26 +340,25 @@ fn filterDice(dices: []macho.data_in_code_entry, start_addr: u64, end_addr: u64) | ... | @@ -347,26 +340,25 @@ fn filterDice(dices: []macho.data_in_code_entry, start_addr: u64, end_addr: u64) |
| 347 | return dices[start..end]; | 340 | return dices[start..end]; |
| 348 | } | 341 | } |
| 349 | | 342 | |
| 350 | const TextBlockParser = struct { | 343 | const Context = struct { |
| 351 | allocator: *Allocator, | 344 | allocator: *Allocator, |
| | 345 | object: *Object, |
| | 346 | macho_file: *MachO, |
| | 347 | match: MachO.MatchingSection, |
| | 348 | }; |
| | 349 | |
| | 350 | const TextBlockParser = struct { |
| 352 | section: macho.section_64, | 351 | section: macho.section_64, |
| 353 | code: []u8, | 352 | code: []u8, |
| 354 | relocs: []macho.relocation_info, | 353 | relocs: []macho.relocation_info, |
| 355 | object: *Object, | | |
| 356 | macho_file: *MachO, | | |
| 357 | nlists: []NlistWithIndex, | 354 | nlists: []NlistWithIndex, |
| 358 | index: u32 = 0, | 355 | index: u32 = 0, |
| 359 | match: MachO.MatchingSection, | | |
| 360 | | 356 | |
| 361 | fn peek(self: *TextBlockParser) ?NlistWithIndex { | 357 | fn peek(self: TextBlockParser) ?NlistWithIndex { |
| 362 | return if (self.index + 1 < self.nlists.len) self.nlists[self.index + 1] else null; | 358 | return if (self.index + 1 < self.nlists.len) self.nlists[self.index + 1] else null; |
| 363 | } | 359 | } |
| 364 | | 360 | |
| 365 | const SeniorityContext = struct { | 361 | fn lessThanBySeniority(context: Context, lhs: NlistWithIndex, rhs: NlistWithIndex) bool { |
| 366 | object: *Object, | | |
| 367 | }; | | |
| 368 | | | |
| 369 | fn lessThanBySeniority(context: SeniorityContext, lhs: NlistWithIndex, rhs: NlistWithIndex) bool { | | |
| 370 | if (!MachO.symbolIsExt(rhs.nlist)) { | 362 | if (!MachO.symbolIsExt(rhs.nlist)) { |
| 371 | return MachO.symbolIsTemp(lhs.nlist, context.object.getString(lhs.nlist.n_strx)); | 363 | return MachO.symbolIsTemp(lhs.nlist, context.object.getString(lhs.nlist.n_strx)); |
| 372 | } else if (MachO.symbolIsPext(rhs.nlist) or MachO.symbolIsWeakDef(rhs.nlist)) { | 364 | } else if (MachO.symbolIsPext(rhs.nlist) or MachO.symbolIsWeakDef(rhs.nlist)) { |
| ... | @@ -376,10 +368,10 @@ const TextBlockParser = struct { | ... | @@ -376,10 +368,10 @@ const TextBlockParser = struct { |
| 376 | } | 368 | } |
| 377 | } | 369 | } |
| 378 | | 370 | |
| 379 | pub fn next(self: *TextBlockParser) !?*TextBlock { | 371 | pub fn next(self: *TextBlockParser, context: Context) !?*TextBlock { |
| 380 | if (self.index == self.nlists.len) return null; | 372 | if (self.index == self.nlists.len) return null; |
| 381 | | 373 | |
| 382 | var aliases = std.ArrayList(NlistWithIndex).init(self.allocator); | 374 | var aliases = std.ArrayList(NlistWithIndex).init(context.allocator); |
| 383 | defer aliases.deinit(); | 375 | defer aliases.deinit(); |
| 384 | | 376 | |
| 385 | const next_nlist: ?NlistWithIndex = blk: while (true) { | 377 | const next_nlist: ?NlistWithIndex = blk: while (true) { |
| ... | @@ -397,7 +389,7 @@ const TextBlockParser = struct { | ... | @@ -397,7 +389,7 @@ const TextBlockParser = struct { |
| 397 | } else null; | 389 | } else null; |
| 398 | | 390 | |
| 399 | for (aliases.items) |*nlist_with_index| { | 391 | for (aliases.items) |*nlist_with_index| { |
| 400 | nlist_with_index.index = self.object.symbol_mapping.get(nlist_with_index.index) orelse unreachable; | 392 | nlist_with_index.index = context.object.symbol_mapping.get(nlist_with_index.index) orelse unreachable; |
| 401 | } | 393 | } |
| 402 | | 394 | |
| 403 | if (aliases.items.len > 1) { | 395 | if (aliases.items.len > 1) { |
| ... | @@ -405,14 +397,14 @@ const TextBlockParser = struct { | ... | @@ -405,14 +397,14 @@ const TextBlockParser = struct { |
| 405 | sort.sort( | 397 | sort.sort( |
| 406 | NlistWithIndex, | 398 | NlistWithIndex, |
| 407 | aliases.items, | 399 | aliases.items, |
| 408 | SeniorityContext{ .object = self.object }, | 400 | context, |
| 409 | TextBlockParser.lessThanBySeniority, | 401 | TextBlockParser.lessThanBySeniority, |
| 410 | ); | 402 | ); |
| 411 | } | 403 | } |
| 412 | | 404 | |
| 413 | const senior_nlist = aliases.pop(); | 405 | const senior_nlist = aliases.pop(); |
| 414 | const senior_sym = &self.macho_file.locals.items[senior_nlist.index]; | 406 | const senior_sym = &context.macho_file.locals.items[senior_nlist.index]; |
| 415 | senior_sym.n_sect = self.macho_file.section_to_ordinal.get(self.match) orelse unreachable; | 407 | senior_sym.n_sect = context.macho_file.section_to_ordinal.get(context.match) orelse unreachable; |
| 416 | | 408 | |
| 417 | const start_addr = senior_nlist.nlist.n_value - self.section.addr; | 409 | const start_addr = senior_nlist.nlist.n_value - self.section.addr; |
| 418 | const end_addr = if (next_nlist) |n| n.nlist.n_value - self.section.addr else self.section.size; | 410 | const end_addr = if (next_nlist) |n| n.nlist.n_value - self.section.addr else self.section.size; |
| ... | @@ -426,7 +418,7 @@ const TextBlockParser = struct { | ... | @@ -426,7 +418,7 @@ const TextBlockParser = struct { |
| 426 | else | 418 | else |
| 427 | max_align; | 419 | max_align; |
| 428 | | 420 | |
| 429 | const stab: ?TextBlock.Stab = if (self.object.debug_info) |di| blk: { | 421 | const stab: ?TextBlock.Stab = if (context.object.debug_info) |di| blk: { |
| 430 | // TODO there has to be a better to handle this. | 422 | // TODO there has to be a better to handle this. |
| 431 | for (di.inner.func_list.items) |func| { | 423 | for (di.inner.func_list.items) |func| { |
| 432 | if (func.pc_range) |range| { | 424 | if (func.pc_range) |range| { |
| ... | @@ -442,35 +434,37 @@ const TextBlockParser = struct { | ... | @@ -442,35 +434,37 @@ const TextBlockParser = struct { |
| 442 | break :blk .static; | 434 | break :blk .static; |
| 443 | } else null; | 435 | } else null; |
| 444 | | 436 | |
| 445 | const block = try self.macho_file.base.allocator.create(TextBlock); | 437 | const block = try context.allocator.create(TextBlock); |
| 446 | block.* = TextBlock.empty; | 438 | block.* = TextBlock.empty; |
| 447 | block.local_sym_index = senior_nlist.index; | 439 | block.local_sym_index = senior_nlist.index; |
| 448 | block.stab = stab; | 440 | block.stab = stab; |
| 449 | block.size = size; | 441 | block.size = size; |
| 450 | block.alignment = actual_align; | 442 | block.alignment = actual_align; |
| 451 | try self.macho_file.managed_blocks.append(self.macho_file.base.allocator, block); | 443 | try context.macho_file.managed_blocks.append(context.allocator, block); |
| 452 | | 444 | |
| 453 | try block.code.appendSlice(self.macho_file.base.allocator, code); | 445 | try block.code.appendSlice(context.allocator, code); |
| 454 | | 446 | |
| 455 | try block.aliases.ensureTotalCapacity(self.macho_file.base.allocator, aliases.items.len); | 447 | try block.aliases.ensureTotalCapacity(context.allocator, aliases.items.len); |
| 456 | for (aliases.items) |alias| { | 448 | for (aliases.items) |alias| { |
| 457 | block.aliases.appendAssumeCapacity(alias.index); | 449 | block.aliases.appendAssumeCapacity(alias.index); |
| 458 | const sym = &self.macho_file.locals.items[alias.index]; | 450 | const sym = &context.macho_file.locals.items[alias.index]; |
| 459 | sym.n_sect = self.macho_file.section_to_ordinal.get(self.match) orelse unreachable; | 451 | sym.n_sect = context.macho_file.section_to_ordinal.get(context.match) orelse unreachable; |
| 460 | } | 452 | } |
| 461 | | 453 | |
| 462 | try block.parseRelocsFromObject(self.macho_file.base.allocator, self.relocs, self.object, .{ | 454 | try block.parseRelocs(self.relocs, .{ |
| 463 | .base_addr = start_addr, | 455 | .base_addr = start_addr, |
| 464 | .macho_file = self.macho_file, | 456 | .allocator = context.allocator, |
| | 457 | .object = context.object, |
| | 458 | .macho_file = context.macho_file, |
| 465 | }); | 459 | }); |
| 466 | | 460 | |
| 467 | if (self.macho_file.has_dices) { | 461 | if (context.macho_file.has_dices) { |
| 468 | const dices = filterDice( | 462 | const dices = filterDice( |
| 469 | self.object.data_in_code_entries.items, | 463 | context.object.data_in_code_entries.items, |
| 470 | senior_nlist.nlist.n_value, | 464 | senior_nlist.nlist.n_value, |
| 471 | senior_nlist.nlist.n_value + size, | 465 | senior_nlist.nlist.n_value + size, |
| 472 | ); | 466 | ); |
| 473 | try block.dices.ensureTotalCapacity(self.macho_file.base.allocator, dices.len); | 467 | try block.dices.ensureTotalCapacity(context.allocator, dices.len); |
| 474 | | 468 | |
| 475 | for (dices) |dice| { | 469 | for (dices) |dice| { |
| 476 | block.dices.appendAssumeCapacity(.{ | 470 | block.dices.appendAssumeCapacity(.{ |
| ... | @@ -487,16 +481,16 @@ const TextBlockParser = struct { | ... | @@ -487,16 +481,16 @@ const TextBlockParser = struct { |
| 487 | } | 481 | } |
| 488 | }; | 482 | }; |
| 489 | | 483 | |
| 490 | pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { | 484 | pub fn parseTextBlocks(self: *Object, allocator: *Allocator, macho_file: *MachO) !void { |
| 491 | const seg = self.load_commands.items[self.segment_cmd_index.?].Segment; | 485 | const seg = self.load_commands.items[self.segment_cmd_index.?].Segment; |
| 492 | | 486 | |
| 493 | log.debug("analysing {s}", .{self.name.?}); | 487 | log.debug("analysing {s}", .{self.name}); |
| 494 | | 488 | |
| 495 | // You would expect that the symbol table is at least pre-sorted based on symbol's type: | 489 | // You would expect that the symbol table is at least pre-sorted based on symbol's type: |
| 496 | // local < extern defined < undefined. Unfortunately, this is not guaranteed! For instance, | 490 | // local < extern defined < undefined. Unfortunately, this is not guaranteed! For instance, |
| 497 | // the GO compiler does not necessarily respect that therefore we sort immediately by type | 491 | // the GO compiler does not necessarily respect that therefore we sort immediately by type |
| 498 | // and address within. | 492 | // and address within. |
| 499 | var sorted_all_nlists = std.ArrayList(NlistWithIndex).init(self.allocator); | 493 | var sorted_all_nlists = std.ArrayList(NlistWithIndex).init(allocator); |
| 500 | defer sorted_all_nlists.deinit(); | 494 | defer sorted_all_nlists.deinit(); |
| 501 | try sorted_all_nlists.ensureTotalCapacity(self.symtab.items.len); | 495 | try sorted_all_nlists.ensureTotalCapacity(self.symtab.items.len); |
| 502 | | 496 | |
| ... | @@ -540,14 +534,14 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { | ... | @@ -540,14 +534,14 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { |
| 540 | }; | 534 | }; |
| 541 | | 535 | |
| 542 | // Read section's code | 536 | // Read section's code |
| 543 | var code = try self.allocator.alloc(u8, @intCast(usize, sect.size)); | 537 | var code = try allocator.alloc(u8, @intCast(usize, sect.size)); |
| 544 | defer self.allocator.free(code); | 538 | defer allocator.free(code); |
| 545 | _ = try self.file.?.preadAll(code, sect.offset); | 539 | _ = try self.file.preadAll(code, sect.offset); |
| 546 | | 540 | |
| 547 | // Read section's list of relocations | 541 | // Read section's list of relocations |
| 548 | var raw_relocs = try self.allocator.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); | 542 | var raw_relocs = try allocator.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); |
| 549 | defer self.allocator.free(raw_relocs); | 543 | defer allocator.free(raw_relocs); |
| 550 | _ = try self.file.?.preadAll(raw_relocs, sect.reloff); | 544 | _ = try self.file.preadAll(raw_relocs, sect.reloff); |
| 551 | const relocs = mem.bytesAsSlice(macho.relocation_info, raw_relocs); | 545 | const relocs = mem.bytesAsSlice(macho.relocation_info, raw_relocs); |
| 552 | | 546 | |
| 553 | // Symbols within this section only. | 547 | // Symbols within this section only. |
| ... | @@ -579,46 +573,48 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { | ... | @@ -579,46 +573,48 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { |
| 579 | // as a temporary symbol and insert the matching TextBlock. | 573 | // as a temporary symbol and insert the matching TextBlock. |
| 580 | const first_nlist = filtered_nlists[0].nlist; | 574 | const first_nlist = filtered_nlists[0].nlist; |
| 581 | if (first_nlist.n_value > sect.addr) { | 575 | if (first_nlist.n_value > sect.addr) { |
| 582 | const sym_name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{ | 576 | const sym_name = try std.fmt.allocPrint(allocator, "l_{s}_{s}_{s}", .{ |
| 583 | self.name.?, | 577 | self.name, |
| 584 | segmentName(sect), | 578 | segmentName(sect), |
| 585 | sectionName(sect), | 579 | sectionName(sect), |
| 586 | }); | 580 | }); |
| 587 | defer self.allocator.free(sym_name); | 581 | defer allocator.free(sym_name); |
| 588 | | 582 | |
| 589 | const block_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { | 583 | const block_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { |
| 590 | const block_local_sym_index = @intCast(u32, macho_file.locals.items.len); | 584 | const block_local_sym_index = @intCast(u32, macho_file.locals.items.len); |
| 591 | try macho_file.locals.append(macho_file.base.allocator, .{ | 585 | try macho_file.locals.append(allocator, .{ |
| 592 | .n_strx = try macho_file.makeString(sym_name), | 586 | .n_strx = try macho_file.makeString(sym_name), |
| 593 | .n_type = macho.N_SECT, | 587 | .n_type = macho.N_SECT, |
| 594 | .n_sect = macho_file.section_to_ordinal.get(match) orelse unreachable, | 588 | .n_sect = macho_file.section_to_ordinal.get(match) orelse unreachable, |
| 595 | .n_desc = 0, | 589 | .n_desc = 0, |
| 596 | .n_value = sect.addr, | 590 | .n_value = sect.addr, |
| 597 | }); | 591 | }); |
| 598 | try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, block_local_sym_index); | 592 | try self.sections_as_symbols.putNoClobber(allocator, sect_id, block_local_sym_index); |
| 599 | break :blk block_local_sym_index; | 593 | break :blk block_local_sym_index; |
| 600 | }; | 594 | }; |
| 601 | | 595 | |
| 602 | const block_code = code[0 .. first_nlist.n_value - sect.addr]; | 596 | const block_code = code[0 .. first_nlist.n_value - sect.addr]; |
| 603 | const block_size = block_code.len; | 597 | const block_size = block_code.len; |
| 604 | | 598 | |
| 605 | const block = try macho_file.base.allocator.create(TextBlock); | 599 | const block = try allocator.create(TextBlock); |
| 606 | block.* = TextBlock.empty; | 600 | block.* = TextBlock.empty; |
| 607 | block.local_sym_index = block_local_sym_index; | 601 | block.local_sym_index = block_local_sym_index; |
| 608 | block.size = block_size; | 602 | block.size = block_size; |
| 609 | block.alignment = sect.@"align"; | 603 | block.alignment = sect.@"align"; |
| 610 | try macho_file.managed_blocks.append(macho_file.base.allocator, block); | 604 | try macho_file.managed_blocks.append(allocator, block); |
| 611 | | 605 | |
| 612 | try block.code.appendSlice(macho_file.base.allocator, block_code); | 606 | try block.code.appendSlice(allocator, block_code); |
| 613 | | 607 | |
| 614 | try block.parseRelocsFromObject(self.allocator, relocs, self, .{ | 608 | try block.parseRelocs(relocs, .{ |
| 615 | .base_addr = 0, | 609 | .base_addr = 0, |
| | 610 | .allocator = allocator, |
| | 611 | .object = self, |
| 616 | .macho_file = macho_file, | 612 | .macho_file = macho_file, |
| 617 | }); | 613 | }); |
| 618 | | 614 | |
| 619 | if (macho_file.has_dices) { | 615 | if (macho_file.has_dices) { |
| 620 | const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + block_size); | 616 | const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + block_size); |
| 621 | try block.dices.ensureTotalCapacity(macho_file.base.allocator, dices.len); | 617 | try block.dices.ensureTotalCapacity(allocator, dices.len); |
| 622 | | 618 | |
| 623 | for (dices) |dice| { | 619 | for (dices) |dice| { |
| 624 | block.dices.appendAssumeCapacity(.{ | 620 | block.dices.appendAssumeCapacity(.{ |
| ... | @@ -645,24 +641,25 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { | ... | @@ -645,24 +641,25 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { |
| 645 | block.prev = last.*; | 641 | block.prev = last.*; |
| 646 | last.* = block; | 642 | last.* = block; |
| 647 | } else { | 643 | } else { |
| 648 | try macho_file.blocks.putNoClobber(macho_file.base.allocator, match, block); | 644 | try macho_file.blocks.putNoClobber(allocator, match, block); |
| 649 | } | 645 | } |
| 650 | | 646 | |
| 651 | try self.text_blocks.append(self.allocator, block); | 647 | try self.text_blocks.append(allocator, block); |
| 652 | } | 648 | } |
| 653 | | 649 | |
| 654 | var parser = TextBlockParser{ | 650 | var parser = TextBlockParser{ |
| 655 | .allocator = self.allocator, | | |
| 656 | .section = sect, | 651 | .section = sect, |
| 657 | .code = code, | 652 | .code = code, |
| 658 | .relocs = relocs, | 653 | .relocs = relocs, |
| 659 | .object = self, | | |
| 660 | .macho_file = macho_file, | | |
| 661 | .nlists = filtered_nlists, | 654 | .nlists = filtered_nlists, |
| 662 | .match = match, | | |
| 663 | }; | 655 | }; |
| 664 | | 656 | |
| 665 | while (try parser.next()) |block| { | 657 | while (try parser.next(.{ |
| | 658 | .allocator = allocator, |
| | 659 | .object = self, |
| | 660 | .macho_file = macho_file, |
| | 661 | .match = match, |
| | 662 | })) |block| { |
| 666 | const sym = macho_file.locals.items[block.local_sym_index]; | 663 | const sym = macho_file.locals.items[block.local_sym_index]; |
| 667 | const is_ext = blk: { | 664 | const is_ext = blk: { |
| 668 | const orig_sym_id = self.reverse_symbol_mapping.get(block.local_sym_index) orelse unreachable; | 665 | const orig_sym_id = self.reverse_symbol_mapping.get(block.local_sym_index) orelse unreachable; |
| ... | @@ -675,9 +672,9 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { | ... | @@ -675,9 +672,9 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { |
| 675 | if (global_object != self) { | 672 | if (global_object != self) { |
| 676 | log.debug("deduping definition of {s} in {s}", .{ | 673 | log.debug("deduping definition of {s} in {s}", .{ |
| 677 | macho_file.getString(sym.n_strx), | 674 | macho_file.getString(sym.n_strx), |
| 678 | self.name.?, | 675 | self.name, |
| 679 | }); | 676 | }); |
| 680 | log.debug(" already defined in {s}", .{global_object.name.?}); | 677 | log.debug(" already defined in {s}", .{global_object.name}); |
| 681 | continue; | 678 | continue; |
| 682 | } | 679 | } |
| 683 | } | 680 | } |
| ... | @@ -688,7 +685,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { | ... | @@ -688,7 +685,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { |
| 688 | // In x86_64 relocs, it can so happen that the compiler refers to the same | 685 | // In x86_64 relocs, it can so happen that the compiler refers to the same |
| 689 | // atom by both the actual assigned symbol and the start of the section. In this | 686 | // atom by both the actual assigned symbol and the start of the section. In this |
| 690 | // case, we need to link the two together so add an alias. | 687 | // case, we need to link the two together so add an alias. |
| 691 | try block.aliases.append(macho_file.base.allocator, alias); | 688 | try block.aliases.append(allocator, alias); |
| 692 | } | 689 | } |
| 693 | } | 690 | } |
| 694 | | 691 | |
| ... | @@ -708,10 +705,10 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { | ... | @@ -708,10 +705,10 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { |
| 708 | block.prev = last.*; | 705 | block.prev = last.*; |
| 709 | last.* = block; | 706 | last.* = block; |
| 710 | } else { | 707 | } else { |
| 711 | try macho_file.blocks.putNoClobber(macho_file.base.allocator, match, block); | 708 | try macho_file.blocks.putNoClobber(allocator, match, block); |
| 712 | } | 709 | } |
| 713 | | 710 | |
| 714 | try self.text_blocks.append(self.allocator, block); | 711 | try self.text_blocks.append(allocator, block); |
| 715 | } | 712 | } |
| 716 | | 713 | |
| 717 | break :next; | 714 | break :next; |
| ... | @@ -720,43 +717,45 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { | ... | @@ -720,43 +717,45 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { |
| 720 | // Since there is no symbol to refer to this block, we create | 717 | // Since there is no symbol to refer to this block, we create |
| 721 | // a temp one, unless we already did that when working out the relocations | 718 | // a temp one, unless we already did that when working out the relocations |
| 722 | // of other text blocks. | 719 | // of other text blocks. |
| 723 | const sym_name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{ | 720 | const sym_name = try std.fmt.allocPrint(allocator, "l_{s}_{s}_{s}", .{ |
| 724 | self.name.?, | 721 | self.name, |
| 725 | segmentName(sect), | 722 | segmentName(sect), |
| 726 | sectionName(sect), | 723 | sectionName(sect), |
| 727 | }); | 724 | }); |
| 728 | defer self.allocator.free(sym_name); | 725 | defer allocator.free(sym_name); |
| 729 | | 726 | |
| 730 | const block_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { | 727 | const block_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { |
| 731 | const block_local_sym_index = @intCast(u32, macho_file.locals.items.len); | 728 | const block_local_sym_index = @intCast(u32, macho_file.locals.items.len); |
| 732 | try macho_file.locals.append(macho_file.base.allocator, .{ | 729 | try macho_file.locals.append(allocator, .{ |
| 733 | .n_strx = try macho_file.makeString(sym_name), | 730 | .n_strx = try macho_file.makeString(sym_name), |
| 734 | .n_type = macho.N_SECT, | 731 | .n_type = macho.N_SECT, |
| 735 | .n_sect = macho_file.section_to_ordinal.get(match) orelse unreachable, | 732 | .n_sect = macho_file.section_to_ordinal.get(match) orelse unreachable, |
| 736 | .n_desc = 0, | 733 | .n_desc = 0, |
| 737 | .n_value = sect.addr, | 734 | .n_value = sect.addr, |
| 738 | }); | 735 | }); |
| 739 | try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, block_local_sym_index); | 736 | try self.sections_as_symbols.putNoClobber(allocator, sect_id, block_local_sym_index); |
| 740 | break :blk block_local_sym_index; | 737 | break :blk block_local_sym_index; |
| 741 | }; | 738 | }; |
| 742 | | 739 | |
| 743 | const block = try macho_file.base.allocator.create(TextBlock); | 740 | const block = try allocator.create(TextBlock); |
| 744 | block.* = TextBlock.empty; | 741 | block.* = TextBlock.empty; |
| 745 | block.local_sym_index = block_local_sym_index; | 742 | block.local_sym_index = block_local_sym_index; |
| 746 | block.size = sect.size; | 743 | block.size = sect.size; |
| 747 | block.alignment = sect.@"align"; | 744 | block.alignment = sect.@"align"; |
| 748 | try macho_file.managed_blocks.append(macho_file.base.allocator, block); | 745 | try macho_file.managed_blocks.append(allocator, block); |
| 749 | | 746 | |
| 750 | try block.code.appendSlice(macho_file.base.allocator, code); | 747 | try block.code.appendSlice(allocator, code); |
| 751 | | 748 | |
| 752 | try block.parseRelocsFromObject(self.allocator, relocs, self, .{ | 749 | try block.parseRelocs(relocs, .{ |
| 753 | .base_addr = 0, | 750 | .base_addr = 0, |
| | 751 | .allocator = allocator, |
| | 752 | .object = self, |
| 754 | .macho_file = macho_file, | 753 | .macho_file = macho_file, |
| 755 | }); | 754 | }); |
| 756 | | 755 | |
| 757 | if (macho_file.has_dices) { | 756 | if (macho_file.has_dices) { |
| 758 | const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + sect.size); | 757 | const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + sect.size); |
| 759 | try block.dices.ensureTotalCapacity(macho_file.base.allocator, dices.len); | 758 | try block.dices.ensureTotalCapacity(allocator, dices.len); |
| 760 | | 759 | |
| 761 | for (dices) |dice| { | 760 | for (dices) |dice| { |
| 762 | block.dices.appendAssumeCapacity(.{ | 761 | block.dices.appendAssumeCapacity(.{ |
| ... | @@ -772,7 +771,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { | ... | @@ -772,7 +771,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { |
| 772 | // the filtered symbols and note which symbol is contained within so that | 771 | // the filtered symbols and note which symbol is contained within so that |
| 773 | // we can properly allocate addresses down the line. | 772 | // we can properly allocate addresses down the line. |
| 774 | // While we're at it, we need to update segment,section mapping of each symbol too. | 773 | // While we're at it, we need to update segment,section mapping of each symbol too. |
| 775 | try block.contained.ensureTotalCapacity(self.allocator, filtered_nlists.len); | 774 | try block.contained.ensureTotalCapacity(allocator, filtered_nlists.len); |
| 776 | | 775 | |
| 777 | for (filtered_nlists) |nlist_with_index| { | 776 | for (filtered_nlists) |nlist_with_index| { |
| 778 | const nlist = nlist_with_index.nlist; | 777 | const nlist = nlist_with_index.nlist; |
| ... | @@ -819,35 +818,35 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { | ... | @@ -819,35 +818,35 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { |
| 819 | block.prev = last.*; | 818 | block.prev = last.*; |
| 820 | last.* = block; | 819 | last.* = block; |
| 821 | } else { | 820 | } else { |
| 822 | try macho_file.blocks.putNoClobber(macho_file.base.allocator, match, block); | 821 | try macho_file.blocks.putNoClobber(allocator, match, block); |
| 823 | } | 822 | } |
| 824 | | 823 | |
| 825 | try self.text_blocks.append(self.allocator, block); | 824 | try self.text_blocks.append(allocator, block); |
| 826 | } | 825 | } |
| 827 | } | 826 | } |
| 828 | } | 827 | } |
| 829 | | 828 | |
| 830 | fn parseSymtab(self: *Object) !void { | 829 | fn parseSymtab(self: *Object, allocator: *Allocator) !void { |
| 831 | const index = self.symtab_cmd_index orelse return; | 830 | const index = self.symtab_cmd_index orelse return; |
| 832 | const symtab_cmd = self.load_commands.items[index].Symtab; | 831 | const symtab_cmd = self.load_commands.items[index].Symtab; |
| 833 | | 832 | |
| 834 | var symtab = try self.allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms); | 833 | var symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms); |
| 835 | defer self.allocator.free(symtab); | 834 | defer allocator.free(symtab); |
| 836 | _ = try self.file.?.preadAll(symtab, symtab_cmd.symoff); | 835 | _ = try self.file.preadAll(symtab, symtab_cmd.symoff); |
| 837 | const slice = @alignCast(@alignOf(macho.nlist_64), mem.bytesAsSlice(macho.nlist_64, symtab)); | 836 | const slice = @alignCast(@alignOf(macho.nlist_64), mem.bytesAsSlice(macho.nlist_64, symtab)); |
| 838 | try self.symtab.appendSlice(self.allocator, slice); | 837 | try self.symtab.appendSlice(allocator, slice); |
| 839 | | 838 | |
| 840 | var strtab = try self.allocator.alloc(u8, symtab_cmd.strsize); | 839 | var strtab = try allocator.alloc(u8, symtab_cmd.strsize); |
| 841 | defer self.allocator.free(strtab); | 840 | defer allocator.free(strtab); |
| 842 | _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff); | 841 | _ = try self.file.preadAll(strtab, symtab_cmd.stroff); |
| 843 | try self.strtab.appendSlice(self.allocator, strtab); | 842 | try self.strtab.appendSlice(allocator, strtab); |
| 844 | } | 843 | } |
| 845 | | 844 | |
| 846 | pub fn parseDebugInfo(self: *Object) !void { | 845 | pub fn parseDebugInfo(self: *Object, allocator: *Allocator) !void { |
| 847 | log.debug("parsing debug info in '{s}'", .{self.name.?}); | 846 | log.debug("parsing debug info in '{s}'", .{self.name}); |
| 848 | | 847 | |
| 849 | var debug_info = blk: { | 848 | var debug_info = blk: { |
| 850 | var di = try DebugInfo.parseFromObject(self.allocator, self); | 849 | var di = try DebugInfo.parseFromObject(allocator, self); |
| 851 | break :blk di orelse return; | 850 | break :blk di orelse return; |
| 852 | }; | 851 | }; |
| 853 | | 852 | |
| ... | @@ -855,7 +854,7 @@ pub fn parseDebugInfo(self: *Object) !void { | ... | @@ -855,7 +854,7 @@ pub fn parseDebugInfo(self: *Object) !void { |
| 855 | const compile_unit = debug_info.inner.findCompileUnit(0x0) catch |err| switch (err) { | 854 | const compile_unit = debug_info.inner.findCompileUnit(0x0) catch |err| switch (err) { |
| 856 | error.MissingDebugInfo => { | 855 | error.MissingDebugInfo => { |
| 857 | // TODO audit cases with missing debug info and audit our dwarf.zig module. | 856 | // TODO audit cases with missing debug info and audit our dwarf.zig module. |
| 858 | log.debug("invalid or missing debug info in {s}; skipping", .{self.name.?}); | 857 | log.debug("invalid or missing debug info in {s}; skipping", .{self.name}); |
| 859 | return; | 858 | return; |
| 860 | }, | 859 | }, |
| 861 | else => |e| return e, | 860 | else => |e| return e, |
| ... | @@ -864,26 +863,25 @@ pub fn parseDebugInfo(self: *Object) !void { | ... | @@ -864,26 +863,25 @@ pub fn parseDebugInfo(self: *Object) !void { |
| 864 | const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_comp_dir); | 863 | const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_comp_dir); |
| 865 | | 864 | |
| 866 | self.debug_info = debug_info; | 865 | self.debug_info = debug_info; |
| 867 | self.tu_name = try self.allocator.dupe(u8, name); | 866 | self.tu_name = try allocator.dupe(u8, name); |
| 868 | self.tu_comp_dir = try self.allocator.dupe(u8, comp_dir); | 867 | self.tu_comp_dir = try allocator.dupe(u8, comp_dir); |
| 869 | | 868 | |
| 870 | if (self.mtime == null) { | 869 | if (self.mtime == null) { |
| 871 | self.mtime = mtime: { | 870 | self.mtime = mtime: { |
| 872 | const file = self.file orelse break :mtime 0; | 871 | const stat = self.file.stat() catch break :mtime 0; |
| 873 | const stat = file.stat() catch break :mtime 0; | | |
| 874 | break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000)); | 872 | break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000)); |
| 875 | }; | 873 | }; |
| 876 | } | 874 | } |
| 877 | } | 875 | } |
| 878 | | 876 | |
| 879 | pub fn parseDataInCode(self: *Object) !void { | 877 | pub fn parseDataInCode(self: *Object, allocator: *Allocator) !void { |
| 880 | const index = self.data_in_code_cmd_index orelse return; | 878 | const index = self.data_in_code_cmd_index orelse return; |
| 881 | const data_in_code = self.load_commands.items[index].LinkeditData; | 879 | const data_in_code = self.load_commands.items[index].LinkeditData; |
| 882 | | 880 | |
| 883 | var buffer = try self.allocator.alloc(u8, data_in_code.datasize); | 881 | var buffer = try allocator.alloc(u8, data_in_code.datasize); |
| 884 | defer self.allocator.free(buffer); | 882 | defer allocator.free(buffer); |
| 885 | | 883 | |
| 886 | _ = try self.file.?.preadAll(buffer, data_in_code.dataoff); | 884 | _ = try self.file.preadAll(buffer, data_in_code.dataoff); |
| 887 | | 885 | |
| 888 | var stream = io.fixedBufferStream(buffer); | 886 | var stream = io.fixedBufferStream(buffer); |
| 889 | var reader = stream.reader(); | 887 | var reader = stream.reader(); |
| ... | @@ -892,7 +890,7 @@ pub fn parseDataInCode(self: *Object) !void { | ... | @@ -892,7 +890,7 @@ pub fn parseDataInCode(self: *Object) !void { |
| 892 | error.EndOfStream => break, | 890 | error.EndOfStream => break, |
| 893 | else => |e| return e, | 891 | else => |e| return e, |
| 894 | }; | 892 | }; |
| 895 | try self.data_in_code_entries.append(self.allocator, dice); | 893 | try self.data_in_code_entries.append(allocator, dice); |
| 896 | } | 894 | } |
| 897 | } | 895 | } |
| 898 | | 896 | |
| ... | @@ -900,7 +898,7 @@ fn readSection(self: Object, allocator: *Allocator, index: u16) ![]u8 { | ... | @@ -900,7 +898,7 @@ fn readSection(self: Object, allocator: *Allocator, index: u16) ![]u8 { |
| 900 | const seg = self.load_commands.items[self.segment_cmd_index.?].Segment; | 898 | const seg = self.load_commands.items[self.segment_cmd_index.?].Segment; |
| 901 | const sect = seg.sections.items[index]; | 899 | const sect = seg.sections.items[index]; |
| 902 | var buffer = try allocator.alloc(u8, @intCast(usize, sect.size)); | 900 | var buffer = try allocator.alloc(u8, @intCast(usize, sect.size)); |
| 903 | _ = try self.file.?.preadAll(buffer, sect.offset); | 901 | _ = try self.file.preadAll(buffer, sect.offset); |
| 904 | return buffer; | 902 | return buffer; |
| 905 | } | 903 | } |
| 906 | | 904 | |