mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-10 16:19:28 +01:00
Merge pull request #6932 from sepalani/debug-patches
DebugInterface: MemoryPatches methods added
This commit is contained in:
commit
0e9255c469
@ -9,6 +9,7 @@ add_library(common
|
|||||||
Crypto/AES.cpp
|
Crypto/AES.cpp
|
||||||
Crypto/bn.cpp
|
Crypto/bn.cpp
|
||||||
Crypto/ec.cpp
|
Crypto/ec.cpp
|
||||||
|
Debug/MemoryPatches.cpp
|
||||||
Debug/Watches.cpp
|
Debug/Watches.cpp
|
||||||
ENetUtil.cpp
|
ENetUtil.cpp
|
||||||
File.cpp
|
File.cpp
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
<ClInclude Include="Config\Layer.h" />
|
<ClInclude Include="Config\Layer.h" />
|
||||||
<ClInclude Include="CPUDetect.h" />
|
<ClInclude Include="CPUDetect.h" />
|
||||||
<ClInclude Include="DebugInterface.h" />
|
<ClInclude Include="DebugInterface.h" />
|
||||||
|
<ClInclude Include="Debug\MemoryPatches.h" />
|
||||||
<ClInclude Include="Debug\Watches.h" />
|
<ClInclude Include="Debug\Watches.h" />
|
||||||
<ClInclude Include="ENetUtil.h" />
|
<ClInclude Include="ENetUtil.h" />
|
||||||
<ClInclude Include="Event.h" />
|
<ClInclude Include="Event.h" />
|
||||||
@ -176,6 +177,7 @@
|
|||||||
<ClCompile Include="Config\Config.cpp" />
|
<ClCompile Include="Config\Config.cpp" />
|
||||||
<ClCompile Include="Config\ConfigInfo.cpp" />
|
<ClCompile Include="Config\ConfigInfo.cpp" />
|
||||||
<ClCompile Include="Config\Layer.cpp" />
|
<ClCompile Include="Config\Layer.cpp" />
|
||||||
|
<ClCompile Include="Debug\MemoryPatches.cpp" />
|
||||||
<ClCompile Include="Debug\Watches.cpp" />
|
<ClCompile Include="Debug\Watches.cpp" />
|
||||||
<ClCompile Include="ENetUtil.cpp" />
|
<ClCompile Include="ENetUtil.cpp" />
|
||||||
<ClCompile Include="File.cpp" />
|
<ClCompile Include="File.cpp" />
|
||||||
|
@ -269,6 +269,9 @@
|
|||||||
<ClInclude Include="Debug\Watches.h">
|
<ClInclude Include="Debug\Watches.h">
|
||||||
<Filter>Debug</Filter>
|
<Filter>Debug</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Debug\MemoryPatches.h">
|
||||||
|
<Filter>Debug</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="CDUtils.cpp" />
|
<ClCompile Include="CDUtils.cpp" />
|
||||||
@ -292,7 +295,6 @@
|
|||||||
<ClCompile Include="Network.cpp" />
|
<ClCompile Include="Network.cpp" />
|
||||||
<ClCompile Include="PcapFile.cpp" />
|
<ClCompile Include="PcapFile.cpp" />
|
||||||
<ClCompile Include="Profiler.cpp" />
|
<ClCompile Include="Profiler.cpp" />
|
||||||
<ClCompile Include="QoSSession.h" />
|
|
||||||
<ClCompile Include="SDCardUtil.cpp" />
|
<ClCompile Include="SDCardUtil.cpp" />
|
||||||
<ClCompile Include="SettingsHandler.cpp" />
|
<ClCompile Include="SettingsHandler.cpp" />
|
||||||
<ClCompile Include="StringUtil.cpp" />
|
<ClCompile Include="StringUtil.cpp" />
|
||||||
@ -344,6 +346,10 @@
|
|||||||
<ClCompile Include="Debug\Watches.cpp">
|
<ClCompile Include="Debug\Watches.cpp">
|
||||||
<Filter>Debug</Filter>
|
<Filter>Debug</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="QoSSession.cpp" />
|
||||||
|
<ClCompile Include="Debug\MemoryPatches.cpp">
|
||||||
|
<Filter>Debug</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Text Include="CMakeLists.txt" />
|
<Text Include="CMakeLists.txt" />
|
||||||
|
99
Source/Core/Common/Debug/MemoryPatches.cpp
Normal file
99
Source/Core/Common/Debug/MemoryPatches.cpp
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
// Copyright 2018 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "Common/Debug/MemoryPatches.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace Common::Debug
|
||||||
|
{
|
||||||
|
MemoryPatch::MemoryPatch(u32 address_, std::vector<u8> value_)
|
||||||
|
: address(address_), value(value_), is_enabled(State::Enabled)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryPatch::MemoryPatch(u32 address, u32 value)
|
||||||
|
: MemoryPatch(address, {static_cast<u8>(value >> 24), static_cast<u8>(value >> 16),
|
||||||
|
static_cast<u8>(value >> 8), static_cast<u8>(value)})
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryPatches::MemoryPatches() = default;
|
||||||
|
MemoryPatches::~MemoryPatches() = default;
|
||||||
|
|
||||||
|
void MemoryPatches::SetPatch(u32 address, u32 value)
|
||||||
|
{
|
||||||
|
const std::size_t index = m_patches.size();
|
||||||
|
m_patches.emplace_back(address, value);
|
||||||
|
Patch(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryPatches::SetPatch(u32 address, std::vector<u8> value)
|
||||||
|
{
|
||||||
|
const std::size_t index = m_patches.size();
|
||||||
|
m_patches.emplace_back(address, std::move(value));
|
||||||
|
Patch(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<MemoryPatch>& MemoryPatches::GetPatches() const
|
||||||
|
{
|
||||||
|
return m_patches;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryPatches::UnsetPatch(u32 address)
|
||||||
|
{
|
||||||
|
const auto it = std::remove_if(m_patches.begin(), m_patches.end(),
|
||||||
|
[address](const auto& patch) { return patch.address == address; });
|
||||||
|
|
||||||
|
if (it == m_patches.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const std::size_t size = m_patches.size();
|
||||||
|
std::size_t index = size - std::distance(it, m_patches.end());
|
||||||
|
while (index < size)
|
||||||
|
{
|
||||||
|
DisablePatch(index);
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
m_patches.erase(it, m_patches.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryPatches::EnablePatch(std::size_t index)
|
||||||
|
{
|
||||||
|
if (m_patches[index].is_enabled == MemoryPatch::State::Enabled)
|
||||||
|
return;
|
||||||
|
m_patches[index].is_enabled = MemoryPatch::State::Enabled;
|
||||||
|
Patch(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryPatches::DisablePatch(std::size_t index)
|
||||||
|
{
|
||||||
|
if (m_patches[index].is_enabled == MemoryPatch::State::Disabled)
|
||||||
|
return;
|
||||||
|
m_patches[index].is_enabled = MemoryPatch::State::Disabled;
|
||||||
|
Patch(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryPatches::HasEnabledPatch(u32 address) const
|
||||||
|
{
|
||||||
|
return std::any_of(m_patches.begin(), m_patches.end(), [address](const MemoryPatch& patch) {
|
||||||
|
return patch.address == address && patch.is_enabled == MemoryPatch::State::Enabled;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryPatches::RemovePatch(std::size_t index)
|
||||||
|
{
|
||||||
|
DisablePatch(index);
|
||||||
|
m_patches.erase(m_patches.begin() + index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryPatches::ClearPatches()
|
||||||
|
{
|
||||||
|
const std::size_t size = m_patches.size();
|
||||||
|
for (std::size_t index = 0; index < size; ++index)
|
||||||
|
DisablePatch(index);
|
||||||
|
m_patches.clear();
|
||||||
|
}
|
||||||
|
} // namespace Common::Debug
|
52
Source/Core/Common/Debug/MemoryPatches.h
Normal file
52
Source/Core/Common/Debug/MemoryPatches.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// Copyright 2018 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
namespace Common::Debug
|
||||||
|
{
|
||||||
|
struct MemoryPatch
|
||||||
|
{
|
||||||
|
enum class State
|
||||||
|
{
|
||||||
|
Enabled,
|
||||||
|
Disabled
|
||||||
|
};
|
||||||
|
|
||||||
|
u32 address;
|
||||||
|
std::vector<u8> value;
|
||||||
|
State is_enabled;
|
||||||
|
|
||||||
|
MemoryPatch(u32 address, std::vector<u8> value);
|
||||||
|
MemoryPatch(u32 address, u32 value);
|
||||||
|
};
|
||||||
|
|
||||||
|
class MemoryPatches
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MemoryPatches();
|
||||||
|
virtual ~MemoryPatches();
|
||||||
|
|
||||||
|
void SetPatch(u32 address, u32 value);
|
||||||
|
void SetPatch(u32 address, std::vector<u8> value);
|
||||||
|
const std::vector<MemoryPatch>& GetPatches() const;
|
||||||
|
void UnsetPatch(u32 address);
|
||||||
|
void EnablePatch(std::size_t index);
|
||||||
|
void DisablePatch(std::size_t index);
|
||||||
|
bool HasEnabledPatch(u32 address) const;
|
||||||
|
void RemovePatch(std::size_t index);
|
||||||
|
void ClearPatches();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void Patch(std::size_t index) = 0;
|
||||||
|
|
||||||
|
std::vector<MemoryPatch> m_patches;
|
||||||
|
};
|
||||||
|
} // namespace Common::Debug
|
@ -10,6 +10,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Debug/MemoryPatches.h"
|
||||||
#include "Common/Debug/Watches.h"
|
#include "Common/Debug/Watches.h"
|
||||||
|
|
||||||
class DebugInterface
|
class DebugInterface
|
||||||
@ -34,6 +35,17 @@ public:
|
|||||||
virtual std::vector<std::string> SaveWatchesToStrings() const = 0;
|
virtual std::vector<std::string> SaveWatchesToStrings() const = 0;
|
||||||
virtual void ClearWatches() = 0;
|
virtual void ClearWatches() = 0;
|
||||||
|
|
||||||
|
// Memory Patches
|
||||||
|
virtual void SetPatch(u32 address, u32 value) = 0;
|
||||||
|
virtual void SetPatch(u32 address, std::vector<u8> value) = 0;
|
||||||
|
virtual const std::vector<Common::Debug::MemoryPatch>& GetPatches() const = 0;
|
||||||
|
virtual void UnsetPatch(u32 address) = 0;
|
||||||
|
virtual void EnablePatch(std::size_t index) = 0;
|
||||||
|
virtual void DisablePatch(std::size_t index) = 0;
|
||||||
|
virtual bool HasEnabledPatch(u32 address) const = 0;
|
||||||
|
virtual void RemovePatch(std::size_t index) = 0;
|
||||||
|
virtual void ClearPatches() = 0;
|
||||||
|
|
||||||
virtual std::string Disassemble(unsigned int /*address*/) { return "NODEBUGGER"; }
|
virtual std::string Disassemble(unsigned int /*address*/) { return "NODEBUGGER"; }
|
||||||
virtual std::string GetRawMemoryString(int /*memory*/, unsigned int /*address*/)
|
virtual std::string GetRawMemoryString(int /*memory*/, unsigned int /*address*/)
|
||||||
{
|
{
|
||||||
@ -59,7 +71,6 @@ public:
|
|||||||
virtual void SetPC(unsigned int /*address*/) {}
|
virtual void SetPC(unsigned int /*address*/) {}
|
||||||
virtual void Step() {}
|
virtual void Step() {}
|
||||||
virtual void RunToBreakpoint() {}
|
virtual void RunToBreakpoint() {}
|
||||||
virtual void Patch(unsigned int /*address*/, unsigned int /*value*/) {}
|
|
||||||
virtual int GetColor(unsigned int /*address*/) { return 0xFFFFFFFF; }
|
virtual int GetColor(unsigned int /*address*/) { return 0xFFFFFFFF; }
|
||||||
virtual std::string GetDescription(unsigned int /*address*/) = 0;
|
virtual std::string GetDescription(unsigned int /*address*/) = 0;
|
||||||
virtual void Clear() = 0;
|
virtual void Clear() = 0;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "Common/Align.h"
|
||||||
#include "Common/GekkoDisassembler.h"
|
#include "Common/GekkoDisassembler.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
|
||||||
@ -16,6 +17,33 @@
|
|||||||
#include "Core/PowerPC/PPCSymbolDB.h"
|
#include "Core/PowerPC/PPCSymbolDB.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
|
|
||||||
|
void PPCPatches::Patch(std::size_t index)
|
||||||
|
{
|
||||||
|
auto& patch = m_patches[index];
|
||||||
|
if (patch.value.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const u32 address = patch.address;
|
||||||
|
const std::size_t size = patch.value.size();
|
||||||
|
if (!PowerPC::HostIsRAMAddress(address))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (u32 offset = 0; offset < size; ++offset)
|
||||||
|
{
|
||||||
|
const u8 value = PowerPC::HostRead_U8(address + offset);
|
||||||
|
PowerPC::HostWrite_U8(patch.value[offset], address + offset);
|
||||||
|
patch.value[offset] = value;
|
||||||
|
|
||||||
|
if (((address + offset) % 4) == 3)
|
||||||
|
PowerPC::ScheduleInvalidateCacheThreadSafe(Common::AlignDown(address + offset, 4));
|
||||||
|
}
|
||||||
|
if (((address + size) % 4) != 0)
|
||||||
|
{
|
||||||
|
PowerPC::ScheduleInvalidateCacheThreadSafe(
|
||||||
|
Common::AlignDown(address + static_cast<u32>(size), 4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t PPCDebugInterface::SetWatch(u32 address, const std::string& name)
|
std::size_t PPCDebugInterface::SetWatch(u32 address, const std::string& name)
|
||||||
{
|
{
|
||||||
return m_watches.SetWatch(address, name);
|
return m_watches.SetWatch(address, name);
|
||||||
@ -86,6 +114,51 @@ void PPCDebugInterface::ClearWatches()
|
|||||||
m_watches.Clear();
|
m_watches.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PPCDebugInterface::SetPatch(u32 address, u32 value)
|
||||||
|
{
|
||||||
|
m_patches.SetPatch(address, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PPCDebugInterface::SetPatch(u32 address, std::vector<u8> value)
|
||||||
|
{
|
||||||
|
m_patches.SetPatch(address, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Common::Debug::MemoryPatch>& PPCDebugInterface::GetPatches() const
|
||||||
|
{
|
||||||
|
return m_patches.GetPatches();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PPCDebugInterface::UnsetPatch(u32 address)
|
||||||
|
{
|
||||||
|
m_patches.UnsetPatch(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PPCDebugInterface::EnablePatch(std::size_t index)
|
||||||
|
{
|
||||||
|
m_patches.EnablePatch(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PPCDebugInterface::DisablePatch(std::size_t index)
|
||||||
|
{
|
||||||
|
m_patches.DisablePatch(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PPCDebugInterface::HasEnabledPatch(u32 address) const
|
||||||
|
{
|
||||||
|
return m_patches.HasEnabledPatch(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PPCDebugInterface::RemovePatch(std::size_t index)
|
||||||
|
{
|
||||||
|
m_patches.RemovePatch(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PPCDebugInterface::ClearPatches()
|
||||||
|
{
|
||||||
|
m_patches.ClearPatches();
|
||||||
|
}
|
||||||
|
|
||||||
std::string PPCDebugInterface::Disassemble(unsigned int address)
|
std::string PPCDebugInterface::Disassemble(unsigned int address)
|
||||||
{
|
{
|
||||||
// PowerPC::HostRead_U32 seemed to crash on shutdown
|
// PowerPC::HostRead_U32 seemed to crash on shutdown
|
||||||
@ -220,12 +293,6 @@ void PPCDebugInterface::ToggleMemCheck(unsigned int address, bool read, bool wri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPCDebugInterface::Patch(unsigned int address, unsigned int value)
|
|
||||||
{
|
|
||||||
PowerPC::HostWrite_U32(value, address);
|
|
||||||
PowerPC::ScheduleInvalidateCacheThreadSafe(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// Separate the blocks with colors.
|
// Separate the blocks with colors.
|
||||||
// -------------
|
// -------------
|
||||||
@ -275,5 +342,6 @@ void PPCDebugInterface::Clear()
|
|||||||
{
|
{
|
||||||
ClearAllBreakpoints();
|
ClearAllBreakpoints();
|
||||||
ClearAllMemChecks();
|
ClearAllMemChecks();
|
||||||
|
ClearPatches();
|
||||||
ClearWatches();
|
ClearWatches();
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,12 @@
|
|||||||
|
|
||||||
#include "Common/DebugInterface.h"
|
#include "Common/DebugInterface.h"
|
||||||
|
|
||||||
|
class PPCPatches : public Common::Debug::MemoryPatches
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
void Patch(std::size_t index) override;
|
||||||
|
};
|
||||||
|
|
||||||
// wrapper between disasm control and Dolphin debugger
|
// wrapper between disasm control and Dolphin debugger
|
||||||
|
|
||||||
class PPCDebugInterface final : public DebugInterface
|
class PPCDebugInterface final : public DebugInterface
|
||||||
@ -31,6 +37,17 @@ public:
|
|||||||
std::vector<std::string> SaveWatchesToStrings() const override;
|
std::vector<std::string> SaveWatchesToStrings() const override;
|
||||||
void ClearWatches() override;
|
void ClearWatches() override;
|
||||||
|
|
||||||
|
// Memory Patches
|
||||||
|
void SetPatch(u32 address, u32 value);
|
||||||
|
void SetPatch(u32 address, std::vector<u8> value);
|
||||||
|
const std::vector<Common::Debug::MemoryPatch>& GetPatches() const;
|
||||||
|
void UnsetPatch(u32 address);
|
||||||
|
void EnablePatch(std::size_t index);
|
||||||
|
void DisablePatch(std::size_t index);
|
||||||
|
bool HasEnabledPatch(u32 address) const;
|
||||||
|
void RemovePatch(std::size_t index);
|
||||||
|
void ClearPatches();
|
||||||
|
|
||||||
std::string Disassemble(unsigned int address) override;
|
std::string Disassemble(unsigned int address) override;
|
||||||
std::string GetRawMemoryString(int memory, unsigned int address) override;
|
std::string GetRawMemoryString(int memory, unsigned int address) override;
|
||||||
int GetInstructionSize(int /*instruction*/) override { return 4; }
|
int GetInstructionSize(int /*instruction*/) override { return 4; }
|
||||||
@ -57,7 +74,6 @@ public:
|
|||||||
void SetPC(unsigned int address) override;
|
void SetPC(unsigned int address) override;
|
||||||
void Step() override {}
|
void Step() override {}
|
||||||
void RunToBreakpoint() override;
|
void RunToBreakpoint() override;
|
||||||
void Patch(unsigned int address, unsigned int value) override;
|
|
||||||
int GetColor(unsigned int address) override;
|
int GetColor(unsigned int address) override;
|
||||||
std::string GetDescription(unsigned int address) override;
|
std::string GetDescription(unsigned int address) override;
|
||||||
|
|
||||||
@ -65,4 +81,5 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Common::Debug::Watches m_watches;
|
Common::Debug::Watches m_watches;
|
||||||
|
PPCPatches m_patches;
|
||||||
};
|
};
|
||||||
|
@ -17,6 +17,11 @@ namespace DSP
|
|||||||
{
|
{
|
||||||
namespace LLE
|
namespace LLE
|
||||||
{
|
{
|
||||||
|
void DSPPatches::Patch(std::size_t index)
|
||||||
|
{
|
||||||
|
PanicAlert("Patch functionality not supported in DSP module.");
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t DSPDebugInterface::SetWatch(u32 address, const std::string& name)
|
std::size_t DSPDebugInterface::SetWatch(u32 address, const std::string& name)
|
||||||
{
|
{
|
||||||
return m_watches.SetWatch(address, name);
|
return m_watches.SetWatch(address, name);
|
||||||
@ -87,6 +92,51 @@ void DSPDebugInterface::ClearWatches()
|
|||||||
m_watches.Clear();
|
m_watches.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DSPDebugInterface::SetPatch(u32 address, u32 value)
|
||||||
|
{
|
||||||
|
m_patches.SetPatch(address, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPDebugInterface::SetPatch(u32 address, std::vector<u8> value)
|
||||||
|
{
|
||||||
|
m_patches.SetPatch(address, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Common::Debug::MemoryPatch>& DSPDebugInterface::GetPatches() const
|
||||||
|
{
|
||||||
|
return m_patches.GetPatches();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPDebugInterface::UnsetPatch(u32 address)
|
||||||
|
{
|
||||||
|
m_patches.UnsetPatch(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPDebugInterface::EnablePatch(std::size_t index)
|
||||||
|
{
|
||||||
|
m_patches.EnablePatch(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPDebugInterface::DisablePatch(std::size_t index)
|
||||||
|
{
|
||||||
|
m_patches.DisablePatch(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPDebugInterface::RemovePatch(std::size_t index)
|
||||||
|
{
|
||||||
|
m_patches.RemovePatch(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DSPDebugInterface::HasEnabledPatch(u32 address) const
|
||||||
|
{
|
||||||
|
return m_patches.HasEnabledPatch(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPDebugInterface::ClearPatches()
|
||||||
|
{
|
||||||
|
m_patches.ClearPatches();
|
||||||
|
}
|
||||||
|
|
||||||
std::string DSPDebugInterface::Disassemble(unsigned int address)
|
std::string DSPDebugInterface::Disassemble(unsigned int address)
|
||||||
{
|
{
|
||||||
// we'll treat addresses as line numbers.
|
// we'll treat addresses as line numbers.
|
||||||
@ -202,11 +252,6 @@ void DSPDebugInterface::ToggleMemCheck(unsigned int address, bool read, bool wri
|
|||||||
PanicAlert("MemCheck functionality not supported in DSP module.");
|
PanicAlert("MemCheck functionality not supported in DSP module.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPDebugInterface::Patch(unsigned int address, unsigned int value)
|
|
||||||
{
|
|
||||||
PanicAlert("Patch functionality not supported in DSP module.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// Separate the blocks with colors.
|
// Separate the blocks with colors.
|
||||||
// -------------
|
// -------------
|
||||||
@ -264,6 +309,7 @@ void DSPDebugInterface::RunToBreakpoint()
|
|||||||
|
|
||||||
void DSPDebugInterface::Clear()
|
void DSPDebugInterface::Clear()
|
||||||
{
|
{
|
||||||
|
ClearPatches();
|
||||||
ClearWatches();
|
ClearWatches();
|
||||||
}
|
}
|
||||||
} // namespace LLE
|
} // namespace LLE
|
||||||
|
@ -14,6 +14,12 @@ namespace DSP
|
|||||||
{
|
{
|
||||||
namespace LLE
|
namespace LLE
|
||||||
{
|
{
|
||||||
|
class DSPPatches : public Common::Debug::MemoryPatches
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
void Patch(std::size_t index) override;
|
||||||
|
};
|
||||||
|
|
||||||
class DSPDebugInterface final : public DebugInterface
|
class DSPDebugInterface final : public DebugInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -34,6 +40,17 @@ public:
|
|||||||
std::vector<std::string> SaveWatchesToStrings() const override;
|
std::vector<std::string> SaveWatchesToStrings() const override;
|
||||||
void ClearWatches() override;
|
void ClearWatches() override;
|
||||||
|
|
||||||
|
// Memory Patches
|
||||||
|
void SetPatch(u32 address, u32 value);
|
||||||
|
void SetPatch(u32 address, std::vector<u8> value);
|
||||||
|
const std::vector<Common::Debug::MemoryPatch>& GetPatches() const;
|
||||||
|
void UnsetPatch(u32 address);
|
||||||
|
void EnablePatch(std::size_t index);
|
||||||
|
void DisablePatch(std::size_t index);
|
||||||
|
void RemovePatch(std::size_t index);
|
||||||
|
bool HasEnabledPatch(u32 address) const;
|
||||||
|
void ClearPatches();
|
||||||
|
|
||||||
std::string Disassemble(unsigned int address) override;
|
std::string Disassemble(unsigned int address) override;
|
||||||
std::string GetRawMemoryString(int memory, unsigned int address) override;
|
std::string GetRawMemoryString(int memory, unsigned int address) override;
|
||||||
int GetInstructionSize(int instruction) override { return 1; }
|
int GetInstructionSize(int instruction) override { return 1; }
|
||||||
@ -53,7 +70,6 @@ public:
|
|||||||
void SetPC(unsigned int address) override;
|
void SetPC(unsigned int address) override;
|
||||||
void Step() override {}
|
void Step() override {}
|
||||||
void RunToBreakpoint() override;
|
void RunToBreakpoint() override;
|
||||||
void Patch(unsigned int address, unsigned int value) override;
|
|
||||||
int GetColor(unsigned int address) override;
|
int GetColor(unsigned int address) override;
|
||||||
std::string GetDescription(unsigned int address) override;
|
std::string GetDescription(unsigned int address) override;
|
||||||
|
|
||||||
@ -61,6 +77,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Common::Debug::Watches m_watches;
|
Common::Debug::Watches m_watches;
|
||||||
|
DSPPatches m_patches;
|
||||||
};
|
};
|
||||||
} // namespace LLE
|
} // namespace LLE
|
||||||
} // namespace DSP
|
} // namespace DSP
|
||||||
|
@ -549,7 +549,7 @@ void CheatsManager::Update()
|
|||||||
{
|
{
|
||||||
if (m_watch[i].locked)
|
if (m_watch[i].locked)
|
||||||
{
|
{
|
||||||
PowerPC::debug_interface.Patch(m_watch[i].address, m_watch[i].locked_value);
|
PowerPC::debug_interface.SetPatch(m_watch[i].address, m_watch[i].locked_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (m_watch[i].type)
|
switch (m_watch[i].type)
|
||||||
|
@ -199,26 +199,8 @@ void CodeViewWidget::SetAddress(u32 address, SetAddressUpdate update)
|
|||||||
|
|
||||||
void CodeViewWidget::ReplaceAddress(u32 address, ReplaceWith replace)
|
void CodeViewWidget::ReplaceAddress(u32 address, ReplaceWith replace)
|
||||||
{
|
{
|
||||||
auto found = std::find_if(m_repl_list.begin(), m_repl_list.end(),
|
PowerPC::debug_interface.UnsetPatch(address);
|
||||||
[address](ReplStruct r) { return r.address == address; });
|
PowerPC::debug_interface.SetPatch(address, replace == ReplaceWith::BLR ? 0x4e800020 : 0x60000000);
|
||||||
|
|
||||||
if (found != m_repl_list.end())
|
|
||||||
{
|
|
||||||
PowerPC::debug_interface.WriteExtraMemory(0, found->old_value, address);
|
|
||||||
m_repl_list.erase(found);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ReplStruct repl;
|
|
||||||
|
|
||||||
repl.address = address;
|
|
||||||
repl.old_value = PowerPC::debug_interface.ReadInstruction(address);
|
|
||||||
|
|
||||||
m_repl_list.push_back(repl);
|
|
||||||
|
|
||||||
PowerPC::debug_interface.Patch(address, replace == ReplaceWith::BLR ? 0x4e800020 : 0x60000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,6 +243,8 @@ void CodeViewWidget::OnContextMenu()
|
|||||||
auto* insert_nop_action = AddAction(menu, tr("Insert &nop"), this, &CodeViewWidget::OnInsertNOP);
|
auto* insert_nop_action = AddAction(menu, tr("Insert &nop"), this, &CodeViewWidget::OnInsertNOP);
|
||||||
auto* replace_action =
|
auto* replace_action =
|
||||||
AddAction(menu, tr("Re&place instruction"), this, &CodeViewWidget::OnReplaceInstruction);
|
AddAction(menu, tr("Re&place instruction"), this, &CodeViewWidget::OnReplaceInstruction);
|
||||||
|
auto* restore_action =
|
||||||
|
AddAction(menu, tr("Restore instruction"), this, &CodeViewWidget::OnRestoreInstruction);
|
||||||
|
|
||||||
follow_branch_action->setEnabled(running && GetBranchFromAddress(addr));
|
follow_branch_action->setEnabled(running && GetBranchFromAddress(addr));
|
||||||
|
|
||||||
@ -271,6 +255,8 @@ void CodeViewWidget::OnContextMenu()
|
|||||||
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);
|
||||||
|
|
||||||
|
restore_action->setEnabled(running && PowerPC::debug_interface.HasEnabledPatch(addr));
|
||||||
|
|
||||||
menu->exec(QCursor::pos());
|
menu->exec(QCursor::pos());
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
@ -474,11 +460,20 @@ void CodeViewWidget::OnReplaceInstruction()
|
|||||||
|
|
||||||
if (good)
|
if (good)
|
||||||
{
|
{
|
||||||
PowerPC::debug_interface.Patch(addr, code);
|
PowerPC::debug_interface.UnsetPatch(addr);
|
||||||
|
PowerPC::debug_interface.SetPatch(addr, code);
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CodeViewWidget::OnRestoreInstruction()
|
||||||
|
{
|
||||||
|
const u32 addr = GetContextAddress();
|
||||||
|
|
||||||
|
PowerPC::debug_interface.UnsetPatch(addr);
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
|
||||||
void CodeViewWidget::resizeEvent(QResizeEvent*)
|
void CodeViewWidget::resizeEvent(QResizeEvent*)
|
||||||
{
|
{
|
||||||
Update();
|
Update();
|
||||||
|
@ -70,14 +70,8 @@ private:
|
|||||||
void OnInsertBLR();
|
void OnInsertBLR();
|
||||||
void OnInsertNOP();
|
void OnInsertNOP();
|
||||||
void OnReplaceInstruction();
|
void OnReplaceInstruction();
|
||||||
|
void OnRestoreInstruction();
|
||||||
|
|
||||||
struct ReplStruct
|
|
||||||
{
|
|
||||||
u32 address;
|
|
||||||
u32 old_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<ReplStruct> m_repl_list;
|
|
||||||
bool m_updating = false;
|
bool m_updating = false;
|
||||||
|
|
||||||
u32 m_address = 0;
|
u32 m_address = 0;
|
||||||
|
@ -45,6 +45,7 @@ enum
|
|||||||
IDM_INSERTBLR,
|
IDM_INSERTBLR,
|
||||||
IDM_INSERTNOP,
|
IDM_INSERTNOP,
|
||||||
IDM_ASSEMBLE,
|
IDM_ASSEMBLE,
|
||||||
|
IDM_RESTORE,
|
||||||
IDM_RUNTOHERE,
|
IDM_RUNTOHERE,
|
||||||
IDM_JITRESULTS,
|
IDM_JITRESULTS,
|
||||||
IDM_FOLLOWBRANCH,
|
IDM_FOLLOWBRANCH,
|
||||||
@ -201,36 +202,10 @@ u32 CCodeView::AddrToBranch(u32 addr)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCodeView::InsertBlrNop(int Blr)
|
void CCodeView::InsertBlrNop(int blr)
|
||||||
{
|
{
|
||||||
// Check if this address has been modified
|
m_debugger->UnsetPatch(m_selection);
|
||||||
int find = -1;
|
m_debugger->SetPatch(m_selection, (blr == 0) ? 0x4e800020 : 0x60000000);
|
||||||
for (u32 i = 0; i < m_blrList.size(); i++)
|
|
||||||
{
|
|
||||||
if (m_blrList.at(i).address == m_selection)
|
|
||||||
{
|
|
||||||
find = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the old value
|
|
||||||
if (find >= 0)
|
|
||||||
{
|
|
||||||
m_debugger->WriteExtraMemory(0, m_blrList.at(find).oldValue, m_selection);
|
|
||||||
m_blrList.erase(m_blrList.begin() + find);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BlrStruct temp;
|
|
||||||
temp.address = m_selection;
|
|
||||||
temp.oldValue = m_debugger->ReadMemory(m_selection);
|
|
||||||
m_blrList.push_back(temp);
|
|
||||||
if (Blr == 0)
|
|
||||||
m_debugger->Patch(m_selection, 0x4e800020);
|
|
||||||
else
|
|
||||||
m_debugger->Patch(m_selection, 0x60000000);
|
|
||||||
}
|
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,13 +295,19 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
|
|||||||
unsigned long code;
|
unsigned long code;
|
||||||
if (dialog.GetValue().ToULong(&code, 0) && code <= std::numeric_limits<u32>::max())
|
if (dialog.GetValue().ToULong(&code, 0) && code <= std::numeric_limits<u32>::max())
|
||||||
{
|
{
|
||||||
m_debugger->Patch(m_selection, code);
|
m_debugger->UnsetPatch(m_selection);
|
||||||
|
m_debugger->SetPatch(m_selection, code);
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case IDM_RESTORE:
|
||||||
|
m_debugger->UnsetPatch(m_selection);
|
||||||
|
Refresh();
|
||||||
|
break;
|
||||||
|
|
||||||
case IDM_JITRESULTS:
|
case IDM_JITRESULTS:
|
||||||
{
|
{
|
||||||
// Propagate back to the parent window and tell it
|
// Propagate back to the parent window and tell it
|
||||||
@ -451,6 +432,8 @@ void CCodeView::OnMouseUpR(wxMouseEvent& event)
|
|||||||
menu.Append(IDM_INSERTBLR, _("&Insert blr"))->Enable(Core::IsRunning());
|
menu.Append(IDM_INSERTBLR, _("&Insert blr"))->Enable(Core::IsRunning());
|
||||||
menu.Append(IDM_INSERTNOP, _("Insert &nop"))->Enable(Core::IsRunning());
|
menu.Append(IDM_INSERTNOP, _("Insert &nop"))->Enable(Core::IsRunning());
|
||||||
menu.Append(IDM_ASSEMBLE, _("Re&place instruction"))->Enable(Core::IsRunning());
|
menu.Append(IDM_ASSEMBLE, _("Re&place instruction"))->Enable(Core::IsRunning());
|
||||||
|
menu.Append(IDM_RESTORE, _("Restore instruction"))
|
||||||
|
->Enable(Core::IsRunning() && m_debugger->HasEnabledPatch(m_selection));
|
||||||
// menu.Append(IDM_PATCHALERT, _("Patch alert"))->Enable(Core::IsRunning());
|
// menu.Append(IDM_PATCHALERT, _("Patch alert"))->Enable(Core::IsRunning());
|
||||||
PopupMenu(&menu);
|
PopupMenu(&menu);
|
||||||
event.Skip();
|
event.Skip();
|
||||||
|
@ -55,13 +55,6 @@ private:
|
|||||||
u32 AddrToBranch(u32 addr);
|
u32 AddrToBranch(u32 addr);
|
||||||
void OnResize(wxSizeEvent& event);
|
void OnResize(wxSizeEvent& event);
|
||||||
|
|
||||||
struct BlrStruct // for IDM_INSERTBLR
|
|
||||||
{
|
|
||||||
u32 address;
|
|
||||||
u32 oldValue;
|
|
||||||
};
|
|
||||||
std::vector<BlrStruct> m_blrList;
|
|
||||||
|
|
||||||
static constexpr int LEFT_COL_WIDTH = 16;
|
static constexpr int LEFT_COL_WIDTH = 16;
|
||||||
|
|
||||||
DebugInterface* m_debugger;
|
DebugInterface* m_debugger;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user