mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-24 21:13:40 +01:00
Merge pull request #11554 from JosJuice/host-lock-cpu
DolphinQt: Properly lock CPU before accessing emulated memory
This commit is contained in:
commit
a4729a026f
@ -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();
|
||||||
|
@ -322,14 +322,17 @@ void CodeWidget::Update()
|
|||||||
|
|
||||||
void CodeWidget::UpdateCallstack()
|
void CodeWidget::UpdateCallstack()
|
||||||
{
|
{
|
||||||
if (Core::GetState() == Core::State::Starting)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_callstack_list->clear();
|
m_callstack_list->clear();
|
||||||
|
|
||||||
|
if (Core::GetState() != Core::State::Paused)
|
||||||
|
return;
|
||||||
|
|
||||||
std::vector<Dolphin_Debugger::CallstackEntry> stack;
|
std::vector<Dolphin_Debugger::CallstackEntry> stack;
|
||||||
|
|
||||||
bool success = Dolphin_Debugger::GetCallstack(Core::System::GetInstance(), stack);
|
const bool success = [&stack] {
|
||||||
|
Core::CPUThreadGuard guard;
|
||||||
|
return Dolphin_Debugger::GetCallstack(Core::System::GetInstance(), guard, stack);
|
||||||
|
}();
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
@ -452,7 +455,11 @@ void CodeWidget::StepOver()
|
|||||||
if (!CPU::IsStepping())
|
if (!CPU::IsStepping())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
UGeckoInstruction inst = PowerPC::HostRead_Instruction(PowerPC::ppcState.pc);
|
const UGeckoInstruction inst = [] {
|
||||||
|
Core::CPUThreadGuard guard;
|
||||||
|
return PowerPC::HostRead_Instruction(guard, PowerPC::ppcState.pc);
|
||||||
|
}();
|
||||||
|
|
||||||
if (inst.LK)
|
if (inst.LK)
|
||||||
{
|
{
|
||||||
PowerPC::breakpoints.ClearAllTemporary();
|
PowerPC::breakpoints.ClearAllTemporary();
|
||||||
@ -485,48 +492,51 @@ void CodeWidget::StepOut()
|
|||||||
if (!CPU::IsStepping())
|
if (!CPU::IsStepping())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CPU::PauseAndLock(true, false);
|
|
||||||
PowerPC::breakpoints.ClearAllTemporary();
|
|
||||||
|
|
||||||
// Keep stepping until the next return instruction or timeout after five seconds
|
// Keep stepping until the next return instruction or timeout after five seconds
|
||||||
using clock = std::chrono::steady_clock;
|
using clock = std::chrono::steady_clock;
|
||||||
clock::time_point timeout = clock::now() + std::chrono::seconds(5);
|
clock::time_point timeout = clock::now() + std::chrono::seconds(5);
|
||||||
PowerPC::CoreMode old_mode = PowerPC::GetMode();
|
|
||||||
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
|
|
||||||
|
|
||||||
// Loop until either the current instruction is a return instruction with no Link flag
|
|
||||||
// or a breakpoint is detected so it can step at the breakpoint. If the PC is currently
|
|
||||||
// on a breakpoint, skip it.
|
|
||||||
UGeckoInstruction inst = PowerPC::HostRead_Instruction(PowerPC::ppcState.pc);
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
if (WillInstructionReturn(inst))
|
Core::CPUThreadGuard guard;
|
||||||
{
|
|
||||||
PowerPC::SingleStep();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inst.LK)
|
PowerPC::breakpoints.ClearAllTemporary();
|
||||||
|
|
||||||
|
PowerPC::CoreMode old_mode = PowerPC::GetMode();
|
||||||
|
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
|
||||||
|
|
||||||
|
// Loop until either the current instruction is a return instruction with no Link flag
|
||||||
|
// or a breakpoint is detected so it can step at the breakpoint. If the PC is currently
|
||||||
|
// on a breakpoint, skip it.
|
||||||
|
UGeckoInstruction inst = PowerPC::HostRead_Instruction(guard, PowerPC::ppcState.pc);
|
||||||
|
do
|
||||||
{
|
{
|
||||||
// Step over branches
|
if (WillInstructionReturn(inst))
|
||||||
u32 next_pc = PowerPC::ppcState.pc + 4;
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
PowerPC::SingleStep();
|
PowerPC::SingleStep();
|
||||||
} while (PowerPC::ppcState.pc != next_pc && clock::now() < timeout &&
|
break;
|
||||||
!PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc));
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PowerPC::SingleStep();
|
|
||||||
}
|
|
||||||
|
|
||||||
inst = PowerPC::HostRead_Instruction(PowerPC::ppcState.pc);
|
if (inst.LK)
|
||||||
} while (clock::now() < timeout &&
|
{
|
||||||
!PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc));
|
// Step over branches
|
||||||
|
u32 next_pc = PowerPC::ppcState.pc + 4;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
PowerPC::SingleStep();
|
||||||
|
} while (PowerPC::ppcState.pc != next_pc && clock::now() < timeout &&
|
||||||
|
!PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PowerPC::SingleStep();
|
||||||
|
}
|
||||||
|
|
||||||
PowerPC::SetMode(old_mode);
|
inst = PowerPC::HostRead_Instruction(guard, PowerPC::ppcState.pc);
|
||||||
CPU::PauseAndLock(false, false);
|
} while (clock::now() < timeout &&
|
||||||
|
!PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc));
|
||||||
|
|
||||||
|
PowerPC::SetMode(old_mode);
|
||||||
|
}
|
||||||
|
|
||||||
emit Host::GetInstance()->UpdateDisasmDialog();
|
emit Host::GetInstance()->UpdateDisasmDialog();
|
||||||
|
|
||||||
|
@ -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…
x
Reference in New Issue
Block a user