Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *error_string) { Module *module = new Module; kernelObjects.Create(module); memset(&module->nm, 0, sizeof(module->nm)); u8 *newptr = 0; if (*(u32*)ptr == 0x4543537e) { // "~SCE" INFO_LOG(HLE, "~SCE module, skipping header"); ptr += *(u32*)(ptr + 4); } if (*(u32*)ptr == 0x5053507e) { // "~PSP" // Decrypt module! YAY! INFO_LOG(HLE, "Decrypting ~PSP file"); PSP_Header *head = (PSP_Header*)ptr; const u8 *in = ptr; u32 size = head->elf_size; if (head->psp_size > size) { size = head->psp_size; } newptr = new u8[head->elf_size + head->psp_size]; ptr = newptr; int ret = pspDecryptPRX(in, (u8*)ptr, head->psp_size); if (ret == MISSING_KEY) { // This should happen for all "kernel" modules so disabling. // Reporting::ReportMessage("Missing PRX decryption key!"); *error_string = "Missing key"; delete [] newptr; module->isFake = true; strncpy(module->nm.name, head->modname, 28); module->nm.entry_addr = -1; module->nm.gp_value = -1; return module; } else if (ret <= 0) { ERROR_LOG(HLE, "Failed decrypting PRX! That's not normal! ret = %i\n", ret); Reporting::ReportMessage("Failed decrypting the PRX (ret = %i, size = %i, psp_size = %i)!", ret, head->elf_size, head->psp_size); } } if (*(u32*)ptr != 0x464c457f) { ERROR_LOG_REPORT(HLE, "Wrong magic number %08x", *(u32*)ptr); *error_string = "File corrupt"; if (newptr) { delete [] newptr; } kernelObjects.Destroy<Module>(module->GetUID()); return 0; } // Open ELF reader ElfReader reader((void*)ptr); if (!reader.LoadInto(loadAddress)) { ERROR_LOG(HLE, "LoadInto failed"); if (newptr) { delete [] newptr; } kernelObjects.Destroy<Module>(module->GetUID()); return 0; } module->memoryBlockAddr = reader.GetVaddr(); struct libent { u32 exportName; //default 0 u16 bcdVersion; u16 moduleAttributes; u8 exportEntrySize; u8 numVariables; u16 numFunctions; u32 __entrytableAddr; }; struct PspModuleInfo { // 0, 0, 1, 1 ? u16 moduleAttrs; //0x0000 User Mode, 0x1000 Kernel Mode u16 moduleVersion; // 28 bytes of module name, packed with 0's. char name[28]; u32 gp; // ptr to MIPS GOT data (global offset table) u32 libent; // ptr to .lib.ent section u32 libentend; // ptr to end of .lib.ent section u32 libstub; // ptr to .lib.stub section u32 libstubend; // ptr to end of .lib.stub section }; SectionID sceModuleInfoSection = reader.GetSectionByName(".rodata.sceModuleInfo"); PspModuleInfo *modinfo; if (sceModuleInfoSection != -1) modinfo = (PspModuleInfo *)Memory::GetPointer(reader.GetSectionAddr(sceModuleInfoSection)); else modinfo = (PspModuleInfo *)Memory::GetPointer(reader.GetSegmentVaddr(0) + (reader.GetSegmentPaddr(0) & 0x7FFFFFFF) - reader.GetSegmentOffset(0)); module->nm.gp_value = modinfo->gp; strncpy(module->nm.name, modinfo->name, 28); // Check for module blacklist - we don't allow games to load these modules from disc // as we have HLE implementations and the originals won't run in the emu because they // directly access hardware or for other reasons. for (u32 i = 0; i < ARRAY_SIZE(blacklistedModules); i++) { if (strcmp(modinfo->name, blacklistedModules[i]) == 0) { *error_string = "Blacklisted"; if (newptr) { delete [] newptr; } module->isFake = true; module->nm.entry_addr = -1; return module; } } bool hasSymbols = false; bool dontadd = false; SectionID textSection = reader.GetSectionByName(".text"); if (textSection != -1) { u32 textStart = reader.GetSectionAddr(textSection); u32 textSize = reader.GetSectionSize(textSection); if (!host->AttemptLoadSymbolMap()) { hasSymbols = reader.LoadSymbols(); if (!hasSymbols) { symbolMap.ResetSymbolMap(); MIPSAnalyst::ScanForFunctions(textStart, textStart+textSize); } } else { dontadd = true; } } else if (host->AttemptLoadSymbolMap()) { dontadd = true; } INFO_LOG(LOADER,"Module %s: %08x %08x %08x", modinfo->name, modinfo->gp, modinfo->libent,modinfo->libstub); struct PspLibStubEntry { u32 name; u16 version; u16 flags; u16 size; u16 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 nidData; // the address of the function stubs where the function address jumps // should be filled in u32 firstSymAddr; }; int numModules = (modinfo->libstubend - modinfo->libstub)/sizeof(PspLibStubEntry); DEBUG_LOG(LOADER,"Num Modules: %i",numModules); DEBUG_LOG(LOADER,"==================================================="); PspLibStubEntry *entry = (PspLibStubEntry *)Memory::GetPointer(modinfo->libstub); int numSyms=0; for (int m = 0; m < numModules; m++) { const char *modulename; if (Memory::IsValidAddress(entry[m].name)) modulename = (const char*)Memory::GetPointer(entry[m].name); else modulename = "(invalidname)"; if (!Memory::IsValidAddress(entry[m].nidData)) { ERROR_LOG(LOADER, "Crazy niddata address %08x, skipping entire module", entry[m].nidData); continue; } u32 *nidDataPtr = (u32*)Memory::GetPointer(entry[m].nidData); // u32 *stubs = (u32*)Memory::GetPointer(entry[m].firstSymAddr); DEBUG_LOG(LOADER,"Importing Module %s, stubs at %08x",modulename,entry[m].firstSymAddr); for (int i=0; i<entry[m].numFuncs; i++) { u32 addrToWriteSyscall = entry[m].firstSymAddr+i*8; DEBUG_LOG(LOADER,"%s : %08x",GetFuncName(modulename, nidDataPtr[i]), addrToWriteSyscall); //write a syscall here if (Memory::IsValidAddress(addrToWriteSyscall)) WriteSyscall(modulename, nidDataPtr[i], addrToWriteSyscall); if (!dontadd) { char temp[256]; sprintf(temp,"zz_%s", GetFuncName(modulename, nidDataPtr[i])); symbolMap.AddSymbol(temp, addrToWriteSyscall, 8, ST_FUNCTION); } numSyms++; } DEBUG_LOG(LOADER,"-------------------------------------------------------------"); } // Look at the exports, too. struct PspLibEntEntry { u32 name; /* ent's name (module name) address */ u16 version; u16 flags; u8 size; u8 vcount; u16 fcount; u32 resident; }; int numEnts = (modinfo->libentend - modinfo->libent)/sizeof(PspLibEntEntry); PspLibEntEntry *ent = (PspLibEntEntry *)Memory::GetPointer(modinfo->libent); for (int m=0; m<numEnts; m++) { const char *name; if (ent->size == 0) continue; if (ent->name == 0) { // ? name = module->nm.name; } else if (Memory::IsValidAddress(ent->name)) { name = (const char*)Memory::GetPointer(ent->name); } else { name = "invalid?"; // God Eater Burst } INFO_LOG(HLE,"Exporting ent %d named %s, %d funcs, %d vars, resident %08x", m, name, ent->fcount, ent->vcount, ent->resident); // Seen 0x00060005 in God Eater Burst if (Memory::IsValidAddress(ent->resident)) { u32 *residentPtr = (u32*)Memory::GetPointer(ent->resident); for (u32 j = 0; j < ent->fcount; j++) { u32 nid = residentPtr[j]; u32 exportAddr = residentPtr[ent->fcount + ent->vcount + j]; switch (nid) { case NID_MODULE_START: module->nm.module_start_func = exportAddr; break; case NID_MODULE_STOP: module->nm.module_stop_func = exportAddr; break; case NID_MODULE_REBOOT_BEFORE: module->nm.module_reboot_before_func = exportAddr; break; case NID_MODULE_REBOOT_PHASE: module->nm.module_reboot_phase_func = exportAddr; break; case NID_MODULE_BOOTSTART: module->nm.module_bootstart_func = exportAddr; break; default: ResolveSyscall(name, nid, exportAddr); } } for (u32 j = 0; j < ent->vcount; j++) { u32 nid = residentPtr[ent->fcount + j]; u32 exportAddr = residentPtr[ent->fcount + ent->vcount + ent->fcount + j]; switch (nid) { case NID_MODULE_INFO: break; case NID_MODULE_START_THREAD_PARAMETER: if (Memory::Read_U32(exportAddr) != 3) WARN_LOG_REPORT(LOADER, "Strange value at module_start_thread_parameter export: %08x", Memory::Read_U32(exportAddr)); module->nm.module_start_thread_priority = Memory::Read_U32(exportAddr + 4); module->nm.module_start_thread_stacksize = Memory::Read_U32(exportAddr + 8); module->nm.module_start_thread_attr = Memory::Read_U32(exportAddr + 12); break; case NID_MODULE_STOP_THREAD_PARAMETER: if (Memory::Read_U32(exportAddr) != 3) WARN_LOG_REPORT(LOADER, "Strange value at module_stop_thread_parameter export: %08x", Memory::Read_U32(exportAddr)); module->nm.module_stop_thread_priority = Memory::Read_U32(exportAddr + 4); module->nm.module_stop_thread_stacksize = Memory::Read_U32(exportAddr + 8); module->nm.module_stop_thread_attr = Memory::Read_U32(exportAddr + 12); break; case NID_MODULE_REBOOT_BEFORE_THREAD_PARAMETER: if (Memory::Read_U32(exportAddr) != 3) WARN_LOG_REPORT(LOADER, "Strange value at module_reboot_before_thread_parameter export: %08x", Memory::Read_U32(exportAddr)); module->nm.module_reboot_before_thread_priority = Memory::Read_U32(exportAddr + 4); module->nm.module_reboot_before_thread_stacksize = Memory::Read_U32(exportAddr + 8); module->nm.module_reboot_before_thread_attr = Memory::Read_U32(exportAddr + 12); break; case NID_MODULE_SDK_VERSION: DEBUG_LOG(LOADER, "Module SDK: %08x", Memory::Read_U32(exportAddr)); break; default: DEBUG_LOG(LOADER, "Unexpected variable with nid: %08x", nid); break; } } } if (ent->size > 4) { ent = (PspLibEntEntry*)((u8*)ent + ent->size * 4); } else { ent++; } } module->nm.entry_addr = reader.GetEntryPoint(); // use module_start_func instead of entry_addr if entry_addr is 0 if (module->nm.entry_addr == 0) module->nm.entry_addr = module->nm.module_start_func; if (newptr) { delete [] newptr; } return module; }
Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *error_string) { Module *module = new Module; kernelObjects.Create(module); u8 *newptr = 0; if (*(u32*)ptr == 0x5053507e) { // "~PSP" // Decrypt module! YAY! INFO_LOG(HLE, "Decrypting ~PSP file"); PSP_Header *head = (PSP_Header*)ptr; const u8 *in = ptr; u32 size = head->elf_size; if (head->psp_size > size) { size = head->psp_size; } newptr = new u8[head->elf_size + head->psp_size]; ptr = newptr; pspDecryptPRX(in, (u8*)ptr, head->psp_size); } if (*(u32*)ptr == 0x4543537e) { // "~SCE" ERROR_LOG(HLE, "Wrong magic number %08x (~SCE, kernel module?)",*(u32*)ptr); *error_string = "Kernel module?"; if (newptr) { delete [] newptr; } kernelObjects.Destroy<Module>(module->GetUID()); return 0; } if (*(u32*)ptr != 0x464c457f) { ERROR_LOG(HLE, "Wrong magic number %08x",*(u32*)ptr); *error_string = "File corrupt"; if (newptr) { delete [] newptr; } kernelObjects.Destroy<Module>(module->GetUID()); return 0; } // Open ELF reader ElfReader reader((void*)ptr); if (!reader.LoadInto(loadAddress)) { ERROR_LOG(HLE, "LoadInto failed"); if (newptr) { delete [] newptr; } kernelObjects.Destroy<Module>(module->GetUID()); return 0; } struct libent { u32 exportName; //default 0 u16 bcdVersion; u16 moduleAttributes; u8 exportEntrySize; u8 numVariables; u16 numFunctions; u32 __entrytableAddr; }; struct PspModuleInfo { // 0, 0, 1, 1 ? u16 moduleAttrs; //0x0000 User Mode, 0x1000 Kernel Mode u16 moduleVersion; // 28 bytes of module name, packed with 0's. char name[28]; u32 gp; // ptr to MIPS GOT data (global offset table) u32 libent; // ptr to .lib.ent section u32 libentend; // ptr to end of .lib.ent section u32 libstub; // ptr to .lib.stub section u32 libstubend; // ptr to end of .lib.stub section }; SectionID sceModuleInfoSection = reader.GetSectionByName(".rodata.sceModuleInfo"); PspModuleInfo *modinfo; if (sceModuleInfoSection != -1) modinfo = (PspModuleInfo *)Memory::GetPointer(reader.GetSectionAddr(sceModuleInfoSection)); else modinfo = (PspModuleInfo *)Memory::GetPointer(reader.GetVaddr() + (reader.GetSegmentPaddr(0) & 0x7FFFFFFF) - reader.GetSegmentOffset(0)); // Check for module blacklist - we don't allow games to load these modules from disc // as we have HLE implementations and the originals won't run in the emu because they // directly access hardware or for other reasons. for (u32 i = 0; i < ARRAY_SIZE(blacklistedModules); i++) { if (strcmp(modinfo->name, blacklistedModules[i]) == 0) { *error_string = "Blacklisted"; if (newptr) { delete [] newptr; } kernelObjects.Destroy<Module>(module->GetUID()); return 0; } } bool hasSymbols = false; bool dontadd = false; SectionID textSection = reader.GetSectionByName(".text"); if (textSection != -1) { u32 textStart = reader.GetSectionAddr(textSection); u32 textSize = reader.GetSectionSize(textSection); if (!host->AttemptLoadSymbolMap()) { hasSymbols = reader.LoadSymbols(); if (!hasSymbols) { symbolMap.ResetSymbolMap(); MIPSAnalyst::ScanForFunctions(textStart, textStart+textSize); } } else { dontadd = true; } } module->gp_value = modinfo->gp; strncpy(module->name, modinfo->name, 28); INFO_LOG(LOADER,"Module %s: %08x %08x %08x", modinfo->name, modinfo->gp, modinfo->libent,modinfo->libstub); struct PspLibStubEntry { u32 name; u16 version; u16 flags; u16 size; u16 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 nidData; // the address of the function stubs where the function address jumps // should be filled in u32 firstSymAddr; }; int numModules = (modinfo->libstubend - modinfo->libstub)/sizeof(PspLibStubEntry); DEBUG_LOG(LOADER,"Num Modules: %i",numModules); DEBUG_LOG(LOADER,"==================================================="); PspLibStubEntry *entry = (PspLibStubEntry *)Memory::GetPointer(modinfo->libstub); int numSyms=0; for (int m = 0; m < numModules; m++) { const char *modulename = (const char*)Memory::GetPointer(entry[m].name); u32 *nidDataPtr = (u32*)Memory::GetPointer(entry[m].nidData); // u32 *stubs = (u32*)Memory::GetPointer(entry[m].firstSymAddr); DEBUG_LOG(LOADER,"Importing Module %s, stubs at %08x",modulename,entry[m].firstSymAddr); for (int i=0; i<entry[m].numFuncs; i++) { u32 addrToWriteSyscall = entry[m].firstSymAddr+i*8; DEBUG_LOG(LOADER,"%s : %08x",GetFuncName(modulename, nidDataPtr[i]), addrToWriteSyscall); //write a syscall here WriteSyscall(modulename, nidDataPtr[i], addrToWriteSyscall); if (!dontadd) { char temp[256]; sprintf(temp,"zz_%s", GetFuncName(modulename, nidDataPtr[i])); symbolMap.AddSymbol(temp, addrToWriteSyscall, 8, ST_FUNCTION); } numSyms++; } DEBUG_LOG(LOADER,"-------------------------------------------------------------"); } // Look at the exports, too. struct PspLibEntEntry { u32 name; /* ent's name (module name) address */ u16 version; u16 flags; u8 size; u8 vcount; u16 fcount; u32 resident; }; int numEnts = (modinfo->libentend - modinfo->libent)/sizeof(PspLibEntEntry); PspLibEntEntry *ent = (PspLibEntEntry *)Memory::GetPointer(modinfo->libent); for (int m=0; m<numEnts; m++) { const char *name; if (ent->size == 0) { continue; } if (ent->name == 0) { // ? name = module->name; } else { name = (const char*)Memory::GetPointer(ent->name); } INFO_LOG(HLE,"Exporting ent %d named %s, %d funcs, %d vars, resident %08x", m, name, ent->fcount, ent->vcount, ent->resident); u32 *residentPtr = (u32*)Memory::GetPointer(ent->resident); for (u32 j = 0; j < ent->fcount; j++) { u32 nid = residentPtr[j]; u32 exportAddr = residentPtr[ent->fcount + ent->vcount + j]; ResolveSyscall(name, nid, exportAddr); } if (ent->size > 4) { ent = (PspLibEntEntry*)((u8*)ent + ent->size * 4); } else { ent++; } } module->entry_addr = reader.GetEntryPoint(); if (newptr) { delete [] newptr; } return module; }