mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
Merge pull request #7763 from kivikakk/zig-elf-parse
std.elf: expose parsing decoupled from std.fs.File
This commit is contained in:
commit
ffb2568a9f
@ -51,9 +51,9 @@ const BinaryElfOutput = struct {
|
||||
.segments = ArrayList(*BinaryElfSegment).init(allocator),
|
||||
.sections = ArrayList(*BinaryElfSection).init(allocator),
|
||||
};
|
||||
const elf_hdr = try std.elf.readHeader(elf_file);
|
||||
const elf_hdr = try std.elf.Header.read(&elf_file);
|
||||
|
||||
var section_headers = elf_hdr.section_header_iterator(elf_file);
|
||||
var section_headers = elf_hdr.section_header_iterator(&elf_file);
|
||||
while (try section_headers.next()) |section| {
|
||||
if (sectionValidForOutput(section)) {
|
||||
const newSection = try allocator.create(BinaryElfSection);
|
||||
@ -67,7 +67,7 @@ const BinaryElfOutput = struct {
|
||||
}
|
||||
}
|
||||
|
||||
var program_headers = elf_hdr.program_header_iterator(elf_file);
|
||||
var program_headers = elf_hdr.program_header_iterator(&elf_file);
|
||||
while (try program_headers.next()) |phdr| {
|
||||
if (phdr.p_type == elf.PT_LOAD) {
|
||||
const newSegment = try allocator.create(BinaryElfSegment);
|
||||
|
||||
@ -335,7 +335,7 @@ pub const ET = extern enum(u16) {
|
||||
};
|
||||
|
||||
/// All integers are native endian.
|
||||
const Header = struct {
|
||||
pub const Header = struct {
|
||||
endian: builtin.Endian,
|
||||
is_64: bool,
|
||||
entry: u64,
|
||||
@ -347,26 +347,30 @@ const Header = struct {
|
||||
shnum: u16,
|
||||
shstrndx: u16,
|
||||
|
||||
pub fn program_header_iterator(self: Header, file: File) ProgramHeaderIterator {
|
||||
return .{
|
||||
pub fn program_header_iterator(self: Header, parse_source: anytype) ProgramHeaderIterator(@TypeOf(parse_source)) {
|
||||
return ProgramHeaderIterator(@TypeOf(parse_source)){
|
||||
.elf_header = self,
|
||||
.file = file,
|
||||
.parse_source = parse_source,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn section_header_iterator(self: Header, file: File) SectionHeaderIterator {
|
||||
return .{
|
||||
pub fn section_header_iterator(self: Header, parse_source: anytype) SectionHeaderIterator(@TypeOf(parse_source)) {
|
||||
return SectionHeaderIterator(@TypeOf(parse_source)){
|
||||
.elf_header = self,
|
||||
.file = file,
|
||||
.parse_source = parse_source,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub fn readHeader(file: File) !Header {
|
||||
pub fn read(parse_source: anytype) !Header {
|
||||
var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;
|
||||
try preadNoEof(file, &hdr_buf, 0);
|
||||
const hdr32 = @ptrCast(*Elf32_Ehdr, &hdr_buf);
|
||||
const hdr64 = @ptrCast(*Elf64_Ehdr, &hdr_buf);
|
||||
try parse_source.seekableStream().seekTo(0);
|
||||
try parse_source.reader().readNoEof(&hdr_buf);
|
||||
return Header.parse(&hdr_buf);
|
||||
}
|
||||
|
||||
pub fn parse(hdr_buf: *align(@alignOf(Elf64_Ehdr)) const [@sizeOf(Elf64_Ehdr)]u8) !Header {
|
||||
const hdr32 = @ptrCast(*const Elf32_Ehdr, hdr_buf);
|
||||
const hdr64 = @ptrCast(*const Elf64_Ehdr, hdr_buf);
|
||||
if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
|
||||
if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion;
|
||||
|
||||
@ -395,21 +399,24 @@ pub fn readHeader(file: File) !Header {
|
||||
.shnum = int(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum),
|
||||
.shstrndx = int(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx),
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const ProgramHeaderIterator = struct {
|
||||
pub fn ProgramHeaderIterator(ParseSource: anytype) type {
|
||||
return struct {
|
||||
elf_header: Header,
|
||||
file: File,
|
||||
parse_source: ParseSource,
|
||||
index: usize = 0,
|
||||
|
||||
pub fn next(self: *ProgramHeaderIterator) !?Elf64_Phdr {
|
||||
pub fn next(self: *@This()) !?Elf64_Phdr {
|
||||
if (self.index >= self.elf_header.phnum) return null;
|
||||
defer self.index += 1;
|
||||
|
||||
if (self.elf_header.is_64) {
|
||||
var phdr: Elf64_Phdr = undefined;
|
||||
const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
|
||||
try preadNoEof(self.file, mem.asBytes(&phdr), offset);
|
||||
try self.parse_source.seekableStream().seekTo(offset);
|
||||
try self.parse_source.reader().readNoEof(mem.asBytes(&phdr));
|
||||
|
||||
// ELF endianness matches native endianness.
|
||||
if (self.elf_header.endian == std.builtin.endian) return phdr;
|
||||
@ -429,7 +436,8 @@ pub const ProgramHeaderIterator = struct {
|
||||
|
||||
var phdr: Elf32_Phdr = undefined;
|
||||
const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
|
||||
try preadNoEof(self.file, mem.asBytes(&phdr), offset);
|
||||
try self.parse_source.seekableStream().seekTo(offset);
|
||||
try self.parse_source.reader().readNoEof(mem.asBytes(&phdr));
|
||||
|
||||
// ELF endianness does NOT match native endianness.
|
||||
if (self.elf_header.endian != std.builtin.endian) {
|
||||
@ -458,21 +466,24 @@ pub const ProgramHeaderIterator = struct {
|
||||
.p_align = phdr.p_align,
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
pub const SectionHeaderIterator = struct {
|
||||
pub fn SectionHeaderIterator(ParseSource: anytype) type {
|
||||
return struct {
|
||||
elf_header: Header,
|
||||
file: File,
|
||||
parse_source: ParseSource,
|
||||
index: usize = 0,
|
||||
|
||||
pub fn next(self: *SectionHeaderIterator) !?Elf64_Shdr {
|
||||
pub fn next(self: *@This()) !?Elf64_Shdr {
|
||||
if (self.index >= self.elf_header.shnum) return null;
|
||||
defer self.index += 1;
|
||||
|
||||
if (self.elf_header.is_64) {
|
||||
var shdr: Elf64_Shdr = undefined;
|
||||
const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
|
||||
try preadNoEof(self.file, mem.asBytes(&shdr), offset);
|
||||
try self.parse_source.seekableStream().seekTo(offset);
|
||||
try self.parse_source.reader().readNoEof(mem.asBytes(&shdr));
|
||||
|
||||
// ELF endianness matches native endianness.
|
||||
if (self.elf_header.endian == std.builtin.endian) return shdr;
|
||||
@ -494,7 +505,8 @@ pub const SectionHeaderIterator = struct {
|
||||
|
||||
var shdr: Elf32_Shdr = undefined;
|
||||
const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
|
||||
try preadNoEof(self.file, mem.asBytes(&shdr), offset);
|
||||
try self.parse_source.seekableStream().seekTo(offset);
|
||||
try self.parse_source.reader().readNoEof(mem.asBytes(&shdr));
|
||||
|
||||
// ELF endianness does NOT match native endianness.
|
||||
if (self.elf_header.endian != std.builtin.endian) {
|
||||
@ -527,7 +539,8 @@ pub const SectionHeaderIterator = struct {
|
||||
.sh_entsize = shdr.sh_entsize,
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {
|
||||
if (is_64) {
|
||||
@ -549,28 +562,6 @@ pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {
|
||||
}
|
||||
}
|
||||
|
||||
fn preadNoEof(file: std.fs.File, buf: []u8, offset: u64) !void {
|
||||
var i: usize = 0;
|
||||
while (i < buf.len) {
|
||||
const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) {
|
||||
error.SystemResources => return error.SystemResources,
|
||||
error.IsDir => return error.UnableToReadElfFile,
|
||||
error.OperationAborted => return error.UnableToReadElfFile,
|
||||
error.BrokenPipe => return error.UnableToReadElfFile,
|
||||
error.Unseekable => return error.UnableToReadElfFile,
|
||||
error.ConnectionResetByPeer => return error.UnableToReadElfFile,
|
||||
error.ConnectionTimedOut => return error.UnableToReadElfFile,
|
||||
error.InputOutput => return error.FileSystem,
|
||||
error.Unexpected => return error.Unexpected,
|
||||
error.WouldBlock => return error.Unexpected,
|
||||
error.NotOpenForReading => return error.Unexpected,
|
||||
error.AccessDenied => return error.Unexpected,
|
||||
};
|
||||
if (len == 0) return error.UnexpectedEndOfFile;
|
||||
i += len;
|
||||
}
|
||||
}
|
||||
|
||||
pub const EI_NIDENT = 16;
|
||||
|
||||
pub const EI_CLASS = 4;
|
||||
|
||||
@ -1030,8 +1030,8 @@ pub const TestContext = struct {
|
||||
var file = try tmp_dir.openFile(bin_name, .{ .read = true });
|
||||
defer file.close();
|
||||
|
||||
const header = try std.elf.readHeader(file);
|
||||
var iterator = header.program_header_iterator(file);
|
||||
const header = try std.elf.Header.read(&file);
|
||||
var iterator = header.program_header_iterator(&file);
|
||||
|
||||
var none_loaded = true;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user