From 47f16ed97b9dd400e3eb08c62dfc5f82ef08ac44 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 29 May 2016 08:05:42 -0700 Subject: [PATCH] Module: Refactor stub imports to dedicated func. --- Core/HLE/sceKernelModule.cpp | 307 +++++++++++++++++++---------------- 1 file changed, 163 insertions(+), 144 deletions(-) diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 124e28a3d..6ba2f0be3 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -221,7 +221,7 @@ enum NativeModuleStatus { class Module : public KernelObject { public: - Module() : textStart(0), textEnd(0), memoryBlockAddr(0), isFake(false) {} + Module() : textStart(0), textEnd(0), libstub(0), libstubend(0), memoryBlockAddr(0), isFake(false) {} ~Module() { if (memoryBlockAddr) { // If it's either below user memory, or using a high kernel bit, it's in kernel. @@ -374,6 +374,10 @@ public: u32 textStart; u32 textEnd; + // Keep track of the libstub pointers so we can recheck on load state. + u32 libstub; + u32 libstubend; + u32 memoryBlockAddr; u32 memoryBlockSize; bool isFake; @@ -844,6 +848,160 @@ static bool IsHLEVersionedModule(const char *name) { return false; } +static bool KernelImportModuleFuncs(Module *module, u32 *firstImportStubAddr) { + struct PspLibStubEntry { + u32_le name; + u16_le version; + u16_le flags; + u8 size; + u8 numVars; + u16_le numFuncs; + // each symbol has an associated nid; nidData is a pointer + // (in .rodata.sceNid section) to an array of longs, one + // for each function, which identifies the function whose + // address is to be inserted. + // + // The hash is the first 4 bytes of a SHA-1 hash of the function + // name. (Represented as a little-endian long, so the order + // of the bytes is reversed.) + u32_le nidData; + // the address of the function stubs where the function address jumps + // should be filled in + u32_le firstSymAddr; + // Optional, this is where var relocations are. + // They use the format: u32 addr, u32 nid, ... + // WARNING: May have garbage if size < 6. + u32_le varData; + // Not sure what this is yet, assume garbage for now. + // TODO: Tales of the World: Radiant Mythology 2 has something here? + u32_le extra; + }; + + // Can't run - we didn't keep track of the libstub entry. + if (module->libstub == 0) { + return false; + } + if (!Memory::IsValidRange(module->libstub, module->libstubend - module->libstub)) { + ERROR_LOG_REPORT(LOADER, "Garbage libstub address or end"); + return false; + } + + u32_le *entryPos = (u32_le *)Memory::GetPointerUnchecked(module->libstub); + u32_le *entryEnd = (u32_le *)Memory::GetPointerUnchecked(module->libstubend); + + bool needReport = false; + while (entryPos < entryEnd) { + PspLibStubEntry *entry = (PspLibStubEntry *)entryPos; + entryPos += entry->size; + + const char *modulename; + if (Memory::IsValidAddress(entry->name)) { + modulename = Memory::GetCharPointer(entry->name); + } else { + modulename = "(invalidname)"; + needReport = true; + } + + DEBUG_LOG(LOADER, "Importing Module %s, stubs at %08x", modulename, entry->firstSymAddr); + if (entry->size != 5 && entry->size != 6) { + if (entry->size != 7) { + WARN_LOG_REPORT(LOADER, "Unexpected module entry size %d", entry->size); + needReport = true; + } else if (entry->extra != 0) { + WARN_LOG_REPORT(LOADER, "Unexpected module entry with non-zero 7th value %08x", entry->extra); + needReport = true; + } + } + + // If nidData is 0, only variables are being imported. + if (entry->nidData != 0) { + if (!Memory::IsValidAddress(entry->nidData)) { + ERROR_LOG_REPORT(LOADER, "Crazy nidData address %08x, skipping entire module", entry->nidData); + needReport = true; + continue; + } + + FuncSymbolImport func; + strncpy(func.moduleName, modulename, KERNELOBJECT_MAX_NAME_LENGTH); + func.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0'; + + u32_le *nidDataPtr = (u32_le *)Memory::GetPointer(entry->nidData); + for (int i = 0; i < entry->numFuncs; ++i) { + // This is the id of the import. + func.nid = nidDataPtr[i]; + // This is the address to write the j and delay slot to. + func.stubAddr = entry->firstSymAddr + i * 8; + module->ImportFunc(func); + } + + if (firstImportStubAddr && (!*firstImportStubAddr || *firstImportStubAddr > (u32)entry->firstSymAddr)) + *firstImportStubAddr = entry->firstSymAddr; + } else if (entry->numFuncs > 0) { + WARN_LOG_REPORT(LOADER, "Module entry with %d imports but no valid address", entry->numFuncs); + needReport = true; + } + + if (entry->varData != 0) { + if (!Memory::IsValidAddress(entry->varData)) { + ERROR_LOG_REPORT(LOADER, "Crazy varData address %08x, skipping rest of module", entry->varData); + needReport = true; + continue; + } + + VarSymbolImport var; + strncpy(var.moduleName, modulename, KERNELOBJECT_MAX_NAME_LENGTH); + var.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0'; + + for (int i = 0; i < entry->numVars; ++i) { + u32 varRefsPtr = Memory::Read_U32(entry->varData + i * 8); + u32 nid = Memory::Read_U32(entry->varData + i * 8 + 4); + if (!Memory::IsValidAddress(varRefsPtr)) { + WARN_LOG_REPORT(LOADER, "Bad relocation list address for nid %08x in %s", nid, modulename); + continue; + } + + u32_le *varRef = (u32_le *)Memory::GetPointer(varRefsPtr); + for (; *varRef != 0; ++varRef) { + var.nid = nid; + var.stubAddr = (*varRef & 0x03FFFFFF) << 2; + var.type = *varRef >> 26; + module->ImportVar(var); + } + } + } else if (entry->numVars > 0) { + WARN_LOG_REPORT(LOADER, "Module entry with %d var imports but no valid address", entry->numVars); + needReport = true; + } + + DEBUG_LOG(LOADER, "-------------------------------------------------------------"); + } + + if (needReport) { + std::string debugInfo; + entryPos = (u32_le *)Memory::GetPointer(module->libstub); + while (entryPos < entryEnd) { + PspLibStubEntry *entry = (PspLibStubEntry *)entryPos; + entryPos += entry->size; + + char temp[512]; + const char *modulename; + if (Memory::IsValidAddress(entry->name)) { + modulename = Memory::GetCharPointer(entry->name); + } else { + modulename = "(invalidname)"; + } + + snprintf(temp, sizeof(temp), "%s ver=%04x, flags=%04x, size=%d, numVars=%d, numFuncs=%d, nidData=%08x, firstSym=%08x, varData=%08x, extra=%08x\n", + modulename, entry->version, entry->flags, entry->size, entry->numVars, entry->numFuncs, entry->nidData, entry->firstSymAddr, entry->size >= 6 ? entry->varData : 0, entry->size >= 7 ? entry->extra : 0); + debugInfo += temp; + } + + Reporting::ReportMessage("Module linking debug info:\n%s", debugInfo.c_str()); + } + + return true; +} + static Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, bool fromTop, std::string *error_string, u32 *magic, u32 &error) { Module *module = new Module; kernelObjects.Create(module); @@ -1038,153 +1196,14 @@ static Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, bool fromT module->nm.bss_size = reader.GetTotalSectionSizeByPrefix(".bss"); module->nm.data_size = reader.GetTotalDataSize() - module->nm.bss_size; + module->libstub = modinfo->libstub; + module->libstubend = modinfo->libstubend; INFO_LOG(LOADER, "Module %s: %08x %08x %08x", modinfo->name, modinfo->gp, modinfo->libent, modinfo->libstub); - - struct PspLibStubEntry { - u32_le name; - u16_le version; - u16_le flags; - u8 size; - u8 numVars; - u16_le numFuncs; - // each symbol has an associated nid; nidData is a pointer - // (in .rodata.sceNid section) to an array of longs, one - // for each function, which identifies the function whose - // address is to be inserted. - // - // The hash is the first 4 bytes of a SHA-1 hash of the function - // name. (Represented as a little-endian long, so the order - // of the bytes is reversed.) - u32_le nidData; - // the address of the function stubs where the function address jumps - // should be filled in - u32_le firstSymAddr; - // Optional, this is where var relocations are. - // They use the format: u32 addr, u32 nid, ... - // WARNING: May have garbage if size < 6. - u32_le varData; - // Not sure what this is yet, assume garbage for now. - // TODO: Tales of the World: Radiant Mythology 2 has something here? - u32_le extra; - }; - DEBUG_LOG(LOADER,"==================================================="); - u32_le *entryPos = (u32_le *)Memory::GetPointer(modinfo->libstub); - u32_le *entryEnd = (u32_le *)Memory::GetPointer(modinfo->libstubend); - - u32_le firstImportStubAddr = 0; - - bool needReport = false; - while (entryPos < entryEnd) { - PspLibStubEntry *entry = (PspLibStubEntry *)entryPos; - entryPos += entry->size; - - const char *modulename; - if (Memory::IsValidAddress(entry->name)) { - modulename = Memory::GetCharPointer(entry->name); - } else { - modulename = "(invalidname)"; - needReport = true; - } - - DEBUG_LOG(LOADER, "Importing Module %s, stubs at %08x", modulename, entry->firstSymAddr); - if (entry->size != 5 && entry->size != 6) { - if (entry->size != 7) { - WARN_LOG_REPORT(LOADER, "Unexpected module entry size %d", entry->size); - needReport = true; - } else if (entry->extra != 0) { - WARN_LOG_REPORT(LOADER, "Unexpected module entry with non-zero 7th value %08x", entry->extra); - needReport = true; - } - } - - // If nidData is 0, only variables are being imported. - if (entry->nidData != 0) { - if (!Memory::IsValidAddress(entry->nidData)) { - ERROR_LOG_REPORT(LOADER, "Crazy nidData address %08x, skipping entire module", entry->nidData); - needReport = true; - continue; - } - - FuncSymbolImport func; - strncpy(func.moduleName, modulename, KERNELOBJECT_MAX_NAME_LENGTH); - func.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0'; - - u32_le *nidDataPtr = (u32_le *)Memory::GetPointer(entry->nidData); - for (int i = 0; i < entry->numFuncs; ++i) { - // This is the id of the import. - func.nid = nidDataPtr[i]; - // This is the address to write the j and delay slot to. - func.stubAddr = entry->firstSymAddr + i * 8; - module->ImportFunc(func); - } - - if (!firstImportStubAddr || firstImportStubAddr > entry->firstSymAddr) - firstImportStubAddr = entry->firstSymAddr; - } else if (entry->numFuncs > 0) { - WARN_LOG_REPORT(LOADER, "Module entry with %d imports but no valid address", entry->numFuncs); - needReport = true; - } - - if (entry->varData != 0) { - if (!Memory::IsValidAddress(entry->varData)) { - ERROR_LOG_REPORT(LOADER, "Crazy varData address %08x, skipping rest of module", entry->varData); - needReport = true; - continue; - } - - VarSymbolImport var; - strncpy(var.moduleName, modulename, KERNELOBJECT_MAX_NAME_LENGTH); - var.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0'; - - for (int i = 0; i < entry->numVars; ++i) { - u32 varRefsPtr = Memory::Read_U32(entry->varData + i * 8); - u32 nid = Memory::Read_U32(entry->varData + i * 8 + 4); - if (!Memory::IsValidAddress(varRefsPtr)) { - WARN_LOG_REPORT(LOADER, "Bad relocation list address for nid %08x in %s", nid, modulename); - continue; - } - - u32_le *varRef = (u32_le *)Memory::GetPointer(varRefsPtr); - for (; *varRef != 0; ++varRef) { - var.nid = nid; - var.stubAddr = (*varRef & 0x03FFFFFF) << 2; - var.type = *varRef >> 26; - module->ImportVar(var); - } - } - } else if (entry->numVars > 0) { - WARN_LOG_REPORT(LOADER, "Module entry with %d var imports but no valid address", entry->numVars); - needReport = true; - } - - DEBUG_LOG(LOADER, "-------------------------------------------------------------"); - } - - if (needReport) { - std::string debugInfo; - entryPos = (u32_le *)Memory::GetPointer(modinfo->libstub); - while (entryPos < entryEnd) { - PspLibStubEntry *entry = (PspLibStubEntry *)entryPos; - entryPos += entry->size; - - char temp[512]; - const char *modulename; - if (Memory::IsValidAddress(entry->name)) { - modulename = Memory::GetCharPointer(entry->name); - } else { - modulename = "(invalidname)"; - } - - snprintf(temp, sizeof(temp), "%s ver=%04x, flags=%04x, size=%d, numVars=%d, numFuncs=%d, nidData=%08x, firstSym=%08x, varData=%08x, extra=%08x\n", - modulename, entry->version, entry->flags, entry->size, entry->numVars, entry->numFuncs, entry->nidData, entry->firstSymAddr, entry->size >= 6 ? entry->varData : 0, entry->size >= 7 ? entry->extra : 0); - debugInfo += temp; - } - - Reporting::ReportMessage("Module linking debug info:\n%s", debugInfo.c_str()); - } + u32 firstImportStubAddr = 0; + KernelImportModuleFuncs(module, &firstImportStubAddr); if (textSection == -1) { module->textStart = reader.GetVaddr();