mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-26 02:25:36 +00:00
660276a0b8
I'm not a fan of 100% of the Black coding style, but I've spent too much time manually formatting Python code, so let's just pull the trigger.
157 lines
5.0 KiB
Python
157 lines
5.0 KiB
Python
import struct
|
|
from typing import Optional, Sequence
|
|
|
|
from tests.elf import ET, PT, SHT
|
|
|
|
|
|
class ElfSection:
|
|
def __init__(
|
|
self,
|
|
data: bytes,
|
|
name: Optional[str] = None,
|
|
sh_type: Optional[SHT] = None,
|
|
p_type: Optional[PT] = None,
|
|
vaddr: int = 0,
|
|
paddr: int = 0,
|
|
memsz: Optional[int] = None,
|
|
p_align: int = 0,
|
|
):
|
|
self.data = data
|
|
self.name = name
|
|
self.sh_type = sh_type
|
|
self.p_type = p_type
|
|
self.vaddr = vaddr
|
|
self.paddr = paddr
|
|
self.memsz = memsz
|
|
self.p_align = p_align
|
|
|
|
assert (self.name is not None) or (self.p_type is not None)
|
|
assert (self.name is None) == (self.sh_type is None)
|
|
if self.p_type is None:
|
|
assert self.memsz is None
|
|
elif self.memsz is None:
|
|
self.memsz = len(self.data)
|
|
|
|
|
|
def create_elf_file(
|
|
type: ET, sections: Sequence[ElfSection], little_endian: bool = True, bits: int = 64
|
|
):
|
|
endian = "<" if little_endian else ">"
|
|
if bits == 64:
|
|
ehdr_struct = struct.Struct(endian + "16BHHIQQQIHHHHHH")
|
|
shdr_struct = struct.Struct(endian + "IIQQQQIIQQ")
|
|
phdr_struct = struct.Struct(endian + "IIQQQQQQ")
|
|
e_machine = 62 if little_endian else 43 # EM_X86_64 or EM_SPARCV9
|
|
else:
|
|
assert bits == 32
|
|
ehdr_struct = struct.Struct(endian + "16BHHIIIIIHHHHHH")
|
|
shdr_struct = struct.Struct(endian + "10I")
|
|
phdr_struct = struct.Struct(endian + "8I")
|
|
e_machine = 3 if little_endian else 8 # EM_386 or EM_MIPS
|
|
|
|
shstrtab = ElfSection(name=".shstrtab", sh_type=SHT.STRTAB, data=bytearray(1),)
|
|
tmp = [shstrtab]
|
|
tmp.extend(sections)
|
|
sections = tmp
|
|
shnum = 1 # One for the SHT_NULL section.
|
|
phnum = 0
|
|
for section in sections:
|
|
if section.name is not None:
|
|
shstrtab.data.extend(section.name.encode())
|
|
shstrtab.data.append(0)
|
|
shnum += 1
|
|
if section.p_type is not None:
|
|
phnum += 1
|
|
|
|
shdr_offset = ehdr_struct.size
|
|
phdr_offset = shdr_offset + shdr_struct.size * shnum
|
|
headers_size = phdr_offset + phdr_struct.size * phnum
|
|
buf = bytearray(headers_size)
|
|
ehdr_struct.pack_into(
|
|
buf,
|
|
0,
|
|
0x7F, # ELFMAG0
|
|
ord("E"), # ELFMAG1
|
|
ord("L"), # ELFMAG2
|
|
ord("F"), # ELFMAG3
|
|
2 if bits == 64 else 1, # EI_CLASS = ELFCLASS64 or ELFCLASS32
|
|
1 if little_endian else 2, # EI_DATA = ELFDATA2LSB or ELFDATA2MSB
|
|
1, # EI_VERSION = EV_CURRENT
|
|
0, # EI_OSABI = ELFOSABI_NONE
|
|
0, # EI_ABIVERSION
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, # EI_PAD
|
|
type, # e_type
|
|
e_machine,
|
|
1, # e_version = EV_CURRENT
|
|
0, # e_entry
|
|
phdr_offset, # e_phoff
|
|
shdr_offset, # e_shoff
|
|
0, # e_flags
|
|
ehdr_struct.size, # e_ehsize
|
|
phdr_struct.size, # e_phentsize
|
|
phnum, # e_phnum
|
|
shdr_struct.size, # e_shentsize,
|
|
shnum, # e_shnum,
|
|
1, # e_shstrndx
|
|
)
|
|
|
|
shdr_offset += shdr_struct.size
|
|
for section in sections:
|
|
if section.p_align:
|
|
padding = section.vaddr % section.p_align - len(buf) % section.p_align
|
|
buf.extend(bytes(padding))
|
|
if section.name is not None:
|
|
shdr_struct.pack_into(
|
|
buf,
|
|
shdr_offset,
|
|
shstrtab.data.index(section.name.encode()), # sh_name
|
|
section.sh_type, # sh_type
|
|
0, # sh_flags
|
|
section.vaddr, # sh_addr
|
|
len(buf), # sh_offset
|
|
len(section.data), # sh_size
|
|
0, # sh_link
|
|
0, # sh_info
|
|
1 if section.p_type is None else bits // 8, # sh_addralign
|
|
0, # sh_entsize
|
|
)
|
|
shdr_offset += shdr_struct.size
|
|
if section.p_type is not None:
|
|
flags = 7 # PF_R | PF_W | PF_X
|
|
if bits == 64:
|
|
phdr_struct.pack_into(
|
|
buf,
|
|
phdr_offset,
|
|
section.p_type, # p_type
|
|
flags, # p_flags
|
|
len(buf), # p_offset
|
|
section.vaddr, # p_vaddr
|
|
section.paddr, # p_paddr
|
|
len(section.data), # p_filesz
|
|
section.memsz, # p_memsz
|
|
section.p_align, # p_align
|
|
)
|
|
else:
|
|
phdr_struct.pack_into(
|
|
buf,
|
|
phdr_offset,
|
|
section.p_type, # p_type
|
|
len(buf), # p_offset
|
|
section.vaddr, # p_vaddr
|
|
section.paddr, # p_paddr
|
|
len(section.data), # p_filesz
|
|
section.memsz, # p_memsz
|
|
flags, # p_flags
|
|
section.p_align, # p_align
|
|
)
|
|
phdr_offset += phdr_struct.size
|
|
buf.extend(section.data)
|
|
|
|
return buf
|