lib/tldr/src/formats/elf/group/membership.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 const root = @import("../../../root.zig");
  3 const elf = @import("../root.zig");
  4 const record = @import("record.zig");
  5 
  6 const Allocator = std.mem.Allocator;
  7 const model = root.model;
  8 const ObjectFile = elf.parser.ObjectFile;
  9 const SectionRef = elf.parser.SectionRef;
 10 
 11 const Range = struct {
 12     start: usize = 0,
 13     count: usize = 0,
 14 };
 15 
 16 const Memberships = struct {
 17     ranges: []Range = &.{},
 18     group_sections: []usize = &.{},
 19 
 20     fn init(allocator: Allocator, object: ObjectFile) model.Error!Memberships {
 21         const ranges = try allocator.alloc(Range, object.sections.len);
 22         errdefer allocator.free(ranges);
 23         for (ranges) |*range| range.* = .{};
 24 
 25         for (object.sections) |section| {
 26             if (section.section_type != std.elf.SHT_GROUP) continue;
 27             const group_bytes = try record.bytes(object, section);
 28             var member_iterator = record.members(group_bytes);
 29             while (member_iterator.next()) |member_index| {
 30                 if (member_index >= object.sections.len) continue;
 31                 if (ranges[member_index].count == std.math.maxInt(usize)) return error.InvalidObject;
 32                 ranges[member_index].count += 1;
 33             }
 34         }
 35 
 36         var total_group_references: usize = 0;
 37         for (ranges) |*range| {
 38             const group_count = range.count;
 39             range.start = total_group_references;
 40             range.count = 0;
 41             if (group_count > std.math.maxInt(usize) - total_group_references) return error.InvalidObject;
 42             total_group_references += group_count;
 43         }
 44 
 45         const group_sections = try allocator.alloc(usize, total_group_references);
 46         errdefer allocator.free(group_sections);
 47 
 48         for (object.sections, 0..) |section, group_section_index| {
 49             if (section.section_type != std.elf.SHT_GROUP) continue;
 50             const group_bytes = try record.bytes(object, section);
 51             var member_iterator = record.members(group_bytes);
 52             while (member_iterator.next()) |member_index| {
 53                 if (member_index >= object.sections.len) continue;
 54                 const range = &ranges[member_index];
 55                 group_sections[range.start + range.count] = group_section_index;
 56                 range.count += 1;
 57             }
 58         }
 59 
 60         return .{
 61             .ranges = ranges,
 62             .group_sections = group_sections,
 63         };
 64     }
 65 
 66     fn deinit(self: *Memberships, allocator: Allocator) void {
 67         if (self.ranges.len != 0) allocator.free(self.ranges);
 68         if (self.group_sections.len != 0) allocator.free(self.group_sections);
 69     }
 70 
 71     fn groupsForSection(self: Memberships, section_index: usize) []const usize {
 72         if (section_index >= self.ranges.len) return &.{};
 73         const range = self.ranges[section_index];
 74         return self.group_sections[range.start..][0..range.count];
 75     }
 76 };
 77 
 78 pub const Index = struct {
 79     objects: []Memberships = &.{},
 80 
 81     pub fn init(allocator: Allocator, objects: []const ObjectFile) model.Error!Index {
 82         const object_memberships = try allocator.alloc(Memberships, objects.len);
 83         var initialized_count: usize = 0;
 84         errdefer {
 85             for (object_memberships[0..initialized_count]) |*memberships| memberships.deinit(allocator);
 86             allocator.free(object_memberships);
 87         }
 88 
 89         for (objects, 0..) |object, object_index| {
 90             object_memberships[object_index] = try Memberships.init(allocator, object);
 91             initialized_count += 1;
 92         }
 93 
 94         return .{ .objects = object_memberships };
 95     }
 96 
 97     pub fn deinit(self: *Index, allocator: Allocator) void {
 98         for (self.objects) |*memberships| memberships.deinit(allocator);
 99         if (self.objects.len != 0) allocator.free(self.objects);
100     }
101 
102     pub fn groupsForSection(self: Index, section_ref: SectionRef) []const usize {
103         if (section_ref.object_index >= self.objects.len) return &.{};
104         return self.objects[section_ref.object_index].groupsForSection(section_ref.section_index);
105     }
106 };