in net/JetBrains.FormatRipper/src/Elf/ElfFile.cs [52:177]
public static ElfFile Parse(Stream stream)
{
stream.Position = 0;
var eIdent = StreamUtil.ReadBytes(stream, EI.EI_NIDENT);
if (eIdent[EI.EI_MAG0] != ELFMAG.ELFMAG0 ||
eIdent[EI.EI_MAG1] != ELFMAG.ELFMAG1 ||
eIdent[EI.EI_MAG2] != ELFMAG.ELFMAG2 ||
eIdent[EI.EI_MAG3] != ELFMAG.ELFMAG3)
throw new FormatException("Invalid ELF magic numbers");
if ((EV)eIdent[EI.EI_VERSION] != EV.EV_CURRENT)
throw new FormatException("Invalid ELF file version");
var eiData = (ELFDATA)eIdent[EI.EI_DATA];
var needSwap = BitConverter.IsLittleEndian != eiData switch
{
ELFDATA.ELFDATA2LSB => true,
ELFDATA.ELFDATA2MSB => false,
_ => throw new FormatException("Invalid ELF data encoding")
};
ushort GetU2(ushort v) => needSwap ? MemoryUtil.SwapU2(v) : v;
uint GetU4(uint v) => needSwap ? MemoryUtil.SwapU4(v) : v;
ulong GetU8(ulong v) => needSwap ? MemoryUtil.SwapU8(v) : v;
unsafe Data Read32()
{
Elf32_Ehdr ehdr;
StreamUtil.ReadBytes(stream, (byte*)&ehdr, sizeof(Elf32_Ehdr));
if (ehdr.e_ehsize < EI.EI_NIDENT + sizeof(Elf32_Ehdr))
throw new FormatException("Invalid ELF header size");
if (GetU4(ehdr.e_version) != 1u)
throw new FormatException("Invalid ELF object file version");
stream.Position = GetU4(ehdr.e_phoff);
var ePhNum = GetU2(ehdr.e_phnum);
var ePhEntSize = GetU2(ehdr.e_phentsize);
if (ePhNum > 0 && ePhEntSize < sizeof(Elf32_Phdr))
throw new FormatException("Too small ELF program header entry size");
string? interpreter = null;
if (ePhNum > 0)
{
fixed (byte* buf = StreamUtil.ReadBytes(stream, checked(ePhNum * ePhEntSize)))
{
for (var ptr = buf; ePhNum-- > 0; ptr += ePhEntSize)
{
Elf32_Phdr phdr;
MemoryUtil.CopyBytes(ptr, (byte*)&phdr, sizeof(Elf32_Phdr));
switch ((PT)GetU4(phdr.p_type))
{
case PT.PT_INTERP:
stream.Position = GetU4(phdr.p_offset);
var interpreterBuf = StreamUtil.ReadBytes(stream, checked((int)GetU4(phdr.p_filesz)));
interpreter = new string(Encoding.UTF8.GetChars(interpreterBuf, 0,
MemoryUtil.GetAsciiStringZSize(interpreterBuf)));
break;
}
}
}
}
return new(
(ET)GetU2(ehdr.e_type),
(EM)GetU2(ehdr.e_machine),
(EF)GetU4(ehdr.e_flags),
interpreter);
}
unsafe Data Read64()
{
Elf64_Ehdr ehdr;
StreamUtil.ReadBytes(stream, (byte*)&ehdr, sizeof(Elf64_Ehdr));
if (ehdr.e_ehsize < EI.EI_NIDENT + sizeof(Elf64_Ehdr))
throw new FormatException("Invalid ELF header size");
if (GetU4(ehdr.e_version) != 1u)
throw new FormatException("Invalid ELF object file version");
stream.Position = checked((long)GetU8(ehdr.e_phoff));
var ePhNum = GetU2(ehdr.e_phnum);
var ePhEntSize = GetU2(ehdr.e_phentsize);
if (ePhNum > 0 && ePhEntSize < sizeof(Elf64_Phdr))
throw new FormatException("Too small ELF program header entry size");
string? interpreter = null;
if (ePhNum > 0)
{
fixed (byte* buf = StreamUtil.ReadBytes(stream, checked(ePhNum * ePhEntSize)))
{
for (var ptr = buf; ePhNum-- > 0; ptr += ePhEntSize)
{
Elf64_Phdr phdr;
MemoryUtil.CopyBytes(ptr, (byte*)&phdr, sizeof(Elf64_Phdr));
switch ((PT)GetU4(phdr.p_type))
{
case PT.PT_INTERP:
stream.Position = checked((long)GetU8(phdr.p_offset));
var interpreterBuf = StreamUtil.ReadBytes(stream, checked((int)GetU8(phdr.p_filesz)));
interpreter = new string(Encoding.UTF8.GetChars(interpreterBuf, 0,
MemoryUtil.GetAsciiStringZSize(interpreterBuf)));
break;
}
}
}
}
return new(
(ET)GetU2(ehdr.e_type),
(EM)GetU2(ehdr.e_machine),
(EF)GetU4(ehdr.e_flags),
interpreter);
}
var eiClass = (ELFCLASS)eIdent[EI.EI_CLASS];
var data = eiClass switch
{
ELFCLASS.ELFCLASS32 => Read32(),
ELFCLASS.ELFCLASS64 => Read64(),
_ => throw new FormatException("Invalid ELF file encoding")
};
return new(eiClass, eiData, (ELFOSABI)eIdent[EI.EI_OSABI], eIdent[EI.EI_ABIVERSION], data.EType, data.EMachine, data.EFlags, data.Interpreter);
}