| 1106 | } |
| 1107 | |
| 1108 | void LoadFuncs(u32 a0reg) |
| 1109 | { |
| 1110 | if (!EmuConfig.DebuggerAnalysis.GenerateSymbolsForIRXExports) |
| 1111 | return; |
| 1112 | |
| 1113 | const std::string modname = iopMemReadString(a0reg + 12, 8); |
| 1114 | s32 version_major = iopMemRead8(a0reg + 9); |
| 1115 | s32 version_minor = iopMemRead8(a0reg + 8); |
| 1116 | DevCon.WriteLn(Color_Gray, "RegisterLibraryEntries: %8.8s version %x.%02x", modname.data(), version_major, version_minor); |
| 1117 | |
| 1118 | R3000SymbolGuardian.ReadWrite([&](ccc::SymbolDatabase& database) { |
| 1119 | ccc::Result<ccc::SymbolSourceHandle> source = database.get_symbol_source("IRX Export Table"); |
| 1120 | if (!source.success()) |
| 1121 | return; |
| 1122 | |
| 1123 | // Enumerate the module symbols that already exist for this IRX |
| 1124 | // module. Really there should only be one. |
| 1125 | std::vector<ccc::ModuleHandle> existing_modules; |
| 1126 | for (const auto& pair : database.modules.handles_from_name(modname)) |
| 1127 | { |
| 1128 | const ccc::Module* existing_module = database.modules.symbol_from_handle(pair.second); |
| 1129 | if (!existing_module || !existing_module->is_irx) |
| 1130 | continue; |
| 1131 | |
| 1132 | // Different major versions, we treat this one as a different module. |
| 1133 | if (existing_module->version_major != version_major) |
| 1134 | continue; |
| 1135 | |
| 1136 | // RegisterLibraryEntries will fail if the new minor ver is <= the old minor ver |
| 1137 | // and the major version is the same. |
| 1138 | if (existing_module->version_minor >= version_minor) |
| 1139 | return; |
| 1140 | |
| 1141 | existing_modules.emplace_back(existing_module->handle()); |
| 1142 | } |
| 1143 | |
| 1144 | // Destroy the old symbols for this IRX module if any exist. |
| 1145 | for (ccc::ModuleHandle existing_module : existing_modules) |
| 1146 | database.destroy_symbols_from_module(existing_module, true); |
| 1147 | |
| 1148 | ccc::Result<ccc::Module*> module_symbol = database.modules.create_symbol(modname, *source, nullptr); |
| 1149 | if (!module_symbol.success()) |
| 1150 | return; |
| 1151 | |
| 1152 | (*module_symbol)->is_irx = true; |
| 1153 | (*module_symbol)->version_major = version_major; |
| 1154 | (*module_symbol)->version_minor = version_minor; |
| 1155 | |
| 1156 | u32 func = a0reg + 20; |
| 1157 | u32 funcptr = iopMemRead32(func); |
| 1158 | u32 index = 0; |
| 1159 | while (funcptr != 0) |
| 1160 | { |
| 1161 | const char* unqualified_name = irxImportFuncname(modname, index); |
| 1162 | |
| 1163 | std::string qualified_name; |
| 1164 | if (unqualified_name && unqualified_name[0] != '\0') |
| 1165 | qualified_name = fmt::format("{}[{:02}]::{}", modname, index, unqualified_name); |
no test coverage detected