mirror of
https://github.com/zeldaret/mm.git
synced 2024-10-07 10:13:32 +00:00
Update tools (#16)
* Clean up .gitignore * Set exec bit on all python and shell scripts * Delete unused files * Add decomp-permuter repo * Update submodules
This commit is contained in:
parent
189d0d6c30
commit
ec912054da
56
.gitignore
vendored
56
.gitignore
vendored
@ -1,22 +1,42 @@
|
||||
# Cache files
|
||||
__pycache__/
|
||||
.pyc
|
||||
.DS_Store
|
||||
|
||||
# Text editor remnants
|
||||
.vscode/
|
||||
.vs/
|
||||
.idea/
|
||||
CMakeLists.txt
|
||||
cmake-build-debug
|
||||
venv/
|
||||
|
||||
# Project-specific ignores
|
||||
*.z64
|
||||
*.bin
|
||||
*.elf
|
||||
doc/*
|
||||
archive/*
|
||||
build/*
|
||||
baserom/*
|
||||
decomp/*
|
||||
S/*
|
||||
asm/*
|
||||
font_test/*
|
||||
ido/*
|
||||
__pychahe__/*
|
||||
*.pyc
|
||||
test.txt
|
||||
*.xlsx
|
||||
src/test.c
|
||||
*.dump
|
||||
tools/ido5.3_compiler/*
|
||||
tools/ido7.1_compiler/*
|
||||
expected/*
|
||||
archive/
|
||||
build/
|
||||
baserom/
|
||||
decomp/
|
||||
asm/
|
||||
expected/
|
||||
nonmatchings/
|
||||
|
||||
# Tool artifacts
|
||||
tools/ido5.3_compiler/
|
||||
tools/ido7.1_compiler/
|
||||
tools/qemu-mips
|
||||
|
||||
# Assets
|
||||
*.rgba32.png
|
||||
*.rgb5a1.png
|
||||
*.i4.png
|
||||
*.i8.png
|
||||
*.ia4.png
|
||||
*.ia8.png
|
||||
*.ci4.png
|
||||
*.ci8.png
|
||||
|
||||
# Per-user configuration
|
||||
.python-version
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -7,3 +7,6 @@
|
||||
[submodule "tools/ZAP2"]
|
||||
path = tools/ZAP2
|
||||
url = https://github.com/NEstelami/ZAP2.git
|
||||
[submodule "tools/decomp-permuter"]
|
||||
path = tools/decomp-permuter
|
||||
url = https://github.com/simonlindholm/decomp-permuter
|
||||
|
10
asmdiff.sh
10
asmdiff.sh
@ -1,10 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
OBJDUMP="${MIPS_BINUTILS_PREFIX}objdump -D -z -mmips -EB -j .text -j .data -j .rodata"
|
||||
|
||||
FORMATTER="sed '/^0/!s/.*://'"
|
||||
|
||||
$OBJDUMP build/src/test.o | sed '1,6d; /^0/!s/.*://' > test.dump
|
||||
$OBJDUMP $1 | sed '1,6d; /^0/!s/.*://' > comp.dump
|
||||
diff -y test.dump comp.dump > diff.dump
|
||||
rm test.dump comp.dump
|
0
diff_settings.py
Normal file → Executable file
0
diff_settings.py
Normal file → Executable file
0
file_setup.sh
Normal file → Executable file
0
file_setup.sh
Normal file → Executable file
3975
textures.csv
3975
textures.csv
File diff suppressed because it is too large
Load Diff
@ -1 +1 @@
|
||||
Subproject commit ba00137cf7ef67477ccae2211bf541013b197367
|
||||
Subproject commit 15fcb21d2c4e2ef2f720d28a0f7dec259ddd06f5
|
@ -1 +1 @@
|
||||
Subproject commit d71fbe15c40e74c8f2226c0af596b80c9e92c97c
|
||||
Subproject commit 9d79eb9f539e5fa58fe63c62862661c5d9ce0d27
|
@ -1 +1 @@
|
||||
Subproject commit cbc5b1af79d236f914509bd037213861d65001b0
|
||||
Subproject commit bc7db5a0e489b73595d5e97004f11d5fdea026e4
|
1
tools/decomp-permuter
Submodule
1
tools/decomp-permuter
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit cbb41c125464c3cbe799d77fe2d661615f934720
|
0
tools/disasm.py
Normal file → Executable file
0
tools/disasm.py
Normal file → Executable file
0
tools/dmadata.py
Normal file → Executable file
0
tools/dmadata.py
Normal file → Executable file
0
tools/extract_rom.py
Normal file → Executable file
0
tools/extract_rom.py
Normal file → Executable file
@ -1,178 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import struct;
|
||||
from tkinter import *;
|
||||
from tkinter.ttk import *
|
||||
from PIL import Image, ImageTk, ImageDraw
|
||||
|
||||
import png;
|
||||
|
||||
#FILE_NAME = 'baserom/jpn_font_static'
|
||||
FILE_NAME = 'decomp/object_boss03'
|
||||
|
||||
data = []
|
||||
image_data = [];
|
||||
|
||||
try:
|
||||
with open(FILE_NAME, 'rb') as f:
|
||||
data = f.read()
|
||||
except IOError:
|
||||
print('failed to read file ' + FILE_NAME)
|
||||
sys.exit(1)
|
||||
|
||||
#size = 0x80
|
||||
height = 32
|
||||
width = 32
|
||||
pixel_width = 2
|
||||
size = height*width*pixel_width
|
||||
scale = 4
|
||||
|
||||
window = Tk()
|
||||
|
||||
window.title("MM Texture viewer")
|
||||
window.geometry('500x500')
|
||||
|
||||
def load_file():
|
||||
print('load')
|
||||
update_image()
|
||||
|
||||
def read_i4_image(data, image_data):
|
||||
for i in range(0, len(data)):
|
||||
byte = data[i]
|
||||
color1 = ((byte >> 4) & 0xF) * 17
|
||||
color2 = (byte & 0xF) * 17
|
||||
image_data.append(color1)
|
||||
image_data.append(color1)
|
||||
image_data.append(color1)
|
||||
image_data.append(255)
|
||||
image_data.append(color2)
|
||||
image_data.append(color2)
|
||||
image_data.append(color2)
|
||||
image_data.append(255)
|
||||
|
||||
def read_i8_image(data, image_data):
|
||||
for i in range(0, len(data)):
|
||||
byte = data[i]
|
||||
image_data.append(byte)
|
||||
image_data.append(byte)
|
||||
image_data.append(byte)
|
||||
image_data.append(255)
|
||||
|
||||
def read_ia4_image(data, image_data):
|
||||
None
|
||||
|
||||
def read_ia8_image(data, image_data):
|
||||
None
|
||||
|
||||
def read_ia16_image(data, image_data):
|
||||
None
|
||||
|
||||
def read_rbg5a1_image(data, image_data):
|
||||
for i in range(0, len(data) // 2):
|
||||
byte1 = data[i*2]
|
||||
byte2 = data[i*2 + 1]
|
||||
red = (byte1 >> 3)*8
|
||||
green = (((byte1&0x7)<<2) | ((byte2>>6)&0x3))*8
|
||||
blue = ((byte2 >> 1) & 0x1F)*8
|
||||
alpha = (byte2&0x1)*0xFF
|
||||
image_data.append(red)
|
||||
image_data.append(green)
|
||||
image_data.append(blue)
|
||||
image_data.append(alpha)
|
||||
|
||||
def read_rbga32_image(data, image_data):
|
||||
for i in range(0, len(data)):
|
||||
byte = data[i]
|
||||
image_data.append(byte)
|
||||
|
||||
def read_ci4_image(data, image_data):
|
||||
None
|
||||
|
||||
def read_ci8_image(data, image_data):
|
||||
None
|
||||
|
||||
def update_image(*args):
|
||||
global image_label
|
||||
global image_data
|
||||
global data
|
||||
|
||||
image_data = []
|
||||
|
||||
texture_type = texture_type_combo.get()
|
||||
if texture_type == 'i4':
|
||||
read_i4_image(data, image_data)
|
||||
elif texture_type == 'i8':
|
||||
read_i8_image(data, image_data)
|
||||
elif texture_type == 'ia4':
|
||||
read_ia4_image(data, image_data)
|
||||
elif texture_type == 'ia8':
|
||||
read_ia8_image(data, image_data)
|
||||
elif texture_type == 'ia16':
|
||||
read_ia16_image(data, image_data)
|
||||
elif texture_type == 'rbg5a1':
|
||||
read_rbg5a1_image(data, image_data)
|
||||
elif texture_type == 'rbga32':
|
||||
read_rbga32_image(data, image_data)
|
||||
elif texture_type == 'ci4':
|
||||
read_ci4_image(data, image_data)
|
||||
elif texture_type == 'ci8':
|
||||
read_ci8_image(data, image_data)
|
||||
else:
|
||||
print('other type')
|
||||
|
||||
offset = int(offset_spinbox.get())
|
||||
|
||||
image = Image.frombytes("RGBA", (width, height), bytes(image_data[offset*4:])).resize((width*scale, height*scale))
|
||||
image_tk = ImageTk.PhotoImage(image=image)
|
||||
image_label.configure(image=image_tk)
|
||||
image_label.image = image_tk # prevent GC?
|
||||
|
||||
|
||||
|
||||
load_button = Button(window, text='Load File', command=load_file)
|
||||
load_button.pack()
|
||||
|
||||
texture_type_combo = Combobox(window)
|
||||
texture_type_combo['values'] = ('i4', 'i8', 'ia4', 'ia8', 'ia16', 'rbg5a1', 'rbga32', 'ci4', 'ci8')
|
||||
texture_type_combo.current(5)
|
||||
texture_type_combo.bind("<<ComboboxSelected>>", update_image)
|
||||
texture_type_combo.pack()
|
||||
|
||||
# TODO textures should be able to only take a few discret values, find them
|
||||
width_default = StringVar(window)
|
||||
width_default.set("32")
|
||||
width_spinbox = Spinbox(window, from_=1, to=48, textvariable=width_default, command=update_image)
|
||||
width_spinbox.pack();
|
||||
|
||||
offset_default = StringVar(window)
|
||||
offset_default.set("0")
|
||||
offset_spinbox = Spinbox(window, from_=0, to=len(data), textvariable=offset_default, command=update_image)
|
||||
offset_spinbox.pack();
|
||||
|
||||
image_label = Label(window)
|
||||
image_label.pack()
|
||||
|
||||
update_image()
|
||||
|
||||
window.mainloop()
|
||||
|
||||
#for i in range(0, len(data) // size):
|
||||
# texture_data = data[(i * size):((i + 1) * size)]
|
||||
#
|
||||
# with open('font_test2/' + str(i) + '.png', 'wb') as f:
|
||||
# w = png.Writer(width, height, alpha=True)#, greyscale=True)#
|
||||
# png_data = [];
|
||||
# for y in range(0, height):
|
||||
# row = []
|
||||
# '''
|
||||
# for x in range(0, 16//2):
|
||||
# byte = texture_data[8*y + x]
|
||||
# row.append(((byte >> 4) & 0xF) * 17)
|
||||
# row.append((byte & 0xF) * 17)
|
||||
# '''
|
||||
# '''
|
||||
# for x in range(0, width*pixel_width):
|
||||
# byte = texture_data[width*pixel_width*y + x]
|
||||
# row.append(byte)
|
||||
# '''
|
||||
# png_data.append(row)
|
||||
# w.write(f, png_data)
|
0
tools/gen_mips_to_c_context.py
Normal file → Executable file
0
tools/gen_mips_to_c_context.py
Normal file → Executable file
0
tools/makerom.py
Normal file → Executable file
0
tools/makerom.py
Normal file → Executable file
0
tools/overlay.py
Normal file → Executable file
0
tools/overlay.py
Normal file → Executable file
@ -1,57 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# TODO generalize
|
||||
|
||||
data = [
|
||||
0xC8580005,
|
||||
0xB874FE0C,
|
||||
0x801F0002,
|
||||
0x30540FA0
|
||||
]
|
||||
|
||||
last_continue = True
|
||||
for entry in data:
|
||||
if not last_continue:
|
||||
print('Error: entries after entry without continue bit')
|
||||
|
||||
value = entry & 0xFFFF
|
||||
offset = (entry >> 16) & 0x7FF
|
||||
type = (entry >> 27) & 0xF
|
||||
_continue = (entry >> 31) & 0x1
|
||||
|
||||
# convert to signed short
|
||||
if value >= 0x8000:
|
||||
value -= 0x10000
|
||||
|
||||
# TODO which ones are signed?
|
||||
print('0x{:X}: '.format(offset), end='')
|
||||
if type == 0:
|
||||
print('char {}'.format(value))
|
||||
elif type == 1:
|
||||
print('char {}'.format(value))
|
||||
elif type == 2:
|
||||
print('short {}'.format(value))
|
||||
elif type == 3:
|
||||
print('short {}'.format(value))
|
||||
elif type == 4:
|
||||
print('int {}'.format(value))
|
||||
elif type == 5:
|
||||
print('int {}'.format(value))
|
||||
elif type == 6:
|
||||
print('float {:f}'.format(value))
|
||||
elif type == 7:
|
||||
print('float {:f}'.format(value / 1000))
|
||||
elif type == 8:
|
||||
print('Vector3f ({0:f}, {0:f}, {0:f})'.format(value))
|
||||
elif type == 9:
|
||||
value /= 1000
|
||||
print('Vector3f ({0:f}, {0:f}, {0:f})'.format(value))
|
||||
elif type == 10:
|
||||
print('Vector3f ({0}, {0}, {0})'.format(value))
|
||||
else:
|
||||
print('Error: invalid type ' + str(value))
|
||||
|
||||
if not _continue:
|
||||
print('END')
|
||||
|
||||
last_continue = _continue
|
||||
|
1391
tools/parse_dl.py
1391
tools/parse_dl.py
File diff suppressed because it is too large
Load Diff
2
tools/preprocess.py
Normal file → Executable file
2
tools/preprocess.py
Normal file → Executable file
@ -6,7 +6,7 @@ import subprocess
|
||||
import tempfile
|
||||
|
||||
dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||
asm_processor = ['python3', os.path.join(dir_path, "asm-processor/asm-processor.py")]
|
||||
asm_processor = ['python3', os.path.join(dir_path, "asm-processor/asm_processor.py")]
|
||||
prelude = os.path.join(dir_path, "prelude.inc")
|
||||
|
||||
all_args = sys.argv[1:]
|
||||
|
@ -1,488 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
'''
|
||||
Resources:
|
||||
http://www.cs.unibo.it/~solmi/teaching/arch_2002-2003/AssemblyLanguageProgDoc.pdf
|
||||
https://github.com/pathscale/binutils/blob/5c2c133020e41fc4aadd80a99156d2cea4754b96/include/coff/sym.h
|
||||
https://github.com/pathscale/binutils/blob/5c2c133020e41fc4aadd80a99156d2cea4754b96/include/coff/symconst.h
|
||||
https://github.com/pathscale/binutils/blob/5c2c133020e41fc4aadd80a99156d2cea4754b96/gas/ecoff.c
|
||||
https://github.com/pathscale/binutils/blob/5c2c133020e41fc4aadd80a99156d2cea4754b96/bfd/ecoff.c
|
||||
https://github.com/pathscale/absoft/blob/master/svn/trunk/ekopath-gcc/ekopath-gcc-4.2.0/gcc/mips-tdump.c
|
||||
'''
|
||||
|
||||
import os
|
||||
import struct
|
||||
import collections
|
||||
import sys
|
||||
|
||||
OFFSET = 0 # TODO why are the offsets in the symbolic header off by some amount?
|
||||
|
||||
indent_level = 0
|
||||
is_comment = False
|
||||
|
||||
symbol_type_list = [
|
||||
'stNil', 'stGlobal', 'stStatic', 'stParam', 'stLocal', 'stLabel', 'stProc', 'stBlock',
|
||||
'stEnd', 'stMember', 'stTypedef', 'stFile', 'INVALID', 'INVALID', 'stStaticProc', 'stConstant',
|
||||
'stStaParam', 'INVALID', 'INVALID', 'INVALID', 'INVALID', 'INVALID', 'INVALID', 'INVALID',
|
||||
'INVALID', 'INVALID', 'stStruct', 'stUnion', 'stEnum', 'INVALID', 'INVALID', 'INVALID',
|
||||
'INVALID', 'INVALID', 'stIndirect']
|
||||
storage_class_list = ['scNil', 'scText', 'scData', 'scBss', 'scRegister', 'scAbs', 'scUndefined', 'reserved',
|
||||
'scBits', 'scDbx', 'scRegImage', 'scInfo', 'scUserStruct', 'scSData', 'scSBss', 'scRData',
|
||||
'scVar', 'scCommon', 'scSCommon', 'scVarRegister', 'scVariant', 'scUndefined', 'scInit']
|
||||
basic_type_c_list = ['nil', 'addr', 'signed char', 'unsigned char', 'short', 'unsigned short', 'int', 'unsigned int',
|
||||
'long', 'unsigned long', 'float', 'double', 'struct', 'union', 'enum', 'typedef',
|
||||
'range', 'set', 'complex', 'double complex', 'indirect', 'fixed decimal', 'float decimal', 'string',
|
||||
'bit', 'picture', 'void', 'long long', 'unsigned long long', 'INVALID', 'long', 'unsigned long',
|
||||
'long long', 'unsigned long long', 'addr', 'int64', 'unsigned int64']
|
||||
|
||||
def increase_indent():
|
||||
global indent_level
|
||||
indent_level += 1
|
||||
|
||||
def decrease_indent():
|
||||
global indent_level
|
||||
indent_level -= 1
|
||||
|
||||
def set_is_comment(set_to):
|
||||
global is_comment
|
||||
old = is_comment
|
||||
is_comment = set_to
|
||||
return old
|
||||
|
||||
def get_indent():
|
||||
global indent_level
|
||||
global is_comment
|
||||
ret = '//' if is_comment else ''
|
||||
for i in range(indent_level):
|
||||
ret += ' '
|
||||
return ret
|
||||
|
||||
def read_uint32_be(file_data, offset):
|
||||
return struct.unpack('>I', file_data[offset:offset+4])[0]
|
||||
|
||||
def read_uint16_be(file_data, offset):
|
||||
return struct.unpack('>H', file_data[offset:offset+2])[0]
|
||||
|
||||
def read_uint8_be(file_data, offset):
|
||||
return struct.unpack('>B', file_data[offset:offset+1])[0]
|
||||
|
||||
def read_elf_header(file_data, offset):
|
||||
Header = collections.namedtuple('ElfHeader',
|
||||
'''e_magic e_class e_data e_version e_osabi e_abiversion e_pad
|
||||
e_type e_machine e_version2 e_entry e_phoff e_shoff e_flags
|
||||
e_ehsize e_phentsize e_phnum e_shentsize e_shnum e_shstrndx''')
|
||||
return Header._make(struct.unpack('>I5B7s2H5I6H', file_data[offset:offset+52]))
|
||||
|
||||
def read_elf_section_header(file_data, offset):
|
||||
Header = collections.namedtuple('SectionHeader',
|
||||
'''sh_name sh_type sh_flags sh_addr sh_offset sh_size sh_link
|
||||
sh_info sh_addralign sh_entsize''')
|
||||
return Header._make(struct.unpack('>10I', file_data[offset:offset+40]))
|
||||
|
||||
def read_symbolic_header(file_data, offset):
|
||||
Header = collections.namedtuple('SymbolicHeader',
|
||||
'''magic vstamp ilineMax cbLine cbLineOffset idnMax cbDnOffset
|
||||
ipdMax cbPdOffset isymMax cbSymOffset ioptMax cbOptOffset
|
||||
iauxMax cbAuxOffset issMax cbSsOffset issExtMax cbSsExtOffset
|
||||
ifdMax cbFdOffset crfd cbRfdOffset iextMax cbExtOffset''')
|
||||
return Header._make(struct.unpack('>2H23I', file_data[offset:offset+96]))
|
||||
|
||||
# TODO find a better solution for the bitfield
|
||||
def read_file_descriptor(file_data, offset):
|
||||
if 'init' not in read_file_descriptor.__dict__:
|
||||
read_file_descriptor.cache = {}
|
||||
read_file_descriptor.header = collections.namedtuple('FileDescriptor',
|
||||
'''adr rss issBase cbSs isymBase csym ilineBase cline ioptBase
|
||||
copt ipdFirst cpd iauxBase caux rfdBase crfd XXX_bitfield
|
||||
cbLineOffset cbLine''')
|
||||
read_file_descriptor.init = True
|
||||
if offset in read_file_descriptor.cache:
|
||||
return read_file_descriptor.cache[offset]
|
||||
read_file_descriptor.cache[offset] = read_file_descriptor.header._make(
|
||||
struct.unpack('>I2iI6iHh4iI2I', file_data[offset:offset+72]))
|
||||
return read_file_descriptor.cache[offset]
|
||||
|
||||
def read_procedure_descriptor(file_data, offset):
|
||||
Header = collections.namedtuple('ProcedureDescriptor',
|
||||
'''adr isym iline regmask regoffset iopt fregmask fregoffset
|
||||
frameoffset framereg pcreg lnLow lnHigh cbLineOffset''')
|
||||
return Header._make(struct.unpack('>I8i2h2iI', file_data[offset:offset+52]))
|
||||
|
||||
def read_symbol(file_data, offset):
|
||||
if 'init' not in read_symbol.__dict__:
|
||||
read_symbol.cache = {}
|
||||
read_symbol.header = collections.namedtuple('Symbol', '''iss value st sc index''')
|
||||
read_symbol.init = True
|
||||
if offset in read_symbol.cache:
|
||||
return read_symbol.cache[offset]
|
||||
(word0, word1, word2) = struct.unpack('>iII', file_data[offset:offset+12])
|
||||
read_symbol.cache[offset] = read_symbol.header._make((
|
||||
word0, word1, (word2 >> 26) & 0x3F, (word2 >> 21) & 0x1F, word2 & 0xFFFFF))
|
||||
return read_symbol.cache[offset]
|
||||
|
||||
def read_auxiliary_symbol(file_data, offset):
|
||||
if 'init' not in read_auxiliary_symbol.__dict__:
|
||||
read_auxiliary_symbol.cache = {}
|
||||
read_auxiliary_symbol.header = collections.namedtuple('AuxSymbol',
|
||||
'''ti rndx dnLow dnHigh isym iss width count''')
|
||||
read_auxiliary_symbol.type_info = collections.namedtuple('TypeInfo',
|
||||
'''fBitfield continued bt tq4 tq5 tq0 tq1 tq2 tq3''')
|
||||
read_auxiliary_symbol.rel_sym = collections.namedtuple('RelativeSymbol', '''rfd index''')
|
||||
read_auxiliary_symbol.init = True
|
||||
if offset in read_auxiliary_symbol.cache:
|
||||
return read_auxiliary_symbol.cache[offset]
|
||||
word0 = struct.unpack('>I', file_data[offset:offset+4])[0]
|
||||
read_auxiliary_symbol.cache[offset] = read_auxiliary_symbol.header._make((
|
||||
read_auxiliary_symbol.type_info._make(((word0 >> 31) & 1, (word0 >> 30) & 1, (word0 >> 24) & 0x3F, (word0 >> 20) & 0xF, (word0 >> 16) & 0xF, (word0 >> 12) & 0xF, (word0 >> 8) & 0xF, (word0 >> 4) & 0xF, word0 & 0xF)),
|
||||
read_auxiliary_symbol.rel_sym._make(((word0 >> 20) & 0xFFF, word0 & 0xFFFFF)),
|
||||
word0, word0, word0, word0, word0, word0))
|
||||
return read_auxiliary_symbol.cache[offset]
|
||||
|
||||
def read_string(file_data, offset):
|
||||
current_offset = 0
|
||||
current_string = b''
|
||||
while True:
|
||||
char = struct.unpack('c', file_data[offset+current_offset:offset+current_offset+1])[0]
|
||||
if char == b'\0':
|
||||
return current_string.decode('ascii')
|
||||
else:
|
||||
current_string += char
|
||||
current_offset += 1
|
||||
|
||||
def get_symbol_name_from_aux(file_data, fd, symbolic_header, aux_num, search_for_typedef):
|
||||
aux = read_auxiliary_symbol(file_data, symbolic_header.cbAuxOffset - OFFSET + (fd.iauxBase + aux_num)*4)
|
||||
fd_num = aux.rndx.rfd
|
||||
next_aux = aux_num+1
|
||||
if fd_num == 4095:
|
||||
aux2 = read_auxiliary_symbol(file_data, symbolic_header.cbAuxOffset - OFFSET + (fd.iauxBase + next_aux)*4)
|
||||
fd_num = aux2.isym
|
||||
next_aux = next_aux+1;
|
||||
fd2 = read_file_descriptor(file_data, symbolic_header.cbFdOffset - OFFSET + fd_num*72)
|
||||
sym = read_symbol(file_data, symbolic_header.cbSymOffset - OFFSET + (fd2.isymBase + aux.rndx.index)*12)
|
||||
ret = ''
|
||||
#print('%r' % (aux,));
|
||||
#print('%r' % (aux2,));
|
||||
#print('%r' % (sym,));
|
||||
if sym.st == 26 or sym.st == 27: #stStruct, stunion
|
||||
ret = get_struct_or_union_string(file_data, fd2, symbolic_header, fd2.isymBase + aux.rndx.index, search_for_typedef)
|
||||
elif sym.st == 28: #stEnum:
|
||||
ret = get_enum_string(file_data, fd2, symbolic_header, fd2.isymBase + aux.rndx.index)
|
||||
else:
|
||||
ret = read_string(file_data, symbolic_header.cbSsOffset - OFFSET + fd2.issBase + sym.iss)
|
||||
return (ret, next_aux)
|
||||
|
||||
def get_type_string(file_data, fd, symbolic_header, aux_num, name, search_for_typedef):
|
||||
ret = ''
|
||||
aux = read_auxiliary_symbol(file_data, symbolic_header.cbAuxOffset - OFFSET + (fd.iauxBase + aux_num)*4)
|
||||
#print('');
|
||||
#print('%r' % (aux,));
|
||||
next_aux = aux_num+1
|
||||
has_bitfield = aux.ti.fBitfield == 1
|
||||
bitwidth = 0
|
||||
if has_bitfield:
|
||||
bit_aux = read_auxiliary_symbol(file_data, symbolic_header.cbAuxOffset - OFFSET + (fd.iauxBase + next_aux)*4)
|
||||
bitwidth = bit_aux.isym
|
||||
next_aux = next_aux+1
|
||||
if aux.ti.bt == 12: # btStruct
|
||||
(ret, next_aux) = get_symbol_name_from_aux(file_data, fd, symbolic_header, next_aux, search_for_typedef)
|
||||
elif aux.ti.bt == 13: # btUnion
|
||||
(ret, next_aux) = get_symbol_name_from_aux(file_data, fd, symbolic_header, next_aux, search_for_typedef)
|
||||
elif aux.ti.bt == 15: # btTypedef
|
||||
(ret, next_aux) = get_symbol_name_from_aux(file_data, fd, symbolic_header, next_aux, search_for_typedef)
|
||||
elif aux.ti.bt == 14: # btEnum
|
||||
(ret, next_aux) = get_symbol_name_from_aux(file_data, fd, symbolic_header, next_aux, search_for_typedef)
|
||||
else:
|
||||
ret = basic_type_c_list[aux.ti.bt]
|
||||
|
||||
tq_list = (aux.ti.tq0, aux.ti.tq1, aux.ti.tq2, aux.ti.tq3, aux.ti.tq4, aux.ti.tq5)
|
||||
|
||||
# TODO this is very naive and probably does not work in a large amount of cases
|
||||
last_was_proc = False # if we see a tqProc, assume the next will be a tqPtr
|
||||
for tq in tq_list:
|
||||
if tq == 0: # tqNil
|
||||
break;
|
||||
elif tq == 1: # tqPtr
|
||||
if last_was_proc:
|
||||
last_was_proc = False
|
||||
continue
|
||||
ret += '*'
|
||||
elif tq == 2: # tqProc
|
||||
last_was_proc = True
|
||||
name = '(*%s)(/* ECOFF does not store param types */)' % name
|
||||
elif tq == 3: # tqArray
|
||||
next_aux += 2 # todo what does this skip over? (Apparantly the type of the index, so always int for C)
|
||||
array_low_aux = read_auxiliary_symbol(file_data, symbolic_header.cbAuxOffset - OFFSET + (fd.iauxBase + next_aux)*4)
|
||||
array_high_aux = read_auxiliary_symbol(file_data, symbolic_header.cbAuxOffset - OFFSET + (fd.iauxBase + next_aux+1)*4)
|
||||
stride_aux = read_auxiliary_symbol(file_data, symbolic_header.cbAuxOffset - OFFSET + (fd.iauxBase + next_aux+2)*4)
|
||||
next_aux += 3
|
||||
if array_high_aux.dnHigh == 0xFFFFFFFF:
|
||||
name += '[]'
|
||||
else:
|
||||
name += '[%d]' % (array_high_aux.dnHigh + 1)
|
||||
elif tq == 4: # tqFar
|
||||
print('ERROR tqFar in get_type_name')
|
||||
elif tq == 5: # tqVol
|
||||
ret = 'volatile ' + ret
|
||||
elif tq == 6: # tqConst
|
||||
ret = 'const ' + ret
|
||||
if has_bitfield:
|
||||
name += ' : %d' % bitwidth
|
||||
return ret + ' ' + name
|
||||
|
||||
def get_enum_string(file_data, fd, symbolic_header, enum_sym_num):
|
||||
ret = ''
|
||||
start_sym = read_symbol(file_data, symbolic_header.cbSymOffset - OFFSET + enum_sym_num*12)
|
||||
if start_sym.st != 28:
|
||||
print('ERROR unkown type in get_enum_string start:%d' % start_sym.st)
|
||||
return ret
|
||||
ret += 'enum {\n'
|
||||
increase_indent()
|
||||
sym_num = enum_sym_num + 1
|
||||
while sym_num < fd.isymBase + start_sym.index:
|
||||
sym = read_symbol(file_data, symbolic_header.cbSymOffset - OFFSET + sym_num*12)
|
||||
if sym.st == 8: # stEnd
|
||||
decrease_indent()
|
||||
ret += get_indent()
|
||||
ret += '}'
|
||||
elif sym.st == 9: # stMember
|
||||
name = read_string(file_data, symbolic_header.cbSsOffset - OFFSET + fd.issBase + sym.iss)
|
||||
ret += get_indent()
|
||||
ret += '%s = %d,\n' % (name, sym.value)
|
||||
else:
|
||||
print('ERROR unkown type in get_enum_string:%d' % sym.st)
|
||||
break
|
||||
sym_num += 1
|
||||
return ret
|
||||
|
||||
def get_struct_or_union_string(file_data, fd, symbolic_header, union_sym_num, search_for_typedef):
|
||||
ret = ''
|
||||
start_sym = read_symbol(file_data, symbolic_header.cbSymOffset - OFFSET + union_sym_num*12)
|
||||
if search_for_typedef:
|
||||
typedef_sym = read_symbol(file_data, symbolic_header.cbSymOffset - OFFSET + (fd.isymBase + start_sym.index)*12)
|
||||
if typedef_sym.st == 10: # stTypedef
|
||||
return read_string(file_data, symbolic_header.cbSsOffset - OFFSET + fd.issBase + typedef_sym.iss)
|
||||
else:
|
||||
name = read_string(file_data, symbolic_header.cbSsOffset - OFFSET + fd.issBase + start_sym.iss)
|
||||
if name != '':
|
||||
return name
|
||||
if start_sym.st == 26: # stStruct
|
||||
ret += 'struct {\n'
|
||||
increase_indent()
|
||||
elif start_sym.st == 27: # stUnion
|
||||
ret += 'union {\n'
|
||||
increase_indent()
|
||||
else:
|
||||
print('ERROR unkown type in get_struct_or_union_string start:%d' % start_sym.st)
|
||||
return ret
|
||||
sym_num = union_sym_num + 1
|
||||
while sym_num < fd.isymBase + start_sym.index:
|
||||
sym = read_symbol(file_data, symbolic_header.cbSymOffset - OFFSET + sym_num*12)
|
||||
if sym.st == 8: # stEnd
|
||||
decrease_indent()
|
||||
ret += get_indent()
|
||||
ret += '}'
|
||||
elif sym.st == 9: # stMember
|
||||
name = read_string(file_data, symbolic_header.cbSsOffset - OFFSET + fd.issBase + sym.iss)
|
||||
ret += get_indent()
|
||||
ret += '/* 0x%X */ %s;\n' % (sym.value // 8, get_type_string(file_data, fd, symbolic_header, sym.index, name, True))
|
||||
elif sym.st == 26 or sym.st == 27: #stStruct, stUnion
|
||||
sym_num = fd.isymBase + sym.index
|
||||
continue
|
||||
elif sym.st == 34: # stIndirect
|
||||
# TODO what even is a stIndirect?
|
||||
sym_num += 1
|
||||
else:
|
||||
print('ERROR unkown type in get_struct_or_union_string:%d' % sym.st)
|
||||
break
|
||||
sym_num += 1
|
||||
return ret
|
||||
|
||||
def print_typedef_symbols(file_data, fd, symbolic_header, typedef_sym_num):
|
||||
typedef_sym = read_symbol(file_data, symbolic_header.cbSymOffset - OFFSET + typedef_sym_num*12)
|
||||
if typedef_sym.st != 10: # stTypedef
|
||||
print('ERROR expected stTypedef symbol in print_typedef_symbols, found:%d' % typedef_sym.st)
|
||||
return
|
||||
name = read_string(file_data, symbolic_header.cbSsOffset - OFFSET + fd.issBase + typedef_sym.iss)
|
||||
print('typedef %s;' % get_type_string(file_data, fd, symbolic_header, typedef_sym.index, name, False))
|
||||
|
||||
def print_procedure(file_data, fd, symbolic_header, proc_sym_num):
|
||||
proc_sym = read_symbol(file_data, symbolic_header.cbSymOffset - OFFSET + proc_sym_num*12)
|
||||
proc_name = read_string(file_data, symbolic_header.cbSsOffset - OFFSET + fd.issBase + proc_sym.iss)
|
||||
print('%s(' % get_type_string(file_data, fd, symbolic_header, proc_sym.index+1, proc_name, True), end='')
|
||||
sym_num = proc_sym_num+1
|
||||
param_sym = read_symbol(file_data, symbolic_header.cbSymOffset - OFFSET + sym_num*12)
|
||||
first = True
|
||||
while param_sym.st == 3: # stParam
|
||||
param_name = read_string(file_data, symbolic_header.cbSsOffset - OFFSET + fd.issBase + param_sym.iss)
|
||||
print('%s%s' % ('' if first else ', ',
|
||||
get_type_string(file_data, fd, symbolic_header, param_sym.index, param_name, True)),
|
||||
end='')
|
||||
sym_num += 1
|
||||
param_sym = read_symbol(file_data, symbolic_header.cbSymOffset - OFFSET + sym_num*12)
|
||||
first = False
|
||||
|
||||
print(');')
|
||||
comment_old = set_is_comment(True)
|
||||
while sym_num < fd.isymBase + fd.csym:
|
||||
sym = read_symbol(file_data, symbolic_header.cbSymOffset - OFFSET + sym_num*12)
|
||||
sym_num += 1
|
||||
if sym.st == 7: # stBlock
|
||||
print('%s{' % get_indent())
|
||||
increase_indent()
|
||||
elif sym.st == 8: # stEnd
|
||||
if proc_name == read_string(file_data, symbolic_header.cbSsOffset - OFFSET + fd.issBase + sym.iss):
|
||||
set_is_comment(comment_old)
|
||||
return sym_num
|
||||
decrease_indent()
|
||||
print('%s}' % get_indent())
|
||||
elif sym.st == 4: # stLocal
|
||||
local_name = read_string(file_data, symbolic_header.cbSsOffset - OFFSET + fd.issBase + sym.iss)
|
||||
is_reg = sym.sc == 4 # scRegister
|
||||
print('%s%s%s;' % (get_indent(),
|
||||
'register ' if is_reg else '',
|
||||
get_type_string(file_data, fd, symbolic_header, sym.index, local_name, True)))
|
||||
elif sym.st == 2: # stStatic
|
||||
static_name = read_string(file_data, symbolic_header.cbSsOffset - OFFSET + fd.issBase + sym.iss)
|
||||
print('%sstatic %s;' % (get_indent(),get_type_string(file_data, fd, symbolic_header, sym.index, static_name, True)))
|
||||
elif sym.st == 5: # stLabel
|
||||
static_name = read_string(file_data, symbolic_header.cbSsOffset - OFFSET + fd.issBase + sym.iss)
|
||||
print('%sLabel: %s @ %d;' % (get_indent(), static_name, sym.value))
|
||||
elif sym.st == 6: # stProc
|
||||
# multiple name for function?
|
||||
sym_num = print_procedure(file_data, fd, symbolic_header, sym_num-1)
|
||||
elif sym.st == 26 or sym.st == 27: #stStruct, stUnion
|
||||
sym_num = fd.isymBase + sym.index
|
||||
elif sym.st == 34: # stIndirect
|
||||
# TODO what even is a stIndirect?
|
||||
sym_num += 1
|
||||
else:
|
||||
print('ERROR unkown st in print_procedure: %d' % sym.st)
|
||||
set_is_comment(comment_old)
|
||||
return sym_num
|
||||
|
||||
def print_symbols(file_data, fd, symbolic_header):
|
||||
sym_num = fd.isymBase
|
||||
while sym_num < fd.isymBase + fd.csym:
|
||||
root_sym = read_symbol(file_data, symbolic_header.cbSymOffset - OFFSET + sym_num*12)
|
||||
if root_sym.st == 11: # stFile
|
||||
file_name = read_string(file_data, symbolic_header.cbSsOffset - OFFSET + fd.issBase + root_sym.iss)
|
||||
print('// begin file %s\n' % file_name)
|
||||
sym_num += 1
|
||||
leaf_sym = read_symbol(file_data, symbolic_header.cbSymOffset - OFFSET + sym_num*12)
|
||||
while leaf_sym.st != 8: # stEnd
|
||||
if leaf_sym.st == 26 or leaf_sym.st == 27 or leaf_sym.st == 28: # stStruct, stUnion, stEnum
|
||||
sym_num = fd.isymBase + leaf_sym.index
|
||||
print('')
|
||||
elif leaf_sym.st == 10: # stTypedef
|
||||
print_typedef_symbols(file_data, fd, symbolic_header, sym_num)
|
||||
sym_num += 1
|
||||
print('')
|
||||
elif leaf_sym.st == 6 or leaf_sym.st == 14: # stProc, stStaticProc
|
||||
# TODO how do stProc and stStaticProc differ? stStaticProc isn't exported?
|
||||
sym_num = print_procedure(file_data, fd, symbolic_header, sym_num)
|
||||
print('')
|
||||
elif leaf_sym.st == 2: # stStatic
|
||||
static_name = read_string(file_data, symbolic_header.cbSsOffset - OFFSET + fd.issBase + leaf_sym.iss)
|
||||
if leaf_sym.sc == 2 or leaf_sym.sc == 3 or leaf_sym.sc == 15: # scData, scBss, scRData
|
||||
if leaf_sym.index != 0xFFFFF: # looks like it's an invalid value for .s files
|
||||
print('static %s;\n' % get_type_string(file_data, fd, symbolic_header, leaf_sym.index, static_name, True))
|
||||
else:
|
||||
print('static %s;\n' % static_name)
|
||||
else:
|
||||
print('ERROR unkown sc for stStatic in print_symbols: %d' % leaf_sym.sc)
|
||||
sym_num += 1
|
||||
else:
|
||||
print('ERROR unkown st in leaf_sym in print_symbols: %d' % leaf_sym.st)
|
||||
sym_num += 1
|
||||
leaf_sym = read_symbol(file_data, symbolic_header.cbSymOffset - OFFSET + sym_num*12)
|
||||
sym_num = fd.isymBase + root_sym.index
|
||||
print('// end file %s' % file_name)
|
||||
else:
|
||||
print('ERROR expected st of stFile as only root type in print_symbols:%d' % root_sym.st)
|
||||
return
|
||||
|
||||
def main():
|
||||
global OFFSET
|
||||
if len(sys.argv) < 2:
|
||||
return # TODO print usage
|
||||
|
||||
filename = sys.argv[1]
|
||||
|
||||
try:
|
||||
with open(filename, 'rb') as f:
|
||||
file_data = f.read()
|
||||
except IOError:
|
||||
print('failed to read file ' + filename)
|
||||
return
|
||||
|
||||
elf_header = read_elf_header(file_data, 0)
|
||||
section_headers = []
|
||||
debug_index = 0xFFFFFFFF
|
||||
#print('%r' % (elf_header,))
|
||||
for i in range(elf_header.e_shnum):
|
||||
section_headers.append(read_elf_section_header(file_data, elf_header.e_shoff + i*40))
|
||||
#print('%r' % (section_headers[i],))
|
||||
if section_headers[i].sh_type == 0x70000005:
|
||||
debug_index = i
|
||||
|
||||
if debug_index != 0xFFFFFFFF:
|
||||
symbolic_header = read_symbolic_header(file_data, section_headers[debug_index].sh_offset)
|
||||
file_descriptors = []
|
||||
print('%r' % (symbolic_header,))
|
||||
# Set offset by assuming that there are no optimization symbols so cbOptOffset points to the start of the symbolic header
|
||||
OFFSET = symbolic_header.cbOptOffset - section_headers[debug_index].sh_offset
|
||||
print('Using OFFSET of %d' % OFFSET)
|
||||
#for sym_num in range(symbolic_header.isymMax):
|
||||
#sym = read_symbol(file_data, symbolic_header.cbSymOffset - OFFSET + sym_num*12)
|
||||
#print('%d:%r' % (sym_num, (sym,)));
|
||||
#for aux_num in range(symbolic_header.iauxMax):
|
||||
#aux = read_auxiliary_symbol(file_data, symbolic_header.cbAuxOffset - OFFSET + aux_num*4)
|
||||
#print('%d:%r' % (aux_num, (aux,)));
|
||||
for file_num in range(symbolic_header.ifdMax):
|
||||
fd = read_file_descriptor(file_data, symbolic_header.cbFdOffset - OFFSET + file_num*72)
|
||||
file_descriptors.append(fd)
|
||||
for file_num in range(symbolic_header.ifdMax):
|
||||
fd = read_file_descriptor(file_data, symbolic_header.cbFdOffset - OFFSET + file_num*72)
|
||||
print('%r' % (fd,))
|
||||
print(' name:%s' % read_string(file_data, symbolic_header.cbSsOffset - OFFSET + fd.issBase + fd.rss))
|
||||
|
||||
print(' procedures:')
|
||||
for proc_num in range(fd.ipdFirst, fd.ipdFirst + fd.cpd):
|
||||
pd = read_procedure_descriptor(file_data, symbolic_header.cbPdOffset - OFFSET + proc_num*52)
|
||||
print(' %r' % ((pd,)))
|
||||
|
||||
print(' symbols:')
|
||||
for sym_num in range(fd.isymBase, fd.isymBase + fd.csym):
|
||||
sym = read_symbol(file_data, symbolic_header.cbSymOffset - OFFSET + sym_num*12)
|
||||
print(' %r' % ((sym,)))
|
||||
print(' name:%s' % read_string(file_data, symbolic_header.cbSsOffset - OFFSET + fd.issBase + sym.iss))
|
||||
print(' type:%s(%d)' % (symbol_type_list[sym.st], sym.st))
|
||||
print(' storage class:%s(%d)' % (storage_class_list[sym.sc], sym.sc))
|
||||
if sym.st == 3 or sym.st == 4 or sym.st == 9 or sym.st == 10 or sym.st == 28: # stParam, stLocal, stMember, stTypedef, stEnum
|
||||
aux = read_auxiliary_symbol(file_data, symbolic_header.cbAuxOffset - OFFSET + (fd.iauxBase + sym.index)*4)
|
||||
print(' %r' % ((aux,)))
|
||||
offset = 0
|
||||
if aux.ti.fBitfield == 1:
|
||||
bitfield_aux = read_auxiliary_symbol(file_data, symbolic_header.cbAuxOffset - OFFSET + (fd.iauxBase + sym.index + 1)*4)
|
||||
print(' %r' % ((bitfield_aux,)))
|
||||
offset = 1
|
||||
if aux.ti.bt == 12 or aux.ti.bt == 13 or aux.ti.bt == 14 or aux.ti.bt == 15: # btStruct, btUnion, btEnum, btTypedef
|
||||
aux2 = read_auxiliary_symbol(file_data, symbolic_header.cbAuxOffset - OFFSET + (fd.iauxBase + sym.index + 1 + offset)*4)
|
||||
print(' %r' % ((aux2,)))
|
||||
if aux2.rndx.rfd == 4095:
|
||||
aux3 = read_auxiliary_symbol(file_data, symbolic_header.cbAuxOffset - OFFSET + (fd.iauxBase + sym.index + 2 + offset)*4)
|
||||
print(' %r' % ((aux3,)))
|
||||
sym2 = read_symbol(file_data, symbolic_header.cbSymOffset - OFFSET + (file_descriptors[aux3.isym].isymBase + aux2.rndx.index)*12)
|
||||
print(' %r' % (sym2,))
|
||||
print(' name:%s' % read_string(file_data, symbolic_header.cbSsOffset - OFFSET + file_descriptors[aux3.isym].issBase + sym2.iss))
|
||||
if sym.st == 6: # stProc
|
||||
# TODO what is the first aux symbol for?
|
||||
aux = read_auxiliary_symbol(file_data, symbolic_header.cbAuxOffset - OFFSET + (fd.iauxBase + sym.index)*4)
|
||||
type_aux = read_auxiliary_symbol(file_data, symbolic_header.cbAuxOffset - OFFSET + (fd.iauxBase + sym.index+1)*4)
|
||||
print(' %r' % ((aux,)))
|
||||
print(' %r' % ((type_aux,)))
|
||||
|
||||
print(' pretty print:')
|
||||
print_symbols(file_data, fd, symbolic_header)
|
||||
|
||||
|
||||
main()
|
2
tools/progress.py
Normal file → Executable file
2
tools/progress.py
Normal file → Executable file
@ -98,5 +98,5 @@ if __name__ == "__main__":
|
||||
if (rupees > 0):
|
||||
print('You have {}/{} masks and {}/{} rupee(s).\n'.format(masks, num_masks, rupees, max_rupees));
|
||||
else:
|
||||
print('You have {}/{} masks .\n'.format(masks, num_masks));
|
||||
print('You have {}/{} masks.\n'.format(masks, num_masks));
|
||||
|
||||
|
0
tools/regconvert.py
Normal file → Executable file
0
tools/regconvert.py
Normal file → Executable file
0
tools/rename_sym.sh
Normal file → Executable file
0
tools/rename_sym.sh
Normal file → Executable file
0
tools/set_o32abi_bit.py
Normal file → Executable file
0
tools/set_o32abi_bit.py
Normal file → Executable file
4
tools/split_asm.py
Normal file → Executable file
4
tools/split_asm.py
Normal file → Executable file
@ -42,8 +42,8 @@ if __name__ == '__main__':
|
||||
if args.c_base != None:
|
||||
os.makedirs(os.path.dirname(args.c_base), exist_ok=True)
|
||||
with open(args.c_base, 'w') as f:
|
||||
f.write('#include <ultra64.h>\n#include <global.h>\n\n')
|
||||
f.write('#include <ultra64.h>\n#include <global.h>\n')
|
||||
|
||||
for name in file_names:
|
||||
f.write('GLOBAL_ASM("{}")\n\n'.format(name))
|
||||
f.write('\nGLOBAL_ASM("{}")\n'.format(name))
|
||||
|
||||
|
0
tools/yaz0.py
Normal file → Executable file
0
tools/yaz0.py
Normal file → Executable file
Loading…
Reference in New Issue
Block a user