lib/tldr/src/formats/elf/archive/member.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 const root = @import("../../../root.zig");
  3 const elf = @import("../root.zig");
  4 const prefetch = @import("prefetch.zig");
  5 
  6 const Allocator = std.mem.Allocator;
  7 const archive_format = root.archive;
  8 const model = root.model;
  9 const trace = root.trace;
 10 const ObjectParseOptions = elf.parser.ObjectParseOptions;
 11 const ObjectSelectionSummary = elf.parser.ObjectSelectionSummary;
 12 const isElf = elf.format.isElf;
 13 const parseObjectWithOptions = elf.parser.parseObjectWithOptions;
 14 
 15 pub fn addCandidates(
 16     allocator: Allocator,
 17     selection: Allocator,
 18     input: model.Input,
 19     input_index: usize,
 20     state: anytype,
 21     parse_options: ObjectParseOptions,
 22     prefetched: ?prefetch.Prefetched,
 23 ) model.Error!void {
 24     const parsed = if (prefetched) |ready| ready.parsed else parse_table: {
 25         const table_phase = trace.product(.archive_table_parse);
 26         defer table_phase.end();
 27         break :parse_table try archive_format.parseDetailed(selection, input);
 28     };
 29 
 30     if (!parsed.has_symbol_index) {
 31         const first_candidate_index = state.candidates.items.len;
 32         try buildScannedCandidates(allocator, input.name, input_index, parsed.members, state, parse_options);
 33         try indexDefinitionsFromObjects(
 34             allocator,
 35             state,
 36             first_candidate_index,
 37         );
 38     } else {
 39         const indexing_phase = trace.product(.archive_definition_indexing);
 40         defer indexing_phase.end();
 41         try buildIndexedCandidates(
 42             allocator,
 43             input.name,
 44             input_index,
 45             parsed.members,
 46             parsed.symbol_index,
 47             state,
 48             if (prefetched) |ready| ready.summaries else &.{},
 49             if (prefetched) |ready| ready.failures else &.{},
 50         );
 51     }
 52 }
 53 
 54 fn buildScannedCandidates(
 55     allocator: Allocator,
 56     archive_name: []const u8,
 57     archive_input_index: usize,
 58     members: []const archive_format.Member,
 59     state: anytype,
 60     parse_options: ObjectParseOptions,
 61 ) model.Error!void {
 62     for (members) |member| {
 63         if (!isElf(member.bytes)) continue;
 64         var object = try parseObjectWithOptions(allocator, .{
 65             .name = member.name,
 66             .bytes = member.bytes,
 67         }, parse_options);
 68         object.input_index = archive_input_index;
 69         errdefer object.deinit(allocator);
 70         _ = try state.appendCandidate(allocator, .{
 71             .archive_name = archive_name,
 72             .archive_input_index = archive_input_index,
 73             .member = member,
 74             .object = object,
 75         });
 76     }
 77 }
 78 
 79 fn buildIndexedCandidates(
 80     allocator: Allocator,
 81     archive_name: []const u8,
 82     archive_input_index: usize,
 83     members: []const archive_format.Member,
 84     symbol_index: []const archive_format.SymbolIndexEntry,
 85     state: anytype,
 86     summaries: []const ?ObjectSelectionSummary,
 87     failures: []const ?model.Error,
 88 ) model.Error!void {
 89     try state.candidates.ensureUnusedCapacity(allocator, symbol_index.len);
 90     try state.active_candidate_counts.ensureUnusedCapacity(allocator, symbol_index.len);
 91     const definition_capacity = std.math.cast(u32, symbol_index.len) orelse return error.InvalidArchive;
 92     try state.definitions.ensureUnusedCapacity(allocator, definition_capacity);
 93 
 94     const missing_candidate = std.math.maxInt(usize);
 95     const candidate_by_member = try allocator.alloc(usize, members.len);
 96     defer allocator.free(candidate_by_member);
 97     @memset(candidate_by_member, missing_candidate);
 98 
 99     var offsets_ordered = true;
100     var previous_member_offset: u64 = 0;
101     var member_cursor: usize = 0;
102     for (symbol_index) |entry| {
103         if (entry.member_offset < previous_member_offset) offsets_ordered = false;
104         previous_member_offset = entry.member_offset;
105         const member_index = if (offsets_ordered)
106             archive_format.memberIndexByOffsetWithCursor(members, entry.member_offset, &member_cursor) orelse return error.InvalidArchive
107         else
108             archive_format.memberIndexByOffset(members, entry.member_offset) orelse return error.InvalidArchive;
109         var candidate_index = candidate_by_member[member_index];
110         if (candidate_index == missing_candidate) {
111             candidate_index = state.candidates.items.len;
112             candidate_by_member[member_index] = candidate_index;
113             state.active_candidate_counts.appendAssumeCapacity(0);
114             state.candidates.appendAssumeCapacity(.{
115                 .archive_name = archive_name,
116                 .archive_input_index = archive_input_index,
117                 .member = members[member_index],
118                 .summary = if (summaries.len != 0) summaries[member_index] else null,
119                 .summary_failure = if (failures.len != 0) failures[member_index] else null,
120             });
121         }
122         try state.addDefinition(allocator, entry.name, candidate_index);
123     }
124 }
125 
126 fn indexDefinitionsFromObjects(
127     allocator: Allocator,
128     state: anytype,
129     first_candidate_index: usize,
130 ) model.Error!void {
131     for (state.candidates.items[first_candidate_index..], 0..) |candidate, index| {
132         const parsed_object = candidate.object orelse return error.InvalidObject;
133         for (parsed_object.symbols) |symbol| {
134             if (!symbol.isGlobalDefinition()) continue;
135             try state.addDefinition(allocator, symbol.name, first_candidate_index + index);
136         }
137     }
138 }