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 }