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 }