Merge pull request #11554 from JosJuice/host-lock-cpu

DolphinQt: Properly lock CPU before accessing emulated memory
This commit is contained in:
Scott Mansell 2023-02-13 16:08:36 +13:00 committed by GitHub
commit a4729a026f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
79 changed files with 1799 additions and 1187 deletions

View File

@ -122,14 +122,14 @@ InstructionAttributes CodeTrace::GetInstructionAttributes(const TraceOutput& ins
return tmp_attributes; return tmp_attributes;
} }
TraceOutput CodeTrace::SaveCurrentInstruction() const TraceOutput CodeTrace::SaveCurrentInstruction(const Core::CPUThreadGuard* guard) const
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState(); auto& ppc_state = system.GetPPCState();
// Quickly save instruction and memory target for fast logging. // Quickly save instruction and memory target for fast logging.
TraceOutput output; TraceOutput output;
const std::string instr = PowerPC::debug_interface.Disassemble(ppc_state.pc); const std::string instr = PowerPC::debug_interface.Disassemble(guard, ppc_state.pc);
output.instruction = instr; output.instruction = instr;
output.address = ppc_state.pc; output.address = ppc_state.pc;
@ -139,14 +139,15 @@ TraceOutput CodeTrace::SaveCurrentInstruction() const
return output; return output;
} }
AutoStepResults CodeTrace::AutoStepping(bool continue_previous, AutoStop stop_on) AutoStepResults CodeTrace::AutoStepping(const Core::CPUThreadGuard& guard, bool continue_previous,
AutoStop stop_on)
{ {
AutoStepResults results; AutoStepResults results;
if (!CPU::IsStepping() || m_recording) if (m_recording)
return results; return results;
TraceOutput pc_instr = SaveCurrentInstruction(); TraceOutput pc_instr = SaveCurrentInstruction(&guard);
const InstructionAttributes instr = GetInstructionAttributes(pc_instr); const InstructionAttributes instr = GetInstructionAttributes(pc_instr);
// Not an instruction we should start autostepping from (ie branches). // Not an instruction we should start autostepping from (ie branches).
@ -187,7 +188,6 @@ AutoStepResults CodeTrace::AutoStepping(bool continue_previous, AutoStop stop_on
else if (stop_on == AutoStop::Changed) else if (stop_on == AutoStop::Changed)
stop_condition = HitType::ACTIVE; stop_condition = HitType::ACTIVE;
CPU::PauseAndLock(true, false);
PowerPC::breakpoints.ClearAllTemporary(); PowerPC::breakpoints.ClearAllTemporary();
using clock = std::chrono::steady_clock; using clock = std::chrono::steady_clock;
clock::time_point timeout = clock::now() + std::chrono::seconds(4); clock::time_point timeout = clock::now() + std::chrono::seconds(4);
@ -199,7 +199,7 @@ AutoStepResults CodeTrace::AutoStepping(bool continue_previous, AutoStop stop_on
{ {
PowerPC::SingleStep(); PowerPC::SingleStep();
pc_instr = SaveCurrentInstruction(); pc_instr = SaveCurrentInstruction(&guard);
hit = TraceLogic(pc_instr); hit = TraceLogic(pc_instr);
results.count += 1; results.count += 1;
} while (clock::now() < timeout && hit < stop_condition && } while (clock::now() < timeout && hit < stop_condition &&
@ -210,7 +210,6 @@ AutoStepResults CodeTrace::AutoStepping(bool continue_previous, AutoStop stop_on
results.timed_out = true; results.timed_out = true;
PowerPC::SetMode(old_mode); PowerPC::SetMode(old_mode);
CPU::PauseAndLock(false, false);
m_recording = false; m_recording = false;
results.reg_tracked = m_reg_autotrack; results.reg_tracked = m_reg_autotrack;

View File

@ -10,6 +10,11 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
namespace Core
{
class CPUThreadGuard;
}
struct InstructionAttributes struct InstructionAttributes
{ {
u32 address = 0; u32 address = 0;
@ -63,11 +68,12 @@ public:
}; };
void SetRegTracked(const std::string& reg); void SetRegTracked(const std::string& reg);
AutoStepResults AutoStepping(bool continue_previous = false, AutoStop stop_on = AutoStop::Always); AutoStepResults AutoStepping(const Core::CPUThreadGuard& guard, bool continue_previous = false,
AutoStop stop_on = AutoStop::Always);
private: private:
InstructionAttributes GetInstructionAttributes(const TraceOutput& line) const; InstructionAttributes GetInstructionAttributes(const TraceOutput& line) const;
TraceOutput SaveCurrentInstruction() const; TraceOutput SaveCurrentInstruction(const Core::CPUThreadGuard* guard) const;
HitType TraceLogic(const TraceOutput& current_instr, bool first_hit = false); HitType TraceLogic(const TraceOutput& current_instr, bool first_hit = false);
bool m_recording = false; bool m_recording = false;

View File

@ -23,36 +23,37 @@ MemoryPatch::MemoryPatch(u32 address_, u32 value_)
MemoryPatches::MemoryPatches() = default; MemoryPatches::MemoryPatches() = default;
MemoryPatches::~MemoryPatches() = default; MemoryPatches::~MemoryPatches() = default;
void MemoryPatches::SetPatch(u32 address, u32 value) void MemoryPatches::SetPatch(const Core::CPUThreadGuard& guard, u32 address, u32 value)
{ {
const std::size_t index = m_patches.size(); const std::size_t index = m_patches.size();
m_patches.emplace_back(address, value); m_patches.emplace_back(address, value);
Patch(index); Patch(guard, index);
} }
void MemoryPatches::SetPatch(u32 address, std::vector<u8> value) void MemoryPatches::SetPatch(const Core::CPUThreadGuard& guard, u32 address, std::vector<u8> value)
{ {
UnsetPatch(address); UnsetPatch(guard, address);
const std::size_t index = m_patches.size(); const std::size_t index = m_patches.size();
m_patches.emplace_back(address, std::move(value)); m_patches.emplace_back(address, std::move(value));
Patch(index); Patch(guard, index);
} }
void MemoryPatches::SetFramePatch(u32 address, u32 value) void MemoryPatches::SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, u32 value)
{ {
const std::size_t index = m_patches.size(); const std::size_t index = m_patches.size();
m_patches.emplace_back(address, value); m_patches.emplace_back(address, value);
m_patches.back().type = MemoryPatch::ApplyType::EachFrame; m_patches.back().type = MemoryPatch::ApplyType::EachFrame;
Patch(index); Patch(guard, index);
} }
void MemoryPatches::SetFramePatch(u32 address, std::vector<u8> value) void MemoryPatches::SetFramePatch(const Core::CPUThreadGuard& guard, u32 address,
std::vector<u8> value)
{ {
UnsetPatch(address); UnsetPatch(guard, address);
const std::size_t index = m_patches.size(); const std::size_t index = m_patches.size();
m_patches.emplace_back(address, std::move(value)); m_patches.emplace_back(address, std::move(value));
m_patches.back().type = MemoryPatch::ApplyType::EachFrame; m_patches.back().type = MemoryPatch::ApplyType::EachFrame;
Patch(index); Patch(guard, index);
} }
const std::vector<MemoryPatch>& MemoryPatches::GetPatches() const const std::vector<MemoryPatch>& MemoryPatches::GetPatches() const
@ -60,7 +61,7 @@ const std::vector<MemoryPatch>& MemoryPatches::GetPatches() const
return m_patches; return m_patches;
} }
void MemoryPatches::UnsetPatch(u32 address) void MemoryPatches::UnsetPatch(const Core::CPUThreadGuard& guard, u32 address)
{ {
const auto it = std::find_if(m_patches.begin(), m_patches.end(), const auto it = std::find_if(m_patches.begin(), m_patches.end(),
[address](const auto& patch) { return patch.address == address; }); [address](const auto& patch) { return patch.address == address; });
@ -69,23 +70,23 @@ void MemoryPatches::UnsetPatch(u32 address)
return; return;
const std::size_t index = std::distance(m_patches.begin(), it); const std::size_t index = std::distance(m_patches.begin(), it);
RemovePatch(index); RemovePatch(guard, index);
} }
void MemoryPatches::EnablePatch(std::size_t index) void MemoryPatches::EnablePatch(const Core::CPUThreadGuard& guard, std::size_t index)
{ {
if (m_patches[index].is_enabled == MemoryPatch::State::Enabled) if (m_patches[index].is_enabled == MemoryPatch::State::Enabled)
return; return;
m_patches[index].is_enabled = MemoryPatch::State::Enabled; m_patches[index].is_enabled = MemoryPatch::State::Enabled;
Patch(index); Patch(guard, index);
} }
void MemoryPatches::DisablePatch(std::size_t index) void MemoryPatches::DisablePatch(const Core::CPUThreadGuard& guard, std::size_t index)
{ {
if (m_patches[index].is_enabled == MemoryPatch::State::Disabled) if (m_patches[index].is_enabled == MemoryPatch::State::Disabled)
return; return;
m_patches[index].is_enabled = MemoryPatch::State::Disabled; m_patches[index].is_enabled = MemoryPatch::State::Disabled;
Patch(index); Patch(guard, index);
} }
bool MemoryPatches::HasEnabledPatch(u32 address) const bool MemoryPatches::HasEnabledPatch(u32 address) const
@ -95,19 +96,19 @@ bool MemoryPatches::HasEnabledPatch(u32 address) const
}); });
} }
void MemoryPatches::RemovePatch(std::size_t index) void MemoryPatches::RemovePatch(const Core::CPUThreadGuard& guard, std::size_t index)
{ {
DisablePatch(index); DisablePatch(guard, index);
UnPatch(index); UnPatch(index);
m_patches.erase(m_patches.begin() + index); m_patches.erase(m_patches.begin() + index);
} }
void MemoryPatches::ClearPatches() void MemoryPatches::ClearPatches(const Core::CPUThreadGuard& guard)
{ {
const std::size_t size = m_patches.size(); const std::size_t size = m_patches.size();
for (std::size_t index = 0; index < size; ++index) for (std::size_t index = 0; index < size; ++index)
{ {
DisablePatch(index); DisablePatch(guard, index);
UnPatch(index); UnPatch(index);
} }
m_patches.clear(); m_patches.clear();

View File

@ -9,6 +9,11 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
namespace Core
{
class CPUThreadGuard;
}
namespace Common::Debug namespace Common::Debug
{ {
struct MemoryPatch struct MemoryPatch
@ -40,21 +45,21 @@ public:
MemoryPatches(); MemoryPatches();
virtual ~MemoryPatches(); virtual ~MemoryPatches();
void SetPatch(u32 address, u32 value); void SetPatch(const Core::CPUThreadGuard& guard, u32 address, u32 value);
void SetPatch(u32 address, std::vector<u8> value); void SetPatch(const Core::CPUThreadGuard& guard, u32 address, std::vector<u8> value);
void SetFramePatch(u32 address, u32 value); void SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, u32 value);
void SetFramePatch(u32 address, std::vector<u8> value); void SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, std::vector<u8> value);
const std::vector<MemoryPatch>& GetPatches() const; const std::vector<MemoryPatch>& GetPatches() const;
void UnsetPatch(u32 address); void UnsetPatch(const Core::CPUThreadGuard& guard, u32 address);
void EnablePatch(std::size_t index); void EnablePatch(const Core::CPUThreadGuard& guard, std::size_t index);
void DisablePatch(std::size_t index); void DisablePatch(const Core::CPUThreadGuard& guard, std::size_t index);
bool HasEnabledPatch(u32 address) const; bool HasEnabledPatch(u32 address) const;
void RemovePatch(std::size_t index); void RemovePatch(const Core::CPUThreadGuard& guard, std::size_t index);
void ClearPatches(); void ClearPatches(const Core::CPUThreadGuard& guard);
virtual void ApplyExistingPatch(std::size_t index) = 0; virtual void ApplyExistingPatch(const Core::CPUThreadGuard& guard, std::size_t index) = 0;
protected: protected:
virtual void Patch(std::size_t index) = 0; virtual void Patch(const Core::CPUThreadGuard& guard, std::size_t index) = 0;
virtual void UnPatch(std::size_t index) = 0; virtual void UnPatch(std::size_t index) = 0;
std::vector<MemoryPatch> m_patches; std::vector<MemoryPatch> m_patches;

View File

@ -11,6 +11,11 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
namespace Core
{
class CPUThreadGuard;
};
namespace Common::Debug namespace Common::Debug
{ {
struct PartialContext struct PartialContext
@ -41,7 +46,7 @@ public:
LWPThread, // devkitPro libogc thread LWPThread, // devkitPro libogc thread
}; };
virtual PartialContext GetContext() const = 0; virtual PartialContext GetContext(const Core::CPUThreadGuard& guard) const = 0;
virtual u32 GetAddress() const = 0; virtual u32 GetAddress() const = 0;
virtual u16 GetState() const = 0; virtual u16 GetState() const = 0;
virtual bool IsSuspended() const = 0; virtual bool IsSuspended() const = 0;
@ -53,8 +58,8 @@ public:
virtual std::size_t GetStackSize() const = 0; virtual std::size_t GetStackSize() const = 0;
virtual s32 GetErrno() const = 0; virtual s32 GetErrno() const = 0;
// Implementation specific, used to store arbitrary data // Implementation specific, used to store arbitrary data
virtual std::string GetSpecific() const = 0; virtual std::string GetSpecific(const Core::CPUThreadGuard& guard) const = 0;
virtual bool IsValid() const = 0; virtual bool IsValid(const Core::CPUThreadGuard& guard) const = 0;
}; };
using Threads = std::vector<std::unique_ptr<ThreadView>>; using Threads = std::vector<std::unique_ptr<ThreadView>>;

View File

@ -16,6 +16,11 @@ struct MemoryPatch;
struct Watch; struct Watch;
} // namespace Common::Debug } // namespace Common::Debug
namespace Core
{
class CPUThreadGuard;
} // namespace Core
namespace Common namespace Common
{ {
class DebugInterface class DebugInterface
@ -42,24 +47,29 @@ public:
virtual void ClearWatches() = 0; virtual void ClearWatches() = 0;
// Memory Patches // Memory Patches
virtual void SetPatch(u32 address, u32 value) = 0; virtual void SetPatch(const Core::CPUThreadGuard& guard, u32 address, u32 value) = 0;
virtual void SetPatch(u32 address, std::vector<u8> value) = 0; virtual void SetPatch(const Core::CPUThreadGuard& guard, u32 address, std::vector<u8> value) = 0;
virtual void SetFramePatch(u32 address, u32 value) = 0; virtual void SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, u32 value) = 0;
virtual void SetFramePatch(u32 address, std::vector<u8> value) = 0; virtual void SetFramePatch(const Core::CPUThreadGuard& guard, u32 address,
std::vector<u8> value) = 0;
virtual const std::vector<Debug::MemoryPatch>& GetPatches() const = 0; virtual const std::vector<Debug::MemoryPatch>& GetPatches() const = 0;
virtual void UnsetPatch(u32 address) = 0; virtual void UnsetPatch(const Core::CPUThreadGuard& guard, u32 address) = 0;
virtual void EnablePatch(std::size_t index) = 0; virtual void EnablePatch(const Core::CPUThreadGuard& guard, std::size_t index) = 0;
virtual void DisablePatch(std::size_t index) = 0; virtual void DisablePatch(const Core::CPUThreadGuard& guard, std::size_t index) = 0;
virtual bool HasEnabledPatch(u32 address) const = 0; virtual bool HasEnabledPatch(u32 address) const = 0;
virtual void RemovePatch(std::size_t index) = 0; virtual void RemovePatch(const Core::CPUThreadGuard& guard, std::size_t index) = 0;
virtual void ClearPatches() = 0; virtual void ClearPatches(const Core::CPUThreadGuard& guard) = 0;
virtual void ApplyExistingPatch(std::size_t index) = 0; virtual void ApplyExistingPatch(const Core::CPUThreadGuard& guard, std::size_t index) = 0;
// Threads // Threads
virtual Debug::Threads GetThreads() const = 0; virtual Debug::Threads GetThreads(const Core::CPUThreadGuard& guard) const = 0;
virtual std::string Disassemble(u32 /*address*/) const { return "NODEBUGGER"; } virtual std::string Disassemble(const Core::CPUThreadGuard* /*guard*/, u32 /*address*/) const
virtual std::string GetRawMemoryString(int /*memory*/, u32 /*address*/) const {
return "NODEBUGGER";
}
virtual std::string GetRawMemoryString(const Core::CPUThreadGuard& /*guard*/, int /*memory*/,
u32 /*address*/) const
{ {
return "NODEBUGGER"; return "NODEBUGGER";
} }
@ -72,10 +82,20 @@ public:
virtual void ClearAllMemChecks() {} virtual void ClearAllMemChecks() {}
virtual bool IsMemCheck(u32 /*address*/, size_t /*size*/) const { return false; } virtual bool IsMemCheck(u32 /*address*/, size_t /*size*/) const { return false; }
virtual void ToggleMemCheck(u32 /*address*/, bool /*read*/, bool /*write*/, bool /*log*/) {} virtual void ToggleMemCheck(u32 /*address*/, bool /*read*/, bool /*write*/, bool /*log*/) {}
virtual u32 ReadMemory(u32 /*address*/) const { return 0; } virtual u32 ReadMemory(const Core::CPUThreadGuard& /*guard*/, u32 /*address*/) const { return 0; }
virtual void WriteExtraMemory(int /*memory*/, u32 /*value*/, u32 /*address*/) {} virtual void WriteExtraMemory(const Core::CPUThreadGuard& /*guard*/, int /*memory*/,
virtual u32 ReadExtraMemory(int /*memory*/, u32 /*address*/) const { return 0; } u32 /*value*/, u32 /*address*/)
virtual u32 ReadInstruction(u32 /*address*/) const { return 0; } {
}
virtual u32 ReadExtraMemory(const Core::CPUThreadGuard& /*guard*/, int /*memory*/,
u32 /*address*/) const
{
return 0;
}
virtual u32 ReadInstruction(const Core::CPUThreadGuard& /*guard*/, u32 /*address*/) const
{
return 0;
}
virtual std::optional<u32> virtual std::optional<u32>
GetMemoryAddressFromInstruction(const std::string& /*instruction*/) const GetMemoryAddressFromInstruction(const std::string& /*instruction*/) const
{ {
@ -85,8 +105,11 @@ public:
virtual void SetPC(u32 /*address*/) {} virtual void SetPC(u32 /*address*/) {}
virtual void Step() {} virtual void Step() {}
virtual void RunToBreakpoint() {} virtual void RunToBreakpoint() {}
virtual u32 GetColor(u32 /*address*/) const { return 0xFFFFFFFF; } virtual u32 GetColor(const Core::CPUThreadGuard* /*guard*/, u32 /*address*/) const
{
return 0xFFFFFFFF;
}
virtual std::string GetDescription(u32 /*address*/) const = 0; virtual std::string GetDescription(u32 /*address*/) const = 0;
virtual void Clear() = 0; virtual void Clear(const Core::CPUThreadGuard& guard) = 0;
}; };
} // namespace Common } // namespace Common

View File

@ -15,6 +15,11 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
namespace Core
{
class CPUThreadGuard;
}
namespace Common namespace Common
{ {
struct SCall struct SCall
@ -68,7 +73,7 @@ public:
virtual ~SymbolDB(); virtual ~SymbolDB();
virtual Symbol* GetSymbolFromAddr(u32 addr) { return nullptr; } virtual Symbol* GetSymbolFromAddr(u32 addr) { return nullptr; }
virtual Symbol* AddFunction(u32 start_addr) { return nullptr; } virtual Symbol* AddFunction(const Core::CPUThreadGuard& guard, u32 start_addr) { return nullptr; }
void AddCompleteSymbol(const Symbol& symbol); void AddCompleteSymbol(const Symbol& symbol);
Symbol* GetSymbolFromName(std::string_view name); Symbol* GetSymbolFromName(std::string_view name);

View File

@ -358,7 +358,8 @@ bool IsSelfLogging()
// ---------------------- // ----------------------
// Code Functions // Code Functions
static bool Subtype_RamWriteAndFill(const ARAddr& addr, const u32 data) static bool Subtype_RamWriteAndFill(const Core::CPUThreadGuard& guard, const ARAddr& addr,
const u32 data)
{ {
const u32 new_addr = addr.GCAddress(); const u32 new_addr = addr.GCAddress();
@ -374,7 +375,7 @@ static bool Subtype_RamWriteAndFill(const ARAddr& addr, const u32 data)
const u32 repeat = data >> 8; const u32 repeat = data >> 8;
for (u32 i = 0; i <= repeat; ++i) for (u32 i = 0; i <= repeat; ++i)
{ {
PowerPC::HostWrite_U8(data & 0xFF, new_addr + i); PowerPC::HostWrite_U8(guard, data & 0xFF, new_addr + i);
LogInfo("Wrote {:08x} to address {:08x}", data & 0xFF, new_addr + i); LogInfo("Wrote {:08x} to address {:08x}", data & 0xFF, new_addr + i);
} }
LogInfo("--------"); LogInfo("--------");
@ -388,7 +389,7 @@ static bool Subtype_RamWriteAndFill(const ARAddr& addr, const u32 data)
const u32 repeat = data >> 16; const u32 repeat = data >> 16;
for (u32 i = 0; i <= repeat; ++i) for (u32 i = 0; i <= repeat; ++i)
{ {
PowerPC::HostWrite_U16(data & 0xFFFF, new_addr + i * 2); PowerPC::HostWrite_U16(guard, data & 0xFFFF, new_addr + i * 2);
LogInfo("Wrote {:08x} to address {:08x}", data & 0xFFFF, new_addr + i * 2); LogInfo("Wrote {:08x} to address {:08x}", data & 0xFFFF, new_addr + i * 2);
} }
LogInfo("--------"); LogInfo("--------");
@ -399,7 +400,7 @@ static bool Subtype_RamWriteAndFill(const ARAddr& addr, const u32 data)
case DATATYPE_32BIT: // Dword write case DATATYPE_32BIT: // Dword write
LogInfo("32-bit Write"); LogInfo("32-bit Write");
LogInfo("--------"); LogInfo("--------");
PowerPC::HostWrite_U32(data, new_addr); PowerPC::HostWrite_U32(guard, data, new_addr);
LogInfo("Wrote {:08x} to address {:08x}", data, new_addr); LogInfo("Wrote {:08x} to address {:08x}", data, new_addr);
LogInfo("--------"); LogInfo("--------");
break; break;
@ -415,10 +416,11 @@ static bool Subtype_RamWriteAndFill(const ARAddr& addr, const u32 data)
return true; return true;
} }
static bool Subtype_WriteToPointer(const ARAddr& addr, const u32 data) static bool Subtype_WriteToPointer(const Core::CPUThreadGuard& guard, const ARAddr& addr,
const u32 data)
{ {
const u32 new_addr = addr.GCAddress(); const u32 new_addr = addr.GCAddress();
const u32 ptr = PowerPC::HostRead_U32(new_addr); const u32 ptr = PowerPC::HostRead_U32(guard, new_addr);
LogInfo("Hardware Address: {:08x}", new_addr); LogInfo("Hardware Address: {:08x}", new_addr);
LogInfo("Size: {:08x}", addr.size); LogInfo("Size: {:08x}", addr.size);
@ -434,7 +436,7 @@ static bool Subtype_WriteToPointer(const ARAddr& addr, const u32 data)
LogInfo("Pointer: {:08x}", ptr); LogInfo("Pointer: {:08x}", ptr);
LogInfo("Byte: {:08x}", thebyte); LogInfo("Byte: {:08x}", thebyte);
LogInfo("Offset: {:08x}", offset); LogInfo("Offset: {:08x}", offset);
PowerPC::HostWrite_U8(thebyte, ptr + offset); PowerPC::HostWrite_U8(guard, thebyte, ptr + offset);
LogInfo("Wrote {:08x} to address {:08x}", thebyte, ptr + offset); LogInfo("Wrote {:08x} to address {:08x}", thebyte, ptr + offset);
LogInfo("--------"); LogInfo("--------");
break; break;
@ -449,7 +451,7 @@ static bool Subtype_WriteToPointer(const ARAddr& addr, const u32 data)
LogInfo("Pointer: {:08x}", ptr); LogInfo("Pointer: {:08x}", ptr);
LogInfo("Byte: {:08x}", theshort); LogInfo("Byte: {:08x}", theshort);
LogInfo("Offset: {:08x}", offset); LogInfo("Offset: {:08x}", offset);
PowerPC::HostWrite_U16(theshort, ptr + offset); PowerPC::HostWrite_U16(guard, theshort, ptr + offset);
LogInfo("Wrote {:08x} to address {:08x}", theshort, ptr + offset); LogInfo("Wrote {:08x} to address {:08x}", theshort, ptr + offset);
LogInfo("--------"); LogInfo("--------");
break; break;
@ -459,7 +461,7 @@ static bool Subtype_WriteToPointer(const ARAddr& addr, const u32 data)
case DATATYPE_32BIT: case DATATYPE_32BIT:
LogInfo("Write 32-bit to pointer"); LogInfo("Write 32-bit to pointer");
LogInfo("--------"); LogInfo("--------");
PowerPC::HostWrite_U32(data, ptr); PowerPC::HostWrite_U32(guard, data, ptr);
LogInfo("Wrote {:08x} to address {:08x}", data, ptr); LogInfo("Wrote {:08x} to address {:08x}", data, ptr);
LogInfo("--------"); LogInfo("--------");
break; break;
@ -474,7 +476,7 @@ static bool Subtype_WriteToPointer(const ARAddr& addr, const u32 data)
return true; return true;
} }
static bool Subtype_AddCode(const ARAddr& addr, const u32 data) static bool Subtype_AddCode(const Core::CPUThreadGuard& guard, const ARAddr& addr, const u32 data)
{ {
// Used to increment/decrement a value in memory // Used to increment/decrement a value in memory
const u32 new_addr = addr.GCAddress(); const u32 new_addr = addr.GCAddress();
@ -487,24 +489,24 @@ static bool Subtype_AddCode(const ARAddr& addr, const u32 data)
case DATATYPE_8BIT: case DATATYPE_8BIT:
LogInfo("8-bit Add"); LogInfo("8-bit Add");
LogInfo("--------"); LogInfo("--------");
PowerPC::HostWrite_U8(PowerPC::HostRead_U8(new_addr) + data, new_addr); PowerPC::HostWrite_U8(guard, PowerPC::HostRead_U8(guard, new_addr) + data, new_addr);
LogInfo("Wrote {:02x} to address {:08x}", PowerPC::HostRead_U8(new_addr), new_addr); LogInfo("Wrote {:02x} to address {:08x}", PowerPC::HostRead_U8(guard, new_addr), new_addr);
LogInfo("--------"); LogInfo("--------");
break; break;
case DATATYPE_16BIT: case DATATYPE_16BIT:
LogInfo("16-bit Add"); LogInfo("16-bit Add");
LogInfo("--------"); LogInfo("--------");
PowerPC::HostWrite_U16(PowerPC::HostRead_U16(new_addr) + data, new_addr); PowerPC::HostWrite_U16(guard, PowerPC::HostRead_U16(guard, new_addr) + data, new_addr);
LogInfo("Wrote {:04x} to address {:08x}", PowerPC::HostRead_U16(new_addr), new_addr); LogInfo("Wrote {:04x} to address {:08x}", PowerPC::HostRead_U16(guard, new_addr), new_addr);
LogInfo("--------"); LogInfo("--------");
break; break;
case DATATYPE_32BIT: case DATATYPE_32BIT:
LogInfo("32-bit Add"); LogInfo("32-bit Add");
LogInfo("--------"); LogInfo("--------");
PowerPC::HostWrite_U32(PowerPC::HostRead_U32(new_addr) + data, new_addr); PowerPC::HostWrite_U32(guard, PowerPC::HostRead_U32(guard, new_addr) + data, new_addr);
LogInfo("Wrote {:08x} to address {:08x}", PowerPC::HostRead_U32(new_addr), new_addr); LogInfo("Wrote {:08x} to address {:08x}", PowerPC::HostRead_U32(guard, new_addr), new_addr);
LogInfo("--------"); LogInfo("--------");
break; break;
@ -513,12 +515,12 @@ static bool Subtype_AddCode(const ARAddr& addr, const u32 data)
LogInfo("32-bit floating Add"); LogInfo("32-bit floating Add");
LogInfo("--------"); LogInfo("--------");
const u32 read = PowerPC::HostRead_U32(new_addr); const u32 read = PowerPC::HostRead_U32(guard, new_addr);
const float read_float = Common::BitCast<float>(read); const float read_float = Common::BitCast<float>(read);
// data contains an (unsigned?) integer value // data contains an (unsigned?) integer value
const float fread = read_float + static_cast<float>(data); const float fread = read_float + static_cast<float>(data);
const u32 newval = Common::BitCast<u32>(fread); const u32 newval = Common::BitCast<u32>(fread);
PowerPC::HostWrite_U32(newval, new_addr); PowerPC::HostWrite_U32(guard, newval, new_addr);
LogInfo("Old Value {:08x}", read); LogInfo("Old Value {:08x}", read);
LogInfo("Increment {:08x}", data); LogInfo("Increment {:08x}", data);
LogInfo("New value {:08x}", newval); LogInfo("New value {:08x}", newval);
@ -550,7 +552,8 @@ static bool Subtype_MasterCodeAndWriteToCCXXXXXX(const ARAddr& addr, const u32 d
} }
// This needs more testing // This needs more testing
static bool ZeroCode_FillAndSlide(const u32 val_last, const ARAddr& addr, const u32 data) static bool ZeroCode_FillAndSlide(const Core::CPUThreadGuard& guard, const u32 val_last,
const ARAddr& addr, const u32 data)
{ {
const u32 new_addr = ARAddr(val_last).GCAddress(); const u32 new_addr = ARAddr(val_last).GCAddress();
const u8 size = ARAddr(val_last).size; const u8 size = ARAddr(val_last).size;
@ -575,7 +578,7 @@ static bool ZeroCode_FillAndSlide(const u32 val_last, const ARAddr& addr, const
LogInfo("--------"); LogInfo("--------");
for (int i = 0; i < write_num; ++i) for (int i = 0; i < write_num; ++i)
{ {
PowerPC::HostWrite_U8(val & 0xFF, curr_addr); PowerPC::HostWrite_U8(guard, val & 0xFF, curr_addr);
curr_addr += addr_incr; curr_addr += addr_incr;
val += val_incr; val += val_incr;
LogInfo("Write {:08x} to address {:08x}", val & 0xFF, curr_addr); LogInfo("Write {:08x} to address {:08x}", val & 0xFF, curr_addr);
@ -591,7 +594,7 @@ static bool ZeroCode_FillAndSlide(const u32 val_last, const ARAddr& addr, const
LogInfo("--------"); LogInfo("--------");
for (int i = 0; i < write_num; ++i) for (int i = 0; i < write_num; ++i)
{ {
PowerPC::HostWrite_U16(val & 0xFFFF, curr_addr); PowerPC::HostWrite_U16(guard, val & 0xFFFF, curr_addr);
LogInfo("Write {:08x} to address {:08x}", val & 0xFFFF, curr_addr); LogInfo("Write {:08x} to address {:08x}", val & 0xFFFF, curr_addr);
curr_addr += addr_incr * 2; curr_addr += addr_incr * 2;
val += val_incr; val += val_incr;
@ -606,7 +609,7 @@ static bool ZeroCode_FillAndSlide(const u32 val_last, const ARAddr& addr, const
LogInfo("--------"); LogInfo("--------");
for (int i = 0; i < write_num; ++i) for (int i = 0; i < write_num; ++i)
{ {
PowerPC::HostWrite_U32(val, curr_addr); PowerPC::HostWrite_U32(guard, val, curr_addr);
LogInfo("Write {:08x} to address {:08x}", val, curr_addr); LogInfo("Write {:08x} to address {:08x}", val, curr_addr);
curr_addr += addr_incr * 4; curr_addr += addr_incr * 4;
val += val_incr; val += val_incr;
@ -629,7 +632,8 @@ static bool ZeroCode_FillAndSlide(const u32 val_last, const ARAddr& addr, const
// kenobi's "memory copy" Z-code. Requires an additional master code // kenobi's "memory copy" Z-code. Requires an additional master code
// on a real AR device. Documented here: // on a real AR device. Documented here:
// https://github.com/dolphin-emu/dolphin/wiki/GameCube-Action-Replay-Code-Types#type-z4-size-3--memory-copy // https://github.com/dolphin-emu/dolphin/wiki/GameCube-Action-Replay-Code-Types#type-z4-size-3--memory-copy
static bool ZeroCode_MemoryCopy(const u32 val_last, const ARAddr& addr, const u32 data) static bool ZeroCode_MemoryCopy(const Core::CPUThreadGuard& guard, const u32 val_last,
const ARAddr& addr, const u32 data)
{ {
const u32 addr_dest = val_last & ~0x06000000; const u32 addr_dest = val_last & ~0x06000000;
const u32 addr_src = addr.GCAddress(); const u32 addr_src = addr.GCAddress();
@ -646,14 +650,15 @@ static bool ZeroCode_MemoryCopy(const u32 val_last, const ARAddr& addr, const u3
{ // Memory Copy With Pointers Support { // Memory Copy With Pointers Support
LogInfo("Memory Copy With Pointers Support"); LogInfo("Memory Copy With Pointers Support");
LogInfo("--------"); LogInfo("--------");
const u32 ptr_dest = PowerPC::HostRead_U32(addr_dest); const u32 ptr_dest = PowerPC::HostRead_U32(guard, addr_dest);
LogInfo("Resolved Dest Address to: {:08x}", ptr_dest); LogInfo("Resolved Dest Address to: {:08x}", ptr_dest);
const u32 ptr_src = PowerPC::HostRead_U32(addr_src); const u32 ptr_src = PowerPC::HostRead_U32(guard, addr_src);
LogInfo("Resolved Src Address to: {:08x}", ptr_src); LogInfo("Resolved Src Address to: {:08x}", ptr_src);
for (int i = 0; i < num_bytes; ++i) for (int i = 0; i < num_bytes; ++i)
{ {
PowerPC::HostWrite_U8(PowerPC::HostRead_U8(ptr_src + i), ptr_dest + i); PowerPC::HostWrite_U8(guard, PowerPC::HostRead_U8(guard, ptr_src + i), ptr_dest + i);
LogInfo("Wrote {:08x} to address {:08x}", PowerPC::HostRead_U8(ptr_src + i), ptr_dest + i); LogInfo("Wrote {:08x} to address {:08x}", PowerPC::HostRead_U8(guard, ptr_src + i),
ptr_dest + i);
} }
LogInfo("--------"); LogInfo("--------");
} }
@ -663,8 +668,8 @@ static bool ZeroCode_MemoryCopy(const u32 val_last, const ARAddr& addr, const u3
LogInfo("--------"); LogInfo("--------");
for (int i = 0; i < num_bytes; ++i) for (int i = 0; i < num_bytes; ++i)
{ {
PowerPC::HostWrite_U8(PowerPC::HostRead_U8(addr_src + i), addr_dest + i); PowerPC::HostWrite_U8(guard, PowerPC::HostRead_U8(guard, addr_src + i), addr_dest + i);
LogInfo("Wrote {:08x} to address {:08x}", PowerPC::HostRead_U8(addr_src + i), LogInfo("Wrote {:08x} to address {:08x}", PowerPC::HostRead_U8(guard, addr_src + i),
addr_dest + i); addr_dest + i);
} }
LogInfo("--------"); LogInfo("--------");
@ -681,25 +686,25 @@ static bool ZeroCode_MemoryCopy(const u32 val_last, const ARAddr& addr, const u3
return true; return true;
} }
static bool NormalCode(const ARAddr& addr, const u32 data) static bool NormalCode(const Core::CPUThreadGuard& guard, const ARAddr& addr, const u32 data)
{ {
switch (addr.subtype) switch (addr.subtype)
{ {
case SUB_RAM_WRITE: // Ram write (and fill) case SUB_RAM_WRITE: // Ram write (and fill)
LogInfo("Doing Ram Write And Fill"); LogInfo("Doing Ram Write And Fill");
if (!Subtype_RamWriteAndFill(addr, data)) if (!Subtype_RamWriteAndFill(guard, addr, data))
return false; return false;
break; break;
case SUB_WRITE_POINTER: // Write to pointer case SUB_WRITE_POINTER: // Write to pointer
LogInfo("Doing Write To Pointer"); LogInfo("Doing Write To Pointer");
if (!Subtype_WriteToPointer(addr, data)) if (!Subtype_WriteToPointer(guard, addr, data))
return false; return false;
break; break;
case SUB_ADD_CODE: // Increment Value case SUB_ADD_CODE: // Increment Value
LogInfo("Doing Add Code"); LogInfo("Doing Add Code");
if (!Subtype_AddCode(addr, data)) if (!Subtype_AddCode(guard, addr, data))
return false; return false;
break; break;
@ -759,7 +764,8 @@ static bool CompareValues(const u32 val1, const u32 val2, const int type)
} }
} }
static bool ConditionalCode(const ARAddr& addr, const u32 data, int* const pSkipCount) static bool ConditionalCode(const Core::CPUThreadGuard& guard, const ARAddr& addr, const u32 data,
int* const pSkipCount)
{ {
const u32 new_addr = addr.GCAddress(); const u32 new_addr = addr.GCAddress();
@ -771,16 +777,16 @@ static bool ConditionalCode(const ARAddr& addr, const u32 data, int* const pSkip
switch (addr.size) switch (addr.size)
{ {
case DATATYPE_8BIT: case DATATYPE_8BIT:
result = CompareValues(PowerPC::HostRead_U8(new_addr), (data & 0xFF), addr.type); result = CompareValues(PowerPC::HostRead_U8(guard, new_addr), (data & 0xFF), addr.type);
break; break;
case DATATYPE_16BIT: case DATATYPE_16BIT:
result = CompareValues(PowerPC::HostRead_U16(new_addr), (data & 0xFFFF), addr.type); result = CompareValues(PowerPC::HostRead_U16(guard, new_addr), (data & 0xFFFF), addr.type);
break; break;
case DATATYPE_32BIT_FLOAT: case DATATYPE_32BIT_FLOAT:
case DATATYPE_32BIT: case DATATYPE_32BIT:
result = CompareValues(PowerPC::HostRead_U32(new_addr), data, addr.type); result = CompareValues(PowerPC::HostRead_U32(guard, new_addr), data, addr.type);
break; break;
default: default:
@ -819,7 +825,7 @@ static bool ConditionalCode(const ARAddr& addr, const u32 data, int* const pSkip
} }
// NOTE: Lock needed to give mutual exclusion to s_current_code and LogInfo // NOTE: Lock needed to give mutual exclusion to s_current_code and LogInfo
static bool RunCodeLocked(const ARCode& arcode) static bool RunCodeLocked(const Core::CPUThreadGuard& guard, const ARCode& arcode)
{ {
// The mechanism is different than what the real AR uses, so there may be compatibility problems. // The mechanism is different than what the real AR uses, so there may be compatibility problems.
@ -873,7 +879,7 @@ static bool RunCodeLocked(const ARCode& arcode)
{ {
do_fill_and_slide = false; do_fill_and_slide = false;
LogInfo("Doing Fill And Slide"); LogInfo("Doing Fill And Slide");
if (false == ZeroCode_FillAndSlide(val_last, addr, data)) if (false == ZeroCode_FillAndSlide(guard, val_last, addr, data))
return false; return false;
continue; continue;
} }
@ -883,7 +889,7 @@ static bool RunCodeLocked(const ARCode& arcode)
{ {
do_memory_copy = false; do_memory_copy = false;
LogInfo("Doing Memory Copy"); LogInfo("Doing Memory Copy");
if (false == ZeroCode_MemoryCopy(val_last, addr, data)) if (false == ZeroCode_MemoryCopy(guard, val_last, addr, data))
return false; return false;
continue; continue;
} }
@ -962,13 +968,13 @@ static bool RunCodeLocked(const ARCode& arcode)
switch (addr.type) switch (addr.type)
{ {
case 0x00: case 0x00:
if (false == NormalCode(addr, data)) if (false == NormalCode(guard, addr, data))
return false; return false;
break; break;
default: default:
LogInfo("This Normal Code is a Conditional Code"); LogInfo("This Normal Code is a Conditional Code");
if (false == ConditionalCode(addr, data, &skip_count)) if (false == ConditionalCode(guard, addr, data, &skip_count))
return false; return false;
break; break;
} }
@ -977,7 +983,7 @@ static bool RunCodeLocked(const ARCode& arcode)
return true; return true;
} }
void RunAllActive() void RunAllActive(const Core::CPUThreadGuard& cpu_guard)
{ {
if (!Config::Get(Config::MAIN_ENABLE_CHEATS)) if (!Config::Get(Config::MAIN_ENABLE_CHEATS))
return; return;
@ -987,8 +993,8 @@ void RunAllActive()
// be contested. // be contested.
std::lock_guard guard(s_lock); std::lock_guard guard(s_lock);
s_active_codes.erase(std::remove_if(s_active_codes.begin(), s_active_codes.end(), s_active_codes.erase(std::remove_if(s_active_codes.begin(), s_active_codes.end(),
[](const ARCode& code) { [&cpu_guard](const ARCode& code) {
bool success = RunCodeLocked(code); bool success = RunCodeLocked(cpu_guard, code);
LogInfo("\n"); LogInfo("\n");
return !success; return !success;
}), }),

View File

@ -12,6 +12,11 @@
class IniFile; class IniFile;
namespace Core
{
class CPUThreadGuard;
};
namespace ActionReplay namespace ActionReplay
{ {
struct AREntry struct AREntry
@ -35,7 +40,7 @@ struct ARCode
bool user_defined = false; bool user_defined = false;
}; };
void RunAllActive(); void RunAllActive(const Core::CPUThreadGuard& cpu_guard);
void ApplyCodes(std::span<const ARCode> codes); void ApplyCodes(std::span<const ARCode> codes);
void SetSyncedCodesAsActive(); void SetSyncedCodesAsActive();

View File

@ -375,11 +375,11 @@ bool CBoot::FindMapFile(std::string* existing_map_file, std::string* writable_ma
return false; return false;
} }
bool CBoot::LoadMapFromFilename() bool CBoot::LoadMapFromFilename(const Core::CPUThreadGuard& guard)
{ {
std::string strMapFilename; std::string strMapFilename;
bool found = FindMapFile(&strMapFilename, nullptr); bool found = FindMapFile(&strMapFilename, nullptr);
if (found && g_symbolDB.LoadMap(strMapFilename)) if (found && g_symbolDB.LoadMap(guard, strMapFilename))
{ {
UpdateDebugger_MapLoaded(); UpdateDebugger_MapLoaded();
return true; return true;
@ -486,7 +486,8 @@ static void CopyDefaultExceptionHandlers(Core::System& system)
} }
// Third boot step after BootManager and Core. See Call schedule in BootManager.cpp // Third boot step after BootManager and Core. See Call schedule in BootManager.cpp
bool CBoot::BootUp(Core::System& system, std::unique_ptr<BootParameters> boot) bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
std::unique_ptr<BootParameters> boot)
{ {
SConfig& config = SConfig::GetInstance(); SConfig& config = SConfig::GetInstance();
@ -502,8 +503,10 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr<BootParameters> boot)
struct BootTitle struct BootTitle
{ {
BootTitle(Core::System& system_, const std::vector<DiscIO::Riivolution::Patch>& patches) BootTitle(Core::System& system_, const Core::CPUThreadGuard& guard_,
: system(system_), config(SConfig::GetInstance()), riivolution_patches(patches) const std::vector<DiscIO::Riivolution::Patch>& patches)
: system(system_), guard(guard_), config(SConfig::GetInstance()),
riivolution_patches(patches)
{ {
} }
bool operator()(BootParameters::Disc& disc) const bool operator()(BootParameters::Disc& disc) const
@ -515,10 +518,10 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr<BootParameters> boot)
if (!volume) if (!volume)
return false; return false;
if (!EmulatedBS2(system, config.bWii, *volume, riivolution_patches)) if (!EmulatedBS2(system, guard, config.bWii, *volume, riivolution_patches))
return false; return false;
SConfig::OnNewTitleLoad(); SConfig::OnNewTitleLoad(guard);
return true; return true;
} }
@ -551,7 +554,7 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr<BootParameters> boot)
} }
else else
{ {
SetupGCMemory(system); SetupGCMemory(system, guard);
} }
if (!executable.reader->LoadIntoMemory()) if (!executable.reader->LoadIntoMemory())
@ -560,11 +563,11 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr<BootParameters> boot)
return false; return false;
} }
SConfig::OnNewTitleLoad(); SConfig::OnNewTitleLoad(guard);
ppc_state.pc = executable.reader->GetEntryPoint(); ppc_state.pc = executable.reader->GetEntryPoint();
if (executable.reader->LoadSymbols()) if (executable.reader->LoadSymbols(guard))
{ {
UpdateDebugger_MapLoaded(); UpdateDebugger_MapLoaded();
HLE::PatchFunctions(system); HLE::PatchFunctions(system);
@ -578,7 +581,7 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr<BootParameters> boot)
if (!Boot_WiiWAD(system, wad)) if (!Boot_WiiWAD(system, wad))
return false; return false;
SConfig::OnNewTitleLoad(); SConfig::OnNewTitleLoad(guard);
return true; return true;
} }
@ -588,7 +591,7 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr<BootParameters> boot)
if (!BootNANDTitle(system, nand_title.id)) if (!BootNANDTitle(system, nand_title.id))
return false; return false;
SConfig::OnNewTitleLoad(); SConfig::OnNewTitleLoad(guard);
return true; return true;
} }
@ -613,7 +616,7 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr<BootParameters> boot)
SetDisc(DiscIO::CreateDisc(ipl.disc->path), ipl.disc->auto_disc_change_paths); SetDisc(DiscIO::CreateDisc(ipl.disc->path), ipl.disc->auto_disc_change_paths);
} }
SConfig::OnNewTitleLoad(); SConfig::OnNewTitleLoad(guard);
return true; return true;
} }
@ -625,14 +628,15 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr<BootParameters> boot)
private: private:
Core::System& system; Core::System& system;
const Core::CPUThreadGuard& guard;
const SConfig& config; const SConfig& config;
const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches; const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches;
}; };
if (!std::visit(BootTitle(system, boot->riivolution_patches), boot->parameters)) if (!std::visit(BootTitle(system, guard, boot->riivolution_patches), boot->parameters))
return false; return false;
DiscIO::Riivolution::ApplyGeneralMemoryPatches(boot->riivolution_patches); DiscIO::Riivolution::ApplyGeneralMemoryPatches(guard, boot->riivolution_patches);
return true; return true;
} }

View File

@ -21,8 +21,9 @@
namespace Core namespace Core
{ {
class CPUThreadGuard;
class System; class System;
} } // namespace Core
namespace File namespace File
{ {
@ -153,7 +154,8 @@ struct BootParameters
class CBoot class CBoot
{ {
public: public:
static bool BootUp(Core::System& system, std::unique_ptr<BootParameters> boot); static bool BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
std::unique_ptr<BootParameters> boot);
// Tries to find a map file for the current game by looking first in the // Tries to find a map file for the current game by looking first in the
// local user directory, then in the shared user directory. // local user directory, then in the shared user directory.
@ -166,7 +168,7 @@ public:
// //
// Returns true if a map file exists, false if none could be found. // Returns true if a map file exists, false if none could be found.
static bool FindMapFile(std::string* existing_map_file, std::string* writable_map_file); static bool FindMapFile(std::string* existing_map_file, std::string* writable_map_file);
static bool LoadMapFromFilename(); static bool LoadMapFromFilename(const Core::CPUThreadGuard& guard);
private: private:
static bool DVDRead(const DiscIO::VolumeDisc& disc, u64 dvd_offset, u32 output_address, static bool DVDRead(const DiscIO::VolumeDisc& disc, u64 dvd_offset, u32 output_address,
@ -182,17 +184,21 @@ private:
static void SetupMSR(PowerPC::PowerPCState& ppc_state); static void SetupMSR(PowerPC::PowerPCState& ppc_state);
static void SetupHID(PowerPC::PowerPCState& ppc_state, bool is_wii); static void SetupHID(PowerPC::PowerPCState& ppc_state, bool is_wii);
static void SetupBAT(Core::System& system, bool is_wii); static void SetupBAT(Core::System& system, bool is_wii);
static bool RunApploader(Core::System& system, bool is_wii, const DiscIO::VolumeDisc& volume, static bool RunApploader(Core::System& system, const Core::CPUThreadGuard& guard, bool is_wii,
const DiscIO::VolumeDisc& volume,
const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches); const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches);
static bool EmulatedBS2_GC(Core::System& system, const DiscIO::VolumeDisc& volume, static bool EmulatedBS2_GC(Core::System& system, const Core::CPUThreadGuard& guard,
const DiscIO::VolumeDisc& volume,
const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches); const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches);
static bool EmulatedBS2_Wii(Core::System& system, const DiscIO::VolumeDisc& volume, static bool EmulatedBS2_Wii(Core::System& system, const Core::CPUThreadGuard& guard,
const DiscIO::VolumeDisc& volume,
const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches); const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches);
static bool EmulatedBS2(Core::System& system, bool is_wii, const DiscIO::VolumeDisc& volume, static bool EmulatedBS2(Core::System& system, const Core::CPUThreadGuard& guard, bool is_wii,
const DiscIO::VolumeDisc& volume,
const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches); const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches);
static bool Load_BS2(Core::System& system, const std::string& boot_rom_filename); static bool Load_BS2(Core::System& system, const std::string& boot_rom_filename);
static void SetupGCMemory(Core::System& system); static void SetupGCMemory(Core::System& system, const Core::CPUThreadGuard& guard);
static bool SetupWiiMemory(Core::System& system, IOS::HLE::IOSC::ConsoleType console_type); static bool SetupWiiMemory(Core::System& system, IOS::HLE::IOSC::ConsoleType console_type);
}; };
@ -208,7 +214,7 @@ public:
virtual bool IsValid() const = 0; virtual bool IsValid() const = 0;
virtual bool IsWii() const = 0; virtual bool IsWii() const = 0;
virtual bool LoadIntoMemory(bool only_in_mem1 = false) const = 0; virtual bool LoadIntoMemory(bool only_in_mem1 = false) const = 0;
virtual bool LoadSymbols() const = 0; virtual bool LoadSymbols(const Core::CPUThreadGuard& guard) const = 0;
protected: protected:
std::vector<u8> m_bytes; std::vector<u8> m_bytes;

View File

@ -44,14 +44,14 @@
namespace namespace
{ {
void PresetTimeBaseTicks() void PresetTimeBaseTicks(const Core::CPUThreadGuard& guard)
{ {
const u64 emulated_time = const u64 emulated_time =
ExpansionInterface::CEXIIPL::GetEmulatedTime(ExpansionInterface::CEXIIPL::GC_EPOCH); ExpansionInterface::CEXIIPL::GetEmulatedTime(ExpansionInterface::CEXIIPL::GC_EPOCH);
const u64 time_base_ticks = emulated_time * 40500000ULL; const u64 time_base_ticks = emulated_time * 40500000ULL;
PowerPC::HostWrite_U64(time_base_ticks, 0x800030D8); PowerPC::HostWrite_U64(guard, time_base_ticks, 0x800030D8);
} }
} // Anonymous namespace } // Anonymous namespace
@ -131,7 +131,8 @@ void CBoot::SetupBAT(Core::System& system, bool is_wii)
PowerPC::IBATUpdated(); PowerPC::IBATUpdated();
} }
bool CBoot::RunApploader(Core::System& system, bool is_wii, const DiscIO::VolumeDisc& volume, bool CBoot::RunApploader(Core::System& system, const Core::CPUThreadGuard& guard, bool is_wii,
const DiscIO::VolumeDisc& volume,
const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches) const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches)
{ {
const DiscIO::Partition partition = volume.GetGamePartition(); const DiscIO::Partition partition = volume.GetGamePartition();
@ -166,8 +167,8 @@ bool CBoot::RunApploader(Core::System& system, bool is_wii, const DiscIO::Volume
// iAppLoaderInit // iAppLoaderInit
DEBUG_LOG_FMT(BOOT, "Call iAppLoaderInit"); DEBUG_LOG_FMT(BOOT, "Call iAppLoaderInit");
PowerPC::HostWrite_U32(0x4E800020, 0x81300000); // Write BLR PowerPC::HostWrite_U32(guard, 0x4E800020, 0x81300000); // Write BLR
HLE::Patch(system, 0x81300000, "AppLoaderReport"); // HLE OSReport for Apploader HLE::Patch(system, 0x81300000, "AppLoaderReport"); // HLE OSReport for Apploader
ppc_state.gpr[3] = 0x81300000; ppc_state.gpr[3] = 0x81300000;
RunFunction(system, iAppLoaderInit); RunFunction(system, iAppLoaderInit);
@ -196,7 +197,8 @@ bool CBoot::RunApploader(Core::System& system, bool is_wii, const DiscIO::Volume
ram_address, length); ram_address, length);
DVDRead(volume, dvd_offset, ram_address, length, partition); DVDRead(volume, dvd_offset, ram_address, length, partition);
DiscIO::Riivolution::ApplyApploaderMemoryPatches(riivolution_patches, ram_address, length); DiscIO::Riivolution::ApplyApploaderMemoryPatches(guard, riivolution_patches, ram_address,
length);
ppc_state.gpr[3] = 0x81300004; ppc_state.gpr[3] = 0x81300004;
ppc_state.gpr[4] = 0x81300008; ppc_state.gpr[4] = 0x81300008;
@ -216,36 +218,37 @@ bool CBoot::RunApploader(Core::System& system, bool is_wii, const DiscIO::Volume
return true; return true;
} }
void CBoot::SetupGCMemory(Core::System& system) void CBoot::SetupGCMemory(Core::System& system, const Core::CPUThreadGuard& guard)
{ {
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
// Booted from bootrom. 0xE5207C22 = booted from jtag // Booted from bootrom. 0xE5207C22 = booted from jtag
PowerPC::HostWrite_U32(0x0D15EA5E, 0x80000020); PowerPC::HostWrite_U32(guard, 0x0D15EA5E, 0x80000020);
// Physical Memory Size (24MB on retail) // Physical Memory Size (24MB on retail)
PowerPC::HostWrite_U32(memory.GetRamSizeReal(), 0x80000028); PowerPC::HostWrite_U32(guard, memory.GetRamSizeReal(), 0x80000028);
// Console type - DevKit (retail ID == 0x00000003) see YAGCD 4.2.1.1.2 // Console type - DevKit (retail ID == 0x00000003) see YAGCD 4.2.1.1.2
// TODO: determine why some games fail when using a retail ID. // TODO: determine why some games fail when using a retail ID.
// (Seem to take different EXI paths, see Ikaruga for example) // (Seem to take different EXI paths, see Ikaruga for example)
const u32 console_type = static_cast<u32>(Core::ConsoleType::LatestDevkit); const u32 console_type = static_cast<u32>(Core::ConsoleType::LatestDevkit);
PowerPC::HostWrite_U32(console_type, 0x8000002C); PowerPC::HostWrite_U32(guard, console_type, 0x8000002C);
// Fake the VI Init of the IPL (YAGCD 4.2.1.4) // Fake the VI Init of the IPL (YAGCD 4.2.1.4)
PowerPC::HostWrite_U32(DiscIO::IsNTSC(SConfig::GetInstance().m_region) ? 0 : 1, 0x800000CC); PowerPC::HostWrite_U32(guard, DiscIO::IsNTSC(SConfig::GetInstance().m_region) ? 0 : 1,
0x800000CC);
PowerPC::HostWrite_U32(0x01000000, 0x800000d0); // ARAM Size. 16MB main + 4/16/32MB external // ARAM Size. 16MB main + 4/16/32MB external. (retail consoles have no external ARAM)
// (retail consoles have no external ARAM) PowerPC::HostWrite_U32(guard, 0x01000000, 0x800000d0);
PowerPC::HostWrite_U32(0x09a7ec80, 0x800000F8); // Bus Clock Speed PowerPC::HostWrite_U32(guard, 0x09a7ec80, 0x800000F8); // Bus Clock Speed
PowerPC::HostWrite_U32(0x1cf7c580, 0x800000FC); // CPU Clock Speed PowerPC::HostWrite_U32(guard, 0x1cf7c580, 0x800000FC); // CPU Clock Speed
PowerPC::HostWrite_U32(0x4c000064, 0x80000300); // Write default DSI Handler: rfi PowerPC::HostWrite_U32(guard, 0x4c000064, 0x80000300); // Write default DSI Handler: rfi
PowerPC::HostWrite_U32(0x4c000064, 0x80000800); // Write default FPU Handler: rfi PowerPC::HostWrite_U32(guard, 0x4c000064, 0x80000800); // Write default FPU Handler: rfi
PowerPC::HostWrite_U32(0x4c000064, 0x80000C00); // Write default Syscall Handler: rfi PowerPC::HostWrite_U32(guard, 0x4c000064, 0x80000C00); // Write default Syscall Handler: rfi
PresetTimeBaseTicks(); PresetTimeBaseTicks(guard);
// HIO checks this // HIO checks this
// PowerPC::HostWrite_U16(0x8200, 0x000030e6); // Console type // PowerPC::HostWrite_U16(0x8200, 0x000030e6); // Console type
@ -255,7 +258,8 @@ void CBoot::SetupGCMemory(Core::System& system)
// GameCube Bootstrap 2 HLE: // GameCube Bootstrap 2 HLE:
// copy the apploader to 0x81200000 // copy the apploader to 0x81200000
// execute the apploader, function by function, using the above utility. // execute the apploader, function by function, using the above utility.
bool CBoot::EmulatedBS2_GC(Core::System& system, const DiscIO::VolumeDisc& volume, bool CBoot::EmulatedBS2_GC(Core::System& system, const Core::CPUThreadGuard& guard,
const DiscIO::VolumeDisc& volume,
const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches) const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches)
{ {
INFO_LOG_FMT(BOOT, "Faking GC BS2..."); INFO_LOG_FMT(BOOT, "Faking GC BS2...");
@ -266,7 +270,7 @@ bool CBoot::EmulatedBS2_GC(Core::System& system, const DiscIO::VolumeDisc& volum
SetupHID(ppc_state, /*is_wii*/ false); SetupHID(ppc_state, /*is_wii*/ false);
SetupBAT(system, /*is_wii*/ false); SetupBAT(system, /*is_wii*/ false);
SetupGCMemory(system); SetupGCMemory(system, guard);
// Datel titles don't initialize the postMatrices, but they have dual-texture coordinate // Datel titles don't initialize the postMatrices, but they have dual-texture coordinate
// transformation enabled. We initialize all of xfmem to 0, which results in everything using // transformation enabled. We initialize all of xfmem to 0, which results in everything using
@ -309,7 +313,7 @@ bool CBoot::EmulatedBS2_GC(Core::System& system, const DiscIO::VolumeDisc& volum
// Global pointer to Small Data Area Base (Luigi's Mansion's apploader uses it) // Global pointer to Small Data Area Base (Luigi's Mansion's apploader uses it)
ppc_state.gpr[13] = ntsc ? 0x81465320 : 0x814b4fc0; ppc_state.gpr[13] = ntsc ? 0x81465320 : 0x814b4fc0;
return RunApploader(system, /*is_wii*/ false, volume, riivolution_patches); return RunApploader(system, guard, /*is_wii*/ false, volume, riivolution_patches);
} }
static DiscIO::Region CodeRegion(char c) static DiscIO::Region CodeRegion(char c)
@ -507,7 +511,8 @@ static void WriteEmptyPlayRecord()
// Wii Bootstrap 2 HLE: // Wii Bootstrap 2 HLE:
// copy the apploader to 0x81200000 // copy the apploader to 0x81200000
// execute the apploader // execute the apploader
bool CBoot::EmulatedBS2_Wii(Core::System& system, const DiscIO::VolumeDisc& volume, bool CBoot::EmulatedBS2_Wii(Core::System& system, const Core::CPUThreadGuard& guard,
const DiscIO::VolumeDisc& volume,
const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches) const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches)
{ {
INFO_LOG_FMT(BOOT, "Faking Wii BS2..."); INFO_LOG_FMT(BOOT, "Faking Wii BS2...");
@ -578,7 +583,7 @@ bool CBoot::EmulatedBS2_Wii(Core::System& system, const DiscIO::VolumeDisc& volu
ppc_state.gpr[1] = 0x816ffff0; // StackPointer ppc_state.gpr[1] = 0x816ffff0; // StackPointer
if (!RunApploader(system, /*is_wii*/ true, volume, riivolution_patches)) if (!RunApploader(system, guard, /*is_wii*/ true, volume, riivolution_patches))
return false; return false;
// The Apploader probably just overwrote values needed for RAM Override. Run this again! // The Apploader probably just overwrote values needed for RAM Override. Run this again!
@ -593,9 +598,10 @@ bool CBoot::EmulatedBS2_Wii(Core::System& system, const DiscIO::VolumeDisc& volu
// Returns true if apploader has run successfully. If is_wii is true, the disc // Returns true if apploader has run successfully. If is_wii is true, the disc
// that volume refers to must currently be inserted into the emulated disc drive. // that volume refers to must currently be inserted into the emulated disc drive.
bool CBoot::EmulatedBS2(Core::System& system, bool is_wii, const DiscIO::VolumeDisc& volume, bool CBoot::EmulatedBS2(Core::System& system, const Core::CPUThreadGuard& guard, bool is_wii,
const DiscIO::VolumeDisc& volume,
const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches) const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches)
{ {
return is_wii ? EmulatedBS2_Wii(system, volume, riivolution_patches) : return is_wii ? EmulatedBS2_Wii(system, guard, volume, riivolution_patches) :
EmulatedBS2_GC(system, volume, riivolution_patches); EmulatedBS2_GC(system, guard, volume, riivolution_patches);
} }

View File

@ -27,7 +27,7 @@ public:
bool IsAncast() const { return m_is_ancast; }; bool IsAncast() const { return m_is_ancast; };
u32 GetEntryPoint() const override { return m_dolheader.entryPoint; } u32 GetEntryPoint() const override { return m_dolheader.entryPoint; }
bool LoadIntoMemory(bool only_in_mem1 = false) const override; bool LoadIntoMemory(bool only_in_mem1 = false) const override;
bool LoadSymbols() const override { return false; } bool LoadSymbols(const Core::CPUThreadGuard& guard) const override { return false; }
private: private:
enum enum

View File

@ -181,7 +181,7 @@ SectionID ElfReader::GetSectionByName(const char* name, int firstSection) const
return -1; return -1;
} }
bool ElfReader::LoadSymbols() const bool ElfReader::LoadSymbols(const Core::CPUThreadGuard& guard) const
{ {
bool hasSymbols = false; bool hasSymbols = false;
SectionID sec = GetSectionByName(".symtab"); SectionID sec = GetSectionByName(".symtab");
@ -219,7 +219,7 @@ bool ElfReader::LoadSymbols() const
default: default:
continue; continue;
} }
g_symbolDB.AddKnownSymbol(value, size, name, symtype); g_symbolDB.AddKnownSymbol(guard, value, size, name, symtype);
hasSymbols = true; hasSymbols = true;
} }
} }

View File

@ -36,7 +36,7 @@ public:
u32 GetEntryPoint() const override { return entryPoint; } u32 GetEntryPoint() const override { return entryPoint; }
u32 GetFlags() const { return (u32)(header->e_flags); } u32 GetFlags() const { return (u32)(header->e_flags); }
bool LoadIntoMemory(bool only_in_mem1 = false) const override; bool LoadIntoMemory(bool only_in_mem1 = false) const override;
bool LoadSymbols() const override; bool LoadSymbols(const Core::CPUThreadGuard& guard) const override;
// TODO: actually check for validity. // TODO: actually check for validity.
bool IsValid() const override { return true; } bool IsValid() const override { return true; }
bool IsWii() const override; bool IsWii() const override;

View File

@ -103,41 +103,47 @@ namespace
{ {
template <typename T> template <typename T>
static std::optional<PowerPC::ReadResult<T>> static std::optional<PowerPC::ReadResult<T>>
TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space); TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr,
PowerPC::RequestedAddressSpace space);
template <> template <>
std::optional<PowerPC::ReadResult<u8>> std::optional<PowerPC::ReadResult<u8>>
TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr,
PowerPC::RequestedAddressSpace space)
{ {
return PowerPC::HostTryReadU8(addr, space); return PowerPC::HostTryReadU8(guard, addr, space);
} }
template <> template <>
std::optional<PowerPC::ReadResult<u16>> std::optional<PowerPC::ReadResult<u16>>
TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr,
PowerPC::RequestedAddressSpace space)
{ {
return PowerPC::HostTryReadU16(addr, space); return PowerPC::HostTryReadU16(guard, addr, space);
} }
template <> template <>
std::optional<PowerPC::ReadResult<u32>> std::optional<PowerPC::ReadResult<u32>>
TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr,
PowerPC::RequestedAddressSpace space)
{ {
return PowerPC::HostTryReadU32(addr, space); return PowerPC::HostTryReadU32(guard, addr, space);
} }
template <> template <>
std::optional<PowerPC::ReadResult<u64>> std::optional<PowerPC::ReadResult<u64>>
TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr,
PowerPC::RequestedAddressSpace space)
{ {
return PowerPC::HostTryReadU64(addr, space); return PowerPC::HostTryReadU64(guard, addr, space);
} }
template <> template <>
std::optional<PowerPC::ReadResult<s8>> std::optional<PowerPC::ReadResult<s8>>
TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr,
PowerPC::RequestedAddressSpace space)
{ {
auto tmp = PowerPC::HostTryReadU8(addr, space); auto tmp = PowerPC::HostTryReadU8(guard, addr, space);
if (!tmp) if (!tmp)
return std::nullopt; return std::nullopt;
return PowerPC::ReadResult<s8>(tmp->translated, Common::BitCast<s8>(tmp->value)); return PowerPC::ReadResult<s8>(tmp->translated, Common::BitCast<s8>(tmp->value));
@ -145,9 +151,10 @@ TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space)
template <> template <>
std::optional<PowerPC::ReadResult<s16>> std::optional<PowerPC::ReadResult<s16>>
TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr,
PowerPC::RequestedAddressSpace space)
{ {
auto tmp = PowerPC::HostTryReadU16(addr, space); auto tmp = PowerPC::HostTryReadU16(guard, addr, space);
if (!tmp) if (!tmp)
return std::nullopt; return std::nullopt;
return PowerPC::ReadResult<s16>(tmp->translated, Common::BitCast<s16>(tmp->value)); return PowerPC::ReadResult<s16>(tmp->translated, Common::BitCast<s16>(tmp->value));
@ -155,9 +162,10 @@ TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space)
template <> template <>
std::optional<PowerPC::ReadResult<s32>> std::optional<PowerPC::ReadResult<s32>>
TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr,
PowerPC::RequestedAddressSpace space)
{ {
auto tmp = PowerPC::HostTryReadU32(addr, space); auto tmp = PowerPC::HostTryReadU32(guard, addr, space);
if (!tmp) if (!tmp)
return std::nullopt; return std::nullopt;
return PowerPC::ReadResult<s32>(tmp->translated, Common::BitCast<s32>(tmp->value)); return PowerPC::ReadResult<s32>(tmp->translated, Common::BitCast<s32>(tmp->value));
@ -165,9 +173,10 @@ TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space)
template <> template <>
std::optional<PowerPC::ReadResult<s64>> std::optional<PowerPC::ReadResult<s64>>
TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr,
PowerPC::RequestedAddressSpace space)
{ {
auto tmp = PowerPC::HostTryReadU64(addr, space); auto tmp = PowerPC::HostTryReadU64(guard, addr, space);
if (!tmp) if (!tmp)
return std::nullopt; return std::nullopt;
return PowerPC::ReadResult<s64>(tmp->translated, Common::BitCast<s64>(tmp->value)); return PowerPC::ReadResult<s64>(tmp->translated, Common::BitCast<s64>(tmp->value));
@ -175,22 +184,25 @@ TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space)
template <> template <>
std::optional<PowerPC::ReadResult<float>> std::optional<PowerPC::ReadResult<float>>
TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr,
PowerPC::RequestedAddressSpace space)
{ {
return PowerPC::HostTryReadF32(addr, space); return PowerPC::HostTryReadF32(guard, addr, space);
} }
template <> template <>
std::optional<PowerPC::ReadResult<double>> std::optional<PowerPC::ReadResult<double>>
TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr,
PowerPC::RequestedAddressSpace space)
{ {
return PowerPC::HostTryReadF64(addr, space); return PowerPC::HostTryReadF64(guard, addr, space);
} }
} // namespace } // namespace
template <typename T> template <typename T>
Common::Result<Cheats::SearchErrorCode, std::vector<Cheats::SearchResult<T>>> Common::Result<Cheats::SearchErrorCode, std::vector<Cheats::SearchResult<T>>>
Cheats::NewSearch(const std::vector<Cheats::MemoryRange>& memory_ranges, Cheats::NewSearch(const Core::CPUThreadGuard& guard,
const std::vector<Cheats::MemoryRange>& memory_ranges,
PowerPC::RequestedAddressSpace address_space, bool aligned, PowerPC::RequestedAddressSpace address_space, bool aligned,
const std::function<bool(const T& value)>& validator) const std::function<bool(const T& value)>& validator)
{ {
@ -229,7 +241,7 @@ Cheats::NewSearch(const std::vector<Cheats::MemoryRange>& memory_ranges,
for (u64 i = 0; i < length; i += increment_per_loop) for (u64 i = 0; i < length; i += increment_per_loop)
{ {
const u32 addr = start_address + i; const u32 addr = start_address + i;
const auto current_value = TryReadValueFromEmulatedMemory<T>(addr, address_space); const auto current_value = TryReadValueFromEmulatedMemory<T>(guard, addr, address_space);
if (!current_value) if (!current_value)
continue; continue;
@ -252,7 +264,8 @@ Cheats::NewSearch(const std::vector<Cheats::MemoryRange>& memory_ranges,
template <typename T> template <typename T>
Common::Result<Cheats::SearchErrorCode, std::vector<Cheats::SearchResult<T>>> Common::Result<Cheats::SearchErrorCode, std::vector<Cheats::SearchResult<T>>>
Cheats::NextSearch(const std::vector<Cheats::SearchResult<T>>& previous_results, Cheats::NextSearch(const Core::CPUThreadGuard& guard,
const std::vector<Cheats::SearchResult<T>>& previous_results,
PowerPC::RequestedAddressSpace address_space, PowerPC::RequestedAddressSpace address_space,
const std::function<bool(const T& new_value, const T& old_value)>& validator) const std::function<bool(const T& new_value, const T& old_value)>& validator)
{ {
@ -277,7 +290,7 @@ Cheats::NextSearch(const std::vector<Cheats::SearchResult<T>>& previous_results,
for (const auto& previous_result : previous_results) for (const auto& previous_result : previous_results)
{ {
const u32 addr = previous_result.m_address; const u32 addr = previous_result.m_address;
const auto current_value = TryReadValueFromEmulatedMemory<T>(addr, address_space); const auto current_value = TryReadValueFromEmulatedMemory<T>(guard, addr, address_space);
if (!current_value) if (!current_value)
{ {
auto& r = results.emplace_back(); auto& r = results.emplace_back();
@ -429,7 +442,7 @@ MakeCompareFunctionForLastValue(Cheats::CompareType op)
} }
template <typename T> template <typename T>
Cheats::SearchErrorCode Cheats::CheatSearchSession<T>::RunSearch() Cheats::SearchErrorCode Cheats::CheatSearchSession<T>::RunSearch(const Core::CPUThreadGuard& guard)
{ {
Common::Result<SearchErrorCode, std::vector<SearchResult<T>>> result = Common::Result<SearchErrorCode, std::vector<SearchResult<T>>> result =
Cheats::SearchErrorCode::InvalidParameters; Cheats::SearchErrorCode::InvalidParameters;
@ -442,12 +455,12 @@ Cheats::SearchErrorCode Cheats::CheatSearchSession<T>::RunSearch()
if (m_first_search_done) if (m_first_search_done)
{ {
result = Cheats::NextSearch<T>( result = Cheats::NextSearch<T>(
m_search_results, m_address_space, guard, m_search_results, m_address_space,
[&func](const T& new_value, const T& old_value) { return func(new_value); }); [&func](const T& new_value, const T& old_value) { return func(new_value); });
} }
else else
{ {
result = Cheats::NewSearch<T>(m_memory_ranges, m_address_space, m_aligned, func); result = Cheats::NewSearch<T>(guard, m_memory_ranges, m_address_space, m_aligned, func);
} }
} }
else if (m_filter_type == FilterType::CompareAgainstLastValue) else if (m_filter_type == FilterType::CompareAgainstLastValue)
@ -455,19 +468,19 @@ Cheats::SearchErrorCode Cheats::CheatSearchSession<T>::RunSearch()
if (!m_first_search_done) if (!m_first_search_done)
return Cheats::SearchErrorCode::InvalidParameters; return Cheats::SearchErrorCode::InvalidParameters;
result = Cheats::NextSearch<T>(m_search_results, m_address_space, result = Cheats::NextSearch<T>(guard, m_search_results, m_address_space,
MakeCompareFunctionForLastValue<T>(m_compare_type)); MakeCompareFunctionForLastValue<T>(m_compare_type));
} }
else if (m_filter_type == FilterType::DoNotFilter) else if (m_filter_type == FilterType::DoNotFilter)
{ {
if (m_first_search_done) if (m_first_search_done)
{ {
result = Cheats::NextSearch<T>(m_search_results, m_address_space, result = Cheats::NextSearch<T>(guard, m_search_results, m_address_space,
[](const T& v1, const T& v2) { return true; }); [](const T& v1, const T& v2) { return true; });
} }
else else
{ {
result = Cheats::NewSearch<T>(m_memory_ranges, m_address_space, m_aligned, result = Cheats::NewSearch<T>(guard, m_memory_ranges, m_address_space, m_aligned,
[](const T& v) { return true; }); [](const T& v) { return true; });
} }
} }

View File

@ -14,6 +14,11 @@
#include "Common/Result.h" #include "Common/Result.h"
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
namespace Core
{
class CPUThreadGuard;
};
namespace Cheats namespace Cheats
{ {
enum class CompareType enum class CompareType
@ -108,7 +113,7 @@ std::vector<u8> GetValueAsByteVector(const SearchValue& value);
// for which the given validator returns true. // for which the given validator returns true.
template <typename T> template <typename T>
Common::Result<SearchErrorCode, std::vector<SearchResult<T>>> Common::Result<SearchErrorCode, std::vector<SearchResult<T>>>
NewSearch(const std::vector<MemoryRange>& memory_ranges, NewSearch(const Core::CPUThreadGuard& guard, const std::vector<MemoryRange>& memory_ranges,
PowerPC::RequestedAddressSpace address_space, bool aligned, PowerPC::RequestedAddressSpace address_space, bool aligned,
const std::function<bool(const T& value)>& validator); const std::function<bool(const T& value)>& validator);
@ -116,7 +121,7 @@ NewSearch(const std::vector<MemoryRange>& memory_ranges,
// which the given validator returns true. // which the given validator returns true.
template <typename T> template <typename T>
Common::Result<SearchErrorCode, std::vector<SearchResult<T>>> Common::Result<SearchErrorCode, std::vector<SearchResult<T>>>
NextSearch(const std::vector<SearchResult<T>>& previous_results, NextSearch(const Core::CPUThreadGuard& guard, const std::vector<SearchResult<T>>& previous_results,
PowerPC::RequestedAddressSpace address_space, PowerPC::RequestedAddressSpace address_space,
const std::function<bool(const T& new_value, const T& old_value)>& validator); const std::function<bool(const T& new_value, const T& old_value)>& validator);
@ -138,7 +143,7 @@ public:
virtual void ResetResults() = 0; virtual void ResetResults() = 0;
// Run either a new search or a next search based on the current state of this session. // Run either a new search or a next search based on the current state of this session.
virtual SearchErrorCode RunSearch() = 0; virtual SearchErrorCode RunSearch(const Core::CPUThreadGuard& guard) = 0;
virtual size_t GetMemoryRangeCount() const = 0; virtual size_t GetMemoryRangeCount() const = 0;
virtual MemoryRange GetMemoryRange(size_t index) const = 0; virtual MemoryRange GetMemoryRange(size_t index) const = 0;
@ -184,7 +189,7 @@ public:
bool SetValueFromString(const std::string& value_as_string, bool force_parse_as_hex) override; bool SetValueFromString(const std::string& value_as_string, bool force_parse_as_hex) override;
void ResetResults() override; void ResetResults() override;
SearchErrorCode RunSearch() override; SearchErrorCode RunSearch(const Core::CPUThreadGuard& guard) override;
size_t GetMemoryRangeCount() const override; size_t GetMemoryRangeCount() const override;
MemoryRange GetMemoryRange(size_t index) const override; MemoryRange GetMemoryRange(size_t index) const override;

View File

@ -191,7 +191,7 @@ void SConfig::SetRunningGameMetadata(const std::string& game_id, const std::stri
DolphinAnalytics::Instance().ReportGameStart(); DolphinAnalytics::Instance().ReportGameStart();
} }
void SConfig::OnNewTitleLoad() void SConfig::OnNewTitleLoad(const Core::CPUThreadGuard& guard)
{ {
if (!Core::IsRunning()) if (!Core::IsRunning())
return; return;
@ -201,7 +201,7 @@ void SConfig::OnNewTitleLoad()
g_symbolDB.Clear(); g_symbolDB.Clear();
Host_NotifyMapLoaded(); Host_NotifyMapLoaded();
} }
CBoot::LoadMapFromFilename(); CBoot::LoadMapFromFilename(guard);
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
HLE::Reload(system); HLE::Reload(system);
PatchEngine::Reload(); PatchEngine::Reload();

View File

@ -16,6 +16,11 @@
class IniFile; class IniFile;
namespace Core
{
class CPUThreadGuard;
}
namespace DiscIO namespace DiscIO
{ {
enum class Language; enum class Language;
@ -68,7 +73,7 @@ struct SConfig
void SetRunningGameMetadata(const std::string& game_id); void SetRunningGameMetadata(const std::string& game_id);
// Reloads title-specific map files, patches, custom textures, etc. // Reloads title-specific map files, patches, custom textures, etc.
// This should only be called after the new title has been loaded into memory. // This should only be called after the new title has been loaded into memory.
static void OnNewTitleLoad(); static void OnNewTitleLoad(const Core::CPUThreadGuard& guard);
void LoadDefaults(); void LoadDefaults();
static std::string MakeGameID(std::string_view file_name); static std::string MakeGameID(std::string_view file_name);

View File

@ -166,7 +166,12 @@ void OnFrameEnd()
{ {
#ifdef USE_MEMORYWATCHER #ifdef USE_MEMORYWATCHER
if (s_memory_watcher) if (s_memory_watcher)
s_memory_watcher->Step(); {
ASSERT(IsCPUThread());
CPUThreadGuard guard;
s_memory_watcher->Step(guard);
}
#endif #endif
} }
@ -537,7 +542,9 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
PatchEngine::Shutdown(); PatchEngine::Shutdown();
HLE::Clear(); HLE::Clear();
PowerPC::debug_interface.Clear();
CPUThreadGuard guard;
PowerPC::debug_interface.Clear(guard);
}}; }};
VideoBackendBase::PopulateBackendInfo(); VideoBackendBase::PopulateBackendInfo();
@ -587,8 +594,12 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
if (SConfig::GetInstance().bWii) if (SConfig::GetInstance().bWii)
savegame_redirect = DiscIO::Riivolution::ExtractSavegameRedirect(boot->riivolution_patches); savegame_redirect = DiscIO::Riivolution::ExtractSavegameRedirect(boot->riivolution_patches);
if (!CBoot::BootUp(system, std::move(boot))) {
return; ASSERT(IsCPUThread());
CPUThreadGuard guard;
if (!CBoot::BootUp(system, guard, std::move(boot)))
return;
}
// Initialise Wii filesystem contents. // Initialise Wii filesystem contents.
// This is done here after Boot and not in BootManager to ensure that we operate // This is done here after Boot and not in BootManager to ensure that we operate
@ -1036,4 +1047,16 @@ void UpdateInputGate(bool require_focus, bool require_full_focus)
ControlReference::SetInputGate(focus_passes && full_focus_passes); ControlReference::SetInputGate(focus_passes && full_focus_passes);
} }
CPUThreadGuard::CPUThreadGuard() : m_was_cpu_thread(IsCPUThread())
{
if (!m_was_cpu_thread)
m_was_unpaused = PauseAndLock(true, true);
}
CPUThreadGuard::~CPUThreadGuard()
{
if (!m_was_cpu_thread)
PauseAndLock(false, m_was_unpaused);
}
} // namespace Core } // namespace Core

View File

@ -92,6 +92,33 @@ enum class ConsoleType : u32
ReservedTDEVSystem = 0x20000007, ReservedTDEVSystem = 0x20000007,
}; };
// Run a function as the CPU thread. This is an RAII alternative to the RunAsCPUThread function.
//
// If constructed from the Host thread, the CPU thread is paused and the current thread temporarily
// becomes the CPU thread.
// If constructed from the CPU thread, nothing special happens.
//
// This should only be constructed from the CPU thread or the host thread.
//
// Some functions use a parameter of this type to indicate that the function should only be called
// from the CPU thread. If the parameter is a pointer, the function has a fallback for being called
// from the wrong thread (with the argument being set to nullptr).
class CPUThreadGuard final
{
public:
CPUThreadGuard();
~CPUThreadGuard();
CPUThreadGuard(const CPUThreadGuard&) = delete;
CPUThreadGuard(CPUThreadGuard&&) = delete;
CPUThreadGuard& operator=(const CPUThreadGuard&) = delete;
CPUThreadGuard& operator=(CPUThreadGuard&&) = delete;
private:
const bool m_was_cpu_thread;
bool m_was_unpaused = false;
};
bool Init(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi); bool Init(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi);
void Stop(); void Stop();
void Shutdown(); void Shutdown();

View File

@ -39,29 +39,30 @@ void AddAutoBreakpoints()
} }
// Returns true if the address is not a valid RAM address or NULL. // Returns true if the address is not a valid RAM address or NULL.
static bool IsStackBottom(u32 addr) static bool IsStackBottom(const Core::CPUThreadGuard& guard, u32 addr)
{ {
return !addr || !PowerPC::HostIsRAMAddress(addr); return !addr || !PowerPC::HostIsRAMAddress(guard, addr);
} }
static void WalkTheStack(Core::System& system, const std::function<void(u32)>& stack_step) static void WalkTheStack(Core::System& system, const Core::CPUThreadGuard& guard,
const std::function<void(u32)>& stack_step)
{ {
auto& ppc_state = system.GetPPCState(); auto& ppc_state = system.GetPPCState();
if (!IsStackBottom(ppc_state.gpr[1])) if (!IsStackBottom(guard, ppc_state.gpr[1]))
{ {
u32 addr = PowerPC::HostRead_U32(ppc_state.gpr[1]); // SP u32 addr = PowerPC::HostRead_U32(guard, ppc_state.gpr[1]); // SP
// Walk the stack chain // Walk the stack chain
for (int count = 0; !IsStackBottom(addr + 4) && (count++ < 20); ++count) for (int count = 0; !IsStackBottom(guard, addr + 4) && (count++ < 20); ++count)
{ {
u32 func_addr = PowerPC::HostRead_U32(addr + 4); u32 func_addr = PowerPC::HostRead_U32(guard, addr + 4);
stack_step(func_addr); stack_step(func_addr);
if (IsStackBottom(addr)) if (IsStackBottom(guard, addr))
break; break;
addr = PowerPC::HostRead_U32(addr); addr = PowerPC::HostRead_U32(guard, addr);
} }
} }
} }
@ -69,11 +70,12 @@ static void WalkTheStack(Core::System& system, const std::function<void(u32)>& s
// Returns callstack "formatted for debugging" - meaning that it // Returns callstack "formatted for debugging" - meaning that it
// includes LR as the last item, and all items are the last step, // includes LR as the last item, and all items are the last step,
// instead of "pointing ahead" // instead of "pointing ahead"
bool GetCallstack(Core::System& system, std::vector<CallstackEntry>& output) bool GetCallstack(Core::System& system, const Core::CPUThreadGuard& guard,
std::vector<CallstackEntry>& output)
{ {
auto& ppc_state = system.GetPPCState(); auto& ppc_state = system.GetPPCState();
if (!Core::IsRunning() || !PowerPC::HostIsRAMAddress(ppc_state.gpr[1])) if (!Core::IsRunning() || !PowerPC::HostIsRAMAddress(guard, ppc_state.gpr[1]))
return false; return false;
if (LR(ppc_state) == 0) if (LR(ppc_state) == 0)
@ -91,7 +93,7 @@ bool GetCallstack(Core::System& system, std::vector<CallstackEntry>& output)
entry.vAddress = LR(ppc_state) - 4; entry.vAddress = LR(ppc_state) - 4;
output.push_back(entry); output.push_back(entry);
WalkTheStack(system, [&entry, &output](u32 func_addr) { WalkTheStack(system, guard, [&entry, &output](u32 func_addr) {
std::string func_desc = g_symbolDB.GetDescription(func_addr); std::string func_desc = g_symbolDB.GetDescription(func_addr);
if (func_desc.empty() || func_desc == "Invalid") if (func_desc.empty() || func_desc == "Invalid")
func_desc = "(unknown)"; func_desc = "(unknown)";
@ -103,7 +105,8 @@ bool GetCallstack(Core::System& system, std::vector<CallstackEntry>& output)
return true; return true;
} }
void PrintCallstack(Core::System& system, Common::Log::LogType type, Common::Log::LogLevel level) void PrintCallstack(Core::System& system, const Core::CPUThreadGuard& guard,
Common::Log::LogType type, Common::Log::LogLevel level)
{ {
auto& ppc_state = system.GetPPCState(); auto& ppc_state = system.GetPPCState();
@ -120,7 +123,7 @@ void PrintCallstack(Core::System& system, Common::Log::LogType type, Common::Log
LR(ppc_state)); LR(ppc_state));
} }
WalkTheStack(system, [type, level](u32 func_addr) { WalkTheStack(system, guard, [type, level](u32 func_addr) {
std::string func_desc = g_symbolDB.GetDescription(func_addr); std::string func_desc = g_symbolDB.GetDescription(func_addr);
if (func_desc.empty() || func_desc == "Invalid") if (func_desc.empty() || func_desc == "Invalid")
func_desc = "(unknown)"; func_desc = "(unknown)";

View File

@ -12,8 +12,9 @@
namespace Core namespace Core
{ {
class CPUThreadGuard;
class System; class System;
} } // namespace Core
namespace Dolphin_Debugger namespace Dolphin_Debugger
{ {
@ -23,8 +24,10 @@ struct CallstackEntry
u32 vAddress = 0; u32 vAddress = 0;
}; };
bool GetCallstack(Core::System& system, std::vector<CallstackEntry>& output); bool GetCallstack(Core::System& system, const Core::CPUThreadGuard& guard,
void PrintCallstack(Core::System& system, Common::Log::LogType type, Common::Log::LogLevel level); std::vector<CallstackEntry>& output);
void PrintCallstack(Core::System& system, const Core::CPUThreadGuard& guard,
Common::Log::LogType type, Common::Log::LogLevel level);
void PrintDataBuffer(Common::Log::LogType type, const u8* data, size_t size, void PrintDataBuffer(Common::Log::LogType type, const u8* data, size_t size,
std::string_view title); std::string_view title);
void AddAutoBreakpoints(); void AddAutoBreakpoints();

View File

@ -16,40 +16,40 @@ namespace Core::Debug
// - OSDumpContext // - OSDumpContext
// - OSClearContext // - OSClearContext
// - OSExceptionVector // - OSExceptionVector
void OSContext::Read(u32 addr) void OSContext::Read(const Core::CPUThreadGuard& guard, u32 addr)
{ {
for (std::size_t i = 0; i < gpr.size(); i++) for (std::size_t i = 0; i < gpr.size(); i++)
gpr[i] = PowerPC::HostRead_U32(addr + u32(i * sizeof(int))); gpr[i] = PowerPC::HostRead_U32(guard, addr + u32(i * sizeof(int)));
cr = PowerPC::HostRead_U32(addr + 0x80); cr = PowerPC::HostRead_U32(guard, addr + 0x80);
lr = PowerPC::HostRead_U32(addr + 0x84); lr = PowerPC::HostRead_U32(guard, addr + 0x84);
ctr = PowerPC::HostRead_U32(addr + 0x88); ctr = PowerPC::HostRead_U32(guard, addr + 0x88);
xer = PowerPC::HostRead_U32(addr + 0x8C); xer = PowerPC::HostRead_U32(guard, addr + 0x8C);
for (std::size_t i = 0; i < fpr.size(); i++) for (std::size_t i = 0; i < fpr.size(); i++)
fpr[i] = PowerPC::HostRead_F64(addr + 0x90 + u32(i * sizeof(double))); fpr[i] = PowerPC::HostRead_F64(guard, addr + 0x90 + u32(i * sizeof(double)));
fpscr = PowerPC::HostRead_U64(addr + 0x190); fpscr = PowerPC::HostRead_U64(guard, addr + 0x190);
srr0 = PowerPC::HostRead_U32(addr + 0x198); srr0 = PowerPC::HostRead_U32(guard, addr + 0x198);
srr1 = PowerPC::HostRead_U32(addr + 0x19c); srr1 = PowerPC::HostRead_U32(guard, addr + 0x19c);
dummy = PowerPC::HostRead_U16(addr + 0x1a0); dummy = PowerPC::HostRead_U16(guard, addr + 0x1a0);
state = static_cast<OSContext::State>(PowerPC::HostRead_U16(addr + 0x1a2)); state = static_cast<OSContext::State>(PowerPC::HostRead_U16(guard, addr + 0x1a2));
for (std::size_t i = 0; i < gqr.size(); i++) for (std::size_t i = 0; i < gqr.size(); i++)
gqr[i] = PowerPC::HostRead_U32(addr + 0x1a4 + u32(i * sizeof(int))); gqr[i] = PowerPC::HostRead_U32(guard, addr + 0x1a4 + u32(i * sizeof(int)));
psf_padding = 0; psf_padding = 0;
for (std::size_t i = 0; i < psf.size(); i++) for (std::size_t i = 0; i < psf.size(); i++)
psf[i] = PowerPC::HostRead_F64(addr + 0x1c8 + u32(i * sizeof(double))); psf[i] = PowerPC::HostRead_F64(guard, addr + 0x1c8 + u32(i * sizeof(double)));
} }
// Mutex offsets based on the following functions: // Mutex offsets based on the following functions:
// - OSInitMutex // - OSInitMutex
// - OSLockMutex // - OSLockMutex
// - __OSUnlockAllMutex // - __OSUnlockAllMutex
void OSMutex::Read(u32 addr) void OSMutex::Read(const Core::CPUThreadGuard& guard, u32 addr)
{ {
thread_queue.head = PowerPC::HostRead_U32(addr); thread_queue.head = PowerPC::HostRead_U32(guard, addr);
thread_queue.tail = PowerPC::HostRead_U32(addr + 0x4); thread_queue.tail = PowerPC::HostRead_U32(guard, addr + 0x4);
owner_addr = PowerPC::HostRead_U32(addr + 0x8); owner_addr = PowerPC::HostRead_U32(guard, addr + 0x8);
lock_count = PowerPC::HostRead_U32(addr + 0xc); lock_count = PowerPC::HostRead_U32(guard, addr + 0xc);
link.next = PowerPC::HostRead_U32(addr + 0x10); link.next = PowerPC::HostRead_U32(guard, addr + 0x10);
link.prev = PowerPC::HostRead_U32(addr + 0x14); link.prev = PowerPC::HostRead_U32(guard, addr + 0x14);
} }
// Thread offsets based on the following functions: // Thread offsets based on the following functions:
@ -64,46 +64,47 @@ void OSMutex::Read(u32 addr)
// - __OSThreadInit // - __OSThreadInit
// - OSSetThreadSpecific // - OSSetThreadSpecific
// - SOInit (for errno) // - SOInit (for errno)
void OSThread::Read(u32 addr) void OSThread::Read(const Core::CPUThreadGuard& guard, u32 addr)
{ {
context.Read(addr); context.Read(guard, addr);
state = PowerPC::HostRead_U16(addr + 0x2c8); state = PowerPC::HostRead_U16(guard, addr + 0x2c8);
is_detached = PowerPC::HostRead_U16(addr + 0x2ca); is_detached = PowerPC::HostRead_U16(guard, addr + 0x2ca);
suspend = PowerPC::HostRead_U32(addr + 0x2cc); suspend = PowerPC::HostRead_U32(guard, addr + 0x2cc);
effective_priority = PowerPC::HostRead_U32(addr + 0x2d0); effective_priority = PowerPC::HostRead_U32(guard, addr + 0x2d0);
base_priority = PowerPC::HostRead_U32(addr + 0x2d4); base_priority = PowerPC::HostRead_U32(guard, addr + 0x2d4);
exit_code_addr = PowerPC::HostRead_U32(addr + 0x2d8); exit_code_addr = PowerPC::HostRead_U32(guard, addr + 0x2d8);
queue_addr = PowerPC::HostRead_U32(addr + 0x2dc); queue_addr = PowerPC::HostRead_U32(guard, addr + 0x2dc);
queue_link.next = PowerPC::HostRead_U32(addr + 0x2e0); queue_link.next = PowerPC::HostRead_U32(guard, addr + 0x2e0);
queue_link.prev = PowerPC::HostRead_U32(addr + 0x2e4); queue_link.prev = PowerPC::HostRead_U32(guard, addr + 0x2e4);
join_queue.head = PowerPC::HostRead_U32(addr + 0x2e8); join_queue.head = PowerPC::HostRead_U32(guard, addr + 0x2e8);
join_queue.tail = PowerPC::HostRead_U32(addr + 0x2ec); join_queue.tail = PowerPC::HostRead_U32(guard, addr + 0x2ec);
mutex_addr = PowerPC::HostRead_U32(addr + 0x2f0); mutex_addr = PowerPC::HostRead_U32(guard, addr + 0x2f0);
mutex_queue.head = PowerPC::HostRead_U32(addr + 0x2f4); mutex_queue.head = PowerPC::HostRead_U32(guard, addr + 0x2f4);
mutex_queue.tail = PowerPC::HostRead_U32(addr + 0x2f8); mutex_queue.tail = PowerPC::HostRead_U32(guard, addr + 0x2f8);
thread_link.next = PowerPC::HostRead_U32(addr + 0x2fc); thread_link.next = PowerPC::HostRead_U32(guard, addr + 0x2fc);
thread_link.prev = PowerPC::HostRead_U32(addr + 0x300); thread_link.prev = PowerPC::HostRead_U32(guard, addr + 0x300);
stack_addr = PowerPC::HostRead_U32(addr + 0x304); stack_addr = PowerPC::HostRead_U32(guard, addr + 0x304);
stack_end = PowerPC::HostRead_U32(addr + 0x308); stack_end = PowerPC::HostRead_U32(guard, addr + 0x308);
error = PowerPC::HostRead_U32(addr + 0x30c); error = PowerPC::HostRead_U32(guard, addr + 0x30c);
specific[0] = PowerPC::HostRead_U32(addr + 0x310); specific[0] = PowerPC::HostRead_U32(guard, addr + 0x310);
specific[1] = PowerPC::HostRead_U32(addr + 0x314); specific[1] = PowerPC::HostRead_U32(guard, addr + 0x314);
} }
bool OSThread::IsValid() const bool OSThread::IsValid(const Core::CPUThreadGuard& guard) const
{ {
return PowerPC::HostIsRAMAddress(stack_end) && PowerPC::HostRead_U32(stack_end) == STACK_MAGIC; return PowerPC::HostIsRAMAddress(guard, stack_end) &&
PowerPC::HostRead_U32(guard, stack_end) == STACK_MAGIC;
} }
OSThreadView::OSThreadView(u32 addr) OSThreadView::OSThreadView(const Core::CPUThreadGuard& guard, u32 addr)
{ {
m_address = addr; m_address = addr;
m_thread.Read(addr); m_thread.Read(guard, addr);
} }
const OSThread& OSThreadView::Data() const const OSThread& OSThreadView::Data() const
@ -111,11 +112,11 @@ const OSThread& OSThreadView::Data() const
return m_thread; return m_thread;
} }
Common::Debug::PartialContext OSThreadView::GetContext() const Common::Debug::PartialContext OSThreadView::GetContext(const Core::CPUThreadGuard& guard) const
{ {
Common::Debug::PartialContext context; Common::Debug::PartialContext context;
if (!IsValid()) if (!IsValid(guard))
return context; return context;
context.gpr = m_thread.context.gpr; context.gpr = m_thread.context.gpr;
@ -185,23 +186,23 @@ s32 OSThreadView::GetErrno() const
return m_thread.error; return m_thread.error;
} }
std::string OSThreadView::GetSpecific() const std::string OSThreadView::GetSpecific(const Core::CPUThreadGuard& guard) const
{ {
std::string specific; std::string specific;
for (u32 addr : m_thread.specific) for (u32 addr : m_thread.specific)
{ {
if (!PowerPC::HostIsRAMAddress(addr)) if (!PowerPC::HostIsRAMAddress(guard, addr))
break; break;
specific += fmt::format("{:08x} \"{}\"\n", addr, PowerPC::HostGetString(addr)); specific += fmt::format("{:08x} \"{}\"\n", addr, PowerPC::HostGetString(guard, addr));
} }
return specific; return specific;
} }
bool OSThreadView::IsValid() const bool OSThreadView::IsValid(const Core::CPUThreadGuard& guard) const
{ {
return m_thread.IsValid(); return m_thread.IsValid(guard);
} }
} // namespace Core::Debug } // namespace Core::Debug

View File

@ -10,6 +10,11 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Debug/Threads.h" #include "Common/Debug/Threads.h"
namespace Core
{
class CPUThreadGuard;
};
namespace Core::Debug namespace Core::Debug
{ {
template <class C> template <class C>
@ -56,7 +61,7 @@ struct OSContext
u32 psf_padding; u32 psf_padding;
std::array<double, 32> psf; std::array<double, 32> psf;
void Read(u32 addr); void Read(const Core::CPUThreadGuard& guard, u32 addr);
}; };
static_assert(std::is_trivially_copyable_v<OSContext>); static_assert(std::is_trivially_copyable_v<OSContext>);
@ -96,8 +101,8 @@ struct OSThread
std::array<u32, 2> specific; // Pointers to data (can be used to store thread names) std::array<u32, 2> specific; // Pointers to data (can be used to store thread names)
static constexpr u32 STACK_MAGIC = 0xDEADBABE; static constexpr u32 STACK_MAGIC = 0xDEADBABE;
void Read(u32 addr); void Read(const Core::CPUThreadGuard& guard, u32 addr);
bool IsValid() const; bool IsValid(const Core::CPUThreadGuard& guard) const;
}; };
static_assert(std::is_trivially_copyable_v<OSThread>); static_assert(std::is_trivially_copyable_v<OSThread>);
@ -115,7 +120,7 @@ struct OSMutex
OSMutexLink link; // Used to traverse the thread's mutex queue OSMutexLink link; // Used to traverse the thread's mutex queue
// OSLockMutex uses it to insert the acquired mutex at the end of the queue // OSLockMutex uses it to insert the acquired mutex at the end of the queue
void Read(u32 addr); void Read(const Core::CPUThreadGuard& guard, u32 addr);
}; };
static_assert(std::is_trivially_copyable_v<OSMutex>); static_assert(std::is_trivially_copyable_v<OSMutex>);
@ -126,12 +131,12 @@ static_assert(offsetof(OSMutex, link) == 0x10);
class OSThreadView : public Common::Debug::ThreadView class OSThreadView : public Common::Debug::ThreadView
{ {
public: public:
explicit OSThreadView(u32 addr); explicit OSThreadView(const Core::CPUThreadGuard& guard, u32 addr);
~OSThreadView() = default; ~OSThreadView() = default;
const OSThread& Data() const; const OSThread& Data() const;
Common::Debug::PartialContext GetContext() const override; Common::Debug::PartialContext GetContext(const Core::CPUThreadGuard& guard) const override;
u32 GetAddress() const override; u32 GetAddress() const override;
u16 GetState() const override; u16 GetState() const override;
bool IsSuspended() const override; bool IsSuspended() const override;
@ -142,8 +147,8 @@ public:
u32 GetStackEnd() const override; u32 GetStackEnd() const override;
std::size_t GetStackSize() const override; std::size_t GetStackSize() const override;
s32 GetErrno() const override; s32 GetErrno() const override;
std::string GetSpecific() const override; std::string GetSpecific(const Core::CPUThreadGuard& guard) const override;
bool IsValid() const override; bool IsValid(const Core::CPUThreadGuard& guard) const override;
private: private:
u32 m_address = 0; u32 m_address = 0;

View File

@ -25,27 +25,28 @@
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "Core/System.h" #include "Core/System.h"
void ApplyMemoryPatch(Common::Debug::MemoryPatch& patch, bool store_existing_value) void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, Common::Debug::MemoryPatch& patch,
bool store_existing_value)
{ {
if (patch.value.empty()) if (patch.value.empty())
return; return;
const u32 address = patch.address; const u32 address = patch.address;
const std::size_t size = patch.value.size(); const std::size_t size = patch.value.size();
if (!PowerPC::HostIsRAMAddress(address)) if (!PowerPC::HostIsRAMAddress(guard, address))
return; return;
for (u32 offset = 0; offset < size; ++offset) for (u32 offset = 0; offset < size; ++offset)
{ {
if (store_existing_value) if (store_existing_value)
{ {
const u8 value = PowerPC::HostRead_U8(address + offset); const u8 value = PowerPC::HostRead_U8(guard, address + offset);
PowerPC::HostWrite_U8(patch.value[offset], address + offset); PowerPC::HostWrite_U8(guard, patch.value[offset], address + offset);
patch.value[offset] = value; patch.value[offset] = value;
} }
else else
{ {
PowerPC::HostWrite_U8(patch.value[offset], address + offset); PowerPC::HostWrite_U8(guard, patch.value[offset], address + offset);
} }
if (((address + offset) % 4) == 3) if (((address + offset) % 4) == 3)
@ -58,17 +59,17 @@ void ApplyMemoryPatch(Common::Debug::MemoryPatch& patch, bool store_existing_val
} }
} }
void PPCPatches::ApplyExistingPatch(std::size_t index) void PPCPatches::ApplyExistingPatch(const Core::CPUThreadGuard& guard, std::size_t index)
{ {
auto& patch = m_patches[index]; auto& patch = m_patches[index];
ApplyMemoryPatch(patch, false); ApplyMemoryPatch(guard, patch, false);
} }
void PPCPatches::Patch(std::size_t index) void PPCPatches::Patch(const Core::CPUThreadGuard& guard, std::size_t index)
{ {
auto& patch = m_patches[index]; auto& patch = m_patches[index];
if (patch.type == Common::Debug::MemoryPatch::ApplyType::Once) if (patch.type == Common::Debug::MemoryPatch::ApplyType::Once)
ApplyMemoryPatch(patch); ApplyMemoryPatch(guard, patch);
else else
PatchEngine::AddMemoryPatch(index); PatchEngine::AddMemoryPatch(index);
} }
@ -163,24 +164,26 @@ void PPCDebugInterface::ClearWatches()
m_watches.Clear(); m_watches.Clear();
} }
void PPCDebugInterface::SetPatch(u32 address, u32 value) void PPCDebugInterface::SetPatch(const Core::CPUThreadGuard& guard, u32 address, u32 value)
{ {
m_patches.SetPatch(address, value); m_patches.SetPatch(guard, address, value);
} }
void PPCDebugInterface::SetPatch(u32 address, std::vector<u8> value) void PPCDebugInterface::SetPatch(const Core::CPUThreadGuard& guard, u32 address,
std::vector<u8> value)
{ {
m_patches.SetPatch(address, std::move(value)); m_patches.SetPatch(guard, address, std::move(value));
} }
void PPCDebugInterface::SetFramePatch(u32 address, u32 value) void PPCDebugInterface::SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, u32 value)
{ {
m_patches.SetFramePatch(address, value); m_patches.SetFramePatch(guard, address, value);
} }
void PPCDebugInterface::SetFramePatch(u32 address, std::vector<u8> value) void PPCDebugInterface::SetFramePatch(const Core::CPUThreadGuard& guard, u32 address,
std::vector<u8> value)
{ {
m_patches.SetFramePatch(address, std::move(value)); m_patches.SetFramePatch(guard, address, std::move(value));
} }
const std::vector<Common::Debug::MemoryPatch>& PPCDebugInterface::GetPatches() const const std::vector<Common::Debug::MemoryPatch>& PPCDebugInterface::GetPatches() const
@ -188,19 +191,19 @@ const std::vector<Common::Debug::MemoryPatch>& PPCDebugInterface::GetPatches() c
return m_patches.GetPatches(); return m_patches.GetPatches();
} }
void PPCDebugInterface::UnsetPatch(u32 address) void PPCDebugInterface::UnsetPatch(const Core::CPUThreadGuard& guard, u32 address)
{ {
m_patches.UnsetPatch(address); m_patches.UnsetPatch(guard, address);
} }
void PPCDebugInterface::EnablePatch(std::size_t index) void PPCDebugInterface::EnablePatch(const Core::CPUThreadGuard& guard, std::size_t index)
{ {
m_patches.EnablePatch(index); m_patches.EnablePatch(guard, index);
} }
void PPCDebugInterface::DisablePatch(std::size_t index) void PPCDebugInterface::DisablePatch(const Core::CPUThreadGuard& guard, std::size_t index)
{ {
m_patches.DisablePatch(index); m_patches.DisablePatch(guard, index);
} }
bool PPCDebugInterface::HasEnabledPatch(u32 address) const bool PPCDebugInterface::HasEnabledPatch(u32 address) const
@ -208,45 +211,45 @@ bool PPCDebugInterface::HasEnabledPatch(u32 address) const
return m_patches.HasEnabledPatch(address); return m_patches.HasEnabledPatch(address);
} }
void PPCDebugInterface::RemovePatch(std::size_t index) void PPCDebugInterface::RemovePatch(const Core::CPUThreadGuard& guard, std::size_t index)
{ {
m_patches.RemovePatch(index); m_patches.RemovePatch(guard, index);
} }
void PPCDebugInterface::ClearPatches() void PPCDebugInterface::ClearPatches(const Core::CPUThreadGuard& guard)
{ {
m_patches.ClearPatches(); m_patches.ClearPatches(guard);
} }
void PPCDebugInterface::ApplyExistingPatch(std::size_t index) void PPCDebugInterface::ApplyExistingPatch(const Core::CPUThreadGuard& guard, std::size_t index)
{ {
m_patches.ApplyExistingPatch(index); m_patches.ApplyExistingPatch(guard, index);
} }
Common::Debug::Threads PPCDebugInterface::GetThreads() const Common::Debug::Threads PPCDebugInterface::GetThreads(const Core::CPUThreadGuard& guard) const
{ {
Common::Debug::Threads threads; Common::Debug::Threads threads;
constexpr u32 ACTIVE_QUEUE_HEAD_ADDR = 0x800000dc; constexpr u32 ACTIVE_QUEUE_HEAD_ADDR = 0x800000dc;
if (!PowerPC::HostIsRAMAddress(ACTIVE_QUEUE_HEAD_ADDR)) if (!PowerPC::HostIsRAMAddress(guard, ACTIVE_QUEUE_HEAD_ADDR))
return threads; return threads;
const u32 active_queue_head = PowerPC::HostRead_U32(ACTIVE_QUEUE_HEAD_ADDR); const u32 active_queue_head = PowerPC::HostRead_U32(guard, ACTIVE_QUEUE_HEAD_ADDR);
if (!PowerPC::HostIsRAMAddress(active_queue_head)) if (!PowerPC::HostIsRAMAddress(guard, active_queue_head))
return threads; return threads;
auto active_thread = std::make_unique<Core::Debug::OSThreadView>(active_queue_head); auto active_thread = std::make_unique<Core::Debug::OSThreadView>(guard, active_queue_head);
if (!active_thread->IsValid()) if (!active_thread->IsValid(guard))
return threads; return threads;
std::vector<u32> visited_addrs{active_thread->GetAddress()}; std::vector<u32> visited_addrs{active_thread->GetAddress()};
const auto insert_threads = [&threads, &visited_addrs](u32 addr, auto get_next_addr) { const auto insert_threads = [&guard, &threads, &visited_addrs](u32 addr, auto get_next_addr) {
while (addr != 0 && PowerPC::HostIsRAMAddress(addr)) while (addr != 0 && PowerPC::HostIsRAMAddress(guard, addr))
{ {
if (std::find(visited_addrs.begin(), visited_addrs.end(), addr) != visited_addrs.end()) if (std::find(visited_addrs.begin(), visited_addrs.end(), addr) != visited_addrs.end())
break; break;
visited_addrs.push_back(addr); visited_addrs.push_back(addr);
auto thread = std::make_unique<Core::Debug::OSThreadView>(addr); auto thread = std::make_unique<Core::Debug::OSThreadView>(guard, addr);
if (!thread->IsValid()) if (!thread->IsValid(guard))
break; break;
addr = get_next_addr(*thread); addr = get_next_addr(*thread);
threads.emplace_back(std::move(thread)); threads.emplace_back(std::move(thread));
@ -264,20 +267,16 @@ Common::Debug::Threads PPCDebugInterface::GetThreads() const
return threads; return threads;
} }
std::string PPCDebugInterface::Disassemble(u32 address) const std::string PPCDebugInterface::Disassemble(const Core::CPUThreadGuard* guard, u32 address) const
{ {
// PowerPC::HostRead_U32 seemed to crash on shutdown if (guard)
if (!IsAlive())
return "";
if (Core::GetState() == Core::State::Paused)
{ {
if (!PowerPC::HostIsRAMAddress(address)) if (!PowerPC::HostIsRAMAddress(*guard, address))
{ {
return "(No RAM here)"; return "(No RAM here)";
} }
const u32 op = PowerPC::HostRead_Instruction(address); const u32 op = PowerPC::HostRead_Instruction(*guard, address);
std::string disasm = Common::GekkoDisassembler::Disassemble(op, address); std::string disasm = Common::GekkoDisassembler::Disassemble(op, address);
const UGeckoInstruction inst{op}; const UGeckoInstruction inst{op};
@ -294,14 +293,18 @@ std::string PPCDebugInterface::Disassemble(u32 address) const
} }
} }
std::string PPCDebugInterface::GetRawMemoryString(int memory, u32 address) const std::string PPCDebugInterface::GetRawMemoryString(const Core::CPUThreadGuard& guard, int memory,
u32 address) const
{ {
if (IsAlive()) if (IsAlive())
{ {
const bool is_aram = memory != 0; const bool is_aram = memory != 0;
if (is_aram || PowerPC::HostIsRAMAddress(address)) if (is_aram || PowerPC::HostIsRAMAddress(guard, address))
return fmt::format("{:08X}{}", ReadExtraMemory(memory, address), is_aram ? " (ARAM)" : ""); {
return fmt::format("{:08X}{}", ReadExtraMemory(guard, memory, address),
is_aram ? " (ARAM)" : "");
}
return is_aram ? "--ARAM--" : "--------"; return is_aram ? "--ARAM--" : "--------";
} }
@ -309,17 +312,18 @@ std::string PPCDebugInterface::GetRawMemoryString(int memory, u32 address) const
return "<unknwn>"; // bad spelling - 8 chars return "<unknwn>"; // bad spelling - 8 chars
} }
u32 PPCDebugInterface::ReadMemory(u32 address) const u32 PPCDebugInterface::ReadMemory(const Core::CPUThreadGuard& guard, u32 address) const
{ {
return PowerPC::HostRead_U32(address); return PowerPC::HostRead_U32(guard, address);
} }
u32 PPCDebugInterface::ReadExtraMemory(int memory, u32 address) const u32 PPCDebugInterface::ReadExtraMemory(const Core::CPUThreadGuard& guard, int memory,
u32 address) const
{ {
switch (memory) switch (memory)
{ {
case 0: case 0:
return PowerPC::HostRead_U32(address); return PowerPC::HostRead_U32(guard, address);
case 1: case 1:
return (DSP::ReadARAM(address) << 24) | (DSP::ReadARAM(address + 1) << 16) | return (DSP::ReadARAM(address) << 24) | (DSP::ReadARAM(address + 1) << 16) |
(DSP::ReadARAM(address + 2) << 8) | (DSP::ReadARAM(address + 3)); (DSP::ReadARAM(address + 2) << 8) | (DSP::ReadARAM(address + 3));
@ -328,9 +332,9 @@ u32 PPCDebugInterface::ReadExtraMemory(int memory, u32 address) const
} }
} }
u32 PPCDebugInterface::ReadInstruction(u32 address) const u32 PPCDebugInterface::ReadInstruction(const Core::CPUThreadGuard& guard, u32 address) const
{ {
return PowerPC::HostRead_Instruction(address); return PowerPC::HostRead_Instruction(guard, address);
} }
bool PPCDebugInterface::IsAlive() const bool PPCDebugInterface::IsAlive() const
@ -401,11 +405,11 @@ void PPCDebugInterface::ToggleMemCheck(u32 address, bool read, bool write, bool
// ======================================================= // =======================================================
// Separate the blocks with colors. // Separate the blocks with colors.
// ------------- // -------------
u32 PPCDebugInterface::GetColor(u32 address) const u32 PPCDebugInterface::GetColor(const Core::CPUThreadGuard* guard, u32 address) const
{ {
if (!IsAlive()) if (!guard || !IsAlive())
return 0xFFFFFF; return 0xFFFFFF;
if (!PowerPC::HostIsRAMAddress(address)) if (!PowerPC::HostIsRAMAddress(*guard, address))
return 0xeeeeee; return 0xeeeeee;
Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(address); Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(address);
@ -525,11 +529,11 @@ std::shared_ptr<Core::NetworkCaptureLogger> PPCDebugInterface::NetworkLogger()
return m_network_logger; return m_network_logger;
} }
void PPCDebugInterface::Clear() void PPCDebugInterface::Clear(const Core::CPUThreadGuard& guard)
{ {
ClearAllBreakpoints(); ClearAllBreakpoints();
ClearAllMemChecks(); ClearAllMemChecks();
ClearPatches(); ClearPatches(guard);
ClearWatches(); ClearWatches();
m_network_logger.reset(); m_network_logger.reset();
} }

View File

@ -14,18 +14,20 @@
namespace Core namespace Core
{ {
class CPUThreadGuard;
class System; class System;
} } // namespace Core
void ApplyMemoryPatch(Common::Debug::MemoryPatch& patch, bool store_existing_value = true); void ApplyMemoryPatch(const Core::CPUThreadGuard&, Common::Debug::MemoryPatch& patch,
bool store_existing_value = true);
class PPCPatches final : public Common::Debug::MemoryPatches class PPCPatches final : public Common::Debug::MemoryPatches
{ {
public: public:
void ApplyExistingPatch(std::size_t index) override; void ApplyExistingPatch(const Core::CPUThreadGuard& guard, std::size_t index) override;
private: private:
void Patch(std::size_t index) override; void Patch(const Core::CPUThreadGuard& guard, std::size_t index) override;
void UnPatch(std::size_t index) override; void UnPatch(std::size_t index) override;
}; };
@ -55,24 +57,26 @@ public:
void ClearWatches() override; void ClearWatches() override;
// Memory Patches // Memory Patches
void SetPatch(u32 address, u32 value) override; void SetPatch(const Core::CPUThreadGuard& guard, u32 address, u32 value) override;
void SetPatch(u32 address, std::vector<u8> value) override; void SetPatch(const Core::CPUThreadGuard& guard, u32 address, std::vector<u8> value) override;
void SetFramePatch(u32 address, u32 value) override; void SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, u32 value) override;
void SetFramePatch(u32 address, std::vector<u8> value) override; void SetFramePatch(const Core::CPUThreadGuard& guard, u32 address,
std::vector<u8> value) override;
const std::vector<Common::Debug::MemoryPatch>& GetPatches() const override; const std::vector<Common::Debug::MemoryPatch>& GetPatches() const override;
void UnsetPatch(u32 address) override; void UnsetPatch(const Core::CPUThreadGuard& guard, u32 address) override;
void EnablePatch(std::size_t index) override; void EnablePatch(const Core::CPUThreadGuard& guard, std::size_t index) override;
void DisablePatch(std::size_t index) override; void DisablePatch(const Core::CPUThreadGuard& guard, std::size_t index) override;
bool HasEnabledPatch(u32 address) const override; bool HasEnabledPatch(u32 address) const override;
void RemovePatch(std::size_t index) override; void RemovePatch(const Core::CPUThreadGuard& guard, std::size_t index) override;
void ClearPatches() override; void ClearPatches(const Core::CPUThreadGuard& guard) override;
void ApplyExistingPatch(std::size_t index) override; void ApplyExistingPatch(const Core::CPUThreadGuard& guard, std::size_t index) override;
// Threads // Threads
Common::Debug::Threads GetThreads() const override; Common::Debug::Threads GetThreads(const Core::CPUThreadGuard& guard) const override;
std::string Disassemble(u32 address) const override; std::string Disassemble(const Core::CPUThreadGuard* guard, u32 address) const override;
std::string GetRawMemoryString(int memory, u32 address) const override; std::string GetRawMemoryString(const Core::CPUThreadGuard& guard, int memory,
u32 address) const override;
bool IsAlive() const override; bool IsAlive() const override;
bool IsBreakpoint(u32 address) const override; bool IsBreakpoint(u32 address) const override;
void SetBreakpoint(u32 address) override; void SetBreakpoint(u32 address) override;
@ -82,26 +86,26 @@ public:
void ClearAllMemChecks() override; void ClearAllMemChecks() override;
bool IsMemCheck(u32 address, size_t size = 1) const override; bool IsMemCheck(u32 address, size_t size = 1) const override;
void ToggleMemCheck(u32 address, bool read = true, bool write = true, bool log = true) override; void ToggleMemCheck(u32 address, bool read = true, bool write = true, bool log = true) override;
u32 ReadMemory(u32 address) const override; u32 ReadMemory(const Core::CPUThreadGuard& guard, u32 address) const override;
enum enum
{ {
EXTRAMEM_ARAM = 1, EXTRAMEM_ARAM = 1,
}; };
u32 ReadExtraMemory(int memory, u32 address) const override; u32 ReadExtraMemory(const Core::CPUThreadGuard& guard, int memory, u32 address) const override;
u32 ReadInstruction(u32 address) const override; u32 ReadInstruction(const Core::CPUThreadGuard& guard, u32 address) const override;
std::optional<u32> GetMemoryAddressFromInstruction(const std::string& instruction) const override; std::optional<u32> GetMemoryAddressFromInstruction(const std::string& instruction) const override;
u32 GetPC() const override; u32 GetPC() const override;
void SetPC(u32 address) override; void SetPC(u32 address) override;
void Step() override {} void Step() override {}
void RunToBreakpoint() override; void RunToBreakpoint() override;
u32 GetColor(u32 address) const override; u32 GetColor(const Core::CPUThreadGuard* guard, u32 address) const override;
std::string GetDescription(u32 address) const override; std::string GetDescription(u32 address) const override;
std::shared_ptr<Core::NetworkCaptureLogger> NetworkLogger(); std::shared_ptr<Core::NetworkCaptureLogger> NetworkLogger();
void Clear() override; void Clear(const Core::CPUThreadGuard& guard) override;
private: private:
Common::Debug::Watches m_watches; Common::Debug::Watches m_watches;

View File

@ -14,40 +14,40 @@
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PPCSymbolDB.h" #include "Core/PowerPC/PPCSymbolDB.h"
void RSOHeaderView::Load(u32 address) void RSOHeaderView::Load(const Core::CPUThreadGuard& guard, u32 address)
{ {
m_address = address; m_address = address;
m_header.entry.next_entry = PowerPC::HostRead_U32(address); m_header.entry.next_entry = PowerPC::HostRead_U32(guard, address);
m_header.entry.prev_entry = PowerPC::HostRead_U32(address + 0x04); m_header.entry.prev_entry = PowerPC::HostRead_U32(guard, address + 0x04);
m_header.entry.section_count = PowerPC::HostRead_U32(address + 0x08); m_header.entry.section_count = PowerPC::HostRead_U32(guard, address + 0x08);
m_header.entry.section_table_offset = PowerPC::HostRead_U32(address + 0xC); m_header.entry.section_table_offset = PowerPC::HostRead_U32(guard, address + 0xC);
m_header.entry.name_offset = PowerPC::HostRead_U32(address + 0x10); m_header.entry.name_offset = PowerPC::HostRead_U32(guard, address + 0x10);
m_header.entry.name_size = PowerPC::HostRead_U32(address + 0x14); m_header.entry.name_size = PowerPC::HostRead_U32(guard, address + 0x14);
m_header.entry.version = PowerPC::HostRead_U32(address + 0x18); m_header.entry.version = PowerPC::HostRead_U32(guard, address + 0x18);
m_header.entry.bss_size = PowerPC::HostRead_U32(address + 0x1C); m_header.entry.bss_size = PowerPC::HostRead_U32(guard, address + 0x1C);
m_header.section_info.prolog_section_index = PowerPC::HostRead_U8(address + 0x20); m_header.section_info.prolog_section_index = PowerPC::HostRead_U8(guard, address + 0x20);
m_header.section_info.epilog_section_index = PowerPC::HostRead_U8(address + 0x21); m_header.section_info.epilog_section_index = PowerPC::HostRead_U8(guard, address + 0x21);
m_header.section_info.unresolved_section_index = PowerPC::HostRead_U8(address + 0x22); m_header.section_info.unresolved_section_index = PowerPC::HostRead_U8(guard, address + 0x22);
m_header.section_info.bss_section_index = PowerPC::HostRead_U8(address + 0x23); m_header.section_info.bss_section_index = PowerPC::HostRead_U8(guard, address + 0x23);
m_header.section_info.prolog_offset = PowerPC::HostRead_U32(address + 0x24); m_header.section_info.prolog_offset = PowerPC::HostRead_U32(guard, address + 0x24);
m_header.section_info.epilog_offset = PowerPC::HostRead_U32(address + 0x28); m_header.section_info.epilog_offset = PowerPC::HostRead_U32(guard, address + 0x28);
m_header.section_info.unresolved_offset = PowerPC::HostRead_U32(address + 0x2C); m_header.section_info.unresolved_offset = PowerPC::HostRead_U32(guard, address + 0x2C);
m_header.relocation_tables.internals_offset = PowerPC::HostRead_U32(address + 0x30); m_header.relocation_tables.internals_offset = PowerPC::HostRead_U32(guard, address + 0x30);
m_header.relocation_tables.internals_size = PowerPC::HostRead_U32(address + 0x34); m_header.relocation_tables.internals_size = PowerPC::HostRead_U32(guard, address + 0x34);
m_header.relocation_tables.externals_offset = PowerPC::HostRead_U32(address + 0x38); m_header.relocation_tables.externals_offset = PowerPC::HostRead_U32(guard, address + 0x38);
m_header.relocation_tables.externals_size = PowerPC::HostRead_U32(address + 0x3C); m_header.relocation_tables.externals_size = PowerPC::HostRead_U32(guard, address + 0x3C);
m_header.symbol_tables.exports_offset = PowerPC::HostRead_U32(address + 0x40); m_header.symbol_tables.exports_offset = PowerPC::HostRead_U32(guard, address + 0x40);
m_header.symbol_tables.exports_size = PowerPC::HostRead_U32(address + 0x44); m_header.symbol_tables.exports_size = PowerPC::HostRead_U32(guard, address + 0x44);
m_header.symbol_tables.exports_name_table = PowerPC::HostRead_U32(address + 0x48); m_header.symbol_tables.exports_name_table = PowerPC::HostRead_U32(guard, address + 0x48);
m_header.symbol_tables.imports_offset = PowerPC::HostRead_U32(address + 0x4C); m_header.symbol_tables.imports_offset = PowerPC::HostRead_U32(guard, address + 0x4C);
m_header.symbol_tables.imports_size = PowerPC::HostRead_U32(address + 0x50); m_header.symbol_tables.imports_size = PowerPC::HostRead_U32(guard, address + 0x50);
m_header.symbol_tables.imports_name_table = PowerPC::HostRead_U32(address + 0x54); m_header.symbol_tables.imports_name_table = PowerPC::HostRead_U32(guard, address + 0x54);
// Prevent an invalid name going wild // Prevent an invalid name going wild
if (m_header.entry.name_size < 0x100) if (m_header.entry.name_size < 0x100)
m_name = PowerPC::HostGetString(m_header.entry.name_offset, m_header.entry.name_size); m_name = PowerPC::HostGetString(guard, m_header.entry.name_offset, m_header.entry.name_size);
else else
m_name = PowerPC::HostGetString(m_header.entry.name_offset, 0x100); m_name = PowerPC::HostGetString(guard, m_header.entry.name_offset, 0x100);
} }
u32 RSOHeaderView::GetNextEntry() const u32 RSOHeaderView::GetNextEntry() const
@ -170,14 +170,14 @@ u32 RSOHeaderView::GetImportsNameTable() const
return m_header.symbol_tables.imports_name_table; return m_header.symbol_tables.imports_name_table;
} }
void RSOSectionsView::Load(u32 address, std::size_t count) void RSOSectionsView::Load(const Core::CPUThreadGuard& guard, u32 address, std::size_t count)
{ {
m_address = address; m_address = address;
for (std::size_t i = 0; i < count; ++i) for (std::size_t i = 0; i < count; ++i)
{ {
RSOSection section; RSOSection section;
section.offset = PowerPC::HostRead_U32(address); section.offset = PowerPC::HostRead_U32(guard, address);
section.size = PowerPC::HostRead_U32(address + 4); section.size = PowerPC::HostRead_U32(guard, address + 4);
m_sections.emplace_back(std::move(section)); m_sections.emplace_back(std::move(section));
address += sizeof(RSOSection); address += sizeof(RSOSection);
} }
@ -198,15 +198,15 @@ const std::vector<RSOSection>& RSOSectionsView::GetSections() const
return m_sections; return m_sections;
} }
void RSOImportsView::Load(u32 address, std::size_t count) void RSOImportsView::Load(const Core::CPUThreadGuard& guard, u32 address, std::size_t count)
{ {
m_address = address; m_address = address;
for (std::size_t i = 0; i < count; ++i) for (std::size_t i = 0; i < count; ++i)
{ {
RSOImport rso_import; RSOImport rso_import;
rso_import.name_offset = PowerPC::HostRead_U32(address); rso_import.name_offset = PowerPC::HostRead_U32(guard, address);
rso_import.code_offset = PowerPC::HostRead_U32(address + 4); rso_import.code_offset = PowerPC::HostRead_U32(guard, address + 4);
rso_import.entry_offset = PowerPC::HostRead_U32(address + 8); rso_import.entry_offset = PowerPC::HostRead_U32(guard, address + 8);
m_imports.emplace_back(std::move(rso_import)); m_imports.emplace_back(std::move(rso_import));
address += sizeof(RSOImport); address += sizeof(RSOImport);
} }
@ -227,16 +227,16 @@ const std::vector<RSOImport>& RSOImportsView::GetImports() const
return m_imports; return m_imports;
} }
void RSOExportsView::Load(u32 address, std::size_t count) void RSOExportsView::Load(const Core::CPUThreadGuard& guard, u32 address, std::size_t count)
{ {
m_address = address; m_address = address;
for (std::size_t i = 0; i < count; ++i) for (std::size_t i = 0; i < count; ++i)
{ {
RSOExport rso_export; RSOExport rso_export;
rso_export.name_offset = PowerPC::HostRead_U32(address); rso_export.name_offset = PowerPC::HostRead_U32(guard, address);
rso_export.code_offset = PowerPC::HostRead_U32(address + 4); rso_export.code_offset = PowerPC::HostRead_U32(guard, address + 4);
rso_export.section_index = PowerPC::HostRead_U32(address + 8); rso_export.section_index = PowerPC::HostRead_U32(guard, address + 8);
rso_export.hash = PowerPC::HostRead_U32(address + 12); rso_export.hash = PowerPC::HostRead_U32(guard, address + 12);
m_exports.emplace_back(std::move(rso_export)); m_exports.emplace_back(std::move(rso_export));
address += sizeof(RSOExport); address += sizeof(RSOExport);
} }
@ -257,15 +257,15 @@ const std::vector<RSOExport>& RSOExportsView::GetExports() const
return m_exports; return m_exports;
} }
void RSOInternalsView::Load(u32 address, std::size_t count) void RSOInternalsView::Load(const Core::CPUThreadGuard& guard, u32 address, std::size_t count)
{ {
m_address = address; m_address = address;
for (std::size_t i = 0; i < count; ++i) for (std::size_t i = 0; i < count; ++i)
{ {
RSOInternalsEntry entry; RSOInternalsEntry entry;
entry.r_offset = PowerPC::HostRead_U32(address); entry.r_offset = PowerPC::HostRead_U32(guard, address);
entry.r_info = PowerPC::HostRead_U32(address + 4); entry.r_info = PowerPC::HostRead_U32(guard, address + 4);
entry.r_addend = PowerPC::HostRead_U32(address + 8); entry.r_addend = PowerPC::HostRead_U32(guard, address + 8);
m_entries.emplace_back(std::move(entry)); m_entries.emplace_back(std::move(entry));
address += sizeof(RSOInternalsEntry); address += sizeof(RSOInternalsEntry);
} }
@ -286,15 +286,15 @@ const std::vector<RSOInternalsEntry>& RSOInternalsView::GetEntries() const
return m_entries; return m_entries;
} }
void RSOExternalsView::Load(u32 address, std::size_t count) void RSOExternalsView::Load(const Core::CPUThreadGuard& guard, u32 address, std::size_t count)
{ {
m_address = address; m_address = address;
for (std::size_t i = 0; i < count; ++i) for (std::size_t i = 0; i < count; ++i)
{ {
RSOExternalsEntry entry; RSOExternalsEntry entry;
entry.r_offset = PowerPC::HostRead_U32(address); entry.r_offset = PowerPC::HostRead_U32(guard, address);
entry.r_info = PowerPC::HostRead_U32(address + 4); entry.r_info = PowerPC::HostRead_U32(guard, address + 4);
entry.r_addend = PowerPC::HostRead_U32(address + 8); entry.r_addend = PowerPC::HostRead_U32(guard, address + 8);
m_entries.emplace_back(std::move(entry)); m_entries.emplace_back(std::move(entry));
address += sizeof(RSOExternalsEntry); address += sizeof(RSOExternalsEntry);
} }
@ -315,71 +315,71 @@ const std::vector<RSOExternalsEntry>& RSOExternalsView::GetEntries() const
return m_entries; return m_entries;
} }
void RSOView::LoadHeader(u32 address) void RSOView::LoadHeader(const Core::CPUThreadGuard& guard, u32 address)
{ {
m_address = address; m_address = address;
m_header.Load(address); m_header.Load(guard, address);
} }
void RSOView::LoadSections() void RSOView::LoadSections(const Core::CPUThreadGuard& guard)
{ {
m_sections.Load(m_header.GetSectionTableOffset(), m_header.GetSectionCount()); m_sections.Load(guard, m_header.GetSectionTableOffset(), m_header.GetSectionCount());
} }
void RSOView::LoadImports() void RSOView::LoadImports(const Core::CPUThreadGuard& guard)
{ {
const std::size_t size = m_header.GetImportsSize(); const std::size_t size = m_header.GetImportsSize();
if (size % sizeof(RSOImport) != 0) if (size % sizeof(RSOImport) != 0)
WARN_LOG_FMT(SYMBOLS, "RSO Imports Table has an incoherent size ({:08x})", size); WARN_LOG_FMT(SYMBOLS, "RSO Imports Table has an incoherent size ({:08x})", size);
m_imports.Load(m_header.GetImportsOffset(), size / sizeof(RSOImport)); m_imports.Load(guard, m_header.GetImportsOffset(), size / sizeof(RSOImport));
} }
void RSOView::LoadExports() void RSOView::LoadExports(const Core::CPUThreadGuard& guard)
{ {
const std::size_t size = m_header.GetExportsSize(); const std::size_t size = m_header.GetExportsSize();
if (size % sizeof(RSOExport) != 0) if (size % sizeof(RSOExport) != 0)
WARN_LOG_FMT(SYMBOLS, "RSO Exports Table has an incoherent size ({:08x})", size); WARN_LOG_FMT(SYMBOLS, "RSO Exports Table has an incoherent size ({:08x})", size);
m_exports.Load(m_header.GetExportsOffset(), size / sizeof(RSOExport)); m_exports.Load(guard, m_header.GetExportsOffset(), size / sizeof(RSOExport));
} }
void RSOView::LoadInternals() void RSOView::LoadInternals(const Core::CPUThreadGuard& guard)
{ {
const std::size_t size = m_header.GetInternalsSize(); const std::size_t size = m_header.GetInternalsSize();
if (size % sizeof(RSOInternalsEntry) != 0) if (size % sizeof(RSOInternalsEntry) != 0)
WARN_LOG_FMT(SYMBOLS, "RSO Internals Relocation Table has an incoherent size ({:08x})", size); WARN_LOG_FMT(SYMBOLS, "RSO Internals Relocation Table has an incoherent size ({:08x})", size);
m_imports.Load(m_header.GetInternalsOffset(), size / sizeof(RSOInternalsEntry)); m_imports.Load(guard, m_header.GetInternalsOffset(), size / sizeof(RSOInternalsEntry));
} }
void RSOView::LoadExternals() void RSOView::LoadExternals(const Core::CPUThreadGuard& guard)
{ {
const std::size_t size = m_header.GetExternalsSize(); const std::size_t size = m_header.GetExternalsSize();
if (size % sizeof(RSOExternalsEntry) != 0) if (size % sizeof(RSOExternalsEntry) != 0)
WARN_LOG_FMT(SYMBOLS, "RSO Externals Relocation Table has an incoherent size ({:08x})", size); WARN_LOG_FMT(SYMBOLS, "RSO Externals Relocation Table has an incoherent size ({:08x})", size);
m_imports.Load(m_header.GetExternalsOffset(), size / sizeof(RSOExternalsEntry)); m_imports.Load(guard, m_header.GetExternalsOffset(), size / sizeof(RSOExternalsEntry));
} }
void RSOView::LoadAll(u32 address) void RSOView::LoadAll(const Core::CPUThreadGuard& guard, u32 address)
{ {
LoadHeader(address); LoadHeader(guard, address);
LoadSections(); LoadSections(guard);
LoadImports(); LoadImports(guard);
LoadExports(); LoadExports(guard);
LoadInternals(); LoadInternals(guard);
LoadExternals(); LoadExternals(guard);
} }
void RSOView::Apply(PPCSymbolDB* symbol_db) const void RSOView::Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* symbol_db) const
{ {
for (const RSOExport& rso_export : GetExports()) for (const RSOExport& rso_export : GetExports())
{ {
u32 address = GetExportAddress(rso_export); u32 address = GetExportAddress(rso_export);
if (address != 0) if (address != 0)
{ {
Common::Symbol* symbol = symbol_db->AddFunction(address); Common::Symbol* symbol = symbol_db->AddFunction(guard, address);
if (!symbol) if (!symbol)
symbol = symbol_db->GetSymbolFromAddr(address); symbol = symbol_db->GetSymbolFromAddr(address);
const std::string export_name = GetExportName(rso_export); const std::string export_name = GetExportName(guard, rso_export);
if (symbol) if (symbol)
{ {
// Function symbol // Function symbol
@ -388,7 +388,7 @@ void RSOView::Apply(PPCSymbolDB* symbol_db) const
else else
{ {
// Data symbol // Data symbol
symbol_db->AddKnownSymbol(address, 0, export_name, Common::Symbol::Type::Data); symbol_db->AddKnownSymbol(guard, address, 0, export_name, Common::Symbol::Type::Data);
} }
} }
} }
@ -440,9 +440,10 @@ const RSOImport& RSOView::GetImport(std::size_t index) const
return m_imports.GetImport(index); return m_imports.GetImport(index);
} }
std::string RSOView::GetImportName(const RSOImport& rso_import) const std::string RSOView::GetImportName(const Core::CPUThreadGuard& guard,
const RSOImport& rso_import) const
{ {
return PowerPC::HostGetString(m_header.GetImportsNameTable() + rso_import.name_offset); return PowerPC::HostGetString(guard, m_header.GetImportsNameTable() + rso_import.name_offset);
} }
const std::vector<RSOImport>& RSOView::GetImports() const const std::vector<RSOImport>& RSOView::GetImports() const
@ -460,9 +461,10 @@ const RSOExport& RSOView::GetExport(std::size_t index) const
return m_exports.GetExport(index); return m_exports.GetExport(index);
} }
std::string RSOView::GetExportName(const RSOExport& rso_export) const std::string RSOView::GetExportName(const Core::CPUThreadGuard& guard,
const RSOExport& rso_export) const
{ {
return PowerPC::HostGetString(m_header.GetExportsNameTable() + rso_export.name_offset); return PowerPC::HostGetString(guard, m_header.GetExportsNameTable() + rso_export.name_offset);
} }
u32 RSOView::GetExportAddress(const RSOExport& rso_export) const u32 RSOView::GetExportAddress(const RSOExport& rso_export) const
@ -515,14 +517,14 @@ const std::string& RSOView::GetName() const
return m_header.GetName(); return m_header.GetName();
} }
std::string RSOView::GetName(const RSOImport& rso_import) const std::string RSOView::GetName(const Core::CPUThreadGuard& guard, const RSOImport& rso_import) const
{ {
return GetImportName(rso_import); return GetImportName(guard, rso_import);
} }
std::string RSOView::GetName(const RSOExport& rso_export) const std::string RSOView::GetName(const Core::CPUThreadGuard& guard, const RSOExport& rso_export) const
{ {
return GetExportName(rso_export); return GetExportName(guard, rso_export);
} }
u32 RSOView::GetProlog() const u32 RSOView::GetProlog() const
@ -561,33 +563,33 @@ u32 RSOView::GetUnresolved() const
return 0; return 0;
} }
bool RSOChainView::Load(u32 address) bool RSOChainView::Load(const Core::CPUThreadGuard& guard, u32 address)
{ {
// Load node // Load node
RSOView node; RSOView node;
node.LoadHeader(address); node.LoadHeader(guard, address);
DEBUG_LOG_FMT(SYMBOLS, "RSOChain node name: {}", node.GetName()); DEBUG_LOG_FMT(SYMBOLS, "RSOChain node name: {}", node.GetName());
m_chain.emplace_front(std::move(node)); m_chain.emplace_front(std::move(node));
if (LoadNextChain(m_chain.front()) && LoadPrevChain(m_chain.front())) if (LoadNextChain(guard, m_chain.front()) && LoadPrevChain(guard, m_chain.front()))
{ {
for (RSOView& view : m_chain) for (RSOView& view : m_chain)
{ {
view.LoadSections(); view.LoadSections(guard);
view.LoadExports(); view.LoadExports(guard);
view.LoadImports(); view.LoadImports(guard);
view.LoadExternals(); view.LoadExternals(guard);
view.LoadInternals(); view.LoadInternals(guard);
} }
return true; return true;
} }
return false; return false;
} }
void RSOChainView::Apply(PPCSymbolDB* symbol_db) const void RSOChainView::Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* symbol_db) const
{ {
for (const RSOView& rso_view : m_chain) for (const RSOView& rso_view : m_chain)
rso_view.Apply(symbol_db); rso_view.Apply(guard, symbol_db);
} }
void RSOChainView::Clear() void RSOChainView::Clear()
@ -600,7 +602,7 @@ const std::list<RSOView>& RSOChainView::GetChain() const
return m_chain; return m_chain;
} }
bool RSOChainView::LoadNextChain(const RSOView& view) bool RSOChainView::LoadNextChain(const Core::CPUThreadGuard& guard, const RSOView& view)
{ {
u32 prev_address = view.GetAddress(); u32 prev_address = view.GetAddress();
u32 next_address = view.GetNextEntry(); u32 next_address = view.GetNextEntry();
@ -608,7 +610,7 @@ bool RSOChainView::LoadNextChain(const RSOView& view)
while (next_address != 0) while (next_address != 0)
{ {
RSOView next_node; RSOView next_node;
next_node.LoadHeader(next_address); next_node.LoadHeader(guard, next_address);
if (prev_address != next_node.GetPrevEntry()) if (prev_address != next_node.GetPrevEntry())
{ {
@ -625,7 +627,7 @@ bool RSOChainView::LoadNextChain(const RSOView& view)
return true; return true;
} }
bool RSOChainView::LoadPrevChain(const RSOView& view) bool RSOChainView::LoadPrevChain(const Core::CPUThreadGuard& guard, const RSOView& view)
{ {
u32 prev_address = view.GetPrevEntry(); u32 prev_address = view.GetPrevEntry();
u32 next_address = view.GetAddress(); u32 next_address = view.GetAddress();
@ -633,7 +635,7 @@ bool RSOChainView::LoadPrevChain(const RSOView& view)
while (prev_address != 0) while (prev_address != 0)
{ {
RSOView prev_node; RSOView prev_node;
prev_node.LoadHeader(prev_address); prev_node.LoadHeader(guard, prev_address);
if (next_address != prev_node.GetNextEntry()) if (next_address != prev_node.GetNextEntry())
{ {

View File

@ -13,6 +13,11 @@
class PPCSymbolDB; class PPCSymbolDB;
namespace Core
{
class CPUThreadGuard;
};
struct RSOEntry struct RSOEntry
{ {
u32 next_entry; u32 next_entry;
@ -103,7 +108,7 @@ using RSOExternalsEntry = RSORelocationTableEntry<RSORelocationTableType::Extern
class RSOHeaderView class RSOHeaderView
{ {
public: public:
void Load(u32 address); void Load(const Core::CPUThreadGuard& guard, u32 address);
u32 GetNextEntry() const; u32 GetNextEntry() const;
u32 GetPrevEntry() const; u32 GetPrevEntry() const;
@ -139,7 +144,7 @@ private:
class RSOSectionsView class RSOSectionsView
{ {
public: public:
void Load(u32 address, std::size_t count = 1); void Load(const Core::CPUThreadGuard& guard, u32 address, std::size_t count = 1);
std::size_t Count() const; std::size_t Count() const;
const RSOSection& GetSection(std::size_t index) const; const RSOSection& GetSection(std::size_t index) const;
@ -153,7 +158,7 @@ private:
class RSOImportsView class RSOImportsView
{ {
public: public:
void Load(u32 address, std::size_t count = 1); void Load(const Core::CPUThreadGuard& guard, u32 address, std::size_t count = 1);
std::size_t Count() const; std::size_t Count() const;
const RSOImport& GetImport(std::size_t index) const; const RSOImport& GetImport(std::size_t index) const;
@ -167,7 +172,7 @@ private:
class RSOExportsView class RSOExportsView
{ {
public: public:
void Load(u32 address, std::size_t count = 1); void Load(const Core::CPUThreadGuard& guard, u32 address, std::size_t count = 1);
std::size_t Count() const; std::size_t Count() const;
const RSOExport& GetExport(std::size_t index) const; const RSOExport& GetExport(std::size_t index) const;
@ -181,7 +186,7 @@ private:
class RSOInternalsView class RSOInternalsView
{ {
public: public:
void Load(u32 address, std::size_t count = 1); void Load(const Core::CPUThreadGuard& guard, u32 address, std::size_t count = 1);
std::size_t Count() const; std::size_t Count() const;
const RSOInternalsEntry& GetEntry(std::size_t index) const; const RSOInternalsEntry& GetEntry(std::size_t index) const;
@ -195,7 +200,7 @@ private:
class RSOExternalsView class RSOExternalsView
{ {
public: public:
void Load(u32 address, std::size_t count = 1); void Load(const Core::CPUThreadGuard& guard, u32 address, std::size_t count = 1);
std::size_t Count() const; std::size_t Count() const;
const RSOExternalsEntry& GetEntry(std::size_t index) const; const RSOExternalsEntry& GetEntry(std::size_t index) const;
@ -209,15 +214,15 @@ private:
class RSOView class RSOView
{ {
public: public:
void LoadHeader(u32 address); void LoadHeader(const Core::CPUThreadGuard& guard, u32 address);
void LoadSections(); void LoadSections(const Core::CPUThreadGuard& guard);
void LoadImports(); void LoadImports(const Core::CPUThreadGuard& guard);
void LoadExports(); void LoadExports(const Core::CPUThreadGuard& guard);
void LoadInternals(); void LoadInternals(const Core::CPUThreadGuard& guard);
void LoadExternals(); void LoadExternals(const Core::CPUThreadGuard& guard);
void LoadAll(u32 address); void LoadAll(const Core::CPUThreadGuard& guard, u32 address);
void Apply(PPCSymbolDB* symbol_db) const; void Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* symbol_db) const;
u32 GetNextEntry() const; u32 GetNextEntry() const;
u32 GetPrevEntry() const; u32 GetPrevEntry() const;
@ -230,12 +235,12 @@ public:
std::size_t GetImportsCount() const; std::size_t GetImportsCount() const;
const RSOImport& GetImport(std::size_t index) const; const RSOImport& GetImport(std::size_t index) const;
std::string GetImportName(const RSOImport& rso_import) const; std::string GetImportName(const Core::CPUThreadGuard& guard, const RSOImport& rso_import) const;
const std::vector<RSOImport>& GetImports() const; const std::vector<RSOImport>& GetImports() const;
std::size_t GetExportsCount() const; std::size_t GetExportsCount() const;
const RSOExport& GetExport(std::size_t index) const; const RSOExport& GetExport(std::size_t index) const;
std::string GetExportName(const RSOExport& rso_export) const; std::string GetExportName(const Core::CPUThreadGuard& guard, const RSOExport& rso_export) const;
u32 GetExportAddress(const RSOExport& rso_export) const; u32 GetExportAddress(const RSOExport& rso_export) const;
const std::vector<RSOExport>& GetExports() const; const std::vector<RSOExport>& GetExports() const;
@ -248,8 +253,8 @@ public:
const std::vector<RSOExternalsEntry>& GetExternals() const; const std::vector<RSOExternalsEntry>& GetExternals() const;
const std::string& GetName() const; const std::string& GetName() const;
std::string GetName(const RSOImport& rso_import) const; std::string GetName(const Core::CPUThreadGuard& guard, const RSOImport& rso_import) const;
std::string GetName(const RSOExport& rso_export) const; std::string GetName(const Core::CPUThreadGuard& guard, const RSOExport& rso_export) const;
u32 GetProlog() const; u32 GetProlog() const;
u32 GetEpilog() const; u32 GetEpilog() const;
@ -268,14 +273,14 @@ private:
class RSOChainView class RSOChainView
{ {
public: public:
bool Load(u32 address); bool Load(const Core::CPUThreadGuard& guard, u32 address);
void Apply(PPCSymbolDB* symbol_db) const; void Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* symbol_db) const;
void Clear(); void Clear();
const std::list<RSOView>& GetChain() const; const std::list<RSOView>& GetChain() const;
private: private:
bool LoadNextChain(const RSOView& view); bool LoadNextChain(const Core::CPUThreadGuard& guard, const RSOView& view);
bool LoadPrevChain(const RSOView& view); bool LoadPrevChain(const Core::CPUThreadGuard& guard, const RSOView& view);
std::list<RSOView> m_chain; std::list<RSOView> m_chain;
}; };

View File

@ -118,7 +118,7 @@ std::vector<GeckoCode> SetAndReturnActiveCodes(std::span<const GeckoCode> gcodes
// Requires s_active_codes_lock // Requires s_active_codes_lock
// NOTE: Refer to "codehandleronly.s" from Gecko OS. // NOTE: Refer to "codehandleronly.s" from Gecko OS.
static Installation InstallCodeHandlerLocked() static Installation InstallCodeHandlerLocked(const Core::CPUThreadGuard& guard)
{ {
std::string data; std::string data;
if (!File::ReadFileToString(File::GetSysDirectory() + GECKO_CODE_HANDLER, data)) if (!File::ReadFileToString(File::GetSysDirectory() + GECKO_CODE_HANDLER, data))
@ -142,16 +142,17 @@ static Installation InstallCodeHandlerLocked()
// Install code handler // Install code handler
for (u32 i = 0; i < data.size(); ++i) for (u32 i = 0; i < data.size(); ++i)
PowerPC::HostWrite_U8(data[i], INSTALLER_BASE_ADDRESS + i); PowerPC::HostWrite_U8(guard, data[i], INSTALLER_BASE_ADDRESS + i);
// Patch the code handler to the current system type (Gamecube/Wii) // Patch the code handler to the current system type (Gamecube/Wii)
for (unsigned int h = 0; h < data.length(); h += 4) for (unsigned int h = 0; h < data.length(); h += 4)
{ {
// Patch MMIO address // Patch MMIO address
if (PowerPC::HostRead_U32(INSTALLER_BASE_ADDRESS + h) == (0x3f000000u | ((mmio_addr ^ 1) << 8))) if (PowerPC::HostRead_U32(guard, INSTALLER_BASE_ADDRESS + h) ==
(0x3f000000u | ((mmio_addr ^ 1) << 8)))
{ {
NOTICE_LOG_FMT(ACTIONREPLAY, "Patching MMIO access at {:08x}", INSTALLER_BASE_ADDRESS + h); NOTICE_LOG_FMT(ACTIONREPLAY, "Patching MMIO access at {:08x}", INSTALLER_BASE_ADDRESS + h);
PowerPC::HostWrite_U32(0x3f000000u | mmio_addr << 8, INSTALLER_BASE_ADDRESS + h); PowerPC::HostWrite_U32(guard, 0x3f000000u | mmio_addr << 8, INSTALLER_BASE_ADDRESS + h);
} }
} }
@ -161,11 +162,11 @@ static Installation InstallCodeHandlerLocked()
// Write a magic value to 'gameid' (codehandleronly does not actually read this). // Write a magic value to 'gameid' (codehandleronly does not actually read this).
// This value will be read back and modified over time by HLE_Misc::GeckoCodeHandlerICacheFlush. // This value will be read back and modified over time by HLE_Misc::GeckoCodeHandlerICacheFlush.
PowerPC::HostWrite_U32(MAGIC_GAMEID, INSTALLER_BASE_ADDRESS); PowerPC::HostWrite_U32(guard, MAGIC_GAMEID, INSTALLER_BASE_ADDRESS);
// Create GCT in memory // Create GCT in memory
PowerPC::HostWrite_U32(0x00d0c0de, codelist_base_address); PowerPC::HostWrite_U32(guard, 0x00d0c0de, codelist_base_address);
PowerPC::HostWrite_U32(0x00d0c0de, codelist_base_address + 4); PowerPC::HostWrite_U32(guard, 0x00d0c0de, codelist_base_address + 4);
// Each code is 8 bytes (2 words) wide. There is a starter code and an end code. // Each code is 8 bytes (2 words) wide. There is a starter code and an end code.
const u32 start_address = codelist_base_address + CODE_SIZE; const u32 start_address = codelist_base_address + CODE_SIZE;
@ -188,8 +189,8 @@ static Installation InstallCodeHandlerLocked()
for (const GeckoCode::Code& code : active_code.codes) for (const GeckoCode::Code& code : active_code.codes)
{ {
PowerPC::HostWrite_U32(code.address, next_address); PowerPC::HostWrite_U32(guard, code.address, next_address);
PowerPC::HostWrite_U32(code.data, next_address + 4); PowerPC::HostWrite_U32(guard, code.data, next_address + 4);
next_address += CODE_SIZE; next_address += CODE_SIZE;
} }
} }
@ -198,12 +199,12 @@ static Installation InstallCodeHandlerLocked()
end_address - start_address); end_address - start_address);
// Stop code. Tells the handler that this is the end of the list. // Stop code. Tells the handler that this is the end of the list.
PowerPC::HostWrite_U32(0xF0000000, next_address); PowerPC::HostWrite_U32(guard, 0xF0000000, next_address);
PowerPC::HostWrite_U32(0x00000000, next_address + 4); PowerPC::HostWrite_U32(guard, 0x00000000, next_address + 4);
PowerPC::HostWrite_U32(0, HLE_TRAMPOLINE_ADDRESS); PowerPC::HostWrite_U32(guard, 0, HLE_TRAMPOLINE_ADDRESS);
// Turn on codes // Turn on codes
PowerPC::HostWrite_U8(1, INSTALLER_BASE_ADDRESS + 7); PowerPC::HostWrite_U8(guard, 1, INSTALLER_BASE_ADDRESS + 7);
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState(); auto& ppc_state = system.GetPPCState();
@ -235,7 +236,7 @@ void Shutdown()
s_code_handler_installed = Installation::Uninstalled; s_code_handler_installed = Installation::Uninstalled;
} }
void RunCodeHandler() void RunCodeHandler(const Core::CPUThreadGuard& guard)
{ {
if (!Config::Get(Config::MAIN_ENABLE_CHEATS)) if (!Config::Get(Config::MAIN_ENABLE_CHEATS))
return; return;
@ -249,7 +250,7 @@ void RunCodeHandler()
// fixed within 1 frame of the last error. // fixed within 1 frame of the last error.
if (s_active_codes.empty() || s_code_handler_installed == Installation::Failed) if (s_active_codes.empty() || s_code_handler_installed == Installation::Failed)
return; return;
s_code_handler_installed = InstallCodeHandlerLocked(); s_code_handler_installed = InstallCodeHandlerLocked(guard);
// A warning was already issued for the install failing // A warning was already issued for the install failing
if (s_code_handler_installed != Installation::Installed) if (s_code_handler_installed != Installation::Installed)
@ -273,17 +274,17 @@ void RunCodeHandler()
ppc_state.gpr[1] -= 8; // Fake stack frame for codehandler ppc_state.gpr[1] -= 8; // Fake stack frame for codehandler
ppc_state.gpr[1] &= 0xFFFFFFF0; // Align stack to 16bytes ppc_state.gpr[1] &= 0xFFFFFFF0; // Align stack to 16bytes
u32 SP = ppc_state.gpr[1]; // Stack Pointer u32 SP = ppc_state.gpr[1]; // Stack Pointer
PowerPC::HostWrite_U32(SP + 8, SP); PowerPC::HostWrite_U32(guard, SP + 8, SP);
// SP + 4 is reserved for the codehandler to save LR to the stack. // SP + 4 is reserved for the codehandler to save LR to the stack.
PowerPC::HostWrite_U32(SFP, SP + 8); // Real stack frame PowerPC::HostWrite_U32(guard, SFP, SP + 8); // Real stack frame
PowerPC::HostWrite_U32(ppc_state.pc, SP + 12); PowerPC::HostWrite_U32(guard, ppc_state.pc, SP + 12);
PowerPC::HostWrite_U32(LR(ppc_state), SP + 16); PowerPC::HostWrite_U32(guard, LR(ppc_state), SP + 16);
PowerPC::HostWrite_U32(ppc_state.cr.Get(), SP + 20); PowerPC::HostWrite_U32(guard, ppc_state.cr.Get(), SP + 20);
// Registers FPR0->13 are volatile // Registers FPR0->13 are volatile
for (int i = 0; i < 14; ++i) for (int i = 0; i < 14; ++i)
{ {
PowerPC::HostWrite_U64(ppc_state.ps[i].PS0AsU64(), SP + 24 + 2 * i * sizeof(u64)); PowerPC::HostWrite_U64(guard, ppc_state.ps[i].PS0AsU64(), SP + 24 + 2 * i * sizeof(u64));
PowerPC::HostWrite_U64(ppc_state.ps[i].PS1AsU64(), SP + 24 + (2 * i + 1) * sizeof(u64)); PowerPC::HostWrite_U64(guard, ppc_state.ps[i].PS1AsU64(), SP + 24 + (2 * i + 1) * sizeof(u64));
} }
DEBUG_LOG_FMT(ACTIONREPLAY, DEBUG_LOG_FMT(ACTIONREPLAY,
"GeckoCodes: Initiating phantom branch-and-link. " "GeckoCodes: Initiating phantom branch-and-link. "

View File

@ -11,6 +11,11 @@
class PointerWrap; class PointerWrap;
namespace Core
{
class CPUThreadGuard;
};
namespace Gecko namespace Gecko
{ {
class GeckoCode class GeckoCode
@ -63,7 +68,7 @@ void SetActiveCodes(std::span<const GeckoCode> gcodes);
void SetSyncedCodesAsActive(); void SetSyncedCodesAsActive();
void UpdateSyncedCodes(std::span<const GeckoCode> gcodes); void UpdateSyncedCodes(std::span<const GeckoCode> gcodes);
std::vector<GeckoCode> SetAndReturnActiveCodes(std::span<const GeckoCode> gcodes); std::vector<GeckoCode> SetAndReturnActiveCodes(std::span<const GeckoCode> gcodes);
void RunCodeHandler(); void RunCodeHandler(const Core::CPUThreadGuard& guard);
void Shutdown(); void Shutdown();
void DoState(PointerWrap&); void DoState(PointerWrap&);

View File

@ -152,12 +152,12 @@ void Reload(Core::System& system)
PatchFunctions(system); PatchFunctions(system);
} }
void Execute(u32 current_pc, u32 hook_index) void Execute(const Core::CPUThreadGuard& guard, u32 current_pc, u32 hook_index)
{ {
hook_index &= 0xFFFFF; hook_index &= 0xFFFFF;
if (hook_index > 0 && hook_index < os_patches.size()) if (hook_index > 0 && hook_index < os_patches.size())
{ {
os_patches[hook_index].function(); os_patches[hook_index].function(guard);
} }
else else
{ {

View File

@ -9,12 +9,13 @@
namespace Core namespace Core
{ {
class CPUThreadGuard;
class System; class System;
} } // namespace Core
namespace HLE namespace HLE
{ {
using HookFunction = void (*)(); using HookFunction = void (*)(const Core::CPUThreadGuard&);
enum class HookType enum class HookType
{ {
@ -46,7 +47,7 @@ void Reload(Core::System& system);
void Patch(Core::System& system, u32 pc, std::string_view func_name); void Patch(Core::System& system, u32 pc, std::string_view func_name);
u32 UnPatch(Core::System& system, std::string_view patch_name); u32 UnPatch(Core::System& system, std::string_view patch_name);
u32 UnpatchRange(Core::System& system, u32 start_addr, u32 end_addr); u32 UnpatchRange(Core::System& system, u32 start_addr, u32 end_addr);
void Execute(u32 current_pc, u32 hook_index); void Execute(const Core::CPUThreadGuard& guard, u32 current_pc, u32 hook_index);
// Returns the HLE hook index of the address // Returns the HLE hook index of the address
u32 GetHookByAddress(u32 address); u32 GetHookByAddress(u32 address);

View File

@ -16,21 +16,21 @@ namespace HLE_Misc
{ {
// If you just want to kill a function, one of the three following are usually appropriate. // If you just want to kill a function, one of the three following are usually appropriate.
// According to the PPC ABI, the return value is always in r3. // According to the PPC ABI, the return value is always in r3.
void UnimplementedFunction() void UnimplementedFunction(const Core::CPUThreadGuard&)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState(); auto& ppc_state = system.GetPPCState();
ppc_state.npc = LR(ppc_state); ppc_state.npc = LR(ppc_state);
} }
void HBReload() void HBReload(const Core::CPUThreadGuard&)
{ {
// There isn't much we can do. Just stop cleanly. // There isn't much we can do. Just stop cleanly.
CPU::Break(); CPU::Break();
Host_Message(HostMessageID::WMUserStop); Host_Message(HostMessageID::WMUserStop);
} }
void GeckoCodeHandlerICacheFlush() void GeckoCodeHandlerICacheFlush(const Core::CPUThreadGuard& guard)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState(); auto& ppc_state = system.GetPPCState();
@ -41,7 +41,7 @@ void GeckoCodeHandlerICacheFlush()
// been read into memory, or such, so we do the first 5 frames. More // been read into memory, or such, so we do the first 5 frames. More
// robust alternative would be to actually detect memory writes, but that // robust alternative would be to actually detect memory writes, but that
// would be even uglier.) // would be even uglier.)
u32 gch_gameid = PowerPC::HostRead_U32(Gecko::INSTALLER_BASE_ADDRESS); u32 gch_gameid = PowerPC::HostRead_U32(guard, Gecko::INSTALLER_BASE_ADDRESS);
if (gch_gameid - Gecko::MAGIC_GAMEID == 5) if (gch_gameid - Gecko::MAGIC_GAMEID == 5)
{ {
return; return;
@ -50,7 +50,7 @@ void GeckoCodeHandlerICacheFlush()
{ {
gch_gameid = Gecko::MAGIC_GAMEID; gch_gameid = Gecko::MAGIC_GAMEID;
} }
PowerPC::HostWrite_U32(gch_gameid + 1, Gecko::INSTALLER_BASE_ADDRESS); PowerPC::HostWrite_U32(guard, gch_gameid + 1, Gecko::INSTALLER_BASE_ADDRESS);
ppc_state.iCache.Reset(); ppc_state.iCache.Reset();
} }
@ -59,21 +59,21 @@ void GeckoCodeHandlerICacheFlush()
// need a way to branch into the GCH from an arbitrary PC address. Branching is easy, returning // need a way to branch into the GCH from an arbitrary PC address. Branching is easy, returning
// back is the hard part. This HLE function acts as a trampoline that restores the original LR, SP, // back is the hard part. This HLE function acts as a trampoline that restores the original LR, SP,
// and PC before the magic, invisible BL instruction happened. // and PC before the magic, invisible BL instruction happened.
void GeckoReturnTrampoline() void GeckoReturnTrampoline(const Core::CPUThreadGuard& guard)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState(); auto& ppc_state = system.GetPPCState();
// Stack frame is built in GeckoCode.cpp, Gecko::RunCodeHandler. // Stack frame is built in GeckoCode.cpp, Gecko::RunCodeHandler.
u32 SP = ppc_state.gpr[1]; u32 SP = ppc_state.gpr[1];
ppc_state.gpr[1] = PowerPC::HostRead_U32(SP + 8); ppc_state.gpr[1] = PowerPC::HostRead_U32(guard, SP + 8);
ppc_state.npc = PowerPC::HostRead_U32(SP + 12); ppc_state.npc = PowerPC::HostRead_U32(guard, SP + 12);
LR(ppc_state) = PowerPC::HostRead_U32(SP + 16); LR(ppc_state) = PowerPC::HostRead_U32(guard, SP + 16);
ppc_state.cr.Set(PowerPC::HostRead_U32(SP + 20)); ppc_state.cr.Set(PowerPC::HostRead_U32(guard, SP + 20));
for (int i = 0; i < 14; ++i) for (int i = 0; i < 14; ++i)
{ {
ppc_state.ps[i].SetBoth(PowerPC::HostRead_U64(SP + 24 + 2 * i * sizeof(u64)), ppc_state.ps[i].SetBoth(PowerPC::HostRead_U64(guard, SP + 24 + 2 * i * sizeof(u64)),
PowerPC::HostRead_U64(SP + 24 + (2 * i + 1) * sizeof(u64))); PowerPC::HostRead_U64(guard, SP + 24 + (2 * i + 1) * sizeof(u64)));
} }
} }
} // namespace HLE_Misc } // namespace HLE_Misc

View File

@ -3,10 +3,15 @@
#pragma once #pragma once
namespace Core
{
class CPUThreadGuard;
};
namespace HLE_Misc namespace HLE_Misc
{ {
void UnimplementedFunction(); void UnimplementedFunction(const Core::CPUThreadGuard& guard);
void HBReload(); void HBReload(const Core::CPUThreadGuard& guard);
void GeckoCodeHandlerICacheFlush(); void GeckoCodeHandlerICacheFlush(const Core::CPUThreadGuard& guard);
void GeckoReturnTrampoline(); void GeckoReturnTrampoline(const Core::CPUThreadGuard& guard);
} // namespace HLE_Misc } // namespace HLE_Misc

View File

@ -23,19 +23,19 @@ enum class ParameterType : bool
VariableArgumentList = true VariableArgumentList = true
}; };
std::string GetStringVA(Core::System& system, u32 str_reg = 3, std::string GetStringVA(Core::System& system, const Core::CPUThreadGuard& guard, u32 str_reg = 3,
ParameterType parameter_type = ParameterType::ParameterList); ParameterType parameter_type = ParameterType::ParameterList);
void HLE_GeneralDebugPrint(ParameterType parameter_type); void HLE_GeneralDebugPrint(const Core::CPUThreadGuard& guard, ParameterType parameter_type);
void HLE_LogDPrint(ParameterType parameter_type); void HLE_LogDPrint(const Core::CPUThreadGuard& guard, ParameterType parameter_type);
void HLE_LogFPrint(ParameterType parameter_type); void HLE_LogFPrint(const Core::CPUThreadGuard& guard, ParameterType parameter_type);
void HLE_OSPanic() void HLE_OSPanic(const Core::CPUThreadGuard& guard)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState(); auto& ppc_state = system.GetPPCState();
std::string error = GetStringVA(system); std::string error = GetStringVA(system, guard);
std::string msg = GetStringVA(system, 5); std::string msg = GetStringVA(system, guard, 5);
StringPopBackIf(&error, '\n'); StringPopBackIf(&error, '\n');
StringPopBackIf(&msg, '\n'); StringPopBackIf(&msg, '\n');
@ -48,7 +48,7 @@ void HLE_OSPanic()
} }
// Generalized function for printing formatted string. // Generalized function for printing formatted string.
void HLE_GeneralDebugPrint(ParameterType parameter_type) void HLE_GeneralDebugPrint(const Core::CPUThreadGuard& guard, ParameterType parameter_type)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState(); auto& ppc_state = system.GetPPCState();
@ -56,32 +56,32 @@ void HLE_GeneralDebugPrint(ParameterType parameter_type)
std::string report_message; std::string report_message;
// Is gpr3 pointing to a pointer (including nullptr) rather than an ASCII string // Is gpr3 pointing to a pointer (including nullptr) rather than an ASCII string
if (PowerPC::HostIsRAMAddress(ppc_state.gpr[3]) && if (PowerPC::HostIsRAMAddress(guard, ppc_state.gpr[3]) &&
(PowerPC::HostIsRAMAddress(PowerPC::HostRead_U32(ppc_state.gpr[3])) || (PowerPC::HostIsRAMAddress(guard, PowerPC::HostRead_U32(guard, ppc_state.gpr[3])) ||
PowerPC::HostRead_U32(ppc_state.gpr[3]) == 0)) PowerPC::HostRead_U32(guard, ppc_state.gpr[3]) == 0))
{ {
if (PowerPC::HostIsRAMAddress(ppc_state.gpr[4])) if (PowerPC::HostIsRAMAddress(guard, ppc_state.gpr[4]))
{ {
// ___blank(void* this, const char* fmt, ...); // ___blank(void* this, const char* fmt, ...);
report_message = GetStringVA(system, 4, parameter_type); report_message = GetStringVA(system, guard, 4, parameter_type);
} }
else else
{ {
// ___blank(void* this, int log_type, const char* fmt, ...); // ___blank(void* this, int log_type, const char* fmt, ...);
report_message = GetStringVA(system, 5, parameter_type); report_message = GetStringVA(system, guard, 5, parameter_type);
} }
} }
else else
{ {
if (PowerPC::HostIsRAMAddress(ppc_state.gpr[3])) if (PowerPC::HostIsRAMAddress(guard, ppc_state.gpr[3]))
{ {
// ___blank(const char* fmt, ...); // ___blank(const char* fmt, ...);
report_message = GetStringVA(system, 3, parameter_type); report_message = GetStringVA(system, guard, 3, parameter_type);
} }
else else
{ {
// ___blank(int log_type, const char* fmt, ...); // ___blank(int log_type, const char* fmt, ...);
report_message = GetStringVA(system, 4, parameter_type); report_message = GetStringVA(system, guard, 4, parameter_type);
} }
} }
@ -92,25 +92,25 @@ void HLE_GeneralDebugPrint(ParameterType parameter_type)
} }
// Generalized function for printing formatted string using parameter list. // Generalized function for printing formatted string using parameter list.
void HLE_GeneralDebugPrint() void HLE_GeneralDebugPrint(const Core::CPUThreadGuard& guard)
{ {
HLE_GeneralDebugPrint(ParameterType::ParameterList); HLE_GeneralDebugPrint(guard, ParameterType::ParameterList);
} }
// Generalized function for printing formatted string using va_list. // Generalized function for printing formatted string using va_list.
void HLE_GeneralDebugVPrint() void HLE_GeneralDebugVPrint(const Core::CPUThreadGuard& guard)
{ {
HLE_GeneralDebugPrint(ParameterType::VariableArgumentList); HLE_GeneralDebugPrint(guard, ParameterType::VariableArgumentList);
} }
// __write_console(int fd, const void* buffer, const u32* size) // __write_console(int fd, const void* buffer, const u32* size)
void HLE_write_console() void HLE_write_console(const Core::CPUThreadGuard& guard)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState(); auto& ppc_state = system.GetPPCState();
std::string report_message = GetStringVA(system, 4); std::string report_message = GetStringVA(system, guard, 4);
if (PowerPC::HostIsRAMAddress(ppc_state.gpr[5])) if (PowerPC::HostIsRAMAddress(guard, ppc_state.gpr[5]))
{ {
const u32 size = PowerPC::Read_U32(ppc_state.gpr[5]); const u32 size = PowerPC::Read_U32(ppc_state.gpr[5]);
if (size > report_message.size()) if (size > report_message.size())
@ -132,7 +132,7 @@ void HLE_write_console()
} }
// Log (v)dprintf message if fd is 1 (stdout) or 2 (stderr) // Log (v)dprintf message if fd is 1 (stdout) or 2 (stderr)
void HLE_LogDPrint(ParameterType parameter_type) void HLE_LogDPrint(const Core::CPUThreadGuard& guard, ParameterType parameter_type)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState(); auto& ppc_state = system.GetPPCState();
@ -140,7 +140,7 @@ void HLE_LogDPrint(ParameterType parameter_type)
if (ppc_state.gpr[3] != 1 && ppc_state.gpr[3] != 2) if (ppc_state.gpr[3] != 1 && ppc_state.gpr[3] != 2)
return; return;
std::string report_message = GetStringVA(system, 4, parameter_type); std::string report_message = GetStringVA(system, guard, 4, parameter_type);
StringPopBackIf(&report_message, '\n'); StringPopBackIf(&report_message, '\n');
NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR(ppc_state), ppc_state.pc, NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR(ppc_state), ppc_state.pc,
SHIFTJISToUTF8(report_message)); SHIFTJISToUTF8(report_message));
@ -148,20 +148,20 @@ void HLE_LogDPrint(ParameterType parameter_type)
// Log dprintf message // Log dprintf message
// -> int dprintf(int fd, const char* format, ...); // -> int dprintf(int fd, const char* format, ...);
void HLE_LogDPrint() void HLE_LogDPrint(const Core::CPUThreadGuard& guard)
{ {
HLE_LogDPrint(ParameterType::ParameterList); HLE_LogDPrint(guard, ParameterType::ParameterList);
} }
// Log vdprintf message // Log vdprintf message
// -> int vdprintf(int fd, const char* format, va_list ap); // -> int vdprintf(int fd, const char* format, va_list ap);
void HLE_LogVDPrint() void HLE_LogVDPrint(const Core::CPUThreadGuard& guard)
{ {
HLE_LogDPrint(ParameterType::VariableArgumentList); HLE_LogDPrint(guard, ParameterType::VariableArgumentList);
} }
// Log (v)fprintf message if FILE is stdout or stderr // Log (v)fprintf message if FILE is stdout or stderr
void HLE_LogFPrint(ParameterType parameter_type) void HLE_LogFPrint(const Core::CPUThreadGuard& guard, ParameterType parameter_type)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState(); auto& ppc_state = system.GetPPCState();
@ -169,21 +169,21 @@ void HLE_LogFPrint(ParameterType parameter_type)
// The structure FILE is implementation defined. // The structure FILE is implementation defined.
// Both libogc and Dolphin SDK seem to store the fd at the same address. // Both libogc and Dolphin SDK seem to store the fd at the same address.
int fd = -1; int fd = -1;
if (PowerPC::HostIsRAMAddress(ppc_state.gpr[3]) && if (PowerPC::HostIsRAMAddress(guard, ppc_state.gpr[3]) &&
PowerPC::HostIsRAMAddress(ppc_state.gpr[3] + 0xF)) PowerPC::HostIsRAMAddress(guard, ppc_state.gpr[3] + 0xF))
{ {
// The fd is stored as a short at FILE+0xE. // The fd is stored as a short at FILE+0xE.
fd = static_cast<short>(PowerPC::HostRead_U16(ppc_state.gpr[3] + 0xE)); fd = static_cast<short>(PowerPC::HostRead_U16(guard, ppc_state.gpr[3] + 0xE));
} }
if (fd != 1 && fd != 2) if (fd != 1 && fd != 2)
{ {
// On RVL SDK it seems stored at FILE+0x2. // On RVL SDK it seems stored at FILE+0x2.
fd = static_cast<short>(PowerPC::HostRead_U16(ppc_state.gpr[3] + 0x2)); fd = static_cast<short>(PowerPC::HostRead_U16(guard, ppc_state.gpr[3] + 0x2));
} }
if (fd != 1 && fd != 2) if (fd != 1 && fd != 2)
return; return;
std::string report_message = GetStringVA(system, 4, parameter_type); std::string report_message = GetStringVA(system, guard, 4, parameter_type);
StringPopBackIf(&report_message, '\n'); StringPopBackIf(&report_message, '\n');
NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR(ppc_state), ppc_state.pc, NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR(ppc_state), ppc_state.pc,
SHIFTJISToUTF8(report_message)); SHIFTJISToUTF8(report_message));
@ -191,28 +191,30 @@ void HLE_LogFPrint(ParameterType parameter_type)
// Log fprintf message // Log fprintf message
// -> int fprintf(FILE* stream, const char* format, ...); // -> int fprintf(FILE* stream, const char* format, ...);
void HLE_LogFPrint() void HLE_LogFPrint(const Core::CPUThreadGuard& guard)
{ {
HLE_LogFPrint(ParameterType::ParameterList); HLE_LogFPrint(guard, ParameterType::ParameterList);
} }
// Log vfprintf message // Log vfprintf message
// -> int vfprintf(FILE* stream, const char* format, va_list ap); // -> int vfprintf(FILE* stream, const char* format, va_list ap);
void HLE_LogVFPrint() void HLE_LogVFPrint(const Core::CPUThreadGuard& guard)
{ {
HLE_LogFPrint(ParameterType::VariableArgumentList); HLE_LogFPrint(guard, ParameterType::VariableArgumentList);
} }
std::string GetStringVA(Core::System& system, u32 str_reg, ParameterType parameter_type) std::string GetStringVA(Core::System& system, const Core::CPUThreadGuard& guard, u32 str_reg,
ParameterType parameter_type)
{ {
auto& ppc_state = system.GetPPCState(); auto& ppc_state = system.GetPPCState();
std::string ArgumentBuffer; std::string ArgumentBuffer;
std::string result; std::string result;
std::string string = PowerPC::HostGetString(ppc_state.gpr[str_reg]); std::string string = PowerPC::HostGetString(guard, ppc_state.gpr[str_reg]);
auto ap = auto ap =
parameter_type == ParameterType::VariableArgumentList ? parameter_type == ParameterType::VariableArgumentList ?
std::make_unique<HLE::SystemVABI::VAListStruct>(system, ppc_state.gpr[str_reg + 1]) : std::make_unique<HLE::SystemVABI::VAListStruct>(system, guard,
ppc_state.gpr[str_reg + 1]) :
std::make_unique<HLE::SystemVABI::VAList>(system, ppc_state.gpr[1] + 0x8, str_reg + 1); std::make_unique<HLE::SystemVABI::VAList>(system, ppc_state.gpr[1] + 0x8, str_reg + 1);
for (size_t i = 0; i < string.size(); i++) for (size_t i = 0; i < string.size(); i++)
@ -241,7 +243,7 @@ std::string GetStringVA(Core::System& system, u32 str_reg, ParameterType paramet
{ {
case 's': case 's':
result += StringFromFormat(ArgumentBuffer.c_str(), result += StringFromFormat(ArgumentBuffer.c_str(),
PowerPC::HostGetString(ap->GetArgT<u32>()).c_str()); PowerPC::HostGetString(guard, ap->GetArgT<u32>(guard)).c_str());
break; break;
case 'a': case 'a':
@ -252,12 +254,12 @@ std::string GetStringVA(Core::System& system, u32 str_reg, ParameterType paramet
case 'F': case 'F':
case 'g': case 'g':
case 'G': case 'G':
result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT<double>()); result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT<double>(guard));
break; break;
case 'p': case 'p':
// Override, so 64bit Dolphin prints 32bit pointers, since the ppc is 32bit :) // Override, so 64bit Dolphin prints 32bit pointers, since the ppc is 32bit :)
result += StringFromFormat("%x", ap->GetArgT<u32>()); result += StringFromFormat("%x", ap->GetArgT<u32>(guard));
break; break;
case 'n': case 'n':
@ -267,9 +269,9 @@ std::string GetStringVA(Core::System& system, u32 str_reg, ParameterType paramet
default: default:
if (string[i - 1] == 'l' && string[i - 2] == 'l') if (string[i - 1] == 'l' && string[i - 2] == 'l')
result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT<u64>()); result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT<u64>(guard));
else else
result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT<u32>()); result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT<u32>(guard));
break; break;
} }
} }

View File

@ -3,14 +3,19 @@
#pragma once #pragma once
namespace Core
{
class CPUThreadGuard;
};
namespace HLE_OS namespace HLE_OS
{ {
void HLE_GeneralDebugPrint(); void HLE_GeneralDebugPrint(const Core::CPUThreadGuard& guard);
void HLE_GeneralDebugVPrint(); void HLE_GeneralDebugVPrint(const Core::CPUThreadGuard& guard);
void HLE_write_console(); void HLE_write_console(const Core::CPUThreadGuard& guard);
void HLE_OSPanic(); void HLE_OSPanic(const Core::CPUThreadGuard& guard);
void HLE_LogDPrint(); void HLE_LogDPrint(const Core::CPUThreadGuard& guard);
void HLE_LogVDPrint(); void HLE_LogVDPrint(const Core::CPUThreadGuard& guard);
void HLE_LogFPrint(); void HLE_LogFPrint(const Core::CPUThreadGuard& guard);
void HLE_LogVFPrint(); void HLE_LogVFPrint(const Core::CPUThreadGuard& guard);
} // namespace HLE_OS } // namespace HLE_OS

View File

@ -8,20 +8,22 @@
HLE::SystemVABI::VAList::~VAList() = default; HLE::SystemVABI::VAList::~VAList() = default;
u32 HLE::SystemVABI::VAList::GetGPR(u32 gpr) const u32 HLE::SystemVABI::VAList::GetGPR(const Core::CPUThreadGuard&, u32 gpr) const
{ {
return m_system.GetPPCState().gpr[gpr]; return m_system.GetPPCState().gpr[gpr];
} }
double HLE::SystemVABI::VAList::GetFPR(u32 fpr) const double HLE::SystemVABI::VAList::GetFPR(const Core::CPUThreadGuard&, u32 fpr) const
{ {
return m_system.GetPPCState().ps[fpr].PS0AsDouble(); return m_system.GetPPCState().ps[fpr].PS0AsDouble();
} }
HLE::SystemVABI::VAListStruct::VAListStruct(Core::System& system, u32 address) HLE::SystemVABI::VAListStruct::VAListStruct(Core::System& system, const Core::CPUThreadGuard& guard,
: VAList(system, 0), m_va_list{PowerPC::HostRead_U8(address), PowerPC::HostRead_U8(address + 1), u32 address)
PowerPC::HostRead_U32(address + 4), : VAList(system, 0), m_va_list{PowerPC::HostRead_U8(guard, address),
PowerPC::HostRead_U32(address + 8)}, PowerPC::HostRead_U8(guard, address + 1),
PowerPC::HostRead_U32(guard, address + 4),
PowerPC::HostRead_U32(guard, address + 8)},
m_address(address), m_has_fpr_area(system.GetPPCState().cr.GetBit(6) == 1) m_address(address), m_has_fpr_area(system.GetPPCState().cr.GetBit(6) == 1)
{ {
m_stack = m_va_list.overflow_arg_area; m_stack = m_va_list.overflow_arg_area;
@ -39,7 +41,7 @@ u32 HLE::SystemVABI::VAListStruct::GetFPRArea() const
return GetGPRArea() + 4 * 8; return GetGPRArea() + 4 * 8;
} }
u32 HLE::SystemVABI::VAListStruct::GetGPR(u32 gpr) const u32 HLE::SystemVABI::VAListStruct::GetGPR(const Core::CPUThreadGuard& guard, u32 gpr) const
{ {
if (gpr < 3 || gpr > 10) if (gpr < 3 || gpr > 10)
{ {
@ -47,10 +49,10 @@ u32 HLE::SystemVABI::VAListStruct::GetGPR(u32 gpr) const
return 0; return 0;
} }
const u32 gpr_address = Common::AlignUp(GetGPRArea() + 4 * (gpr - 3), 4); const u32 gpr_address = Common::AlignUp(GetGPRArea() + 4 * (gpr - 3), 4);
return PowerPC::HostRead_U32(gpr_address); return PowerPC::HostRead_U32(guard, gpr_address);
} }
double HLE::SystemVABI::VAListStruct::GetFPR(u32 fpr) const double HLE::SystemVABI::VAListStruct::GetFPR(const Core::CPUThreadGuard& guard, u32 fpr) const
{ {
if (!m_has_fpr_area || fpr < 1 || fpr > 8) if (!m_has_fpr_area || fpr < 1 || fpr > 8)
{ {
@ -58,5 +60,5 @@ double HLE::SystemVABI::VAListStruct::GetFPR(u32 fpr) const
return 0.0; return 0.0;
} }
const u32 fpr_address = Common::AlignUp(GetFPRArea() + 8 * (fpr - 1), 8); const u32 fpr_address = Common::AlignUp(GetFPRArea() + 8 * (fpr - 1), 8);
return PowerPC::HostRead_F64(fpr_address); return PowerPC::HostRead_F64(guard, fpr_address);
} }

View File

@ -13,8 +13,9 @@
namespace Core namespace Core
{ {
class CPUThreadGuard;
class System; class System;
} } // namespace Core
namespace HLE::SystemVABI namespace HLE::SystemVABI
{ {
@ -47,14 +48,14 @@ public:
// 0 - arg_ARGPOINTER // 0 - arg_ARGPOINTER
template <typename T, typename std::enable_if_t<IS_ARG_POINTER<T>>* = nullptr> template <typename T, typename std::enable_if_t<IS_ARG_POINTER<T>>* = nullptr>
T GetArg() T GetArg(const Core::CPUThreadGuard& guard)
{ {
T obj; T obj;
u32 addr = GetArg<u32>(); u32 addr = GetArg<u32>(guard);
for (size_t i = 0; i < sizeof(T); i += 1, addr += 1) for (size_t i = 0; i < sizeof(T); i += 1, addr += 1)
{ {
reinterpret_cast<u8*>(&obj)[i] = PowerPC::HostRead_U8(addr); reinterpret_cast<u8*>(&obj)[i] = PowerPC::HostRead_U8(guard, addr);
} }
return obj; return obj;
@ -62,20 +63,20 @@ public:
// 1 - arg_WORD // 1 - arg_WORD
template <typename T, typename std::enable_if_t<IS_WORD<T>>* = nullptr> template <typename T, typename std::enable_if_t<IS_WORD<T>>* = nullptr>
T GetArg() T GetArg(const Core::CPUThreadGuard& guard)
{ {
static_assert(!std::is_pointer<T>(), "VAList doesn't support pointers"); static_assert(!std::is_pointer<T>(), "VAList doesn't support pointers");
u64 value; u64 value;
if (m_gpr <= m_gpr_max) if (m_gpr <= m_gpr_max)
{ {
value = GetGPR(m_gpr); value = GetGPR(guard, m_gpr);
m_gpr += 1; m_gpr += 1;
} }
else else
{ {
m_stack = Common::AlignUp(m_stack, 4); m_stack = Common::AlignUp(m_stack, 4);
value = PowerPC::HostRead_U32(m_stack); value = PowerPC::HostRead_U32(guard, m_stack);
m_stack += 4; m_stack += 4;
} }
@ -84,7 +85,7 @@ public:
// 2 - arg_DOUBLEWORD // 2 - arg_DOUBLEWORD
template <typename T, typename std::enable_if_t<IS_DOUBLE_WORD<T>>* = nullptr> template <typename T, typename std::enable_if_t<IS_DOUBLE_WORD<T>>* = nullptr>
T GetArg() T GetArg(const Core::CPUThreadGuard& guard)
{ {
u64 value; u64 value;
@ -92,13 +93,13 @@ public:
m_gpr += 1; m_gpr += 1;
if (m_gpr < m_gpr_max) if (m_gpr < m_gpr_max)
{ {
value = static_cast<u64>(GetGPR(m_gpr)) << 32 | GetGPR(m_gpr + 1); value = static_cast<u64>(GetGPR(guard, m_gpr)) << 32 | GetGPR(guard, m_gpr + 1);
m_gpr += 2; m_gpr += 2;
} }
else else
{ {
m_stack = Common::AlignUp(m_stack, 8); m_stack = Common::AlignUp(m_stack, 8);
value = PowerPC::HostRead_U64(m_stack); value = PowerPC::HostRead_U64(guard, m_stack);
m_stack += 8; m_stack += 8;
} }
@ -107,19 +108,19 @@ public:
// 3 - arg_ARGREAL // 3 - arg_ARGREAL
template <typename T, typename std::enable_if_t<IS_ARG_REAL<T>>* = nullptr> template <typename T, typename std::enable_if_t<IS_ARG_REAL<T>>* = nullptr>
T GetArg() T GetArg(const Core::CPUThreadGuard& guard)
{ {
double value; double value;
if (m_fpr <= m_fpr_max) if (m_fpr <= m_fpr_max)
{ {
value = GetFPR(m_fpr); value = GetFPR(guard, m_fpr);
m_fpr += 1; m_fpr += 1;
} }
else else
{ {
m_stack = Common::AlignUp(m_stack, 8); m_stack = Common::AlignUp(m_stack, 8);
value = PowerPC::HostRead_F64(m_stack); value = PowerPC::HostRead_F64(guard, m_stack);
m_stack += 8; m_stack += 8;
} }
@ -128,9 +129,9 @@ public:
// Helper // Helper
template <typename T> template <typename T>
T GetArgT() T GetArgT(const Core::CPUThreadGuard& guard)
{ {
return static_cast<T>(GetArg<T>()); return static_cast<T>(GetArg<T>(guard));
} }
protected: protected:
@ -142,8 +143,8 @@ protected:
u32 m_stack; u32 m_stack;
private: private:
virtual u32 GetGPR(u32 gpr) const; virtual u32 GetGPR(const Core::CPUThreadGuard& guard, u32 gpr) const;
virtual double GetFPR(u32 fpr) const; virtual double GetFPR(const Core::CPUThreadGuard& guard, u32 fpr) const;
}; };
// See System V ABI (SVR4) for more details // See System V ABI (SVR4) for more details
@ -155,7 +156,7 @@ private:
class VAListStruct : public VAList class VAListStruct : public VAList
{ {
public: public:
explicit VAListStruct(Core::System& system, u32 address); explicit VAListStruct(Core::System& system, const Core::CPUThreadGuard& guard, u32 address);
~VAListStruct() = default; ~VAListStruct() = default;
private: private:
@ -173,8 +174,8 @@ private:
u32 GetGPRArea() const; u32 GetGPRArea() const;
u32 GetFPRArea() const; u32 GetFPRArea() const;
u32 GetGPR(u32 gpr) const override; u32 GetGPR(const Core::CPUThreadGuard& guard, u32 gpr) const override;
double GetFPR(u32 fpr) const override; double GetFPR(const Core::CPUThreadGuard& guard, u32 fpr) const override;
}; };
} // namespace HLE::SystemVABI } // namespace HLE::SystemVABI

View File

@ -14,48 +14,48 @@
namespace AddressSpace namespace AddressSpace
{ {
u16 Accessors::ReadU16(u32 address) const u16 Accessors::ReadU16(const Core::CPUThreadGuard& guard, u32 address) const
{ {
u32 result = ReadU8(address); u32 result = ReadU8(guard, address);
result = result << 8 | ReadU8(address + 1); result = result << 8 | ReadU8(guard, address + 1);
return result; return result;
} }
void Accessors::WriteU16(u32 address, u16 value) void Accessors::WriteU16(const Core::CPUThreadGuard& guard, u32 address, u16 value)
{ {
WriteU8(address, value & 0xff); WriteU8(guard, address, value & 0xff);
WriteU8(address + 1, (value >> 8) & 0xff); WriteU8(guard, address + 1, (value >> 8) & 0xff);
} }
u32 Accessors::ReadU32(u32 address) const u32 Accessors::ReadU32(const Core::CPUThreadGuard& guard, u32 address) const
{ {
u32 result = ReadU16(address); u32 result = ReadU16(guard, address);
result = result << 16 | ReadU16(address + 2); result = result << 16 | ReadU16(guard, address + 2);
return result; return result;
} }
void Accessors::WriteU32(u32 address, u32 value) void Accessors::WriteU32(const Core::CPUThreadGuard& guard, u32 address, u32 value)
{ {
WriteU16(address, value & 0xffff); WriteU16(guard, address, value & 0xffff);
WriteU16(address + 2, (value >> 16) & 0xffff); WriteU16(guard, address + 2, (value >> 16) & 0xffff);
} }
u64 Accessors::ReadU64(u32 address) const u64 Accessors::ReadU64(const Core::CPUThreadGuard& guard, u32 address) const
{ {
u64 result = ReadU32(address); u64 result = ReadU32(guard, address);
result = result << 32 | ReadU32(address + 4); result = result << 32 | ReadU32(guard, address + 4);
return result; return result;
} }
void Accessors::WriteU64(u32 address, u64 value) void Accessors::WriteU64(const Core::CPUThreadGuard& guard, u32 address, u64 value)
{ {
WriteU32(address, value & 0xffffffff); WriteU32(guard, address, value & 0xffffffff);
WriteU32(address + 4, (value >> 32) & 0xffffffff); WriteU32(guard, address + 4, (value >> 32) & 0xffffffff);
} }
float Accessors::ReadF32(u32 address) const float Accessors::ReadF32(const Core::CPUThreadGuard& guard, u32 address) const
{ {
return Common::BitCast<float>(ReadU32(address)); return Common::BitCast<float>(ReadU32(guard, address));
} }
Accessors::iterator Accessors::begin() const Accessors::iterator Accessors::begin() const
@ -68,8 +68,9 @@ Accessors::iterator Accessors::end() const
return nullptr; return nullptr;
} }
std::optional<u32> Accessors::Search(u32 haystack_start, const u8* needle_start, std::optional<u32> Accessors::Search(const Core::CPUThreadGuard& guard, u32 haystack_start,
std::size_t needle_size, bool forwards) const const u8* needle_start, std::size_t needle_size,
bool forwards) const
{ {
return std::nullopt; return std::nullopt;
} }
@ -80,18 +81,49 @@ Accessors::~Accessors()
struct EffectiveAddressSpaceAccessors : Accessors struct EffectiveAddressSpaceAccessors : Accessors
{ {
bool IsValidAddress(u32 address) const override { return PowerPC::HostIsRAMAddress(address); } bool IsValidAddress(const Core::CPUThreadGuard& guard, u32 address) const override
u8 ReadU8(u32 address) const override { return PowerPC::HostRead_U8(address); } {
void WriteU8(u32 address, u8 value) override { PowerPC::HostWrite_U8(value, address); } return PowerPC::HostIsRAMAddress(guard, address);
u16 ReadU16(u32 address) const override { return PowerPC::HostRead_U16(address); } }
void WriteU16(u32 address, u16 value) override { PowerPC::HostWrite_U16(value, address); } u8 ReadU8(const Core::CPUThreadGuard& guard, u32 address) const override
u32 ReadU32(u32 address) const override { return PowerPC::HostRead_U32(address); } {
void WriteU32(u32 address, u32 value) override { PowerPC::HostWrite_U32(value, address); } return PowerPC::HostRead_U8(guard, address);
u64 ReadU64(u32 address) const override { return PowerPC::HostRead_U64(address); } }
void WriteU64(u32 address, u64 value) override { PowerPC::HostWrite_U64(value, address); } void WriteU8(const Core::CPUThreadGuard& guard, u32 address, u8 value) override
float ReadF32(u32 address) const override { return PowerPC::HostRead_F32(address); }; {
PowerPC::HostWrite_U8(guard, value, address);
}
u16 ReadU16(const Core::CPUThreadGuard& guard, u32 address) const override
{
return PowerPC::HostRead_U16(guard, address);
}
void WriteU16(const Core::CPUThreadGuard& guard, u32 address, u16 value) override
{
PowerPC::HostWrite_U16(guard, value, address);
}
u32 ReadU32(const Core::CPUThreadGuard& guard, u32 address) const override
{
return PowerPC::HostRead_U32(guard, address);
}
void WriteU32(const Core::CPUThreadGuard& guard, u32 address, u32 value) override
{
PowerPC::HostWrite_U32(guard, value, address);
}
u64 ReadU64(const Core::CPUThreadGuard& guard, u32 address) const override
{
return PowerPC::HostRead_U64(guard, address);
}
void WriteU64(const Core::CPUThreadGuard& guard, u32 address, u64 value) override
{
PowerPC::HostWrite_U64(guard, value, address);
}
float ReadF32(const Core::CPUThreadGuard& guard, u32 address) const override
{
return PowerPC::HostRead_F32(guard, address);
};
bool Matches(u32 haystack_start, const u8* needle_start, std::size_t needle_size) const bool Matches(const Core::CPUThreadGuard& guard, u32 haystack_start, const u8* needle_start,
std::size_t needle_size) const
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
@ -100,7 +132,7 @@ struct EffectiveAddressSpaceAccessors : Accessors
u32 offset = haystack_start & 0x0000fff; u32 offset = haystack_start & 0x0000fff;
do do
{ {
if (!PowerPC::HostIsRAMAddress(page_base)) if (!PowerPC::HostIsRAMAddress(guard, page_base))
{ {
return false; return false;
} }
@ -137,7 +169,8 @@ struct EffectiveAddressSpaceAccessors : Accessors
return (needle_size == 0); return (needle_size == 0);
} }
std::optional<u32> Search(u32 haystack_start, const u8* needle_start, std::size_t needle_size, std::optional<u32> Search(const Core::CPUThreadGuard& guard, u32 haystack_start,
const u8* needle_start, std::size_t needle_size,
bool forward) const override bool forward) const override
{ {
u32 haystack_address = haystack_start; u32 haystack_address = haystack_start;
@ -150,11 +183,11 @@ struct EffectiveAddressSpaceAccessors : Accessors
const u32 haystack_offset_change = forward ? 1 : -1; const u32 haystack_offset_change = forward ? 1 : -1;
do do
{ {
if (PowerPC::HostIsRAMAddress(haystack_address)) if (PowerPC::HostIsRAMAddress(guard, haystack_address))
{ {
do do
{ {
if (Matches(haystack_address, needle_start, needle_size)) if (Matches(guard, haystack_address, needle_start, needle_size))
{ {
return std::optional<u32>(haystack_address); return std::optional<u32>(haystack_address);
} }
@ -173,17 +206,17 @@ struct EffectiveAddressSpaceAccessors : Accessors
struct AuxiliaryAddressSpaceAccessors : Accessors struct AuxiliaryAddressSpaceAccessors : Accessors
{ {
static constexpr u32 aram_base_address = 0; static constexpr u32 aram_base_address = 0;
bool IsValidAddress(u32 address) const override bool IsValidAddress(const Core::CPUThreadGuard& guard, u32 address) const override
{ {
return !SConfig::GetInstance().bWii && (address - aram_base_address) < GetSize(); return !SConfig::GetInstance().bWii && (address - aram_base_address) < GetSize();
} }
u8 ReadU8(u32 address) const override u8 ReadU8(const Core::CPUThreadGuard& guard, u32 address) const override
{ {
const u8* base = DSP::GetARAMPtr(); const u8* base = DSP::GetARAMPtr();
return base[address]; return base[address];
} }
void WriteU8(u32 address, u8 value) override void WriteU8(const Core::CPUThreadGuard& guard, u32 address, u8 value) override
{ {
u8* base = DSP::GetARAMPtr(); u8* base = DSP::GetARAMPtr();
base[address] = value; base[address] = value;
@ -193,10 +226,11 @@ struct AuxiliaryAddressSpaceAccessors : Accessors
iterator end() const override { return DSP::GetARAMPtr() + GetSize(); } iterator end() const override { return DSP::GetARAMPtr() + GetSize(); }
std::optional<u32> Search(u32 haystack_offset, const u8* needle_start, std::size_t needle_size, std::optional<u32> Search(const Core::CPUThreadGuard& guard, u32 haystack_offset,
const u8* needle_start, std::size_t needle_size,
bool forward) const override bool forward) const override
{ {
if (!IsValidAddress(haystack_offset)) if (!IsValidAddress(guard, haystack_offset))
{ {
return std::nullopt; return std::nullopt;
} }
@ -243,42 +277,44 @@ struct CompositeAddressSpaceAccessors : Accessors
{ {
} }
bool IsValidAddress(u32 address) const override bool IsValidAddress(const Core::CPUThreadGuard& guard, u32 address) const override
{ {
return FindAppropriateAccessor(address) != m_accessor_mappings.end(); return FindAppropriateAccessor(guard, address) != m_accessor_mappings.end();
} }
u8 ReadU8(u32 address) const override u8 ReadU8(const Core::CPUThreadGuard& guard, u32 address) const override
{ {
auto mapping = FindAppropriateAccessor(address); auto mapping = FindAppropriateAccessor(guard, address);
if (mapping == m_accessor_mappings.end()) if (mapping == m_accessor_mappings.end())
{ {
return 0; return 0;
} }
return mapping->accessors->ReadU8(address - mapping->base); return mapping->accessors->ReadU8(guard, address - mapping->base);
} }
void WriteU8(u32 address, u8 value) override void WriteU8(const Core::CPUThreadGuard& guard, u32 address, u8 value) override
{ {
auto mapping = FindAppropriateAccessor(address); auto mapping = FindAppropriateAccessor(guard, address);
if (mapping == m_accessor_mappings.end()) if (mapping == m_accessor_mappings.end())
{ {
return; return;
} }
return mapping->accessors->WriteU8(address - mapping->base, value); return mapping->accessors->WriteU8(guard, address - mapping->base, value);
} }
std::optional<u32> Search(u32 haystack_offset, const u8* needle_start, std::size_t needle_size, std::optional<u32> Search(const Core::CPUThreadGuard& guard, u32 haystack_offset,
const u8* needle_start, std::size_t needle_size,
bool forward) const override bool forward) const override
{ {
for (const AccessorMapping& mapping : m_accessor_mappings) for (const AccessorMapping& mapping : m_accessor_mappings)
{ {
u32 mapping_offset = haystack_offset - mapping.base; u32 mapping_offset = haystack_offset - mapping.base;
if (!mapping.accessors->IsValidAddress(mapping_offset)) if (!mapping.accessors->IsValidAddress(guard, mapping_offset))
{ {
continue; continue;
} }
auto result = mapping.accessors->Search(mapping_offset, needle_start, needle_size, forward); auto result =
mapping.accessors->Search(guard, mapping_offset, needle_start, needle_size, forward);
if (result.has_value()) if (result.has_value())
{ {
return std::optional<u32>(*result + mapping.base); return std::optional<u32>(*result + mapping.base);
@ -289,18 +325,20 @@ struct CompositeAddressSpaceAccessors : Accessors
private: private:
std::vector<AccessorMapping> m_accessor_mappings; std::vector<AccessorMapping> m_accessor_mappings;
std::vector<AccessorMapping>::iterator FindAppropriateAccessor(u32 address) std::vector<AccessorMapping>::iterator FindAppropriateAccessor(const Core::CPUThreadGuard& guard,
u32 address)
{ {
return std::find_if(m_accessor_mappings.begin(), m_accessor_mappings.end(), return std::find_if(m_accessor_mappings.begin(), m_accessor_mappings.end(),
[address](const AccessorMapping& a) { [&guard, address](const AccessorMapping& a) {
return a.accessors->IsValidAddress(address - a.base); return a.accessors->IsValidAddress(guard, address - a.base);
}); });
} }
std::vector<AccessorMapping>::const_iterator FindAppropriateAccessor(u32 address) const std::vector<AccessorMapping>::const_iterator
FindAppropriateAccessor(const Core::CPUThreadGuard& guard, u32 address) const
{ {
return std::find_if(m_accessor_mappings.begin(), m_accessor_mappings.end(), return std::find_if(m_accessor_mappings.begin(), m_accessor_mappings.end(),
[address](const AccessorMapping& a) { [&guard, address](const AccessorMapping& a) {
return a.accessors->IsValidAddress(address - a.base); return a.accessors->IsValidAddress(guard, address - a.base);
}); });
} }
}; };
@ -310,13 +348,19 @@ struct SmallBlockAccessors : Accessors
SmallBlockAccessors() = default; SmallBlockAccessors() = default;
SmallBlockAccessors(u8** alloc_base_, u32 size_) : alloc_base{alloc_base_}, size{size_} {} SmallBlockAccessors(u8** alloc_base_, u32 size_) : alloc_base{alloc_base_}, size{size_} {}
bool IsValidAddress(u32 address) const override bool IsValidAddress(const Core::CPUThreadGuard& guard, u32 address) const override
{ {
return (*alloc_base != nullptr) && (address < size); return (*alloc_base != nullptr) && (address < size);
} }
u8 ReadU8(u32 address) const override { return (*alloc_base)[address]; } u8 ReadU8(const Core::CPUThreadGuard& guard, u32 address) const override
{
return (*alloc_base)[address];
}
void WriteU8(u32 address, u8 value) override { (*alloc_base)[address] = value; } void WriteU8(const Core::CPUThreadGuard& guard, u32 address, u8 value) override
{
(*alloc_base)[address] = value;
}
iterator begin() const override { return *alloc_base; } iterator begin() const override { return *alloc_base; }
@ -325,11 +369,12 @@ struct SmallBlockAccessors : Accessors
return (*alloc_base == nullptr) ? nullptr : (*alloc_base + size); return (*alloc_base == nullptr) ? nullptr : (*alloc_base + size);
} }
std::optional<u32> Search(u32 haystack_offset, const u8* needle_start, std::size_t needle_size, std::optional<u32> Search(const Core::CPUThreadGuard& guard, u32 haystack_offset,
const u8* needle_start, std::size_t needle_size,
bool forward) const override bool forward) const override
{ {
if (!IsValidAddress(haystack_offset) || if (!IsValidAddress(guard, haystack_offset) ||
!IsValidAddress(haystack_offset + static_cast<u32>(needle_size) - 1)) !IsValidAddress(guard, haystack_offset + static_cast<u32>(needle_size) - 1))
{ {
return std::nullopt; return std::nullopt;
} }
@ -364,9 +409,12 @@ private:
struct NullAccessors : Accessors struct NullAccessors : Accessors
{ {
bool IsValidAddress(u32 address) const override { return false; } bool IsValidAddress(const Core::CPUThreadGuard& guard, u32 address) const override
u8 ReadU8(u32 address) const override { return 0; } {
void WriteU8(u32 address, u8 value) override {} return false;
}
u8 ReadU8(const Core::CPUThreadGuard& guard, u32 address) const override { return 0; }
void WriteU8(const Core::CPUThreadGuard& guard, u32 address, u8 value) override {}
}; };
static EffectiveAddressSpaceAccessors s_effective_address_space_accessors; static EffectiveAddressSpaceAccessors s_effective_address_space_accessors;

View File

@ -7,6 +7,11 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
namespace Core
{
class CPUThreadGuard;
}
namespace AddressSpace namespace AddressSpace
{ {
enum class Type enum class Type
@ -23,24 +28,25 @@ struct Accessors
{ {
using iterator = const u8*; using iterator = const u8*;
virtual bool IsValidAddress(u32 address) const = 0; virtual bool IsValidAddress(const Core::CPUThreadGuard& guard, u32 address) const = 0;
virtual u8 ReadU8(u32 address) const = 0; virtual u8 ReadU8(const Core::CPUThreadGuard& guard, u32 address) const = 0;
virtual void WriteU8(u32 address, u8 value) = 0; virtual void WriteU8(const Core::CPUThreadGuard& guard, u32 address, u8 value) = 0;
// overrideable naive implementations of below are defined // overrideable naive implementations of below are defined
virtual u16 ReadU16(u32 address) const; virtual u16 ReadU16(const Core::CPUThreadGuard& guard, u32 address) const;
virtual void WriteU16(u32 address, u16 value); virtual void WriteU16(const Core::CPUThreadGuard& guard, u32 address, u16 value);
virtual u32 ReadU32(u32 address) const; virtual u32 ReadU32(const Core::CPUThreadGuard& guard, u32 address) const;
virtual void WriteU32(u32 address, u32 value); virtual void WriteU32(const Core::CPUThreadGuard& guard, u32 address, u32 value);
virtual u64 ReadU64(u32 address) const; virtual u64 ReadU64(const Core::CPUThreadGuard& guard, u32 address) const;
virtual void WriteU64(u32 address, u64 value); virtual void WriteU64(const Core::CPUThreadGuard& guard, u32 address, u64 value);
virtual float ReadF32(u32 address) const; virtual float ReadF32(const Core::CPUThreadGuard& guard, u32 address) const;
virtual iterator begin() const; virtual iterator begin() const;
virtual iterator end() const; virtual iterator end() const;
virtual std::optional<u32> Search(u32 haystack_offset, const u8* needle_start, virtual std::optional<u32> Search(const Core::CPUThreadGuard& guard, u32 haystack_offset,
std::size_t needle_size, bool forward) const; const u8* needle_start, std::size_t needle_size,
bool forward) const;
virtual ~Accessors(); virtual ~Accessors();
}; };

View File

@ -17,6 +17,7 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/Timer.h" #include "Common/Timer.h"
#include "Core/Boot/AncastTypes.h" #include "Core/Boot/AncastTypes.h"
#include "Core/Boot/DolReader.h" #include "Core/Boot/DolReader.h"
#include "Core/Boot/ElfReader.h" #include "Core/Boot/ElfReader.h"
@ -912,7 +913,10 @@ static void FinishPPCBootstrap(Core::System& system, u64 userdata, s64 cycles_la
else else
ReleasePPC(); ReleasePPC();
SConfig::OnNewTitleLoad(); ASSERT(Core::IsCPUThread());
Core::CPUThreadGuard guard;
SConfig::OnNewTitleLoad(guard);
INFO_LOG_FMT(IOS, "Bootstrapping done."); INFO_LOG_FMT(IOS, "Bootstrapping done.");
} }

View File

@ -6,11 +6,13 @@
#include <cstring> #include <cstring>
#include <utility> #include <utility>
#include "Common/Assert.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/FileUtil.h" #include "Common/FileUtil.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/MsgHandler.h" #include "Common/MsgHandler.h"
#include "Common/Swap.h" #include "Common/Swap.h"
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/Core.h" #include "Core/Core.h"
@ -57,6 +59,10 @@ bool Load()
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
ASSERT(Core::IsCPUThread());
Core::CPUThreadGuard guard;
memory.Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE); memory.Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE);
memory.Write_U32(0x09142001, 0x3180); memory.Write_U32(0x09142001, 0x3180);
@ -69,7 +75,7 @@ bool Load()
g_symbolDB.Clear(); g_symbolDB.Clear();
Host_NotifyMapLoaded(); Host_NotifyMapLoaded();
} }
if (g_symbolDB.LoadMap(File::GetUserPath(D_MAPS_IDX) + "mios-ipl.map")) if (g_symbolDB.LoadMap(guard, File::GetUserPath(D_MAPS_IDX) + "mios-ipl.map"))
{ {
::HLE::Clear(); ::HLE::Clear();
::HLE::PatchFunctions(system); ::HLE::PatchFunctions(system);
@ -93,7 +99,7 @@ bool Load()
NOTICE_LOG_FMT(IOS, "IPL ready."); NOTICE_LOG_FMT(IOS, "IPL ready.");
SConfig::GetInstance().m_is_mios = true; SConfig::GetInstance().m_is_mios = true;
DVDInterface::UpdateRunningGameMetadata(); DVDInterface::UpdateRunningGameMetadata();
SConfig::OnNewTitleLoad(); SConfig::OnNewTitleLoad(guard);
return true; return true;
} }
} // namespace IOS::HLE::MIOS } // namespace IOS::HLE::MIOS

View File

@ -67,19 +67,19 @@ bool MemoryWatcher::OpenSocket(const std::string& path)
return m_fd >= 0; return m_fd >= 0;
} }
u32 MemoryWatcher::ChasePointer(const std::string& line) u32 MemoryWatcher::ChasePointer(const Core::CPUThreadGuard& guard, const std::string& line)
{ {
u32 value = 0; u32 value = 0;
for (u32 offset : m_addresses[line]) for (u32 offset : m_addresses[line])
{ {
value = PowerPC::HostRead_U32(value + offset); value = PowerPC::HostRead_U32(guard, value + offset);
if (!PowerPC::HostIsRAMAddress(value)) if (!PowerPC::HostIsRAMAddress(guard, value))
break; break;
} }
return value; return value;
} }
std::string MemoryWatcher::ComposeMessages() std::string MemoryWatcher::ComposeMessages(const Core::CPUThreadGuard& guard)
{ {
std::ostringstream message_stream; std::ostringstream message_stream;
message_stream << std::hex; message_stream << std::hex;
@ -89,7 +89,7 @@ std::string MemoryWatcher::ComposeMessages()
std::string address = entry.first; std::string address = entry.first;
u32& current_value = entry.second; u32& current_value = entry.second;
u32 new_value = ChasePointer(address); u32 new_value = ChasePointer(guard, address);
if (new_value != current_value) if (new_value != current_value)
{ {
// Update the value // Update the value
@ -101,12 +101,12 @@ std::string MemoryWatcher::ComposeMessages()
return message_stream.str(); return message_stream.str();
} }
void MemoryWatcher::Step() void MemoryWatcher::Step(const Core::CPUThreadGuard& guard)
{ {
if (!m_running) if (!m_running)
return; return;
std::string message = ComposeMessages(); std::string message = ComposeMessages(guard);
sendto(m_fd, message.c_str(), message.size() + 1, 0, reinterpret_cast<sockaddr*>(&m_addr), sendto(m_fd, message.c_str(), message.size() + 1, 0, reinterpret_cast<sockaddr*>(&m_addr),
sizeof(m_addr)); sizeof(m_addr));
} }

View File

@ -11,6 +11,11 @@
#include <sys/un.h> #include <sys/un.h>
#include <vector> #include <vector>
namespace Core
{
class CPUThreadGuard;
}
// MemoryWatcher reads a file containing in-game memory addresses and outputs // MemoryWatcher reads a file containing in-game memory addresses and outputs
// changes to those memory addresses to a unix domain socket as the game runs. // changes to those memory addresses to a unix domain socket as the game runs.
// //
@ -24,15 +29,15 @@ class MemoryWatcher final
public: public:
MemoryWatcher(); MemoryWatcher();
~MemoryWatcher(); ~MemoryWatcher();
void Step(); void Step(const Core::CPUThreadGuard& guard);
private: private:
bool LoadAddresses(const std::string& path); bool LoadAddresses(const std::string& path);
bool OpenSocket(const std::string& path); bool OpenSocket(const std::string& path);
void ParseLine(const std::string& line); void ParseLine(const std::string& line);
u32 ChasePointer(const std::string& line); u32 ChasePointer(const Core::CPUThreadGuard& guard, const std::string& line);
std::string ComposeMessages(); std::string ComposeMessages(const Core::CPUThreadGuard& guard);
bool m_running = false; bool m_running = false;

View File

@ -28,6 +28,7 @@
#include "Core/CheatCodes.h" #include "Core/CheatCodes.h"
#include "Core/Config/SessionSettings.h" #include "Core/Config/SessionSettings.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/Debugger/PPCDebugInterface.h" #include "Core/Debugger/PPCDebugInterface.h"
#include "Core/GeckoCode.h" #include "Core/GeckoCode.h"
#include "Core/GeckoCodeConfig.h" #include "Core/GeckoCodeConfig.h"
@ -230,7 +231,7 @@ void LoadPatches()
LoadSpeedhacks("Speedhacks", merged); LoadSpeedhacks("Speedhacks", merged);
} }
static void ApplyPatches(const std::vector<Patch>& patches) static void ApplyPatches(const Core::CPUThreadGuard& guard, const std::vector<Patch>& patches)
{ {
for (const Patch& patch : patches) for (const Patch& patch : patches)
{ {
@ -244,16 +245,17 @@ static void ApplyPatches(const std::vector<Patch>& patches)
switch (entry.type) switch (entry.type)
{ {
case PatchType::Patch8Bit: case PatchType::Patch8Bit:
if (!entry.conditional || PowerPC::HostRead_U8(addr) == static_cast<u8>(comparand)) if (!entry.conditional || PowerPC::HostRead_U8(guard, addr) == static_cast<u8>(comparand))
PowerPC::HostWrite_U8(static_cast<u8>(value), addr); PowerPC::HostWrite_U8(guard, static_cast<u8>(value), addr);
break; break;
case PatchType::Patch16Bit: case PatchType::Patch16Bit:
if (!entry.conditional || PowerPC::HostRead_U16(addr) == static_cast<u16>(comparand)) if (!entry.conditional ||
PowerPC::HostWrite_U16(static_cast<u16>(value), addr); PowerPC::HostRead_U16(guard, addr) == static_cast<u16>(comparand))
PowerPC::HostWrite_U16(guard, static_cast<u16>(value), addr);
break; break;
case PatchType::Patch32Bit: case PatchType::Patch32Bit:
if (!entry.conditional || PowerPC::HostRead_U32(addr) == comparand) if (!entry.conditional || PowerPC::HostRead_U32(guard, addr) == comparand)
PowerPC::HostWrite_U32(value, addr); PowerPC::HostWrite_U32(guard, value, addr);
break; break;
default: default:
// unknown patchtype // unknown patchtype
@ -264,19 +266,20 @@ static void ApplyPatches(const std::vector<Patch>& patches)
} }
} }
static void ApplyMemoryPatches(std::span<const std::size_t> memory_patch_indices) static void ApplyMemoryPatches(const Core::CPUThreadGuard& guard,
std::span<const std::size_t> memory_patch_indices)
{ {
std::lock_guard lock(s_on_frame_memory_mutex); std::lock_guard lock(s_on_frame_memory_mutex);
for (std::size_t index : memory_patch_indices) for (std::size_t index : memory_patch_indices)
{ {
PowerPC::debug_interface.ApplyExistingPatch(index); PowerPC::debug_interface.ApplyExistingPatch(guard, index);
} }
} }
// Requires MSR.DR, MSR.IR // Requires MSR.DR, MSR.IR
// There's no perfect way to do this, it's just a heuristic. // There's no perfect way to do this, it's just a heuristic.
// We require at least 2 stack frames, if the stack is shallower than that then it won't work. // We require at least 2 stack frames, if the stack is shallower than that then it won't work.
static bool IsStackSane() static bool IsStackValid(const Core::CPUThreadGuard& guard)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState(); auto& ppc_state = system.GetPPCState();
@ -285,19 +288,19 @@ static bool IsStackSane()
// Check the stack pointer // Check the stack pointer
u32 SP = ppc_state.gpr[1]; u32 SP = ppc_state.gpr[1];
if (!PowerPC::HostIsRAMAddress(SP)) if (!PowerPC::HostIsRAMAddress(guard, SP))
return false; return false;
// Read the frame pointer from the stack (find 2nd frame from top), assert that it makes sense // Read the frame pointer from the stack (find 2nd frame from top), assert that it makes sense
u32 next_SP = PowerPC::HostRead_U32(SP); u32 next_SP = PowerPC::HostRead_U32(guard, SP);
if (next_SP <= SP || !PowerPC::HostIsRAMAddress(next_SP) || if (next_SP <= SP || !PowerPC::HostIsRAMAddress(guard, next_SP) ||
!PowerPC::HostIsRAMAddress(next_SP + 4)) !PowerPC::HostIsRAMAddress(guard, next_SP + 4))
return false; return false;
// Check the link register makes sense (that it points to a valid IBAT address) // Check the link register makes sense (that it points to a valid IBAT address)
const u32 address = PowerPC::HostRead_U32(next_SP + 4); const u32 address = PowerPC::HostRead_U32(guard, next_SP + 4);
return PowerPC::HostIsInstructionRAMAddress(address) && return PowerPC::HostIsInstructionRAMAddress(guard, address) &&
0 != PowerPC::HostRead_Instruction(address); 0 != PowerPC::HostRead_Instruction(guard, address);
} }
void AddMemoryPatch(std::size_t index) void AddMemoryPatch(std::size_t index)
@ -318,11 +321,14 @@ bool ApplyFramePatches()
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState(); auto& ppc_state = system.GetPPCState();
ASSERT(Core::IsCPUThread());
Core::CPUThreadGuard guard;
// Because we're using the VI Interrupt to time this instead of patching the game with a // Because we're using the VI Interrupt to time this instead of patching the game with a
// callback hook we can end up catching the game in an exception vector. // callback hook we can end up catching the game in an exception vector.
// We deal with this by returning false so that SystemTimers will reschedule us in a few cycles // We deal with this by returning false so that SystemTimers will reschedule us in a few cycles
// where we can try again after the CPU hopefully returns back to the normal instruction flow. // where we can try again after the CPU hopefully returns back to the normal instruction flow.
if (!ppc_state.msr.DR || !ppc_state.msr.IR || !IsStackSane()) if (!ppc_state.msr.DR || !ppc_state.msr.IR || !IsStackValid(guard))
{ {
DEBUG_LOG_FMT(ACTIONREPLAY, DEBUG_LOG_FMT(ACTIONREPLAY,
"Need to retry later. CPU configuration is currently incorrect. PC = {:#010x}, " "Need to retry later. CPU configuration is currently incorrect. PC = {:#010x}, "
@ -331,12 +337,12 @@ bool ApplyFramePatches()
return false; return false;
} }
ApplyPatches(s_on_frame); ApplyPatches(guard, s_on_frame);
ApplyMemoryPatches(s_on_frame_memory); ApplyMemoryPatches(guard, s_on_frame_memory);
// Run the Gecko code handler // Run the Gecko code handler
Gecko::RunCodeHandler(); Gecko::RunCodeHandler(guard);
ActionReplay::RunAllActive(); ActionReplay::RunAllActive(guard);
return true; return true;
} }

View File

@ -23,57 +23,57 @@
#include "Core/System.h" #include "Core/System.h"
template <typename T> template <typename T>
static T HostRead(u32 address); static T HostRead(const Core::CPUThreadGuard& guard, u32 address);
template <typename T> template <typename T>
static void HostWrite(T var, u32 address); static void HostWrite(const Core::CPUThreadGuard& guard, T var, u32 address);
template <> template <>
u8 HostRead(u32 address) u8 HostRead(const Core::CPUThreadGuard& guard, u32 address)
{ {
return PowerPC::HostRead_U8(address); return PowerPC::HostRead_U8(guard, address);
} }
template <> template <>
u16 HostRead(u32 address) u16 HostRead(const Core::CPUThreadGuard& guard, u32 address)
{ {
return PowerPC::HostRead_U16(address); return PowerPC::HostRead_U16(guard, address);
} }
template <> template <>
u32 HostRead(u32 address) u32 HostRead(const Core::CPUThreadGuard& guard, u32 address)
{ {
return PowerPC::HostRead_U32(address); return PowerPC::HostRead_U32(guard, address);
} }
template <> template <>
u64 HostRead(u32 address) u64 HostRead(const Core::CPUThreadGuard& guard, u32 address)
{ {
return PowerPC::HostRead_U64(address); return PowerPC::HostRead_U64(guard, address);
} }
template <> template <>
void HostWrite(u8 var, u32 address) void HostWrite(const Core::CPUThreadGuard& guard, u8 var, u32 address)
{ {
PowerPC::HostWrite_U8(var, address); PowerPC::HostWrite_U8(guard, var, address);
} }
template <> template <>
void HostWrite(u16 var, u32 address) void HostWrite(const Core::CPUThreadGuard& guard, u16 var, u32 address)
{ {
PowerPC::HostWrite_U16(var, address); PowerPC::HostWrite_U16(guard, var, address);
} }
template <> template <>
void HostWrite(u32 var, u32 address) void HostWrite(const Core::CPUThreadGuard& guard, u32 var, u32 address)
{ {
PowerPC::HostWrite_U32(var, address); PowerPC::HostWrite_U32(guard, var, address);
} }
template <> template <>
void HostWrite(u64 var, u32 address) void HostWrite(const Core::CPUThreadGuard& guard, u64 var, u32 address)
{ {
PowerPC::HostWrite_U64(var, address); PowerPC::HostWrite_U64(guard, var, address);
} }
template <typename T, typename U = T> template <typename T, typename U = T>
@ -81,8 +81,9 @@ static double HostReadFunc(expr_func* f, vec_expr_t* args, void* c)
{ {
if (vec_len(args) != 1) if (vec_len(args) != 1)
return 0; return 0;
const auto* guard = reinterpret_cast<const Core::CPUThreadGuard*>(c);
const u32 address = static_cast<u32>(expr_eval(&vec_nth(args, 0))); const u32 address = static_cast<u32>(expr_eval(&vec_nth(args, 0)));
return Common::BitCast<T>(HostRead<U>(address)); return Common::BitCast<T>(HostRead<U>(*guard, address));
} }
template <typename T, typename U = T> template <typename T, typename U = T>
@ -90,9 +91,10 @@ static double HostWriteFunc(expr_func* f, vec_expr_t* args, void* c)
{ {
if (vec_len(args) != 2) if (vec_len(args) != 2)
return 0; return 0;
const auto* guard = reinterpret_cast<const Core::CPUThreadGuard*>(c);
const T var = static_cast<T>(expr_eval(&vec_nth(args, 0))); const T var = static_cast<T>(expr_eval(&vec_nth(args, 0)));
const u32 address = static_cast<u32>(expr_eval(&vec_nth(args, 1))); const u32 address = static_cast<u32>(expr_eval(&vec_nth(args, 1)));
HostWrite<U>(Common::BitCast<U>(var), address); HostWrite<U>(*guard, Common::BitCast<U>(var), address);
return var; return var;
} }
@ -110,7 +112,8 @@ static double CallstackFunc(expr_func* f, vec_expr_t* args, void* c)
return 0; return 0;
std::vector<Dolphin_Debugger::CallstackEntry> stack; std::vector<Dolphin_Debugger::CallstackEntry> stack;
bool success = Dolphin_Debugger::GetCallstack(Core::System::GetInstance(), stack); const auto* guard = reinterpret_cast<const Core::CPUThreadGuard*>(c);
bool success = Dolphin_Debugger::GetCallstack(Core::System::GetInstance(), *guard, stack);
if (!success) if (!success)
return 0; return 0;
@ -225,7 +228,13 @@ double Expression::Evaluate() const
{ {
SynchronizeBindings(SynchronizeDirection::From); SynchronizeBindings(SynchronizeDirection::From);
double result = expr_eval(m_expr.get()); double result;
{
Core::CPUThreadGuard guard;
m_expr->param.func.context = &guard;
result = expr_eval(m_expr.get());
m_expr->param.func.context = nullptr;
}
SynchronizeBindings(SynchronizeDirection::To); SynchronizeBindings(SynchronizeDirection::To);

View File

@ -12,6 +12,11 @@
struct expr; struct expr;
struct expr_var_list; struct expr_var_list;
namespace Core
{
class CPUThreadGuard;
}
struct ExprDeleter struct ExprDeleter
{ {
void operator()(expr* expression) const; void operator()(expr* expression) const;

View File

@ -25,6 +25,7 @@ typedef SSIZE_T ssize_t;
#include <unistd.h> #include <unistd.h>
#endif #endif
#include "Common/Assert.h"
#include "Common/Event.h" #include "Common/Event.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/SocketContext.h" #include "Common/SocketContext.h"
@ -799,7 +800,7 @@ static void WriteRegister()
SendReply("OK"); SendReply("OK");
} }
static void ReadMemory() static void ReadMemory(const Core::CPUThreadGuard& guard)
{ {
static u8 reply[GDB_BFR_MAX - 4]; static u8 reply[GDB_BFR_MAX - 4];
u32 addr, len; u32 addr, len;
@ -819,7 +820,7 @@ static void ReadMemory()
if (len * 2 > sizeof reply) if (len * 2 > sizeof reply)
SendReply("E01"); SendReply("E01");
if (!PowerPC::HostIsRAMAddress(addr)) if (!PowerPC::HostIsRAMAddress(guard, addr))
return SendReply("E00"); return SendReply("E00");
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
@ -830,7 +831,7 @@ static void ReadMemory()
SendReply((char*)reply); SendReply((char*)reply);
} }
static void WriteMemory() static void WriteMemory(const Core::CPUThreadGuard& guard)
{ {
u32 addr, len; u32 addr, len;
u32 i; u32 i;
@ -846,7 +847,7 @@ static void WriteMemory()
len = (len << 4) | Hex2char(s_cmd_bfr[i++]); len = (len << 4) | Hex2char(s_cmd_bfr[i++]);
INFO_LOG_FMT(GDB_STUB, "gdb: write memory: {:08x} bytes to {:08x}", len, addr); INFO_LOG_FMT(GDB_STUB, "gdb: write memory: {:08x} bytes to {:08x}", len, addr);
if (!PowerPC::HostIsRAMAddress(addr)) if (!PowerPC::HostIsRAMAddress(guard, addr))
return SendReply("E00"); return SendReply("E00");
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
@ -990,11 +991,19 @@ void ProcessCommands(bool loop_until_continue)
WriteRegister(); WriteRegister();
break; break;
case 'm': case 'm':
ReadMemory(); {
ASSERT(Core::IsCPUThread());
Core::CPUThreadGuard guard;
ReadMemory(guard);
break; break;
}
case 'M': case 'M':
{ {
WriteMemory(); ASSERT(Core::IsCPUThread());
Core::CPUThreadGuard guard;
WriteMemory(guard);
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState(); auto& ppc_state = system.GetPPCState();
ppc_state.iCache.Reset(); ppc_state.iCache.Reset();

View File

@ -14,6 +14,7 @@
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h" #include "Core/CoreTiming.h"
#include "Core/Debugger/Debugger_SymbolMap.h" #include "Core/Debugger/Debugger_SymbolMap.h"
#include "Core/HLE/HLE.h" #include "Core/HLE/HLE.h"
@ -339,11 +340,14 @@ void Interpreter::Run()
void Interpreter::unknown_instruction(UGeckoInstruction inst) void Interpreter::unknown_instruction(UGeckoInstruction inst)
{ {
const u32 opcode = PowerPC::HostRead_U32(last_pc); ASSERT(Core::IsCPUThread());
Core::CPUThreadGuard guard;
const u32 opcode = PowerPC::HostRead_U32(guard, last_pc);
const std::string disasm = Common::GekkoDisassembler::Disassemble(opcode, last_pc); const std::string disasm = Common::GekkoDisassembler::Disassemble(opcode, last_pc);
NOTICE_LOG_FMT(POWERPC, "Last PC = {:08x} : {}", last_pc, disasm); NOTICE_LOG_FMT(POWERPC, "Last PC = {:08x} : {}", last_pc, disasm);
Dolphin_Debugger::PrintCallstack(Core::System::GetInstance(), Common::Log::LogType::POWERPC, Dolphin_Debugger::PrintCallstack(Core::System::GetInstance(), guard,
Common::Log::LogLevel::LNOTICE); Common::Log::LogType::POWERPC, Common::Log::LogLevel::LNOTICE);
NOTICE_LOG_FMT( NOTICE_LOG_FMT(
POWERPC, POWERPC,
"\nIntCPU: Unknown instruction {:08x} at PC = {:08x} last_PC = {:08x} LR = {:08x}\n", "\nIntCPU: Unknown instruction {:08x} at PC = {:08x} last_PC = {:08x} LR = {:08x}\n",

View File

@ -6,6 +6,7 @@
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/HLE/HLE.h" #include "Core/HLE/HLE.h"
#include "Core/PowerPC/Interpreter/ExceptionUtils.h" #include "Core/PowerPC/Interpreter/ExceptionUtils.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
@ -95,7 +96,11 @@ void Interpreter::bclrx(UGeckoInstruction inst)
void Interpreter::HLEFunction(UGeckoInstruction inst) void Interpreter::HLEFunction(UGeckoInstruction inst)
{ {
m_end_block = true; m_end_block = true;
HLE::Execute(PowerPC::ppcState.pc, inst.hex);
ASSERT(Core::IsCPUThread());
Core::CPUThreadGuard guard;
HLE::Execute(guard, PowerPC::ppcState.pc, inst.hex);
} }
void Interpreter::rfi(UGeckoInstruction inst) void Interpreter::rfi(UGeckoInstruction inst)

View File

@ -16,6 +16,7 @@
#include <fmt/format.h> #include <fmt/format.h>
#include "Common/Assert.h"
#include "Common/ChunkFile.h" #include "Common/ChunkFile.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/IOFile.h" #include "Common/IOFile.h"
@ -271,8 +272,12 @@ void CompileExceptionCheck(ExceptionType type)
{ {
if (type == ExceptionType::FIFOWrite) if (type == ExceptionType::FIFOWrite)
{ {
ASSERT(Core::IsCPUThread());
Core::CPUThreadGuard guard;
// Check in case the code has been replaced since: do we need to do this? // Check in case the code has been replaced since: do we need to do this?
const OpType optype = PPCTables::GetOpInfo(PowerPC::HostRead_U32(PowerPC::ppcState.pc))->type; const OpType optype =
PPCTables::GetOpInfo(PowerPC::HostRead_U32(guard, PowerPC::ppcState.pc))->type;
if (optype != OpType::Store && optype != OpType::StoreFP && optype != OpType::StorePS) if (optype != OpType::Store && optype != OpType::StoreFP && optype != OpType::StorePS)
return; return;
} }

View File

@ -519,17 +519,18 @@ TryReadInstResult TryReadInstruction(u32 address)
return TryReadInstResult{true, from_bat, hex, address}; return TryReadInstResult{true, from_bat, hex, address};
} }
u32 HostRead_Instruction(const u32 address) u32 HostRead_Instruction(const Core::CPUThreadGuard& guard, const u32 address)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
return ReadFromHardware<XCheckTLBFlag::OpcodeNoException, u32>(memory, address); return ReadFromHardware<XCheckTLBFlag::OpcodeNoException, u32>(memory, address);
} }
std::optional<ReadResult<u32>> HostTryReadInstruction(const u32 address, std::optional<ReadResult<u32>> HostTryReadInstruction(const Core::CPUThreadGuard& guard,
const u32 address,
RequestedAddressSpace space) RequestedAddressSpace space)
{ {
if (!HostIsInstructionRAMAddress(address, space)) if (!HostIsInstructionRAMAddress(guard, address, space))
return std::nullopt; return std::nullopt;
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
@ -648,9 +649,10 @@ float Read_F32(const u32 address)
} }
template <typename T> template <typename T>
static std::optional<ReadResult<T>> HostTryReadUX(const u32 address, RequestedAddressSpace space) static std::optional<ReadResult<T>> HostTryReadUX(const Core::CPUThreadGuard& guard,
const u32 address, RequestedAddressSpace space)
{ {
if (!HostIsRAMAddress(address, space)) if (!HostIsRAMAddress(guard, address, space))
return std::nullopt; return std::nullopt;
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
@ -681,37 +683,43 @@ static std::optional<ReadResult<T>> HostTryReadUX(const u32 address, RequestedAd
return std::nullopt; return std::nullopt;
} }
std::optional<ReadResult<u8>> HostTryReadU8(u32 address, RequestedAddressSpace space) std::optional<ReadResult<u8>> HostTryReadU8(const Core::CPUThreadGuard& guard, u32 address,
RequestedAddressSpace space)
{ {
return HostTryReadUX<u8>(address, space); return HostTryReadUX<u8>(guard, address, space);
} }
std::optional<ReadResult<u16>> HostTryReadU16(u32 address, RequestedAddressSpace space) std::optional<ReadResult<u16>> HostTryReadU16(const Core::CPUThreadGuard& guard, u32 address,
RequestedAddressSpace space)
{ {
return HostTryReadUX<u16>(address, space); return HostTryReadUX<u16>(guard, address, space);
} }
std::optional<ReadResult<u32>> HostTryReadU32(u32 address, RequestedAddressSpace space) std::optional<ReadResult<u32>> HostTryReadU32(const Core::CPUThreadGuard& guard, u32 address,
RequestedAddressSpace space)
{ {
return HostTryReadUX<u32>(address, space); return HostTryReadUX<u32>(guard, address, space);
} }
std::optional<ReadResult<u64>> HostTryReadU64(u32 address, RequestedAddressSpace space) std::optional<ReadResult<u64>> HostTryReadU64(const Core::CPUThreadGuard& guard, u32 address,
RequestedAddressSpace space)
{ {
return HostTryReadUX<u64>(address, space); return HostTryReadUX<u64>(guard, address, space);
} }
std::optional<ReadResult<float>> HostTryReadF32(u32 address, RequestedAddressSpace space) std::optional<ReadResult<float>> HostTryReadF32(const Core::CPUThreadGuard& guard, u32 address,
RequestedAddressSpace space)
{ {
const auto result = HostTryReadUX<u32>(address, space); const auto result = HostTryReadUX<u32>(guard, address, space);
if (!result) if (!result)
return std::nullopt; return std::nullopt;
return ReadResult<float>(result->translated, Common::BitCast<float>(result->value)); return ReadResult<float>(result->translated, Common::BitCast<float>(result->value));
} }
std::optional<ReadResult<double>> HostTryReadF64(u32 address, RequestedAddressSpace space) std::optional<ReadResult<double>> HostTryReadF64(const Core::CPUThreadGuard& guard, u32 address,
RequestedAddressSpace space)
{ {
const auto result = HostTryReadUX<u64>(address, space); const auto result = HostTryReadUX<u64>(guard, address, space);
if (!result) if (!result)
return std::nullopt; return std::nullopt;
return ReadResult<double>(result->translated, Common::BitCast<double>(result->value)); return ReadResult<double>(result->translated, Common::BitCast<double>(result->value));
@ -780,70 +788,70 @@ void Write_F64(const double var, const u32 address)
Write_U64(integral, address); Write_U64(integral, address);
} }
u8 HostRead_U8(const u32 address) u8 HostRead_U8(const Core::CPUThreadGuard& guard, const u32 address)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
return ReadFromHardware<XCheckTLBFlag::NoException, u8>(memory, address); return ReadFromHardware<XCheckTLBFlag::NoException, u8>(memory, address);
} }
u16 HostRead_U16(const u32 address) u16 HostRead_U16(const Core::CPUThreadGuard& guard, const u32 address)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
return ReadFromHardware<XCheckTLBFlag::NoException, u16>(memory, address); return ReadFromHardware<XCheckTLBFlag::NoException, u16>(memory, address);
} }
u32 HostRead_U32(const u32 address) u32 HostRead_U32(const Core::CPUThreadGuard& guard, const u32 address)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
return ReadFromHardware<XCheckTLBFlag::NoException, u32>(memory, address); return ReadFromHardware<XCheckTLBFlag::NoException, u32>(memory, address);
} }
u64 HostRead_U64(const u32 address) u64 HostRead_U64(const Core::CPUThreadGuard& guard, const u32 address)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
return ReadFromHardware<XCheckTLBFlag::NoException, u64>(memory, address); return ReadFromHardware<XCheckTLBFlag::NoException, u64>(memory, address);
} }
float HostRead_F32(const u32 address) float HostRead_F32(const Core::CPUThreadGuard& guard, const u32 address)
{ {
const u32 integral = HostRead_U32(address); const u32 integral = HostRead_U32(guard, address);
return Common::BitCast<float>(integral); return Common::BitCast<float>(integral);
} }
double HostRead_F64(const u32 address) double HostRead_F64(const Core::CPUThreadGuard& guard, const u32 address)
{ {
const u64 integral = HostRead_U64(address); const u64 integral = HostRead_U64(guard, address);
return Common::BitCast<double>(integral); return Common::BitCast<double>(integral);
} }
void HostWrite_U8(const u32 var, const u32 address) void HostWrite_U8(const Core::CPUThreadGuard& guard, const u32 var, const u32 address)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
WriteToHardware<XCheckTLBFlag::NoException>(system, memory, address, var, 1); WriteToHardware<XCheckTLBFlag::NoException>(system, memory, address, var, 1);
} }
void HostWrite_U16(const u32 var, const u32 address) void HostWrite_U16(const Core::CPUThreadGuard& guard, const u32 var, const u32 address)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
WriteToHardware<XCheckTLBFlag::NoException>(system, memory, address, var, 2); WriteToHardware<XCheckTLBFlag::NoException>(system, memory, address, var, 2);
} }
void HostWrite_U32(const u32 var, const u32 address) void HostWrite_U32(const Core::CPUThreadGuard& guard, const u32 var, const u32 address)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
WriteToHardware<XCheckTLBFlag::NoException>(system, memory, address, var, 4); WriteToHardware<XCheckTLBFlag::NoException>(system, memory, address, var, 4);
} }
void HostWrite_U64(const u64 var, const u32 address) void HostWrite_U64(const Core::CPUThreadGuard& guard, const u64 var, const u32 address)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
@ -853,24 +861,25 @@ void HostWrite_U64(const u64 var, const u32 address)
static_cast<u32>(var), 4); static_cast<u32>(var), 4);
} }
void HostWrite_F32(const float var, const u32 address) void HostWrite_F32(const Core::CPUThreadGuard& guard, const float var, const u32 address)
{ {
const u32 integral = Common::BitCast<u32>(var); const u32 integral = Common::BitCast<u32>(var);
HostWrite_U32(integral, address); HostWrite_U32(guard, integral, address);
} }
void HostWrite_F64(const double var, const u32 address) void HostWrite_F64(const Core::CPUThreadGuard& guard, const double var, const u32 address)
{ {
const u64 integral = Common::BitCast<u64>(var); const u64 integral = Common::BitCast<u64>(var);
HostWrite_U64(integral, address); HostWrite_U64(guard, integral, address);
} }
static std::optional<WriteResult> HostTryWriteUX(const u32 var, const u32 address, const u32 size, static std::optional<WriteResult> HostTryWriteUX(const Core::CPUThreadGuard& guard, const u32 var,
const u32 address, const u32 size,
RequestedAddressSpace space) RequestedAddressSpace space)
{ {
if (!HostIsRAMAddress(address, space)) if (!HostIsRAMAddress(guard, address, space))
return std::nullopt; return std::nullopt;
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
@ -895,56 +904,56 @@ static std::optional<WriteResult> HostTryWriteUX(const u32 var, const u32 addres
return std::nullopt; return std::nullopt;
} }
std::optional<WriteResult> HostTryWriteU8(const u32 var, const u32 address, std::optional<WriteResult> HostTryWriteU8(const Core::CPUThreadGuard& guard, const u32 var,
RequestedAddressSpace space) const u32 address, RequestedAddressSpace space)
{ {
return HostTryWriteUX(var, address, 1, space); return HostTryWriteUX(guard, var, address, 1, space);
} }
std::optional<WriteResult> HostTryWriteU16(const u32 var, const u32 address, std::optional<WriteResult> HostTryWriteU16(const Core::CPUThreadGuard& guard, const u32 var,
RequestedAddressSpace space) const u32 address, RequestedAddressSpace space)
{ {
return HostTryWriteUX(var, address, 2, space); return HostTryWriteUX(guard, var, address, 2, space);
} }
std::optional<WriteResult> HostTryWriteU32(const u32 var, const u32 address, std::optional<WriteResult> HostTryWriteU32(const Core::CPUThreadGuard& guard, const u32 var,
RequestedAddressSpace space) const u32 address, RequestedAddressSpace space)
{ {
return HostTryWriteUX(var, address, 4, space); return HostTryWriteUX(guard, var, address, 4, space);
} }
std::optional<WriteResult> HostTryWriteU64(const u64 var, const u32 address, std::optional<WriteResult> HostTryWriteU64(const Core::CPUThreadGuard& guard, const u64 var,
RequestedAddressSpace space) const u32 address, RequestedAddressSpace space)
{ {
const auto result = HostTryWriteUX(static_cast<u32>(var >> 32), address, 4, space); const auto result = HostTryWriteUX(guard, static_cast<u32>(var >> 32), address, 4, space);
if (!result) if (!result)
return result; return result;
return HostTryWriteUX(static_cast<u32>(var), address + 4, 4, space); return HostTryWriteUX(guard, static_cast<u32>(var), address + 4, 4, space);
} }
std::optional<WriteResult> HostTryWriteF32(const float var, const u32 address, std::optional<WriteResult> HostTryWriteF32(const Core::CPUThreadGuard& guard, const float var,
RequestedAddressSpace space) const u32 address, RequestedAddressSpace space)
{ {
const u32 integral = Common::BitCast<u32>(var); const u32 integral = Common::BitCast<u32>(var);
return HostTryWriteU32(integral, address, space); return HostTryWriteU32(guard, integral, address, space);
} }
std::optional<WriteResult> HostTryWriteF64(const double var, const u32 address, std::optional<WriteResult> HostTryWriteF64(const Core::CPUThreadGuard& guard, const double var,
RequestedAddressSpace space) const u32 address, RequestedAddressSpace space)
{ {
const u64 integral = Common::BitCast<u64>(var); const u64 integral = Common::BitCast<u64>(var);
return HostTryWriteU64(integral, address, space); return HostTryWriteU64(guard, integral, address, space);
} }
std::string HostGetString(u32 address, size_t size) std::string HostGetString(const Core::CPUThreadGuard& guard, u32 address, size_t size)
{ {
std::string s; std::string s;
do do
{ {
if (!HostIsRAMAddress(address)) if (!HostIsRAMAddress(guard, address))
break; break;
u8 res = HostRead_U8(address); u8 res = HostRead_U8(guard, address);
if (!res) if (!res)
break; break;
s += static_cast<char>(res); s += static_cast<char>(res);
@ -953,10 +962,11 @@ std::string HostGetString(u32 address, size_t size)
return s; return s;
} }
std::optional<ReadResult<std::string>> HostTryReadString(u32 address, size_t size, std::optional<ReadResult<std::string>> HostTryReadString(const Core::CPUThreadGuard& guard,
u32 address, size_t size,
RequestedAddressSpace space) RequestedAddressSpace space)
{ {
auto c = HostTryReadU8(address, space); auto c = HostTryReadU8(guard, address, space);
if (!c) if (!c)
return std::nullopt; return std::nullopt;
if (c->value == 0) if (c->value == 0)
@ -967,7 +977,7 @@ std::optional<ReadResult<std::string>> HostTryReadString(u32 address, size_t siz
while (size == 0 || s.length() < size) while (size == 0 || s.length() < size)
{ {
++address; ++address;
const auto res = HostTryReadU8(address, space); const auto res = HostTryReadU8(guard, address, space);
if (!res || res->value == 0) if (!res || res->value == 0)
break; break;
s += static_cast<char>(res->value); s += static_cast<char>(res->value);
@ -1024,7 +1034,7 @@ static bool IsRAMAddress(Memory::MemoryManager& memory, u32 address, bool transl
return false; return false;
} }
bool HostIsRAMAddress(u32 address, RequestedAddressSpace space) bool HostIsRAMAddress(const Core::CPUThreadGuard& guard, u32 address, RequestedAddressSpace space)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
@ -1045,7 +1055,8 @@ bool HostIsRAMAddress(u32 address, RequestedAddressSpace space)
return false; return false;
} }
bool HostIsInstructionRAMAddress(u32 address, RequestedAddressSpace space) bool HostIsInstructionRAMAddress(const Core::CPUThreadGuard& guard, u32 address,
RequestedAddressSpace space)
{ {
// Instructions are always 32bit aligned. // Instructions are always 32bit aligned.
if (address & 3) if (address & 3)

View File

@ -10,6 +10,11 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
namespace Core
{
class CPUThreadGuard;
};
namespace PowerPC namespace PowerPC
{ {
// Routines for debugger UI, cheats, etc. to access emulated memory from the // Routines for debugger UI, cheats, etc. to access emulated memory from the
@ -27,14 +32,14 @@ enum class RequestedAddressSpace
// If the read fails (eg. address does not correspond to a mapped address in the current address // If the read fails (eg. address does not correspond to a mapped address in the current address
// space), a PanicAlert will be shown to the user and zero (or an empty string for the string case) // space), a PanicAlert will be shown to the user and zero (or an empty string for the string case)
// will be returned. // will be returned.
u8 HostRead_U8(u32 address); u8 HostRead_U8(const Core::CPUThreadGuard& guard, u32 address);
u16 HostRead_U16(u32 address); u16 HostRead_U16(const Core::CPUThreadGuard& guard, u32 address);
u32 HostRead_U32(u32 address); u32 HostRead_U32(const Core::CPUThreadGuard& guard, u32 address);
u64 HostRead_U64(u32 address); u64 HostRead_U64(const Core::CPUThreadGuard& guard, u32 address);
float HostRead_F32(u32 address); float HostRead_F32(const Core::CPUThreadGuard& guard, u32 address);
double HostRead_F64(u32 address); double HostRead_F64(const Core::CPUThreadGuard& guard, u32 address);
u32 HostRead_Instruction(u32 address); u32 HostRead_Instruction(const Core::CPUThreadGuard& guard, u32 address);
std::string HostGetString(u32 address, size_t size = 0); std::string HostGetString(const Core::CPUThreadGuard& guard, u32 address, size_t size = 0);
template <typename T> template <typename T>
struct ReadResult struct ReadResult
@ -57,32 +62,39 @@ struct ReadResult
// value and information on whether the given address had to be translated or not. Unlike the // value and information on whether the given address had to be translated or not. Unlike the
// HostRead functions, this does not raise a user-visible alert on failure. // HostRead functions, this does not raise a user-visible alert on failure.
std::optional<ReadResult<u8>> std::optional<ReadResult<u8>>
HostTryReadU8(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); HostTryReadU8(const Core::CPUThreadGuard& guard, u32 address,
RequestedAddressSpace space = RequestedAddressSpace::Effective);
std::optional<ReadResult<u16>> std::optional<ReadResult<u16>>
HostTryReadU16(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); HostTryReadU16(const Core::CPUThreadGuard& guard, u32 address,
RequestedAddressSpace space = RequestedAddressSpace::Effective);
std::optional<ReadResult<u32>> std::optional<ReadResult<u32>>
HostTryReadU32(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); HostTryReadU32(const Core::CPUThreadGuard& guard, u32 address,
RequestedAddressSpace space = RequestedAddressSpace::Effective);
std::optional<ReadResult<u64>> std::optional<ReadResult<u64>>
HostTryReadU64(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); HostTryReadU64(const Core::CPUThreadGuard& guard, u32 address,
RequestedAddressSpace space = RequestedAddressSpace::Effective);
std::optional<ReadResult<float>> std::optional<ReadResult<float>>
HostTryReadF32(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); HostTryReadF32(const Core::CPUThreadGuard& guard, u32 address,
RequestedAddressSpace space = RequestedAddressSpace::Effective);
std::optional<ReadResult<double>> std::optional<ReadResult<double>>
HostTryReadF64(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); HostTryReadF64(const Core::CPUThreadGuard& guard, u32 address,
RequestedAddressSpace space = RequestedAddressSpace::Effective);
std::optional<ReadResult<u32>> std::optional<ReadResult<u32>>
HostTryReadInstruction(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); HostTryReadInstruction(const Core::CPUThreadGuard& guard, u32 address,
RequestedAddressSpace space = RequestedAddressSpace::Effective);
std::optional<ReadResult<std::string>> std::optional<ReadResult<std::string>>
HostTryReadString(u32 address, size_t size = 0, HostTryReadString(const Core::CPUThreadGuard& guard, u32 address, size_t size = 0,
RequestedAddressSpace space = RequestedAddressSpace::Effective); RequestedAddressSpace space = RequestedAddressSpace::Effective);
// Writes a value to emulated memory using the currently active MMU settings. // Writes a value to emulated memory using the currently active MMU settings.
// If the write fails (eg. address does not correspond to a mapped address in the current address // If the write fails (eg. address does not correspond to a mapped address in the current address
// space), a PanicAlert will be shown to the user. // space), a PanicAlert will be shown to the user.
void HostWrite_U8(u32 var, u32 address); void HostWrite_U8(const Core::CPUThreadGuard& guard, u32 var, u32 address);
void HostWrite_U16(u32 var, u32 address); void HostWrite_U16(const Core::CPUThreadGuard& guard, u32 var, u32 address);
void HostWrite_U32(u32 var, u32 address); void HostWrite_U32(const Core::CPUThreadGuard& guard, u32 var, u32 address);
void HostWrite_U64(u64 var, u32 address); void HostWrite_U64(const Core::CPUThreadGuard& guard, u64 var, u32 address);
void HostWrite_F32(float var, u32 address); void HostWrite_F32(const Core::CPUThreadGuard& guard, float var, u32 address);
void HostWrite_F64(double var, u32 address); void HostWrite_F64(const Core::CPUThreadGuard& guard, double var, u32 address);
struct WriteResult struct WriteResult
{ {
@ -98,30 +110,31 @@ struct WriteResult
// address had to be translated or not. Unlike the HostWrite functions, this does not raise a // address had to be translated or not. Unlike the HostWrite functions, this does not raise a
// user-visible alert on failure. // user-visible alert on failure.
std::optional<WriteResult> std::optional<WriteResult>
HostTryWriteU8(u32 var, const u32 address, HostTryWriteU8(const Core::CPUThreadGuard& guard, u32 var, const u32 address,
RequestedAddressSpace space = RequestedAddressSpace::Effective); RequestedAddressSpace space = RequestedAddressSpace::Effective);
std::optional<WriteResult> std::optional<WriteResult>
HostTryWriteU16(u32 var, const u32 address, HostTryWriteU16(const Core::CPUThreadGuard& guard, u32 var, const u32 address,
RequestedAddressSpace space = RequestedAddressSpace::Effective); RequestedAddressSpace space = RequestedAddressSpace::Effective);
std::optional<WriteResult> std::optional<WriteResult>
HostTryWriteU32(u32 var, const u32 address, HostTryWriteU32(const Core::CPUThreadGuard& guard, u32 var, const u32 address,
RequestedAddressSpace space = RequestedAddressSpace::Effective); RequestedAddressSpace space = RequestedAddressSpace::Effective);
std::optional<WriteResult> std::optional<WriteResult>
HostTryWriteU64(u64 var, const u32 address, HostTryWriteU64(const Core::CPUThreadGuard& guard, u64 var, const u32 address,
RequestedAddressSpace space = RequestedAddressSpace::Effective); RequestedAddressSpace space = RequestedAddressSpace::Effective);
std::optional<WriteResult> std::optional<WriteResult>
HostTryWriteF32(float var, const u32 address, HostTryWriteF32(const Core::CPUThreadGuard& guard, float var, const u32 address,
RequestedAddressSpace space = RequestedAddressSpace::Effective); RequestedAddressSpace space = RequestedAddressSpace::Effective);
std::optional<WriteResult> std::optional<WriteResult>
HostTryWriteF64(double var, const u32 address, HostTryWriteF64(const Core::CPUThreadGuard& guard, double var, const u32 address,
RequestedAddressSpace space = RequestedAddressSpace::Effective); RequestedAddressSpace space = RequestedAddressSpace::Effective);
// Returns whether a read or write to the given address will resolve to a RAM access in the given // Returns whether a read or write to the given address will resolve to a RAM access in the given
// address space. // address space.
bool HostIsRAMAddress(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); bool HostIsRAMAddress(const Core::CPUThreadGuard& guard, u32 address,
RequestedAddressSpace space = RequestedAddressSpace::Effective);
// Same as HostIsRAMAddress, but uses IBAT instead of DBAT. // Same as HostIsRAMAddress, but uses IBAT instead of DBAT.
bool HostIsInstructionRAMAddress(u32 address, bool HostIsInstructionRAMAddress(const Core::CPUThreadGuard& guard, u32 address,
RequestedAddressSpace space = RequestedAddressSpace::Effective); RequestedAddressSpace space = RequestedAddressSpace::Effective);
// Routines for the CPU core to access memory. // Routines for the CPU core to access memory.

View File

@ -74,7 +74,8 @@ static u32 EvaluateBranchTarget(UGeckoInstruction instr, u32 pc)
// Also collect which internal branch goes the farthest. // Also collect which internal branch goes the farthest.
// If any one goes farther than the blr or rfi, assume that there is more than // If any one goes farther than the blr or rfi, assume that there is more than
// one blr or rfi, and keep scanning. // one blr or rfi, and keep scanning.
bool AnalyzeFunction(u32 startAddr, Common::Symbol& func, u32 max_size) bool AnalyzeFunction(const Core::CPUThreadGuard& guard, u32 startAddr, Common::Symbol& func,
u32 max_size)
{ {
if (func.name.empty()) if (func.name.empty())
func.Rename(fmt::format("zz_{:08x}_", startAddr)); func.Rename(fmt::format("zz_{:08x}_", startAddr));
@ -91,15 +92,18 @@ bool AnalyzeFunction(u32 startAddr, Common::Symbol& func, u32 max_size)
for (u32 addr = startAddr; true; addr += 4) for (u32 addr = startAddr; true; addr += 4)
{ {
func.size += 4; func.size += 4;
if (func.size >= JitBase::code_buffer_size * 4 || !PowerPC::HostIsInstructionRAMAddress(addr)) if (func.size >= JitBase::code_buffer_size * 4 ||
!PowerPC::HostIsInstructionRAMAddress(guard, addr))
{
return false; return false;
}
if (max_size && func.size > max_size) if (max_size && func.size > max_size)
{ {
func.address = startAddr; func.address = startAddr;
func.analyzed = true; func.analyzed = true;
func.size -= 4; func.size -= 4;
func.hash = HashSignatureDB::ComputeCodeChecksum(startAddr, addr - 4); func.hash = HashSignatureDB::ComputeCodeChecksum(guard, startAddr, addr - 4);
if (numInternalBranches == 0) if (numInternalBranches == 0)
func.flags |= Common::FFLAG_STRAIGHT; func.flags |= Common::FFLAG_STRAIGHT;
return true; return true;
@ -121,7 +125,7 @@ bool AnalyzeFunction(u32 startAddr, Common::Symbol& func, u32 max_size)
// Let's calc the checksum and get outta here // Let's calc the checksum and get outta here
func.address = startAddr; func.address = startAddr;
func.analyzed = true; func.analyzed = true;
func.hash = HashSignatureDB::ComputeCodeChecksum(startAddr, addr); func.hash = HashSignatureDB::ComputeCodeChecksum(guard, startAddr, addr);
if (numInternalBranches == 0) if (numInternalBranches == 0)
func.flags |= Common::FFLAG_STRAIGHT; func.flags |= Common::FFLAG_STRAIGHT;
return true; return true;
@ -167,12 +171,13 @@ bool AnalyzeFunction(u32 startAddr, Common::Symbol& func, u32 max_size)
} }
} }
bool ReanalyzeFunction(u32 start_addr, Common::Symbol& func, u32 max_size) bool ReanalyzeFunction(const Core::CPUThreadGuard& guard, u32 start_addr, Common::Symbol& func,
u32 max_size)
{ {
ASSERT_MSG(SYMBOLS, func.analyzed, "The function wasn't previously analyzed!"); ASSERT_MSG(SYMBOLS, func.analyzed, "The function wasn't previously analyzed!");
func.analyzed = false; func.analyzed = false;
return AnalyzeFunction(start_addr, func, max_size); return AnalyzeFunction(guard, start_addr, func, max_size);
} }
// Second pass analysis, done after the first pass is done for all functions // Second pass analysis, done after the first pass is done for all functions
@ -256,7 +261,8 @@ bool PPCAnalyzer::CanSwapAdjacentOps(const CodeOp& a, const CodeOp& b) const
// called by another function. Therefore, let's scan the // called by another function. Therefore, let's scan the
// entire space for bl operations and find what functions // entire space for bl operations and find what functions
// get called. // get called.
static void FindFunctionsFromBranches(u32 startAddr, u32 endAddr, Common::SymbolDB* func_db) static void FindFunctionsFromBranches(const Core::CPUThreadGuard& guard, u32 startAddr, u32 endAddr,
Common::SymbolDB* func_db)
{ {
for (u32 addr = startAddr; addr < endAddr; addr += 4) for (u32 addr = startAddr; addr < endAddr; addr += 4)
{ {
@ -274,9 +280,9 @@ static void FindFunctionsFromBranches(u32 startAddr, u32 endAddr, Common::Symbol
u32 target = SignExt26(instr.LI << 2); u32 target = SignExt26(instr.LI << 2);
if (!instr.AA) if (!instr.AA)
target += addr; target += addr;
if (PowerPC::HostIsRAMAddress(target)) if (PowerPC::HostIsRAMAddress(guard, target))
{ {
func_db->AddFunction(target); func_db->AddFunction(guard, target);
} }
} }
} }
@ -288,7 +294,7 @@ static void FindFunctionsFromBranches(u32 startAddr, u32 endAddr, Common::Symbol
} }
} }
static void FindFunctionsFromHandlers(PPCSymbolDB* func_db) static void FindFunctionsFromHandlers(const Core::CPUThreadGuard& guard, PPCSymbolDB* func_db)
{ {
static const std::map<u32, const char* const> handlers = { static const std::map<u32, const char* const> handlers = {
{0x80000100, "system_reset_exception_handler"}, {0x80000100, "system_reset_exception_handler"},
@ -314,7 +320,7 @@ static void FindFunctionsFromHandlers(PPCSymbolDB* func_db)
if (read_result.valid && PPCTables::IsValidInstruction(read_result.hex)) if (read_result.valid && PPCTables::IsValidInstruction(read_result.hex))
{ {
// Check if this function is already mapped // Check if this function is already mapped
Common::Symbol* f = func_db->AddFunction(entry.first); Common::Symbol* f = func_db->AddFunction(guard, entry.first);
if (!f) if (!f)
continue; continue;
f->Rename(entry.second); f->Rename(entry.second);
@ -322,7 +328,8 @@ static void FindFunctionsFromHandlers(PPCSymbolDB* func_db)
} }
} }
static void FindFunctionsAfterReturnInstruction(PPCSymbolDB* func_db) static void FindFunctionsAfterReturnInstruction(const Core::CPUThreadGuard& guard,
PPCSymbolDB* func_db)
{ {
std::vector<u32> funcAddrs; std::vector<u32> funcAddrs;
@ -346,7 +353,7 @@ static void FindFunctionsAfterReturnInstruction(PPCSymbolDB* func_db)
if (read_result.valid && PPCTables::IsValidInstruction(read_result.hex)) if (read_result.valid && PPCTables::IsValidInstruction(read_result.hex))
{ {
// check if this function is already mapped // check if this function is already mapped
Common::Symbol* f = func_db->AddFunction(location); Common::Symbol* f = func_db->AddFunction(guard, location);
if (!f) if (!f)
break; break;
else else
@ -358,12 +365,13 @@ static void FindFunctionsAfterReturnInstruction(PPCSymbolDB* func_db)
} }
} }
void FindFunctions(u32 startAddr, u32 endAddr, PPCSymbolDB* func_db) void FindFunctions(const Core::CPUThreadGuard& guard, u32 startAddr, u32 endAddr,
PPCSymbolDB* func_db)
{ {
// Step 1: Find all functions // Step 1: Find all functions
FindFunctionsFromBranches(startAddr, endAddr, func_db); FindFunctionsFromBranches(guard, startAddr, endAddr, func_db);
FindFunctionsFromHandlers(func_db); FindFunctionsFromHandlers(guard, func_db);
FindFunctionsAfterReturnInstruction(func_db); FindFunctionsAfterReturnInstruction(guard, func_db);
// Step 2: // Step 2:
func_db->FillInCallers(); func_db->FillInCallers();

View File

@ -19,6 +19,11 @@ namespace Common
struct Symbol; struct Symbol;
} }
namespace Core
{
class CPUThreadGuard;
}
namespace PPCAnalyst namespace PPCAnalyst
{ {
struct CodeOp // 16B struct CodeOp // 16B
@ -201,8 +206,11 @@ private:
bool m_enable_div_by_zero_exceptions = false; bool m_enable_div_by_zero_exceptions = false;
}; };
void FindFunctions(u32 startAddr, u32 endAddr, PPCSymbolDB* func_db); void FindFunctions(const Core::CPUThreadGuard& guard, u32 startAddr, u32 endAddr,
bool AnalyzeFunction(u32 startAddr, Common::Symbol& func, u32 max_size = 0); PPCSymbolDB* func_db);
bool ReanalyzeFunction(u32 start_addr, Common::Symbol& func, u32 max_size = 0); bool AnalyzeFunction(const Core::CPUThreadGuard& guard, u32 startAddr, Common::Symbol& func,
u32 max_size = 0);
bool ReanalyzeFunction(const Core::CPUThreadGuard& guard, u32 start_addr, Common::Symbol& func,
u32 max_size = 0);
} // namespace PPCAnalyst } // namespace PPCAnalyst

View File

@ -32,14 +32,14 @@ PPCSymbolDB::PPCSymbolDB() : debugger{&PowerPC::debug_interface}
PPCSymbolDB::~PPCSymbolDB() = default; PPCSymbolDB::~PPCSymbolDB() = default;
// Adds the function to the list, unless it's already there // Adds the function to the list, unless it's already there
Common::Symbol* PPCSymbolDB::AddFunction(u32 start_addr) Common::Symbol* PPCSymbolDB::AddFunction(const Core::CPUThreadGuard& guard, u32 start_addr)
{ {
// It's already in the list // It's already in the list
if (m_functions.find(start_addr) != m_functions.end()) if (m_functions.find(start_addr) != m_functions.end())
return nullptr; return nullptr;
Common::Symbol symbol; Common::Symbol symbol;
if (!PPCAnalyst::AnalyzeFunction(start_addr, symbol)) if (!PPCAnalyst::AnalyzeFunction(guard, start_addr, symbol))
return nullptr; return nullptr;
m_functions[start_addr] = std::move(symbol); m_functions[start_addr] = std::move(symbol);
@ -49,8 +49,8 @@ Common::Symbol* PPCSymbolDB::AddFunction(u32 start_addr)
return ptr; return ptr;
} }
void PPCSymbolDB::AddKnownSymbol(u32 startAddr, u32 size, const std::string& name, void PPCSymbolDB::AddKnownSymbol(const Core::CPUThreadGuard& guard, u32 startAddr, u32 size,
Common::Symbol::Type type) const std::string& name, Common::Symbol::Type type)
{ {
auto iter = m_functions.find(startAddr); auto iter = m_functions.find(startAddr);
if (iter != m_functions.end()) if (iter != m_functions.end())
@ -58,7 +58,7 @@ void PPCSymbolDB::AddKnownSymbol(u32 startAddr, u32 size, const std::string& nam
// already got it, let's just update name, checksum & size to be sure. // already got it, let's just update name, checksum & size to be sure.
Common::Symbol* tempfunc = &iter->second; Common::Symbol* tempfunc = &iter->second;
tempfunc->Rename(name); tempfunc->Rename(name);
tempfunc->hash = HashSignatureDB::ComputeCodeChecksum(startAddr, startAddr + size - 4); tempfunc->hash = HashSignatureDB::ComputeCodeChecksum(guard, startAddr, startAddr + size - 4);
tempfunc->type = type; tempfunc->type = type;
tempfunc->size = size; tempfunc->size = size;
} }
@ -71,7 +71,7 @@ void PPCSymbolDB::AddKnownSymbol(u32 startAddr, u32 size, const std::string& nam
tf.address = startAddr; tf.address = startAddr;
if (tf.type == Common::Symbol::Type::Function) if (tf.type == Common::Symbol::Type::Function)
{ {
PPCAnalyst::AnalyzeFunction(startAddr, tf, size); PPCAnalyst::AnalyzeFunction(guard, startAddr, tf, size);
// Do not truncate symbol when a size is expected // Do not truncate symbol when a size is expected
if (size != 0 && tf.size != size) if (size != 0 && tf.size != size)
{ {
@ -224,7 +224,7 @@ void PPCSymbolDB::LogFunctionCall(u32 addr)
// This one can load both leftover map files on game discs (like Zelda), and mapfiles // This one can load both leftover map files on game discs (like Zelda), and mapfiles
// produced by SaveSymbolMap below. // produced by SaveSymbolMap below.
// bad=true means carefully load map files that might not be from exactly the right version // bad=true means carefully load map files that might not be from exactly the right version
bool PPCSymbolDB::LoadMap(const std::string& filename, bool bad) bool PPCSymbolDB::LoadMap(const Core::CPUThreadGuard& guard, const std::string& filename, bool bad)
{ {
File::IOFile f(filename, "r"); File::IOFile f(filename, "r");
if (!f) if (!f)
@ -407,8 +407,8 @@ bool PPCSymbolDB::LoadMap(const std::string& filename, bool bad)
if (strlen(name) > 0) if (strlen(name) > 0)
{ {
// Can't compute the checksum if not in RAM // Can't compute the checksum if not in RAM
bool good = !bad && PowerPC::HostIsInstructionRAMAddress(vaddress) && bool good = !bad && PowerPC::HostIsInstructionRAMAddress(guard, vaddress) &&
PowerPC::HostIsInstructionRAMAddress(vaddress + size - 4); PowerPC::HostIsInstructionRAMAddress(guard, vaddress + size - 4);
if (!good) if (!good)
{ {
// check for BLR before function // check for BLR before function
@ -423,10 +423,10 @@ bool PPCSymbolDB::LoadMap(const std::string& filename, bool bad)
if (good) if (good)
{ {
++good_count; ++good_count;
if (section_name == ".text" || section_name == ".init") const Common::Symbol::Type type = section_name == ".text" || section_name == ".init" ?
AddKnownSymbol(vaddress, size, name, Common::Symbol::Type::Function); Common::Symbol::Type::Function :
else Common::Symbol::Type::Data;
AddKnownSymbol(vaddress, size, name, Common::Symbol::Type::Data); AddKnownSymbol(guard, vaddress, size, name, type);
} }
else else
{ {
@ -485,7 +485,7 @@ bool PPCSymbolDB::SaveSymbolMap(const std::string& filename) const
// Notes: // Notes:
// - Dolphin doesn't load back code maps // - Dolphin doesn't load back code maps
// - It's a custom code map format // - It's a custom code map format
bool PPCSymbolDB::SaveCodeMap(const std::string& filename) const bool PPCSymbolDB::SaveCodeMap(const Core::CPUThreadGuard& guard, const std::string& filename) const
{ {
constexpr int SYMBOL_NAME_LIMIT = 30; constexpr int SYMBOL_NAME_LIMIT = 30;
File::IOFile f(filename, "w"); File::IOFile f(filename, "w");
@ -515,7 +515,7 @@ bool PPCSymbolDB::SaveCodeMap(const std::string& filename) const
// Write the code // Write the code
for (u32 address = symbol.address; address < next_address; address += 4) for (u32 address = symbol.address; address < next_address; address += 4)
{ {
const std::string disasm = debugger->Disassemble(address); const std::string disasm = debugger->Disassemble(&guard, address);
f.WriteString(fmt::format("{0:08x} {1:<{2}.{3}} {4}\n", address, symbol.name, f.WriteString(fmt::format("{0:08x} {1:<{2}.{3}} {4}\n", address, symbol.name,
SYMBOL_NAME_LIMIT, SYMBOL_NAME_LIMIT, disasm)); SYMBOL_NAME_LIMIT, SYMBOL_NAME_LIMIT, disasm));
} }

View File

@ -12,6 +12,11 @@
#include "Core/Debugger/PPCDebugInterface.h" #include "Core/Debugger/PPCDebugInterface.h"
namespace Core
{
class CPUThreadGuard;
}
// This has functionality overlapping Debugger_Symbolmap. Should merge that stuff in here later. // This has functionality overlapping Debugger_Symbolmap. Should merge that stuff in here later.
class PPCSymbolDB : public Common::SymbolDB class PPCSymbolDB : public Common::SymbolDB
{ {
@ -19,8 +24,9 @@ public:
PPCSymbolDB(); PPCSymbolDB();
~PPCSymbolDB() override; ~PPCSymbolDB() override;
Common::Symbol* AddFunction(u32 start_addr) override; Common::Symbol* AddFunction(const Core::CPUThreadGuard& guard, u32 start_addr) override;
void AddKnownSymbol(u32 startAddr, u32 size, const std::string& name, void AddKnownSymbol(const Core::CPUThreadGuard& guard, u32 startAddr, u32 size,
const std::string& name,
Common::Symbol::Type type = Common::Symbol::Type::Function); Common::Symbol::Type type = Common::Symbol::Type::Function);
Common::Symbol* GetSymbolFromAddr(u32 addr) override; Common::Symbol* GetSymbolFromAddr(u32 addr) override;
@ -29,9 +35,9 @@ public:
void FillInCallers(); void FillInCallers();
bool LoadMap(const std::string& filename, bool bad = false); bool LoadMap(const Core::CPUThreadGuard& guard, const std::string& filename, bool bad = false);
bool SaveSymbolMap(const std::string& filename) const; bool SaveSymbolMap(const std::string& filename) const;
bool SaveCodeMap(const std::string& filename) const; bool SaveCodeMap(const Core::CPUThreadGuard& guard, const std::string& filename) const;
void PrintCalls(u32 funcAddr) const; void PrintCalls(u32 funcAddr) const;
void PrintCallers(u32 funcAddr) const; void PrintCallers(u32 funcAddr) const;

View File

@ -101,7 +101,7 @@ bool GetRefs(MEGASignature* sig, std::istringstream* iss)
return true; return true;
} }
bool Compare(u32 address, u32 size, const MEGASignature& sig) bool Compare(const Core::CPUThreadGuard& guard, u32 address, u32 size, const MEGASignature& sig)
{ {
if (size != sig.code.size() * sizeof(u32)) if (size != sig.code.size() * sizeof(u32))
return false; return false;
@ -109,8 +109,10 @@ bool Compare(u32 address, u32 size, const MEGASignature& sig)
for (size_t i = 0; i < sig.code.size(); ++i) for (size_t i = 0; i < sig.code.size(); ++i)
{ {
if (sig.code[i] != 0 && if (sig.code[i] != 0 &&
PowerPC::HostRead_U32(static_cast<u32>(address + i * sizeof(u32))) != sig.code[i]) PowerPC::HostRead_U32(guard, static_cast<u32>(address + i * sizeof(u32))) != sig.code[i])
{
return false; return false;
}
} }
return true; return true;
} }
@ -156,14 +158,14 @@ bool MEGASignatureDB::Save(const std::string& file_path) const
return false; return false;
} }
void MEGASignatureDB::Apply(PPCSymbolDB* symbol_db) const void MEGASignatureDB::Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* symbol_db) const
{ {
for (auto& it : symbol_db->AccessSymbols()) for (auto& it : symbol_db->AccessSymbols())
{ {
auto& symbol = it.second; auto& symbol = it.second;
for (const auto& sig : m_signatures) for (const auto& sig : m_signatures)
{ {
if (Compare(symbol.address, symbol.size, sig)) if (Compare(guard, symbol.address, symbol.size, sig))
{ {
symbol.name = sig.name; symbol.name = sig.name;
INFO_LOG_FMT(SYMBOLS, "Found {} at {:08x} (size: {:08x})!", sig.name, symbol.address, INFO_LOG_FMT(SYMBOLS, "Found {} at {:08x} (size: {:08x})!", sig.name, symbol.address,
@ -180,7 +182,8 @@ void MEGASignatureDB::Populate(const PPCSymbolDB* func_db, const std::string& fi
ERROR_LOG_FMT(SYMBOLS, "MEGA database can't be populated yet."); ERROR_LOG_FMT(SYMBOLS, "MEGA database can't be populated yet.");
} }
bool MEGASignatureDB::Add(u32 startAddr, u32 size, const std::string& name) bool MEGASignatureDB::Add(const Core::CPUThreadGuard& guard, u32 startAddr, u32 size,
const std::string& name)
{ {
ERROR_LOG_FMT(SYMBOLS, "Can't add symbol to MEGA database yet."); ERROR_LOG_FMT(SYMBOLS, "Can't add symbol to MEGA database yet.");
return false; return false;

View File

@ -9,6 +9,11 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Core/PowerPC/SignatureDB/SignatureDB.h" #include "Core/PowerPC/SignatureDB/SignatureDB.h"
namespace Core
{
class CPUThreadGuard;
}
class PPCSymbolDB; class PPCSymbolDB;
struct MEGASignatureReference struct MEGASignatureReference
@ -46,10 +51,11 @@ public:
bool Save(const std::string& file_path) const override; bool Save(const std::string& file_path) const override;
void List() const override; void List() const override;
void Apply(PPCSymbolDB* symbol_db) const override; void Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* symbol_db) const override;
void Populate(const PPCSymbolDB* func_db, const std::string& filter = "") override; void Populate(const PPCSymbolDB* func_db, const std::string& filter = "") override;
bool Add(u32 startAddr, u32 size, const std::string& name) override; bool Add(const Core::CPUThreadGuard& guard, u32 startAddr, u32 size,
const std::string& name) override;
private: private:
std::vector<MEGASignature> m_signatures; std::vector<MEGASignature> m_signatures;

View File

@ -76,20 +76,22 @@ void SignatureDB::Populate(const PPCSymbolDB* func_db, const std::string& filter
m_handler->Populate(func_db, filter); m_handler->Populate(func_db, filter);
} }
void SignatureDB::Apply(PPCSymbolDB* func_db) const void SignatureDB::Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* func_db) const
{ {
m_handler->Apply(func_db); m_handler->Apply(guard, func_db);
} }
bool SignatureDB::Add(u32 start_addr, u32 size, const std::string& name) bool SignatureDB::Add(const Core::CPUThreadGuard& guard, u32 start_addr, u32 size,
const std::string& name)
{ {
return m_handler->Add(start_addr, size, name); return m_handler->Add(guard, start_addr, size, name);
} }
// Adds a known function to the hash database // Adds a known function to the hash database
bool HashSignatureDB::Add(u32 startAddr, u32 size, const std::string& name) bool HashSignatureDB::Add(const Core::CPUThreadGuard& guard, u32 startAddr, u32 size,
const std::string& name)
{ {
u32 hash = ComputeCodeChecksum(startAddr, startAddr + size - 4); u32 hash = ComputeCodeChecksum(guard, startAddr, startAddr + size - 4);
DBFunc temp_dbfunc; DBFunc temp_dbfunc;
temp_dbfunc.size = size; temp_dbfunc.size = size;
@ -119,7 +121,7 @@ void HashSignatureDB::Clear()
m_database.clear(); m_database.clear();
} }
void HashSignatureDB::Apply(PPCSymbolDB* symbol_db) const void HashSignatureDB::Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* symbol_db) const
{ {
for (const auto& entry : m_database) for (const auto& entry : m_database)
{ {
@ -158,12 +160,13 @@ void HashSignatureDB::Populate(const PPCSymbolDB* symbol_db, const std::string&
} }
} }
u32 HashSignatureDB::ComputeCodeChecksum(u32 offsetStart, u32 offsetEnd) u32 HashSignatureDB::ComputeCodeChecksum(const Core::CPUThreadGuard& guard, u32 offsetStart,
u32 offsetEnd)
{ {
u32 sum = 0; u32 sum = 0;
for (u32 offset = offsetStart; offset <= offsetEnd; offset += 4) for (u32 offset = offsetStart; offset <= offsetEnd; offset += 4)
{ {
u32 opcode = PowerPC::HostRead_Instruction(offset); u32 opcode = PowerPC::HostRead_Instruction(guard, offset);
u32 op = opcode & 0xFC000000; u32 op = opcode & 0xFC000000;
u32 op2 = 0; u32 op2 = 0;
u32 op3 = 0; u32 op3 = 0;

View File

@ -11,6 +11,11 @@
// You're not meant to keep around SignatureDB objects persistently. Use 'em, throw them away. // You're not meant to keep around SignatureDB objects persistently. Use 'em, throw them away.
namespace Core
{
class CPUThreadGuard;
}
class PPCSymbolDB; class PPCSymbolDB;
class SignatureDBFormatHandler; class SignatureDBFormatHandler;
@ -33,9 +38,9 @@ public:
void List() const; void List() const;
void Populate(const PPCSymbolDB* func_db, const std::string& filter = ""); void Populate(const PPCSymbolDB* func_db, const std::string& filter = "");
void Apply(PPCSymbolDB* func_db) const; void Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* func_db) const;
bool Add(u32 start_addr, u32 size, const std::string& name); bool Add(const Core::CPUThreadGuard& guard, u32 start_addr, u32 size, const std::string& name);
private: private:
std::unique_ptr<SignatureDBFormatHandler> m_handler; std::unique_ptr<SignatureDBFormatHandler> m_handler;
@ -52,9 +57,10 @@ public:
virtual void List() const = 0; virtual void List() const = 0;
virtual void Populate(const PPCSymbolDB* func_db, const std::string& filter = "") = 0; virtual void Populate(const PPCSymbolDB* func_db, const std::string& filter = "") = 0;
virtual void Apply(PPCSymbolDB* func_db) const = 0; virtual void Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* func_db) const = 0;
virtual bool Add(u32 startAddr, u32 size, const std::string& name) = 0; virtual bool Add(const Core::CPUThreadGuard& guard, u32 startAddr, u32 size,
const std::string& name) = 0;
}; };
class HashSignatureDB : public SignatureDBFormatHandler class HashSignatureDB : public SignatureDBFormatHandler
@ -69,15 +75,16 @@ public:
}; };
using FuncDB = std::map<u32, DBFunc>; using FuncDB = std::map<u32, DBFunc>;
static u32 ComputeCodeChecksum(u32 offsetStart, u32 offsetEnd); static u32 ComputeCodeChecksum(const Core::CPUThreadGuard& guard, u32 offsetStart, u32 offsetEnd);
void Clear() override; void Clear() override;
void List() const override; void List() const override;
void Populate(const PPCSymbolDB* func_db, const std::string& filter = "") override; void Populate(const PPCSymbolDB* func_db, const std::string& filter = "") override;
void Apply(PPCSymbolDB* func_db) const override; void Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* func_db) const override;
bool Add(u32 startAddr, u32 size, const std::string& name) override; bool Add(const Core::CPUThreadGuard& guard, u32 startAddr, u32 size,
const std::string& name) override;
protected: protected:
// Map from signature to function. We store the DB in this map because it optimizes the // Map from signature to function. We store the DB in this map because it optimizes the

View File

@ -477,30 +477,31 @@ void ApplyPatchesToFiles(const std::vector<Patch>& patches, PatchIndex index,
} }
} }
static bool MemoryMatchesAt(u32 offset, const std::vector<u8>& value) static bool MemoryMatchesAt(const Core::CPUThreadGuard& guard, u32 offset,
const std::vector<u8>& value)
{ {
for (u32 i = 0; i < value.size(); ++i) for (u32 i = 0; i < value.size(); ++i)
{ {
auto result = PowerPC::HostTryReadU8(offset + i); auto result = PowerPC::HostTryReadU8(guard, offset + i);
if (!result || result->value != value[i]) if (!result || result->value != value[i])
return false; return false;
} }
return true; return true;
} }
static void ApplyMemoryPatch(u32 offset, const std::vector<u8>& value, static void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, u32 offset,
const std::vector<u8>& original) const std::vector<u8>& value, const std::vector<u8>& original)
{ {
if (value.empty()) if (value.empty())
return; return;
if (!original.empty() && !MemoryMatchesAt(offset, original)) if (!original.empty() && !MemoryMatchesAt(guard, offset, original))
return; return;
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
const u32 size = static_cast<u32>(value.size()); const u32 size = static_cast<u32>(value.size());
for (u32 i = 0; i < size; ++i) for (u32 i = 0; i < size; ++i)
PowerPC::HostTryWriteU8(value[i], offset + i); PowerPC::HostTryWriteU8(guard, value[i], offset + i);
const u32 overlapping_hook_count = HLE::UnpatchRange(system, offset, offset + size); const u32 overlapping_hook_count = HLE::UnpatchRange(system, offset, offset + size);
if (overlapping_hook_count != 0) if (overlapping_hook_count != 0)
{ {
@ -516,17 +517,18 @@ static std::vector<u8> GetMemoryPatchValue(const Patch& patch, const Memory& mem
return memory_patch.m_value; return memory_patch.m_value;
} }
static void ApplyMemoryPatch(const Patch& patch, const Memory& memory_patch) static void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, const Patch& patch,
const Memory& memory_patch)
{ {
if (memory_patch.m_offset == 0) if (memory_patch.m_offset == 0)
return; return;
ApplyMemoryPatch(memory_patch.m_offset | 0x80000000, GetMemoryPatchValue(patch, memory_patch), ApplyMemoryPatch(guard, memory_patch.m_offset | 0x80000000,
memory_patch.m_original); GetMemoryPatchValue(patch, memory_patch), memory_patch.m_original);
} }
static void ApplySearchMemoryPatch(const Patch& patch, const Memory& memory_patch, u32 ram_start, static void ApplySearchMemoryPatch(const Core::CPUThreadGuard& guard, const Patch& patch,
u32 length) const Memory& memory_patch, u32 ram_start, u32 length)
{ {
if (memory_patch.m_original.empty() || memory_patch.m_align == 0) if (memory_patch.m_original.empty() || memory_patch.m_align == 0)
return; return;
@ -535,16 +537,16 @@ static void ApplySearchMemoryPatch(const Patch& patch, const Memory& memory_patc
for (u32 i = 0; i < length - (stride - 1); i += stride) for (u32 i = 0; i < length - (stride - 1); i += stride)
{ {
const u32 address = ram_start + i; const u32 address = ram_start + i;
if (MemoryMatchesAt(address, memory_patch.m_original)) if (MemoryMatchesAt(guard, address, memory_patch.m_original))
{ {
ApplyMemoryPatch(address, GetMemoryPatchValue(patch, memory_patch), {}); ApplyMemoryPatch(guard, address, GetMemoryPatchValue(patch, memory_patch), {});
break; break;
} }
} }
} }
static void ApplyOcarinaMemoryPatch(const Patch& patch, const Memory& memory_patch, u32 ram_start, static void ApplyOcarinaMemoryPatch(const Core::CPUThreadGuard& guard, const Patch& patch,
u32 length) const Memory& memory_patch, u32 ram_start, u32 length)
{ {
if (memory_patch.m_offset == 0) if (memory_patch.m_offset == 0)
return; return;
@ -557,19 +559,19 @@ static void ApplyOcarinaMemoryPatch(const Patch& patch, const Memory& memory_pat
{ {
// first find the pattern // first find the pattern
const u32 address = ram_start + i; const u32 address = ram_start + i;
if (MemoryMatchesAt(address, value)) if (MemoryMatchesAt(guard, address, value))
{ {
for (; i < length; i += 4) for (; i < length; i += 4)
{ {
// from the pattern find the next blr instruction // from the pattern find the next blr instruction
const u32 blr_address = ram_start + i; const u32 blr_address = ram_start + i;
auto blr = PowerPC::HostTryReadU32(blr_address); auto blr = PowerPC::HostTryReadU32(guard, blr_address);
if (blr && blr->value == 0x4e800020) if (blr && blr->value == 0x4e800020)
{ {
// and replace it with a jump to the given offset // and replace it with a jump to the given offset
const u32 target = memory_patch.m_offset | 0x80000000; const u32 target = memory_patch.m_offset | 0x80000000;
const u32 jmp = ((target - blr_address) & 0x03fffffc) | 0x48000000; const u32 jmp = ((target - blr_address) & 0x03fffffc) | 0x48000000;
PowerPC::HostTryWriteU32(jmp, blr_address); PowerPC::HostTryWriteU32(guard, jmp, blr_address);
const u32 overlapping_hook_count = const u32 overlapping_hook_count =
HLE::UnpatchRange(system, blr_address, blr_address + 4); HLE::UnpatchRange(system, blr_address, blr_address + 4);
if (overlapping_hook_count != 0) if (overlapping_hook_count != 0)
@ -584,7 +586,7 @@ static void ApplyOcarinaMemoryPatch(const Patch& patch, const Memory& memory_pat
} }
} }
void ApplyGeneralMemoryPatches(const std::vector<Patch>& patches) void ApplyGeneralMemoryPatches(const Core::CPUThreadGuard& guard, const std::vector<Patch>& patches)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& system_memory = system.GetMemory(); auto& system_memory = system.GetMemory();
@ -597,14 +599,15 @@ void ApplyGeneralMemoryPatches(const std::vector<Patch>& patches)
continue; continue;
if (memory.m_search) if (memory.m_search)
ApplySearchMemoryPatch(patch, memory, 0x80000000, system_memory.GetRamSize()); ApplySearchMemoryPatch(guard, patch, memory, 0x80000000, system_memory.GetRamSize());
else else
ApplyMemoryPatch(patch, memory); ApplyMemoryPatch(guard, patch, memory);
} }
} }
} }
void ApplyApploaderMemoryPatches(const std::vector<Patch>& patches, u32 ram_address, u32 ram_length) void ApplyApploaderMemoryPatches(const Core::CPUThreadGuard& guard,
const std::vector<Patch>& patches, u32 ram_address, u32 ram_length)
{ {
for (const auto& patch : patches) for (const auto& patch : patches)
{ {
@ -614,9 +617,9 @@ void ApplyApploaderMemoryPatches(const std::vector<Patch>& patches, u32 ram_addr
continue; continue;
if (memory.m_ocarina) if (memory.m_ocarina)
ApplyOcarinaMemoryPatch(patch, memory, ram_address, ram_length); ApplyOcarinaMemoryPatch(guard, patch, memory, ram_address, ram_length);
else else
ApplySearchMemoryPatch(patch, memory, ram_address, ram_length); ApplySearchMemoryPatch(guard, patch, memory, ram_address, ram_length);
} }
} }
} }

View File

@ -11,6 +11,11 @@
#include "DiscIO/DirectoryBlob.h" #include "DiscIO/DirectoryBlob.h"
#include "DiscIO/RiivolutionParser.h" #include "DiscIO/RiivolutionParser.h"
namespace Core
{
class CPUThreadGuard;
}
namespace DiscIO::Riivolution namespace DiscIO::Riivolution
{ {
struct SavegameRedirect struct SavegameRedirect
@ -74,8 +79,10 @@ enum class PatchIndex
void ApplyPatchesToFiles(const std::vector<Patch>& patches, PatchIndex index, void ApplyPatchesToFiles(const std::vector<Patch>& patches, PatchIndex index,
std::vector<DiscIO::FSTBuilderNode>* fst, std::vector<DiscIO::FSTBuilderNode>* fst,
DiscIO::FSTBuilderNode* dol_node); DiscIO::FSTBuilderNode* dol_node);
void ApplyGeneralMemoryPatches(const std::vector<Patch>& patches); void ApplyGeneralMemoryPatches(const Core::CPUThreadGuard& guard,
void ApplyApploaderMemoryPatches(const std::vector<Patch>& patches, u32 ram_address, const std::vector<Patch>& patches);
void ApplyApploaderMemoryPatches(const Core::CPUThreadGuard& guard,
const std::vector<Patch>& patches, u32 ram_address,
u32 ram_length); u32 ram_length);
std::optional<SavegameRedirect> std::optional<SavegameRedirect>
ExtractSavegameRedirect(const std::vector<Patch>& riivolution_patches); ExtractSavegameRedirect(const std::vector<Patch>& riivolution_patches);

View File

@ -36,6 +36,7 @@
#include "Core/CheatGeneration.h" #include "Core/CheatGeneration.h"
#include "Core/CheatSearch.h" #include "Core/CheatSearch.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "DolphinQt/Config/CheatCodeEditor.h" #include "DolphinQt/Config/CheatCodeEditor.h"
@ -286,7 +287,11 @@ void CheatSearchWidget::OnNextScanClicked()
return; return;
} }
} }
Cheats::SearchErrorCode error_code = m_session->RunSearch();
const Cheats::SearchErrorCode error_code = [this] {
Core::CPUThreadGuard guard;
return m_session->RunSearch(guard);
}();
if (error_code == Cheats::SearchErrorCode::Success) if (error_code == Cheats::SearchErrorCode::Success)
{ {
@ -391,7 +396,13 @@ bool CheatSearchWidget::RefreshValues()
} }
tmp->SetFilterType(Cheats::FilterType::DoNotFilter); tmp->SetFilterType(Cheats::FilterType::DoNotFilter);
if (tmp->RunSearch() != Cheats::SearchErrorCode::Success)
const Cheats::SearchErrorCode error_code = [&tmp] {
Core::CPUThreadGuard guard;
return tmp->RunSearch(guard);
}();
if (error_code != Cheats::SearchErrorCode::Success)
{ {
m_info_label_1->setText(tr("Refresh failed. Please run the game for a bit and try again.")); m_info_label_1->setText(tr("Refresh failed. Please run the game for a bit and try again."));
return false; return false;

View File

@ -483,7 +483,11 @@ void CodeDiffDialog::OnSetBLR()
Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(item->data(Qt::UserRole).toUInt()); Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(item->data(Qt::UserRole).toUInt());
if (!symbol) if (!symbol)
return; return;
PowerPC::debug_interface.SetPatch(symbol->address, 0x4E800020);
{
Core::CPUThreadGuard guard;
PowerPC::debug_interface.SetPatch(guard, symbol->address, 0x4E800020);
}
int row = item->row(); int row = item->row();
m_matching_results_table->item(row, 0)->setForeground(QBrush(Qt::red)); m_matching_results_table->item(row, 0)->setForeground(QBrush(Qt::red));

View File

@ -175,14 +175,15 @@ CodeViewWidget::CodeViewWidget()
Update(); Update();
}); });
connect(&Settings::Instance(), &Settings::ThemeChanged, this, &CodeViewWidget::Update); connect(&Settings::Instance(), &Settings::ThemeChanged, this,
qOverload<>(&CodeViewWidget::Update));
} }
CodeViewWidget::~CodeViewWidget() = default; CodeViewWidget::~CodeViewWidget() = default;
static u32 GetBranchFromAddress(u32 addr) static u32 GetBranchFromAddress(const Core::CPUThreadGuard& guard, u32 addr)
{ {
std::string disasm = PowerPC::debug_interface.Disassemble(addr); std::string disasm = PowerPC::debug_interface.Disassemble(&guard, addr);
size_t pos = disasm.find("->0x"); size_t pos = disasm.find("->0x");
if (pos == std::string::npos) if (pos == std::string::npos)
@ -248,6 +249,26 @@ static bool IsInstructionLoadStore(std::string_view ins)
} }
void CodeViewWidget::Update() void CodeViewWidget::Update()
{
if (!isVisible())
return;
if (m_updating)
return;
if (Core::GetState() == Core::State::Paused)
{
Core::CPUThreadGuard guard;
Update(&guard);
}
else
{
// If the core is running, blank out the view of memory instead of reading anything.
Update(nullptr);
}
}
void CodeViewWidget::Update(const Core::CPUThreadGuard* guard)
{ {
if (!isVisible()) if (!isVisible())
return; return;
@ -284,11 +305,11 @@ void CodeViewWidget::Update()
for (int i = 0; i < rowCount(); i++) for (int i = 0; i < rowCount(); i++)
{ {
const u32 addr = AddressForRow(i); const u32 addr = AddressForRow(i);
const u32 color = PowerPC::debug_interface.GetColor(addr); const u32 color = PowerPC::debug_interface.GetColor(guard, addr);
auto* bp_item = new QTableWidgetItem; auto* bp_item = new QTableWidgetItem;
auto* addr_item = new QTableWidgetItem(QStringLiteral("%1").arg(addr, 8, 16, QLatin1Char('0'))); auto* addr_item = new QTableWidgetItem(QStringLiteral("%1").arg(addr, 8, 16, QLatin1Char('0')));
std::string disas = PowerPC::debug_interface.Disassemble(addr); std::string disas = PowerPC::debug_interface.Disassemble(guard, addr);
auto split = disas.find('\t'); auto split = disas.find('\t');
std::string ins = (split == std::string::npos ? disas : disas.substr(0, split)); std::string ins = (split == std::string::npos ? disas : disas.substr(0, split));
@ -332,9 +353,9 @@ void CodeViewWidget::Update()
hex_str = param.substr(pos); hex_str = param.substr(pos);
} }
if (hex_str.length() == VALID_BRANCH_LENGTH && desc != "---") if (guard && hex_str.length() == VALID_BRANCH_LENGTH && desc != "---")
{ {
u32 branch_addr = GetBranchFromAddress(addr); u32 branch_addr = GetBranchFromAddress(*guard, addr);
CodeViewBranch& branch = m_branches.emplace_back(); CodeViewBranch& branch = m_branches.emplace_back();
branch.src_addr = addr; branch.src_addr = addr;
branch.dst_addr = branch_addr; branch.dst_addr = branch_addr;
@ -514,15 +535,20 @@ void CodeViewWidget::SetAddress(u32 address, SetAddressUpdate update)
void CodeViewWidget::ReplaceAddress(u32 address, ReplaceWith replace) void CodeViewWidget::ReplaceAddress(u32 address, ReplaceWith replace)
{ {
PowerPC::debug_interface.SetPatch(address, replace == ReplaceWith::BLR ? 0x4e800020 : 0x60000000); Core::CPUThreadGuard guard;
Update();
PowerPC::debug_interface.SetPatch(guard, address,
replace == ReplaceWith::BLR ? 0x4e800020 : 0x60000000);
Update(&guard);
} }
void CodeViewWidget::OnContextMenu() void CodeViewWidget::OnContextMenu()
{ {
QMenu* menu = new QMenu(this); QMenu* menu = new QMenu(this);
bool running = Core::GetState() != Core::State::Uninitialized; const bool running = Core::GetState() != Core::State::Uninitialized;
const bool paused = Core::GetState() == Core::State::Paused;
const u32 addr = GetContextAddress(); const u32 addr = GetContextAddress();
@ -567,14 +593,25 @@ void CodeViewWidget::OnContextMenu()
menu->addAction(tr("Restore instruction"), this, &CodeViewWidget::OnRestoreInstruction); menu->addAction(tr("Restore instruction"), this, &CodeViewWidget::OnRestoreInstruction);
QString target; QString target;
if (addr == PowerPC::ppcState.pc && running && Core::GetState() == Core::State::Paused) bool valid_load_store = false;
bool follow_branch_enabled = false;
if (paused)
{ {
const std::string line = PowerPC::debug_interface.Disassemble(PowerPC::ppcState.pc); Core::CPUThreadGuard guard;
const auto target_it = std::find(line.begin(), line.end(), '\t'); const std::string disasm = PowerPC::debug_interface.Disassemble(&guard, PowerPC::ppcState.pc);
const auto target_end = std::find(target_it, line.end(), ',');
if (target_it != line.end() && target_end != line.end()) if (addr == PowerPC::ppcState.pc)
target = QString::fromStdString(std::string{target_it + 1, target_end}); {
const auto target_it = std::find(disasm.begin(), disasm.end(), '\t');
const auto target_end = std::find(target_it, disasm.end(), ',');
if (target_it != disasm.end() && target_end != disasm.end())
target = QString::fromStdString(std::string{target_it + 1, target_end});
}
valid_load_store = IsInstructionLoadStore(disasm);
follow_branch_enabled = GetBranchFromAddress(guard, addr);
} }
auto* run_until_menu = menu->addMenu(tr("Run until (ignoring breakpoints)")); auto* run_until_menu = menu->addMenu(tr("Run until (ignoring breakpoints)"));
@ -589,18 +626,17 @@ void CodeViewWidget::OnContextMenu()
[this] { AutoStep(CodeTrace::AutoStop::Changed); }); [this] { AutoStep(CodeTrace::AutoStop::Changed); });
run_until_menu->setEnabled(!target.isEmpty()); run_until_menu->setEnabled(!target.isEmpty());
follow_branch_action->setEnabled(running && GetBranchFromAddress(addr)); follow_branch_action->setEnabled(follow_branch_enabled);
for (auto* action : {copy_address_action, copy_line_action, copy_hex_action, function_action, for (auto* action : {copy_address_action, copy_line_action, copy_hex_action, function_action,
ppc_action, insert_blr_action, insert_nop_action, replace_action}) ppc_action, insert_blr_action, insert_nop_action, replace_action})
{
action->setEnabled(running); action->setEnabled(running);
}
for (auto* action : {symbol_rename_action, symbol_size_action, symbol_end_action}) for (auto* action : {symbol_rename_action, symbol_size_action, symbol_end_action})
action->setEnabled(has_symbol); action->setEnabled(has_symbol);
const bool valid_load_store = Core::GetState() == Core::State::Paused &&
IsInstructionLoadStore(PowerPC::debug_interface.Disassemble(addr));
for (auto* action : {copy_target_memory, show_target_memory}) for (auto* action : {copy_target_memory, show_target_memory})
{ {
action->setEnabled(valid_load_store); action->setEnabled(valid_load_store);
@ -617,6 +653,8 @@ void CodeViewWidget::AutoStep(CodeTrace::AutoStop option)
// Autosteps and follows value in the target (left-most) register. The Used and Changed options // Autosteps and follows value in the target (left-most) register. The Used and Changed options
// silently follows target through reshuffles in memory and registers and stops on use or update. // silently follows target through reshuffles in memory and registers and stops on use or update.
Core::CPUThreadGuard guard;
CodeTrace code_trace; CodeTrace code_trace;
bool repeat = false; bool repeat = false;
@ -628,7 +666,7 @@ void CodeViewWidget::AutoStep(CodeTrace::AutoStop option)
do do
{ {
// Run autostep then update codeview // Run autostep then update codeview
const AutoStepResults results = code_trace.AutoStepping(repeat, option); const AutoStepResults results = code_trace.AutoStepping(guard, repeat, option);
emit Host::GetInstance()->UpdateDisasmDialog(); emit Host::GetInstance()->UpdateDisasmDialog();
repeat = true; repeat = true;
@ -703,16 +741,24 @@ void CodeViewWidget::OnCopyTargetAddress()
if (Core::GetState() != Core::State::Paused) if (Core::GetState() != Core::State::Paused)
return; return;
const std::string code_line = PowerPC::debug_interface.Disassemble(GetContextAddress()); const u32 addr = GetContextAddress();
const std::string code_line = [addr] {
Core::CPUThreadGuard guard;
return PowerPC::debug_interface.Disassemble(&guard, addr);
}();
if (!IsInstructionLoadStore(code_line)) if (!IsInstructionLoadStore(code_line))
return; return;
const std::optional<u32> addr = const std::optional<u32> target_addr =
PowerPC::debug_interface.GetMemoryAddressFromInstruction(code_line); PowerPC::debug_interface.GetMemoryAddressFromInstruction(code_line);
if (addr) if (addr)
QApplication::clipboard()->setText(QStringLiteral("%1").arg(*addr, 8, 16, QLatin1Char('0'))); {
QApplication::clipboard()->setText(
QStringLiteral("%1").arg(*target_addr, 8, 16, QLatin1Char('0')));
}
} }
void CodeViewWidget::OnShowInMemory() void CodeViewWidget::OnShowInMemory()
@ -725,24 +771,33 @@ void CodeViewWidget::OnShowTargetInMemory()
if (Core::GetState() != Core::State::Paused) if (Core::GetState() != Core::State::Paused)
return; return;
const std::string code_line = PowerPC::debug_interface.Disassemble(GetContextAddress()); const u32 addr = GetContextAddress();
const std::string code_line = [addr] {
Core::CPUThreadGuard guard;
return PowerPC::debug_interface.Disassemble(&guard, addr);
}();
if (!IsInstructionLoadStore(code_line)) if (!IsInstructionLoadStore(code_line))
return; return;
const std::optional<u32> addr = const std::optional<u32> target_addr =
PowerPC::debug_interface.GetMemoryAddressFromInstruction(code_line); PowerPC::debug_interface.GetMemoryAddressFromInstruction(code_line);
if (addr) if (addr)
emit ShowMemory(*addr); emit ShowMemory(*target_addr);
} }
void CodeViewWidget::OnCopyCode() void CodeViewWidget::OnCopyCode()
{ {
const u32 addr = GetContextAddress(); const u32 addr = GetContextAddress();
QApplication::clipboard()->setText( const std::string text = [addr] {
QString::fromStdString(PowerPC::debug_interface.Disassemble(addr))); Core::CPUThreadGuard guard;
return PowerPC::debug_interface.Disassemble(&guard, addr);
}();
QApplication::clipboard()->setText(QString::fromStdString(text));
} }
void CodeViewWidget::OnCopyFunction() void CodeViewWidget::OnCopyFunction()
@ -754,13 +809,18 @@ void CodeViewWidget::OnCopyFunction()
return; return;
std::string text = symbol->name + "\r\n"; std::string text = symbol->name + "\r\n";
// we got a function
const u32 start = symbol->address;
const u32 end = start + symbol->size;
for (u32 addr = start; addr != end; addr += 4)
{ {
const std::string disasm = PowerPC::debug_interface.Disassemble(addr); Core::CPUThreadGuard guard;
fmt::format_to(std::back_inserter(text), "{:08x}: {}\r\n", addr, disasm);
// we got a function
const u32 start = symbol->address;
const u32 end = start + symbol->size;
for (u32 addr = start; addr != end; addr += 4)
{
const std::string disasm = PowerPC::debug_interface.Disassemble(&guard, addr);
fmt::format_to(std::back_inserter(text), "{:08x}: {}\r\n", addr, disasm);
}
} }
QApplication::clipboard()->setText(QString::fromStdString(text)); QApplication::clipboard()->setText(QString::fromStdString(text));
@ -769,7 +829,11 @@ void CodeViewWidget::OnCopyFunction()
void CodeViewWidget::OnCopyHex() void CodeViewWidget::OnCopyHex()
{ {
const u32 addr = GetContextAddress(); const u32 addr = GetContextAddress();
const u32 instruction = PowerPC::debug_interface.ReadInstruction(addr);
const u32 instruction = [addr] {
Core::CPUThreadGuard guard;
return PowerPC::debug_interface.ReadInstruction(guard, addr);
}();
QApplication::clipboard()->setText( QApplication::clipboard()->setText(
QStringLiteral("%1").arg(instruction, 8, 16, QLatin1Char('0'))); QStringLiteral("%1").arg(instruction, 8, 16, QLatin1Char('0')));
@ -795,9 +859,11 @@ void CodeViewWidget::OnAddFunction()
{ {
const u32 addr = GetContextAddress(); const u32 addr = GetContextAddress();
g_symbolDB.AddFunction(addr); Core::CPUThreadGuard guard;
g_symbolDB.AddFunction(guard, addr);
emit SymbolsChanged(); emit SymbolsChanged();
Update(); Update(&guard);
} }
void CodeViewWidget::OnInsertBLR() void CodeViewWidget::OnInsertBLR()
@ -818,7 +884,10 @@ void CodeViewWidget::OnFollowBranch()
{ {
const u32 addr = GetContextAddress(); const u32 addr = GetContextAddress();
u32 branch_addr = GetBranchFromAddress(addr); const u32 branch_addr = [addr] {
Core::CPUThreadGuard guard;
return GetBranchFromAddress(guard, addr);
}();
if (!branch_addr) if (!branch_addr)
return; return;
@ -879,9 +948,11 @@ void CodeViewWidget::OnSetSymbolSize()
if (!good) if (!good)
return; return;
PPCAnalyst::ReanalyzeFunction(symbol->address, *symbol, size); Core::CPUThreadGuard guard;
PPCAnalyst::ReanalyzeFunction(guard, symbol->address, *symbol, size);
emit SymbolsChanged(); emit SymbolsChanged();
Update(); Update(&guard);
} }
void CodeViewWidget::OnSetSymbolEndAddress() void CodeViewWidget::OnSetSymbolEndAddress()
@ -905,37 +976,43 @@ void CodeViewWidget::OnSetSymbolEndAddress()
if (!good) if (!good)
return; return;
PPCAnalyst::ReanalyzeFunction(symbol->address, *symbol, address - symbol->address); Core::CPUThreadGuard guard;
PPCAnalyst::ReanalyzeFunction(guard, symbol->address, *symbol, address - symbol->address);
emit SymbolsChanged(); emit SymbolsChanged();
Update(); Update(&guard);
} }
void CodeViewWidget::OnReplaceInstruction() void CodeViewWidget::OnReplaceInstruction()
{ {
Core::CPUThreadGuard guard;
const u32 addr = GetContextAddress(); const u32 addr = GetContextAddress();
if (!PowerPC::HostIsInstructionRAMAddress(addr)) if (!PowerPC::HostIsInstructionRAMAddress(guard, addr))
return; return;
const PowerPC::TryReadInstResult read_result = PowerPC::TryReadInstruction(addr); const PowerPC::TryReadInstResult read_result = PowerPC::TryReadInstruction(addr);
if (!read_result.valid) if (!read_result.valid)
return; return;
PatchInstructionDialog dialog(this, addr, PowerPC::debug_interface.ReadInstruction(addr)); PatchInstructionDialog dialog(this, addr, PowerPC::debug_interface.ReadInstruction(guard, addr));
if (dialog.exec() == QDialog::Accepted) if (dialog.exec() == QDialog::Accepted)
{ {
PowerPC::debug_interface.SetPatch(addr, dialog.GetCode()); PowerPC::debug_interface.SetPatch(guard, addr, dialog.GetCode());
Update(); Update(&guard);
} }
} }
void CodeViewWidget::OnRestoreInstruction() void CodeViewWidget::OnRestoreInstruction()
{ {
Core::CPUThreadGuard guard;
const u32 addr = GetContextAddress(); const u32 addr = GetContextAddress();
PowerPC::debug_interface.UnsetPatch(addr); PowerPC::debug_interface.UnsetPatch(guard, addr);
Update(); Update(&guard);
} }
void CodeViewWidget::resizeEvent(QResizeEvent*) void CodeViewWidget::resizeEvent(QResizeEvent*)

View File

@ -15,6 +15,11 @@ class QMouseEvent;
class QResizeEvent; class QResizeEvent;
class QShowEvent; class QShowEvent;
namespace Core
{
class CPUThreadGuard;
};
struct CodeViewBranch; struct CodeViewBranch;
class BranchDisplayDelegate; class BranchDisplayDelegate;
@ -39,6 +44,7 @@ public:
// Set tighter row height. Set BP column sizing. This needs to run when font type changes. // Set tighter row height. Set BP column sizing. This needs to run when font type changes.
void FontBasedSizing(); void FontBasedSizing();
void Update(); void Update();
void Update(const Core::CPUThreadGuard* guard);
void ToggleBreakpoint(); void ToggleBreakpoint();
void AddBreakpoint(); void AddBreakpoint();

View File

@ -322,14 +322,17 @@ void CodeWidget::Update()
void CodeWidget::UpdateCallstack() void CodeWidget::UpdateCallstack()
{ {
if (Core::GetState() == Core::State::Starting)
return;
m_callstack_list->clear(); m_callstack_list->clear();
if (Core::GetState() != Core::State::Paused)
return;
std::vector<Dolphin_Debugger::CallstackEntry> stack; std::vector<Dolphin_Debugger::CallstackEntry> stack;
bool success = Dolphin_Debugger::GetCallstack(Core::System::GetInstance(), stack); const bool success = [&stack] {
Core::CPUThreadGuard guard;
return Dolphin_Debugger::GetCallstack(Core::System::GetInstance(), guard, stack);
}();
if (!success) if (!success)
{ {
@ -452,7 +455,11 @@ void CodeWidget::StepOver()
if (!CPU::IsStepping()) if (!CPU::IsStepping())
return; return;
UGeckoInstruction inst = PowerPC::HostRead_Instruction(PowerPC::ppcState.pc); const UGeckoInstruction inst = [] {
Core::CPUThreadGuard guard;
return PowerPC::HostRead_Instruction(guard, PowerPC::ppcState.pc);
}();
if (inst.LK) if (inst.LK)
{ {
PowerPC::breakpoints.ClearAllTemporary(); PowerPC::breakpoints.ClearAllTemporary();
@ -485,48 +492,51 @@ void CodeWidget::StepOut()
if (!CPU::IsStepping()) if (!CPU::IsStepping())
return; return;
CPU::PauseAndLock(true, false);
PowerPC::breakpoints.ClearAllTemporary();
// Keep stepping until the next return instruction or timeout after five seconds // Keep stepping until the next return instruction or timeout after five seconds
using clock = std::chrono::steady_clock; using clock = std::chrono::steady_clock;
clock::time_point timeout = clock::now() + std::chrono::seconds(5); clock::time_point timeout = clock::now() + std::chrono::seconds(5);
PowerPC::CoreMode old_mode = PowerPC::GetMode();
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
// Loop until either the current instruction is a return instruction with no Link flag
// or a breakpoint is detected so it can step at the breakpoint. If the PC is currently
// on a breakpoint, skip it.
UGeckoInstruction inst = PowerPC::HostRead_Instruction(PowerPC::ppcState.pc);
do
{ {
if (WillInstructionReturn(inst)) Core::CPUThreadGuard guard;
{
PowerPC::SingleStep();
break;
}
if (inst.LK) PowerPC::breakpoints.ClearAllTemporary();
PowerPC::CoreMode old_mode = PowerPC::GetMode();
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
// Loop until either the current instruction is a return instruction with no Link flag
// or a breakpoint is detected so it can step at the breakpoint. If the PC is currently
// on a breakpoint, skip it.
UGeckoInstruction inst = PowerPC::HostRead_Instruction(guard, PowerPC::ppcState.pc);
do
{ {
// Step over branches if (WillInstructionReturn(inst))
u32 next_pc = PowerPC::ppcState.pc + 4;
do
{ {
PowerPC::SingleStep(); PowerPC::SingleStep();
} while (PowerPC::ppcState.pc != next_pc && clock::now() < timeout && break;
!PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc)); }
}
else
{
PowerPC::SingleStep();
}
inst = PowerPC::HostRead_Instruction(PowerPC::ppcState.pc); if (inst.LK)
} while (clock::now() < timeout && {
!PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc)); // Step over branches
u32 next_pc = PowerPC::ppcState.pc + 4;
do
{
PowerPC::SingleStep();
} while (PowerPC::ppcState.pc != next_pc && clock::now() < timeout &&
!PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc));
}
else
{
PowerPC::SingleStep();
}
PowerPC::SetMode(old_mode); inst = PowerPC::HostRead_Instruction(guard, PowerPC::ppcState.pc);
CPU::PauseAndLock(false, false); } while (clock::now() < timeout &&
!PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc));
PowerPC::SetMode(old_mode);
}
emit Host::GetInstance()->UpdateDisasmDialog(); emit Host::GetInstance()->UpdateDisasmDialog();

View File

@ -18,6 +18,7 @@
#include <fmt/printf.h> #include <fmt/printf.h>
#include "Common/Align.h" #include "Common/Align.h"
#include "Common/Assert.h"
#include "Common/FloatUtils.h" #include "Common/FloatUtils.h"
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "Common/Swap.h" #include "Common/Swap.h"
@ -46,6 +47,8 @@ constexpr int SCROLLBAR_PAGESTEP = 250;
constexpr int SCROLLBAR_MAXIMUM = 20000; constexpr int SCROLLBAR_MAXIMUM = 20000;
constexpr int SCROLLBAR_CENTER = SCROLLBAR_MAXIMUM / 2; constexpr int SCROLLBAR_CENTER = SCROLLBAR_MAXIMUM / 2;
const QString INVALID_MEMORY = QStringLiteral("-");
class MemoryViewTable final : public QTableWidget class MemoryViewTable final : public QTableWidget
{ {
public: public:
@ -151,11 +154,13 @@ public:
u32 end_address = address + static_cast<u32>(bytes.size()) - 1; u32 end_address = address + static_cast<u32>(bytes.size()) - 1;
AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_view->GetAddressSpace()); AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_view->GetAddressSpace());
if (!bytes.empty() && accessors->IsValidAddress(address) && Core::CPUThreadGuard guard;
accessors->IsValidAddress(end_address))
if (!bytes.empty() && accessors->IsValidAddress(guard, address) &&
accessors->IsValidAddress(guard, end_address))
{ {
for (const u8 c : bytes) for (const u8 c : bytes)
accessors->WriteU8(address++, c); accessors->WriteU8(guard, address++, c);
} }
m_view->Update(); m_view->Update();
@ -190,8 +195,9 @@ MemoryViewWidget::MemoryViewWidget(QWidget* parent) : QWidget(parent)
connect(&Settings::Instance(), &Settings::DebugFontChanged, this, &MemoryViewWidget::UpdateFont); connect(&Settings::Instance(), &Settings::DebugFontChanged, this, &MemoryViewWidget::UpdateFont);
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
&MemoryViewWidget::UpdateColumns); qOverload<>(&MemoryViewWidget::UpdateColumns));
connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this, &MemoryViewWidget::UpdateColumns); connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this,
qOverload<>(&MemoryViewWidget::UpdateColumns));
connect(&Settings::Instance(), &Settings::ThemeChanged, this, &MemoryViewWidget::Update); connect(&Settings::Instance(), &Settings::ThemeChanged, this, &MemoryViewWidget::Update);
// Also calls create table. // Also calls create table.
@ -322,13 +328,13 @@ void MemoryViewWidget::CreateTable()
bp_item->setData(USER_ROLE_VALUE_TYPE, static_cast<int>(Type::Null)); bp_item->setData(USER_ROLE_VALUE_TYPE, static_cast<int>(Type::Null));
// Row Addresses // Row Addresses
auto* row_item = new QTableWidgetItem(QStringLiteral("-")); auto* row_item = new QTableWidgetItem(INVALID_MEMORY);
row_item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); row_item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
row_item->setData(USER_ROLE_IS_ROW_BREAKPOINT_CELL, false); row_item->setData(USER_ROLE_IS_ROW_BREAKPOINT_CELL, false);
row_item->setData(USER_ROLE_VALUE_TYPE, static_cast<int>(Type::Null)); row_item->setData(USER_ROLE_VALUE_TYPE, static_cast<int>(Type::Null));
// Data item // Data item
auto* item = new QTableWidgetItem(QStringLiteral("-")); auto* item = new QTableWidgetItem(INVALID_MEMORY);
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable); item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
item->setData(USER_ROLE_IS_ROW_BREAKPOINT_CELL, false); item->setData(USER_ROLE_IS_ROW_BREAKPOINT_CELL, false);
@ -430,6 +436,24 @@ void MemoryViewWidget::Update()
} }
void MemoryViewWidget::UpdateColumns() void MemoryViewWidget::UpdateColumns()
{
// Check if table is created
if (m_table->item(1, 1) == nullptr)
return;
if (Core::GetState() == Core::State::Paused)
{
Core::CPUThreadGuard guard;
UpdateColumns(&guard);
}
else
{
// If the core is running, blank out the view of memory instead of reading anything.
UpdateColumns(nullptr);
}
}
void MemoryViewWidget::UpdateColumns(const Core::CPUThreadGuard* guard)
{ {
// Check if table is created // Check if table is created
if (m_table->item(1, 1) == nullptr) if (m_table->item(1, 1) == nullptr)
@ -445,7 +469,7 @@ void MemoryViewWidget::UpdateColumns()
const u32 cell_address = cell_item->data(USER_ROLE_CELL_ADDRESS).toUInt(); const u32 cell_address = cell_item->data(USER_ROLE_CELL_ADDRESS).toUInt();
const Type type = static_cast<Type>(cell_item->data(USER_ROLE_VALUE_TYPE).toInt()); const Type type = static_cast<Type>(cell_item->data(USER_ROLE_VALUE_TYPE).toInt());
cell_item->setText(ValueToString(cell_address, type)); cell_item->setText(guard ? ValueToString(*guard, cell_address, type) : INVALID_MEMORY);
// Set search address to selected / colored // Set search address to selected / colored
if (cell_address == m_address_highlight) if (cell_address == m_address_highlight)
@ -454,55 +478,56 @@ void MemoryViewWidget::UpdateColumns()
} }
} }
QString MemoryViewWidget::ValueToString(u32 address, Type type) // May only be called if we have taken on the role of the CPU thread
QString MemoryViewWidget::ValueToString(const Core::CPUThreadGuard& guard, u32 address, Type type)
{ {
const AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_address_space); const AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_address_space);
if (!accessors->IsValidAddress(address) || Core::GetState() != Core::State::Paused) if (!accessors->IsValidAddress(guard, address))
return QStringLiteral("-"); return INVALID_MEMORY;
switch (type) switch (type)
{ {
case Type::Hex8: case Type::Hex8:
{ {
const u8 value = accessors->ReadU8(address); const u8 value = accessors->ReadU8(guard, address);
return QStringLiteral("%1").arg(value, 2, 16, QLatin1Char('0')); return QStringLiteral("%1").arg(value, 2, 16, QLatin1Char('0'));
} }
case Type::ASCII: case Type::ASCII:
{ {
const char value = accessors->ReadU8(address); const char value = accessors->ReadU8(guard, address);
return IsPrintableCharacter(value) ? QString{QChar::fromLatin1(value)} : return IsPrintableCharacter(value) ? QString{QChar::fromLatin1(value)} :
QString{QChar::fromLatin1('.')}; QString{QChar::fromLatin1('.')};
} }
case Type::Hex16: case Type::Hex16:
{ {
const u16 value = accessors->ReadU16(address); const u16 value = accessors->ReadU16(guard, address);
return QStringLiteral("%1").arg(value, 4, 16, QLatin1Char('0')); return QStringLiteral("%1").arg(value, 4, 16, QLatin1Char('0'));
} }
case Type::Hex32: case Type::Hex32:
{ {
const u32 value = accessors->ReadU32(address); const u32 value = accessors->ReadU32(guard, address);
return QStringLiteral("%1").arg(value, 8, 16, QLatin1Char('0')); return QStringLiteral("%1").arg(value, 8, 16, QLatin1Char('0'));
} }
case Type::Hex64: case Type::Hex64:
{ {
const u64 value = accessors->ReadU64(address); const u64 value = accessors->ReadU64(guard, address);
return QStringLiteral("%1").arg(value, 16, 16, QLatin1Char('0')); return QStringLiteral("%1").arg(value, 16, 16, QLatin1Char('0'));
} }
case Type::Unsigned8: case Type::Unsigned8:
return QString::number(accessors->ReadU8(address)); return QString::number(accessors->ReadU8(guard, address));
case Type::Unsigned16: case Type::Unsigned16:
return QString::number(accessors->ReadU16(address)); return QString::number(accessors->ReadU16(guard, address));
case Type::Unsigned32: case Type::Unsigned32:
return QString::number(accessors->ReadU32(address)); return QString::number(accessors->ReadU32(guard, address));
case Type::Signed8: case Type::Signed8:
return QString::number(Common::BitCast<s8>(accessors->ReadU8(address))); return QString::number(Common::BitCast<s8>(accessors->ReadU8(guard, address)));
case Type::Signed16: case Type::Signed16:
return QString::number(Common::BitCast<s16>(accessors->ReadU16(address))); return QString::number(Common::BitCast<s16>(accessors->ReadU16(guard, address)));
case Type::Signed32: case Type::Signed32:
return QString::number(Common::BitCast<s32>(accessors->ReadU32(address))); return QString::number(Common::BitCast<s32>(accessors->ReadU32(guard, address)));
case Type::Float32: case Type::Float32:
{ {
QString string = QString::number(accessors->ReadF32(address), 'g', 4); QString string = QString::number(accessors->ReadF32(guard, address), 'g', 4);
// Align to first digit. // Align to first digit.
if (!string.startsWith(QLatin1Char('-'))) if (!string.startsWith(QLatin1Char('-')))
string.prepend(QLatin1Char(' ')); string.prepend(QLatin1Char(' '));
@ -511,7 +536,8 @@ QString MemoryViewWidget::ValueToString(u32 address, Type type)
} }
case Type::Double: case Type::Double:
{ {
QString string = QString::number(Common::BitCast<double>(accessors->ReadU64(address)), 'g', 4); QString string =
QString::number(Common::BitCast<double>(accessors->ReadU64(guard, address)), 'g', 4);
// Align to first digit. // Align to first digit.
if (!string.startsWith(QLatin1Char('-'))) if (!string.startsWith(QLatin1Char('-')))
string.prepend(QLatin1Char(' ')); string.prepend(QLatin1Char(' '));
@ -519,7 +545,7 @@ QString MemoryViewWidget::ValueToString(u32 address, Type type)
return string; return string;
} }
default: default:
return QStringLiteral("-"); return INVALID_MEMORY;
} }
} }
@ -823,7 +849,11 @@ void MemoryViewWidget::OnCopyHex(u32 addr)
const auto length = GetTypeSize(m_type); const auto length = GetTypeSize(m_type);
const AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_address_space); const AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_address_space);
u64 value = accessors->ReadU64(addr);
const u64 value = [addr, accessors] {
Core::CPUThreadGuard guard;
return accessors->ReadU64(guard, addr);
}();
QApplication::clipboard()->setText( QApplication::clipboard()->setText(
QStringLiteral("%1").arg(value, sizeof(u64) * 2, 16, QLatin1Char('0')).left(length * 2)); QStringLiteral("%1").arg(value, sizeof(u64) * 2, 16, QLatin1Char('0')).left(length * 2));
@ -839,10 +869,14 @@ void MemoryViewWidget::OnContextMenu(const QPoint& pos)
return; return;
const u32 addr = item_selected->data(USER_ROLE_CELL_ADDRESS).toUInt(); const u32 addr = item_selected->data(USER_ROLE_CELL_ADDRESS).toUInt();
const AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_address_space);
const bool item_has_value = const bool item_has_value =
item_selected->data(USER_ROLE_VALUE_TYPE).toInt() != static_cast<int>(Type::Null) && item_selected->data(USER_ROLE_VALUE_TYPE).toInt() != static_cast<int>(Type::Null) &&
accessors->IsValidAddress(addr); [this, addr] {
const AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_address_space);
Core::CPUThreadGuard guard;
return accessors->IsValidAddress(guard, addr);
}();
auto* menu = new QMenu(this); auto* menu = new QMenu(this);

View File

@ -15,6 +15,11 @@ namespace AddressSpace
enum class Type; enum class Type;
} }
namespace Core
{
class CPUThreadGuard;
}
class MemoryViewTable; class MemoryViewTable;
class MemoryViewWidget final : public QWidget class MemoryViewWidget final : public QWidget
@ -75,9 +80,10 @@ private:
void OnCopyHex(u32 addr); void OnCopyHex(u32 addr);
void UpdateBreakpointTags(); void UpdateBreakpointTags();
void UpdateColumns(); void UpdateColumns();
void UpdateColumns(const Core::CPUThreadGuard* guard);
void ScrollbarActionTriggered(int action); void ScrollbarActionTriggered(int action);
void ScrollbarSliderReleased(); void ScrollbarSliderReleased();
QString ValueToString(u32 address, Type type); QString ValueToString(const Core::CPUThreadGuard& guard, u32 address, Type type);
MemoryViewTable* m_table; MemoryViewTable* m_table;
QScrollBar* m_scrollbar; QScrollBar* m_scrollbar;

View File

@ -495,7 +495,9 @@ void MemoryWidget::SetAddress(u32 address)
{ {
AddressSpace::Accessors* accessors = AddressSpace::Accessors* accessors =
AddressSpace::GetAccessors(m_memory_view->GetAddressSpace()); AddressSpace::GetAccessors(m_memory_view->GetAddressSpace());
good = accessors->IsValidAddress(current_addr);
Core::CPUThreadGuard guard;
good = accessors->IsValidAddress(guard, current_addr);
} }
if (m_search_address->findText(current_text) == -1 && good) if (m_search_address->findText(current_text) == -1 && good)
@ -651,17 +653,20 @@ void MemoryWidget::OnSetValue()
return; return;
} }
Core::CPUThreadGuard guard;
AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_memory_view->GetAddressSpace()); AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_memory_view->GetAddressSpace());
u32 end_address = target_addr.address + static_cast<u32>(bytes.size()) - 1; u32 end_address = target_addr.address + static_cast<u32>(bytes.size()) - 1;
if (!accessors->IsValidAddress(target_addr.address) || !accessors->IsValidAddress(end_address)) if (!accessors->IsValidAddress(guard, target_addr.address) ||
!accessors->IsValidAddress(guard, end_address))
{ {
ModalMessageBox::critical(this, tr("Error"), tr("Target address range is invalid.")); ModalMessageBox::critical(this, tr("Error"), tr("Target address range is invalid."));
return; return;
} }
for (const char c : bytes) for (const char c : bytes)
accessors->WriteU8(target_addr.address++, static_cast<u8>(c)); accessors->WriteU8(guard, target_addr.address++, static_cast<u8>(c));
Update(); Update();
} }
@ -710,8 +715,10 @@ void MemoryWidget::OnSetValueFromFile()
AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_memory_view->GetAddressSpace()); AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_memory_view->GetAddressSpace());
Core::CPUThreadGuard guard;
for (u8 b : file_contents) for (u8 b : file_contents)
accessors->WriteU8(target_addr.address++, b); accessors->WriteU8(guard, target_addr.address++, b);
Update(); Update();
} }
@ -822,11 +829,15 @@ void MemoryWidget::FindValue(bool next)
target_addr.address += next ? 1 : -1; target_addr.address += next ? 1 : -1;
} }
AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_memory_view->GetAddressSpace()); const std::optional<u32> found_addr = [&] {
AddressSpace::Accessors* accessors =
AddressSpace::GetAccessors(m_memory_view->GetAddressSpace());
const auto found_addr = Core::CPUThreadGuard guard;
accessors->Search(target_addr.address, reinterpret_cast<const u8*>(search_for.data()), return accessors->Search(guard, target_addr.address,
static_cast<u32>(search_for.size()), next); reinterpret_cast<const u8*>(search_for.data()),
static_cast<u32>(search_for.size()), next);
}();
if (found_addr.has_value()) if (found_addr.has_value())
{ {

View File

@ -20,6 +20,11 @@ class QRadioButton;
class QShowEvent; class QShowEvent;
class QSplitter; class QSplitter;
namespace Core
{
class CPUThreadGuard;
}
class MemoryWidget : public QDockWidget class MemoryWidget : public QDockWidget
{ {
Q_OBJECT Q_OBJECT

View File

@ -295,7 +295,11 @@ void RegisterWidget::AutoStep(const std::string& reg) const
while (true) while (true)
{ {
const AutoStepResults results = trace.AutoStepping(true); const AutoStepResults results = [&trace] {
Core::CPUThreadGuard guard;
return trace.AutoStepping(guard, true);
}();
emit Host::GetInstance()->UpdateDisasmDialog(); emit Host::GetInstance()->UpdateDisasmDialog();
if (!results.timed_out) if (!results.timed_out)

View File

@ -256,7 +256,9 @@ void ThreadWidget::Update()
{ {
m_thread_table->setRowCount(0); m_thread_table->setRowCount(0);
UpdateThreadContext({}); UpdateThreadContext({});
UpdateThreadCallstack({});
Core::CPUThreadGuard guard;
UpdateThreadCallstack(guard, {});
} }
if (emu_state != Core::State::Paused) if (emu_state != Core::State::Paused)
return; return;
@ -264,8 +266,8 @@ void ThreadWidget::Update()
const auto format_hex = [](u32 value) { const auto format_hex = [](u32 value) {
return QStringLiteral("%1").arg(value, 8, 16, QLatin1Char('0')); return QStringLiteral("%1").arg(value, 8, 16, QLatin1Char('0'));
}; };
const auto format_hex_from = [&format_hex](u32 addr) { const auto format_hex_from = [&format_hex](const Core::CPUThreadGuard& guard, u32 addr) {
addr = PowerPC::HostIsRAMAddress(addr) ? PowerPC::HostRead_U32(addr) : 0; addr = PowerPC::HostIsRAMAddress(guard, addr) ? PowerPC::HostRead_U32(guard, addr) : 0;
return format_hex(addr); return format_hex(addr);
}; };
const auto get_state = [](u16 thread_state) { const auto get_state = [](u16 thread_state) {
@ -298,35 +300,41 @@ void ThreadWidget::Update()
.arg(start, 8, 16, QLatin1Char('0')); .arg(start, 8, 16, QLatin1Char('0'));
}; };
// YAGCD - Section 4.2.1.4 Dolphin OS Globals
m_current_context->setText(format_hex_from(0x800000D4));
m_current_thread->setText(format_hex_from(0x800000E4));
m_default_thread->setText(format_hex_from(0x800000D8));
m_queue_head->setText(format_hex_from(0x800000DC));
m_queue_tail->setText(format_hex_from(0x800000E0));
// Thread group
m_threads = PowerPC::debug_interface.GetThreads();
int i = 0;
m_thread_table->setRowCount(i);
for (const auto& thread : m_threads)
{ {
m_thread_table->insertRow(i); Core::CPUThreadGuard guard;
m_thread_table->setItem(i, 0, new QTableWidgetItem(format_hex(thread->GetAddress())));
m_thread_table->setItem(i, 1, new QTableWidgetItem(get_state(thread->GetState()))); // YAGCD - Section 4.2.1.4 Dolphin OS Globals
m_thread_table->setItem(i, 2, new QTableWidgetItem(QString::number(thread->IsDetached()))); m_current_context->setText(format_hex_from(guard, 0x800000D4));
m_thread_table->setItem(i, 3, new QTableWidgetItem(QString::number(thread->IsSuspended()))); m_current_thread->setText(format_hex_from(guard, 0x800000E4));
m_thread_table->setItem(i, 4, m_default_thread->setText(format_hex_from(guard, 0x800000D8));
new QTableWidgetItem(get_priority(thread->GetBasePriority(),
thread->GetEffectivePriority()))); m_queue_head->setText(format_hex_from(guard, 0x800000DC));
m_thread_table->setItem( m_queue_tail->setText(format_hex_from(guard, 0x800000E0));
i, 5, new QTableWidgetItem(get_stack(thread->GetStackEnd(), thread->GetStackStart())));
m_thread_table->setItem(i, 6, new QTableWidgetItem(QString::number(thread->GetErrno()))); // Thread group
m_thread_table->setItem(i, 7, m_threads = PowerPC::debug_interface.GetThreads(guard);
new QTableWidgetItem(QString::fromStdString(thread->GetSpecific())));
i += 1; int i = 0;
m_thread_table->setRowCount(i);
for (const auto& thread : m_threads)
{
m_thread_table->insertRow(i);
m_thread_table->setItem(i, 0, new QTableWidgetItem(format_hex(thread->GetAddress())));
m_thread_table->setItem(i, 1, new QTableWidgetItem(get_state(thread->GetState())));
m_thread_table->setItem(i, 2, new QTableWidgetItem(QString::number(thread->IsDetached())));
m_thread_table->setItem(i, 3, new QTableWidgetItem(QString::number(thread->IsSuspended())));
m_thread_table->setItem(i, 4,
new QTableWidgetItem(get_priority(thread->GetBasePriority(),
thread->GetEffectivePriority())));
m_thread_table->setItem(
i, 5, new QTableWidgetItem(get_stack(thread->GetStackEnd(), thread->GetStackStart())));
m_thread_table->setItem(i, 6, new QTableWidgetItem(QString::number(thread->GetErrno())));
m_thread_table->setItem(
i, 7, new QTableWidgetItem(QString::fromStdString(thread->GetSpecific(guard))));
i += 1;
}
} }
m_thread_table->resizeColumnsToContents(); m_thread_table->resizeColumnsToContents();
m_thread_table->resizeRowsToContents(); m_thread_table->resizeRowsToContents();
@ -425,7 +433,8 @@ void ThreadWidget::UpdateThreadContext(const Common::Debug::PartialContext& cont
m_context_table->resizeColumnsToContents(); m_context_table->resizeColumnsToContents();
} }
void ThreadWidget::UpdateThreadCallstack(const Common::Debug::PartialContext& context) void ThreadWidget::UpdateThreadCallstack(const Core::CPUThreadGuard& guard,
const Common::Debug::PartialContext& context)
{ {
m_callstack_table->setRowCount(0); m_callstack_table->setRowCount(0);
@ -439,13 +448,13 @@ void ThreadWidget::UpdateThreadCallstack(const Common::Debug::PartialContext& co
u32 sp = context.gpr->at(1); u32 sp = context.gpr->at(1);
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
{ {
if (sp == 0 || sp == 0xffffffff || !PowerPC::HostIsRAMAddress(sp)) if (sp == 0 || sp == 0xffffffff || !PowerPC::HostIsRAMAddress(guard, sp))
break; break;
m_callstack_table->insertRow(i); m_callstack_table->insertRow(i);
m_callstack_table->setItem(i, 0, new QTableWidgetItem(format_hex(sp))); m_callstack_table->setItem(i, 0, new QTableWidgetItem(format_hex(sp)));
if (PowerPC::HostIsRAMAddress(sp + 4)) if (PowerPC::HostIsRAMAddress(guard, sp + 4))
{ {
const u32 lr_save = PowerPC::HostRead_U32(sp + 4); const u32 lr_save = PowerPC::HostRead_U32(guard, sp + 4);
m_callstack_table->setItem(i, 2, new QTableWidgetItem(format_hex(lr_save))); m_callstack_table->setItem(i, 2, new QTableWidgetItem(format_hex(lr_save)));
m_callstack_table->setItem(i, 3, m_callstack_table->setItem(i, 3,
new QTableWidgetItem(QString::fromStdString( new QTableWidgetItem(QString::fromStdString(
@ -455,18 +464,19 @@ void ThreadWidget::UpdateThreadCallstack(const Common::Debug::PartialContext& co
{ {
m_callstack_table->setItem(i, 2, new QTableWidgetItem(QStringLiteral("--------"))); m_callstack_table->setItem(i, 2, new QTableWidgetItem(QStringLiteral("--------")));
} }
sp = PowerPC::HostRead_U32(sp); sp = PowerPC::HostRead_U32(guard, sp);
m_callstack_table->setItem(i, 1, new QTableWidgetItem(format_hex(sp))); m_callstack_table->setItem(i, 1, new QTableWidgetItem(format_hex(sp)));
} }
} }
void ThreadWidget::OnSelectionChanged(int row) void ThreadWidget::OnSelectionChanged(int row)
{ {
Core::CPUThreadGuard guard;
Common::Debug::PartialContext context; Common::Debug::PartialContext context;
if (row >= 0 && size_t(row) < m_threads.size()) if (row >= 0 && size_t(row) < m_threads.size())
context = m_threads[row]->GetContext(); context = m_threads[row]->GetContext(guard);
UpdateThreadContext(context); UpdateThreadContext(context);
UpdateThreadCallstack(context); UpdateThreadCallstack(guard, context);
} }

View File

@ -47,7 +47,8 @@ private:
void Update(); void Update();
void UpdateThreadContext(const Common::Debug::PartialContext& context); void UpdateThreadContext(const Common::Debug::PartialContext& context);
void UpdateThreadCallstack(const Common::Debug::PartialContext& context); void UpdateThreadCallstack(const Core::CPUThreadGuard& guard,
const Common::Debug::PartialContext& context);
void OnSelectionChanged(int row); void OnSelectionChanged(int row);
QGroupBox* m_state; QGroupBox* m_state;

View File

@ -161,6 +161,8 @@ void WatchWidget::Update()
// i18n: Floating-point (non-integer) number // i18n: Floating-point (non-integer) number
tr("Float"), tr("Locked")}); tr("Float"), tr("Locked")});
Core::CPUThreadGuard guard;
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
const auto& entry = PowerPC::debug_interface.GetWatch(i); const auto& entry = PowerPC::debug_interface.GetWatch(i);
@ -181,18 +183,18 @@ void WatchWidget::Update()
QBrush brush = QPalette().brush(QPalette::Text); QBrush brush = QPalette().brush(QPalette::Text);
if (!Core::IsRunning() || !PowerPC::HostIsRAMAddress(entry.address)) if (!Core::IsRunning() || !PowerPC::HostIsRAMAddress(guard, entry.address))
brush.setColor(Qt::red); brush.setColor(Qt::red);
if (Core::IsRunning()) if (Core::IsRunning())
{ {
if (PowerPC::HostIsRAMAddress(entry.address)) if (PowerPC::HostIsRAMAddress(guard, entry.address))
{ {
hex->setText(QStringLiteral("%1").arg(PowerPC::HostRead_U32(entry.address), 8, 16, hex->setText(QStringLiteral("%1").arg(PowerPC::HostRead_U32(guard, entry.address), 8, 16,
QLatin1Char('0'))); QLatin1Char('0')));
decimal->setText(QString::number(PowerPC::HostRead_U32(entry.address))); decimal->setText(QString::number(PowerPC::HostRead_U32(guard, entry.address)));
string->setText(QString::fromStdString(PowerPC::HostGetString(entry.address, 32))); string->setText(QString::fromStdString(PowerPC::HostGetString(guard, entry.address, 32)));
floatValue->setText(QString::number(PowerPC::HostRead_F32(entry.address))); floatValue->setText(QString::number(PowerPC::HostRead_F32(guard, entry.address)));
lockValue->setCheckState(entry.locked ? Qt::Checked : Qt::Unchecked); lockValue->setCheckState(entry.locked ? Qt::Checked : Qt::Unchecked);
} }
} }
@ -279,11 +281,13 @@ void WatchWidget::OnLoad()
return; return;
} }
Core::CPUThreadGuard guard;
if (ini.GetLines("Watches", &watches, false)) if (ini.GetLines("Watches", &watches, false))
{ {
for (const auto& watch : PowerPC::debug_interface.GetWatches()) for (const auto& watch : PowerPC::debug_interface.GetWatches())
{ {
PowerPC::debug_interface.UnsetPatch(watch.address); PowerPC::debug_interface.UnsetPatch(guard, watch.address);
} }
PowerPC::debug_interface.ClearWatches(); PowerPC::debug_interface.ClearWatches();
PowerPC::debug_interface.LoadWatchesFromStrings(watches); PowerPC::debug_interface.LoadWatchesFromStrings(watches);
@ -387,17 +391,19 @@ void WatchWidget::OnItemChanged(QTableWidgetItem* item)
if (good) if (good)
{ {
Core::CPUThreadGuard guard;
if (column == COLUMN_INDEX_ADDRESS) if (column == COLUMN_INDEX_ADDRESS)
{ {
const auto& watch = PowerPC::debug_interface.GetWatch(row); const auto& watch = PowerPC::debug_interface.GetWatch(row);
PowerPC::debug_interface.UnsetPatch(watch.address); PowerPC::debug_interface.UnsetPatch(guard, watch.address);
PowerPC::debug_interface.UpdateWatchAddress(row, value); PowerPC::debug_interface.UpdateWatchAddress(row, value);
if (watch.locked) if (watch.locked)
LockWatchAddress(value); LockWatchAddress(guard, value);
} }
else else
{ {
PowerPC::HostWrite_U32(value, PowerPC::debug_interface.GetWatch(row).address); PowerPC::HostWrite_U32(guard, value, PowerPC::debug_interface.GetWatch(row).address);
} }
} }
else else
@ -410,10 +416,11 @@ void WatchWidget::OnItemChanged(QTableWidgetItem* item)
{ {
PowerPC::debug_interface.UpdateWatchLockedState(row, item->checkState() == Qt::Checked); PowerPC::debug_interface.UpdateWatchLockedState(row, item->checkState() == Qt::Checked);
const auto& watch = PowerPC::debug_interface.GetWatch(row); const auto& watch = PowerPC::debug_interface.GetWatch(row);
Core::CPUThreadGuard guard;
if (watch.locked) if (watch.locked)
LockWatchAddress(watch.address); LockWatchAddress(guard, watch.address);
else else
PowerPC::debug_interface.UnsetPatch(watch.address); PowerPC::debug_interface.UnsetPatch(guard, watch.address);
break; break;
} }
} }
@ -422,9 +429,9 @@ void WatchWidget::OnItemChanged(QTableWidgetItem* item)
} }
} }
void WatchWidget::LockWatchAddress(u32 address) void WatchWidget::LockWatchAddress(const Core::CPUThreadGuard& guard, u32 address)
{ {
const std::string memory_data_as_string = PowerPC::HostGetString(address, 4); const std::string memory_data_as_string = PowerPC::HostGetString(guard, address, 4);
std::vector<u8> bytes; std::vector<u8> bytes;
for (const char c : memory_data_as_string) for (const char c : memory_data_as_string)
@ -432,42 +439,48 @@ void WatchWidget::LockWatchAddress(u32 address)
bytes.push_back(static_cast<u8>(c)); bytes.push_back(static_cast<u8>(c));
} }
PowerPC::debug_interface.SetFramePatch(address, bytes); PowerPC::debug_interface.SetFramePatch(guard, address, bytes);
} }
void WatchWidget::DeleteSelectedWatches() void WatchWidget::DeleteSelectedWatches()
{ {
std::vector<int> row_indices;
for (const auto& index : m_table->selectionModel()->selectedRows())
{ {
const auto* item = m_table->item(index.row(), index.column()); Core::CPUThreadGuard guard;
const auto row_variant = item->data(Qt::UserRole); std::vector<int> row_indices;
if (row_variant.isNull()) for (const auto& index : m_table->selectionModel()->selectedRows())
continue; {
const auto* item = m_table->item(index.row(), index.column());
const auto row_variant = item->data(Qt::UserRole);
if (row_variant.isNull())
continue;
row_indices.push_back(row_variant.toInt()); row_indices.push_back(row_variant.toInt());
} }
// Sort greatest to smallest, so we // Sort greatest to smallest, so we don't stomp on existing indices
// don't stomp on existing indices std::sort(row_indices.begin(), row_indices.end(), std::greater{});
std::sort(row_indices.begin(), row_indices.end(), std::greater{}); for (const int row : row_indices)
for (const int row : row_indices) {
{ DeleteWatch(guard, row);
DeleteWatch(row); }
} }
Update(); Update();
} }
void WatchWidget::DeleteWatch(int row) void WatchWidget::DeleteWatch(const Core::CPUThreadGuard& guard, int row)
{ {
PowerPC::debug_interface.UnsetPatch(PowerPC::debug_interface.GetWatch(row).address); PowerPC::debug_interface.UnsetPatch(guard, PowerPC::debug_interface.GetWatch(row).address);
PowerPC::debug_interface.RemoveWatch(row); PowerPC::debug_interface.RemoveWatch(row);
} }
void WatchWidget::DeleteWatchAndUpdate(int row) void WatchWidget::DeleteWatchAndUpdate(int row)
{ {
DeleteWatch(row); {
Core::CPUThreadGuard guard;
DeleteWatch(guard, row);
}
Update(); Update();
} }
@ -489,18 +502,21 @@ void WatchWidget::AddWatch(QString name, u32 addr)
void WatchWidget::LockSelectedWatches() void WatchWidget::LockSelectedWatches()
{ {
for (const auto& index : m_table->selectionModel()->selectedRows())
{ {
const auto* item = m_table->item(index.row(), index.column()); Core::CPUThreadGuard guard;
const auto row_variant = item->data(Qt::UserRole); for (const auto& index : m_table->selectionModel()->selectedRows())
if (row_variant.isNull()) {
continue; const auto* item = m_table->item(index.row(), index.column());
const int row = row_variant.toInt(); const auto row_variant = item->data(Qt::UserRole);
const auto& watch = PowerPC::debug_interface.GetWatch(row); if (row_variant.isNull())
if (watch.locked) continue;
continue; const int row = row_variant.toInt();
PowerPC::debug_interface.UpdateWatchLockedState(row, true); const auto& watch = PowerPC::debug_interface.GetWatch(row);
LockWatchAddress(watch.address); if (watch.locked)
continue;
PowerPC::debug_interface.UpdateWatchLockedState(row, true);
LockWatchAddress(guard, watch.address);
}
} }
Update(); Update();
@ -508,18 +524,21 @@ void WatchWidget::LockSelectedWatches()
void WatchWidget::UnlockSelectedWatches() void WatchWidget::UnlockSelectedWatches()
{ {
for (const auto& index : m_table->selectionModel()->selectedRows())
{ {
const auto* item = m_table->item(index.row(), index.column()); Core::CPUThreadGuard guard;
const auto row_variant = item->data(Qt::UserRole); for (const auto& index : m_table->selectionModel()->selectedRows())
if (row_variant.isNull()) {
continue; const auto* item = m_table->item(index.row(), index.column());
const int row = row_variant.toInt(); const auto row_variant = item->data(Qt::UserRole);
const auto& watch = PowerPC::debug_interface.GetWatch(row); if (row_variant.isNull())
if (!watch.locked) continue;
continue; const int row = row_variant.toInt();
PowerPC::debug_interface.UpdateWatchLockedState(row, false); const auto& watch = PowerPC::debug_interface.GetWatch(row);
PowerPC::debug_interface.UnsetPatch(watch.address); if (!watch.locked)
continue;
PowerPC::debug_interface.UpdateWatchLockedState(row, false);
PowerPC::debug_interface.UnsetPatch(guard, watch.address);
}
} }
Update(); Update();

View File

@ -14,6 +14,11 @@ class QTableWidget;
class QTableWidgetItem; class QTableWidgetItem;
class QToolBar; class QToolBar;
namespace Core
{
class CPUThreadGuard;
};
class WatchWidget : public QDockWidget class WatchWidget : public QDockWidget
{ {
Q_OBJECT Q_OBJECT
@ -46,9 +51,9 @@ private:
void ShowContextMenu(); void ShowContextMenu();
void OnItemChanged(QTableWidgetItem* item); void OnItemChanged(QTableWidgetItem* item);
void LockWatchAddress(u32 address); void LockWatchAddress(const Core::CPUThreadGuard& guard, u32 address);
void DeleteSelectedWatches(); void DeleteSelectedWatches();
void DeleteWatch(int row); void DeleteWatch(const Core::CPUThreadGuard& guard, int row);
void DeleteWatchAndUpdate(int row); void DeleteWatchAndUpdate(int row);
void AddWatchBreakpoint(int row); void AddWatchBreakpoint(int row);
void ShowInMemory(int row); void ShowInMemory(int row);

View File

@ -1186,25 +1186,29 @@ void MenuBar::ClearSymbols()
void MenuBar::GenerateSymbolsFromAddress() void MenuBar::GenerateSymbolsFromAddress()
{ {
Core::CPUThreadGuard guard;
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
PPCAnalyst::FindFunctions(Memory::MEM1_BASE_ADDR, PPCAnalyst::FindFunctions(guard, Memory::MEM1_BASE_ADDR,
Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal(), &g_symbolDB); Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal(), &g_symbolDB);
emit NotifySymbolsUpdated(); emit NotifySymbolsUpdated();
} }
void MenuBar::GenerateSymbolsFromSignatureDB() void MenuBar::GenerateSymbolsFromSignatureDB()
{ {
Core::CPUThreadGuard guard;
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
PPCAnalyst::FindFunctions(Memory::MEM1_BASE_ADDR, PPCAnalyst::FindFunctions(guard, Memory::MEM1_BASE_ADDR,
Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal(), &g_symbolDB); Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal(), &g_symbolDB);
SignatureDB db(SignatureDB::HandlerType::DSY); SignatureDB db(SignatureDB::HandlerType::DSY);
if (db.Load(File::GetSysDirectory() + TOTALDB)) if (db.Load(File::GetSysDirectory() + TOTALDB))
{ {
db.Apply(&g_symbolDB); db.Apply(guard, &g_symbolDB);
ModalMessageBox::information( ModalMessageBox::information(
this, tr("Information"), this, tr("Information"),
tr("Generated symbol names from '%1'").arg(QString::fromStdString(TOTALDB))); tr("Generated symbol names from '%1'").arg(QString::fromStdString(TOTALDB)));
@ -1240,10 +1244,12 @@ void MenuBar::GenerateSymbolsFromRSO()
return; return;
} }
Core::CPUThreadGuard guard;
RSOChainView rso_chain; RSOChainView rso_chain;
if (rso_chain.Load(static_cast<u32>(address))) if (rso_chain.Load(guard, static_cast<u32>(address)))
{ {
rso_chain.Apply(&g_symbolDB); rso_chain.Apply(guard, &g_symbolDB);
emit NotifySymbolsUpdated(); emit NotifySymbolsUpdated();
} }
else else
@ -1293,9 +1299,12 @@ void MenuBar::GenerateSymbolsFromRSOAuto()
RSOChainView rso_chain; RSOChainView rso_chain;
const u32 address = item.mid(0, item.indexOf(QLatin1Char(' '))).toUInt(nullptr, 16); const u32 address = item.mid(0, item.indexOf(QLatin1Char(' '))).toUInt(nullptr, 16);
if (rso_chain.Load(address))
Core::CPUThreadGuard guard;
if (rso_chain.Load(guard, address))
{ {
rso_chain.Apply(&g_symbolDB); rso_chain.Apply(guard, &g_symbolDB);
emit NotifySymbolsUpdated(); emit NotifySymbolsUpdated();
} }
else else
@ -1306,6 +1315,8 @@ void MenuBar::GenerateSymbolsFromRSOAuto()
RSOVector MenuBar::DetectRSOModules(ParallelProgressDialog& progress) RSOVector MenuBar::DetectRSOModules(ParallelProgressDialog& progress)
{ {
Core::CPUThreadGuard guard;
constexpr std::array<std::string_view, 2> search_for = {".elf", ".plf"}; constexpr std::array<std::string_view, 2> search_for = {".elf", ".plf"};
const AddressSpace::Accessors* accessors = const AddressSpace::Accessors* accessors =
@ -1324,8 +1335,8 @@ RSOVector MenuBar::DetectRSOModules(ParallelProgressDialog& progress)
return matches; return matches;
} }
auto found_addr = auto found_addr = accessors->Search(guard, next, reinterpret_cast<const u8*>(str.data()),
accessors->Search(next, reinterpret_cast<const u8*>(str.data()), str.size() + 1, true); str.size() + 1, true);
if (!found_addr.has_value()) if (!found_addr.has_value())
break; break;
@ -1334,13 +1345,13 @@ RSOVector MenuBar::DetectRSOModules(ParallelProgressDialog& progress)
// Non-null data can precede the module name. // Non-null data can precede the module name.
// Get the maximum name length that a module could have. // Get the maximum name length that a module could have.
auto get_max_module_name_len = [found_addr] { auto get_max_module_name_len = [&guard, found_addr] {
constexpr u32 MODULE_NAME_MAX_LENGTH = 260; constexpr u32 MODULE_NAME_MAX_LENGTH = 260;
u32 len = 0; u32 len = 0;
for (; len < MODULE_NAME_MAX_LENGTH; ++len) for (; len < MODULE_NAME_MAX_LENGTH; ++len)
{ {
const auto res = PowerPC::HostRead_U8(*found_addr - (len + 1)); const auto res = PowerPC::HostRead_U8(guard, *found_addr - (len + 1));
if (!std::isprint(res)) if (!std::isprint(res))
{ {
break; break;
@ -1375,12 +1386,12 @@ RSOVector MenuBar::DetectRSOModules(ParallelProgressDialog& progress)
// Get the field (Module Name Offset) that point to the string // Get the field (Module Name Offset) that point to the string
const auto module_name_offset_addr = const auto module_name_offset_addr =
accessors->Search(lookup_addr, ref.data(), ref.size(), false); accessors->Search(guard, lookup_addr, ref.data(), ref.size(), false);
if (!module_name_offset_addr.has_value()) if (!module_name_offset_addr.has_value())
continue; continue;
// The next 4 bytes should be the module name length // The next 4 bytes should be the module name length
module_name_length = accessors->ReadU32(*module_name_offset_addr + 4); module_name_length = accessors->ReadU32(guard, *module_name_offset_addr + 4);
if (module_name_length == max_name_length - i + str.length()) if (module_name_length == max_name_length - i + str.length())
{ {
found_addr = module_name_offset_addr; found_addr = module_name_offset_addr;
@ -1392,11 +1403,11 @@ RSOVector MenuBar::DetectRSOModules(ParallelProgressDialog& progress)
if (!found) if (!found)
continue; continue;
const auto module_name_offset = accessors->ReadU32(*found_addr); const auto module_name_offset = accessors->ReadU32(guard, *found_addr);
// Go to the beginning of the RSO header // Go to the beginning of the RSO header
matches.emplace_back(*found_addr - 16, matches.emplace_back(*found_addr - 16,
PowerPC::HostGetString(module_name_offset, module_name_length)); PowerPC::HostGetString(guard, module_name_offset, module_name_length));
progress.SetLabelText(tr("Modules found: %1").arg(matches.size())); progress.SetLabelText(tr("Modules found: %1").arg(matches.size()));
} }
@ -1416,11 +1427,16 @@ void MenuBar::LoadSymbolMap()
if (!map_exists) if (!map_exists)
{ {
g_symbolDB.Clear(); g_symbolDB.Clear();
PPCAnalyst::FindFunctions(Memory::MEM1_BASE_ADDR + 0x1300000,
Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal(), &g_symbolDB); {
SignatureDB db(SignatureDB::HandlerType::DSY); Core::CPUThreadGuard guard;
if (db.Load(File::GetSysDirectory() + TOTALDB))
db.Apply(&g_symbolDB); PPCAnalyst::FindFunctions(guard, Memory::MEM1_BASE_ADDR + 0x1300000,
Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal(), &g_symbolDB);
SignatureDB db(SignatureDB::HandlerType::DSY);
if (db.Load(File::GetSysDirectory() + TOTALDB))
db.Apply(guard, &g_symbolDB);
}
ModalMessageBox::warning(this, tr("Warning"), ModalMessageBox::warning(this, tr("Warning"),
tr("'%1' not found, scanning for common functions instead") tr("'%1' not found, scanning for common functions instead")
@ -1505,7 +1521,13 @@ void MenuBar::SaveCode()
const std::string path = const std::string path =
writable_map_file.substr(0, writable_map_file.find_last_of('.')) + "_code.map"; writable_map_file.substr(0, writable_map_file.find_last_of('.')) + "_code.map";
if (!g_symbolDB.SaveCodeMap(path)) bool success;
{
Core::CPUThreadGuard guard;
success = g_symbolDB.SaveCodeMap(guard, path);
}
if (!success)
{ {
ModalMessageBox::warning( ModalMessageBox::warning(
this, tr("Error"), this, tr("Error"),
@ -1515,7 +1537,9 @@ void MenuBar::SaveCode()
bool MenuBar::TryLoadMapFile(const QString& path, const bool bad) bool MenuBar::TryLoadMapFile(const QString& path, const bool bad)
{ {
if (!g_symbolDB.LoadMap(path.toStdString(), bad)) Core::CPUThreadGuard guard;
if (!g_symbolDB.LoadMap(guard, path.toStdString(), bad))
{ {
ModalMessageBox::warning(this, tr("Error"), tr("Failed to load map file '%1'").arg(path)); ModalMessageBox::warning(this, tr("Error"), tr("Failed to load map file '%1'").arg(path));
return false; return false;
@ -1596,7 +1620,10 @@ void MenuBar::ApplySignatureFile()
const std::string load_path = file.toStdString(); const std::string load_path = file.toStdString();
SignatureDB db(load_path); SignatureDB db(load_path);
db.Load(load_path); db.Load(load_path);
db.Apply(&g_symbolDB); {
Core::CPUThreadGuard guard;
db.Apply(guard, &g_symbolDB);
}
db.List(); db.List();
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
HLE::PatchFunctions(system); HLE::PatchFunctions(system);
@ -1665,12 +1692,14 @@ void MenuBar::SearchInstruction()
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
Core::CPUThreadGuard guard;
bool found = false; bool found = false;
for (u32 addr = Memory::MEM1_BASE_ADDR; addr < Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal(); for (u32 addr = Memory::MEM1_BASE_ADDR; addr < Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal();
addr += 4) addr += 4)
{ {
const auto ins_name = const auto ins_name =
QString::fromStdString(PPCTables::GetInstructionName(PowerPC::HostRead_U32(addr))); QString::fromStdString(PPCTables::GetInstructionName(PowerPC::HostRead_U32(guard, addr)));
if (op == ins_name) if (op == ins_name)
{ {
NOTICE_LOG_FMT(POWERPC, "Found {} at {:08x}", op.toStdString(), addr); NOTICE_LOG_FMT(POWERPC, "Found {} at {:08x}", op.toStdString(), addr);