diff --git a/ps2xRecomp/include/ps2recomp/ps2_recompiler.h b/ps2xRecomp/include/ps2recomp/ps2_recompiler.h index 49188ba..95bb39d 100644 --- a/ps2xRecomp/include/ps2recomp/ps2_recompiler.h +++ b/ps2xRecomp/include/ps2recomp/ps2_recompiler.h @@ -37,29 +37,15 @@ namespace ps2recomp std::vector m_relocations; std::unordered_map> m_decodedFunctions; - std::unordered_map m_stubFunctions; std::unordered_map m_skipFunctions; std::map m_generatedStubs; bool decodeFunction(Function &function); - bool shouldStubFunction(const std::string &name) const; bool shouldSkipFunction(const std::string &name) const; std::string generateRuntimeHeader(); - std::string generateStubFunction(const Function &function); bool generateFunctionHeader(); bool writeToFile(const std::string &path, const std::string &content); std::filesystem::path getOutputPath(const Function &function) const; - - private: - std::string generatePrintfStub(const std::string &name); - std::string generateMemoryCopyStub(const std::string &name); - std::string generateFileIOStub(const std::string &name); - std::string generateStringStub(const std::string &name); - std::string generateMathStub(const std::string &name); - std::string generateTimeStub(const std::string &name); - std::string generateNetworkStub(const std::string &name); - std::string generateThreadStub(const std::string &name); - std::string generateDefaultStub(const std::string &name); }; } diff --git a/ps2xRecomp/include/ps2recomp/types.h b/ps2xRecomp/include/ps2recomp/types.h index 9166878..6747404 100644 --- a/ps2xRecomp/include/ps2recomp/types.h +++ b/ps2xRecomp/include/ps2recomp/types.h @@ -153,7 +153,6 @@ namespace ps2recomp std::string inputPath; std::string outputPath; bool singleFileOutput; - std::vector stubFunctions; std::vector skipFunctions; std::unordered_map patches; std::map stubImplementations; diff --git a/ps2xRecomp/src/config_manager.cpp b/ps2xRecomp/src/config_manager.cpp index 9ccea6b..2601af6 100644 --- a/ps2xRecomp/src/config_manager.cpp +++ b/ps2xRecomp/src/config_manager.cpp @@ -26,7 +26,6 @@ namespace ps2recomp config.outputPath = toml::find(data, "general", "output"); config.singleFileOutput = toml::find(data, "general", "single_file_output"); - config.stubFunctions = toml::find>(data, "general", "stubs"); config.skipFunctions = toml::find>(data, "general", "skip"); if (data.contains("patches") && data.at("patches").is_table()) @@ -78,13 +77,6 @@ namespace ps2recomp general["single_file_output"] = config.singleFileOutput; data["general"] = general; - toml::array stubs; - for (const auto &stub : config.stubFunctions) - { - stubs.push_back(stub); - } - data["stubs"] = stubs; - toml::array skips; for (const auto &skip : config.skipFunctions) { diff --git a/ps2xRecomp/src/ps2_recompiler.cpp b/ps2xRecomp/src/ps2_recompiler.cpp index f415fc8..c12411c 100644 --- a/ps2xRecomp/src/ps2_recompiler.cpp +++ b/ps2xRecomp/src/ps2_recompiler.cpp @@ -21,12 +21,7 @@ namespace ps2recomp try { m_config = m_configManager.loadConfig(); - - for (const auto &name : m_config.stubFunctions) - { - m_stubFunctions[name] = true; - } - + for (const auto &name : m_config.skipFunctions) { m_skipFunctions[name] = true; @@ -44,6 +39,11 @@ namespace ps2recomp m_sections = m_elfParser->getSections(); m_relocations = m_elfParser->getRelocations(); + std::cout << "Extracted " << m_functions.size() << " functions, " + << m_symbols.size() << " symbols, " + << m_sections.size() << " sections, " + << m_relocations.size() << " relocations." << std::endl; + m_decoder = std::make_unique(); m_codeGenerator = std::make_unique(m_symbols); @@ -80,18 +80,6 @@ namespace ps2recomp continue; } - if (shouldStubFunction(function.name)) - { - std::cout << "Stubbing function: " << function.name << std::endl; - function.isStub = true; - function.isRecompiled = true; // we're generating code for it - - std::string stubCode = generateStubFunction(function); - m_generatedStubs[function.start] = stubCode; - - continue; - } - if (!decodeFunction(function)) { std::cerr << "Failed to decode function: " << function.name << std::endl; @@ -273,11 +261,6 @@ namespace ps2recomp return true; } - bool PS2Recompiler::shouldStubFunction(const std::string &name) const - { - return m_stubFunctions.find(name) != m_stubFunctions.end(); - } - bool PS2Recompiler::shouldSkipFunction(const std::string &name) const { return m_skipFunctions.find(name) != m_skipFunctions.end(); @@ -288,115 +271,6 @@ namespace ps2recomp return m_codeGenerator->generateMacroHeader(); } - std::string PS2Recompiler::generateStubFunction(const Function &function) - { - std::stringstream ss; - - ss << "#include \"ps2_runtime_macros.h\"\n"; - ss << "#include \"ps2_runtime.h\"\n"; - ss << "#include \"ps2_recompiled_functions.h\"\n\n"; - - ss << "// STUB FUNCTION: " << function.name << "\n"; - ss << "// Address: 0x" << std::hex << function.start << " - 0x" << function.end << std::dec << "\n"; - ss << "void " << function.name << "(uint8_t* rdram, R5900Context* ctx) {\n"; - - auto stubImpl = m_config.stubImplementations.find(function.name); - if (stubImpl != m_config.stubImplementations.end()) - { - ss << " // Custom stub implementation\n"; - ss << " " << stubImpl->second << "\n"; - } - else - { - const std::string &name = function.name; - - if (name == "printf" || name == "fprintf" || name == "sprintf" || - name == "snprintf" || name == "vprintf" || name == "vfprintf" || - name == "vsprintf" || name == "vsnprintf") - { - ss << generatePrintfStub(name); - } - else if (name == "fopen" || name == "fclose" || name == "fread" || - name == "fwrite" || name == "fseek" || name == "ftell" || - name == "rewind" || name == "fflush" || name == "ferror" || - name == "clearerr" || name == "feof" || name == "open" || - name == "close" || name == "read" || name == "write" || - name == "lseek" || name == "stat" || name == "fstat") - { - ss << generateFileIOStub(name); - } - else if (name == "strlen" || name == "strcpy" || name == "strncpy" || - name == "strcat" || name == "strncat" || name == "strcmp" || - name == "strncmp" || name == "strchr" || name == "strrchr" || - name == "strstr" || name == "strtok" || name == "strtok_r") - { - ss << generateStringStub(name); - } - else if (name == "sin" || name == "cos" || name == "tan" || - name == "asin" || name == "acos" || name == "atan" || - name == "atan2" || name == "sinh" || name == "cosh" || - name == "tanh" || name == "exp" || name == "log" || - name == "log10" || name == "pow" || name == "sqrt" || - name == "ceil" || name == "floor" || name == "fabs" || - name == "fmod") - { - ss << generateMathStub(name); - } - else if (name == "time" || name == "clock" || name == "difftime" || - name == "mktime" || name == "localtime" || name == "gmtime" || - name == "asctime" || name == "ctime" || name == "strftime") - { - ss << generateTimeStub(name); - } - else if (name == "socket" || name == "bind" || name == "listen" || - name == "accept" || name == "connect" || name == "send" || - name == "recv" || name == "sendto" || name == "recvfrom" || - name == "gethostbyname" || name == "gethostbyaddr") - { - ss << generateNetworkStub(name); - } - else if (name == "pthread_create" || name == "pthread_join" || - name == "pthread_exit" || name == "pthread_mutex_init" || - name == "pthread_mutex_lock" || name == "pthread_mutex_unlock" || - name == "pthread_cond_init" || name == "pthread_cond_wait" || - name == "pthread_cond_signal") - { - ss << generateThreadStub(name); - } - else - { - ss << generateDefaultStub(name); - } - } - - ss << "}\n"; - - return ss.str(); - } - - std::string PS2Recompiler::generatePrintfStub(const std::string &name) - { - std::stringstream ss; - - ss << " // Format string is in $a0 (r4), args start at $a1 (r5)\n"; - ss << " #ifdef _DEBUG\n"; - - if (name == "fprintf" || name == "vfprintf") - { - ss << " printf(\"Stub called: " << name << " with file handle=0x%08X, format at 0x%08X\\n\", ctx->r[4], ctx->r[5]);\n"; - } - else - { - ss << " printf(\"Stub called: " << name << " with format at 0x%08X\\n\", ctx->r[4]);\n"; - } - - ss << " #endif\n"; - ss << " // Return success (number of characters, but we'll just say 1)\n"; - ss << " ctx->r[2] = 1;\n"; - - return ss.str(); - } - bool PS2Recompiler::writeToFile(const std::string &path, const std::string &content) { std::ofstream file(path); @@ -433,341 +307,4 @@ namespace ps2recomp return outputPath; } - - std::string PS2Recompiler::generateMemoryCopyStub(const std::string &name) - { - std::stringstream ss; - - ss << " // Memory copy\n"; - - if (name == "bcopy") - { - ss << " uint32_t src = ctx->r[4]; // Source in $a0\n"; - ss << " uint32_t dst = ctx->r[5]; // Destination in $a1\n"; - } - else - { - ss << " uint32_t dst = ctx->r[4]; // Destination in $a0\n"; - ss << " uint32_t src = ctx->r[5]; // Source in $a1\n"; - } - - ss << " uint32_t size = ctx->r[6]; // Size in $a2\n"; - ss << " #ifdef _DEBUG\n"; - ss << " printf(\"Stub called: " << name << "(dst=0x%08X, src=0x%08X, size=%u)\\n\", " - << (name == "bcopy" ? "dst, src" : "dst, src") << ", size);\n"; - ss << " #endif\n"; - ss << " // Only copy if within valid memory range\n"; - ss << " if (dst < 0x2000000 && src < 0x2000000 && dst + size < 0x2000000 && src + size < 0x2000000) {\n"; - - if (name == "memmove") - { - ss << " memmove(rdram + dst, rdram + src, size);\n"; - } - else - { - ss << " memcpy(rdram + dst, rdram + src, size);\n"; - } - - ss << " }\n"; - - if (name == "bcopy") - { - ss << " // bcopy doesn't return a value\n"; - } - else - { - ss << " ctx->r[2] = dst; // Return destination pointer\n"; - } - - return ss.str(); - } - - std::string PS2Recompiler::generateFileIOStub(const std::string &name) - { - std::stringstream ss; - - ss << " // File I/O operation: " << name << "\n"; - ss << " #ifdef _DEBUG\n"; - - if (name == "fopen" || name == "open") - { - ss << " uint32_t path_ptr = ctx->r[4]; // Path pointer in $a0\n"; - ss << " uint32_t mode_ptr = ctx->r[5]; // Mode pointer in $a1\n"; - ss << " printf(\"Stub called: " << name << "(path=0x%08X, mode=0x%08X)\\n\", path_ptr, mode_ptr);\n"; - ss << " #endif\n"; - ss << " // Return a fake file handle\n"; - ss << " ctx->r[2] = 0x12345678; // Fake file handle\n"; - } - else if (name == "fclose" || name == "close") - { - ss << " uint32_t handle = ctx->r[4]; // File handle in $a0\n"; - ss << " printf(\"Stub called: " << name << "(handle=0x%08X)\\n\", handle);\n"; - ss << " #endif\n"; - ss << " // Return success\n"; - ss << " ctx->r[2] = 0;\n"; - } - else if (name == "fread" || name == "read") - { - ss << " uint32_t buffer = ctx->r[4]; // Buffer pointer in $a0\n"; - ss << " uint32_t size = ctx->r[5]; // Size in $a1\n"; - ss << " uint32_t count = ctx->r[6]; // Count in $a2 (for fread)\n"; - ss << " uint32_t handle = ctx->r[7]; // File handle in $a3\n"; - ss << " printf(\"Stub called: " << name << "(buffer=0x%08X, size=%u, count=%u, handle=0x%08X)\\n\", buffer, size, count, handle);\n"; - ss << " #endif\n"; - ss << " // Return number of bytes/items read\n"; - ss << " ctx->r[2] = " << (name == "fread" ? "count" : "size") << "; // Pretend we read everything\n"; - } - else if (name == "fwrite" || name == "write") - { - ss << " uint32_t buffer = ctx->r[4]; // Buffer pointer in $a0\n"; - ss << " uint32_t size = ctx->r[5]; // Size in $a1\n"; - ss << " uint32_t count = ctx->r[6]; // Count in $a2 (for fwrite)\n"; - ss << " uint32_t handle = ctx->r[7]; // File handle in $a3\n"; - ss << " printf(\"Stub called: " << name << "(buffer=0x%08X, size=%u, count=%u, handle=0x%08X)\\n\", buffer, size, count, handle);\n"; - ss << " #endif\n"; - ss << " // Return number of bytes/items written\n"; - ss << " ctx->r[2] = " << (name == "fwrite" ? "count" : "size") << "; // Pretend we wrote everything\n"; - } - else - { - ss << " printf(\"Stub called: " << name << "()\\n\");\n"; - ss << " #endif\n"; - ss << " // Return success\n"; - ss << " ctx->r[2] = 0;\n"; - } - - return ss.str(); - } - - std::string PS2Recompiler::generateStringStub(const std::string &name) - { - std::stringstream ss; - - ss << " // String operation: " << name << "\n"; - ss << " #ifdef _DEBUG\n"; - - if (name == "strlen") - { - ss << " uint32_t str_ptr = ctx->r[4]; // String pointer in $a0\n"; - ss << " printf(\"Stub called: strlen(str=0x%08X)\\n\", str_ptr);\n"; - ss << " #endif\n"; - ss << " // If string is in valid memory range, calculate real length\n"; - ss << " if (str_ptr < 0x2000000) {\n"; - ss << " const char* str = (const char*)(rdram + str_ptr);\n"; - ss << " // Safely calculate strlen with bounds checking\n"; - ss << " size_t len = 0;\n"; - ss << " while (str_ptr + len < 0x2000000 && str[len] != '\\0') {\n"; - ss << " len++;\n"; - ss << " }\n"; - ss << " ctx->r[2] = len;\n"; - ss << " } else {\n"; - ss << " ctx->r[2] = 0;\n"; - ss << " }\n"; - } - else if (name == "strcpy" || name == "strncpy") - { - ss << " uint32_t dst_ptr = ctx->r[4]; // Destination pointer in $a0\n"; - ss << " uint32_t src_ptr = ctx->r[5]; // Source pointer in $a1\n"; - if (name == "strncpy") - { - ss << " uint32_t max_len = ctx->r[6]; // Max length in $a2\n"; - ss << " printf(\"Stub called: strncpy(dst=0x%08X, src=0x%08X, n=%u)\\n\", dst_ptr, src_ptr, max_len);\n"; - } - else - { - ss << " printf(\"Stub called: strcpy(dst=0x%08X, src=0x%08X)\\n\", dst_ptr, src_ptr);\n"; - } - ss << " #endif\n"; - ss << " // Return destination pointer\n"; - ss << " ctx->r[2] = dst_ptr;\n"; - } - else if (name == "strcmp" || name == "strncmp") - { - ss << " uint32_t str1_ptr = ctx->r[4]; // String 1 pointer in $a0\n"; - ss << " uint32_t str2_ptr = ctx->r[5]; // String 2 pointer in $a1\n"; - if (name == "strncmp") - { - ss << " uint32_t max_len = ctx->r[6]; // Max length in $a2\n"; - ss << " printf(\"Stub called: strncmp(s1=0x%08X, s2=0x%08X, n=%u)\\n\", str1_ptr, str2_ptr, max_len);\n"; - } - else - { - ss << " printf(\"Stub called: strcmp(s1=0x%08X, s2=0x%08X)\\n\", str1_ptr, str2_ptr);\n"; - } - ss << " #endif\n"; - ss << " // Return comparison result (0 for equal)\n"; - ss << " ctx->r[2] = 0;\n"; - } - else - { - ss << " printf(\"Stub called: " << name << "()\\n\");\n"; - ss << " #endif\n"; - ss << " // Return success\n"; - ss << " ctx->r[2] = 0;\n"; - } - - return ss.str(); - } - - std::string PS2Recompiler::generateMathStub(const std::string &name) - { - std::stringstream ss; - - ss << " // Math operation: " << name << "\n"; - ss << " #ifdef _DEBUG\n"; - ss << " printf(\"Stub called: " << name << "()\\n\");\n"; - ss << " #endif\n"; - - if (name == "sin" || name == "cos" || name == "tan" || - name == "asin" || name == "acos" || name == "atan" || - name == "atan2" || name == "sinh" || name == "cosh" || - name == "tanh" || name == "exp" || name == "log" || - name == "log10" || name == "pow" || name == "sqrt" || - name == "ceil" || name == "floor" || name == "fabs" || - name == "fmod") - { - ss << " // Simply delegate to host function\n"; - ss << " float arg1 = *(float*)&ctx->r[4]; // First argument in $a0\n"; - - if (name == "atan2" || name == "pow" || name == "fmod") - { - ss << " float arg2 = *(float*)&ctx->r[5]; // Second argument in $a1\n"; - ss << " float result = " << name << "f(arg1, arg2);\n"; - } - else - { - ss << " float result = " << name << "f(arg1);\n"; - } - - ss << " *(float*)&ctx->r[2] = result; // Return result in $v0\n"; - } - else - { - ss << " // Return 0.0f as default\n"; - ss << " *(float*)&ctx->r[2] = 0.0f;\n"; - } - - return ss.str(); - } - - std::string PS2Recompiler::generateTimeStub(const std::string &name) - { - std::stringstream ss; - - ss << " // Time operation: " << name << "\n"; - ss << " #ifdef _DEBUG\n"; - ss << " printf(\"Stub called: " << name << "()\\n\");\n"; - ss << " #endif\n"; - - if (name == "time") - { - ss << " // Return current time value (seconds since epoch)\n"; - ss << " ctx->r[2] = (uint32_t)time(NULL);\n"; - } - else if (name == "clock") - { - ss << " // Return clock ticks\n"; - ss << " ctx->r[2] = (uint32_t)clock();\n"; - } - else - { - ss << " // Return success\n"; - ss << " ctx->r[2] = 0;\n"; - } - - return ss.str(); - } - - // TODO give this more attention - std::string PS2Recompiler::generateNetworkStub(const std::string &name) - { - std::stringstream ss; - - ss << " // Network operation: " << name << "\n"; - ss << " #ifdef _DEBUG\n"; - ss << " printf(\"Stub called: " << name << "()\\n\");\n"; - ss << " #endif\n"; - - if (name == "socket") - { - ss << " // Return fake socket descriptor\n"; - ss << " ctx->r[2] = 3; // Fake socket fd\n"; - } - else if (name == "bind" || name == "listen" || name == "connect") - { - ss << " // Return success\n"; - ss << " ctx->r[2] = 0;\n"; - } - else if (name == "accept") - { - ss << " // Return fake client socket descriptor\n"; - ss << " ctx->r[2] = 4; // Fake client socket fd\n"; - } - else if (name == "send" || name == "sendto") - { - ss << " uint32_t size = ctx->r[6]; // Size in $a2\n"; - ss << " // Return bytes sent (all of them)\n"; - ss << " ctx->r[2] = size;\n"; - } - else if (name == "recv" || name == "recvfrom") - { - ss << " // Return 0 (no data)\n"; - ss << " ctx->r[2] = 0;\n"; - } - else - { - ss << " // Return failure (-1)\n"; - ss << " ctx->r[2] = (uint32_t)-1;\n"; - } - - return ss.str(); - } - - std::string PS2Recompiler::generateThreadStub(const std::string &name) - { - std::stringstream ss; - - ss << " // Thread operation: " << name << "\n"; - ss << " #ifdef _DEBUG\n"; - ss << " printf(\"Stub called: " << name << "()\\n\");\n"; - ss << " #endif\n"; - - if (name == "pthread_create") - { - ss << " // Return success\n"; - ss << " ctx->r[2] = 0;\n"; - ss << " // Set thread ID to 1 in the output parameter\n"; - ss << " uint32_t thread_id_ptr = ctx->r[4]; // Thread ID pointer in $a0\n"; - ss << " if (thread_id_ptr < 0x2000000) {\n"; - ss << " *(uint32_t*)(rdram + thread_id_ptr) = 1;\n"; - ss << " }\n"; - } - else if (name.find("pthread_mutex_") != std::string::npos || - name.find("pthread_cond_") != std::string::npos) - { - ss << " // Return success\n"; - ss << " ctx->r[2] = 0;\n"; - } - else - { - ss << " // Return success\n"; - ss << " ctx->r[2] = 0;\n"; - } - - return ss.str(); - } - - std::string PS2Recompiler::generateDefaultStub(const std::string &name) - { - std::stringstream ss; - - ss << " // Default stub implementation\n"; - ss << " #ifdef _DEBUG\n"; - ss << " printf(\"Stub function called: " << name << " at PC=0x%08X\\n\", ctx->pc);\n"; - ss << " #endif\n"; - ss << " // Default return value (0)\n"; - ss << " ctx->r[2] = 0;\n"; - - return ss.str(); - } } \ No newline at end of file