mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-09-14 21:42:06 +00:00
DolphinQt: Properly lock CPU before accessing emulated memory
This fixes a problem I was having where using frame advance with the debugger open would frequently cause panic alerts about invalid addresses due to the CPU thread changing MSR.DR while the host thread was trying to access memory. To aid in tracking down all the places where we weren't properly locking the CPU, I've created a new type (in Core.h) that you have to pass as a reference or pointer to functions that require running as the CPU thread.
This commit is contained in:
parent
efed037c4a
commit
7cecb28bdf
79 changed files with 1796 additions and 1184 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>>;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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; });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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)";
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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())
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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. "
|
||||||
|
|
|
@ -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&);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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*)
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -329,7 +329,10 @@ void CodeWidget::UpdateCallstack()
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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())
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue