mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-07-10 01:24:41 -06:00
Merge branch 'cemu-project:main' into main
This commit is contained in:
commit
11903d09c2
2
dependencies/vcpkg
vendored
2
dependencies/vcpkg
vendored
@ -1 +1 @@
|
||||
Subproject commit c3867e714dd3a51c272826eea77267876517ed99
|
||||
Subproject commit 9849e070ad4c3383890fb1c80ae0c54325e2484a
|
||||
@ -165,7 +165,7 @@ void LoadMainExecutable()
|
||||
else
|
||||
{
|
||||
// RPX
|
||||
RPLLoader_AddDependency(_pathToExecutable.c_str());
|
||||
RPLLoader_AddDependency(_pathToExecutable.c_str(), true);
|
||||
applicationRPX = RPLLoader_LoadFromMemory(rpxData, rpxSize, (char*)_pathToExecutable.c_str());
|
||||
if (!applicationRPX)
|
||||
{
|
||||
|
||||
@ -420,7 +420,7 @@ void PatchEntryInstruction::undoPatch()
|
||||
uint8* patchAddr = (uint8*)memory_base + addr;
|
||||
memcpy(patchAddr, m_dataBackup, m_length);
|
||||
PPCRecompiler_invalidateRange(addr, addr + m_length);
|
||||
rplSymbolStorage_removeRange(addr, m_length);
|
||||
rplSymbolStorage_removeRange(addr, m_length, RPL_STORED_SYMBOL_PATCH);
|
||||
DebugSymbolStorage::ClearRange(addr, m_length);
|
||||
}
|
||||
|
||||
@ -434,7 +434,7 @@ bool registerU32Variable(PatchContext_t& ctx, std::string& name, uint32 value, P
|
||||
}
|
||||
ctx.map_values[name] = value;
|
||||
// keep track of address symbols for the debugger
|
||||
rplSymbolStorage_store(ctx.graphicPack->GetName().data(), name.data(), value);
|
||||
rplSymbolStorage_store(ctx.graphicPack->GetName().data(), name.data(), value, RPL_STORED_SYMBOL_PATCH);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -688,7 +688,7 @@ void GraphicPack2::UndoPatchGroups(std::vector<PatchGroup*>& groups, const RPLMo
|
||||
|
||||
void GraphicPack2::NotifyModuleLoaded(const RPLModule* rpl)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Loaded module \'{}\' with checksum 0x{:08x}", rpl->moduleName2, rpl->patchCRC);
|
||||
cemuLog_log(LogType::Force, "Loaded module \'{}\' with checksum 0x{:08x}", rpl->moduleName, rpl->patchCRC);
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx_patches);
|
||||
list_modules.emplace_back(rpl);
|
||||
|
||||
@ -756,7 +756,7 @@ void debugger_addParserSymbols(class ExpressionParser& ep)
|
||||
if (module)
|
||||
{
|
||||
moduleTmp[i] = (double)module->regionMappingBase_text.GetMPTR();
|
||||
ep.AddConstant(module->moduleName2, moduleTmp[i]);
|
||||
ep.AddConstant(module->moduleName, moduleTmp[i]);
|
||||
}
|
||||
}
|
||||
PPCInterpreter_t* hCPU = debugger_lockDebugSession();
|
||||
|
||||
@ -556,7 +556,7 @@ void GDBServer::HandleQuery(std::unique_ptr<CommandContext>& context) const
|
||||
const auto module_list = RPLLoader_GetModuleList();
|
||||
for (sint32 i = 0; i < module_count; i++)
|
||||
{
|
||||
library_list += fmt::format(R"(<library name="{}"><segment address="{:#x}"/></library>)", CommandContext::EscapeXMLString(module_list[i]->moduleName2), module_list[i]->regionMappingBase_text.GetMPTR());
|
||||
library_list += fmt::format(R"(<library name="{}"><segment address="{:#x}"/></library>)", CommandContext::EscapeXMLString(module_list[i]->moduleName), module_list[i]->regionMappingBase_text.GetMPTR());
|
||||
}
|
||||
library_list += "</library-list>";
|
||||
|
||||
|
||||
@ -21,6 +21,8 @@ void LatteTextureReadback_StartTransfer(LatteTextureView* textureView)
|
||||
HRTick currentTick = HighResolutionTimer().now().getTick();
|
||||
// create info entry and store in ordered linked list
|
||||
LatteTextureReadbackInfo* readbackInfo = g_renderer->texture_createReadback(textureView);
|
||||
if (!readbackInfo)
|
||||
return;
|
||||
sTextureActiveReadbackQueue.push(readbackInfo);
|
||||
readbackInfo->StartTransfer();
|
||||
readbackInfo->transferStartTime = currentTick;
|
||||
|
||||
@ -243,7 +243,7 @@ namespace LatteDecompiler
|
||||
cemu_assert_debug(decompilerContext->output->resourceMappingVK.attributeMapping[i] >= 0);
|
||||
cemu_assert_debug(decompilerContext->output->resourceMappingGL.attributeMapping[i] == decompilerContext->output->resourceMappingVK.attributeMapping[i]);
|
||||
|
||||
shaderSrc->addFmt("ATTR_LAYOUT({}, {}) in uvec4 attrDataSem{};" _CRLF, (sint32)decompilerContext->output->resourceMappingVK.setIndex, (sint32)decompilerContext->output->resourceMappingVK.attributeMapping[i], i);
|
||||
shaderSrc->addFmt("ATTR_LAYOUT({}) in uvec4 attrDataSem{};" _CRLF, (sint32)decompilerContext->output->resourceMappingVK.attributeMapping[i], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -255,7 +255,7 @@ namespace LatteDecompiler
|
||||
// OpenGL/Vulkan ifdefs
|
||||
src->add("#ifdef VULKAN" _CRLF);
|
||||
// Vulkan defines
|
||||
src->add("#define ATTR_LAYOUT(__vkSet, __location) layout(set = __vkSet, location = __location)" _CRLF);
|
||||
src->add("#define ATTR_LAYOUT(__location) layout(location = __location)" _CRLF);
|
||||
src->add("#define UNIFORM_BUFFER_LAYOUT(__glLocation, __vkSet, __vkLocation) layout(set = __vkSet, binding = __vkLocation, std140)" _CRLF);
|
||||
src->add("#define TEXTURE_LAYOUT(__glLocation, __vkSet, __vkLocation) layout(set = __vkSet, binding = __vkLocation)" _CRLF);
|
||||
if (decompilerContext->shaderType == LatteConst::ShaderType::Vertex || decompilerContext->shaderType == LatteConst::ShaderType::Geometry)
|
||||
@ -293,7 +293,7 @@ namespace LatteDecompiler
|
||||
}
|
||||
src->add("#else" _CRLF);
|
||||
// OpenGL defines
|
||||
src->add("#define ATTR_LAYOUT(__vkSet, __location) layout(location = __location)" _CRLF);
|
||||
src->add("#define ATTR_LAYOUT(__location) layout(location = __location)" _CRLF);
|
||||
src->add("#define UNIFORM_BUFFER_LAYOUT(__glLocation, __vkSet, __vkLocation) layout(binding = __glLocation, std140) " _CRLF);
|
||||
src->add("#define TEXTURE_LAYOUT(__glLocation, __vkSet, __vkLocation) layout(binding = __glLocation)" _CRLF);
|
||||
if (decompilerContext->shaderType == LatteConst::ShaderType::Vertex || decompilerContext->shaderType == LatteConst::ShaderType::Geometry)
|
||||
|
||||
@ -192,11 +192,6 @@ VKFUNC_DEVICE(vkCmdEndRenderingKHR);
|
||||
// khr_present_wait
|
||||
VKFUNC_DEVICE(vkWaitForPresentKHR);
|
||||
|
||||
// transform feedback extension
|
||||
VKFUNC_DEVICE(vkCmdBindTransformFeedbackBuffersEXT);
|
||||
VKFUNC_DEVICE(vkCmdBeginTransformFeedbackEXT);
|
||||
VKFUNC_DEVICE(vkCmdEndTransformFeedbackEXT);
|
||||
|
||||
// query
|
||||
VKFUNC_DEVICE(vkCreateQueryPool);
|
||||
VKFUNC_DEVICE(vkDestroyQueryPool);
|
||||
|
||||
@ -646,10 +646,7 @@ VulkanRenderer::VulkanRenderer()
|
||||
deviceFeatures.robustBufferAccess = VK_TRUE;
|
||||
}
|
||||
|
||||
if (m_featureControl.mode.useTFEmulationViaSSBO)
|
||||
{
|
||||
deviceFeatures.vertexPipelineStoresAndAtomics = true;
|
||||
}
|
||||
deviceFeatures.vertexPipelineStoresAndAtomics = true;
|
||||
|
||||
void* deviceExtensionFeatures = nullptr;
|
||||
|
||||
@ -787,7 +784,8 @@ VulkanRenderer::VulkanRenderer()
|
||||
m_textureReadbackBufferPtr = (uint8*)bufferPtr;
|
||||
|
||||
// transform feedback ringbuffer
|
||||
memoryManager->CreateBuffer(LatteStreamout_GetRingBufferSize(), VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | (m_featureControl.mode.useTFEmulationViaSSBO ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : 0), 0, m_xfbRingBuffer, m_xfbRingBufferMemory);
|
||||
VkBufferUsageFlags xfbRingBufferUsage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||
memoryManager->CreateBuffer(LatteStreamout_GetRingBufferSize(), xfbRingBufferUsage, 0, m_xfbRingBuffer, m_xfbRingBufferMemory);
|
||||
|
||||
// occlusion query result buffer
|
||||
if (!memoryManager->CreateBuffer(OCCLUSION_QUERY_POOL_SIZE * sizeof(uint64), VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, m_occlusionQueries.bufferQueryResults, m_occlusionQueries.memoryQueryResults))
|
||||
@ -1367,7 +1365,6 @@ bool VulkanRenderer::CheckDeviceExtensionSupport(const VkPhysicalDevice device,
|
||||
}
|
||||
|
||||
info.deviceExtensions.tooling_info = isExtensionAvailable(VK_EXT_TOOLING_INFO_EXTENSION_NAME);
|
||||
info.deviceExtensions.transform_feedback = isExtensionAvailable(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
|
||||
info.deviceExtensions.depth_range_unrestricted = isExtensionAvailable(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME);
|
||||
info.deviceExtensions.nv_fill_rectangle = isExtensionAvailable(VK_NV_FILL_RECTANGLE_EXTENSION_NAME);
|
||||
info.deviceExtensions.pipeline_feedback = isExtensionAvailable(VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME);
|
||||
@ -3673,14 +3670,14 @@ void VulkanRenderer::texture_copyImageSubData(LatteTexture* src, sint32 srcMip,
|
||||
LatteTextureReadbackInfo* VulkanRenderer::texture_createReadback(LatteTextureView* textureView)
|
||||
{
|
||||
auto* result = new LatteTextureReadbackInfoVk(m_logicalDevice, textureView);
|
||||
|
||||
LatteTextureVk* vkTex = (LatteTextureVk*)textureView->baseTexture;
|
||||
|
||||
VkMemoryRequirements memRequirements;
|
||||
vkGetImageMemoryRequirements(m_logicalDevice, vkTex->GetImageObj()->m_image, &memRequirements);
|
||||
|
||||
const uint32 linearImageSize = result->GetImageSize();
|
||||
const uint32 uploadSize = (linearImageSize == 0) ? memRequirements.size : linearImageSize;
|
||||
if (linearImageSize == 0)
|
||||
{
|
||||
delete result;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const uint32 uploadSize = linearImageSize;
|
||||
const uint32 uploadAlignment = 256; // todo - use Vk optimalBufferCopyOffsetAlignment
|
||||
m_textureReadbackBufferWriteIndex = (m_textureReadbackBufferWriteIndex + uploadAlignment - 1) & ~(uploadAlignment - 1);
|
||||
|
||||
@ -3714,46 +3711,14 @@ void VulkanRenderer::streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBuf
|
||||
|
||||
void VulkanRenderer::streamout_begin()
|
||||
{
|
||||
if (m_featureControl.mode.useTFEmulationViaSSBO)
|
||||
return;
|
||||
if (m_state.hasActiveXfb == false)
|
||||
m_state.hasActiveXfb = true;
|
||||
}
|
||||
|
||||
void VulkanRenderer::streamout_applyTransformFeedbackState()
|
||||
{
|
||||
if (m_featureControl.mode.useTFEmulationViaSSBO)
|
||||
return;
|
||||
cemu_assert_debug(m_state.hasActiveXfb == false);
|
||||
if (m_state.hasActiveXfb)
|
||||
{
|
||||
// set buffers
|
||||
for (sint32 i = 0; i < LATTE_NUM_STREAMOUT_BUFFER; i++)
|
||||
{
|
||||
if (m_streamoutState.buffer[i].enabled)
|
||||
{
|
||||
VkBuffer tfBuffer = m_xfbRingBuffer;
|
||||
VkDeviceSize tfBufferOffset = m_streamoutState.buffer[i].ringBufferOffset;
|
||||
VkDeviceSize tfBufferSize = VK_WHOLE_SIZE;
|
||||
vkCmdBindTransformFeedbackBuffersEXT(m_state.currentCommandBuffer, i, 1, &tfBuffer, &tfBufferOffset, &tfBufferSize);
|
||||
}
|
||||
}
|
||||
// begin transform feedback
|
||||
vkCmdBeginTransformFeedbackEXT(m_state.currentCommandBuffer, 0, 0, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanRenderer::streamout_rendererFinishDrawcall()
|
||||
{
|
||||
if (m_state.hasActiveXfb)
|
||||
{
|
||||
vkCmdEndTransformFeedbackEXT(m_state.currentCommandBuffer, 0, 0, nullptr, nullptr);
|
||||
m_streamoutState.buffer[0].enabled = false;
|
||||
m_streamoutState.buffer[1].enabled = false;
|
||||
m_streamoutState.buffer[2].enabled = false;
|
||||
m_streamoutState.buffer[3].enabled = false;
|
||||
m_state.hasActiveXfb = false;
|
||||
}
|
||||
m_streamoutState.buffer[0].enabled = false;
|
||||
m_streamoutState.buffer[1].enabled = false;
|
||||
m_streamoutState.buffer[2].enabled = false;
|
||||
m_streamoutState.buffer[3].enabled = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -380,9 +380,6 @@ private:
|
||||
uint32 offset;
|
||||
}currentVertexBinding[LATTE_MAX_VERTEX_BUFFERS]{};
|
||||
|
||||
// transform feedback
|
||||
bool hasActiveXfb{};
|
||||
|
||||
// index buffer
|
||||
Renderer::INDEX_TYPE activeIndexType{};
|
||||
uint32 activeIndexBufferIndex{};
|
||||
@ -442,7 +439,6 @@ private:
|
||||
{
|
||||
// if using new optional extensions add to CheckDeviceExtensionSupport and CreateDeviceCreateInfo
|
||||
bool tooling_info = false; // VK_EXT_tooling_info
|
||||
bool transform_feedback = false;
|
||||
bool depth_range_unrestricted = false;
|
||||
bool nv_fill_rectangle = false; // NV_fill_rectangle
|
||||
bool pipeline_feedback = false;
|
||||
@ -470,11 +466,6 @@ private:
|
||||
bool debug_utils = false; // VK_EXT_DEBUG_UTILS
|
||||
}instanceExtensions;
|
||||
|
||||
struct
|
||||
{
|
||||
bool useTFEmulationViaSSBO = true; // emulate transform feedback via shader writes to a storage buffer
|
||||
}mode;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 minUniformBufferOffsetAlignment = 256;
|
||||
@ -521,7 +512,10 @@ private:
|
||||
void DeleteFontTextures() override;
|
||||
bool BeginFrame(bool mainWindow) override;
|
||||
|
||||
bool UseTFViaSSBO() const override { return m_featureControl.mode.useTFEmulationViaSSBO; }
|
||||
bool UseTFViaSSBO() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// drawcall emulation
|
||||
PipelineInfo* draw_createGraphicsPipeline(uint32 indexCount);
|
||||
@ -567,7 +561,6 @@ private:
|
||||
// streamout
|
||||
void streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) override;
|
||||
void streamout_begin() override;
|
||||
void streamout_applyTransformFeedbackState();
|
||||
void bufferCache_copyStreamoutToMainBuffer(uint32 srcOffset, uint32 dstOffset, uint32 size) override;
|
||||
void streamout_rendererFinishDrawcall() override;
|
||||
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
#include "Cafe/OS/RPL/rpl.h"
|
||||
#include "Cafe/OS/RPL/rpl_structs.h"
|
||||
#include "Cafe/OS/RPL/rpl_symbol_storage.h"
|
||||
#include "util/VirtualHeap/VirtualHeap.h"
|
||||
#include "Cafe/HW/Espresso/Recompiler/PPCRecompiler.h"
|
||||
#include "Cafe/HW/Espresso/Debugger/Debugger.h"
|
||||
#include "Cafe/GraphicPack/GraphicPack2.h"
|
||||
@ -272,10 +271,7 @@ bool RPLLoader_ProcessHeaders(std::string_view moduleName, uint8* rplData, uint3
|
||||
// init section address table
|
||||
rplLoaderContext->sectionAddressTable2.resize(sectionCount);
|
||||
// init modulename
|
||||
rplLoaderContext->moduleName2.assign(moduleName);
|
||||
// convert modulename to lower-case
|
||||
for(auto& c : rplLoaderContext->moduleName2)
|
||||
c = _ansiToLower(c);
|
||||
rplLoaderContext->moduleName.assign(moduleName);
|
||||
|
||||
// load CRC section
|
||||
uint32 crcTableExpectedSize = sectionCount * sizeof(uint32be);
|
||||
@ -525,7 +521,7 @@ bool RPLLoader_LoadSections(sint32 aProcId, RPLModule* rplLoaderContext)
|
||||
PPCRecompiler_allocateRange(rplLoaderContext->regionMappingBase_text.GetMPTR(), regionTextSize + 0x1000);
|
||||
|
||||
// workaround for DKC Tropical Freeze
|
||||
if (boost::iequals(rplLoaderContext->moduleName2, "rs10_production"))
|
||||
if (rplLoaderContext->moduleName == "rs10_production")
|
||||
{
|
||||
// allocate additional 12MB of unused data to get below a size of 0x3E200000 for the main ExpHeap
|
||||
// otherwise the game will assume it's running on a Devkit unit with 2GB of RAM and subtract 1GB from available space
|
||||
@ -536,6 +532,10 @@ bool RPLLoader_LoadSections(sint32 aProcId, RPLModule* rplLoaderContext)
|
||||
rplLoaderContext->regionSize_loaderInfo = regionLoaderinfoSize;
|
||||
rplLoaderContext->regionSize_text = regionTextSize;
|
||||
|
||||
// set original base addresses
|
||||
rplLoaderContext->regionOrigAddr_text = regionMappingTable.region[RPL_MAPPING_REGION_TEXT].baseAddress;
|
||||
rplLoaderContext->regionOrigAddr_data = regionMappingTable.region[RPL_MAPPING_REGION_DATA].baseAddress;
|
||||
|
||||
// load data sections
|
||||
for (sint32 i = 0; i < (sint32)rplLoaderContext->rplHeader.sectionTableEntryCount; i++)
|
||||
{
|
||||
@ -844,7 +844,7 @@ MPTR _findHLEExport(RPLModule* rplLoaderContext, RPLSharedImportTracking* shared
|
||||
MPTR weakExportAddr = osLib_getPointer(libname, symbolName);
|
||||
if (weakExportAddr != 0xFFFFFFFF)
|
||||
return weakExportAddr;
|
||||
cemuLog_logDebug(LogType::Force, "Unsupported data export ({}): {}.{}", rplLoaderContext->moduleName2, libname, symbolName);
|
||||
cemuLog_logDebug(LogType::Force, "Unsupported data export ({}): {}.{}", rplLoaderContext->moduleName, libname, symbolName);
|
||||
return MPTR_NULL;
|
||||
}
|
||||
else
|
||||
@ -1281,7 +1281,7 @@ bool RPLLoader_ApplyRelocs(RPLModule* rplLoaderContext, sint32 relaSectionIndex,
|
||||
uint32 crc = rplLoaderContext->GetSectionCRC(relaSectionIndex);
|
||||
if (calcCRC != crc)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "RPLLoader {} - Relocation section {} has CRC mismatch - Calc: {:08x} Actual: {:08x}", rplLoaderContext->moduleName2.c_str(), relaSectionIndex, calcCRC, crc);
|
||||
cemuLog_log(LogType::Force, "RPLLoader {} - Relocation section {} has CRC mismatch - Calc: {:08x} Actual: {:08x}", rplLoaderContext->moduleName.c_str(), relaSectionIndex, calcCRC, crc);
|
||||
}
|
||||
// process relocations
|
||||
sint32 relocCount = relocSize / sizeof(rplRelocNew_t);
|
||||
@ -1379,7 +1379,7 @@ bool RPLLoader_HandleRelocs(RPLModule* rplLoaderContext, std::span<RPLSharedImpo
|
||||
return true;
|
||||
}
|
||||
|
||||
void _RPLLoader_ExtractModuleNameFromPath(char* output, std::string_view input)
|
||||
std::string _RPLLoader_ExtractModuleNameFromPath(std::string_view input)
|
||||
{
|
||||
// scan to last '/'
|
||||
cemu_assert(!input.empty());
|
||||
@ -1404,10 +1404,11 @@ void _RPLLoader_ExtractModuleNameFromPath(char* output, std::string_view input)
|
||||
size_t nameLen = endIndex - startIndex;
|
||||
cemu_assert(nameLen != 0);
|
||||
nameLen = std::min<size_t>(nameLen, RPL_MODULE_NAME_LENGTH-1);
|
||||
memcpy(output, input.data() + startIndex, nameLen);
|
||||
output[nameLen] = '\0';
|
||||
std::string output;
|
||||
output.append(input.data() + startIndex, nameLen);
|
||||
// convert to lower case
|
||||
std::for_each(output, output + nameLen, [](char& c) {c = _ansiToLower(c);});
|
||||
std::for_each(output.begin(), output.end(), [](char& c) {c = _ansiToLower(c);});
|
||||
return output;
|
||||
}
|
||||
|
||||
void RPLLoader_InitState()
|
||||
@ -1581,8 +1582,7 @@ void RPLLoader_InitModuleAllocator(RPLModule* rpl)
|
||||
// map rpl into memory, but do not resolve relocs and imports yet
|
||||
RPLModule* RPLLoader_LoadFromMemory(uint8* rplData, sint32 size, std::string_view name)
|
||||
{
|
||||
char moduleName[RPL_MODULE_NAME_LENGTH];
|
||||
_RPLLoader_ExtractModuleNameFromPath(moduleName, name);
|
||||
std::string moduleName = _RPLLoader_ExtractModuleNameFromPath(name);
|
||||
RPLModule* rpl = nullptr;
|
||||
if (RPLLoader_ProcessHeaders({ moduleName }, rplData, size, &rpl) == false)
|
||||
{
|
||||
@ -1596,9 +1596,7 @@ RPLModule* RPLLoader_LoadFromMemory(uint8* rplData, sint32 size, std::string_vie
|
||||
delete rpl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cemuLog_logDebug(LogType::Force, "Load {} Code-Offset: -0x{:x}", name, rpl->regionMappingBase_text.GetMPTR() - 0x02000000);
|
||||
|
||||
// sdata (r2/r13)
|
||||
uint32 sdataBaseAddress = rpl->fileInfo.sdataBase1; // base + 0x8000
|
||||
uint32 sdataBaseAddress2 = rpl->fileInfo.sdataBase2; // base + 0x8000
|
||||
@ -1693,16 +1691,14 @@ void RPLLoader_LinkSingleModule(RPLModule* rplLoaderContext, bool resolveOnlyExp
|
||||
{
|
||||
if( rplLoaderContext->sectionTablePtr[i].type != (uint32be)SHT_RPL_IMPORTS )
|
||||
continue;
|
||||
cemu_assert(rplLoaderContext->sectionTablePtr[i].sectionSize >= 9);
|
||||
char* libName = (char*)((uint8*)rplLoaderContext->sectionAddressTable2[i].ptr + 8);
|
||||
// make module name
|
||||
char _importModuleName[RPL_MODULE_NAME_LENGTH];
|
||||
_RPLLoader_ExtractModuleNameFromPath(_importModuleName, libName);
|
||||
// find in loaded module list
|
||||
std::string importModuleName{_importModuleName};
|
||||
std::string importModuleName = _RPLLoader_ExtractModuleNameFromPath(libName);
|
||||
bool foundModule = false;
|
||||
for (sint32 f = 0; f < rplModuleCount; f++)
|
||||
{
|
||||
if (boost::iequals(rplModuleList[f]->moduleName2, importModuleName))
|
||||
if (rplModuleList[f]->moduleName == importModuleName)
|
||||
{
|
||||
sharedImportTracking[i].rplLoaderContext = rplModuleList[f];
|
||||
memset(sharedImportTracking[i].modulename, 0, sizeof(sharedImportTracking[i].modulename));
|
||||
@ -1766,7 +1762,7 @@ void RPLLoader_LoadSectionDebugSymbols(RPLModule* rplLoaderContext, rplSectionEn
|
||||
char* symbolName = (char*)strtabData + nameOffset;
|
||||
if (sym->info == 0x12)
|
||||
{
|
||||
rplSymbolStorage_store(rplLoaderContext->moduleName2.c_str(), symbolName, sym->symbolAddress);
|
||||
rplSymbolStorage_store(rplLoaderContext->moduleName.c_str(), symbolName, sym->symbolAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1860,7 +1856,7 @@ void RPLLoader_FixModuleTLSIndex(RPLModule* rplLoaderContext)
|
||||
sint16 tlsModuleIndex = -1;
|
||||
for (auto& dep : rplDependencyList)
|
||||
{
|
||||
if (boost::iequals(rplLoaderContext->moduleName2, dep->modulename))
|
||||
if (rplLoaderContext->moduleName == dep->moduleName)
|
||||
{
|
||||
tlsModuleIndex = dep->tlsModuleIndex;
|
||||
break;
|
||||
@ -1928,23 +1924,21 @@ COSModule* RPLLoader_GetHLECafeOSModule(std::string_view moduleName)
|
||||
std::span<COSModule*> cosModules = GetCOSModules();
|
||||
for (auto& module : cosModules)
|
||||
{
|
||||
if (boost::iequals(module->GetName(), moduleName))
|
||||
if (module->GetName() == moduleName)
|
||||
return module;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// increment reference counter for module
|
||||
void RPLLoader_AddDependency(std::string_view name)
|
||||
void RPLLoader_AddDependency(std::string_view name, bool isMainExecutable)
|
||||
{
|
||||
cemu_assert(!name.empty());
|
||||
// get module name from path
|
||||
char moduleName[RPL_MODULE_NAME_LENGTH];
|
||||
_RPLLoader_ExtractModuleNameFromPath(moduleName, name);
|
||||
std::string moduleName = _RPLLoader_ExtractModuleNameFromPath(name);
|
||||
// check if dependency already exists
|
||||
for (auto& dep : rplDependencyList)
|
||||
{
|
||||
if (strcmp(moduleName, dep->modulename) == 0)
|
||||
if (moduleName == dep->moduleName)
|
||||
{
|
||||
dep->referenceCount++;
|
||||
return;
|
||||
@ -1952,7 +1946,8 @@ void RPLLoader_AddDependency(std::string_view name)
|
||||
}
|
||||
// add new entry
|
||||
RPLDependency* newDependency = new RPLDependency();
|
||||
strcpy(newDependency->modulename, moduleName);
|
||||
newDependency->isMainExecutable = isMainExecutable;
|
||||
newDependency->moduleName = moduleName;
|
||||
newDependency->referenceCount = 1;
|
||||
newDependency->coreinitHandle = rplLoader_currentHandleCounter;
|
||||
newDependency->tlsModuleIndex = rplLoader_currentTlsModuleIndex;
|
||||
@ -1961,21 +1956,13 @@ void RPLLoader_AddDependency(std::string_view name)
|
||||
rplLoader_currentHandleCounter++;
|
||||
if (rplLoader_currentTlsModuleIndex == 0x7FFF)
|
||||
cemuLog_log(LogType::Force, "RPLLoader: Exhausted TLS module indices pool");
|
||||
// convert name to path/filename if it isn't already one
|
||||
if (name.find_first_of('.') != std::string_view::npos)
|
||||
{
|
||||
newDependency->filepath = name;
|
||||
}
|
||||
else
|
||||
{
|
||||
newDependency->filepath = name;
|
||||
newDependency->filepath.append(".rpl");
|
||||
}
|
||||
if (newDependency->filepath.size() >= RPL_MODULE_PATH_LENGTH)
|
||||
cemuLog_log(LogType::Force, "RPLLoader_AddDependency(): RPL path too long \"{}\"", newDependency->filepath);
|
||||
if (moduleName.size() >= RPL_MODULE_PATH_LENGTH)
|
||||
cemuLog_log(LogType::Force, "RPLLoader_AddDependency(): RPL module name too long \"{}\"", moduleName);
|
||||
std::string fileName = moduleName;
|
||||
fileName.append(isMainExecutable ? ".rpx" : ".rpl");
|
||||
// if no CafeLibs RPL is present then try to load as a HLE module
|
||||
// we dont check for isCafeOSModule == true here because the user might want to replace application RPLs in some cases
|
||||
const auto cafeLibsFilePath = ActiveSettings::GetUserDataPath("cafeLibs/{}", newDependency->filepath);
|
||||
const auto cafeLibsFilePath = ActiveSettings::GetUserDataPath("cafeLibs/{}", fileName);
|
||||
std::error_code ec;
|
||||
if (!fs::exists(cafeLibsFilePath, ec))
|
||||
newDependency->rplHLEModule = RPLLoader_GetHLECafeOSModule(moduleName);
|
||||
@ -1985,14 +1972,14 @@ void RPLLoader_AddDependency(std::string_view name)
|
||||
// decrement reference counter for dependency by module path
|
||||
void RPLLoader_RemoveDependency(std::string_view name)
|
||||
{
|
||||
cemu_assert(!name.empty());
|
||||
// get module name from path
|
||||
char moduleName[RPL_MODULE_NAME_LENGTH];
|
||||
_RPLLoader_ExtractModuleNameFromPath(moduleName, name);
|
||||
cemu_assert_debug(!name.empty());
|
||||
if (name.empty())
|
||||
return;
|
||||
std::string moduleName = _RPLLoader_ExtractModuleNameFromPath(name);
|
||||
// find dependency and decrement ref count
|
||||
for (auto& dep : rplDependencyList)
|
||||
{
|
||||
if (strcmp(moduleName, dep->modulename) == 0)
|
||||
if (dep->moduleName == moduleName)
|
||||
{
|
||||
dep->referenceCount--;
|
||||
return;
|
||||
@ -2002,11 +1989,12 @@ void RPLLoader_RemoveDependency(std::string_view name)
|
||||
|
||||
bool RPLLoader_HasDependency(std::string_view name)
|
||||
{
|
||||
char moduleName[RPL_MODULE_NAME_LENGTH];
|
||||
_RPLLoader_ExtractModuleNameFromPath(moduleName, name);
|
||||
if (name.empty())
|
||||
return false;
|
||||
std::string moduleName = _RPLLoader_ExtractModuleNameFromPath(name);
|
||||
for (const auto& dep : rplDependencyList)
|
||||
{
|
||||
if (strcmp(moduleName, dep->modulename) == 0)
|
||||
if (dep->moduleName == moduleName)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -2041,13 +2029,11 @@ RPLDependency* RPLLoader_GetDependencyByRPLModule(RPLModule* rpl)
|
||||
|
||||
uint32 RPLLoader_GetHandleByModuleName(const char* name)
|
||||
{
|
||||
// get module name from path
|
||||
char moduleName[RPL_MODULE_NAME_LENGTH];
|
||||
_RPLLoader_ExtractModuleNameFromPath(moduleName, name);
|
||||
std::string moduleName = _RPLLoader_ExtractModuleNameFromPath(name);
|
||||
// search for existing dependency
|
||||
for (auto& dep : rplDependencyList)
|
||||
{
|
||||
if (strcmp(moduleName, dep->modulename) == 0)
|
||||
if (dep->moduleName == moduleName)
|
||||
{
|
||||
cemu_assert_debug(dep->loadAttempted);
|
||||
if (!dep->isCafeOSModule && !dep->rplLoaderContext)
|
||||
@ -2107,7 +2093,7 @@ void RPLLoader_LoadDependency(RPLDependency* dependency)
|
||||
{
|
||||
dependency->rplHLEModule->RPLMapped();
|
||||
// load chained dependencies
|
||||
// this is necessary for something like GX2.rpl which uses TCL.rpl functions
|
||||
// this is necessary for something like HLE GX2.rpl which uses TCL.rpl functions
|
||||
auto depList = dependency->rplHLEModule->GetDependencies();
|
||||
for (const auto& dep : depList)
|
||||
RPLLoader_AddDependency(dep);
|
||||
@ -2116,43 +2102,36 @@ void RPLLoader_LoadDependency(RPLDependency* dependency)
|
||||
// check if module is already loaded
|
||||
for (sint32 i = 0; i < rplModuleCount; i++)
|
||||
{
|
||||
if(!boost::iequals(rplModuleList[i]->moduleName2, dependency->modulename))
|
||||
if (rplModuleList[i]->moduleName != dependency->moduleName)
|
||||
continue;
|
||||
dependency->rplLoaderContext = rplModuleList[i];
|
||||
return;
|
||||
}
|
||||
//char filePath[RPL_MODULE_PATH_LENGTH];
|
||||
std::string rplPath;
|
||||
// check if path is absolute
|
||||
if (!dependency->filepath.empty() && dependency->filepath.front() == '/')
|
||||
{
|
||||
rplPath = dependency->filepath;
|
||||
RPLLoader_LoadFromVirtualPath(dependency, rplPath);
|
||||
return;
|
||||
}
|
||||
// attempt to load rpl from code directory of current title
|
||||
rplPath = "/internal/current_title/code/";
|
||||
rplPath.append(dependency->filepath);
|
||||
std::string rplFilename = dependency->moduleName;
|
||||
rplFilename.append(dependency->isMainExecutable ? ".rpx" : ".rpl");
|
||||
std::string rplPath = "/internal/current_title/code/";
|
||||
rplPath.append(rplFilename);
|
||||
// except if it is blacklisted
|
||||
bool isBlacklisted = false;
|
||||
if (boost::iequals(dependency->filepath, "erreula.rpl"))
|
||||
if (dependency->moduleName == "erreula")
|
||||
{
|
||||
if (fsc_doesFileExist(rplPath.c_str()))
|
||||
isBlacklisted = true;
|
||||
}
|
||||
if (isBlacklisted)
|
||||
cemuLog_log(LogType::Force, fmt::format("Game tried to load \"{}\" but it is blacklisted (using Cemu's implementation instead)", rplPath));
|
||||
cemuLog_log(LogType::Force, "Game tried to load code/{} but it is blacklisted (using Cemu's implementation instead)", rplFilename);
|
||||
else if (RPLLoader_LoadFromVirtualPath(dependency, rplPath))
|
||||
return;
|
||||
// attempt to load rpl from Cemu's /cafeLibs/ directory
|
||||
if (ActiveSettings::LoadSharedLibrariesEnabled())
|
||||
{
|
||||
const auto cafeLibsFilePath = ActiveSettings::GetUserDataPath("cafeLibs/{}", dependency->filepath);
|
||||
const auto cafeLibsFilePath = ActiveSettings::GetUserDataPath("cafeLibs/{}", rplFilename);
|
||||
auto fileData = FileStream::LoadIntoMemory(cafeLibsFilePath);
|
||||
if (fileData)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Loading RPL: /cafeLibs/{}", dependency->filepath);
|
||||
dependency->rplLoaderContext = RPLLoader_LoadFromMemory(fileData->data(), fileData->size(), dependency->filepath);
|
||||
cemuLog_log(LogType::Force, "Loading RPL: /cafeLibs/{}", rplFilename);
|
||||
dependency->rplLoaderContext = RPLLoader_LoadFromMemory(fileData->data(), fileData->size(), rplFilename);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -2213,7 +2192,7 @@ void RPLLoader_LoadCoreinit()
|
||||
RPLLoader_AddDependency("coreinit");
|
||||
for (auto& dep : rplDependencyList)
|
||||
{
|
||||
if (strcmp(dep->modulename, "coreinit") == 0)
|
||||
if (dep->moduleName == "coreinit")
|
||||
{
|
||||
dep->loadAttempted = true;
|
||||
RPLLoader_LoadDependency(dep);
|
||||
@ -2276,7 +2255,7 @@ RPLModule* RPLLoader_FindModuleByName(std::string module)
|
||||
{
|
||||
for (sint32 i = 0; i < rplModuleCount; i++)
|
||||
{
|
||||
if (rplModuleList[i]->moduleName2 == module) return rplModuleList[i];
|
||||
if (rplModuleList[i]->moduleName == module) return rplModuleList[i];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -2298,7 +2277,7 @@ void RPLLoader_CallEntrypoints()
|
||||
{
|
||||
if (rplModuleList[i]->entrypointCalled)
|
||||
continue;
|
||||
uint32 moduleHandle = RPLLoader_GetHandleByModuleName(rplModuleList[i]->moduleName2.c_str());
|
||||
uint32 moduleHandle = RPLLoader_GetHandleByModuleName(rplModuleList[i]->moduleName.c_str());
|
||||
MPTR entryPoint = RPLLoader_GetModuleEntrypoint(rplModuleList[i]);
|
||||
PPCCoreCallback(entryPoint, moduleHandle, 1); // 1 -> load, 2 -> unload
|
||||
rplModuleList[i]->entrypointCalled = true;
|
||||
@ -2311,7 +2290,7 @@ void RPLLoader_CallCoreinitEntrypoint()
|
||||
// for HLE modules we need to check the dependency list
|
||||
for (auto& dependency : rplDependencyList)
|
||||
{
|
||||
if (strcmp(dependency->modulename, "coreinit") != 0)
|
||||
if (dependency->moduleName != "coreinit")
|
||||
continue;
|
||||
if (!dependency->rplHLEModule)
|
||||
continue;
|
||||
@ -2354,13 +2333,13 @@ uint32 RPLLoader_FindModuleOrHLEExport(uint32 moduleHandle, bool isData, const c
|
||||
// attempt to find HLE export
|
||||
if (isData)
|
||||
{
|
||||
MPTR weakExportAddr = osLib_getPointer(dependency->modulename, exportName);
|
||||
MPTR weakExportAddr = osLib_getPointer(dependency->moduleName.c_str(), exportName);
|
||||
cemu_assert_debug(weakExportAddr != 0xFFFFFFFF);
|
||||
exportResult = weakExportAddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
exportResult = rpl_mapHLEImport(rplLoaderContext, dependency->modulename, exportName, true);
|
||||
exportResult = rpl_mapHLEImport(rplLoaderContext, dependency->moduleName.c_str(), exportName, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2482,8 +2461,6 @@ void RPLLoader_UnloadAll()
|
||||
cemu_assert_debug(dependency->referenceCount >= 0); // sanity check for ref count
|
||||
if (!dependency->rplHLEModule)
|
||||
continue;
|
||||
if (dependency->referenceCount <= 0)
|
||||
continue;
|
||||
cemu_assert_debug(dependency->hleEntrypointCalled); // entrypoint should have been called
|
||||
dependency->rplHLEModule->rpl_entry(dependency->coreinitHandle, coreinit::RplEntryReason::Unloaded);
|
||||
dependency->rplHLEModule->RPLUnmapped();
|
||||
|
||||
@ -28,7 +28,7 @@ void RPLLoader_CallEntrypoints();
|
||||
void RPLLoader_CallCoreinitEntrypoint();
|
||||
void RPLLoader_NotifyControlPassedToApplication();
|
||||
|
||||
void RPLLoader_AddDependency(std::string_view name);
|
||||
void RPLLoader_AddDependency(std::string_view name, bool isMainExecutable = false);
|
||||
void RPLLoader_RemoveDependency(uint32 handle);
|
||||
bool RPLLoader_HasDependency(std::string_view name);
|
||||
void RPLLoader_UpdateDependencies();
|
||||
|
||||
@ -164,14 +164,16 @@ struct RPLModule
|
||||
uint32 exportFCount;
|
||||
rplExportTableEntry_t* exportFDataPtr;
|
||||
|
||||
std::string moduleName2;
|
||||
std::string moduleName;
|
||||
|
||||
std::vector<rplSectionAddressEntry_t> sectionAddressTable2;
|
||||
|
||||
uint32 tlsStartAddress;
|
||||
uint32 tlsEndAddress;
|
||||
uint32 regionSize_text;
|
||||
uint32 regionOrigAddr_text;
|
||||
uint32 regionSize_data;
|
||||
uint32 regionOrigAddr_data;
|
||||
uint32 regionSize_loaderInfo;
|
||||
|
||||
uint32 patchCRC; // Cemuhook style module crc for patches.txt
|
||||
@ -234,11 +236,11 @@ struct RPLModule
|
||||
|
||||
struct RPLDependency
|
||||
{
|
||||
char modulename[RPL_MODULE_NAME_LENGTH];
|
||||
std::string filepath;
|
||||
bool loadAttempted;
|
||||
std::string moduleName;
|
||||
bool isMainExecutable{false};
|
||||
bool loadAttempted{false};
|
||||
bool hleEntrypointCalled{false};
|
||||
bool isCafeOSModule; // name is a known Cafe OS system RPL
|
||||
bool isCafeOSModule{false}; // name is a known Cafe OS system RPL
|
||||
RPLModule* rplLoaderContext{}; // context of loaded module, can be nullptr for HLE COS modules
|
||||
class COSModule* rplHLEModule{}; // set if this is a HLE module
|
||||
sint32 referenceCount;
|
||||
|
||||
@ -63,7 +63,7 @@ char* rplSymbolStorage_storeLibname(const char* libName)
|
||||
return libEntry->libName;
|
||||
}
|
||||
|
||||
RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolName, MPTR address)
|
||||
RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolName, MPTR address, uint32 type)
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(rplSymbolStorage.m_symbolStorageMutex);
|
||||
char* libNameStorage = rplSymbolStorage_storeLibname(libName);
|
||||
@ -72,7 +72,11 @@ RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolN
|
||||
storedSymbol->address = address;
|
||||
storedSymbol->libName = libNameStorage;
|
||||
storedSymbol->symbolName = symbolNameStorage;
|
||||
storedSymbol->flags = 0;
|
||||
storedSymbol->flags = type;
|
||||
storedSymbol->previous = nullptr;
|
||||
auto it = rplSymbolStorage.map_symbolByAddress.find(address);
|
||||
if (it != rplSymbolStorage.map_symbolByAddress.end())
|
||||
storedSymbol->previous = it->second;
|
||||
rplSymbolStorage.map_symbolByAddress[address] = storedSymbol;
|
||||
return storedSymbol;
|
||||
}
|
||||
@ -80,7 +84,10 @@ RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolN
|
||||
RPLStoredSymbol* rplSymbolStorage_getByAddress(MPTR address)
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(rplSymbolStorage.m_symbolStorageMutex);
|
||||
return rplSymbolStorage.map_symbolByAddress[address];
|
||||
auto it = rplSymbolStorage.map_symbolByAddress.find(address);
|
||||
if (it == rplSymbolStorage.map_symbolByAddress.end())
|
||||
return nullptr;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
RPLStoredSymbol* rplSymbolStorage_getByClosestAddress(MPTR address)
|
||||
@ -89,7 +96,8 @@ RPLStoredSymbol* rplSymbolStorage_getByClosestAddress(MPTR address)
|
||||
std::unique_lock<std::mutex> lck(rplSymbolStorage.m_symbolStorageMutex);
|
||||
for(uint32 i=0; i<4096; i++)
|
||||
{
|
||||
RPLStoredSymbol* symbol = rplSymbolStorage.map_symbolByAddress[address];
|
||||
auto it = rplSymbolStorage.map_symbolByAddress.find(address);
|
||||
RPLStoredSymbol* symbol = (it == rplSymbolStorage.map_symbolByAddress.end()) ? nullptr : it->second;
|
||||
if(symbol)
|
||||
return symbol;
|
||||
address -= 4;
|
||||
@ -100,18 +108,63 @@ RPLStoredSymbol* rplSymbolStorage_getByClosestAddress(MPTR address)
|
||||
void rplSymbolStorage_remove(RPLStoredSymbol* storedSymbol)
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(rplSymbolStorage.m_symbolStorageMutex);
|
||||
if (rplSymbolStorage.map_symbolByAddress[storedSymbol->address] == storedSymbol)
|
||||
rplSymbolStorage.map_symbolByAddress[storedSymbol->address] = nullptr;
|
||||
auto it = rplSymbolStorage.map_symbolByAddress.find(storedSymbol->address);
|
||||
if (it != rplSymbolStorage.map_symbolByAddress.end())
|
||||
{
|
||||
if (it->second == storedSymbol)
|
||||
{
|
||||
if (storedSymbol->previous)
|
||||
it->second = storedSymbol->previous;
|
||||
else
|
||||
rplSymbolStorage.map_symbolByAddress.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
RPLStoredSymbol* parentSymbol = it->second;
|
||||
while (parentSymbol && parentSymbol->previous != storedSymbol)
|
||||
parentSymbol = parentSymbol->previous;
|
||||
if (parentSymbol)
|
||||
parentSymbol->previous = storedSymbol->previous;
|
||||
}
|
||||
}
|
||||
delete storedSymbol;
|
||||
}
|
||||
|
||||
void rplSymbolStorage_removeRange(MPTR address, sint32 length)
|
||||
|
||||
void rplSymbolStorage_removeRange(MPTR address, sint32 length, uint32 type)
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(rplSymbolStorage.m_symbolStorageMutex);
|
||||
while (length > 0)
|
||||
{
|
||||
RPLStoredSymbol* symbol = rplSymbolStorage_getByAddress(address);
|
||||
if (symbol)
|
||||
rplSymbolStorage_remove(symbol);
|
||||
auto it = rplSymbolStorage.map_symbolByAddress.find(address);
|
||||
if (it != rplSymbolStorage.map_symbolByAddress.end())
|
||||
{
|
||||
RPLStoredSymbol* current = it->second;
|
||||
RPLStoredSymbol* newHead = current;
|
||||
RPLStoredSymbol* previousKept = nullptr;
|
||||
while (current)
|
||||
{
|
||||
RPLStoredSymbol* next = current->previous;
|
||||
if ((current->flags & type) == type)
|
||||
{
|
||||
if (previousKept)
|
||||
previousKept->previous = next;
|
||||
else
|
||||
newHead = next;
|
||||
delete current;
|
||||
}
|
||||
else
|
||||
{
|
||||
previousKept = current;
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
|
||||
if (newHead)
|
||||
it->second = newHead;
|
||||
else
|
||||
rplSymbolStorage.map_symbolByAddress.erase(it);
|
||||
}
|
||||
address += 4;
|
||||
length -= 4;
|
||||
}
|
||||
@ -145,7 +198,15 @@ void rplSymbolStorage_unloadAll()
|
||||
{
|
||||
// free symbols
|
||||
for (auto& it : rplSymbolStorage.map_symbolByAddress)
|
||||
delete it.second;
|
||||
{
|
||||
RPLStoredSymbol* symbol = it.second;
|
||||
while (symbol)
|
||||
{
|
||||
RPLStoredSymbol* previous = symbol->previous;
|
||||
delete symbol;
|
||||
symbol = previous;
|
||||
}
|
||||
}
|
||||
rplSymbolStorage.map_symbolByAddress.clear();
|
||||
// free libs
|
||||
rplSymbolLib_t* lib = rplSymbolStorage.libs;
|
||||
|
||||
@ -1,19 +1,27 @@
|
||||
enum RPLStoredSymbolType : uint32
|
||||
{
|
||||
RPL_STORED_SYMBOL_NONE = 0,
|
||||
RPL_STORED_SYMBOL_MAP = 1 << 0,
|
||||
RPL_STORED_SYMBOL_PATCH = 1 << 1,
|
||||
};
|
||||
|
||||
struct RPLStoredSymbol
|
||||
{
|
||||
MPTR address;
|
||||
void* libName;
|
||||
void* symbolName;
|
||||
uint32 flags;
|
||||
RPLStoredSymbol* previous;
|
||||
};
|
||||
|
||||
void rplSymbolStorage_init();
|
||||
void rplSymbolStorage_unloadAll();
|
||||
RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolName, MPTR address);
|
||||
RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolName, MPTR address, uint32 type = RPL_STORED_SYMBOL_NONE);
|
||||
void rplSymbolStorage_remove(RPLStoredSymbol* storedSymbol);
|
||||
void rplSymbolStorage_removeRange(MPTR address, sint32 length);
|
||||
void rplSymbolStorage_removeRange(MPTR address, sint32 length, uint32 type = RPL_STORED_SYMBOL_NONE);
|
||||
RPLStoredSymbol* rplSymbolStorage_getByAddress(MPTR address);
|
||||
RPLStoredSymbol* rplSymbolStorage_getByClosestAddress(MPTR address);
|
||||
void rplSymbolStorage_createJumpProxySymbol(MPTR jumpAddress, MPTR destAddress);
|
||||
|
||||
std::unordered_map<uint32, RPLStoredSymbol*>& rplSymbolStorage_lockSymbolMap();
|
||||
void rplSymbolStorage_unlockSymbolMap();
|
||||
void rplSymbolStorage_unlockSymbolMap();
|
||||
|
||||
@ -5,6 +5,9 @@
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
#include <iphlpapi.h>
|
||||
#elif BOOST_OS_LINUX
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
// AC lib (manages internet connection)
|
||||
@ -81,6 +84,40 @@ void _GetLocalIPAndSubnetMask(uint32& localIp, uint32& subnetMask)
|
||||
cemuLog_logDebug(LogType::Force, "_GetLocalIPAndSubnetMask(): Failed to find network IP and subnet mask");
|
||||
_GetLocalIPAndSubnetMaskFallback(localIp, subnetMask);
|
||||
}
|
||||
#elif BOOST_OS_LINUX
|
||||
void _GetLocalIPAndSubnetMask(uint32& localIp, uint32& subnetMask)
|
||||
{
|
||||
struct ifaddrs *ifaddr;
|
||||
if (getifaddrs(&ifaddr) == -1)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Failed to acquire local IP and subnet mask");
|
||||
_GetLocalIPAndSubnetMaskFallback(localIp, subnetMask);
|
||||
}
|
||||
stdx::scope_exit _ifa([&]{ freeifaddrs(ifaddr); });
|
||||
|
||||
for (const struct ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
|
||||
{
|
||||
if (ifa->ifa_addr == nullptr || ifa->ifa_addr->sa_family != AF_INET)
|
||||
continue;
|
||||
|
||||
if (!(ifa->ifa_flags & IFF_UP) || !(ifa->ifa_flags & IFF_RUNNING))
|
||||
continue;
|
||||
|
||||
if (ifa->ifa_flags & IFF_LOOPBACK || ifa->ifa_flags & IFF_POINTOPOINT)
|
||||
continue;
|
||||
|
||||
if (boost::starts_with(ifa->ifa_name, "br-") || boost::starts_with(ifa->ifa_name, "docker"))
|
||||
continue;
|
||||
|
||||
const auto* addr_in = reinterpret_cast<struct sockaddr_in*>(ifa->ifa_addr);
|
||||
localIp = ntohl(addr_in->sin_addr.s_addr);
|
||||
const auto* mask_in = reinterpret_cast<struct sockaddr_in*>(ifa->ifa_netmask);
|
||||
subnetMask = ntohl(mask_in->sin_addr.s_addr);
|
||||
return;
|
||||
}
|
||||
cemuLog_logDebug(LogType::Force, "_GetLocalIPAndSubnetMask(): Failed to find network IP and subnet mask");
|
||||
_GetLocalIPAndSubnetMaskFallback(localIp, subnetMask);
|
||||
}
|
||||
#else
|
||||
void _GetLocalIPAndSubnetMask(uint32& localIp, uint32& subnetMask)
|
||||
{
|
||||
|
||||
@ -355,6 +355,8 @@ namespace proc_ui
|
||||
{
|
||||
if (!s_isInitialized.exchange(false))
|
||||
return;
|
||||
if (!OSIsSchedulerActive())
|
||||
return; // CafeSystem shutdown in progress, OS functions shouldn't be called anymore. reset() will clean up state on next re-init
|
||||
if ( !s_isInForeground )
|
||||
CancelBackgroundAlarms();
|
||||
for (sint32 i = 0; i < Espresso::CORE_COUNT; i++)
|
||||
|
||||
@ -121,12 +121,6 @@ DownloadCustomGraphicPackWindow::~DownloadCustomGraphicPackWindow()
|
||||
|
||||
int DownloadCustomGraphicPackWindow::ShowModal()
|
||||
{
|
||||
if (CafeSystem::IsTitleRunning())
|
||||
{
|
||||
wxMessageBox(_("Graphic packs cannot be updated while a game is running."), _("Graphic packs"), 5, this);
|
||||
return wxID_CANCEL;
|
||||
}
|
||||
|
||||
wxDialog::ShowModal();
|
||||
return wxID_OK;
|
||||
}
|
||||
|
||||
@ -304,13 +304,13 @@ GraphicPacksWindow2::GraphicPacksWindow2(wxWindow* parent, uint64_t title_id_fil
|
||||
|
||||
auto* row = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
m_download_from_url = new wxButton(m_right_panel, wxID_ANY, _("Download pack from URL"));
|
||||
m_download_from_url->Bind(wxEVT_BUTTON, &GraphicPacksWindow2::OnClickCustomDownload, this);
|
||||
row->Add(m_download_from_url, 0, wxALL, 5);
|
||||
|
||||
m_update_graphicPacks = new wxButton(m_right_panel, wxID_ANY, _("Download latest community graphic packs"));
|
||||
m_update_graphicPacks->Bind(wxEVT_BUTTON, &GraphicPacksWindow2::OnCheckForUpdates, this);
|
||||
row->Add(m_update_graphicPacks, 0, wxALL, 5);
|
||||
row->Add(m_update_graphicPacks, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
m_download_from_url = new wxHyperlinkCtrl(m_right_panel, wxID_ANY, _("Or download pack from URL..."), _(""));
|
||||
m_download_from_url->Bind(wxEVT_HYPERLINK, &GraphicPacksWindow2::OnClickCustomDownload, this);
|
||||
row->Add(m_download_from_url, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
sizer->Add(row, 0, wxALL | wxEXPAND, 5);
|
||||
|
||||
@ -608,7 +608,7 @@ void GraphicPacksWindow2::OnReloadShaders(wxCommandEvent& event)
|
||||
void GraphicPacksWindow2::OnClickCustomDownload(wxCommandEvent& event)
|
||||
{
|
||||
DownloadCustomGraphicPackWindow frame(this);
|
||||
if (frame.ShowModal() == wxID_OK && !CafeSystem::IsTitleRunning())
|
||||
if (frame.ShowModal() == wxID_OK)
|
||||
{
|
||||
RefreshGraphicPacks();
|
||||
FillGraphicPackList();
|
||||
@ -700,10 +700,17 @@ void GraphicPacksWindow2::OnInstalledGamesChanged(wxCommandEvent& event)
|
||||
void GraphicPacksWindow2::UpdateTitleRunning(bool running)
|
||||
{
|
||||
m_update_graphicPacks->Enable(!running);
|
||||
m_download_from_url->Enable(!running);
|
||||
if(running)
|
||||
{
|
||||
m_download_from_url->SetToolTip(_("Graphic packs cannot be updated while a game is running."));
|
||||
m_update_graphicPacks->SetToolTip(_("Graphic packs cannot be updated while a game is running."));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_update_graphicPacks->SetToolTip(nullptr);
|
||||
m_download_from_url->SetToolTip(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicPacksWindow2::ReloadPack(const GraphicPackPtr& graphic_pack) const
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <wx/frame.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/scrolwin.h>
|
||||
#include <wx/infobar.h>
|
||||
#include <wx/hyperlink.h>
|
||||
|
||||
#include "wxcomponents/checktree.h"
|
||||
|
||||
@ -46,7 +46,7 @@ private:
|
||||
wxBoxSizer* m_preset_sizer;
|
||||
std::vector<wxChoice*> m_active_preset;
|
||||
wxButton* m_reload_shaders;
|
||||
wxButton* m_download_from_url;
|
||||
wxHyperlinkCtrl* m_download_from_url;
|
||||
wxButton* m_update_graphicPacks;
|
||||
wxInfoBar* m_info_bar;
|
||||
|
||||
|
||||
@ -3,11 +3,12 @@
|
||||
|
||||
#include "wxHelper.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include "Common/FileStream.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
#include "Cafe/HW/MMU/MMU.h"
|
||||
#include "Cafe/OS/RPL/rpl_structs.h"
|
||||
#include "Cafe/OS/RPL/rpl_debug_symbols.h"
|
||||
#include "Cafe/OS/RPL/rpl_symbol_storage.h"
|
||||
|
||||
#include "wxgui/debugger/RegisterWindow.h"
|
||||
#include "wxgui/debugger/DumpWindow.h"
|
||||
@ -20,6 +21,7 @@
|
||||
#include "wxgui/debugger/BreakpointWindow.h"
|
||||
#include "wxgui/debugger/ModuleWindow.h"
|
||||
#include "util/helpers/helpers.h"
|
||||
#include "util/helpers/StringHelpers.h"
|
||||
#include "Cafe/HW/Espresso/Recompiler/PPCRecompiler.h"
|
||||
#include "Cemu/Logging/CemuLogging.h"
|
||||
|
||||
@ -81,13 +83,14 @@ wxEND_EVENT_TABLE()
|
||||
|
||||
DebuggerModuleInfo::DebuggerModuleInfo(RPLModule* module)
|
||||
{
|
||||
moduleName = module->moduleName2;
|
||||
moduleName = module->moduleName;
|
||||
patchCRC = module->patchCRC;
|
||||
textArea.base = module->regionMappingBase_text.GetMPTR();
|
||||
textArea.origBase = module->regionOrigAddr_text;
|
||||
textArea.size = module->regionSize_text;
|
||||
dataArea.base = module->regionMappingBase_data;
|
||||
dataArea.origBase = module->regionOrigAddr_data;
|
||||
dataArea.size = module->regionSize_data;
|
||||
|
||||
}
|
||||
|
||||
struct DebuggerModuleInfoNotify : public wxClientData
|
||||
@ -99,6 +102,65 @@ struct DebuggerModuleInfoNotify : public wxClientData
|
||||
|
||||
DebuggerWindow2* s_debuggerWindow;
|
||||
|
||||
static bool TryParseMapAddress(std::string_view token, uint32& value)
|
||||
{
|
||||
trim(token, "\t\n\v\f\r ,:;()[]");
|
||||
if (const auto colonIndex = token.find_last_of(':'); colonIndex != std::string_view::npos)
|
||||
token = token.substr(colonIndex + 1);
|
||||
trim(token, "\t\n\v\f\r ,:;()[]");
|
||||
if (!token.empty() && (token.back() == 'h' || token.back() == 'H'))
|
||||
token.remove_suffix(1);
|
||||
if (token.size() > 2 && token[0] == '0' && (token[1] == 'x' || token[1] == 'X'))
|
||||
token.remove_prefix(2);
|
||||
if (token.empty())
|
||||
return false;
|
||||
|
||||
uint64 parsedValue = 0;
|
||||
const auto result = std::from_chars(token.data(), token.data() + token.size(), parsedValue, 16);
|
||||
if (result.ec != std::errc() || result.ptr != (token.data() + token.size()) || parsedValue > std::numeric_limits<uint32>::max())
|
||||
return false;
|
||||
|
||||
value = static_cast<uint32>(parsedValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TryParseMapSymbolLine(std::string_view rawLine, uint32& address, std::string& symbolName)
|
||||
{
|
||||
auto line = rawLine;
|
||||
trim(line);
|
||||
if (line.empty())
|
||||
return false;
|
||||
|
||||
const auto addressEnd = line.find_first_of(" \t");
|
||||
if (addressEnd == std::string_view::npos)
|
||||
return false;
|
||||
if (!TryParseMapAddress(line.substr(0, addressEnd), address))
|
||||
return false;
|
||||
|
||||
line = line.substr(addressEnd + 1);
|
||||
trim(line);
|
||||
if (line.empty())
|
||||
return false;
|
||||
|
||||
const auto symbolEnd = line.find_first_of(" \t");
|
||||
auto symbolToken = symbolEnd == std::string_view::npos ? line : line.substr(0, symbolEnd);
|
||||
trim(symbolToken);
|
||||
if (symbolToken.empty())
|
||||
return false;
|
||||
|
||||
symbolName.assign(symbolToken);
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::optional<MPTR> GetRelocatedMapAddress(const DebuggerModuleInfo& moduleInfo, uint32 mapAddress)
|
||||
{
|
||||
if (moduleInfo.textArea.ContainsOriginalAddress(mapAddress))
|
||||
return moduleInfo.textArea.base + (mapAddress - moduleInfo.textArea.origBase);
|
||||
if (moduleInfo.dataArea.ContainsOriginalAddress(mapAddress))
|
||||
return moduleInfo.dataArea.base + (mapAddress - moduleInfo.dataArea.origBase);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void DebuggerConfig::Load(XMLConfigParser& parser)
|
||||
{
|
||||
pin_to_main = parser.get("PinToMainWindow", true);
|
||||
@ -282,26 +344,79 @@ void DebuggerWindow2::LoadModuleStorage(const DebuggerModuleInfo& moduleInfo)
|
||||
bool already_loaded = std::any_of(m_modulesStorage.begin(), m_modulesStorage.end(), [path](const std::unique_ptr<XMLDebuggerModuleConfig>& debug) { return debug->GetFilename() == path; });
|
||||
if (!path.empty() && !already_loaded)
|
||||
{
|
||||
m_modulesStorage.emplace_back(new XMLDebuggerModuleConfig(path, { moduleInfo, false }))->Load();
|
||||
auto& moduleStorage = m_modulesStorage.emplace_back(new XMLDebuggerModuleConfig(path, { moduleInfo, false }));
|
||||
moduleStorage->Load();
|
||||
LoadModuleMap(moduleStorage->data());
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerWindow2::SaveModuleStorage(const DebuggerModuleInfo& moduleInfo, bool deleteModuleStorage)
|
||||
{
|
||||
auto path = GetModuleStoragePath(moduleInfo.moduleName, moduleInfo.patchCRC);
|
||||
for (auto& moduleStorage : m_modulesStorage)
|
||||
for (auto it = m_modulesStorage.begin(); it != m_modulesStorage.end(); ++it)
|
||||
{
|
||||
auto& moduleStorage = *it;
|
||||
if (moduleStorage->data().moduleInfo.moduleName == moduleInfo.moduleName && moduleStorage->data().moduleInfo.patchCRC == moduleInfo.patchCRC)
|
||||
{
|
||||
moduleStorage->data().delete_breakpoints_after_saving = deleteModuleStorage; // make sure breakpoints are deleted when the storage is removed
|
||||
moduleStorage->Save(path);
|
||||
if (deleteModuleStorage)
|
||||
m_modulesStorage.erase(std::find(m_modulesStorage.begin(), m_modulesStorage.end(), moduleStorage));
|
||||
break;
|
||||
{
|
||||
UnloadModuleMap(moduleStorage->data());
|
||||
m_modulesStorage.erase(it);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerWindow2::LoadModuleMap(DebuggerModuleStorage& moduleStorage)
|
||||
{
|
||||
UnloadModuleMap(moduleStorage);
|
||||
|
||||
const auto mapPath = GetModuleMapPath(moduleStorage.moduleInfo.moduleName, moduleStorage.moduleInfo.patchCRC);
|
||||
if (mapPath.empty())
|
||||
return;
|
||||
|
||||
std::unique_ptr<FileStream> fileStream(FileStream::openFile(mapPath.c_str()));
|
||||
if (!fileStream)
|
||||
return;
|
||||
|
||||
const auto fileSize = fileStream->GetSize();
|
||||
if (fileSize == 0 || fileSize > std::numeric_limits<uint32>::max())
|
||||
return;
|
||||
|
||||
const auto readSize = static_cast<uint32>(fileSize);
|
||||
std::vector<char> fileData(readSize);
|
||||
if (fileStream->readData(fileData.data(), readSize) != readSize)
|
||||
return;
|
||||
|
||||
std::string_view fileView(fileData.data(), fileData.size());
|
||||
for (const auto& line : StringHelpers::StringLineIterator(fileView))
|
||||
{
|
||||
uint32 mapAddress = 0;
|
||||
std::string symbolName;
|
||||
if (TryParseMapSymbolLine(line, mapAddress, symbolName))
|
||||
{
|
||||
const auto relocatedAddress = GetRelocatedMapAddress(moduleStorage.moduleInfo, mapAddress);
|
||||
if (relocatedAddress)
|
||||
{
|
||||
moduleStorage.loaded_map_symbols.emplace_back(rplSymbolStorage_store(moduleStorage.moduleInfo.moduleName.c_str(), symbolName.c_str(), *relocatedAddress, RPL_STORED_SYMBOL_MAP));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerWindow2::UnloadModuleMap(DebuggerModuleStorage& moduleStorage)
|
||||
{
|
||||
for (auto* symbol : moduleStorage.loaded_map_symbols)
|
||||
{
|
||||
if (symbol)
|
||||
rplSymbolStorage_remove(symbol);
|
||||
}
|
||||
moduleStorage.loaded_map_symbols.clear();
|
||||
}
|
||||
|
||||
DebuggerWindow2::DebuggerWindow2(wxFrame& parent, const wxRect& display_size)
|
||||
: wxFrame(&parent, wxID_ANY, _("PPC Debugger"), wxDefaultPosition, wxSize(1280, 300), wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT),
|
||||
m_module_address(0)
|
||||
@ -341,7 +456,7 @@ DebuggerWindow2::DebuggerWindow2(wxFrame& parent, const wxRect& display_size)
|
||||
{
|
||||
RPLModule* currentModule = RPLLoader_FindModuleByCodeAddr(MEMORY_CODEAREA_ADDR);
|
||||
if (currentModule)
|
||||
label_text = wxString::Format("> %s", currentModule->moduleName2.c_str());
|
||||
label_text = wxString::Format("> %s", currentModule->moduleName.c_str());
|
||||
else
|
||||
label_text = _("> unknown module");
|
||||
}
|
||||
@ -497,7 +612,7 @@ void DebuggerWindow2::OnGameLoaded()
|
||||
|
||||
RPLModule* current_rpl_module = RPLLoader_FindModuleByCodeAddr(MEMORY_CODEAREA_ADDR);
|
||||
if(current_rpl_module)
|
||||
m_module_label->SetLabel(wxString::Format("> %s", current_rpl_module->moduleName2.c_str()));
|
||||
m_module_label->SetLabel(wxString::Format("> %s", current_rpl_module->moduleName.c_str()));
|
||||
|
||||
this->SendSizeEvent();
|
||||
}
|
||||
@ -537,6 +652,12 @@ std::wstring DebuggerWindow2::GetModuleStoragePath(std::string module_name, uint
|
||||
return ActiveSettings::GetConfigPath("debugger/{}_{:#10x}.xml", module_name, crc_hash).generic_wstring();
|
||||
}
|
||||
|
||||
std::wstring DebuggerWindow2::GetModuleMapPath(std::string module_name, uint32_t crc_hash) const
|
||||
{
|
||||
if (module_name.empty() || crc_hash == 0) return {};
|
||||
return ActiveSettings::GetConfigPath("debugger/{}_{:#10x}.map", module_name, crc_hash).generic_wstring();
|
||||
}
|
||||
|
||||
void DebuggerWindow2::OnBreakpointHit(wxCommandEvent& event)
|
||||
{
|
||||
PPCInterpreter_t* hCPU = debugger_lockDebugSession();
|
||||
@ -758,7 +879,7 @@ void DebuggerWindow2::UpdateModuleLabel(uint32 address)
|
||||
RPLModule* module = RPLLoader_FindModuleByCodeAddr(address);
|
||||
if (module && m_module_address != module->regionMappingBase_text.GetMPTR())
|
||||
{
|
||||
m_module_label->SetLabel(wxString::Format("> %s", module->moduleName2.c_str()));
|
||||
m_module_label->SetLabel(wxString::Format("> %s", module->moduleName.c_str()));
|
||||
m_module_address = module->regionMappingBase_text.GetMPTR();
|
||||
}
|
||||
else if (address >= mmuRange_CODECAVE.getBase() && address < mmuRange_CODECAVE.getEnd())
|
||||
|
||||
@ -16,6 +16,7 @@ class DumpWindow;
|
||||
class ModuleWindow;
|
||||
class SymbolWindow;
|
||||
class wxStaticText;
|
||||
struct RPLStoredSymbol;
|
||||
|
||||
wxDECLARE_EVENT(wxEVT_UPDATE_VIEW, wxCommandEvent);
|
||||
wxDECLARE_EVENT(wxEVT_BREAKPOINT_HIT, wxCommandEvent);
|
||||
@ -54,12 +55,18 @@ struct DebuggerModuleInfo
|
||||
struct ModuleArea
|
||||
{
|
||||
MPTR base;
|
||||
MPTR origBase;
|
||||
uint32 size;
|
||||
|
||||
bool ContainsAddress(MPTR addr)
|
||||
bool ContainsAddress(MPTR addr) const
|
||||
{
|
||||
return addr >= base && (addr < (base+size));
|
||||
}
|
||||
|
||||
bool ContainsOriginalAddress(MPTR addr) const
|
||||
{
|
||||
return addr >= origBase && (addr < (origBase + size));
|
||||
}
|
||||
};
|
||||
|
||||
std::string moduleName;
|
||||
@ -74,6 +81,7 @@ struct DebuggerModuleStorage
|
||||
{
|
||||
DebuggerModuleInfo moduleInfo;
|
||||
bool delete_breakpoints_after_saving;
|
||||
std::vector<RPLStoredSymbol*> loaded_map_symbols;
|
||||
|
||||
void Load(XMLConfigParser& parser);
|
||||
void Save(XMLConfigParser& parser);
|
||||
@ -126,6 +134,9 @@ private:
|
||||
|
||||
void CreateMenuBar();
|
||||
void UpdateModuleLabel(uint32 address = 0);
|
||||
void LoadModuleMap(DebuggerModuleStorage& moduleStorage);
|
||||
void UnloadModuleMap(DebuggerModuleStorage& moduleStorage);
|
||||
std::wstring GetModuleMapPath(std::string module_name, uint32_t crc_hash) const;
|
||||
|
||||
void UpdateViewThreadsafe() override;
|
||||
void NotifyDebugBreakpointHit() override;
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
#include "Cemu/ExpressionParser/ExpressionParser.h"
|
||||
#include "Cafe/HW/Espresso/Debugger/DebugSymbolStorage.h"
|
||||
|
||||
#include <wx/clipbrd.h>
|
||||
|
||||
wxDEFINE_EVENT(wxEVT_DISASMCTRL_NOTIFY_GOTO_ADDRESS, wxCommandEvent);
|
||||
|
||||
#define MAX_SYMBOL_LEN (120)
|
||||
@ -699,20 +701,11 @@ void DisasmCtrl::OnMouseDClick(const wxPoint& position, uint32 line)
|
||||
|
||||
void DisasmCtrl::CopyToClipboard(std::string text)
|
||||
{
|
||||
#if BOOST_OS_WINDOWS
|
||||
if (OpenClipboard(nullptr))
|
||||
if (wxClipboard::Get()->Open())
|
||||
{
|
||||
EmptyClipboard();
|
||||
const HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, text.size() + 1);
|
||||
if (hGlobal)
|
||||
{
|
||||
memcpy(GlobalLock(hGlobal), text.c_str(), text.size() + 1);
|
||||
GlobalUnlock(hGlobal);
|
||||
SetClipboardData(CF_TEXT, hGlobal);
|
||||
}
|
||||
CloseClipboard();
|
||||
wxClipboard::Get()->SetData(new wxTextDataObject(text));
|
||||
wxClipboard::Get()->Close();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32 GetUnrelocatedAddress(MPTR address)
|
||||
|
||||
@ -89,7 +89,7 @@ void ModuleWindow::OnGameLoaded()
|
||||
{
|
||||
wxListItem item;
|
||||
item.SetId(i);
|
||||
item.SetText(module->moduleName2);
|
||||
item.SetText(module->moduleName);
|
||||
|
||||
const auto index = m_modules->InsertItem(item);
|
||||
m_modules->SetItem(index, ColumnAddress, wxString::Format("%08x", module->regionMappingBase_text.GetMPTR()));
|
||||
|
||||
@ -222,7 +222,7 @@ void RegisterWindow::UpdateIntegerRegister(wxTextCtrl* label, wxTextCtrl* value,
|
||||
RPLModule* code_module = RPLLoader_FindModuleByCodeAddr(registerValue);
|
||||
if (code_module)
|
||||
{
|
||||
label->ChangeValue(wxString::Format("<%s> + %x", code_module->moduleName2.c_str(), registerValue - code_module->regionMappingBase_text.GetMPTR()));
|
||||
label->ChangeValue(wxString::Format("<%s> + %x", code_module->moduleName.c_str(), registerValue - code_module->regionMappingBase_text.GetMPTR()));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#include "Cafe/OS/RPL/rpl_symbol_storage.h"
|
||||
#include "Cafe/HW/Espresso/Debugger/Debugger.h"
|
||||
#include <wx/listctrl.h>
|
||||
#include <wx/clipbrd.h>
|
||||
|
||||
enum ItemColumns
|
||||
{
|
||||
@ -38,13 +39,12 @@ SymbolListCtrl::SymbolListCtrl(wxWindow* parent, const wxWindowID& id, const wxP
|
||||
m_list_filter.Clear();
|
||||
|
||||
OnGameLoaded();
|
||||
|
||||
SetItemCount(m_data.size());
|
||||
}
|
||||
|
||||
void SymbolListCtrl::OnGameLoaded()
|
||||
{
|
||||
m_data.clear();
|
||||
m_visible_items.clear();
|
||||
const auto symbol_map = rplSymbolStorage_lockSymbolMap();
|
||||
for (auto const& [address, symbol_info] : symbol_map)
|
||||
{
|
||||
@ -56,48 +56,30 @@ void SymbolListCtrl::OnGameLoaded()
|
||||
wxString searchNameWX = libNameWX + symbolNameWX;
|
||||
searchNameWX.MakeLower();
|
||||
|
||||
auto new_entry = m_data.try_emplace(
|
||||
symbol_info->address,
|
||||
symbolNameWX,
|
||||
m_data.try_emplace(
|
||||
address,
|
||||
symbolNameWX,
|
||||
libNameWX,
|
||||
searchNameWX,
|
||||
false
|
||||
searchNameWX
|
||||
);
|
||||
|
||||
if (m_list_filter.IsEmpty())
|
||||
new_entry.first->second.visible = true;
|
||||
else if (new_entry.first->second.searchName.Contains(m_list_filter))
|
||||
new_entry.first->second.visible = true;
|
||||
}
|
||||
rplSymbolStorage_unlockSymbolMap();
|
||||
|
||||
SetItemCount(m_data.size());
|
||||
if (m_data.size() > 0)
|
||||
RefreshItems(GetTopItem(), std::min<long>(m_data.size() - 1, GetTopItem() + GetCountPerPage() + 1));
|
||||
RebuildVisibleItems();
|
||||
}
|
||||
|
||||
wxString SymbolListCtrl::OnGetItemText(long item, long column) const
|
||||
{
|
||||
if (item >= GetItemCount())
|
||||
if (item < 0 || item >= static_cast<long>(m_visible_items.size()))
|
||||
return wxEmptyString;
|
||||
|
||||
long visible_idx = 0;
|
||||
for (const auto& [address, symbol] : m_data)
|
||||
{
|
||||
if (!symbol.visible)
|
||||
continue;
|
||||
|
||||
if (item == visible_idx)
|
||||
{
|
||||
if (column == ColumnName)
|
||||
return wxString(symbol.name);
|
||||
if (column == ColumnAddress)
|
||||
return wxString::Format("%08x", address);
|
||||
if (column == ColumnModule)
|
||||
return wxString(symbol.libName);
|
||||
}
|
||||
visible_idx++;
|
||||
}
|
||||
const auto& [address, symbol] = *m_visible_items[item];
|
||||
if (column == ColumnName)
|
||||
return symbol.name;
|
||||
if (column == ColumnAddress)
|
||||
return wxString::Format("%08x", address);
|
||||
if (column == ColumnModule)
|
||||
return symbol.libName;
|
||||
|
||||
return wxEmptyString;
|
||||
}
|
||||
@ -106,10 +88,9 @@ wxString SymbolListCtrl::OnGetItemText(long item, long column) const
|
||||
void SymbolListCtrl::OnLeftDClick(wxListEvent& event)
|
||||
{
|
||||
long selected = GetFirstSelected();
|
||||
if (selected == wxNOT_FOUND)
|
||||
if (selected == wxNOT_FOUND || selected >= static_cast<long>(m_visible_items.size()))
|
||||
return;
|
||||
const auto text = GetItemText(selected, ColumnAddress);
|
||||
const auto address = std::stoul(text.ToStdString(), nullptr, 16);
|
||||
const auto address = m_visible_items[selected]->first;
|
||||
if (address == 0)
|
||||
return;
|
||||
debugger_jumpToAddressInDisasm(address);
|
||||
@ -118,46 +99,40 @@ void SymbolListCtrl::OnLeftDClick(wxListEvent& event)
|
||||
void SymbolListCtrl::OnRightClick(wxListEvent& event)
|
||||
{
|
||||
long selected = GetFirstSelected();
|
||||
if (selected == wxNOT_FOUND)
|
||||
if (selected == wxNOT_FOUND || selected >= static_cast<long>(m_visible_items.size()))
|
||||
return;
|
||||
auto text = GetItemText(selected, ColumnAddress);
|
||||
text = "0x" + text;
|
||||
#if BOOST_OS_WINDOWS
|
||||
if (OpenClipboard(nullptr))
|
||||
if (wxClipboard::Get()->Open())
|
||||
{
|
||||
EmptyClipboard();
|
||||
const HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, text.size()+1);
|
||||
if (hGlobal)
|
||||
{
|
||||
memcpy(GlobalLock(hGlobal), text.c_str(), text.size() + 1);
|
||||
GlobalUnlock(hGlobal);
|
||||
|
||||
SetClipboardData(CF_TEXT, hGlobal);
|
||||
GlobalFree(hGlobal);
|
||||
}
|
||||
CloseClipboard();
|
||||
wxClipboard::Get()->SetData(new wxTextDataObject(wxString::Format("0x%08x", m_visible_items[selected]->first)));
|
||||
wxClipboard::Get()->Close();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SymbolListCtrl::RebuildVisibleItems()
|
||||
{
|
||||
m_visible_items.clear();
|
||||
m_visible_items.reserve(m_data.size());
|
||||
const bool has_filter = !m_list_filter.IsEmpty();
|
||||
for (auto it = m_data.cbegin(); it != m_data.cend(); ++it)
|
||||
{
|
||||
if (has_filter && !it->second.searchName.Contains(m_list_filter))
|
||||
continue;
|
||||
|
||||
m_visible_items.emplace_back(it);
|
||||
}
|
||||
|
||||
SetItemCount(static_cast<long>(m_visible_items.size()));
|
||||
if (!m_visible_items.empty())
|
||||
{
|
||||
const auto top_item = std::min<long>(GetTopItem(), static_cast<long>(m_visible_items.size() - 1));
|
||||
RefreshItems(top_item, std::min<long>(static_cast<long>(m_visible_items.size() - 1), top_item + GetCountPerPage() + 1));
|
||||
}
|
||||
else
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void SymbolListCtrl::ChangeListFilter(wxString filter)
|
||||
{
|
||||
m_list_filter = filter.MakeLower();
|
||||
|
||||
size_t visible_entries = m_data.size();
|
||||
for (auto& [address, symbol] : m_data)
|
||||
{
|
||||
if (m_list_filter.IsEmpty())
|
||||
symbol.visible = true;
|
||||
else if (symbol.searchName.Contains(m_list_filter))
|
||||
symbol.visible = true;
|
||||
else
|
||||
{
|
||||
visible_entries--;
|
||||
symbol.visible = false;
|
||||
}
|
||||
}
|
||||
SetItemCount(visible_entries);
|
||||
if (visible_entries > 0)
|
||||
RefreshItems(GetTopItem(), std::min<long>(visible_entries - 1, GetTopItem() + GetCountPerPage() + 1));
|
||||
RebuildVisibleItems();
|
||||
}
|
||||
|
||||
@ -10,22 +10,23 @@ public:
|
||||
|
||||
void ChangeListFilter(wxString filter);
|
||||
|
||||
private:
|
||||
private:
|
||||
struct SymbolItem {
|
||||
SymbolItem() = default;
|
||||
SymbolItem(wxString name, wxString libName, wxString searchName, bool visible) : name(name), libName(libName), searchName(searchName), visible(visible) {}
|
||||
|
||||
SymbolItem() = default;
|
||||
SymbolItem(const wxString& name, const wxString& libName, const wxString& searchName) : name(name), libName(libName), searchName(searchName) {}
|
||||
|
||||
wxString name;
|
||||
wxString libName;
|
||||
wxString searchName;
|
||||
bool visible;
|
||||
};
|
||||
using SymbolMap = std::map<MPTR, SymbolItem>;
|
||||
|
||||
std::map<MPTR, SymbolItem> m_data;
|
||||
SymbolMap m_data;
|
||||
wxString m_list_filter;
|
||||
std::vector<SymbolMap::const_iterator> m_visible_items;
|
||||
|
||||
wxString OnGetItemText(long item, long column) const;
|
||||
wxString OnGetItemText(long item, long column) const override;
|
||||
void RebuildVisibleItems();
|
||||
void OnLeftDClick(wxListEvent& event);
|
||||
void OnRightClick(wxListEvent& event);
|
||||
};
|
||||
|
||||
@ -244,7 +244,7 @@ void TextureRelationViewerWindow::_setTextureRelationListItemTexture(wxListCtrl*
|
||||
uiList->SetItem(rowIndex, columnIndex, texInfo->mipLevels == 1 ? "1 mip" : wxString::Format("%d mips", texInfo->mipLevels));
|
||||
columnIndex++;
|
||||
// last access
|
||||
uiList->SetItem(rowIndex, columnIndex, wxString::Format("%lus", (GetTickCount() - texInfo->lastAccessTick + 499) / 1000));
|
||||
uiList->SetItem(rowIndex, columnIndex, wxString::Format("%uus", (GetTickCount() - texInfo->lastAccessTick + 499) / 1000));
|
||||
columnIndex++;
|
||||
// overwrite resolution
|
||||
wxString overwriteResLabel;
|
||||
|
||||
@ -696,7 +696,7 @@ std::shared_ptr<VPADController> InputManager::get_vpad_controller(size_t index)
|
||||
return {};
|
||||
|
||||
std::shared_lock lock(m_mutex);
|
||||
return std::static_pointer_cast<VPADController>(m_vpad[index]);
|
||||
return std::dynamic_pointer_cast<VPADController>(m_vpad[index]);
|
||||
}
|
||||
|
||||
std::shared_ptr<WPADController> InputManager::get_wpad_controller(size_t index) const
|
||||
@ -705,7 +705,7 @@ std::shared_ptr<WPADController> InputManager::get_wpad_controller(size_t index)
|
||||
return {};
|
||||
|
||||
std::shared_lock lock(m_mutex);
|
||||
return std::static_pointer_cast<WPADController>(m_wpad[index]);
|
||||
return std::dynamic_pointer_cast<WPADController>(m_wpad[index]);
|
||||
}
|
||||
|
||||
std::pair<size_t, size_t> InputManager::get_controller_count() const
|
||||
|
||||
@ -263,6 +263,7 @@ void EmulatedController::clear_controllers()
|
||||
|
||||
float EmulatedController::get_axis_value(uint64 mapping) const
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
const auto it = m_mappings.find(mapping);
|
||||
if (it != m_mappings.cend())
|
||||
{
|
||||
@ -276,6 +277,7 @@ float EmulatedController::get_axis_value(uint64 mapping) const
|
||||
|
||||
bool EmulatedController::is_mapping_down(uint64 mapping) const
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
const auto it = m_mappings.find(mapping);
|
||||
if (it != m_mappings.cend())
|
||||
{
|
||||
@ -288,6 +290,7 @@ bool EmulatedController::is_mapping_down(uint64 mapping) const
|
||||
|
||||
std::string EmulatedController::get_mapping_name(uint64 mapping) const
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
const auto it = m_mappings.find(mapping);
|
||||
if (it != m_mappings.cend())
|
||||
{
|
||||
@ -301,6 +304,7 @@ std::string EmulatedController::get_mapping_name(uint64 mapping) const
|
||||
|
||||
std::shared_ptr<ControllerBase> EmulatedController::get_mapping_controller(uint64 mapping) const
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
const auto it = m_mappings.find(mapping);
|
||||
if (it != m_mappings.cend())
|
||||
{
|
||||
@ -314,17 +318,20 @@ std::shared_ptr<ControllerBase> EmulatedController::get_mapping_controller(uint6
|
||||
|
||||
void EmulatedController::delete_mapping(uint64 mapping)
|
||||
{
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_mappings.erase(mapping);
|
||||
}
|
||||
|
||||
void EmulatedController::clear_mappings()
|
||||
{
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_mappings.clear();
|
||||
}
|
||||
|
||||
void EmulatedController::set_mapping(uint64 mapping, const std::shared_ptr<ControllerBase>& controller,
|
||||
uint64 button)
|
||||
{
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_mappings[mapping] = { controller, button };
|
||||
}
|
||||
|
||||
|
||||
@ -76,7 +76,7 @@
|
||||
},
|
||||
{
|
||||
"name": "sdl3",
|
||||
"version": "3.4.2"
|
||||
"version": "3.4.10"
|
||||
},
|
||||
{
|
||||
"name": "wxwidgets",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user