lib/tldr/src/formats/elf/address/boundary.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 
 3 pub const Boundary = struct {
 4     section_name: []const u8,
 5     stop: bool,
 6     optional: bool = false,
 7     match_prefix: bool = false,
 8     output_section: bool = false,
 9 
10     pub const Context = struct {
11         pub fn hash(_: Context, boundary: Boundary) u64 {
12             var value = hashU64(0xd297a1b0a6e8d5f3, @intFromBool(boundary.stop));
13             value = hashU64(value, @intFromBool(boundary.optional));
14             value = hashU64(value, @intFromBool(boundary.match_prefix));
15             value = hashU64(value, @intFromBool(boundary.output_section));
16             return std.hash.Wyhash.hash(value, boundary.section_name);
17         }
18 
19         pub fn eql(_: Context, left: Boundary, right: Boundary) bool {
20             return left.stop == right.stop and
21                 left.optional == right.optional and
22                 left.match_prefix == right.match_prefix and
23                 left.output_section == right.output_section and
24                 std.mem.eql(u8, left.section_name, right.section_name);
25         }
26     };
27 };
28 
29 pub fn forSymbol(symbol_name: []const u8) ?Boundary {
30     if (std.mem.eql(u8, symbol_name, "__ehdr_start")) return .{ .section_name = "", .stop = false, .optional = true };
31     if (std.mem.eql(u8, symbol_name, "__rela_iplt_start")) return .{ .section_name = ".rela.iplt", .stop = false, .optional = true, .output_section = true };
32     if (std.mem.eql(u8, symbol_name, "__rela_iplt_end")) return .{ .section_name = ".rela.iplt", .stop = true, .optional = true, .output_section = true };
33     if (arrayForSymbol(symbol_name, "__preinit_array_start", "__preinit_array_end", ".preinit_array")) |boundary| return boundary;
34     if (arrayForSymbol(symbol_name, "__init_array_start", "__init_array_end", ".init_array")) |boundary| return boundary;
35     if (arrayForSymbol(symbol_name, "__fini_array_start", "__fini_array_end", ".fini_array")) |boundary| return boundary;
36 
37     const start_prefix = "__start_";
38     const stop_prefix = "__stop_";
39     if (std.mem.startsWith(u8, symbol_name, start_prefix)) {
40         const section_name = symbol_name[start_prefix.len..];
41         if (isCIdentifier(section_name)) return .{ .section_name = section_name, .stop = false };
42     }
43     if (std.mem.startsWith(u8, symbol_name, stop_prefix)) {
44         const section_name = symbol_name[stop_prefix.len..];
45         if (isCIdentifier(section_name)) return .{ .section_name = section_name, .stop = true };
46     }
47     return null;
48 }
49 
50 pub fn sectionNameMatches(boundary: Boundary, section_name: []const u8) bool {
51     if (std.mem.eql(u8, section_name, boundary.section_name)) return true;
52     return boundary.match_prefix and
53         section_name.len > boundary.section_name.len and
54         std.mem.startsWith(u8, section_name, boundary.section_name) and
55         section_name[boundary.section_name.len] == '.';
56 }
57 
58 fn arrayForSymbol(symbol_name: []const u8, start_name: []const u8, end_name: []const u8, section_name: []const u8) ?Boundary {
59     if (std.mem.eql(u8, symbol_name, start_name)) {
60         return .{ .section_name = section_name, .stop = false, .optional = true, .match_prefix = true };
61     }
62     if (std.mem.eql(u8, symbol_name, end_name)) {
63         return .{ .section_name = section_name, .stop = true, .optional = true, .match_prefix = true };
64     }
65     return null;
66 }
67 
68 fn isCIdentifier(name: []const u8) bool {
69     if (name.len == 0) return false;
70     if (!isCIdentifierStart(name[0])) return false;
71     for (name[1..]) |byte| {
72         if (!isCIdentifierContinue(byte)) return false;
73     }
74     return true;
75 }
76 
77 fn isCIdentifierStart(byte: u8) bool {
78     return byte == '_' or (byte >= 'a' and byte <= 'z') or (byte >= 'A' and byte <= 'Z');
79 }
80 
81 fn isCIdentifierContinue(byte: u8) bool {
82     return isCIdentifierStart(byte) or (byte >= '0' and byte <= '9');
83 }
84 
85 fn hashU64(seed: u64, value: u64) u64 {
86     var bytes: [8]u8 = undefined;
87     std.mem.writeInt(u64, &bytes, value, .little);
88     return std.hash.Wyhash.hash(seed, &bytes);
89 }