Files
PrimeAPI/script/PreplfFile.py
T
2016-10-04 00:16:22 -06:00

190 lines
5.2 KiB
Python

from Stream import *
# Elf Section Type definitions
EST_NULL = 0
EST_PROGBITS = 1
EST_SYMTAB = 2
EST_STRTAB = 3
EST_RELA = 4
class ElfSection:
def __init__(self, stream, parent):
self.parent = parent
self.entryOffset = stream.tell()
# Read section header
self.name = parent.fetch_name(stream, stream.read_long())
self.type = stream.read_long()
self.flags = stream.read_long()
self.address = stream.read_long()
self.offset = stream.read_long()
self.size = stream.read_long()
self.link = stream.read_long()
self.targetSecIdx = stream.read_long()
self.alignment = stream.read_long()
self.entrySize = stream.read_long()
def print_info(self):
print(self.name)
print("Type: 0x%X" % self.type)
print("Flags: 0x%X" % self.flags)
print("Address: 0x%08X" % self.address)
print("Offset: 0x%X" % self.offset)
print("Size: 0x%X" % self.size)
print("Link: %s" % self.parent.get_section_name(self.link))
print("Target Sec: %s" % self.parent.get_section_name(self.targetSecIdx))
print("Alignment: 0x%X" % self.alignment)
print("Entry Size: 0x%X" % self.entrySize)
print('')
def read_section(self, stream):
stream.goto(self.offset)
self.data = stream.read_bytes(self.size)
class ElfSymbolSection(ElfSection):
def read_section(self, stream):
ElfSection.read_section(self, stream)
assert(self.entrySize == 0x10)
stream.goto(self.offset)
numSymbols = int(self.size / self.entrySize)
self.symbols = []
self.symbolDict = {}
for symIdx in range(0, numSymbols):
symbol = {}
nameOffset = stream.read_long()
symbol['name'] = self.parent.fetch_symbol_name(stream, nameOffset, self.link)
symbol['value'] = stream.read_long()
symbol['size'] = stream.read_long()
info = stream.read_byte()
symbol['bind'] = (info >> 4) & 0xF
symbol['type'] = info & 0xF
symbol['visibility'] = stream.read_byte()
symbol['sectionIndex'] = stream.read_short()
self.symbols.append(symbol)
self.symbolDict[symbol['name']] = symbol
def symbol_by_name(self, symName):
if symName in self.symbolDict:
return self.symbolDict[symName]
else:
return None
class ElfRelocSection(ElfSection):
def read_section(self, stream):
ElfSection.read_section(self, stream)
assert(self.entrySize == 0xC)
stream.goto(self.offset)
numRelocs = int(self.size / self.entrySize)
self.relocs = []
for relIdx in range(0, numRelocs):
reloc = {}
reloc['offset'] = stream.read_long()
info = stream.read_long()
reloc['symbolIdx'] = (info >> 8) & 0xFFFFFF
reloc['relocType'] = info & 0xFF
reloc['addend'] = stream.read_long()
self.relocs.append(reloc)
class PreplfFile:
def __init__(self, preplfFilename):
stream = InputStream(preplfFilename)
self.validate_elf_header(stream)
self.read_elf_sections(stream)
def validate_elf_header(self, stream):
stream.goto(0)
magic = stream.read_long()
format = stream.read_byte()
endian = stream.read_byte()
version = stream.read_byte()
osabi = stream.read_byte()
assert(magic == 0x7F454C46)
assert(format == 0x1)
assert(endian == 0x2)
assert(version == 0x1)
assert(osabi == 0x0)
stream.goto(0x10)
type = stream.read_short()
machine = stream.read_short()
version = stream.read_long()
assert(type == 0x1)
assert(machine == 0x14)
assert(version == 0x1)
def read_elf_sections(self, stream):
# Read section header info
stream.goto(0x20)
sectionHeadersOffset = stream.read_long()
stream.goto(0x2E)
sectionHeaderSize = stream.read_short()
numSections = stream.read_short()
nameSectionIdx = stream.read_short()
# Read section header entries
stream.goto(sectionHeadersOffset + (sectionHeaderSize * nameSectionIdx) + 0x10)
self.namesOffset = stream.read_long()
stream.goto(sectionHeadersOffset)
self.sections = []
for secIdx in range(0, numSections):
stream.skip(4)
secType = stream.read_long()
stream.skip(-8)
if secType == EST_SYMTAB: section = ElfSymbolSection(stream, self)
elif secType == EST_RELA: section = ElfRelocSection(stream, self)
else: section = ElfSection(stream, self)
self.sections.append(section)
for section in self.sections:
section.read_section(stream)
def section_by_name(self, secName):
for section in self.sections:
if section.name == secName:
return section
return None
def symbol_by_name(self, symName):
for section in self.sections:
if section.type == EST_SYMTAB:
symbol = section.symbol_by_name(symName)
if symbol is not None: return symbol
return None
def fetch_name(self, stream, nameOffset):
curOffset = stream.tell()
stream.goto(self.namesOffset + nameOffset)
name = stream.read_string()
stream.goto(curOffset)
return name
def fetch_symbol_name(self, stream, nameOffset, symNameSecIdx):
curOffset = stream.tell()
stream.goto(self.sections[symNameSecIdx].offset + nameOffset)
name = stream.read_string()
stream.goto(curOffset)
return name
def fetch_symbol(self, symSecIdx, symIdx):
return self.sections[symSecIdx].symbols[symIdx]
def get_section_name(self, sectionIdx):
if sectionIdx <= 0 or sectionIdx >= len(self.sections):
return "NULL"
out = self.sections[sectionIdx].name
if not out: out = "NULL"
return out