Merge pull request #6932 from sepalani/debug-patches

DebugInterface: MemoryPatches methods added
This commit is contained in:
Léo Lam 2018-05-22 19:15:51 +02:00 committed by GitHub
commit 0e9255c469
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 365 additions and 81 deletions

View File

@ -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

View File

@ -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" />

View File

@ -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" />

View 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

View 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

View File

@ -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;

View File

@ -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();
} }

View File

@ -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;
}; };

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -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;