mirror of https://github.com/zeldaret/tp.git
129 lines
4.0 KiB
Python
129 lines
4.0 KiB
Python
import librel
|
|
|
|
from intervaltree import Interval, IntervalTree
|
|
from dataclasses import dataclass, field
|
|
from typing import Dict, Tuple
|
|
|
|
from .globals import *
|
|
|
|
class AIT(IntervalTree):
|
|
def __reduce__(self):
|
|
super_value = super().__reduce__()
|
|
value = (self.__class__,super_value[1])
|
|
return value
|
|
|
|
def count(self, start, end):
|
|
return len(list(self.overlap(start, end)))
|
|
|
|
def get_one_or_none(self, addr):
|
|
data = list(self.at(addr))
|
|
return data[0].data if len(data) == 1 else None
|
|
|
|
def get_range_one_or_none(self, start, end):
|
|
data = list(self.overlap(start, end))
|
|
return data[0].data if len(data) == 1 else None
|
|
|
|
|
|
import traceback
|
|
@dataclass()
|
|
class GlobalSymbolTable:
|
|
symbols: AIT = field(default_factory=AIT)
|
|
section_addrs: Dict[Tuple[int,int], int] = field(default_factory=dict)
|
|
|
|
def at_relocation(self, relocation, at):
|
|
assert isinstance(relocation, librel.Relocation)
|
|
|
|
section_addr = 0
|
|
if relocation.module != 0:
|
|
key = (relocation.module, relocation.section)
|
|
if not key in self.section_addrs:
|
|
error(f"relocation failed! looking for module={relocation.module}, section={relocation.section}")
|
|
error(relocation)
|
|
fatal_exit()
|
|
section_addr = self.section_addrs[key]
|
|
addr = section_addr + relocation.addend
|
|
else:
|
|
addr = relocation.addend
|
|
|
|
symbol = self.symbols.get_one_or_none(addr)
|
|
if not symbol:
|
|
error(f"relocation failed!")
|
|
error(f"address={addr:08x} not in module={relocation.module}, section={section_addr:08X}")
|
|
fatal_exit()
|
|
|
|
if symbol._module != relocation.module:
|
|
error(f"relocation failed!")
|
|
error(f"symbol found is in the wrong module. got={symbol._module}, expected={relocation.module}")
|
|
fatal_exit()
|
|
|
|
if not symbol.valid_reference(addr):
|
|
error(f"relocation failed!")
|
|
error(f"illegal access to symbol... the address={addr:08X} cannot be used to access symbol of type='{type(symbol).__name__}'")
|
|
fatal_exit()
|
|
|
|
return addr, symbol
|
|
|
|
def at_addr(self, module, addr):
|
|
symbol = self.symbols.get_one_or_none(addr)
|
|
if symbol:
|
|
if module < 0 or symbol._module == module:
|
|
if symbol.valid_reference(addr):
|
|
return symbol
|
|
|
|
return None
|
|
|
|
def always_get(self, addr):
|
|
return self.symbols.get_one_or_none(addr)
|
|
|
|
def at(self, module, addr, at = 0):
|
|
if isinstance(addr, librel.Relocation):
|
|
assert module < 0
|
|
return self.at_relocation(addr, at)
|
|
else:
|
|
return self.at_addr(module, addr)
|
|
|
|
def __getitem__(self, key, at = 0):
|
|
return self.at(key[0], key[1], at)
|
|
|
|
def has_symbol(self, module, addr) -> bool:
|
|
if self.at(module, addr):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def has(self, module, addr) -> bool:
|
|
return self.has_symbol(module, addr)
|
|
|
|
def resolve_set(self, addrs):
|
|
return [y for y in [ self.at(*x) for x in addrs ] if y]
|
|
|
|
def all(self, addrs):
|
|
return set([
|
|
symbol
|
|
for symbol in [
|
|
self.at(-1, addr)
|
|
for addr in addrs
|
|
]
|
|
if symbol ])
|
|
|
|
def add_symbol(self, symbol: "Symbol"):
|
|
if symbol.size > 0:
|
|
self.symbols.addi(symbol.start, symbol.end, symbol)
|
|
|
|
def remove_symbol(self, symbol: "Symbol"):
|
|
if symbol.size > 0:
|
|
self.symbols.remove_overlap(symbol.start, symbol.end)
|
|
|
|
def add_section(self, module: "Module", section: "Section"):
|
|
if len(section.symbols) <= 0:
|
|
return
|
|
|
|
for symbol in section.symbols:
|
|
self.add_symbol(symbol)
|
|
|
|
def add_module_section(self, module: int, section: int, addr: int):
|
|
key = (module, section)
|
|
assert not key in self.section_addrs
|
|
self.section_addrs[key] = addr
|
|
|