Permalink
Browse files

Merge pull request #6932 from sepalani/debug-patches

DebugInterface: MemoryPatches methods added
  • Loading branch information...
leoetlino committed May 22, 2018
2 parents 43680f3 + 8fa898f commit 0e9255c46999865a2d2e8a748ecccdfec7f6d476
@@ -9,6 +9,7 @@ add_library(common
Crypto/AES.cpp
Crypto/bn.cpp
Crypto/ec.cpp
Debug/MemoryPatches.cpp
Debug/Watches.cpp
ENetUtil.cpp
File.cpp
@@ -60,6 +60,7 @@
<ClInclude Include="Config\Layer.h" />
<ClInclude Include="CPUDetect.h" />
<ClInclude Include="DebugInterface.h" />
<ClInclude Include="Debug\MemoryPatches.h" />
<ClInclude Include="Debug\Watches.h" />
<ClInclude Include="ENetUtil.h" />
<ClInclude Include="Event.h" />
@@ -176,6 +177,7 @@
<ClCompile Include="Config\Config.cpp" />
<ClCompile Include="Config\ConfigInfo.cpp" />
<ClCompile Include="Config\Layer.cpp" />
<ClCompile Include="Debug\MemoryPatches.cpp" />
<ClCompile Include="Debug\Watches.cpp" />
<ClCompile Include="ENetUtil.cpp" />
<ClCompile Include="File.cpp" />
@@ -269,6 +269,9 @@
<ClInclude Include="Debug\Watches.h">
<Filter>Debug</Filter>
</ClInclude>
<ClInclude Include="Debug\MemoryPatches.h">
<Filter>Debug</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="CDUtils.cpp" />
@@ -292,7 +295,6 @@
<ClCompile Include="Network.cpp" />
<ClCompile Include="PcapFile.cpp" />
<ClCompile Include="Profiler.cpp" />
<ClCompile Include="QoSSession.h" />
<ClCompile Include="SDCardUtil.cpp" />
<ClCompile Include="SettingsHandler.cpp" />
<ClCompile Include="StringUtil.cpp" />
@@ -344,6 +346,10 @@
<ClCompile Include="Debug\Watches.cpp">
<Filter>Debug</Filter>
</ClCompile>
<ClCompile Include="QoSSession.cpp" />
<ClCompile Include="Debug\MemoryPatches.cpp">
<Filter>Debug</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
@@ -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
@@ -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 "Common/CommonTypes.h"
#include "Common/Debug/MemoryPatches.h"
#include "Common/Debug/Watches.h"
class DebugInterface
@@ -34,6 +35,17 @@ class DebugInterface
virtual std::vector<std::string> SaveWatchesToStrings() const = 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 GetRawMemoryString(int /*memory*/, unsigned int /*address*/)
{
@@ -59,7 +71,6 @@ class DebugInterface
virtual void SetPC(unsigned int /*address*/) {}
virtual void Step() {}
virtual void RunToBreakpoint() {}
virtual void Patch(unsigned int /*address*/, unsigned int /*value*/) {}
virtual int GetColor(unsigned int /*address*/) { return 0xFFFFFFFF; }
virtual std::string GetDescription(unsigned int /*address*/) = 0;
virtual void Clear() = 0;
@@ -7,6 +7,7 @@
#include <cstddef>
#include <string>
#include "Common/Align.h"
#include "Common/GekkoDisassembler.h"
#include "Common/StringUtil.h"
@@ -16,6 +17,33 @@
#include "Core/PowerPC/PPCSymbolDB.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)
{
return m_watches.SetWatch(address, name);
@@ -86,6 +114,51 @@ void PPCDebugInterface::ClearWatches()
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)
{
// 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.
// -------------
@@ -275,5 +342,6 @@ void PPCDebugInterface::Clear()
{
ClearAllBreakpoints();
ClearAllMemChecks();
ClearPatches();
ClearWatches();
}
@@ -9,6 +9,12 @@
#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
class PPCDebugInterface final : public DebugInterface
@@ -31,6 +37,17 @@ class PPCDebugInterface final : public DebugInterface
std::vector<std::string> SaveWatchesToStrings() const 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 GetRawMemoryString(int memory, unsigned int address) override;
int GetInstructionSize(int /*instruction*/) override { return 4; }
@@ -57,12 +74,12 @@ class PPCDebugInterface final : public DebugInterface
void SetPC(unsigned int address) override;
void Step() override {}
void RunToBreakpoint() override;
void Patch(unsigned int address, unsigned int value) override;
int GetColor(unsigned int address) override;
std::string GetDescription(unsigned int address) override;
void Clear() override;
private:
Common::Debug::Watches m_watches;
PPCPatches m_patches;
};
Oops, something went wrong.

0 comments on commit 0e9255c

Please sign in to comment.