tp/tools/libelf/elf.py

397 lines
8.6 KiB
Python

from typing import IO, Dict
from dataclasses import dataclass, field
from .util import *
EI_MAG = 0
EI_CLASS = 1
EI_DATA = 2
EI_VERSION = 3
EI_OSABI = 4
EI_ABIVERSION = 5
EI_PAD = 6
ET_NONE = 0x00
ET_REL = 0x01
ET_EXEC = 0x02
ET_DYN = 0x03
ET_CORE = 0x04
ET_LOOS = 0xFE00
ET_HIOS = 0xFEFF
ET_LOPROC = 0xFF00
ET_HIPROC = 0xFFFF
EM_POWERPC = 0x14
@dataclass
class Header:
e_ident: Dict[int, object] = field(default_factory=lambda: {
EI_MAG: 0x7F454C46,
EI_CLASS: 1, # 32-bit
EI_DATA: 2, # big endian
EI_VERSION: 1,
EI_OSABI: 0,
EI_ABIVERSION: 0,
EI_PAD: [0, 0, 0, 0, 0, 0, 0]
})
e_type: int = 0
e_machine: int = 0
e_version: int = 0
e_entry: int = 0
e_phoff: int = 0
e_shoff: int = 0
e_flags: int = 0
e_ehsize: int = 0x34
e_phentsize: int = 0
e_phnum: int = 0
e_shentsize: int = 0
e_shnum: int = 0
e_shstrndx: int = 0
def read(self, file: IO):
self.e_ident[EI_MAG] = read_u32(file)
self.e_ident[EI_CLASS] = read_u8(file)
self.e_ident[EI_DATA] = read_u8(file)
self.e_ident[EI_VERSION] = read_u8(file)
self.e_ident[EI_OSABI] = read_u8(file)
self.e_ident[EI_ABIVERSION] = read_u8(file)
self.e_ident[EI_PAD] = read_u8_array(file, 7)
self.e_type = read_u16(file)
self.e_machine = read_u16(file)
self.e_version = read_u32(file)
self.e_entry = read_u32(file)
self.e_phoff = read_u32(file)
self.e_shoff = read_u32(file)
self.e_flags = read_u32(file)
self.e_ehsize = read_u16(file)
self.e_phentsize = read_u16(file)
self.e_phnum = read_u16(file)
self.e_shentsize = read_u16(file)
self.e_shnum = read_u16(file)
self.e_shstrndx = read_u16(file)
def write(self, file: IO):
write_u32(file, self.e_ident[EI_MAG])
write_u8(file, self.e_ident[EI_CLASS])
write_u8(file, self.e_ident[EI_DATA])
write_u8(file, self.e_ident[EI_VERSION])
write_u8(file, self.e_ident[EI_OSABI])
write_u8(file, self.e_ident[EI_ABIVERSION])
write_u8_array(file, [0] * 7)
write_u16(file, self.e_type)
write_u16(file, self.e_machine)
write_u32(file, self.e_version)
write_u32(file, self.e_entry)
write_u32(file, self.e_phoff)
write_u32(file, self.e_shoff)
write_u32(file, self.e_flags)
write_u16(file, self.e_ehsize)
write_u16(file, self.e_phentsize)
write_u16(file, self.e_phnum)
write_u16(file, self.e_shentsize)
write_u16(file, self.e_shnum)
write_u16(file, self.e_shstrndx)
PT_NULL = 0x00000000
PT_LOAD = 0x00000001
PT_DYNAMIC = 0x00000002
PT_INTERP = 0x00000003
PT_NOTE = 0x00000004
PT_SHLIB = 0x00000005
PT_PHDR = 0x00000006
PT_TLS = 0x00000007
PT_LOOS = 0x60000000
PT_HIOS = 0x6FFFFFFF
PT_LOPROC = 0x70000000
PT_HIPROC = 0x7FFFFFFF
PF_X = 0x1
PF_W = 0x2
PF_R = 0x4
@dataclass
class ProgramHeader:
p_type: int = 0
p_offset: int = 0
p_vaddr: int = 0
p_paddr: int = 0
p_filesz: int = 0
p_memsz: int = 0
p_flags: int = 0
p_align: int = 0
def read(self, file: IO):
self.p_type = read_u32(file)
self.p_offset = read_u32(file)
self.p_vaddr = read_u32(file)
self.p_paddr = read_u32(file)
self.p_filesz = read_u32(file)
self.p_memsz = read_u32(file)
self.p_flags = read_u32(file)
self.p_align = read_u32(file)
def write(self, file: IO):
write_u32(file, self.p_type)
write_u32(file, self.p_offset)
write_u32(file, self.p_vaddr)
write_u32(file, self.p_paddr)
write_u32(file, self.p_filesz)
write_u32(file, self.p_memsz)
write_u32(file, self.p_flags)
write_u32(file, self.p_align)
SHT_NULL = 0x0
SHT_PROGBITS = 0x1
SHT_SYMTAB = 0x2
SHT_STRTAB = 0x3
SHT_RELA = 0x4
SHT_HASH = 0x5
SHT_DYNAMIC = 0x6
SHT_NOTE = 0x7
SHT_NOBITS = 0x8
SHT_REL = 0x9
SHT_SHLIB = 0x0A
SHT_DYNSYM = 0x0B
SHT_INIT_ARRAY = 0x0E
SHT_FINI_ARRAY = 0x0F
SHT_PREINIT_ARRAY = 0x10
SHT_GROUP = 0x11
SHT_SYMTAB_SHNDX = 0x12
SHT_NUM = 0x13
SHT_MW_CATS = 0xCA2A82C2
SH_TYPES = {
0x0: "SHT_NULL",
0x1: "SHT_PROGBITS",
0x2: "SHT_SYMTAB",
0x3: "SHT_STRTAB",
0x4: "SHT_RELA",
0x5: "SHT_HASH",
0x6: "SHT_DYNAMIC",
0x7: "SHT_NOTE",
0x8: "SHT_NOBITS",
0x9: "SHT_REL",
0x0A: "SHT_SHLIB",
0x0B: "SHT_DYNSYM",
0x0E: "SHT_INIT_ARRAY",
0x0F: "SHT_FINI_ARRAY",
0x10: "SHT_PREINIT_ARRAY",
0x11: "SHT_GROUP",
0x12: "SHT_SYMTAB_SHNDX",
0x13: "SHT_NUM",
0xCA2A82C2: "SHT_MW_CATS",
}
SHF_WRITE = 0x1
SHF_ALLOC = 0x2
SHF_EXECINSTR = 0x4
SHF_MERGE = 0x10
SHF_STRINGS = 0x20
SHF_INFO_LINK = 0x40
SHF_LINK_ORDER = 0x80
SHF_OS_NONCONFORMING = 0x100
SHF_GROUP = 0x200
SHF_TLS = 0x400
SHF_MASKOS = 0x0ff00000
SHF_MASKPROC = 0xf0000000
SHF_ORDERED = 0x4000000
SHF_EXCLUDE = 0x8000000
SH_FLAGS = {
0x1: "SHF_WRITE",
0x2: "SHF_ALLOC",
0x4: "SHF_EXECINSTR",
0x10: "SHF_MERGE",
0x20: "SHF_STRINGS",
0x40: "SHF_INFO_LINK",
0x80: "SHF_LINK_ORDER",
0x100: "SHF_OS_NONCONFORMING",
0x200: "SHF_GROUP",
0x400: "SHF_TLS",
0x0ff00000: "SHF_MASKOS",
0xf0000000: "SHF_MASKPROC",
0x4000000: "SHF_ORDERED",
0x8000000: "SHF_EXCLUDE",
}
@dataclass(unsafe_hash=True)
class SectionHeader:
id: int = 0
sh_name: int = 0
sh_type: int = 0
sh_flags: int = 0
sh_addr: int = 0
sh_offset: int = 0
sh_size: int = 0
sh_link: int = 0
sh_info: int = 0
sh_addralign: int = 0
sh_entsize: int = 0
data: bytes = field(default_factory=bytes, hash=False)
def read(self, id: int, file: IO):
self.id = id
self.sh_name = read_u32(file)
self.sh_type = read_u32(file)
self.sh_flags = read_u32(file)
self.sh_addr = read_u32(file)
self.sh_offset = read_u32(file)
self.sh_size = read_u32(file)
self.sh_link = read_u32(file)
self.sh_info = read_u32(file)
self.sh_addralign = read_u32(file)
self.sh_entsize = read_u32(file)
def write(self, file: IO):
write_u32(file, self.sh_name)
write_u32(file, self.sh_type)
write_u32(file, self.sh_flags)
write_u32(file, self.sh_addr)
write_u32(file, self.sh_offset)
write_u32(file, self.sh_size)
write_u32(file, self.sh_link)
write_u32(file, self.sh_info)
write_u32(file, self.sh_addralign)
write_u32(file, self.sh_entsize)
def ST_BIND(i):
return ((i) >> 4)
def ST_TYPE(i):
return ((i) & 0xf)
def ST_INFO(b, t):
return ((((b) & 0xf) << 4)+((t) & 0xf))
def ST_VISIBILITY(o):
return ((o) & 0x3)
STB_LOCAL = 0
STB_GLOBAL = 1
STB_WEAK = 2
STB_LOOS = 10
STB_HIOS = 12
STB_LOPROC = 13
STB_HIPROC = 15
ST_BINDS = {
0: "STB_LOCAL",
1: "STB_GLOBAL",
2: "STB_WEAK",
10: "STB_LOOS",
12: "STB_HIOS",
13: "STB_LOPROC",
15: "STB_HIPROC",
}
STT_NOTYPE = 0
STT_OBJECT = 1
STT_FUNC = 2
STT_SECTION = 3
STT_FILE = 4
STT_COMMON = 5
STT_TLS = 6
STT_LOOS = 10
STT_HIOS = 12
STT_LOPROC = 13
STT_HIPROC = 15
ST_TYPES = {
0: "STT_NOTYPE",
1: "STT_OBJECT",
2: "STT_FUNC",
3: "STT_SECTION",
4: "STT_FILE",
5: "STT_COMMON",
6: "STT_TLS",
10: "STT_LOOS",
12: "STT_HIOS",
13: "STT_LOPROC",
15: "STT_HIPROC",
}
STV_DEFAULT = 0
STV_INTERNAL = 1
STV_HIDDEN = 2
STV_PROTECTED = 3
ST_VISIBILITIES = {
0: "STV_DEFAULT",
1: "STV_INTERNAL",
2: "STV_HIDDEN",
3: "STV_PROTECTED",
}
SHN_UNDEF = 0
SHN_LORESERVE = 0xff00
SHN_LOPROC = 0xff00
SHN_HIPROC = 0xff1f
SHN_ABS = 0xfff1
SHN_COMMON = 0xfff2
SHN_HIRESERVE = 0xffff
@dataclass
class Symbol:
st_name: int = 0
st_value: int = 0
st_size: int = 0
st_info: int = 0
st_other: int = 0
st_shndx: int = SHN_UNDEF
def read(self, file: IO):
self.st_name = read_u32(file)
self.st_value = read_u32(file)
self.st_size = read_u32(file)
self.st_info = read_u8(file)
self.st_other = read_u8(file)
self.st_shndx = read_u16(file)
def write(self, file: IO):
write_u32(file, self.st_name)
write_u32(file, self.st_value)
write_u32(file, self.st_size)
write_u8(file, self.st_info)
write_u8(file, self.st_other)
write_u16(file, self.st_shndx)
def R_SYM(i):
return ((i) >> 8)
def R_TYPE(i):
return ((i) & 0xFF)
def R_INFO(s, t):
return (((s) << 8)+((t) & 0xFF))
@dataclass
class RelA:
r_offset: int = 0
r_info: int = 0
r_addend: int = 0
def read(self, file: IO):
self.r_offset = read_u32(file)
self.r_info = read_u32(file)
self.r_addend = read_s32(file)