tp/tools/libdol2asm/data/symbol.py

284 lines
10 KiB
Python

from dataclasses import dataclass, field
from .. import util
from ..builder import AsyncBuilder
from ..types import *
from .identifier import *
@dataclass(frozen=True)
class AddressRange:
start: int
end: int
def __contains__(self, value):
return value >= self.start and value < self.end
@dataclass
class ReferenceCount:
total: int = 0
static: int = 0
extern: int = 0
rel: int = 0
def add_reference(self, referencee, referencer, count):
self.total += count
if referencer:
if referencee._module != referencer._module:
self.rel += count
elif (referencee._library == referencer._library and
referencee._translation_unit == referencer._translation_unit):
self.static += count
else:
self.extern += count
else:
self.extern += count
def make_static(self):
self.total = 1
self.static = 1
self.extern = 0
self.rel = 0
@dataclass(eq=False)
class Symbol:
identifier: Identifier
addr: int
size: int
padding: int = 0
alignment: int = 0
reference_count: ReferenceCount = field(default_factory=ReferenceCount)
implicit_reference_count: ReferenceCount = field(default_factory=ReferenceCount)
sda_hack_reference_count: ReferenceCount = field(
default_factory=ReferenceCount)
require_forward_reference: bool = False
data_type: Type = None
source: str = None
force_section: str = None
_module: str = None
_library: str = None
_translation_unit: str = None
_section: str = None
alignment: int = 0
relative_addr: int = -1
template_index: int = -1
demangled_name: NamedType = None
references: Set[int] = field(default_factory=set)
implicit_references: Set[int] = field(default_factory=set)
is_reachable: bool = False
def __hash__(self):
return hash(self.addr)
def __eq__(self, other):
if not hasattr(self, 'addr'):
return True
return self.addr == other.addr and self.size == other.size
@property
def start(self):
return self.addr
@property
def end(self):
return self.addr + self.size
@property
def offset(self):
return self.addr - self.section.addr
@property
def label(self):
return self.identifier.label
@property
def is_static(self):
return False
@property
def has_body(self):
return True
@property
def has_class(self):
return self.demangled_name and self.demangled_name.has_class
@property
def has_template(self):
return self.demangled_name and self.demangled_name.has_template
@property
def uses_class_template(self):
return self.demangled_name and self.demangled_name.has_template
@property
def is_demangled(self):
return self.demangled_name != None
@property
def requires_force_active(self):
return False
def add_reference(self, referencer, count=1):
self.reference_count.add_reference(self, referencer, count)
def add_implicit_reference(self, referencer, count=1):
self.implicit_reference_count.add_reference(self, referencer, count)
def add_sda_hack(self, referencer, count=1):
self.sda_hack_reference_count.add_reference(self, referencer, count)
def valid_reference(self, addr):
return addr == self.addr
def cpp_reference(self, accessor, addr):
if addr != self.addr:
raise Dol2ZelException(
f"invalid reference addr 0x{addr:08X} for {type(self).__name__}\n{self}")
return f"&{self.identifier.label}"
def cpp_load(self, accessor, addr):
if addr != self.addr:
raise Dol2ZelException(
f"invalid reference addr 0x{addr:08X} for {type(self).__name__}\n{self}")
return f"{self.identifier.label}"
def asm_reference(self, addr):
if addr != self.addr:
return None
return self.identifier.label
def gather_references(self, context, valid_range):
pass
def get_reference_information(self, context, symbol_table):
pass
def types(self):
return set()
def set_mlts(self, module: int, library: str, translation_unit: str, section: str):
self._module = module
self._library = library
self._translation_unit = translation_unit
self._section = section
async def export_section_header(self, builder: AsyncBuilder):
if self._section == ".extab":
await builder.write("#pragma section \"extab_\"")
if self._section == ".extabindex":
await builder.write("#pragma section \"extabindex_\"")
elif self._section == ".ctors":
if self.identifier.label == "__init_cpp_exceptions_reference":
#await builder.write("#pragma section \".ctors$10\"")
#await builder.write_nonewline("__declspec(section \".ctors$10\") ")
await builder.write_nonewline("SECTION_CTORS10 ")
elif self.identifier.label == "_ctors":
#await builder.write("#pragma section \".ctors$15\"")
#await builder.write_nonewline("__declspec(section \".ctors$15\") ")
await builder.write_nonewline("SECTION_CTORS15 ")
elif self._section == ".dtors":
if self.identifier.label == "__destroy_global_chain_reference":
#await builder.write("#pragma section \".dtors$10\"")
#await builder.write_nonewline("__declspec(section \".dtors$10\") ")
await builder.write_nonewline("SECTION_DTORS10 ")
elif self.identifier.label == "__fini_cpp_exceptions_reference":
#await builder.write("#pragma section \".dtors$15\"")
#await builder.write_nonewline("__declspec(section \".dtors$15\") ")
await builder.write_nonewline("SECTION_DTORS15 ")
elif self.identifier.label == "__dtors_null_terminator":
#await builder.write("#pragma section \".dtors$15\"")
#await builder.write_nonewline("__declspec(section \".dtors$15\") ")
await builder.write_nonewline("SECTION_DTORS15 ")
elif self.identifier.label == "_dtors":
await builder.write_nonewline("SECTION_DTORS10 ")
elif self.force_section:
if self.force_section == '.bss':
await builder.write_nonewline("SECTION_BSS ")
else:
assert False
else:
await builder.write_nonewline("extern \"C\" ")
async def export_section(self, builder: AsyncBuilder):
section = ""
if self._section == ".data":
section = "SECTION_DATA "
elif self._section == ".sdata":
section = "SECTION_SDATA "
elif self._section == ".sdata2":
section = "SECTION_SDATA2 "
# elif self._section == ".bss":
# section = "SECTION_BSS "
# elif self._section == ".sbss":
# section = "SECTION_SBSS "
elif self._section == ".sbss2":
section = "SECTION_SBSS2 "
elif self._section == ".init":
section = "SECTION_INIT "
elif self._section == ".rodata":
section = "SECTION_RODATA "
elif self._section == ".extab":
await builder.write_nonewline("SECTION_EXTAB ")
elif self._section == ".extabindex":
await builder.write_nonewline("SECTION_EXTABINDEX ")
elif self._section == ".ctors":
if self.identifier.label == "__init_cpp_exceptions_reference":
#section = "__declspec(section \".ctors$10\") "
section = "SECTION_CTORS10 "
elif self.identifier.label == "_ctors":
#section = "__declspec(section \".ctors$15\") "
section = "SECTION_CTORS15 "
elif self._section == ".dtors":
if self.identifier.label == "__destroy_global_chain_reference":
#section = "__declspec(section \".dtors$10\") "
section = "SECTION_DTORS10 "
elif self.identifier.label == "__fini_cpp_exceptions_reference":
#section = "__declspec(section \".dtors$15\") "
section = "SECTION_DTORS15 "
elif self.identifier.label == "__dtors_null_terminator":
#section = "__declspec(section \".dtors$15\") "
section = "SECTION_DTORS15 "
elif self.identifier.label == "_dtors":
section = "SECTION_DTORS10 "
await builder.write_nonewline(section)
async def export_extern(self, builder: AsyncBuilder):
await builder.write_nonewline(f"extern ")
async def export_static(self, builder: AsyncBuilder):
await builder.write_nonewline(f"static ")
async def export_force_active(self, builder: AsyncBuilder):
await builder.write_nonewline(f"__declspec(forceactive) ")
async def export_readonly(self, builder: AsyncBuilder):
if self._section == ".rodata":
await builder.write_nonewline(f"const ")
elif self._section == ".extab":
await builder.write_nonewline(f"const ")
elif self._section == ".extabindex":
await builder.write_nonewline(f"const ")
elif self._section == ".ctors":
await builder.write_nonewline(f"const ")
elif self._section == ".dtors":
await builder.write_nonewline(f"const ")
async def export_declaration_head(self, builder: AsyncBuilder):
assert False
async def export_declaration_body(self, builder: AsyncBuilder):
assert False
async def export_declaration(self, exporter, builder: AsyncBuilder):
await self.export_declaration_head(exporter, builder)
await self.export_declaration_body(exporter, builder)
async def export_u8_data(self, builder: AsyncBuilder, data: bytearray):
for chunk in util.chunks(data, 16):
line = ", ".join([f"0x{x:02X}" for x in chunk])
await builder.write(f"\t{line},")