mirror of
https://github.com/Retropex/dolphin.git
synced 2025-06-05 17:02:32 +02:00

This fixes a problem I was having where using frame advance with the debugger open would frequently cause panic alerts about invalid addresses due to the CPU thread changing MSR.DR while the host thread was trying to access memory. To aid in tracking down all the places where we weren't properly locking the CPU, I've created a new type (in Core.h) that you have to pass as a reference or pointer to functions that require running as the CPU thread.
113 lines
2.5 KiB
C++
113 lines
2.5 KiB
C++
// Copyright 2015 Dolphin Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include "Core/MemoryWatcher.h"
|
|
|
|
#include <cstring>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <unistd.h>
|
|
|
|
#include "Common/FileUtil.h"
|
|
#include "Core/HW/SystemTimers.h"
|
|
#include "Core/PowerPC/MMU.h"
|
|
|
|
MemoryWatcher::MemoryWatcher()
|
|
{
|
|
m_running = false;
|
|
if (!LoadAddresses(File::GetUserPath(F_MEMORYWATCHERLOCATIONS_IDX)))
|
|
return;
|
|
if (!OpenSocket(File::GetUserPath(F_MEMORYWATCHERSOCKET_IDX)))
|
|
return;
|
|
m_running = true;
|
|
}
|
|
|
|
MemoryWatcher::~MemoryWatcher()
|
|
{
|
|
if (!m_running)
|
|
return;
|
|
|
|
m_running = false;
|
|
close(m_fd);
|
|
}
|
|
|
|
bool MemoryWatcher::LoadAddresses(const std::string& path)
|
|
{
|
|
std::ifstream locations;
|
|
File::OpenFStream(locations, path, std::ios_base::in);
|
|
if (!locations)
|
|
return false;
|
|
|
|
std::string line;
|
|
while (std::getline(locations, line))
|
|
ParseLine(line);
|
|
|
|
return !m_values.empty();
|
|
}
|
|
|
|
void MemoryWatcher::ParseLine(const std::string& line)
|
|
{
|
|
m_values[line] = 0;
|
|
m_addresses[line] = std::vector<u32>();
|
|
|
|
std::istringstream offsets(line);
|
|
offsets >> std::hex;
|
|
u32 offset;
|
|
while (offsets >> offset)
|
|
m_addresses[line].push_back(offset);
|
|
}
|
|
|
|
bool MemoryWatcher::OpenSocket(const std::string& path)
|
|
{
|
|
m_addr.sun_family = AF_UNIX;
|
|
strncpy(m_addr.sun_path, path.c_str(), sizeof(m_addr.sun_path) - 1);
|
|
|
|
m_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
|
return m_fd >= 0;
|
|
}
|
|
|
|
u32 MemoryWatcher::ChasePointer(const Core::CPUThreadGuard& guard, const std::string& line)
|
|
{
|
|
u32 value = 0;
|
|
for (u32 offset : m_addresses[line])
|
|
{
|
|
value = PowerPC::HostRead_U32(guard, value + offset);
|
|
if (!PowerPC::HostIsRAMAddress(guard, value))
|
|
break;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
std::string MemoryWatcher::ComposeMessages(const Core::CPUThreadGuard& guard)
|
|
{
|
|
std::ostringstream message_stream;
|
|
message_stream << std::hex;
|
|
|
|
for (auto& entry : m_values)
|
|
{
|
|
std::string address = entry.first;
|
|
u32& current_value = entry.second;
|
|
|
|
u32 new_value = ChasePointer(guard, address);
|
|
if (new_value != current_value)
|
|
{
|
|
// Update the value
|
|
current_value = new_value;
|
|
message_stream << address << '\n' << new_value << '\n';
|
|
}
|
|
}
|
|
|
|
return message_stream.str();
|
|
}
|
|
|
|
void MemoryWatcher::Step(const Core::CPUThreadGuard& guard)
|
|
{
|
|
if (!m_running)
|
|
return;
|
|
|
|
std::string message = ComposeMessages(guard);
|
|
sendto(m_fd, message.c_str(), message.size() + 1, 0, reinterpret_cast<sockaddr*>(&m_addr),
|
|
sizeof(m_addr));
|
|
}
|