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/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 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
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,7 +74,6 @@ public:
|
|||
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;
|
||||
|
||||
|
@ -65,4 +81,5 @@ public:
|
|||
|
||||
private:
|
||||
Common::Debug::Watches m_watches;
|
||||
PPCPatches m_patches;
|
||||
};
|
||||
|
|
|
@ -17,6 +17,11 @@ namespace DSP
|
|||
{
|
||||
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)
|
||||
{
|
||||
return m_watches.SetWatch(address, name);
|
||||
|
@ -87,6 +92,51 @@ void DSPDebugInterface::ClearWatches()
|
|||
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)
|
||||
{
|
||||
// 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.");
|
||||
}
|
||||
|
||||
void DSPDebugInterface::Patch(unsigned int address, unsigned int value)
|
||||
{
|
||||
PanicAlert("Patch functionality not supported in DSP module.");
|
||||
}
|
||||
|
||||
// =======================================================
|
||||
// Separate the blocks with colors.
|
||||
// -------------
|
||||
|
@ -264,6 +309,7 @@ void DSPDebugInterface::RunToBreakpoint()
|
|||
|
||||
void DSPDebugInterface::Clear()
|
||||
{
|
||||
ClearPatches();
|
||||
ClearWatches();
|
||||
}
|
||||
} // namespace LLE
|
||||
|
|
|
@ -14,6 +14,12 @@ namespace DSP
|
|||
{
|
||||
namespace LLE
|
||||
{
|
||||
class DSPPatches : public Common::Debug::MemoryPatches
|
||||
{
|
||||
private:
|
||||
void Patch(std::size_t index) override;
|
||||
};
|
||||
|
||||
class DSPDebugInterface final : public DebugInterface
|
||||
{
|
||||
public:
|
||||
|
@ -34,6 +40,17 @@ public:
|
|||
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);
|
||||
void RemovePatch(std::size_t index);
|
||||
bool HasEnabledPatch(u32 address) const;
|
||||
void ClearPatches();
|
||||
|
||||
std::string Disassemble(unsigned int address) override;
|
||||
std::string GetRawMemoryString(int memory, unsigned int address) override;
|
||||
int GetInstructionSize(int instruction) override { return 1; }
|
||||
|
@ -53,7 +70,6 @@ public:
|
|||
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;
|
||||
|
||||
|
@ -61,6 +77,7 @@ public:
|
|||
|
||||
private:
|
||||
Common::Debug::Watches m_watches;
|
||||
DSPPatches m_patches;
|
||||
};
|
||||
} // namespace LLE
|
||||
} // namespace DSP
|
||||
|
|
|
@ -549,7 +549,7 @@ void CheatsManager::Update()
|
|||
{
|
||||
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)
|
||||
|
|
|
@ -199,26 +199,8 @@ void CodeViewWidget::SetAddress(u32 address, SetAddressUpdate update)
|
|||
|
||||
void CodeViewWidget::ReplaceAddress(u32 address, ReplaceWith replace)
|
||||
{
|
||||
auto found = std::find_if(m_repl_list.begin(), m_repl_list.end(),
|
||||
[address](ReplStruct r) { return r.address == address; });
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
PowerPC::debug_interface.UnsetPatch(address);
|
||||
PowerPC::debug_interface.SetPatch(address, replace == ReplaceWith::BLR ? 0x4e800020 : 0x60000000);
|
||||
Update();
|
||||
}
|
||||
|
||||
|
@ -261,6 +243,8 @@ void CodeViewWidget::OnContextMenu()
|
|||
auto* insert_nop_action = AddAction(menu, tr("Insert &nop"), this, &CodeViewWidget::OnInsertNOP);
|
||||
auto* replace_action =
|
||||
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));
|
||||
|
||||
|
@ -271,6 +255,8 @@ void CodeViewWidget::OnContextMenu()
|
|||
for (auto* action : {symbol_rename_action, symbol_size_action, symbol_end_action})
|
||||
action->setEnabled(has_symbol);
|
||||
|
||||
restore_action->setEnabled(running && PowerPC::debug_interface.HasEnabledPatch(addr));
|
||||
|
||||
menu->exec(QCursor::pos());
|
||||
Update();
|
||||
}
|
||||
|
@ -474,11 +460,20 @@ void CodeViewWidget::OnReplaceInstruction()
|
|||
|
||||
if (good)
|
||||
{
|
||||
PowerPC::debug_interface.Patch(addr, code);
|
||||
PowerPC::debug_interface.UnsetPatch(addr);
|
||||
PowerPC::debug_interface.SetPatch(addr, code);
|
||||
Update();
|
||||
}
|
||||
}
|
||||
|
||||
void CodeViewWidget::OnRestoreInstruction()
|
||||
{
|
||||
const u32 addr = GetContextAddress();
|
||||
|
||||
PowerPC::debug_interface.UnsetPatch(addr);
|
||||
Update();
|
||||
}
|
||||
|
||||
void CodeViewWidget::resizeEvent(QResizeEvent*)
|
||||
{
|
||||
Update();
|
||||
|
|
|
@ -70,14 +70,8 @@ private:
|
|||
void OnInsertBLR();
|
||||
void OnInsertNOP();
|
||||
void OnReplaceInstruction();
|
||||
void OnRestoreInstruction();
|
||||
|
||||
struct ReplStruct
|
||||
{
|
||||
u32 address;
|
||||
u32 old_value;
|
||||
};
|
||||
|
||||
std::vector<ReplStruct> m_repl_list;
|
||||
bool m_updating = false;
|
||||
|
||||
u32 m_address = 0;
|
||||
|
|
|
@ -45,6 +45,7 @@ enum
|
|||
IDM_INSERTBLR,
|
||||
IDM_INSERTNOP,
|
||||
IDM_ASSEMBLE,
|
||||
IDM_RESTORE,
|
||||
IDM_RUNTOHERE,
|
||||
IDM_JITRESULTS,
|
||||
IDM_FOLLOWBRANCH,
|
||||
|
@ -201,36 +202,10 @@ u32 CCodeView::AddrToBranch(u32 addr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void CCodeView::InsertBlrNop(int Blr)
|
||||
void CCodeView::InsertBlrNop(int blr)
|
||||
{
|
||||
// Check if this address has been modified
|
||||
int find = -1;
|
||||
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);
|
||||
}
|
||||
m_debugger->UnsetPatch(m_selection);
|
||||
m_debugger->SetPatch(m_selection, (blr == 0) ? 0x4e800020 : 0x60000000);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
|
@ -320,13 +295,19 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
|
|||
unsigned long code;
|
||||
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();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case IDM_RESTORE:
|
||||
m_debugger->UnsetPatch(m_selection);
|
||||
Refresh();
|
||||
break;
|
||||
|
||||
case IDM_JITRESULTS:
|
||||
{
|
||||
// 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_INSERTNOP, _("Insert &nop"))->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());
|
||||
PopupMenu(&menu);
|
||||
event.Skip();
|
||||
|
|
|
@ -55,13 +55,6 @@ private:
|
|||
u32 AddrToBranch(u32 addr);
|
||||
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;
|
||||
|
||||
DebugInterface* m_debugger;
|
||||
|
|
Loading…
Reference in New Issue