mirror of
https://github.com/pret/pmd-sky.git
synced 2026-04-15 14:06:06 -05:00
215 lines
10 KiB
Python
215 lines
10 KiB
Python
from pmdsky_debug_reader import *
|
|
from symbol_details import *
|
|
from xmap_reader import *
|
|
import re
|
|
|
|
# Syncs symbols from the decomp to a local clone of pmdsky-debug (https://github.com/UsernameFodder/pmdsky-debug).
|
|
# To use this script, you will need:
|
|
# - A file named pmdsky_debug_location.txt with the file path to your local clone of pmdsky-debug.
|
|
# - Python dependencies in requirements.txt.
|
|
# Make sure there are no uncommitted changes in pmdsky-debug when running this, in case you need to revert.
|
|
|
|
pmdsky_debug_symbols = read_pmdsky_debug_symbols()
|
|
xmap_symbols = read_xmap_symbols()
|
|
|
|
pmdsky_debug_location = get_pmdsky_debug_location()
|
|
default_symbol_name = re.compile(r'^(?:ov\d{2}|sub)?_[\dA-F]{8}$')
|
|
multiple_symbol_suffix = re.compile(r'__[\dA-F]{8}$')
|
|
|
|
for section_name, xmap_section in xmap_symbols.items():
|
|
if section_name in pmdsky_debug_symbols:
|
|
pmdsky_debug_section = pmdsky_debug_symbols[section_name]
|
|
else:
|
|
pmdsky_debug_section = {}
|
|
|
|
for address, symbol in xmap_section.items():
|
|
if default_symbol_name.match(symbol.name):
|
|
continue
|
|
|
|
if symbol.name in MIXED_CASE_SYMBOLS:
|
|
symbol.name = MIXED_CASE_SYMBOLS[symbol.name]
|
|
|
|
if address in pmdsky_debug_section:
|
|
old_symbol = pmdsky_debug_section[address]
|
|
if pmdsky_debug_section[address].name != symbol.name:
|
|
print(f'Replacing {old_symbol.name} with {symbol.name}')
|
|
with open(old_symbol.file_path, 'r') as symbol_file:
|
|
symbol_contents = symbol_file.read()
|
|
symbol_contents = symbol_contents.replace(f'name: {old_symbol.name}\n', f'name: {symbol.name}\n')
|
|
with open(old_symbol.file_path, 'w') as symbol_file:
|
|
symbol_file.write(symbol_contents)
|
|
|
|
header_path = old_symbol.file_path.replace(SYMBOLS_FOLDER, os.path.join('headers', 'functions')).replace('.yml', '.h')
|
|
with open(header_path, 'r') as header_file:
|
|
header_contents = header_file.read()
|
|
header_contents = header_contents.replace(f' {old_symbol.name}(', f' {symbol.name}(')
|
|
with open(header_path, 'w') as header_file:
|
|
header_file.write(header_contents)
|
|
else:
|
|
if section_name == 'main':
|
|
symbol_path = 'arm9.yml'
|
|
elif section_name == 'ITCM':
|
|
symbol_path = os.path.join('arm9', 'itcm.yml')
|
|
else:
|
|
symbol_path = f'overlay{int(section_name):02d}.yml'
|
|
print(f'Adding {symbol.name} to {symbol_path}')
|
|
|
|
symbol_path = os.path.join(pmdsky_debug_location, SYMBOLS_FOLDER, symbol_path)
|
|
with open(symbol_path, 'r') as symbol_file:
|
|
symbol_contents = symbol_file.readlines()
|
|
|
|
if multiple_symbol_suffix.search(symbol.name):
|
|
base_symbol_name = symbol.name[:symbol.name.find('__')]
|
|
found_base_symbol = False
|
|
found_base_symbol_na = False
|
|
write_multisymbol_address = False
|
|
for i, line in enumerate(symbol_contents):
|
|
if not found_base_symbol:
|
|
found_base_symbol = line == f' - name: {base_symbol_name}\n'
|
|
elif found_base_symbol and not found_base_symbol_na:
|
|
found_base_symbol_na = line == ' NA:\n'
|
|
elif found_base_symbol_na:
|
|
if line.startswith(' - '):
|
|
if int(line[-11:-1], 16) > address:
|
|
write_multisymbol_address = True
|
|
else:
|
|
write_multisymbol_address = True
|
|
if write_multisymbol_address:
|
|
symbol_contents[i - 1] += f' - 0x{address:X}\n'
|
|
break
|
|
|
|
if write_multisymbol_address:
|
|
with open(symbol_path, 'w') as symbol_file:
|
|
symbol_file.writelines(symbol_contents)
|
|
continue
|
|
else:
|
|
symbol.name = base_symbol_name
|
|
|
|
symbol_length = 0
|
|
string_length = None
|
|
if symbol.is_data:
|
|
symbols_start = ' data:\n'
|
|
|
|
asm_path = os.path.join('asm', symbol.file_path.replace('.o', '.s'))
|
|
if os.path.exists(asm_path):
|
|
with open(asm_path) as asm_file:
|
|
asm_contents = asm_file.readlines()
|
|
for i, line in enumerate(asm_contents):
|
|
if line.startswith(f'\t.global {symbol.name}'):
|
|
target_line = asm_contents[i + 2]
|
|
string_index = target_line.find('.string "')
|
|
if string_index >= 0:
|
|
target_string = target_line[string_index + len('.string "'):-2].replace('\\n', 'n')
|
|
string_length = len(target_string)
|
|
symbol_length = string_length + 1
|
|
if symbol_length % 4 > 0:
|
|
symbol_length += 4 - symbol_length % 4
|
|
break
|
|
|
|
else:
|
|
symbols_start = ' functions:\n'
|
|
|
|
found_symbols = False
|
|
symbol_before = None
|
|
write_end_list = False
|
|
for i, line in enumerate(symbol_contents):
|
|
if found_symbols:
|
|
write_new_symbol = False
|
|
if line.startswith(' - name:'):
|
|
current_symbol_index = i
|
|
elif line.startswith(' NA:'):
|
|
if line.endswith('NA:\n'):
|
|
address_line = symbol_contents[i + 1]
|
|
else:
|
|
address_line = line
|
|
address_line_string = address_line[-10 : -1]
|
|
if ':' not in address_line_string:
|
|
current_symbol_address = int(address_line_string, 16)
|
|
write_new_symbol = address < current_symbol_address
|
|
elif symbol.is_data and i >= len(symbol_contents) - 2 or not symbol.is_data and line == ' data:\n':
|
|
write_new_symbol = True
|
|
write_end_list = True
|
|
current_symbol_index = i
|
|
|
|
if write_new_symbol:
|
|
if write_end_list:
|
|
symbol_before = None
|
|
else:
|
|
symbol_before = symbol_contents[current_symbol_index][len(' - name: ') : -1]
|
|
if symbol.is_data:
|
|
symbol_contents[current_symbol_index - 1] += f""" - name: {symbol.name}
|
|
address:
|
|
NA: 0x{address:X}
|
|
length:
|
|
NA: 0x{symbol_length:X}
|
|
"""
|
|
else:
|
|
symbol_contents[current_symbol_index - 1] += f""" - name: {symbol.name}
|
|
address:
|
|
NA: 0x{address:X}
|
|
"""
|
|
break
|
|
|
|
elif line == symbols_start:
|
|
found_symbols = True
|
|
current_symbol_index = i
|
|
|
|
with open(symbol_path, 'w') as symbol_file:
|
|
symbol_file.writelines(symbol_contents)
|
|
|
|
|
|
if symbol.is_data:
|
|
header_file_name = 'data'
|
|
else:
|
|
header_file_name = 'functions'
|
|
|
|
header_path = symbol_path.replace(SYMBOLS_FOLDER, os.path.join('headers', header_file_name)).replace('.yml', '.h')
|
|
with open(header_path, 'r') as header_file:
|
|
header_contents = header_file.readlines()
|
|
|
|
target_line = None
|
|
if symbol_before is not None:
|
|
for i, line in enumerate(header_contents):
|
|
if symbol.is_data and re.search(fr' {symbol_before}[[;]', line) or symbol.is_data and f' {symbol_before}(' in line:
|
|
target_line = i
|
|
break
|
|
if target_line is None:
|
|
print(f'Could not find preceding symbol {symbol_before} to {symbol.name} in {header_path}')
|
|
continue
|
|
|
|
if target_line is None:
|
|
if 'arm9' in header_path:
|
|
for i, line in enumerate(header_contents):
|
|
if line.startswith('// If declaring'):
|
|
target_line = i
|
|
break
|
|
else:
|
|
target_line = len(header_contents) - 2
|
|
|
|
symbol_header_path = os.path.join(HEADER_FOLDER, symbol.file_path.replace('.o', '.h'))
|
|
if symbol.is_data:
|
|
if string_length is not None:
|
|
symbol_header = f'extern char {symbol.name}[{string_length}];\n'
|
|
else:
|
|
symbol_header = f'extern undefined {symbol.name};\n'
|
|
elif os.path.exists(symbol_header_path):
|
|
with open(symbol_header_path, 'r') as symbol_header_file:
|
|
symbol_header_contents = symbol_header_file.readlines()
|
|
for line in symbol_header_contents:
|
|
if f' {symbol.name}(' in line:
|
|
symbol_header = line
|
|
break
|
|
symbol_header = symbol_header.replace('u32', 'uint32_t')
|
|
symbol_header = symbol_header.replace('u16', 'uint16_t')
|
|
symbol_header = symbol_header.replace('u8', 'uint8_t')
|
|
symbol_header = symbol_header.replace('s32', 'int32_t')
|
|
symbol_header = symbol_header.replace('s16', 'int16_t')
|
|
symbol_header = symbol_header.replace('s8', 'int8_t')
|
|
else:
|
|
symbol_header = f'void {symbol.name}(void);\n'
|
|
|
|
header_contents[target_line - 1] += symbol_header
|
|
|
|
with open(header_path, 'w') as header_file:
|
|
header_file.writelines(header_contents)
|