papermario/tools/splat/util/relocs.py

126 lines
3.9 KiB
Python
Raw Normal View History

from dataclasses import dataclass
from typing import Dict
import spimdisasm
import tqdm
from intervaltree import Interval, IntervalTree
from util import log, options, symbols
@dataclass
class Reloc:
rom_address: int
reloc_type: str
symbol_name: str
addend: int = 0
all_relocs: Dict[int, Reloc] = {}
def add_reloc(reloc: Reloc):
all_relocs[reloc.rom_address] = reloc
def initialize():
global all_relocs
all_relocs = {}
for path in options.opts.reloc_addrs_paths:
if not path.exists():
continue
with path.open() as f:
sym_addrs_lines = f.readlines()
for line_num, line in enumerate(
tqdm.tqdm(sym_addrs_lines, desc=f"Loading relocs ({path.stem})")
):
line = line.strip()
# Allow comments
line = line.split("//")[0]
line = line.strip()
if line == "":
continue
rom_addr = None
reloc_type = None
symbol_name = None
addend = None
for info in line.split(" "):
if ":" not in info:
continue
if info.count(":") > 1:
log.parsing_error_preamble(path, line_num, line)
log.write(f"Too many ':'s in '{info}'")
log.error("")
attr_name, attr_val = info.split(":")
if attr_name == "":
log.parsing_error_preamble(path, line_num, line)
log.write(
f"Missing attribute name in '{info}', is there extra whitespace?"
)
log.error("")
if attr_val == "":
log.parsing_error_preamble(path, line_num, line)
log.write(
f"Missing attribute value in '{info}', is there extra whitespace?"
)
log.error("")
# Non-Boolean attributes
try:
if attr_name == "rom":
rom_addr = int(attr_val, 0)
continue
if attr_name == "reloc":
reloc_type = attr_val
continue
if attr_name == "symbol":
symbol_name = attr_val
continue
if attr_name == "addend":
addend = int(attr_val, 0)
continue
except:
log.parsing_error_preamble(path, line_num, line)
log.write(f"value of attribute '{attr_name}' could not be read:")
log.write("")
raise
if rom_addr is None:
log.parsing_error_preamble(path, line_num, line)
log.error(f"Missing required 'rom' attribute for reloc")
if reloc_type is None:
log.parsing_error_preamble(path, line_num, line)
log.error(f"Missing required 'reloc' attribute for reloc")
if symbol_name is None:
log.parsing_error_preamble(path, line_num, line)
log.error(f"Missing required 'symbol' attribute for reloc")
reloc = Reloc(rom_addr, reloc_type, symbol_name)
if addend is not None:
reloc.addend = addend
add_reloc(reloc)
def initialize_spim_context():
for rom_address, reloc in all_relocs.items():
reloc_type = spimdisasm.common.RelocType.fromStr(reloc.reloc_type)
if reloc_type is None:
log.error(
f"Reloc type '{reloc.reloc_type}' is not valid. Rom address: 0x{rom_address:X}"
)
symbols.spim_context.addGlobalReloc(
rom_address, reloc_type, reloc.symbol_name, addend=reloc.addend
)