diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index 944098fab7..58a33476dc 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -39,6 +39,7 @@ #include "Core/HLE/ErrorCodes.h" #include "Core/HLE/sceKernelThread.h" #include "Core/HLE/sceKernelInterrupt.h" +#include "Core/HLE/sceKernelModule.h" #include "Core/HLE/HLE.h" enum { @@ -906,7 +907,16 @@ const HLEFunction *GetSyscallFuncPointer(MIPSOpcode op) { int modulenum = (callno & 0xFF000) >> 12; if (funcnum == 0xfff) { std::string_view modName = modulenum >= (int)moduleDB.size() ? "(unknown)" : moduleDB[modulenum].name; - ERROR_LOG(Log::HLE, "Unknown syscall: Module: '%.*s' (module: %d func: %d)", (int)modName.size(), modName.data(), modulenum, funcnum); + // This is what a still-unresolved import looks like once written as a syscall opcode - + // the original module name/NID aren't recoverable from the opcode itself (see + // WriteFuncMissingStub), but the calling address is a stub we may still be tracking. + std::string importModuleName, importingModuleName; + u32 nid = 0; + if (currentMIPS->pc >= 8 && KernelFindImportByStubAddr(currentMIPS->pc - 8, &importModuleName, &nid, &importingModuleName)) { + ERROR_LOG(Log::HLE, "Unknown syscall: unresolved import %s/%08x (%s), called from '%s'", importModuleName.c_str(), nid, GetHLEFuncName(importModuleName, nid), importingModuleName.c_str()); + } else { + ERROR_LOG(Log::HLE, "Unknown syscall: Module: '%.*s' (module: %d func: %d)", (int)modName.size(), modName.data(), modulenum, funcnum); + } return NULL; } if (modulenum >= (int)moduleDB.size()) { diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 77484383df..86d9540ec8 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -766,6 +766,30 @@ void UnexportFuncSymbol(const FuncSymbolExport &func) { } } +// Used to add detail to the "Unknown syscall" log in HLE.cpp's GetSyscallFuncPointer - a call +// through a still-unresolved import ends up as a generic "invalid syscall" opcode that no +// longer carries the original module name/NID, but the (fixed, unique) address of the syscall +// instruction itself does - it's exactly the stubAddr every pending FuncSymbolImport recorded +// when it was written by WriteFuncMissingStub. +bool KernelFindImportByStubAddr(u32 stubAddr, std::string *importModuleName, u32 *nid, std::string *importingModuleName) { + u32 error; + for (SceUID moduleId : loadedModules) { + PSPModule *module = kernelObjects.Get(moduleId, error); + if (!module) { + continue; + } + for (const auto &func : module->importedFuncs) { + if (func.stubAddr == stubAddr) { + *importModuleName = func.moduleName; + *nid = func.nid; + *importingModuleName = module->GetName(); + return true; + } + } + } + return false; +} + void PSPModule::Cleanup() { MIPSAnalyst::ForgetFunctions(textStart, textEnd); diff --git a/Core/HLE/sceKernelModule.h b/Core/HLE/sceKernelModule.h index 13af5ef5ef..39274e0a59 100644 --- a/Core/HLE/sceKernelModule.h +++ b/Core/HLE/sceKernelModule.h @@ -228,6 +228,7 @@ u32 __KernelGetModuleGP(SceUID module); bool KernelModuleIsKernelMode(SceUID module); bool __KernelLoadGEDump(std::string_view base_filename, std::string *error_string); bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_string); +bool KernelFindImportByStubAddr(u32 stubAddr, std::string *importModuleName, u32 *nid, std::string *importingModuleName); int __KernelGPUReplay(); void __KernelReturnFromModuleFunc(); SceUID KernelLoadModule(const std::string &filename, std::string *error_string);