demangle data-symbols

This commit is contained in:
Julgodis
2021-04-08 01:47:05 +02:00
parent dca1d2a1c0
commit a23a106399
1756 changed files with 78295 additions and 66184 deletions
+44 -45
View File
@@ -8,29 +8,33 @@ and apply some fixes with makes it easier to decompile.
"""
import importlib
import click
from libdol2asm import settings
import libelf
import libar
from pathlib import Path
import io
import sys
import os
VERSION = "1.0"
import os
import sys
import io
from pathlib import Path
# laod the symbol definition file for main.dol
sys.path.append('defs')
import libar
import libelf
def lcf_generate(output_path):
""" Script for generating .lcf files """
import module0
# load symbols from compiled files
symbols = []
for archive in ARCHIVES:
symbols.extend(load_archive(archive))
# load object files from the 'build/o_files', this way we need no list of
# load object files from the 'build/o_files', this way we need no list of
# object files in the python code.
with open("build/o_files", 'r') as content_file:
o_files = content_file.read().strip().split(" ")
@@ -53,10 +57,12 @@ def lcf_generate(output_path):
for name, align in SECTIONS:
file.write("\t\t%s ALIGN(0x%X):{}\n" % (name, align))
# strip .dead section
file.write("\t\t/DISCARD/ : { *(.dead) }\n")
file.write("\t} > text\n")
file.write("\t_stack_addr = (_f_sbss2 + SIZEOF(.sbss2) + 65536 + 0x7) & ~0x7;\n")
file.write(
"\t_stack_addr = (_f_sbss2 + SIZEOF(.sbss2) + 65536 + 0x7) & ~0x7;\n")
file.write("\t_stack_end = _f_sbss2 + SIZEOF(.sbss2);\n")
file.write("\t_db_stack_addr = (_stack_addr + 0x2000);\n")
file.write("\t_db_stack_end = _stack_addr;\n")
@@ -65,28 +71,28 @@ def lcf_generate(output_path):
file.write("\n")
file.write("\t/* missing symbols */\n")
# improve decompilation workflow by making so that function
# improve decompilation workflow by making so that function
# which, for what ever reason, cannot be named the same as
# the expected name to work. This will happen for all symbols
# with weird characters.
# the expected name to work. This will happen for all symbols
# with weird characters.
base_names = set(module0.SYMBOL_NAMES.keys())
main_names = set([sym.name for sym in symbols])
names = base_names - main_names
for name in names:
symbol = module0.SYMBOLS[module0.SYMBOL_NAMES[name]]
if symbol['type'] == "StringBase": # @stringBase0 is handled below
if symbol['type'] == "StringBase": # @stringBase0 is handled below
continue
if symbol['type'] == "LinkerGenerated": # linker handles these symbols
if symbol['type'] == "LinkerGenerated": # linker handles these symbols
continue
file.write(f"\t\"{symbol['label']}\" = 0x{symbol['addr']:08X};\n")
file.write("\n")
# @stringBase0 is generated by the compiler. The dol2asm is using a trick to
# @stringBase0 is generated by the compiler. The dol2asm is using a trick to
# simulate the stringBase0 by creating another symbol (at the same location)
# that is used instead, as it is impossible to reference the "@stringBase0" (because of the @).
# So all references will be to the new symbol, thus the linker will think
# that the @stringBase0 symbol is never used and strip it.
# that the @stringBase0 symbol is never used and strip it.
file.write("\t/* @stringBase0 */\n")
for x in module0.SYMBOLS:
if x['type'] == "StringBase":
@@ -107,7 +113,7 @@ def lcf_generate(output_path):
continue
require_force_active = False
# if the symbol is not reachable from the __start add it as forceactive
if not x['is_reachable'] or sum(x['r']) == 0:
require_force_active = True
@@ -122,7 +128,7 @@ def lcf_generate(output_path):
continue
if x['is_reachable']:
if x['label'] != x['name']:
if x['label'] != x['name']:
file.write(f"\t\"{x['name']}\"\n")
for symbol in symbols:
@@ -136,15 +142,14 @@ def lcf_generate(output_path):
file.write("}\n")
file.write("\n")
import importlib
from libdol2asm import settings
def rel_lcf_generate(module_index, output_path):
module = importlib.import_module(f"module{module_index}")
base = settings.REL_TEMP_LOCATION[module.LIBRARIES[0].split("/")[-1] + ".rel"]
base = settings.REL_TEMP_LOCATION[module.LIBRARIES[0].split(
"/")[-1] + ".rel"]
# load object files from the 'build/o_files', this way we need no list of
# load object files from the 'build/o_files', this way we need no list of
# object files in the python code.
with open(f"build/M{module_index}_ofiles", 'r') as content_file:
all_files = content_file.read().strip().split(" ")
@@ -173,7 +178,6 @@ def rel_lcf_generate(module_index, output_path):
obj = libelf.load_object_from_file(None, o_file, file)
symbols.extend(get_symbols_from_object_file(obj))
# write rel ldscript file
with output_path.open("w") as file:
file.write("SECTIONS {\n")
@@ -189,33 +193,24 @@ def rel_lcf_generate(module_index, output_path):
file.write("\n")
file.write("\t/* missing symbols */\n")
# improve decompilation workflow by making so that function
# improve decompilation workflow by making so that function
# which, for what ever reason, cannot be named the same as
# the expected name to work. This will happen for all symbols
# with weird characters.
# the expected name to work. This will happen for all symbols
# with weird characters.
base_names = set(module.SYMBOL_NAMES.keys())
main_names = set([sym.name for sym in symbols])
names = base_names - main_names
for name in names:
symbol = module.SYMBOLS[module.SYMBOL_NAMES[name]]
if symbol['type'] == "StringBase": # @stringBase0 is handled below
if symbol['type'] == "StringBase": # @stringBase0 is handled below
continue
if symbol['type'] == "LinkerGenerated": # linker handles these symbols
if symbol['type'] == "LinkerGenerated": # linker handles these symbols
continue
file.write(f"\t\"{symbol['label']}\" = __rel_base + 0x{symbol['addr'] - base:08X}; /* 0x{symbol['addr']:08X} */\n")
file.write(
f"\t\"{symbol['label']}\" = __rel_base + 0x{symbol['addr'] - base:08X}; /* 0x{symbol['addr']:08X} */\n")
file.write("\n")
# @stringBase0 is generated by the compiler. The dol2asm is using a trick to
# simulate the stringBase0 by creating another symbol (at the same location)
# that is used instead, as it is impossible to reference the "@stringBase0" (because of the @).
# So all references will be to the new symbol, thus the linker will think
# that the @stringBase0 symbol is never used and strip it.
#file.write("\t/* @stringBase0 */\n")
#for x in module.SYMBOLS:
# if x['type'] == "StringBase":
# file.write(f"\t\"{x['label']}\" = __rel_base + 0x{x['addr'] - base:08X}; /* 0x{x['addr']:08X} */\n")
file.write("}\n")
file.write("\n")
@@ -232,7 +227,7 @@ def rel_lcf_generate(module_index, output_path):
continue
require_force_active = False
# if the symbol is not reachable from the __start add it as forceactive
if not x['is_reachable'] and not x['static']:
require_force_active = True
@@ -261,6 +256,7 @@ def rel_lcf_generate(module_index, output_path):
file.write("}\n")
file.write("\n")
def get_symbols_from_object_file(obj):
symbols = []
for sym in obj.symbols:
@@ -269,9 +265,10 @@ def get_symbols_from_object_file(obj):
symbols.append(sym)
return symbols
def load_archive(ar_path):
symbols = []
print(ar_path)
archive = libar.read(ar_path)
for path, data in archive.files:
@@ -280,6 +277,7 @@ def load_archive(ar_path):
return symbols
SECTIONS = [
(".init", 0x20),
("extab_", 0x20),
@@ -361,28 +359,29 @@ ARCHIVES = [
]
import click
class PathPath(click.Path):
def convert(self, value, param, ctx):
return Path(super().convert(value, param, ctx))
@click.group()
@click.version_option(VERSION)
def lcf():
pass
@lcf.command(name="dol")
@click.option('--output', '-o', 'output_path', required=False, type=PathPath(file_okay=True, dir_okay=False), default="build/dolzel2/ldscript.lcf")
def dol(output_path):
lcf_generate(output_path)
@lcf.command(name="rel")
@click.option('--output', '-o', 'output_path', required=False, type=PathPath(file_okay=True, dir_okay=False), default="build/dolzel2/ldscript.lcf")
@click.argument('module', metavar="<MODULE>", nargs=1)
def rel(output_path, module):
rel_lcf_generate(module, output_path)
rel_lcf_generate(module, output_path)
if __name__ == "__main__":
lcf()
+74 -40
View File
@@ -39,6 +39,17 @@ class ArbitraryData(Symbol):
return False
return True
@property
def is_class_symbol(self):
# @!game
# don't generate static class variables for 'cNullVec__6Z2Calc', because it will not compile.
# Z2Calc::cNullVec seems to be static data that is initialized in the class definition, thus,
# every translation unit which uses Z2Calc will have a copy of the Z2Calc::cNullVec in the data
# section. Could not find a way to make this compile without easily.
if self.identifier.name == "cNullVec__6Z2Calc":
return False
return self.demangled_name and self.has_class and not self.has_template
@property
def element_size(self):
return 1
@@ -67,18 +78,42 @@ class ArbitraryData(Symbol):
def array_type(self):
if self.zero_length:
return ZeroArrayType.create(self.element_type())
return ZeroArrayType.create(self.element_type())
return PaddingArrayType.create(
self.element_type(),
self.size // self.element_size,
self.padding // self.element_size)
def cpp_reference(self, accessor, addr):
name = self.declaration_name(forward=False, c_export=False,full_qualified_name=True)
if addr == self.addr:
return f"&{self.identifier.label}"
return f"&{name}"
else:
offset = addr - self.addr
return f"(((char*)&{self.identifier.label})+0x{offset:X})"
return f"(((char*)&{name})+0x{offset:X})"
def declaration_name(self, forward: bool,
c_export: bool,
full_qualified_name: bool):
if not self.is_class_symbol or c_export:
return self.identifier.label
if full_qualified_name:
return self.demangled_name.to_str()
else:
return self.demangled_name.last.to_str()
async def export_declaration_header(self, exporter,
builder: AsyncBuilder,
forward: bool,
c_export: bool,
full_qualified_name: bool):
name = self.declaration_name(c_export=c_export,
forward=forward,
full_qualified_name=full_qualified_name)
decl_type = self.array_type()
await builder.write_nonewline(decl_type.decl(name))
async def export_forward_references(self,
exporter,
@@ -86,54 +121,53 @@ class ArbitraryData(Symbol):
c_export: bool = False):
if not c_export:
return
if self.is_static and self.export_static:
if not self.require_forward_reference:
return
if not self.is_class_symbol:
if self.is_static and self.export_static:
if not self.require_forward_reference:
return
await self.export_section_header(builder)
if not (self.is_static and self.export_static):
await self.export_extern(builder)
if not self.is_class_symbol:
if not (self.is_static and self.export_static):
await self.export_extern(builder)
name = self.identifier.label
if self.demangled_name:
name = self.demangled_name.to_str(specialize_templates=False,
without_template=False)
decl_type = self.array_type()
await builder.write_nonewline(decl_type.decl(name))
await self.export_declaration_header(exporter, builder,
forward=True,
c_export=c_export,
full_qualified_name=False)
await builder.write(";")
async def export_declaration_head(self, exporter, builder: AsyncBuilder):
if self.demangled_name:
name = self.demangled_name.to_str(specialize_templates=False,
without_template=False)
else:
name = self.identifier.label
name = self.declaration_name(c_export=False,
forward=False,
full_qualified_name=True)
decl_type = self.array_type()
# for empty symbols that should be exported, we need to double declare it.
# otherwise, the compiler thinks that we're not actual declaring it.
is_extern = not (self.is_static and self.export_as_static)
if not self.data and is_extern:
await self.export_section(builder)
if self.force_section:
await self.export_section_header(builder)
if not self.is_class_symbol:
# for empty symbols that should be exported, we need to double declare it.
# otherwise, the compiler thinks that we're not actual declaring it.
is_extern = not (self.is_static and self.export_as_static)
if not self.data and is_extern:
await self.export_section(builder)
if self.force_section:
await self.export_section_header(builder)
await self.export_extern(builder)
await builder.write_nonewline(decl_type.decl(name))
await builder.write(";")
await self.export_extern(builder)
await builder.write_nonewline(decl_type.decl(name))
await builder.write(";")
await self.export_section(builder)
if self.force_section:
await self.export_section_header(builder)
if not is_extern:
await self.export_static(builder)
elif self.data and is_extern:
await self.export_extern(builder)
if not self.is_class_symbol:
if not is_extern:
await self.export_static(builder)
elif self.data and is_extern:
await self.export_extern(builder)
await builder.write_nonewline(decl_type.decl(name))
@@ -168,11 +202,11 @@ class ArbitraryData(Symbol):
if self._section == ".rodata":
await builder.write(f"COMPILER_STRIP_GATE({self.addr:08X}, {self.cpp_reference(None, self.addr)});")
#await builder.write_nonewline("SECTION_DEAD ")
#await builder.write_nonewline("void* const ")
#await builder.write_nonewline(f"cg_{self.addr:08X} = (void*)(")
#await builder.write_nonewline(self.cpp_reference(None, self.addr))
#await builder.write(f");")
# await builder.write_nonewline("SECTION_DEAD ")
# await builder.write_nonewline("void* const ")
# await builder.write_nonewline(f"cg_{self.addr:08X} = (void*)(")
# await builder.write_nonewline(self.cpp_reference(None, self.addr))
# await builder.write(f");")
if self.requires_force_active:
await builder.write(f"#pragma pop")
+8 -25
View File
@@ -18,15 +18,13 @@ special_func_no_return = set([
class Function(Symbol):
return_type: Type = None
argument_types: List[Type] = field(default_factory=list)
func_name: libdemangle.QualifiedName = None
special_func_name: str = None
func_is_const: bool = False
template_index: int = -1
asm: bool = False
@property
def uses_any_templates(self):
if self.func_name and self.func_name.has_template:
if self.demangled_name and self.demangled_name.has_template:
return True
is_templated = [False]
@@ -44,10 +42,6 @@ class Function(Symbol):
return is_templated[0]
@property
def uses_class_template(self):
return self.func_name and self.func_name.has_template
@property
def is_static(self):
s = self.reference_count.static
@@ -57,7 +51,7 @@ class Function(Symbol):
if not static_by_references:
return False
if not self.func_name:
if not self.demangled_name:
# very arbitrary, but function begining with __ are often special
if self.identifier.name and self.identifier.name.startswith("__"):
return False
@@ -70,13 +64,13 @@ class Function(Symbol):
return self.identifier.label
def function_name(self, c_export: bool, full_qualified_name: bool):
if not self.func_name or c_export:
if not self.demangled_name or c_export:
return self.identifier.label
if self.func_name.require_specialization:
if self.demangled_name.require_specialization:
return self.identifier.label
name = self.func_name
name = self.demangled_name
if self.special_func_name and self.has_class:
# fix up the constructor and destructor if the function is template specialized
special_name = None
@@ -87,16 +81,13 @@ class Function(Symbol):
if special_name:
name = NamedType(
self.func_name.names[:-1] + [ClassName(special_name, [])])
self.demangled_name.names[:-1] + [ClassName(special_name, [])])
if full_qualified_name:
return name.to_str()
else:
return name.last.to_str()
def is_demangled(self):
return self.func_name != None
def valid_reference(self, addr):
return addr % 4 == 0
@@ -115,14 +106,6 @@ class Function(Symbol):
def types(self):
return set()
@property
def has_class(self):
return self.func_name and self.func_name.has_class
@property
def has_template(self):
return self.func_name and self.func_name.has_template
async def export_function_header(self, exporter,
builder: AsyncBuilder,
forward: bool,
@@ -158,7 +141,7 @@ class Function(Symbol):
if self._section == ".init":
await builder.write_nonewline(f"SECTION_INIT ")
elif c_export or (self.func_name and self.func_name.require_specialization and full_qualified_name):
elif c_export or (self.demangled_name and self.demangled_name.require_specialization and full_qualified_name):
await builder.write_nonewline(f"extern \"C\" ")
if self.is_static and not self.has_class:
@@ -173,7 +156,7 @@ class Function(Symbol):
is_special_function = (
self.special_func_name in special_func_no_return)
specialized = (
self.func_name and self.func_name.require_specialization)
self.demangled_name and self.demangled_name.require_specialization)
if c_export:
await builder.write_nonewline(f"{return_type.type()} ")
await builder.write_nonewline(f"{self.function_name(c_export=True,full_qualified_name=full_qualified_name)}")
+14 -1
View File
@@ -62,6 +62,7 @@ class Symbol:
_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)
@@ -100,9 +101,21 @@ class Symbol:
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 False
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):
@@ -309,6 +309,8 @@ class CPPExporter:
for symbol in symbols:
if isinstance(symbol, StringBase):
continue
if symbol in type_list.require_forward_c_reference:
continue
already_fixed_forward_reference.add(symbol)
forward_references = list(decl_references - already_fixed_forward_reference)
+60 -17
View File
@@ -51,6 +51,7 @@ class TypeList:
def __init__(self, context: Context):
self.context = context
self.global_types = dict()
self.require_forward_c_reference = set()
def build(self, symbols: Set[Symbol]):
for symbol in symbols:
@@ -119,18 +120,22 @@ class TypeList:
type.traverse(callback, depth=0)
def convert_symbol_to_types(self, symbol):
if not isinstance(symbol, Function):
return
if isinstance(symbol, Function):
struct = None
if symbol.has_class:
struct = self.get_or_create_type_from_name(
None, -1, self.global_types, symbol.demangled_name.names)
struct.symbols.append(symbol)
struct = None
if symbol.has_class:
struct = self.get_or_create_type_from_name(
None, -1, self.global_types, symbol.func_name.names)
struct.symbols.append(symbol)
self.build_type_structure(struct, symbol.return_type)
for arg in symbol.argument_types:
self.build_type_structure(struct, arg)
self.build_type_structure(struct, symbol.return_type)
for arg in symbol.argument_types:
self.build_type_structure(struct, arg)
elif symbol.demangled_name:
if symbol.is_class_symbol:
self.require_forward_c_reference.add(symbol)
struct = self.get_or_create_type_from_name(
None, -1, self.global_types, symbol.demangled_name.names)
struct.symbols.append(symbol)
def struct_dependencies(self, struct):
deps = set()
@@ -213,7 +218,7 @@ class TypeList:
if not move_function:
await builder.write_nonewline(f"{pad}/* {function.addr:08X} */ ")
if function.template_index >= 0:
await builder.write(f"/* {function.func_name.to_str()} */")
await builder.write(f"/* {function.demangled_name.to_str()} */")
await builder.write_nonewline(f"{pad}")
await function.export_function_header(self, builder,
@@ -222,6 +227,24 @@ class TypeList:
full_qualified_name=False)
await builder.write(f";")
async def export_struct_symbol(self, builder, parent, indent, symbol, specialize):
pad = "\t" * indent
await builder.write_nonewline(f"{pad}")
# non-function symbols will always be static inside structs
if isinstance(parent, Struct):
await builder.write_nonewline(f"static ")
if symbol.template_index >= 0:
await builder.write(f"/* {symbol.demangled_name.to_str()} */")
await builder.write_nonewline(f"{pad}")
await symbol.export_declaration_header(self, builder,
forward=True,
c_export=False,
full_qualified_name=False)
await builder.write(f";")
async def export_struct(self, builder, struct_index, struct, indent):
self.struct_export_set.add(struct)
@@ -243,14 +266,23 @@ class TypeList:
# group functions by name (this is essential grouping templated functions)
names = defaultdict(list)
for symbol in set(struct.symbols):
names[symbol.func_name.last.name].append(symbol)
names[symbol.demangled_name.last.name].append(symbol)
symbols = list(names.items())
symbols.sort(key=lambda x: min([z.addr for z in x[1]]))
fsymbols = []
ssymbols = []
for name, functions in symbols:
if isinstance(functions[0], Function):
fsymbols.append((name, functions))
else:
ssymbols.append((name, functions))
# export functions
last_template = False
for name, functions in symbols:
for name, functions in fsymbols:
if last_template:
await builder.write(f"")
last_template = False
@@ -258,28 +290,39 @@ class TypeList:
if functions[0].template_index >= 0:
# export templated functions
first_function = functions[0]
assert isinstance(first_function, Function)
move_function = self.function_requires_move(first_function)
# export generic function header
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
args = [
f"{alphabet[i]}{struct.depth+1}"
for i in range(len(first_function.func_name.last.templates))
for i in range(len(first_function.demangled_name.last.templates))
]
typename_args = ", ".join([f"typename {x}" for x in args])
await builder.write(f"{pad}\ttemplate <{typename_args}>")
await builder.write_nonewline(f"{pad}\t")
await builder.write_nonewline(f"void {first_function.func_name.last.name}(/* ... */)")
await builder.write_nonewline(f"void {first_function.demangled_name.last.name}(/* ... */)")
await builder.write(f";")
for function in functions:
assert isinstance(function, Function)
await self.export_struct_function(builder, struct, indent + 1, function, True)
last_template = True
else:
# export normal functions
# export functions
for function in functions:
assert isinstance(function, Function)
await self.export_struct_function(builder, struct, indent + 1, function, (struct_index >= 0))
if len(fsymbols) > 0 and len(ssymbols) > 0:
await builder.write("")
for name, syms in ssymbols:
symbol = syms[0]
assert not isinstance(symbol, Function)
await self.export_struct_symbol(builder, struct, indent + 1, symbol, (struct_index >= 0))
await builder.write(f"{pad}}};")
await builder.write("")
+21 -18
View File
@@ -118,8 +118,10 @@ def type_from_demangled_param(param):
return type
dollar_re = re.compile(r'(\w+)\$([0-9]+)')
def nameFix(context, label_collisions, reference_collisions, dollar_names, symbol):
util.escape_name(symbol.identifier)
@@ -132,16 +134,17 @@ def nameFix(context, label_collisions, reference_collisions, dollar_names, symbo
symbol.identifier.override_name = f"{match.group(1)}_{match.group(2)}"
# TODO: Support demangled names for variables
"""
if symbol.identifier.name and (not "@" in symbol.identifier.name) and not isinstance(symbol, Function):
if (symbol.identifier.name and
(not "@" in symbol.identifier.name) and
(not "$" in symbol.identifier.name) and
not isinstance(symbol, Function) and
not symbol.identifier.name.startswith("__vt")):
try:
name = symbol.identifier.name
p = libdemangle.ParseCtx(name)
p.demangle_variable()
if len(p.to_str()) > 0 and p.to_str() != name:
#context.debug(p.to_str())
types = [
type_from_demangled_param(x)
for x in p.demangled
@@ -153,16 +156,16 @@ def nameFix(context, label_collisions, reference_collisions, dollar_names, symbo
valid = False
break
if valid:
symbol.demangled_name = named_type_from_qulified_name(p.full_name)
if valid:
symbol.demangled_name = named_type_from_qulified_name(
p.full_name)
except Exception as e:
context.error(f"demangle error: '{name}'")
context.error(f"\t{e}")
context.error(f"\t{p.func_name}")
context.error(f"\t{p.class_name}")
context.error(f"\t{p.to_str()}")
"""
if (symbol.identifier.name and (not "@" in symbol.identifier.name) and isinstance(symbol, Function)):
name = symbol.identifier.name
try:
@@ -182,7 +185,7 @@ def nameFix(context, label_collisions, reference_collisions, dollar_names, symbo
break
if valid:
symbol.func_name = named_type_from_qulified_name(
symbol.demangled_name = named_type_from_qulified_name(
p.full_name)
symbol.func_is_const = p.is_const
symbol.special_func_name = p.special_func_name
@@ -195,7 +198,7 @@ def nameFix(context, label_collisions, reference_collisions, dollar_names, symbo
else:
symbol.return_type = return_type
#if not symbol.uses_class_template:
# if not symbol.uses_class_template:
# symbol.identifier.is_name_safe = True
else:
context.warning(
@@ -217,7 +220,8 @@ def nameFix(context, label_collisions, reference_collisions, dollar_names, symbo
def nameCollision(context, label_collisions, reference_collisions, parent_name, symbol):
if not symbol.is_static or isinstance(symbol, StringBase):
nice_name = parent_name.replace("/", "_").replace(".", "_").replace("-", "_")
nice_name = parent_name.replace(
"/", "_").replace(".", "_").replace("-", "_")
if isinstance(symbol, StringBase) and symbol._module != 0:
symbol.identifier.override_name = nice_name + "__" + symbol.identifier.label
elif label_collisions[symbol.identifier.label] > 1 or reference_collisions[symbol.identifier.reference] > 1:
@@ -240,7 +244,6 @@ def execute(context, libraries):
continue
dollar_names[match.group(1)] += 1
for sec in tu.sections.values():
for symbol in sec.symbols:
nameFix(context, label_collisions,
@@ -267,10 +270,10 @@ def execute(context, libraries):
for section in tu.sections.values():
for symbol in section.symbols:
if isinstance(symbol, Function):
if symbol.is_demangled():
add_named_type(symbol.func_name, 1)
if symbol.is_demangled:
add_named_type(symbol.demangled_name, 1)
raw_names = tuple(
[x.name for x in symbol.func_name.names])
[x.name for x in symbol.demangled_name.names])
names[raw_names].append(symbol)
if symbol.return_type:
@@ -301,10 +304,10 @@ def execute(context, libraries):
# generate template_index for functions.
for name, functions in names.items():
if functions[0].func_name.last.templates:
if functions[0].demangled_name.last.templates:
#context.debug("Found Templated Function(s):")
functions.sort(key=lambda x: x.addr)
for i, function in enumerate(functions):
function.template_index = i
function.func_name.last.template_index = i
# context.debug(f"\t{function.func_name.to_str(without_template=True)}")
function.demangled_name.last.template_index = i
# context.debug(f"\t{function.demangled_name.to_str(without_template=True)}")
+9 -8
View File
@@ -207,7 +207,7 @@ class Dol2AsmSplitter:
cs.append((0, section.size))
executable_section = ExecutableSection(
section.name, section.addr, section.size, 0, section.data,
section.name, section.addr, section.size, 0, section.data,
code_segments=cs, relocations={}, alignment=4)
executable_sections.append(executable_section)
@@ -245,9 +245,9 @@ class Dol2AsmSplitter:
exe_section = ExecutableSection(
section.name, section.addr, section.length, base_addr,
section.data,
code_segments=cs,
relocations={},
section.data,
code_segments=cs,
relocations={},
alignment=section.alignment)
exe_section.raw_offset = offset
executable_sections.append(exe_section)
@@ -628,7 +628,7 @@ class Dol2AsmSplitter:
self.cpp_group_count = 4
self.asm_group_count = 128
self.step_count = 1
cache = False
cache = True
print(f"dol2asm {VERSION} for '{settings.GAME_NAME}'")
@@ -659,7 +659,6 @@ class Dol2AsmSplitter:
self.search_binary(cache)
start_time = time.time()
cache_path = Path("build/full_cache_xx.dump")
if cache and cache_path.exists():
with cache_path.open('rb') as input:
@@ -694,10 +693,12 @@ class Dol2AsmSplitter:
if not self.select_modules and self.rel_gen:
global_destructor_chain_path = Path(__file__).parent.joinpath(
"global_destructor_chain.template.cpp")
executor_path = Path(__file__).parent.joinpath("executor.template.cpp")
executor_path = Path(__file__).parent.joinpath(
"executor.template.cpp")
if global_destructor_chain_path.exists():
output_path = self.rel_path.joinpath("global_destructor_chain.cpp")
output_path = self.rel_path.joinpath(
"global_destructor_chain.cpp")
util._create_dirs_for_file(output_path)
with global_destructor_chain_path.open('r') as input:
with output_path.open('w') as output: