int KFuncTable::InterceptWin32(void) { int no = 0; // DebugBreak(); for (int i=0; i<m_funcno; i++) if ( (m_func[i].f_kind==FUNC_WIN32API) & !m_func[i].f_hooked ) // if there is an unhooked win32 function { int module = m_func[i].f_module; // if caller and callee are the same module, patch function target if ( strcmp(CallerName(module), CalleeName(module))==0 ) { if ( directpatcher.Patch(ModHandle(module), GetFuncName(i), i, ProxyProlog, (unsigned long *) & m_func[i].f_oldaddress) ) no ++; } else { const char *caller = CallerName(module); const char *address = (const char *) ModHandle(module); // if caller module is loaded into current process, hack in it. if (address) no += InterceptWin32(caller, address); } } return no; }
void AbstractExpression::DeduceExpressionName() { // If alias exists, it will be used in TrafficCop if (!alias.empty()) return; for (auto &child : children_) child->DeduceExpressionName(); // Aggregate expression already has correct expr_name_ if (ExpressionUtil::IsAggregateExpression(exp_type_)) return; auto op_str = ExpressionTypeToString(exp_type_, true); auto children_size = children_.size(); if (exp_type_ == ExpressionType::FUNCTION) { auto expr = (FunctionExpression *)this; expr_name_ = expr->GetFuncName() + "("; for (size_t i = 0; i < children_size; i++) { if (i > 0) expr_name_.append(","); expr_name_.append(GetChild(i)->expr_name_); } expr_name_.append(")"); } else { PL_ASSERT(children_size <= 2); if (children_size == 2) { expr_name_ = GetChild(0)->expr_name_ + " " + op_str + " " + GetChild(1)->expr_name_; } else if (children_size == 1) { expr_name_ = op_str + " " + GetChild(0)->expr_name_; } } }
FARPROC KFuncTable::GetProcAddr(int funcid) { int mod = m_func[funcid].f_module; switch ( m_func[funcid].f_kind ) { case FUNC_COMMETHOD: { const unsigned * pFunc = (const unsigned *) VTable(mod); assert(pFunc); return (FARPROC) pFunc[m_func[funcid].f_methodid]; } break; case FUNC_WIN32API: { HINSTANCE hModule = ModHandle(m_func[funcid].f_module); assert(hModule); FARPROC fp = GetProcAddress(hModule, GetFuncName(funcid)); // assert(fp); if ( fp==NULL ) { char temp[128]; wsprintf(temp, "Not found module %d at %x, func %s at %x", m_func[funcid].f_module, hModule, GetFuncName(funcid), fp); Send(M_TEXT, 0, 0, temp); } return fp; } case FUNC_SYSCALL: return m_func[funcid].f_oldaddress; default: assert(false); } return NULL; }
void CParmChCompareDlg::OnFunc() { UpdateData(); m_Func = GetFuncName(m_FuncIdx); m_pRun->SetValues(this); SetCompStr(); UpdateData(FALSE); }
void CParmChCompareDlg::InitFuncButtons() { m_FuncIdx = -1; for (int i=0; i<CRunChCompare::FUNC_NUM; i++) { CFunc func = GetFuncName(i); m_FuncButton[i].SetWindowText(func); if (m_Func == func) m_FuncIdx = i; } m_FuncButton[CRunChCompare::FUNC_COMP_CASE].EnableWindow(m_Func.SrcType() == pp16u); }
void ParseScript() { char str[512]; while(!feof(infile)) { memset(str,'\0',512); fgets(str,512,infile); switch(GetType(str)) { case 1: { int opcode = GetID(str); if(opcode!=-1) { Push(&bytestack,opcode,1); PushArgs(&bytestack,str,opcode,4); } } break; case 2: { char *name = GetFuncName(str); int opcode = GetOpcode(name); Push(&bytestack,opcode,1); PushArgs(&bytestack,str,opcode,strlen(name)); free(name); } break; case 3: { int id = GetID(str); if(id!=-1) { PushInt(&labelstack,bytestack.size,id); scrhead.labels.size++; } else { printf("Problem parsing label: %s",str); exit(1); } } break; case 4: { int id = GetID(str); if(id!=-1) { //Push(&markerstack,id,4); markerstack[id] = bytestack.size; scrhead.markers.size = 100; } else { printf("Problem parsing marker: %s",str); exit(1); } } break; case 5: { FILE *textfile = NULL; while(str[strlen(str)-1]=='\r' || str[strlen(str)-1]=='\n') str[strlen(str)-1] = '\0'; textfile = fopen(str+9,"rb"); if(!textfile) { printf("Could not open %s\n",str+9); exit(1); } ParseText(textfile); fclose(textfile); } break; case 6: { int t = 0; sscanf(str+1,"%x",&t); if(scrhead.unk12.size==0) unk12stack = (int*)calloc(1,sizeof(int)); else unk12stack = (int*)realloc(unk12stack,(scrhead.unk12.size+1)*sizeof(int)); unk12stack[scrhead.unk12.size++] = t; } break; case 7: { int t = 0; sscanf(str+1,"%x",&t); if(scrhead.unk13.size==0) unk13stack = (int*)calloc(1,sizeof(int)); else unk13stack = (int*)realloc(unk13stack,(scrhead.unk13.size+1)*sizeof(int)); unk13stack[scrhead.unk13.size++] = t; } break; default: break; } } }
//写文件 VOID WriteScriptFile() { CHAR buf[256]; tsnprintf(buf,256,__FILE__); CHAR* pStr = strrchr(buf,'\\'); strcpy(pStr+1,"ScriptFuncForDesigner.h"); FILE* fpScriptFile = fopen(buf,"w"); CHAR** pScanFile = pLuaFnTblFile; while(*pScanFile) { CHAR buf[_MAX_PATH]; tsnprintf(buf,256,__FILE__); CHAR* pStr = strrchr(buf,'\\'); strcpy(pStr+1,*pScanFile); FILE* fp = fopen(buf,"r"); if( fp != NULL && fpScriptFile != NULL) { //写文件头 fprintf(fpScriptFile,"%s\t%s\n","脚本系统C导出函数文档",*pScanFile); CHAR line[_MAX_PATH * 4]; CHAR *pStr1,*pStr2;//,*pStr3,*pStr4; INT linenum = 0; BOOL commentBegin = FALSE; BOOL beginNamaSpace = FALSE; BOOL bDelim = FALSE; while( fgets( line, sizeof( line), fp)) { if(strstr(line,"namespace")) beginNamaSpace = TRUE; if(!beginNamaSpace) continue; if(strstr(line,"endnamespace")) break; if(strstr(line,"/**")) { commentBegin = TRUE; } if(strstr(line,"*/")) { fprintf(fpScriptFile,"%s",line); commentBegin = FALSE; } if(commentBegin) { fprintf(fpScriptFile,"%s",line); continue; } if( (pStr1 = strstr(line,"INT")) && (pStr2 = strstr(line,"Lua_State")) && (pStr2 > pStr1))//简化 { Assert((pStr2 - pStr1) <= NAMELEN); const CHAR* temp = GetFuncName(pStr1,pStr2); for(int i=0;i<numReg;i++) { if(!strcmp(regInfo[i].funcname,temp)) { for(int j=0;j<regInfo[i].regCount;j++) fprintf(fpScriptFile,"\t该函数注册为 %s\n",regInfo[i].regname[j]); } } //剔出Lua_State描述 /*char* pDelim = strchr(line,','); if(pDelim){ char szLine[_MAX_PATH]; memset(szLine,0,_MAX_PATH); strncpy(szLine,line,pStr2-line); strcat(szLine,++pDelim); fprintf(fpScriptFile,"%s\n\n",szLine); } else{*/ //fprintf(fpScriptFile,"%s\n\n",line); //} char* pDelim = strchr(line,'{'); if(pDelim == NULL){ bDelim = TRUE; //fprintf(fpScriptFile,"%s",line); } else{ fprintf(fpScriptFile,"%s\n\n",line); } } if(strchr(line,'{') && bDelim == TRUE) { fprintf(fpScriptFile,"\n\n"); bDelim = FALSE; } if(bDelim) { fprintf(fpScriptFile,"%s",line); } } fclose(fp); } pScanFile++;//读下一个文件 } if(fpScriptFile) { //写文件尾 fprintf(fpScriptFile,"文档生成日期:%d年%d月%d日%d时",g_pTimeManager->GetYear(),g_pTimeManager->GetMonth(),g_pTimeManager->GetDay(),g_pTimeManager->GetHour()); fclose(fpScriptFile); } }
//读Lua函数表文件 VOID ReadLuaFnTblFiles() { CHAR** pScanFile = pLuaFnTblFile; //扫描文件 while(*pScanFile) { CHAR buf[256]; tsnprintf(buf,256,__FILE__); CHAR* pStr = strrchr(buf,'\\'); strcpy(pStr+1,*pScanFile); FILE* fp = fopen(buf,"r"); if( fp != NULL) { CHAR line[_MAX_PATH * 4]; CHAR *pStr1,*pStr2,*pStr3,*pStr4; INT linenum = 0; BOOL commentBegin = FALSE; BOOL beginNamaSpace = FALSE; while( fgets( line, sizeof( line), fp)) { if(strstr(line,"namespace")) beginNamaSpace = TRUE; if(!beginNamaSpace) continue; if(strstr(line,"endnamespace")) break; //找到函数声明 if( (pStr1 = strstr(line,"INT")) && (pStr2 = strstr(line,"Lua_State")) && (pStr2 > pStr1))//简化 { Assert((pStr2 - pStr1) <= NAMELEN); if((pStr2 - pStr1) <= NAMELEN) { const CHAR* temp = GetFuncName(pStr1,pStr2); Q_strncpyz(funcname[numFunc++],temp,NAMELEN); } } //找到已注册函数,没有考虑空格 if((pStr1 = strstr(line,"FuncProto"))) { pStr2 = strstr(line,")"); pStr1 = pStr1 + strlen("FuncProto") + 1; pStr3 = strchr(line,'"'); pStr4 = strchr(pStr3+1,'"'); char szFuncName[NAMELEN]; char szRegName[NAMELEN]; Q_strncpyz(szFuncName,pStr1,pStr2 - pStr1 + 1);//加一 Q_strncpyz(szRegName,pStr3 + 1,pStr4 - pStr3); BOOL toggle = FALSE; INT i; for(i =0;i<numReg;i++) { if(!strcmp(regInfo[i].funcname,szFuncName)) { toggle = TRUE; break; } } if(!toggle) {//第一次注册该函数 Q_strncpyz(regInfo[numReg++].funcname,szFuncName,NAMELEN); Q_strncpyz(regInfo[numReg - 1].regname[regInfo[numReg -1].regCount++],szRegName,NAMELEN); } else { Q_strncpyz(regInfo[i].regname[regInfo[i].regCount++],szRegName,NAMELEN); } } } fclose(fp); } pScanFile++;//扫描下一个文件 } }
{ u32 off = disPC; int imm = (signed short)(op&0xFFFF)<<2; int rs = _RS; off += imm + 4; const char *name = MIPSGetName(op); sprintf(out, "%s\t%s, ->$%08x",name,RN(rs),off); } void Dis_Syscall(MIPSOpcode op, char *out) { u32 callno = (op>>6) & 0xFFFFF; //20 bits int funcnum = callno & 0xFFF; int modulenum = (callno & 0xFF000) >> 12; sprintf(out, "syscall\t %s",/*PSPHLE::GetModuleName(modulenum),*/GetFuncName(modulenum, funcnum)); } void Dis_ToHiloTransfer(MIPSOpcode op, char *out) { int rs = _RS; const char *name = MIPSGetName(op); sprintf(out, "%s\t%s",name,RN(rs)); } void Dis_FromHiloTransfer(MIPSOpcode op, char *out) { int rd = _RD; const char *name = MIPSGetName(op); sprintf(out, "%s\t%s",name,RN(rd)); }
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; }