| ... | ... | @@ -8,7 +8,7 @@ pub fn isArchive(path: []const u8) !bool { |
| 8 | 8 | const file = try std.fs.cwd().openFile(path, .{}); |
| 9 | 9 | defer file.close(); |
| 10 | 10 | const reader = file.reader(); |
| 11 | | const magic = reader.readBytesNoEof(SARMAG) catch return false; |
| 11 | const magic = reader.readBytesNoEof(ARMAG.len) catch return false; |
| 12 | 12 | if (!mem.eql(u8, &magic, ARMAG)) return false; |
| 13 | 13 | return true; |
| 14 | 14 | } |
| ... | ... | @@ -24,14 +24,12 @@ pub fn parse(self: *Archive, elf_file: *Elf) !void { |
| 24 | 24 | |
| 25 | 25 | var stream = std.io.fixedBufferStream(self.data); |
| 26 | 26 | const reader = stream.reader(); |
| 27 | | _ = try reader.readBytesNoEof(SARMAG); |
| 27 | _ = try reader.readBytesNoEof(ARMAG.len); |
| 28 | 28 | |
| 29 | 29 | while (true) { |
| 30 | 30 | if (stream.pos >= self.data.len) break; |
| 31 | if (!mem.isAligned(stream.pos, 2)) stream.pos += 1; |
| 31 | 32 | |
| 32 | | if (stream.pos % 2 != 0) { |
| 33 | | stream.pos += 1; |
| 34 | | } |
| 35 | 33 | const hdr = try reader.readStruct(ar_hdr); |
| 36 | 34 | |
| 37 | 35 | if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) { |
| ... | ... | @@ -48,28 +46,23 @@ pub fn parse(self: *Archive, elf_file: *Elf) !void { |
| 48 | 46 | _ = stream.seekBy(size) catch {}; |
| 49 | 47 | } |
| 50 | 48 | |
| 51 | | if (hdr.isSymtab()) continue; |
| 49 | if (hdr.isSymtab() or hdr.isSymtab64()) continue; |
| 52 | 50 | if (hdr.isStrtab()) { |
| 53 | 51 | self.strtab = self.data[stream.pos..][0..size]; |
| 54 | 52 | continue; |
| 55 | 53 | } |
| 54 | if (hdr.isSymdef() or hdr.isSymdefSorted()) continue; |
| 56 | 55 | |
| 57 | | const name = ar_hdr.getValue(&hdr.ar_name); |
| 58 | | |
| 59 | | if (mem.eql(u8, name, "__.SYMDEF") or mem.eql(u8, name, "__.SYMDEF SORTED")) continue; |
| 60 | | |
| 61 | | const object_name = blk: { |
| 62 | | if (name[0] == '/') { |
| 63 | | const off = try std.fmt.parseInt(u32, name[1..], 10); |
| 64 | | const object_name = self.getString(off); |
| 65 | | break :blk try gpa.dupe(u8, object_name[0 .. object_name.len - 1]); // To account for trailing '/' |
| 66 | | } |
| 67 | | break :blk try gpa.dupe(u8, name); |
| 68 | | }; |
| 56 | const name = if (hdr.name()) |name| |
| 57 | try gpa.dupe(u8, name) |
| 58 | else if (try hdr.nameOffset()) |off| |
| 59 | try gpa.dupe(u8, self.getString(off)) |
| 60 | else |
| 61 | unreachable; |
| 69 | 62 | |
| 70 | 63 | const object = Object{ |
| 71 | 64 | .archive = try gpa.dupe(u8, self.path), |
| 72 | | .path = object_name, |
| 65 | .path = name, |
| 73 | 66 | .data = try gpa.dupe(u8, self.data[stream.pos..][0..size]), |
| 74 | 67 | .index = undefined, |
| 75 | 68 | .alive = false, |
| ... | ... | @@ -83,7 +76,8 @@ pub fn parse(self: *Archive, elf_file: *Elf) !void { |
| 83 | 76 | |
| 84 | 77 | fn getString(self: Archive, off: u32) []const u8 { |
| 85 | 78 | assert(off < self.strtab.len); |
| 86 | | return mem.sliceTo(@as([*:strtab_delimiter]const u8, @ptrCast(self.strtab.ptr + off)), 0); |
| 79 | const name = mem.sliceTo(@as([*:'\n']const u8, @ptrCast(self.strtab.ptr + off)), 0); |
| 80 | return name[0 .. name.len - 1]; |
| 87 | 81 | } |
| 88 | 82 | |
| 89 | 83 | pub fn setArHdr(opts: struct { |
| ... | ... | @@ -113,7 +107,7 @@ pub fn setArHdr(opts: struct { |
| 113 | 107 | switch (opts.name) { |
| 114 | 108 | .symtab => writer.print("{s}", .{Archive.SYM64NAME}) catch unreachable, |
| 115 | 109 | .strtab => writer.print("//", .{}) catch unreachable, |
| 116 | | .name => |x| writer.print("{s}", .{x}) catch unreachable, |
| 110 | .name => |x| writer.print("{s}/", .{x}) catch unreachable, |
| 117 | 111 | .name_off => |x| writer.print("/{d}", .{x}) catch unreachable, |
| 118 | 112 | } |
| 119 | 113 | } |
| ... | ... | @@ -125,25 +119,27 @@ pub fn setArHdr(opts: struct { |
| 125 | 119 | return hdr; |
| 126 | 120 | } |
| 127 | 121 | |
| 122 | fn genSpecialMemberName(comptime name: []const u8) *const [16]u8 { |
| 123 | assert(name.len <= 16); |
| 124 | const padding = 16 - name.len; |
| 125 | return name ++ &[_]u8{0x20} ** padding; |
| 126 | } |
| 127 | |
| 128 | 128 | // Archive files start with the ARMAG identifying string. Then follows a |
| 129 | 129 | // `struct ar_hdr', and as many bytes of member file data as its `ar_size' |
| 130 | 130 | // member indicates, for each member file. |
| 131 | 131 | /// String that begins an archive file. |
| 132 | | pub const ARMAG: *const [SARMAG:0]u8 = "!<arch>\n"; |
| 133 | | /// Size of that string. |
| 134 | | pub const SARMAG = 8; |
| 135 | | |
| 132 | pub const ARMAG = "!<arch>\n"; |
| 136 | 133 | /// String in ar_fmag at the end of each header. |
| 137 | | const ARFMAG: *const [2:0]u8 = "`\n"; |
| 138 | | |
| 139 | | /// Strtab identifier |
| 140 | | const STRNAME: *const [2:0]u8 = "//"; |
| 141 | | |
| 134 | const ARFMAG = "`\n"; |
| 142 | 135 | /// 32-bit symtab identifier |
| 143 | | const SYMNAME: *const [1:0]u8 = "/"; |
| 144 | | |
| 136 | const SYMNAME = genSpecialMemberName("/"); |
| 137 | /// Strtab identifier |
| 138 | const STRNAME = genSpecialMemberName("//"); |
| 145 | 139 | /// 64-bit symtab identifier |
| 146 | | const SYM64NAME: *const [7:0]u8 = "/SYM64/"; |
| 140 | const SYM64NAME = genSpecialMemberName("/SYM64/"); |
| 141 | const SYMDEFNAME = genSpecialMemberName("__.SYMDEF"); |
| 142 | const SYMDEFSORTEDNAME = genSpecialMemberName("__.SYMDEF SORTED"); |
| 147 | 143 | |
| 148 | 144 | const strtab_delimiter = '\n'; |
| 149 | 145 | |
| ... | ... | @@ -170,25 +166,47 @@ pub const ar_hdr = extern struct { |
| 170 | 166 | ar_fmag: [2]u8, |
| 171 | 167 | |
| 172 | 168 | fn date(self: ar_hdr) !u64 { |
| 173 | | const value = getValue(&self.ar_date); |
| 169 | const value = mem.trimRight(u8, &self.ar_date, &[_]u8{0x20}); |
| 174 | 170 | return std.fmt.parseInt(u64, value, 10); |
| 175 | 171 | } |
| 176 | 172 | |
| 177 | 173 | fn size(self: ar_hdr) !u32 { |
| 178 | | const value = getValue(&self.ar_size); |
| 174 | const value = mem.trimRight(u8, &self.ar_size, &[_]u8{0x20}); |
| 179 | 175 | return std.fmt.parseInt(u32, value, 10); |
| 180 | 176 | } |
| 181 | 177 | |
| 182 | | fn getValue(raw: []const u8) []const u8 { |
| 183 | | return mem.trimRight(u8, raw, &[_]u8{@as(u8, 0x20)}); |
| 184 | | } |
| 185 | | |
| 186 | 178 | fn isStrtab(self: ar_hdr) bool { |
| 187 | | return mem.eql(u8, getValue(&self.ar_name), STRNAME); |
| 179 | return mem.eql(u8, &self.ar_name, STRNAME); |
| 188 | 180 | } |
| 189 | 181 | |
| 190 | 182 | fn isSymtab(self: ar_hdr) bool { |
| 191 | | return mem.eql(u8, getValue(&self.ar_name), SYMNAME) or mem.eql(u8, getValue(&self.ar_name), SYM64NAME); |
| 183 | return mem.eql(u8, &self.ar_name, SYMNAME); |
| 184 | } |
| 185 | |
| 186 | fn isSymtab64(self: ar_hdr) bool { |
| 187 | return mem.eql(u8, &self.ar_name, SYM64NAME); |
| 188 | } |
| 189 | |
| 190 | fn isSymdef(self: ar_hdr) bool { |
| 191 | return mem.eql(u8, &self.ar_name, SYMDEFNAME); |
| 192 | } |
| 193 | |
| 194 | fn isSymdefSorted(self: ar_hdr) bool { |
| 195 | return mem.eql(u8, &self.ar_name, SYMDEFSORTEDNAME); |
| 196 | } |
| 197 | |
| 198 | fn name(self: *const ar_hdr) ?[]const u8 { |
| 199 | const value = &self.ar_name; |
| 200 | if (value[0] == '/') return null; |
| 201 | const sentinel = mem.indexOfScalar(u8, value, '/') orelse value.len; |
| 202 | return value[0..sentinel]; |
| 203 | } |
| 204 | |
| 205 | fn nameOffset(self: ar_hdr) !?u32 { |
| 206 | const value = &self.ar_name; |
| 207 | if (value[0] != '/') return null; |
| 208 | const trimmed = mem.trimRight(u8, value, &[_]u8{0x20}); |
| 209 | return try std.fmt.parseInt(u32, trimmed[1..], 10); |
| 192 | 210 | } |
| 193 | 211 | }; |
| 194 | 212 | |