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 };