diff options
author | Treeki <treeki@gmail.com> | 2011-03-12 23:17:12 +0100 |
---|---|---|
committer | Treeki <treeki@gmail.com> | 2011-03-12 23:17:12 +0100 |
commit | 7d4e4c0b34a613dd3c0220475ae4e448197522c1 (patch) | |
tree | 4f5cee367de3fdef4f9a7c84af59ffe76a2bb1c3 /tools | |
download | kamek-7d4e4c0b34a613dd3c0220475ae4e448197522c1.tar.gz kamek-7d4e4c0b34a613dd3c0220475ae4e448197522c1.zip |
initial commit. now I can start playing with stuff!
Diffstat (limited to 'tools')
-rw-r--r-- | tools/__pycache__/mapfile_tool.cpython-32.pyc | bin | 0 -> 6461 bytes | |||
-rwxr-xr-x | tools/hooks.py | 166 | ||||
-rw-r--r-- | tools/hooks.pyc | bin | 0 -> 5873 bytes | |||
-rw-r--r-- | tools/kamek.py | 548 | ||||
-rw-r--r-- | tools/license.dat | 23 | ||||
-rw-r--r-- | tools/lmgr11.dll | bin | 0 -> 1490944 bytes | |||
-rwxr-xr-x | tools/mapfile_tool.py | 273 | ||||
-rw-r--r-- | tools/mapfile_tool.pyc | bin | 0 -> 5950 bytes | |||
-rw-r--r-- | tools/mwasmeppc.exe | bin | 0 -> 1086812 bytes | |||
-rw-r--r-- | tools/mwcceppc.exe | bin | 0 -> 4324912 bytes | |||
-rw-r--r-- | tools/mwcceppc.idb | bin | 0 -> 40820897 bytes | |||
-rw-r--r-- | tools/mwldeppc.exe | bin | 0 -> 1177600 bytes |
12 files changed, 1010 insertions, 0 deletions
diff --git a/tools/__pycache__/mapfile_tool.cpython-32.pyc b/tools/__pycache__/mapfile_tool.cpython-32.pyc Binary files differnew file mode 100644 index 0000000..1271b22 --- /dev/null +++ b/tools/__pycache__/mapfile_tool.cpython-32.pyc diff --git a/tools/hooks.py b/tools/hooks.py new file mode 100755 index 0000000..13c4e19 --- /dev/null +++ b/tools/hooks.py @@ -0,0 +1,166 @@ +import binascii
+import struct
+
+u32 = struct.Struct('>I')
+
+def make_branch_insn(fromAddr, toAddr, branchType):
+ branchTypes = ['b', 'bl', 'ba', 'bla']
+ if branchType not in branchTypes:
+ raise ValueError, 'invalid branch type: %s' % branchType
+
+ extra = branchTypes.index(branchType)
+
+ distance = toAddr - fromAddr
+ if distance >= 0x2000000 or distance <= -0x2000000:
+ raise ValueError, 'branching too far: %08x to %08x' % (fromAddr, toAddr)
+
+ return (distance & 0x3FFFFFC) | 0x48000000 | extra
+
+
+
+class HookContext(object):
+ """Object which can be used by each hook type to hold data."""
+
+ def __init__(self):
+ self.hooks = []
+
+
+
+class Hook(object):
+ """Generic hook class"""
+
+ has_context = False
+ required_data = []
+
+ def __init__(self, builder, module, data):
+ """Sets up a hook"""
+ self.builder = builder
+ self.module = module
+ self.data = data
+
+ if self.has_context:
+ hookType = type(self)
+ self.context = builder._hook_contexts[hookType]
+ self.context.hooks.append(self)
+
+ # validate the hook's data
+ current_config_name = builder._config_short_name
+
+ for field in self.required_data:
+ field = field.replace('%CONFIG%', current_config_name)
+ if field not in data:
+ raise ValueError, 'hook %s : %s is missing the field %s' % (module.moduleName, data['name'], field)
+
+ def create_patches(self):
+ pass
+
+
+
+class BasicPatchHook(Hook):
+ """Hook that simply patches data to an address"""
+
+ required_data = ['addr_%CONFIG%', 'data']
+
+ def __init__(self, builder, module, data):
+ Hook.__init__(self, builder, module, data)
+
+ def create_patches(self):
+ addr = self.data['addr_%s' % self.builder._config_short_name]
+
+ hex_data = self.data['data']
+
+ whitespace = ' \n\r\t'
+ for char in whitespace:
+ hex_data = hex_data.replace(char, '')
+
+ patch = binascii.unhexlify(hex_data)
+
+ self.builder._add_patch(addr, patch)
+
+
+
+class BranchInsnHook(Hook):
+ """Hook that replaces the instruction at a specific address with a branch"""
+
+ required_data = ['branch_type', 'src_addr_%CONFIG%']
+
+ def __init__(self, builder, module, data):
+ Hook.__init__(self, builder, module, data)
+
+ def create_patches(self):
+ try:
+ target_func = self.data['target_func']
+ except KeyError:
+ target_func = self.data['target_func_%s' % self.builder._config_short_name]
+
+ if isinstance(target_func, str):
+ target_func = self.builder._find_func_by_symbol(target_func)
+ else:
+ # assume it's an address
+ pass
+
+
+ src_addr = self.data['src_addr_%s' % self.builder._config_short_name]
+ branch_insn = make_branch_insn(src_addr, target_func, self.data['branch_type'])
+
+ self.builder._add_patch(src_addr, u32.pack(branch_insn))
+
+
+
+class AddFunctionPointerHook(Hook):
+ """Hook that places a function pointer at an address"""
+
+ required_data = ['src_addr_%CONFIG%']
+
+ def __init__(self, builder, module, data):
+ Hook.__init__(self, builder, module, data)
+
+ def create_patches(self):
+ try:
+ target_func = self.data['target_func']
+ except KeyError:
+ target_func = self.data['target_func_%s' % self.builder._config_short_name]
+
+ if isinstance(target_func, str):
+ target_func = self.builder._find_func_by_symbol(target_func)
+ else:
+ # assume it's an address
+ pass
+
+
+ src_addr = self.data['src_addr_%s' % self.builder._config_short_name]
+
+ self.builder._add_patch(src_addr, u32.pack(target_func))
+
+
+
+class NopInsnHook(Hook):
+ """Hook that NOPs out the instruction(s) at an address"""
+
+ required_data = ['area_%CONFIG%']
+
+ def __init__(self, builder, module, data):
+ Hook.__init__(self, builder, module, data)
+
+ def create_patches(self):
+ area = self.data['area_%s' % self.builder._config_short_name]
+
+ if isinstance(area, list):
+ addr, end = area
+ count = (end + 4 - addr) / 4
+ nop_patch = '\x60\x00\x00\x00' * count
+ else:
+ addr = area
+ nop_patch = '\x60\x00\x00\x00'
+
+ self.builder._add_patch(addr, nop_patch)
+
+
+
+HookTypes = {
+ 'patch': BasicPatchHook,
+ 'branch_insn': BranchInsnHook,
+ 'add_func_pointer': AddFunctionPointerHook,
+ 'nop_insn': NopInsnHook,
+}
+
diff --git a/tools/hooks.pyc b/tools/hooks.pyc Binary files differnew file mode 100644 index 0000000..bd0194d --- /dev/null +++ b/tools/hooks.pyc diff --git a/tools/kamek.py b/tools/kamek.py new file mode 100644 index 0000000..f67f049 --- /dev/null +++ b/tools/kamek.py @@ -0,0 +1,548 @@ +#!/usr/bin/env python + +# Kamek - build tool for custom C++ code in New Super Mario Bros. Wii +# All rights reserved (c) Treeki 2010 +# Some function definitions by megazig + +# Requires PyYAML + +version_str = 'Kamek 0.1 by Treeki' + +import binascii +import os +import os.path +import shutil +import struct +import subprocess +import sys +import tempfile +import yaml + +import hooks + +u32 = struct.Struct('>I') + +verbose = True +use_rels = True +use_mw = False +use_wine = False +mw_path = '' +gcc_path = '' +gcc_type = 'powerpc-eabi' +show_cmd = False +delete_temp = True +override_config_file = None +only_build = None + + +def parse_cmd_options(): + global use_rels, use_mw, use_wine, show_cmd, delete_temp, only_build + global override_config_file, gcc_type, gcc_path, mw_path + + if '--no-rels' in sys.argv: + use_rels = False + + if '--use-mw' in sys.argv: + use_mw = True + + if '--use-wine' in sys.argv: + use_wine = True + + if '--show-cmd' in sys.argv: + show_cmd = True + + if '--keep-temp' in sys.argv: + delete_temp = False + + + + only_build = [] + + for arg in sys.argv: + if arg.startswith('--configs='): + override_config_file = arg[10:] + + if arg.startswith('--build='): + only_build.append(arg[8:]) + + if arg.startswith('--gcc-type='): + gcc_type = arg[11:] + + if arg.startswith('--gcc-path='): + gcc_path = arg[11:] + '/' + + if arg.startswith('--mw-path='): + mw_path = arg[10:] + '/' + + if len(only_build) == 0: + only_build = None + + +def print_debug(s): + if verbose: print '* '+str(s) + + +def read_configs(filename): + with open(filename, 'r') as f: + data = f.read() + + return yaml.safe_load(data) + + +current_unique_id = 0 +def generate_unique_id(): + # this is used for temporary filenames, to ensure that .o files + # do not overwrite each other + global current_unique_id + current_unique_id += 1 + return current_unique_id + + +def align_addr_up(addr, align): + align -= 1 + return (addr + align) & ~align + + +def generate_riiv_mempatch(offset, data): + return '<memory offset="0x%08X" value="%s" />' % (offset, binascii.hexlify(data)) + + +def generate_ocarina_patch(destOffset, data): + out = [] + count = len(data) + + sourceOffset = 0 + destOffset -= 0x80000000 + for i in xrange(count >> 2): + out.append('%08X %s' % (destOffset | 0x4000000, binascii.hexlify(data[sourceOffset:sourceOffset+4]))) + sourceOffset += 4 + destOffset += 4 + + # take care + remainder = count % 4 + if remainder == 3: + out.append('%08X 0000%s' % (destOffset | 0x2000000, binascii.hexlify(data[sourceOffset:sourceOffset+2]))) + out.append('%08X 000000%s' % (destOffset, binascii.hexlify(data[sourceOffset+2]))) + elif remainder == 2: + out.append('%08X 0000%s' % (destOffset | 0x2000000, binascii.hexlify(data[sourceOffset:sourceOffset+2]))) + elif remainder == 1: + out.append('%08X 000000%s' % (destOffset, binascii.hexlify(data[sourceOffset]))) + + return '\n'.join(out) + + +def generate_kamek_patches(patchlist): + kamekpatch = '' + for patch in patchlist: + if len(patch[1]) > 4: + # block patch + kamekpatch += u32.pack(align_addr_up(len(patch[1]), 4) / 4) + kamekpatch += u32.pack(patch[0]) + kamekpatch += patch[1] + # align it + if len(patch[1]) % 4 != 0: + kamekpatch += '\0' * (4 - (len(patch[1]) % 4)) + else: + # single patch + kamekpatch += u32.pack(patch[0]) + kamekpatch += patch[1] + + kamekpatch += u32.pack(0xFFFFFFFF) + return kamekpatch + + + +class KamekModule(object): + _requiredFields = ['source_files'] + + + def __init__(self, filename): + # load the module data + self.modulePath = os.path.normpath(filename) + self.moduleName = os.path.basename(self.modulePath) + self.moduleDir = os.path.dirname(self.modulePath) + + with open(self.modulePath, 'r') as f: + self.rawData = f.read() + + self.data = yaml.safe_load(self.rawData) + if not isinstance(self.data, dict): + raise ValueError, 'the module file %s is an invalid format (it should be a YAML mapping)' % self.moduleName + + # verify it + for field in self._requiredFields: + if field not in self.data: + raise ValueError, 'Missing field in the module file %s: %s' % (self.moduleName, field) + + + +class KamekBuilder(object): + def __init__(self, project, configs): + self.project = project + self.configs = configs + + + def build(self): + print_debug('Starting build') + + self._prepare_dirs() + + for config in self.configs: + if only_build != None and config['short_name'] not in only_build: + continue + + self._set_config(config) + + self._configTempDir = tempfile.mkdtemp() + print_debug('Temp files for this configuration are in: '+self._configTempDir) + + self._builtCodeAddr = 0x80001800 + if 'code_address' in self.project.data: + self._builtCodeAddr = self.project.data['code_address'] + + self._patches = [] + self._rel_patches = [] + self._hooks = [] + + # hook setup + self._hook_contexts = {} + for name, hookType in hooks.HookTypes.iteritems(): + if hookType.has_context: + self._hook_contexts[hookType] = hookType.context_type() + + self._create_hooks() + self._compile_modules() + self._link() + self._read_symbol_map() + + for hook in self._hooks: + hook.create_patches() + + self._create_patch() + + if delete_temp: + shutil.rmtree(self._configTempDir) + + + def _prepare_dirs(self): + self._outDir = self.project.makeRelativePath(self.project.data['output_dir']) + print_debug('Project will be built in: '+self._outDir) + + if not os.path.isdir(self._outDir): + os.makedirs(self._outDir) + print_debug('Created that directory') + + + def _set_config(self, config): + self._config = config + print_debug('---') + print_debug('Building for configuration: '+config['friendly_name']) + + self._config_short_name = config['short_name'] + self._rel_area = (config['rel_area_start'], config['rel_area_end']) + + + def _create_hooks(self): + print_debug('---') + print_debug('Creating hooks') + + for m in self.project.modules: + if 'hooks' in m.data: + for hookData in m.data['hooks']: + assert 'name' in hookData and 'type' in hookData + + print_debug('Hook: %s : %s' % (m.moduleName, hookData['name'])) + + if hookData['type'] in hooks.HookTypes: + hookType = hooks.HookTypes[hookData['type']] + hook = hookType(self, m, hookData) + self._hooks.append(hook) + else: + raise ValueError, 'Unknown hook type: %s' % hookData['type'] + + + def _compile_modules(self): + print_debug('---') + print_debug('Compiling modules') + + if use_mw: + # metrowerks setup + cc_command = ['%smwcceppc.exe' % mw_path, '-I.', '-I-', '-I.', '-nostdinc', '-Cpp_exceptions', 'off', '-Os', '-proc', 'gekko', '-fp', 'hard', '-enum', 'int', '-sdata', '0', '-sdata2', '0', '-g'] + as_command = ['%smwasmeppc.exe' % mw_path, '-I.', '-I-', '-I.', '-nostdinc', '-proc', 'gekko', '-d', '__MWERKS__'] + + for d in self._config['defines']: + cc_command.append('-d') + cc_command.append(d) + as_command.append('-d') + as_command.append(d) + + for i in self._config['include_dirs']: + cc_command.append('-I%s' % i) + #cc_command.append(i) + as_command.append('-I%s' % i) + #as_command.append(i) + + if use_wine: + cc_command.insert(0, 'wine') + as_command.insert(0, 'wine') + + else: + # gcc setup + cc_command = ['%s%s-g++' % (gcc_path, gcc_type), '-nodefaultlibs', '-I.', '-fno-builtin', '-Os', '-fno-exceptions', '-fno-rtti', '-mno-sdata'] + as_command = cc_command + + for d in self._config['defines']: + cc_command.append('-D%s' % d) + + for i in self._config['include_dirs']: + cc_command.append('-I%s' % i) + + + self._moduleFiles = [] + for m in self.project.modules: + for normal_sourcefile in m.data['source_files']: + print_debug('Compiling %s : %s' % (m.moduleName, normal_sourcefile)) + + objfile = os.path.join(self._configTempDir, '%d.o' % generate_unique_id()) + sourcefile = os.path.join(m.moduleDir, normal_sourcefile) + + # todo: better extension detection + if sourcefile.endswith('.s') or sourcefile.endswith('.S'): + command = as_command + else: + command = cc_command + + new_command = command + ['-c', '-o', objfile, sourcefile] + + if 'cc_args' in m.data: + new_command += m.data['cc_args'] + + if show_cmd: + print_debug(new_command) + + errorVal = subprocess.call(new_command) + if errorVal != 0: + print 'BUILD FAILED!' + print 'compiler returned %d - an error occurred while compiling %s' % (errorVal, sourcefile) + sys.exit(1) + + self._moduleFiles.append(objfile) + + print_debug('Compilation complete') + + + def _link(self): + print_debug('---') + print_debug('Linking project') + + self._mapFile = '%s/%s_linkmap.map' % (self._outDir, self._config_short_name) + self._outFile = '%s/%s_out.bin' % (self._outDir, self._config_short_name) + + ld_command = ['%s%s-ld' % (gcc_path, gcc_type), '-L.'] + ld_command.append('-o') + ld_command.append(self._outFile) + ld_command.append('-Ttext') + ld_command.append('0x%08X' % self._builtCodeAddr) + ld_command.append('-T') + ld_command.append(self._config['linker_script']) + ld_command.append('-Map') + ld_command.append(self._mapFile) + ld_command.append('--no-demangle') # for debugging + #ld_command.append('--verbose') + ld_command += self._moduleFiles + + if show_cmd: + print_debug(ld_command) + + errorVal = subprocess.call(ld_command) + if errorVal != 0: + print 'BUILD FAILED!' + print 'ld returned %d' % errorVal + sys.exit(1) + + print_debug('Linked successfully') + + + def _read_symbol_map(self): + print_debug('---') + print_debug('Reading symbol map') + + self._symbols = [] + + file = open(self._mapFile, 'r') + + for line in file: + if '__text_start' in line: + self._textSegStart = int(line.split()[0],0) + break + + # now read the individual symbols + # this is probably a bad method to parse it, but whatever + for line in file: + if '__text_end' in line: + self._textSegEnd = int(line.split()[0],0) + break + + if not line.startswith(' '): continue + + sym = line.split() + sym[0] = int(sym[0],0) + self._symbols.append(sym) + + # we've found __text_end, so now we should be at the output section + currentEndAddress = self._textSegEnd + + for line in file: + if line[0] == '.': + # probably a segment + data = line.split() + if len(data) < 3: continue + + segAddr = int(data[1],0) + segSize = int(data[2],0) + + if segAddr+segSize > currentEndAddress: + currentEndAddress = segAddr+segSize + + self._codeStart = self._textSegStart + self._codeEnd = currentEndAddress + + file.close() + print_debug('Read, %d symbol(s) parsed' % len(self._symbols)) + + + # next up, run it through c++filt + print_debug('Running c++filt') + p = subprocess.Popen(gcc_type + '-c++filt', stdin=subprocess.PIPE, stdout=subprocess.PIPE) + + symbolNameList = [sym[1] for sym in self._symbols] + filtResult = p.communicate('\n'.join(symbolNameList)) + filteredSymbols = filtResult[0].split('\n') + + for sym, filt in zip(self._symbols, filteredSymbols): + sym.append(filt) + + print_debug('Done. All symbols complete.') + print_debug('Generated code is at 0x%08X .. 0x%08X' % (self._codeStart, self._codeEnd - 4)) + + + def _find_func_by_symbol(self, find_symbol): + for sym in self._symbols: + if sym[2] == find_symbol: + return sym[0] + + raise ValueError, 'Cannot find function: %s' % find_symbol + + + def _add_patch(self, offset, data): + if offset >= self._rel_area[0] and offset <= self._rel_area[1] and use_rels: + self._rel_patches.append((offset, data)) + else: + self._patches.append((offset, data)) + + + def _create_patch(self): + print_debug('---') + print_debug('Creating patch') + + # convert the .rel patches to KamekPatcher format + if len(self._rel_patches) > 0: + kamekpatch = generate_kamek_patches(self._rel_patches) + #self._patches.append((0x817F4800, kamekpatch)) + self._patches.append((0x80002F60, kamekpatch)) + + # add the outfile as a patch + file = open(self._outFile, 'rb') + patch = (self._codeStart, file.read()) + file.close() + + self._patches.append(patch) + + # generate a Riivolution patch + riiv = open('%s/%s_riiv.xml' % (self._outDir, self._config['short_name']), 'w') + for patch in self._patches: + riiv.write(generate_riiv_mempatch(*patch) + '\n') + + riiv.close() + + # generate an Ocarina patch + ocarina = open('%s/%s_ocarina.txt' % (self._outDir, self._config['short_name']), 'w') + for patch in self._patches: + ocarina.write(generate_ocarina_patch(*patch) + '\n') + + ocarina.close() + + # generate a KamekPatcher patch + kpatch = open('%s/%s_loader.bin' % (self._outDir, self._config['short_name']), 'wb') + kpatch.write(generate_kamek_patches(self._patches)) + kpatch.close() + + print_debug('Patches generated') + + + +class KamekProject(object): + _requiredFields = ['output_dir', 'modules'] + + + def __init__(self, filename): + # load the project data + self.projectPath = os.path.abspath(filename) + self.projectName = os.path.basename(self.projectPath) + self.projectDir = os.path.dirname(self.projectPath) + + with open(self.projectPath, 'r') as f: + self.rawData = f.read() + + self.data = yaml.safe_load(self.rawData) + if not isinstance(self.data, dict): + raise ValueError, 'the project file is an invalid format (it should be a YAML mapping)' + + # verify it + for field in self._requiredFields: + if field not in self.data: + raise ValueError, 'Missing field in the project file: %s' % field + + # load each module + self.modules = [] + for moduleName in self.data['modules']: + modulePath = self.makeRelativePath(moduleName) + self.modules.append(KamekModule(modulePath)) + + + def makeRelativePath(self, path): + return os.path.normpath(os.path.join(self.projectDir, path)) + + + def build(self): + # compile everything in the project + builder = KamekBuilder(self, self.configs) + builder.build() + + + +def main(): + print version_str + print + + if len(sys.argv) < 2: + print 'No input file specified' + sys.exit() + + parse_cmd_options() + + project = KamekProject(os.path.normpath(sys.argv[1])) + + if override_config_file: + project.configs = read_configs(override_config_file) + else: + project.configs = read_configs('kamek_configs.yaml') + + project.build() + + + +if __name__ == '__main__': + main() + + diff --git a/tools/license.dat b/tools/license.dat new file mode 100644 index 0000000..6d83e13 --- /dev/null +++ b/tools/license.dat @@ -0,0 +1,23 @@ +#######################################################
+# MPC55xx MPC56xx V2.x #
+#######################################################
+INCREMENT Win32_PLUGINS_PPCCPU_MPC55xx metrowks 1.0 permanent \
+ uncounted A14591A89164 VENDOR_STRING="MPC55xx CPU Plugins" \
+ HOSTID=ANY ck=79 TS_OK
+INCREMENT Win32_CWIDE_Unlimited metrowks 5.5 permanent uncounted \
+ 0CBFB52552B1 VENDOR_STRING="CodeWarrior IDE 4.2 or later, \
+ Windows" HOSTID=ANY ck=149 TS_OK
+INCREMENT Win32_Plugins_Comp_PPC metrowks 8.0 permanent uncounted \
+ 195E3E33CA10 VENDOR_STRING="131072 bytes of code, PPC build \
+ tools" HOSTID=ANY ck=77 TS_OK
+INCREMENT WIN32_PLUGINS_PPC metrowks 8.0 permanent uncounted \
+ 120885117B48 VENDOR_STRING="EPPC Plugins" HOSTID=ANY ck=97 \
+ TS_OK
+INCREMENT Win32_Plugins_Link_PPC_128K metrowks 8.0 permanent \
+ uncounted 34FDB3A631AF VENDOR_STRING="PPC linker" HOSTID=ANY \
+ TS_OK
+
+
+#######################################################
+# Installer generated keys bellow, if any #
+#######################################################
diff --git a/tools/lmgr11.dll b/tools/lmgr11.dll Binary files differnew file mode 100644 index 0000000..15038e5 --- /dev/null +++ b/tools/lmgr11.dll diff --git a/tools/mapfile_tool.py b/tools/mapfile_tool.py new file mode 100755 index 0000000..4ebd288 --- /dev/null +++ b/tools/mapfile_tool.py @@ -0,0 +1,273 @@ +# half assed
+
+# d_profile: same place
+# d_bases: same place
+# d_enemies and part of d_bases: offset by 0x20
+# d_en_boss: offset by 0x20
+
+def make_hex_offset(offs):
+ return '0x%08X' % offs
+
+def fix_offs_pal_v2(offs):
+ # do this later
+ return 0xdeadbeef
+
+def fix_offs_ntsc_v1(offs):
+ # .text section
+ if offs >= 0x800B4604 and offs <= 0x800C8E4C:
+ return offs - 0x50
+
+ if offs >= 0x800C8E50 and offs <= 0x800E4D70:
+ return offs - 0xF0
+
+ if offs >= 0x800E4EC0 and offs <= 0x8010F200:
+ return offs - 0x110
+
+ if offs >= 0x8010F430 and offs <= 0x802BB6BC:
+ return offs - 0x140
+
+ if offs >= 0x802BB6C0 and offs <= 0x802BB74C:
+ return offs - 0x150
+
+ if offs >= 0x802BB860 and offs <= 0x802BBBFC:
+ return offs - 0x260
+
+ if offs >= 0x802BBC90 and offs <= 0x802EDCC0:
+ return offs - 0x2F0
+
+ # .ctors, .dtors, .rodata, part of .data section
+ if offs >= 0x802EDCE0 and offs <= 0x80317734:
+ return offs - 0x300
+
+ # .data section
+ if offs >= 0x80317750 and offs <= 0x80322FE0:
+ return offs - 0x318
+
+ if offs >= 0x80323118 and offs <= 0x8032E77C:
+ return offs - 0x348
+
+ if offs >= 0x8032E780 and offs <= 0x8035197C:
+ return offs - 0x340
+
+ # .sdata section, part of .sbss
+ if offs >= 0x80351980 and offs <= 0x80427E87:
+ return offs - 0x300
+
+ # .sbss, .sdata2, .sbss2 sections
+ if offs >= 0x80427E88 and offs <= 0x80429563:
+ return offs - 0x310
+
+ if offs >= 0x80429564 and offs <= 0x80429D7F:
+ return offs - 0x2F8
+
+ if offs >= 0x80429D80 and offs <= 0x807684BF:
+ return offs - 0x2E0
+
+ # part of d_basesNP, d_enemiesNP, d_en_bossNP
+ if offs >= 0x8098A43C:
+ return offs + 0x20
+
+ return offs
+
+
+def fix_offs_ntsc_v2(offs):
+ offs = fix_offs_ntsc_v1(offs)
+
+ if offs >= 0x807685A0 and offs <= 0x807AAA70:
+ return offs + 0x40
+
+ if offs >= 0x807AAA74 and offs <= 0x8099081C:
+ return offs + 0x10
+
+ if offs >= 0x80990820:
+ return offs + 0x20
+
+ return offs
+
+
+def fix_offs_jpn_v1(offs):
+ # .text section
+ if offs >= 0x800B4604 and offs <= 0x800B475C:
+ return offs - 0x50
+
+ if offs >= 0x800B4760 and offs <= 0x800C8DAC:
+ return offs - 0xD0
+
+ if offs >= 0x800C8E50 and offs <= 0x800E4D6C:
+ return offs - 0x170
+
+ if offs >= 0x800E4D94 and offs <= 0x800E4EB4:
+ return offs - 0x194
+
+ if offs >= 0x800E4EB8 and offs <= 0x8010F1D0:
+ return offs - 0x190
+
+ if offs >= 0x8010F430 and offs <= 0x802BB6BC:
+ return offs - 0x330
+
+ if offs >= 0x802BB6D0 and offs <= 0x802BB74C:
+ return offs - 0x340
+
+ if offs >= 0x802BB860 and offs <= 0x802BBBFC:
+ return offs - 0x450
+
+ if offs >= 0x802BBC90 and offs <= 0x802EDCC0:
+ return offs - 0x4E0
+
+ # .ctors, .dtors, .rodata, part of .data section
+ if offs >= 0x802EDCE0 and offs <= 0x80317734:
+ return offs - 0x4E0
+
+ # .data section
+ if offs >= 0x80317750 and offs <= 0x80322FDC:
+ return offs - 0x4F8
+
+ if offs >= 0x80323118 and offs <= 0x8035197C:
+ return offs - 0x5E0
+
+ # .sdata, part of .sbss section
+ if offs >= 0x80351980 and offs <= 0x80427E5F:
+ return offs - 0x580
+
+ if offs >= 0x80427E88 and offs <= 0x8042954B:
+ return offs - 0x5A8
+
+ if offs >= 0x80429570 and offs <= 0x80429D7F:
+ return offs - 0x5C8
+
+ # part of .sdata2, .sbss2 section
+ if offs >= 0x80429D80 and offs <= 0x807684BF: # end offset is right before d_profileNP header
+ return offs - 0x5C0
+
+ # d_profileNP and d_basesNP
+ # "no change" gap ends at 8779ABC
+ if offs >= 0x80779C70 and offs <= 0x8078891F:
+ return offs - 0x130
+
+ if offs >= 0x80788AD0 and offs <= 0x80789EEF:
+ return offs - 0x260
+
+ if offs >= 0x80789F00 and offs <= 0x808D3B87:
+ return offs - 0x270
+
+ if offs >= 0x808D3BD4 and offs <= 0x808D3C1F:
+ return offs - 0x2B4
+
+ if offs >= 0x808D3C20 and offs <= 0x80940C47:
+ return offs - 0x2C0
+
+ if offs >= 0x80940F58 and offs <= 0x80943167:
+ return offs - 0x4E8
+
+ if offs >= 0x809431F8 and offs <= 0x8094329F:
+ return offs - 0x4F8
+
+ if offs >= 0x809432C0 and offs <= 0x80944E77:
+ return offs - 0x500
+
+ if offs >= 0x80945144 and offs <= 0x80945153:
+ return offs - 0x714
+
+ if offs >= 0x80945158 and offs <= 0x8098A36B:
+ return offs - 0x718
+
+ if offs >= 0x8098A478 and offs <= 0x8098F81F:
+ return offs - 0x6F8
+
+ # d_enemiesNP
+ # this offset starts at the .rel header
+ if offs >= 0x809A2CA0 and offs <= 0xDEADBEEF:
+ return offs - 0x700
+
+ if offs >= 0x8010F430 and offs <= 0xDEADBEEF:
+ return offs - 0x330
+
+ if offs >= 0x8010F430 and offs <= 0xDEADBEEF:
+ return offs - 0x330
+
+
+
+import yaml
+
+original = 'pal'
+fix_for = {
+ 'pal2': fix_offs_ntsc_v1,
+ 'ntsc': fix_offs_ntsc_v1,
+ 'ntsc2': fix_offs_ntsc_v2
+}
+
+def do_mapfile(src, dest, fix_offset):
+ map = [x.rstrip() for x in open(src, 'r')]
+ new = []
+
+ for line in map:
+ if ' = 0x80' in line:
+ pos = line.find('0x80')
+ offs = int(line[pos:pos+10], 0)
+ offs = fix_offset(offs)
+ line = line[:pos] + make_hex_offset(offs) + line[pos+10:]
+
+ new.append(line + '\n')
+
+ open(dest, 'w').writelines(new)
+
+
+def work_on_hook(hook, id, func):
+ #print 'doing %s (%s) for %s' % (hook['name'], hook['type'], id)
+
+ t = hook['type']
+
+ if t == 'patch':
+ hook['addr_%s' % id] = func(hook['addr_%s' % original])
+
+ elif t == 'branch_insn' or t == 'add_func_pointer':
+ hook['src_addr_%s' % id] = func(hook['src_addr_%s' % original])
+
+ if 'target_func_%s' % original in hook:
+ hook['target_func_%s' % id] = func(hook['target_func_%s' % original])
+
+ elif t == 'nop_insn':
+ area = hook['area_%s' % original]
+ if isinstance(area, list):
+ start = func(area[0])
+ new_area = [start, start + (area[1] - area[0])]
+ else:
+ new_area = func(area)
+
+ hook['area_%s' % id] = new_area
+
+ #if hook['name'] == 'WM_onCreate': print hook
+
+
+def do_module(src, dest):
+ m = yaml.safe_load(open(src, 'r').read())
+
+ if 'hooks' not in m:
+ return
+
+ for id, func in fix_for.iteritems():
+ for hook in m['hooks']:
+ work_on_hook(hook, id, func)
+
+ open(dest, 'w').write(yaml.dump(m))
+
+
+def do_project(f):
+ proj = yaml.safe_load(open(f, 'r').read())
+
+ for m in proj['modules']:
+ do_module(m.replace('processed/', ''), m)
+
+
+def main():
+ do_mapfile('kamek_pal.x', 'kamek_pal2.x', fix_offs_pal_v2)
+ do_mapfile('kamek_pal.x', 'kamek_ntsc.x', fix_offs_ntsc_v1)
+ do_mapfile('kamek_pal.x', 'kamek_ntsc2.x', fix_offs_ntsc_v2)
+
+ do_project('NewerProject.yaml')
+
+ do_module('anotherhax.yaml', 'processed/anotherhax.yaml')
+
+if __name__ == '__main__':
+ main()
+
diff --git a/tools/mapfile_tool.pyc b/tools/mapfile_tool.pyc Binary files differnew file mode 100644 index 0000000..4d4ecc6 --- /dev/null +++ b/tools/mapfile_tool.pyc diff --git a/tools/mwasmeppc.exe b/tools/mwasmeppc.exe Binary files differnew file mode 100644 index 0000000..6e0c31a --- /dev/null +++ b/tools/mwasmeppc.exe diff --git a/tools/mwcceppc.exe b/tools/mwcceppc.exe Binary files differnew file mode 100644 index 0000000..e4061da --- /dev/null +++ b/tools/mwcceppc.exe diff --git a/tools/mwcceppc.idb b/tools/mwcceppc.idb Binary files differnew file mode 100644 index 0000000..c566ef2 --- /dev/null +++ b/tools/mwcceppc.idb diff --git a/tools/mwldeppc.exe b/tools/mwldeppc.exe Binary files differnew file mode 100644 index 0000000..48515e8 --- /dev/null +++ b/tools/mwldeppc.exe |