| ... | ... | @@ -10,20 +10,22 @@ const macho = std.macho; |
| 10 | 10 | const math = std.math; |
| 11 | 11 | const mem = std.mem; |
| 12 | 12 | const sort = std.sort; |
| 13 | const commands = @import("commands.zig"); |
| 14 | const segmentName = commands.segmentName; |
| 15 | const sectionName = commands.sectionName; |
| 13 | 16 | |
| 14 | 17 | const Allocator = mem.Allocator; |
| 15 | 18 | const Arch = std.Target.Cpu.Arch; |
| 19 | const LoadCommand = commands.LoadCommand; |
| 16 | 20 | const MachO = @import("../MachO.zig"); |
| 17 | 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 | 26 | file_offset: ?u32 = null, |
| 26 | | name: ?[]const u8 = null, |
| 27 | |
| 28 | header: ?macho.mach_header_64 = null, |
| 27 | 29 | |
| 28 | 30 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, |
| 29 | 31 | |
| ... | ... | @@ -139,15 +141,13 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u |
| 139 | 141 | errdefer allocator.free(name); |
| 140 | 142 | |
| 141 | 143 | object.* = .{ |
| 142 | | .allocator = allocator, |
| 143 | | .arch = arch, |
| 144 | 144 | .name = name, |
| 145 | 145 | .file = file, |
| 146 | 146 | }; |
| 147 | 147 | |
| 148 | | object.parse() catch |err| switch (err) { |
| 148 | object.parse(allocator, arch) catch |err| switch (err) { |
| 149 | 149 | error.EndOfStream, error.NotObject => { |
| 150 | | object.deinit(); |
| 150 | object.deinit(allocator); |
| 151 | 151 | allocator.destroy(object); |
| 152 | 152 | return null; |
| 153 | 153 | }, |
| ... | ... | @@ -157,44 +157,35 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u |
| 157 | 157 | return object; |
| 158 | 158 | } |
| 159 | 159 | |
| 160 | | pub fn deinit(self: *Object) void { |
| 160 | pub fn deinit(self: *Object, allocator: *Allocator) void { |
| 161 | 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); |
| 165 | | self.data_in_code_entries.deinit(self.allocator); |
| 166 | | self.symtab.deinit(self.allocator); |
| 167 | | self.strtab.deinit(self.allocator); |
| 168 | | self.text_blocks.deinit(self.allocator); |
| 169 | | self.sections_as_symbols.deinit(self.allocator); |
| 170 | | self.symbol_mapping.deinit(self.allocator); |
| 171 | | self.reverse_symbol_mapping.deinit(self.allocator); |
| 164 | self.load_commands.deinit(allocator); |
| 165 | self.data_in_code_entries.deinit(allocator); |
| 166 | self.symtab.deinit(allocator); |
| 167 | self.strtab.deinit(allocator); |
| 168 | self.text_blocks.deinit(allocator); |
| 169 | self.sections_as_symbols.deinit(allocator); |
| 170 | self.symbol_mapping.deinit(allocator); |
| 171 | self.reverse_symbol_mapping.deinit(allocator); |
| 172 | allocator.free(self.name); |
| 172 | 173 | |
| 173 | 174 | if (self.debug_info) |*db| { |
| 174 | | db.deinit(self.allocator); |
| 175 | db.deinit(allocator); |
| 175 | 176 | } |
| 176 | 177 | |
| 177 | 178 | if (self.tu_name) |n| { |
| 178 | | self.allocator.free(n); |
| 179 | allocator.free(n); |
| 179 | 180 | } |
| 180 | 181 | |
| 181 | 182 | if (self.tu_comp_dir) |n| { |
| 182 | | self.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(); |
| 183 | allocator.free(n); |
| 193 | 184 | } |
| 194 | 185 | } |
| 195 | 186 | |
| 196 | | pub fn parse(self: *Object) !void { |
| 197 | | var reader = self.file.?.reader(); |
| 187 | pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void { |
| 188 | var reader = self.file.reader(); |
| 198 | 189 | if (self.file_offset) |offset| { |
| 199 | 190 | try reader.context.seekTo(offset); |
| 200 | 191 | } |
| ... | ... | @@ -214,26 +205,28 @@ pub fn parse(self: *Object) !void { |
| 214 | 205 | return error.UnsupportedCpuArchitecture; |
| 215 | 206 | }, |
| 216 | 207 | }; |
| 217 | | if (this_arch != self.arch.?) { |
| 218 | | log.err("mismatched cpu architecture: expected {s}, found {s}", .{ self.arch.?, this_arch }); |
| 208 | if (this_arch != arch) { |
| 209 | log.err("mismatched cpu architecture: expected {s}, found {s}", .{ arch, this_arch }); |
| 219 | 210 | return error.MismatchedCpuArchitecture; |
| 220 | 211 | } |
| 221 | 212 | |
| 222 | 213 | self.header = header; |
| 223 | 214 | |
| 224 | | try self.readLoadCommands(reader); |
| 225 | | try self.parseSymtab(); |
| 226 | | try self.parseDataInCode(); |
| 227 | | try self.parseDebugInfo(); |
| 215 | try self.readLoadCommands(allocator, reader); |
| 216 | try self.parseSymtab(allocator); |
| 217 | try self.parseDataInCode(allocator); |
| 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 | 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 | 227 | var i: u16 = 0; |
| 235 | | while (i < self.header.?.ncmds) : (i += 1) { |
| 236 | | var cmd = try LoadCommand.read(self.allocator, reader); |
| 228 | while (i < header.ncmds) : (i += 1) { |
| 229 | var cmd = try LoadCommand.read(allocator, reader); |
| 237 | 230 | switch (cmd.cmd()) { |
| 238 | 231 | macho.LC_SEGMENT_64 => { |
| 239 | 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 | 340 | return dices[start..end]; |
| 348 | 341 | } |
| 349 | 342 | |
| 350 | | const TextBlockParser = struct { |
| 343 | const Context = struct { |
| 351 | 344 | allocator: *Allocator, |
| 345 | object: *Object, |
| 346 | macho_file: *MachO, |
| 347 | match: MachO.MatchingSection, |
| 348 | }; |
| 349 | |
| 350 | const TextBlockParser = struct { |
| 352 | 351 | section: macho.section_64, |
| 353 | 352 | code: []u8, |
| 354 | 353 | relocs: []macho.relocation_info, |
| 355 | | object: *Object, |
| 356 | | macho_file: *MachO, |
| 357 | 354 | nlists: []NlistWithIndex, |
| 358 | 355 | index: u32 = 0, |
| 359 | | match: MachO.MatchingSection, |
| 360 | 356 | |
| 361 | | fn peek(self: *TextBlockParser) ?NlistWithIndex { |
| 357 | fn peek(self: TextBlockParser) ?NlistWithIndex { |
| 362 | 358 | return if (self.index + 1 < self.nlists.len) self.nlists[self.index + 1] else null; |
| 363 | 359 | } |
| 364 | 360 | |
| 365 | | const SeniorityContext = struct { |
| 366 | | object: *Object, |
| 367 | | }; |
| 368 | | |
| 369 | | fn lessThanBySeniority(context: SeniorityContext, lhs: NlistWithIndex, rhs: NlistWithIndex) bool { |
| 361 | fn lessThanBySeniority(context: Context, lhs: NlistWithIndex, rhs: NlistWithIndex) bool { |
| 370 | 362 | if (!MachO.symbolIsExt(rhs.nlist)) { |
| 371 | 363 | return MachO.symbolIsTemp(lhs.nlist, context.object.getString(lhs.nlist.n_strx)); |
| 372 | 364 | } else if (MachO.symbolIsPext(rhs.nlist) or MachO.symbolIsWeakDef(rhs.nlist)) { |
| ... | ... | @@ -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 | 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 | 375 | defer aliases.deinit(); |
| 384 | 376 | |
| 385 | 377 | const next_nlist: ?NlistWithIndex = blk: while (true) { |
| ... | ... | @@ -397,7 +389,7 @@ const TextBlockParser = struct { |
| 397 | 389 | } else null; |
| 398 | 390 | |
| 399 | 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 | 395 | if (aliases.items.len > 1) { |
| ... | ... | @@ -405,14 +397,14 @@ const TextBlockParser = struct { |
| 405 | 397 | sort.sort( |
| 406 | 398 | NlistWithIndex, |
| 407 | 399 | aliases.items, |
| 408 | | SeniorityContext{ .object = self.object }, |
| 400 | context, |
| 409 | 401 | TextBlockParser.lessThanBySeniority, |
| 410 | 402 | ); |
| 411 | 403 | } |
| 412 | 404 | |
| 413 | 405 | const senior_nlist = aliases.pop(); |
| 414 | | const senior_sym = &self.macho_file.locals.items[senior_nlist.index]; |
| 415 | | senior_sym.n_sect = self.macho_file.section_to_ordinal.get(self.match) orelse unreachable; |
| 406 | const senior_sym = &context.macho_file.locals.items[senior_nlist.index]; |
| 407 | senior_sym.n_sect = context.macho_file.section_to_ordinal.get(context.match) orelse unreachable; |
| 416 | 408 | |
| 417 | 409 | const start_addr = senior_nlist.nlist.n_value - self.section.addr; |
| 418 | 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 | 418 | else |
| 427 | 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 | 422 | // TODO there has to be a better to handle this. |
| 431 | 423 | for (di.inner.func_list.items) |func| { |
| 432 | 424 | if (func.pc_range) |range| { |
| ... | ... | @@ -442,35 +434,37 @@ const TextBlockParser = struct { |
| 442 | 434 | break :blk .static; |
| 443 | 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 | 438 | block.* = TextBlock.empty; |
| 447 | 439 | block.local_sym_index = senior_nlist.index; |
| 448 | 440 | block.stab = stab; |
| 449 | 441 | block.size = size; |
| 450 | 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 | 448 | for (aliases.items) |alias| { |
| 457 | 449 | block.aliases.appendAssumeCapacity(alias.index); |
| 458 | | const sym = &self.macho_file.locals.items[alias.index]; |
| 459 | | sym.n_sect = self.macho_file.section_to_ordinal.get(self.match) orelse unreachable; |
| 450 | const sym = &context.macho_file.locals.items[alias.index]; |
| 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 | 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 | 462 | const dices = filterDice( |
| 469 | | self.object.data_in_code_entries.items, |
| 463 | context.object.data_in_code_entries.items, |
| 470 | 464 | senior_nlist.nlist.n_value, |
| 471 | 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 | 469 | for (dices) |dice| { |
| 476 | 470 | block.dices.appendAssumeCapacity(.{ |
| ... | ... | @@ -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 | 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 | 489 | // You would expect that the symbol table is at least pre-sorted based on symbol's type: |
| 496 | 490 | // local < extern defined < undefined. Unfortunately, this is not guaranteed! For instance, |
| 497 | 491 | // the GO compiler does not necessarily respect that therefore we sort immediately by type |
| 498 | 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 | 494 | defer sorted_all_nlists.deinit(); |
| 501 | 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 | 534 | }; |
| 541 | 535 | |
| 542 | 536 | // Read section's code |
| 543 | | var code = try self.allocator.alloc(u8, @intCast(usize, sect.size)); |
| 544 | | defer self.allocator.free(code); |
| 545 | | _ = try self.file.?.preadAll(code, sect.offset); |
| 537 | var code = try allocator.alloc(u8, @intCast(usize, sect.size)); |
| 538 | defer allocator.free(code); |
| 539 | _ = try self.file.preadAll(code, sect.offset); |
| 546 | 540 | |
| 547 | 541 | // Read section's list of relocations |
| 548 | | var raw_relocs = try self.allocator.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); |
| 549 | | defer self.allocator.free(raw_relocs); |
| 550 | | _ = try self.file.?.preadAll(raw_relocs, sect.reloff); |
| 542 | var raw_relocs = try allocator.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); |
| 543 | defer allocator.free(raw_relocs); |
| 544 | _ = try self.file.preadAll(raw_relocs, sect.reloff); |
| 551 | 545 | const relocs = mem.bytesAsSlice(macho.relocation_info, raw_relocs); |
| 552 | 546 | |
| 553 | 547 | // Symbols within this section only. |
| ... | ... | @@ -579,46 +573,48 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { |
| 579 | 573 | // as a temporary symbol and insert the matching TextBlock. |
| 580 | 574 | const first_nlist = filtered_nlists[0].nlist; |
| 581 | 575 | if (first_nlist.n_value > sect.addr) { |
| 582 | | const sym_name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{ |
| 583 | | self.name.?, |
| 576 | const sym_name = try std.fmt.allocPrint(allocator, "l_{s}_{s}_{s}", .{ |
| 577 | self.name, |
| 584 | 578 | segmentName(sect), |
| 585 | 579 | sectionName(sect), |
| 586 | 580 | }); |
| 587 | | defer self.allocator.free(sym_name); |
| 581 | defer allocator.free(sym_name); |
| 588 | 582 | |
| 589 | 583 | const block_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { |
| 590 | 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 | 586 | .n_strx = try macho_file.makeString(sym_name), |
| 593 | 587 | .n_type = macho.N_SECT, |
| 594 | 588 | .n_sect = macho_file.section_to_ordinal.get(match) orelse unreachable, |
| 595 | 589 | .n_desc = 0, |
| 596 | 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 | 593 | break :blk block_local_sym_index; |
| 600 | 594 | }; |
| 601 | 595 | |
| 602 | 596 | const block_code = code[0 .. first_nlist.n_value - sect.addr]; |
| 603 | 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 | 600 | block.* = TextBlock.empty; |
| 607 | 601 | block.local_sym_index = block_local_sym_index; |
| 608 | 602 | block.size = block_size; |
| 609 | 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 | 609 | .base_addr = 0, |
| 610 | .allocator = allocator, |
| 611 | .object = self, |
| 616 | 612 | .macho_file = macho_file, |
| 617 | 613 | }); |
| 618 | 614 | |
| 619 | 615 | if (macho_file.has_dices) { |
| 620 | 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 | 619 | for (dices) |dice| { |
| 624 | 620 | block.dices.appendAssumeCapacity(.{ |
| ... | ... | @@ -645,24 +641,25 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { |
| 645 | 641 | block.prev = last.*; |
| 646 | 642 | last.* = block; |
| 647 | 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 | 650 | var parser = TextBlockParser{ |
| 655 | | .allocator = self.allocator, |
| 656 | 651 | .section = sect, |
| 657 | 652 | .code = code, |
| 658 | 653 | .relocs = relocs, |
| 659 | | .object = self, |
| 660 | | .macho_file = macho_file, |
| 661 | 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 | 663 | const sym = macho_file.locals.items[block.local_sym_index]; |
| 667 | 664 | const is_ext = blk: { |
| 668 | 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 | 672 | if (global_object != self) { |
| 676 | 673 | log.debug("deduping definition of {s} in {s}", .{ |
| 677 | 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 | 678 | continue; |
| 682 | 679 | } |
| 683 | 680 | } |
| ... | ... | @@ -688,7 +685,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { |
| 688 | 685 | // In x86_64 relocs, it can so happen that the compiler refers to the same |
| 689 | 686 | // atom by both the actual assigned symbol and the start of the section. In this |
| 690 | 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 | 705 | block.prev = last.*; |
| 709 | 706 | last.* = block; |
| 710 | 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 | 714 | break :next; |
| ... | ... | @@ -720,43 +717,45 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { |
| 720 | 717 | // Since there is no symbol to refer to this block, we create |
| 721 | 718 | // a temp one, unless we already did that when working out the relocations |
| 722 | 719 | // of other text blocks. |
| 723 | | const sym_name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{ |
| 724 | | self.name.?, |
| 720 | const sym_name = try std.fmt.allocPrint(allocator, "l_{s}_{s}_{s}", .{ |
| 721 | self.name, |
| 725 | 722 | segmentName(sect), |
| 726 | 723 | sectionName(sect), |
| 727 | 724 | }); |
| 728 | | defer self.allocator.free(sym_name); |
| 725 | defer allocator.free(sym_name); |
| 729 | 726 | |
| 730 | 727 | const block_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { |
| 731 | 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 | 730 | .n_strx = try macho_file.makeString(sym_name), |
| 734 | 731 | .n_type = macho.N_SECT, |
| 735 | 732 | .n_sect = macho_file.section_to_ordinal.get(match) orelse unreachable, |
| 736 | 733 | .n_desc = 0, |
| 737 | 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 | 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 | 741 | block.* = TextBlock.empty; |
| 745 | 742 | block.local_sym_index = block_local_sym_index; |
| 746 | 743 | block.size = sect.size; |
| 747 | 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 | 750 | .base_addr = 0, |
| 751 | .allocator = allocator, |
| 752 | .object = self, |
| 754 | 753 | .macho_file = macho_file, |
| 755 | 754 | }); |
| 756 | 755 | |
| 757 | 756 | if (macho_file.has_dices) { |
| 758 | 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 | 760 | for (dices) |dice| { |
| 762 | 761 | block.dices.appendAssumeCapacity(.{ |
| ... | ... | @@ -772,7 +771,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { |
| 772 | 771 | // the filtered symbols and note which symbol is contained within so that |
| 773 | 772 | // we can properly allocate addresses down the line. |
| 774 | 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 | 776 | for (filtered_nlists) |nlist_with_index| { |
| 778 | 777 | const nlist = nlist_with_index.nlist; |
| ... | ... | @@ -819,35 +818,35 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void { |
| 819 | 818 | block.prev = last.*; |
| 820 | 819 | last.* = block; |
| 821 | 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 | 830 | const index = self.symtab_cmd_index orelse return; |
| 832 | 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); |
| 835 | | defer self.allocator.free(symtab); |
| 836 | | _ = try self.file.?.preadAll(symtab, symtab_cmd.symoff); |
| 833 | var symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms); |
| 834 | defer allocator.free(symtab); |
| 835 | _ = try self.file.preadAll(symtab, symtab_cmd.symoff); |
| 837 | 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); |
| 841 | | defer self.allocator.free(strtab); |
| 842 | | _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff); |
| 843 | | try self.strtab.appendSlice(self.allocator, strtab); |
| 839 | var strtab = try allocator.alloc(u8, symtab_cmd.strsize); |
| 840 | defer allocator.free(strtab); |
| 841 | _ = try self.file.preadAll(strtab, symtab_cmd.stroff); |
| 842 | try self.strtab.appendSlice(allocator, strtab); |
| 844 | 843 | } |
| 845 | 844 | |
| 846 | | pub fn parseDebugInfo(self: *Object) !void { |
| 847 | | log.debug("parsing debug info in '{s}'", .{self.name.?}); |
| 845 | pub fn parseDebugInfo(self: *Object, allocator: *Allocator) !void { |
| 846 | log.debug("parsing debug info in '{s}'", .{self.name}); |
| 848 | 847 | |
| 849 | 848 | var debug_info = blk: { |
| 850 | | var di = try DebugInfo.parseFromObject(self.allocator, self); |
| 849 | var di = try DebugInfo.parseFromObject(allocator, self); |
| 851 | 850 | break :blk di orelse return; |
| 852 | 851 | }; |
| 853 | 852 | |
| ... | ... | @@ -855,7 +854,7 @@ pub fn parseDebugInfo(self: *Object) !void { |
| 855 | 854 | const compile_unit = debug_info.inner.findCompileUnit(0x0) catch |err| switch (err) { |
| 856 | 855 | error.MissingDebugInfo => { |
| 857 | 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 | 858 | return; |
| 860 | 859 | }, |
| 861 | 860 | else => |e| return e, |
| ... | ... | @@ -864,26 +863,25 @@ pub fn parseDebugInfo(self: *Object) !void { |
| 864 | 863 | const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_comp_dir); |
| 865 | 864 | |
| 866 | 865 | self.debug_info = debug_info; |
| 867 | | self.tu_name = try self.allocator.dupe(u8, name); |
| 868 | | self.tu_comp_dir = try self.allocator.dupe(u8, comp_dir); |
| 866 | self.tu_name = try allocator.dupe(u8, name); |
| 867 | self.tu_comp_dir = try allocator.dupe(u8, comp_dir); |
| 869 | 868 | |
| 870 | 869 | if (self.mtime == null) { |
| 871 | 870 | self.mtime = mtime: { |
| 872 | | const file = self.file orelse break :mtime 0; |
| 873 | | const stat = file.stat() catch break :mtime 0; |
| 871 | const stat = self.file.stat() catch break :mtime 0; |
| 874 | 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 | 878 | const index = self.data_in_code_cmd_index orelse return; |
| 881 | 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); |
| 884 | | defer self.allocator.free(buffer); |
| 881 | var buffer = try allocator.alloc(u8, data_in_code.datasize); |
| 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 | 886 | var stream = io.fixedBufferStream(buffer); |
| 889 | 887 | var reader = stream.reader(); |
| ... | ... | @@ -892,7 +890,7 @@ pub fn parseDataInCode(self: *Object) !void { |
| 892 | 890 | error.EndOfStream => break, |
| 893 | 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 | 898 | const seg = self.load_commands.items[self.segment_cmd_index.?].Segment; |
| 901 | 899 | const sect = seg.sections.items[index]; |
| 902 | 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 | 902 | return buffer; |
| 905 | 903 | } |
| 906 | 904 | |