diff --git a/include/variables.h b/include/variables.h index 36293eeff94..5010961585c 100644 --- a/include/variables.h +++ b/include/variables.h @@ -6,7 +6,6 @@ extern u8 i_item_lst[24]; extern u8 lbl_80430188[16]; extern u8 lbl_80379235[16]; extern char lbl_80379234[0x64]; -extern char lbl_803739A0[0x310]; extern u32 _sRumbleSupported; extern u8 lbl_803A2EF4; extern char lbl_803A2EE0[20]; @@ -14,23 +13,16 @@ extern u8 lbl_80450B19; // extern u8 lbl_80450588; // extern u8 lbl_804511B8; extern u8 lbl_80450B20; -extern u8 lbl_80451A00; extern u8 lbl_80450B1C; extern u8 lbl_80450B28; -extern u8 lbl_80451A04; extern u8 lbl_80450B24; extern u8 lbl_80450B28; extern u8 lbl_80450B30; -extern u8 lbl_80451A08; extern u8 lbl_80450B2C; extern u8 lbl_80450B30; -extern u8 lbl_80451A08; extern u8 lbl_80450B2C; extern u8 lbl_80450B2C; -extern u8 lbl_80451A0C; -extern u8 lbl_80451A10; extern u8 lbl_80450B2C; -extern u8 lbl_80451A18; extern u8 lbl_80450B2C; extern u8 lbl_80450B1C; extern u8 lbl_80450B1C; @@ -101,9 +93,6 @@ extern u32 lbl_80000028; #define OS_GLOBAL(T, ADDR) *((T*)((void*)ADDR)) #define OS_GLOBAL_ADDR(T, ADDR) ((T*)((void*)ADDR)) -// func_802CEB40 -extern char lbl_8039CAD8[12]; // "JKRHeap.cpp" - // func_802D147C extern void* lbl_803CC0F0; // JKRDisposer::__vt @@ -192,10 +181,6 @@ extern void* lbl_804513C4; // JKRThreadSwitch::mUserPostCallback extern char lbl_8039CFA8[1]; // 8039cfdc-0x34 "JKRThreadSwitch: currentHeap destroyed.\n" -extern float lbl_80455FC0; // JKernel::@934 = 100.0 -extern float lbl_80455FC4; // JKernel::@935 = 1000.0 -extern double lbl_80455FC8; // JKernel::@937 = 4.503599627370496E15 - class JKRDvdFile; extern JSUList sDvdList__10JKRDvdFile; // JKRDvdFile::sDvdList extern u8 lbl_803CC438; // JKRDvdFile::__vt @@ -307,7 +292,6 @@ extern u8 lbl_80434318; // JKernel::@492 (global destructor chain) class JKRAramStream; extern JKRAramStream* sAramStreamObject__13JKRAramStream; // JKRAramStream::sAramStreamObject extern u8 transHeap__13JKRAramStream; // JKRAramStream::transHeap -extern char lbl_8039D120[16]; // "JKRAramStream.cpp" extern u8 transBuffer__13JKRAramStream; // JKRAramStream::transBuffer extern u8 transSize__13JKRAramStream; // JKRAramStream::transSize extern u8 lbl_803CC1B8; // JKRAramStream::__vt @@ -343,7 +327,6 @@ extern u8 lbl_803CC518; // JSUFileInputStream::__vt class JKRAram; extern u8 lbl_803CC158; // JKRAram::__vt -extern char lbl_8039D078[16]; // "JKRAram.cpp" extern JKRAram* sAramObject__7JKRAram; // JKRAram::sAramObject extern OSMessageQueue sMessageQueue__7JKRAram; // JKRAram::sMessageQueue extern bool lbl_804513FC; // DAT_804513fc (init global mutex) diff --git a/ldscript.lcf b/ldscript.lcf index ba50f6f137d..c4d4eee46f7 100644 --- a/ldscript.lcf +++ b/ldscript.lcf @@ -757,6 +757,7 @@ SECTIONS { "__dt__7JKRFileFv" = 0x802D7B90; "lbl_8039CE50" = 0x8039CE50; +"lbl_803739A0" = 0x803739A0; } FORCEACTIVE { getParentPane__7J2DPaneFv diff --git a/libs/JSystem/JKernel/JKRAram.cpp b/libs/JSystem/JKernel/JKRAram.cpp index ad2a8858fdc..1a4843275d2 100644 --- a/libs/JSystem/JKernel/JKRAram.cpp +++ b/libs/JSystem/JKernel/JKRAram.cpp @@ -107,17 +107,11 @@ asm void* JKRAram::run(void) { void JKRAram::checkOkAddress(u8* addr, u32 size, JKRAramBlock* block, u32 param_4) { if (!IS_ALIGNED((u32)addr, 0x20) && !IS_ALIGNED(size, 0x20)) { - const char* file = lbl_8039D078; - const char* format = lbl_8039D078 + 0xc; - const char* arg1 = lbl_8039D078 + 0xc + 0x3; - JUTException_NS_panic_f(file, 0xdb, format, arg1); + JUTException_NS_panic_f("JKRAram.cpp", 0xdb, "%s", ":::address not 32Byte aligned."); } if (block && !IS_ALIGNED((u32)block->getAddress() + param_4, 0x20)) { - const char* file = lbl_8039D078; - const char* format = lbl_8039D078 + 0xc; - const char* arg1 = lbl_8039D078 + 0xc + 0x3; - JUTException_NS_panic_f(file, 0xe3, format, arg1); + JUTException_NS_panic_f("JKRAram.cpp", 0xe3, "%s", ":::address not 32Byte aligned."); } } @@ -290,3 +284,6 @@ asm JSUList<12JKRAMCommand>::~JSUList<12JKRAMCommand>(void) { #include "JSystem/JKernel/JKRAram/asm/func_802D2DF0.s" } #endif + +const char* lbl_8039D0A6 = "bad aramSync\n"; +const char* lbl_8039D0B4 = "\x00\x00\x00"; /* padding */ diff --git a/libs/JSystem/JKernel/JKRAramPiece.cpp b/libs/JSystem/JKernel/JKRAramPiece.cpp index ad2b83d1701..4f45b4ca4ca 100644 --- a/libs/JSystem/JKernel/JKRAramPiece.cpp +++ b/libs/JSystem/JKernel/JKRAramPiece.cpp @@ -24,15 +24,11 @@ JKRAMCommand* JKRAramPiece::orderAsync(int direction, u32 source, u32 destinatio JKRAramBlock* block, JKRAMCommand::AsyncCallback callback) { lock(); if (((source & 0x1f) != 0) || ((destination & 0x1f) != 0)) { - OSReport(lbl_8039D0B8, direction); // "direction = %x\n" - OSReport(lbl_8039D0B8 + 0x10, source); // "source = %x\n" - OSReport(lbl_8039D0B8 + 0x1D, destination); // "destination = %x\n" - OSReport(lbl_8039D0B8 + 0x2F, length); // "length = %x\n" - - const char* filename = lbl_8039D0B8 + 0x3C; // "JKRAramPiece.cpp"ยง - const char* format = lbl_8039D0B8 + 0x3C + 0x11; // "%s" - const char* arg1 = lbl_8039D0B8 + 0x3C + 0x14; // "illegal address. abort." - JUTException_NS_panic_f(filename, 0x6c, format, arg1); + OSReport("direction = %x\n", direction); + OSReport("source = %x\n", source); + OSReport("destination = %x\n", destination); + OSReport("length = %x\n", length); + JUTException_NS_panic_f("JKRAramPiece.cpp", 0x6c, "%s", "illegal address. abort."); } Message* message = new (JKRHeap::getSystemHeap(), -4) Message(); diff --git a/libs/JSystem/JKernel/JKRAramStream.cpp b/libs/JSystem/JKernel/JKRAramStream.cpp index 353bfbe2854..6e1f3322fb1 100644 --- a/libs/JSystem/JKernel/JKRAramStream.cpp +++ b/libs/JSystem/JKernel/JKRAramStream.cpp @@ -2,6 +2,8 @@ #include "JSystem/JKernel/JKRAramPiece/JKRAramPiece.h" #include "global.h" +extern char lbl_8039D120[32]; + JKRAramStream* JKRAramStream::create(long priority) { if (!sAramStreamObject) { sAramStreamObject = new (JKRGetSystemHeap(), 0) JKRAramStream(priority); @@ -86,10 +88,7 @@ s32 JKRAramStream::writeToAram(JKRAramStreamCommand* command) { heap->dump(); } - const char* file = lbl_8039D120; // "JKRAramStream.cpp"; - const char* format = lbl_8039D120 + 0x12; // "%s"; - const char* arg1 = lbl_8039D120 + 0x15; // ":::Cannot alloc memory\n"; - JUTException_NS_panic_f(file, 0xac, format, arg1); + JUTException_NS_panic_f("JKRAramStream.cpp", 0xac, "%s", ":::Cannot alloc memory\n"); } if (buffer) { diff --git a/libs/JSystem/JKernel/JKRHeap.cpp b/libs/JSystem/JKernel/JKRHeap.cpp index bf3ee748983..96d49dbb941 100644 --- a/libs/JSystem/JKernel/JKRHeap.cpp +++ b/libs/JSystem/JKernel/JKRHeap.cpp @@ -336,10 +336,7 @@ void JKRHeap::copyMemory(void* dst, void* src, u32 size) { } void JKRHeap::JKRDefaultMemoryErrorRoutine(JKRHeap* heap, u32 size, int alignment) { - const char* filename = lbl_8039CAD8; // "JKRHeap.cpp" - const char* format = lbl_8039CAD8 + 12; // "%s" - const char* arg1 = lbl_8039CAD8 + 15; // "abort\n" - JUTException_NS_panic_f(filename, 0x33f, format, arg1); + JUTException_NS_panic_f("JKRHeap.cpp", 0x33f, "%s", "abort\n"); } bool JKRHeap::setErrorFlag(bool errorFlag) { @@ -437,3 +434,5 @@ u8 JKRHeap::do_changeGroupID(u8 newGroupID) { u8 JKRHeap::do_getCurrentGroupId() const { return 0; } + +const char* lbl_8039CAEE = "\x00"; /* padding */ diff --git a/libs/JSystem/JKernel/JKRSolidHeap.cpp b/libs/JSystem/JKernel/JKRSolidHeap.cpp index 5bbbd40a3da..ddbe0b75f90 100644 --- a/libs/JSystem/JKernel/JKRSolidHeap.cpp +++ b/libs/JSystem/JKernel/JKRSolidHeap.cpp @@ -282,3 +282,5 @@ void* JKRSolidHeap::do_getMaxFreeBlock(void) const { s32 JKRSolidHeap::do_getTotalFreeSize(void) const { return getFreeSize(); } + +const char* lbl_8039CFA7 = ""; /* padding */ diff --git a/libs/JSystem/JKernel/JKRThread.cpp b/libs/JSystem/JKernel/JKRThread.cpp index b37c996d3d6..e2da7735f95 100644 --- a/libs/JSystem/JKernel/JKRThread.cpp +++ b/libs/JSystem/JKernel/JKRThread.cpp @@ -2,6 +2,13 @@ #include "JSystem/JKernel/JKRHeap/JKRHeap.h" #include "global.h" +// lbl_80455FC0 JKRThread.o @934 +static const u8 lbl_80455FC0[4] = {0x42, 0xc8, 0x0, 0x0}; +// lbl_80455FC4 JKRThread.o @935 +static const u8 lbl_80455FC4[4] = {0x44, 0x7a, 0x0, 0x0}; +// lbl_80455FC8 JKRThread.o @937 +static const u8 lbl_80455FC8[8] = {0x43, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; + JKRThread::JKRThread(u32 stack_size, int message_count, int param_3) : mThreadListLink(this) { mSwitchCount = 0; mCost = 0; diff --git a/obj_files.mk b/obj_files.mk index 5ba663bc6d4..1a599c6b27e 100644 --- a/obj_files.mk +++ b/obj_files.mk @@ -10,10 +10,10 @@ EXTABINDEX_O_FILES := \ $(BUILD_DIR)/asm/extabindex.o TEXT_O_FILES := \ - $(BUILD_DIR)/asm/rodata/rodata_m_Do_main.o \ $(BUILD_DIR)/asm/sdata2/m_Do_main.o \ $(BUILD_DIR)/src/m_Do/m_Do_main.o \ $(BUILD_DIR)/asm/rodata/rodata_m_Do_printf.o \ + $(BUILD_DIR)/src/m_Do/m_Do_printf.o \ $(BUILD_DIR)/asm/m/Do/m_Do_printf.o \ $(BUILD_DIR)/asm/rodata/rodata_m_Do_audio.o \ $(BUILD_DIR)/src/m_Do/m_Do_audio.o \ @@ -804,26 +804,21 @@ TEXT_O_FILES := \ $(BUILD_DIR)/asm/sdata2/GFPixel.o \ $(BUILD_DIR)/asm/gf/GFPixel.o \ $(BUILD_DIR)/asm/gf/GFTev.o \ - $(BUILD_DIR)/asm/rodata/rodata_JKRHeap.o \ $(BUILD_DIR)/libs/JSystem/JKernel/JKRHeap.o \ $(BUILD_DIR)/asm/rodata/rodata_JKRExpHeap.o \ $(BUILD_DIR)/asm/sdata2/JKRExpHeap.o \ $(BUILD_DIR)/libs/JSystem/JKernel/JKRExpHeap.o \ $(BUILD_DIR)/libs/JSystem/JKernel/JKRSolidHeap.o \ - $(BUILD_DIR)/asm/rodata/rodata_JKRSolidHeap_padding.o \ $(BUILD_DIR)/libs/JSystem/JKernel/JKRAssertHeap.o \ $(BUILD_DIR)/libs/JSystem/JKernel/JKRDisposer.o \ $(BUILD_DIR)/asm/rodata/rodata_JKRThread.o \ - $(BUILD_DIR)/asm/sdata2/JKRThread.o \ $(BUILD_DIR)/libs/JSystem/JKernel/JKRThread.o \ $(BUILD_DIR)/asm/JKernel/JKRThread.o \ - $(BUILD_DIR)/asm/rodata/rodata_JKRAram.o \ $(BUILD_DIR)/libs/JSystem/JKernel/JKRAram.o \ $(BUILD_DIR)/asm/JKernel/JKRAram.o \ $(BUILD_DIR)/libs/JSystem/JKernel/JKRAramHeap.o \ $(BUILD_DIR)/asm/JKernel/JKRAramHeap.o \ $(BUILD_DIR)/libs/JSystem/JKernel/JKRAramBlock.o \ - $(BUILD_DIR)/asm/rodata/rodata_JKRAramPiece.o \ $(BUILD_DIR)/libs/JSystem/JKernel/JKRAramPiece.o \ $(BUILD_DIR)/asm/JKernel/JKRAramPiece.o \ $(BUILD_DIR)/asm/rodata/rodata_JKRAramStream.o \ diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 7001ca9f9a3..cb535686292 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -11,13 +11,24 @@ #include "m_Do/m_Do_machine/m_Do_machine.h" #include "m_Do/m_Do_reset/m_Do_reset.h" +extern u8 lbl_80451A00; +extern u8 lbl_80451A04; +extern u8 lbl_80451A08; +extern u8 lbl_80451A0C; +extern u8 lbl_80451A10; +extern u8 lbl_80451A18; +// extern char lbl_803739A0[0x310]; + +extern char lbl_803739A0; + void version_check(void) { - if ((!strcmp((char*)lbl_803739A0, (char*)lbl_803739A0)) && - (!strcmp(((char*)lbl_803739A0 + 0xA), ((char*)lbl_803739A0 + 0xA)))) { + if ((!strcmp("20Apr2004", "20Apr2004")) && (!strcmp("Patch2", "Patch2"))) { return; } - OSReport_Error((char*)lbl_803739A0 + 0x11); + OSReport_Error((char*)"\x53\x44\x4B\x82\xCC\x83\x6F\x81\x5B\x83\x57\x83\x87\x83\x93\x82\xAA\x88" + "\xEA\x92\x76\x82\xB5\x82\xDC\x82\xB9\x82\xF1\x81\x42\x92\xE2\x8E\x7E\x82" + "\xB5\x82\xDC\x82\xB7\x0A"); do { } while (true); } @@ -93,24 +104,46 @@ void HeapCheck::heapDisplay(void) const { s32 heap_total_free_size = heap->getTotalFreeSize(); s32 heap_free_size = heap->getFreeSize(); - JUTReport__FiiPCce(0x64, 0xd4, lbl_803739A0 + 0x3C, names[0]); - JUTReport__FiiPCce(0x64, 0xe3, lbl_803739A0 + 0x45, heap_size1); - JUTReport__FiiPCce(0x64, 0xf0, lbl_803739A0 + 0x5B, heap_size); - JUTReport__FiiPCce(0x64, 0xfd, lbl_803739A0 + 0x71, heap_total_free_size - heap_size2); - JUTReport__FiiPCce(0x64, 0x10a, lbl_803739A0 + 0x87, heap_free_size - heap_size2); - JUTReport__FiiPCce(0x64, 0x117, lbl_803739A0 + 0x9D, heap_total_used_size); - JUTReport__FiiPCce(0x64, 0x124, lbl_803739A0 + 0xB3, + JUTReport__FiiPCce(0x64, 0xd4, "[%sName]", names[0]); + JUTReport__FiiPCce(0x64, 0xe3, "HeapSize %8ld", heap_size1); + JUTReport__FiiPCce(0x64, 0xf0, "TargetHeapSize %8ld", heap_size); + JUTReport__FiiPCce(0x64, 0xfd, "TotalFree %8ld", heap_total_free_size - heap_size2); + JUTReport__FiiPCce(0x64, 0x10a, "FreeSize %8ld", heap_free_size - heap_size2); + JUTReport__FiiPCce(0x64, 0x117, "TotalUsedSize %8ld", heap_total_used_size); + JUTReport__FiiPCce(0x64, 0x124, "TotalUsedRate %3ld%%", (int)(heap_total_used_size * 0x64) / (int)heap_size); - JUTReport__FiiPCce(0x64, 0x131, lbl_803739A0 + 0xCF, max_total_used_size); - JUTReport__FiiPCce(0x64, 0x13e, lbl_803739A0 + 0xE5, + JUTReport__FiiPCce(0x64, 0x131, "MaxTotalUsedSize %8ld", max_total_used_size); + JUTReport__FiiPCce(0x64, 0x13e, "MaxTotalUsedRate %3ld%%", (max_total_used_size * 0x64) / (int)heap_size); - JUTReport__FiiPCce(0x64, 0x14b, lbl_803739A0 + 0x101, max_total_free_size - heap_size2); - JUTReport__FiiPCce(0x64, 0x158, lbl_803739A0 + 0x117, + JUTReport__FiiPCce(0x64, 0x14b, "MinFreeSize %8ld", max_total_free_size - heap_size2); + JUTReport__FiiPCce(0x64, 0x158, "MinFreeRate %3ld%%", ((max_total_free_size - heap_size2) * 0x64) / (int)heap_size); heap_size2 = countUsed(heap); - JUTReport__FiiPCce(0x64, 0x165, lbl_803739A0 + 0x133, heap_size2); + JUTReport__FiiPCce(0x64, 0x165, "UsedCount %3ld%", heap_size2); } +const char* lbl_80373AEF = ""; +const char* lbl_80373AF0 = "TotalFree"; +const char* lbl_80373AFA = "MaxUsed "; +const char* lbl_80373B04 = "Used "; +const char* lbl_80373B0E = "RelUsed "; +const char* lbl_80373B18 = "/ MaxFree"; +const char* lbl_80373B22 = "/HeapSize"; +const char* lbl_80373B2C = "Blk/Bytes"; +const char* lbl_80373B36 = "ARAM Free"; +const char* lbl_80373B40 = "%d"; +const char* lbl_80373B43 = "%s"; +const char* lbl_80373B46 = " [%s]"; +const char* lbl_80373B4C = "%10d"; +const char* lbl_80373B51 = "Press X+Y+START to CLEAR console."; +const char* lbl_80373B73 = "3DStick UP/Down to scroll"; +const char* lbl_80373B8D = "Press A to output terminal from console."; +const char* lbl_80373BB6 = + "\x53\x43\x52\x4F\x4C\x4C\x81\x46\x25\x33\x64\x20\x25\x33\x64\x20\x25\x33\x64\x20\x4F\x75\x74" + "\x70\x75\x74\x3D\x25\x31\x78"; /* undecodable string */ +const char* lbl_80373BD5 = "Press L+R trigger to control console."; +const char* lbl_80373BFB = "Press [Z] trigger to close this window."; + asm void debugDisplay(void) { nofralloc #include "m_Do\m_Do_main\asm\func_80005AD8.s" @@ -122,30 +155,42 @@ asm void Debug_console(u32) { } #ifdef NONMATCHING - -extern void memcpy(void*, void*, int); - void LOAD_COPYDATE(void*) { - s32 dvd_status; - char buffer[32]; DVDFileInfo file_info; - dvd_status = DVDOpen((const char*)lbl_803739A0[0x283], &file_info); - + s32 dvd_status = DVDOpen("/str/Final/Release/COPYDATE", &file_info); if (dvd_status) { + char buffer[32]; DVDReadPrio(&file_info, buffer, 32, 0, 2); memcpy(lbl_803A2EE0, buffer, 17); DVDClose(&file_info); } - return; } #else +const char* lbl_80373C23 = "/str/Final/Release/COPYDATE"; asm void LOAD_COPYDATE(void*) { nofralloc #include "m_Do\m_Do_main\asm\func_8000614C.s" } #endif +const char* lbl_80373C3F = "Root"; +const char* lbl_80373C44 = "\x83\x8B\x81\x5B\x83\x67"; /* undecodable string */ +const char* lbl_80373C4B = "System"; +const char* lbl_80373C52 = "\x83\x56\x83\x58\x83\x65\x83\x80"; /* undecodable string */ +const char* lbl_80373C5B = "Zelda"; +const char* lbl_80373C61 = "\x83\x5B\x83\x8B\x83\x5F"; /* undecodable string */ +const char* lbl_80373C68 = "Game"; +const char* lbl_80373C6D = "\x83\x51\x81\x5B\x83\x80"; /* undecodable string */ +const char* lbl_80373C74 = "Archive"; +const char* lbl_80373C7C = "\x83\x41\x81\x5B\x83\x4A\x83\x43\x83\x75"; /* undecodable string */ +const char* lbl_80373C87 = "J2d"; +const char* lbl_80373C8B = "J2D"; +const char* lbl_80373C8F = "Hostio"; +const char* lbl_80373C96 = "\x83\x7A\x83\x58\x83\x67\x49\x4F"; /* undecodable string */ +const char* lbl_80373C9F = "Command"; +const char* lbl_80373CA7 = "\x83\x52\x83\x7D\x83\x93\x83\x68"; /* undecodable string */ + void debug(void) { if (lbl_80450580[0]) { if (lbl_80450B1A[0]) { diff --git a/tools/section2cpp.py b/tools/section2cpp.py new file mode 100644 index 00000000000..1187abc8fa3 --- /dev/null +++ b/tools/section2cpp.py @@ -0,0 +1,612 @@ +#!/usr/bin/env python3 +# PYTHON_ARGCOMPLETE_OK + +""" + +This script will extract literals and strings data +from sections located in the baserom.dol. +Useful when trying to match .rodata and .sdata2. + +Usage: +./tools/section2cpp.py --section .rodata --string --object JKRSolidHeap.o + +""" + +import argparse +import sys +import os +import struct +from decimal import getcontext, Decimal +from pathlib import Path, PurePath, PureWindowsPath +from typing import ( + Any, + Dict, + List, + Match, + NamedTuple, + NoReturn, + Optional, + Set, + Tuple, + Union, + Callable, + Pattern, +) + +try: + import numpy +except: + print("error: missing numpy") + sys.exit(1) + + +try: + import argcomplete # type: ignore +except ModuleNotFoundError: + argcomplete = None + +parser = argparse.ArgumentParser(description="Extract section data and generate C++ code.") + +parser.add_argument( + "--section", + dest="section", + type=str, + metavar="SECTION", + help="SECTION to extract data from.", + required=True +) + +parser.add_argument( + "--file-offset", + dest="file_offset", + type=lambda x: int(x,0), + metavar="OFFSET", + help="OFFSET in the baserom for the SECTION." +) + +parser.add_argument( + "--object", + dest="object_name", + type=str, + metavar="OBJECT", + help="OBJECT filename to extract data from. (e.g. JKRSolidHeap.o)" +) + +parser.add_argument( + "--map", + dest="map_path", + type=str, + metavar="MAP", + help="frameworkF.map path", + default="frameworkF.map" +) + +parser.add_argument( + "--baserom", + dest="baserom", + type=str, + metavar="DOL", + help="baserom.dol path", + default="baserom.dol" +) + +parser.add_argument( + "--string", + dest="as_string", + action="store_true", + help="Print arrays as strings" +) + +parser.add_argument( + "--array", + dest="as_array", + action="store_true", + help="Print everything as u8 arrays" +) + +parser.add_argument( + "--shift-jis", + dest="shift_jis", + action="store_true", + help="Convert shift-jis to utf-8" +) + + +# +# +# + +def _itersplit(l, splitters): + current = [] + for item in l: + if item in splitters: + yield current + current = [] + else: + current.append(item) + yield current + +def magicsplit(l, *splitters): + return [subl for subl in _itersplit(l, splitters) ] + +def str_encoding(data): + if data[-1] != 0: + return None + + try: + data.decode("utf-8") + return "utf-8" + except: + pass + + try: + data.decode("shift_jisx0213") + return "shift-jis" + except: + pass + + return None + +def encoding_char_list(encoding, data): + if args.shift_jis and encoding == "shift-jis": + try: + return escape(data.decode("shift_jisx0213")) + except: + pass + return [ str(bytes([x]))[2:-1].replace("\"", "\\\"") for x in data ] + +def raw_string(data): + return "".join(data) + +def raw_array(data): + return ",".join([hex(x) for x in list(data)]) + +def escape_char(v): + if v == "\n": + return "\\n" + elif v == "\t": + return "\\t" + elif v == "\v": + return "\\v" + elif v == "\b": + return "\\b" + elif v == "\r": + return "\\r" + elif v == "\f": + return "\\f" + elif v == "\a": + return "\\a" + elif v == "\\": + return "\\\\" + elif v == "\"": + return "\\\"" + elif ord(v) < 32 and ord(v) > 127: + return "\\x" + hex(v)[2:].upper().rjust(2, '0') + else: + return v + +def escape(v): + return "".join([ escape_char(x) for x in list(v) ]) + +def bytes2float32(data): + if len(data) < 4: + return None + result = numpy.frombuffer(data[0:4][::-1], dtype='float32') + if result: + return result[0] + else: + return None + +def bytes2float64(data): + if len(data) < 8: + return None + result = numpy.frombuffer(data[0:8][::-1], dtype='float64') + if result: + return result[0] + else: + return None + +def is_nice_float32(f): + try: + if int(f*1000) == f*1000: + return True + if int(f*100) == f*100: + return True + if int(f*10) == f*10: + return True + if int(f) == f: + return True + except: + return False + return False + +def is_nice_float64(f): + try: + if int(f*1000) == f*1000: + return True + if int(f*100) == f*100: + return True + if int(f*10) == f*10: + return True + if int(f) == f: + return True + except: + return False + return False + +float32_exact: Dict[numpy.float32, Tuple[int,int]] = {} +float64_exact: Dict[numpy.float64, Tuple[int,int]] = {} + +getcontext().prec = 64 +for i in range(1,32): + for j in range(1,32): + if i%j == 0: + continue + d = Decimal(i)/Decimal(j) + f = numpy.float32(d) + if str(f) != str(d): + if not f in float32_exact: + float32_exact[f] = (i,j) + +for i in range(1,32): + for j in range(1,32): + if i%j == 0: + continue + d = Decimal(i)/Decimal(j) + f = numpy.float64(d) + if str(f) != str(d): + if not f in float64_exact: + float64_exact[f] = (i,j) + +class Symbol: + def __init__(self, name, addr, size): + self.name = name + self.addr = addr + self.size = size + self.padding = 0 + + def __str__(self): + return " %s %s %s+%s %s" % (self.name.ljust(40, ' '), hex(self.addr), hex(self.addr + self.size), hex(self.padding), hex(self.size)) + +class ObjectFile: + def __init__(self, path): + self.path = path + self.symbols = [] + self.start = 0 + self.end = 0 + self.mk = False + + def addSymbol(self, name, str_addr, str_size): + addr = int(str_addr, base=16) + size = int(str_size, base=16) + + symbol = Symbol(name, addr, size) + if not self.symbols: + self.start = symbol.addr + else: + last_symbol = self.symbols[-1] + last_addr = last_symbol.addr + last_symbol.size + if last_addr != addr: + last_symbol.padding += addr - last_addr + self.symbols += [ symbol ] + + def setEnd(self, end): + self.end = end + last_symbol = self.symbols[-1] + last_symbol.padding = self.end - (last_symbol.addr + last_symbol.size) + +def find_symbols(): + file = map_path.open('r') + lines = file.readlines() + + in_section = False + last_obj = None + for line in lines: + data = [ x.strip() for x in line.strip().split(" ") ] + data = [ x for x in data if len(x) > 0 ] + + if len(data) == 3: + in_section = False + if data[0] == section: + in_section = True + continue + + if not in_section: + continue + if len(data) < 6 or len(data) > 7: + continue + + # get object filename + obj = data[5] + if len(data) > 6: + obj = data[6] + + # remove path from object filename + obj = obj.split("\\")[-1] + if last_obj != obj: + assert obj not in object_map + object_map[obj] = ObjectFile(obj) + last_obj = obj + + # add symbol + size = data[1] + addr = data[2] + name = data[4] + object_map[obj].addSymbol(name, addr, size) + + keys = list(object_map.keys()) + for i,_ in enumerate(keys[:-1]): + obj = object_map[keys[i]] + next_obj = object_map[keys[i + 1]] + obj.setEnd(next_obj.start) + + # total size of rodata must be aligned to 0x20 + obj = object_map[keys[-1]] + last_symbol = obj.symbols[-1] + last_addr = last_symbol.addr + last_symbol.size + last_symbol.padding = ((last_addr + 31) & ~31) - last_addr + file.close() + +def chunks(lst, n): + for i in range(0, len(lst), n): + yield lst[i:i + n] + +def data_as_string(data): + return ", ".join([ "0x" + hex(x)[2:].rjust(2, '0') for x in data ]) + + +class Literal: + def __init__(self, name, type, value, comment=None): + self.name = name + self.type = type + self.value = value + self.comment = comment + + def format(self): + return str(self.value) + + def lines(self): + line = "static const %s %s = %s;" % (self.type, self.name, self.format()) + if self.comment: + line = line.ljust(90, ' ') + " // " + self.comment + return [ line ] + + def __str__(self): + return "\n".join(self.lines()) + +class Label(Literal): + def __init__(self, name): + super().__init__(name, "", None, None) + + def lines(self): + return [ "", "", "// " + self.name ] + +class Float32Literal(Literal): + def __init__(self, name, value, comment=None): + super().__init__(name, "float", value, comment) + + def format(self): + return "%sf" % self.value + +class Float64Literal(Literal): + def __init__(self, name, value, comment=None): + super().__init__(name, "double", value, comment) + +class FractionFloat32Literal(Literal): + def __init__(self, name, value, comment=None): + super().__init__(name, "float", value, comment) + + def format(self): + return "%i.0f / %i.0f" % self.value + +class FractionFloat64Literal(Literal): + def __init__(self, name, value, comment=None): + super().__init__(name, "double", value, comment) + + def format(self): + return "%i.0 / %i.0" % self.value + +class U32Literal(Literal): + def __init__(self, name, value, comment=None): + super().__init__(name, "u32", value, comment) + +class S32Literal(Literal): + def __init__(self, name, value, comment=None): + super().__init__(name, "s32", value, comment) + +class S64Literal(Literal): + def __init__(self, name, value, comment=None): + super().__init__(name, "s64", value, comment) + +class U64Literal(Literal): + def __init__(self, name, value, comment=None): + super().__init__(name, "u64", value, comment) + +class ArrayLiteral(Literal): + def __init__(self, name, value, comment=None): + super().__init__(name, "u8", value, comment) + + def lines(self): + one_line = "static const %s %s[%i] = { %s };" % (self.type, self.name, len(self.value), data_as_string(self.value)) + + lines = [] + if len(one_line) < 90: + lines += [ one_line ] + else: + lines += [ "static const %s %s[%i] = {" % (self.type, self.name, len(self.value)) ] + data_chunks = chunks(list(self.value), 16) + for chunk in data_chunks: + lines += [ " " + data_as_string(chunk) ] + lines += [ "};" ] + + if lines and self.comment: + lines[0] = lines[0].ljust(90, ' ') + " // " + self.comment + return lines + +class StringLiteral(Literal): + def __init__(self, name, encoding, value, comment=None): + assert value[-1] == 0 + super().__init__(name, "char", value[:-1], comment) + self.encoding = encoding + + def lines(self): + char_list = encoding_char_list(self.encoding, self.value) + one_line = "static const %s %s = \"%s\";" % (self.type, self.name, raw_string(char_list)) + + lines = [] + if len(one_line) < 90: + lines += [ one_line ] + else: + lines += [ "static const %s %s = " % (self.type, self.name) ] + data_chunks = chunks(char_list, 16) + for chunk in data_chunks: + lines += [ " \"%s\"" % raw_string(chunk) ] + lines[-1] += ";" + + if lines and self.comment: + lines[0] = lines[0].ljust(90, ' ') + " // " + self.comment + return lines + +def output_cpp(): + object_names = [] + if object_name: + if not object_name in object_map: + print("error: %s object file not found!" % object_name) + sys.exit(1) + object_names += [ object_name ] + else: + object_names = [*object_map.keys()] + + br = baserom.open("rb") + br.seek(0, os.SEEK_END) + br_size = br.tell() + br.seek(0, os.SEEK_SET) + + literals = [] + for obj_name in object_names: + literals += [ Label(obj_name) ] + + obj = object_map[obj_name] + for symbol in obj.symbols: + label = "lbl_%s" % (hex(symbol.addr).upper()[2:]) + + symbol_file_offset = symbol.addr - file_offset + symbol_file_size = symbol.size + symbol.padding + + if symbol_file_offset + symbol_file_size > br_size: + print("error: reading outside baserom file. (%i, %i)" % (symbol_file_offset + symbol_file_size, br_size)) + + br.seek(symbol_file_offset, os.SEEK_SET) + data = br.read(symbol.size) + padding = br.read(symbol.padding) + + if args.as_string: + offset = 0 + str_segments = [ x for x in magicsplit(data, 0) ] + for segment in str_segments[:-1]: + str_data = bytes(segment + [0]) + encoding = str_encoding(str_data) + + str_label = "lbl_%s" % (hex(symbol.addr + offset).upper()[2:]) + if encoding == "shift-jis": + literals += [ StringLiteral(str_label, "shift-jis", str_data, "TODO: shift-jis strings in Metrowerks") ] + elif encoding == "utf-8": + literals += [ StringLiteral(str_label, "utf-8", str_data) ] + else: + literals += [ ArrayLiteral(str_label, str_data, "undecodable string") ] + offset += len(str_data) + + if padding: + padding_label = "lbl_%s" % (hex(symbol.addr + symbol.size).upper()[2:]) + literals += [ StringLiteral(padding_label, None, padding, "padding") ] + padding = None + elif args.as_array: + literals += [ ArrayLiteral(label, data) ] + else: + lit = None + if len(data) == 4: + u32_data = struct.unpack('>I', data)[0] + s32_data = struct.unpack('>i', data)[0] + float_data = bytes2float32(data) + + if s32_data == 0 or (s32_data >= -4096 and s32_data <= 4096): + lit = S32Literal(label, s32_data) + elif u32_data == 0 or (u32_data < 4096): + lit = U32Literal(label, u32_data) + elif float_data in float32_exact: + lit = FractionFloat32Literal(label, float32_exact[float_data], "%sf %s" % (float_data, hex(u32_data))) + elif is_nice_float32(float_data): + lit = Float32Literal(label, float_data, hex(u32_data)) + + elif len(data) == 8: + u64_data = struct.unpack('>Q', data)[0] + s64_data = struct.unpack('>q', data)[0] + double_data = bytes2float64(data) + + if u64_data == 0x4330000000000000: + lit = Float64Literal(label, double_data, "%s | u32 to float (compiler-generated)" % hex(u64_data)) + elif u64_data == 0x4330000080000000: + lit = Float64Literal(label, double_data, "%s | s32 to float (compiler-generated)" % hex(u64_data)) + elif s64_data == 0 or (s64_data >= -4096 and s64_data <= 4096): + lit = S64Literal(label, s64_data) + elif u64_data == 0 or (u64_data < 4096): + lit = U64Literal(label, u64_data) + elif double_data in float64_exact: + lit = FractionFloat64Literal(label, float64_exact[double_data], "%s %s" % (double_data, hex(u64_data))) + elif is_nice_float64(double_data): + lit = Float64Literal(label, double_data, hex(u64_data)) + + if not lit: + lit = ArrayLiteral(label, data) + literals += [ lit ] + + if padding: + padding_label = "lbl_%s" % (hex(symbol.addr + symbol.size).upper()[2:]) + literals += [ ArrayLiteral(padding_label, padding, "padding") ] + + for lit in literals: + print(lit) + + br.close() + +# +# +# + +try: + args = parser.parse_args() +except: + parser.print_help() + sys.exit(0) + +section = args.section +object_name = args.object_name +file_offset: Optional[int] = args.file_offset +baserom = Path(args.baserom) +map_path = Path(args.map_path) + +file_offsets = { + ".rodata": 0x80003000, + ".sdata": 0x800802A0, + ".sdata2": 0x800811A0, +} + +if not file_offset: + if not section in file_offsets: + print("error: missing --file-offset") + sys.exit(1) + else: + file_offset = file_offsets[section] + +if not baserom.exists(): + print("error: baserom '%s' not found!" % args.baserom) + sys.exit(1) + +if not map_path.exists(): + print("error: frameworkF.map '%s' not found!" % args.map_path) + sys.exit(1) + +object_map: Dict[str,ObjectFile] = {} + +find_symbols() +output_cpp()