All integers are native endian.
pub const Header = struct
pub const Header = struct {
is_64: bool,
endian: Endian,
os_abi: OSABI,
/// The meaning of this value depends on `os_abi`.
abi_version: u8,
type: ET,
machine: EM,
entry: u64,
phoff: u64,
shoff: u64,
phentsize: u16,
phnum: u16,
shentsize: u16,
shnum: u16,
shstrndx: u16,
pub fn iterateProgramHeaders(h: *const Header, file_reader: *Io.File.Reader) ProgramHeaderIterator {
return .{
.is_64 = h.is_64,
.endian = h.endian,
.phnum = h.phnum,
.phoff = h.phoff,
.file_reader = file_reader,
};
}
pub fn iterateProgramHeadersBuffer(h: *const Header, buf: []const u8) ProgramHeaderBufferIterator {
return .{
.is_64 = h.is_64,
.endian = h.endian,
.phnum = h.phnum,
.phoff = h.phoff,
.buf = buf,
};
}
pub fn iterateSectionHeaders(h: *const Header, file_reader: *Io.File.Reader) SectionHeaderIterator {
return .{
.is_64 = h.is_64,
.endian = h.endian,
.shnum = h.shnum,
.shoff = h.shoff,
.file_reader = file_reader,
};
}
pub fn iterateSectionHeadersBuffer(h: *const Header, buf: []const u8) SectionHeaderBufferIterator {
return .{
.is_64 = h.is_64,
.endian = h.endian,
.shnum = h.shnum,
.shoff = h.shoff,
.buf = buf,
};
}
pub fn iterateDynamicSection(
h: *const Header,
file_reader: *Io.File.Reader,
offset: u64,
size: u64,
) DynamicSectionIterator {
return .{
.is_64 = h.is_64,
.endian = h.endian,
.offset = offset,
.end_offset = offset + size,
.file_reader = file_reader,
};
}
pub fn iterateDynamicSectionBuffer(
h: *const Header,
buf: []const u8,
offset: u64,
size: u64,
) DynamicSectionBufferIterator {
return .{
.is_64 = h.is_64,
.endian = h.endian,
.offset = offset,
.end_offset = offset + size,
.buf = buf,
};
}
pub const ReadError = Io.Reader.Error || error{
InvalidElfMagic,
InvalidElfVersion,
InvalidElfClass,
InvalidElfEndian,
};
/// If this function fails, seek position of `r` is unchanged.
pub fn read(r: *Io.Reader) ReadError!Header {
const buf = try r.peek(@sizeOf(Elf64_Ehdr));
if (!mem.eql(u8, buf[0..4], MAGIC)) return error.InvalidElfMagic;
if (buf[EI.VERSION] != 1) return error.InvalidElfVersion;
const endian: Endian = switch (buf[EI.DATA]) {
ELFDATA2LSB => .little,
ELFDATA2MSB => .big,
else => return error.InvalidElfEndian,
};
return switch (buf[EI.CLASS]) {
ELFCLASS32 => .init(try r.takeStruct(Elf32_Ehdr, endian), endian),
ELFCLASS64 => .init(try r.takeStruct(Elf64_Ehdr, endian), endian),
else => return error.InvalidElfClass,
};
}
pub fn init(hdr: anytype, endian: Endian) Header {
// Converting integers to exhaustive enums using `@enumFromInt` could cause a panic.
comptime assert(@typeInfo(OSABI).@"enum".mode == .nonexhaustive);
return .{
.is_64 = switch (@TypeOf(hdr)) {
Elf32_Ehdr => false,
Elf64_Ehdr => true,
else => @compileError("bad type"),
},
.endian = endian,
.os_abi = @fromBackingInt(@intCast(hdr.e_ident[EI.OSABI])),
.abi_version = hdr.e_ident[EI.ABIVERSION],
.type = hdr.e_type,
.machine = hdr.e_machine,
.entry = hdr.e_entry,
.phoff = hdr.e_phoff,
.shoff = hdr.e_shoff,
.phentsize = hdr.e_phentsize,
.phnum = hdr.e_phnum,
.shentsize = hdr.e_shentsize,
.shnum = hdr.e_shnum,
.shstrndx = hdr.e_shstrndx,
};
}
}