mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-09-26 08:51:05 -04:00
feat: remove stub from recompiler
This commit is contained in:
@@ -37,29 +37,15 @@ namespace ps2recomp
|
||||
std::vector<Relocation> m_relocations;
|
||||
|
||||
std::unordered_map<uint32_t, std::vector<Instruction>> m_decodedFunctions;
|
||||
std::unordered_map<std::string, bool> m_stubFunctions;
|
||||
std::unordered_map<std::string, bool> m_skipFunctions;
|
||||
std::map<uint32_t, std::string> 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);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -153,7 +153,6 @@ namespace ps2recomp
|
||||
std::string inputPath;
|
||||
std::string outputPath;
|
||||
bool singleFileOutput;
|
||||
std::vector<std::string> stubFunctions;
|
||||
std::vector<std::string> skipFunctions;
|
||||
std::unordered_map<uint32_t, std::string> patches;
|
||||
std::map<std::string, std::string> stubImplementations;
|
||||
|
||||
@@ -26,7 +26,6 @@ namespace ps2recomp
|
||||
config.outputPath = toml::find<std::string>(data, "general", "output");
|
||||
config.singleFileOutput = toml::find<bool>(data, "general", "single_file_output");
|
||||
|
||||
config.stubFunctions = toml::find<std::vector<std::string>>(data, "general", "stubs");
|
||||
config.skipFunctions = toml::find<std::vector<std::string>>(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)
|
||||
{
|
||||
|
||||
@@ -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<R5900Decoder>();
|
||||
m_codeGenerator = std::make_unique<CodeGenerator>(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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user