lib/tldr/src/formats/elf/liveness/state.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const root = @import("../../../root.zig");
3 const elf = @import("../root.zig");
4
5 const Allocator = std.mem.Allocator;
6 const model = root.model;
7 const ObjectFile = elf.parser.ObjectFile;
8 const SectionRef = elf.parser.SectionRef;
9 const ensureDiscardedSections = elf.section_state.ensureDiscardedSections;
10 const sectionDiscarded = elf.section_state.sectionDiscarded;
11
12 pub const State = struct {
13 live_sections: [][]bool,
14 live_count: usize,
15 pending: std.ArrayListUnmanaged(SectionRef),
16 };
17
18 pub fn init(allocator: Allocator, objects: []const ObjectFile) model.Error!State {
19 var live_sections = try allocator.alloc([]bool, objects.len);
20 var live_count: usize = 0;
21 errdefer {
22 for (live_sections[0..live_count]) |sections| allocator.free(sections);
23 allocator.free(live_sections);
24 }
25
26 for (objects, 0..) |object, object_index| {
27 live_sections[object_index] = try allocator.alloc(bool, object.sections.len);
28 @memset(live_sections[object_index], false);
29 live_count += 1;
30 }
31
32 var pending: std.ArrayListUnmanaged(SectionRef) = .empty;
33 errdefer pending.deinit(allocator);
34 try pending.ensureTotalCapacity(allocator, try countSections(objects));
35
36 return .{
37 .live_sections = live_sections,
38 .live_count = live_count,
39 .pending = pending,
40 };
41 }
42
43 pub fn deinit(live: *State, allocator: Allocator) void {
44 live.pending.deinit(allocator);
45 for (live.live_sections[0..live.live_count]) |sections| allocator.free(sections);
46 allocator.free(live.live_sections);
47 live.* = .{
48 .live_sections = &.{},
49 .live_count = 0,
50 .pending = .empty,
51 };
52 }
53
54 pub fn markSection(
55 live: *State,
56 objects: []const ObjectFile,
57 section_ref: SectionRef,
58 ) model.Error!void {
59 if (section_ref.object_index >= objects.len) return error.InvalidObject;
60 const object = objects[section_ref.object_index];
61 if (section_ref.section_index >= object.sections.len) return error.MissingSection;
62 if (sectionDiscarded(object, section_ref.section_index)) return;
63 if (live.live_sections[section_ref.object_index][section_ref.section_index]) return;
64
65 live.live_sections[section_ref.object_index][section_ref.section_index] = true;
66 live.pending.appendAssumeCapacity(section_ref);
67 }
68
69 pub fn discardUnmarked(
70 live: *State,
71 allocator: Allocator,
72 objects: []ObjectFile,
73 ) model.Error!void {
74 for (objects, 0..) |*object, object_index| {
75 const discarded_sections = try ensureDiscardedSections(allocator, object);
76 for (object.sections, 0..) |section, section_index| {
77 if (discarded_sections[section_index]) continue;
78 if ((section.flags & std.elf.SHF_ALLOC) == 0) continue;
79 if (!live.live_sections[object_index][section_index]) {
80 discarded_sections[section_index] = true;
81 }
82 }
83 }
84 }
85
86 fn countSections(objects: []const ObjectFile) model.Error!usize {
87 var total: usize = 0;
88 for (objects) |object| {
89 if (object.sections.len > std.math.maxInt(usize) - total) return error.InvalidObject;
90 total += object.sections.len;
91 }
92 return total;
93 }