diff --git a/Source/iop/IopBios.cpp b/Source/iop/IopBios.cpp index 2668275d9f..27bef54e6f 100644 --- a/Source/iop/IopBios.cpp +++ b/Source/iop/IopBios.cpp @@ -338,7 +338,7 @@ void CIopBios::SaveState(Framework::CZipArchiveWriter& archive) { CRegisterState moduleState; { - uint32 importTableAddress = reinterpret_cast(dynamicModule->GetExportTable()) - m_ram; + uint32 importTableAddress = reinterpret_cast(dynamicModule->GetExportTable()) - m_ram; moduleState.SetRegister32(STATE_MODULE_IMPORT_TABLE_ADDRESS, importTableAddress); } modulesFile->InsertRegisterState(dynamicModule->GetId().c_str(), std::move(moduleState)); diff --git a/Source/iop/Iop_Dynamic.cpp b/Source/iop/Iop_Dynamic.cpp index 85485f82c8..db9be81bde 100644 --- a/Source/iop/Iop_Dynamic.cpp +++ b/Source/iop/Iop_Dynamic.cpp @@ -1,24 +1,47 @@ #include #include "Iop_Dynamic.h" +#include "Log.h" + +#define LOG_NAME ("iop_dynamic") using namespace Iop; -CDynamic::CDynamic(uint32* exportTable) +static constexpr uint32 g_exportModuleNameOffset = 3; +static constexpr uint32 g_exportFctTableOffset = 5; + +CDynamic::CDynamic(const uint32* exportTable) : m_exportTable(exportTable) { m_name = GetDynamicModuleName(exportTable); + m_functionCount = GetDynamicModuleExportCount(exportTable); } -std::string CDynamic::GetDynamicModuleName(uint32* exportTable) +std::string CDynamic::GetDynamicModuleName(const uint32* exportTable) { //Name is 8 bytes long without zero, so we need to make sure it's properly null-terminated const unsigned int nameLength = 8; char name[nameLength + 1]; memset(name, 0, nameLength + 1); - memcpy(name, reinterpret_cast(exportTable) + 12, nameLength); + memcpy(name, reinterpret_cast(exportTable + g_exportModuleNameOffset), nameLength); return name; } +uint32 CDynamic::GetDynamicModuleExportCount(const uint32* exportTable) +{ + //Export tables are supposed to finish with a 0 value. + uint32 functionCount = 0; + while(exportTable[g_exportFctTableOffset + functionCount] != 0) + { + functionCount++; + if(functionCount >= 1000) + { + CLog::GetInstance().Warn(LOG_NAME, "Export count exceeded threshold of %d functions. Bailing.\r\n", functionCount); + break; + } + } + return functionCount; +} + std::string CDynamic::GetId() const { return m_name; @@ -33,12 +56,20 @@ std::string CDynamic::GetFunctionName(unsigned int functionId) const void CDynamic::Invoke(CMIPS& context, unsigned int functionId) { - uint32 functionAddress = m_exportTable[5 + functionId]; - context.m_State.nGPR[CMIPS::RA].nD0 = context.m_State.nPC; - context.m_State.nPC = functionAddress; + if(functionId < m_functionCount) + { + uint32 functionAddress = m_exportTable[g_exportFctTableOffset + functionId]; + context.m_State.nGPR[CMIPS::RA].nD0 = context.m_State.nPC; + context.m_State.nPC = functionAddress; + } + else + { + CLog::GetInstance().Warn(LOG_NAME, "Failed to find export %d for module '%s'.\r\n", + functionId, m_name.c_str()); + } } -uint32* CDynamic::GetExportTable() const +const uint32* CDynamic::GetExportTable() const { return m_exportTable; } diff --git a/Source/iop/Iop_Dynamic.h b/Source/iop/Iop_Dynamic.h index 6f78da34b9..2455065545 100644 --- a/Source/iop/Iop_Dynamic.h +++ b/Source/iop/Iop_Dynamic.h @@ -7,20 +7,22 @@ namespace Iop class CDynamic : public CModule { public: - CDynamic(uint32*); + CDynamic(const uint32*); virtual ~CDynamic() = default; - static std::string GetDynamicModuleName(uint32*); + static std::string GetDynamicModuleName(const uint32*); + static uint32 GetDynamicModuleExportCount(const uint32*); std::string GetId() const override; std::string GetFunctionName(unsigned int) const override; void Invoke(CMIPS&, unsigned int) override; - uint32* GetExportTable() const; + const uint32* GetExportTable() const; private: - uint32* m_exportTable; + const uint32* m_exportTable; std::string m_name; + uint32 m_functionCount = 0; }; typedef std::shared_ptr DynamicPtr;