Merge pull request #11554 from JosJuice/host-lock-cpu

DolphinQt: Properly lock CPU before accessing emulated memory
This commit is contained in:
Scott Mansell
2023-02-13 16:08:36 +13:00
committed by GitHub
79 changed files with 1799 additions and 1187 deletions

View File

@ -36,6 +36,7 @@
#include "Core/CheatGeneration.h"
#include "Core/CheatSearch.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/PowerPC/PowerPC.h"
#include "DolphinQt/Config/CheatCodeEditor.h"
@ -286,7 +287,11 @@ void CheatSearchWidget::OnNextScanClicked()
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)
{
@ -391,7 +396,13 @@ bool CheatSearchWidget::RefreshValues()
}
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."));
return false;

View File

@ -483,7 +483,11 @@ void CodeDiffDialog::OnSetBLR()
Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(item->data(Qt::UserRole).toUInt());
if (!symbol)
return;
PowerPC::debug_interface.SetPatch(symbol->address, 0x4E800020);
{
Core::CPUThreadGuard guard;
PowerPC::debug_interface.SetPatch(guard, symbol->address, 0x4E800020);
}
int row = item->row();
m_matching_results_table->item(row, 0)->setForeground(QBrush(Qt::red));

View File

@ -175,14 +175,15 @@ CodeViewWidget::CodeViewWidget()
Update();
});
connect(&Settings::Instance(), &Settings::ThemeChanged, this, &CodeViewWidget::Update);
connect(&Settings::Instance(), &Settings::ThemeChanged, this,
qOverload<>(&CodeViewWidget::Update));
}
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");
if (pos == std::string::npos)
@ -248,6 +249,26 @@ static bool IsInstructionLoadStore(std::string_view ins)
}
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())
return;
@ -284,11 +305,11 @@ void CodeViewWidget::Update()
for (int i = 0; i < rowCount(); 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* 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');
std::string ins = (split == std::string::npos ? disas : disas.substr(0, split));
@ -332,9 +353,9 @@ void CodeViewWidget::Update()
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();
branch.src_addr = addr;
branch.dst_addr = branch_addr;
@ -514,15 +535,20 @@ void CodeViewWidget::SetAddress(u32 address, SetAddressUpdate update)
void CodeViewWidget::ReplaceAddress(u32 address, ReplaceWith replace)
{
PowerPC::debug_interface.SetPatch(address, replace == ReplaceWith::BLR ? 0x4e800020 : 0x60000000);
Update();
Core::CPUThreadGuard guard;
PowerPC::debug_interface.SetPatch(guard, address,
replace == ReplaceWith::BLR ? 0x4e800020 : 0x60000000);
Update(&guard);
}
void CodeViewWidget::OnContextMenu()
{
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();
@ -567,14 +593,25 @@ void CodeViewWidget::OnContextMenu()
menu->addAction(tr("Restore instruction"), this, &CodeViewWidget::OnRestoreInstruction);
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);
const auto target_it = std::find(line.begin(), line.end(), '\t');
const auto target_end = std::find(target_it, line.end(), ',');
Core::CPUThreadGuard guard;
const std::string disasm = PowerPC::debug_interface.Disassemble(&guard, PowerPC::ppcState.pc);
if (target_it != line.end() && target_end != line.end())
target = QString::fromStdString(std::string{target_it + 1, target_end});
if (addr == PowerPC::ppcState.pc)
{
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)"));
@ -589,18 +626,17 @@ void CodeViewWidget::OnContextMenu()
[this] { AutoStep(CodeTrace::AutoStop::Changed); });
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,
ppc_action, insert_blr_action, insert_nop_action, replace_action})
{
action->setEnabled(running);
}
for (auto* action : {symbol_rename_action, symbol_size_action, symbol_end_action})
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})
{
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
// silently follows target through reshuffles in memory and registers and stops on use or update.
Core::CPUThreadGuard guard;
CodeTrace code_trace;
bool repeat = false;
@ -628,7 +666,7 @@ void CodeViewWidget::AutoStep(CodeTrace::AutoStop option)
do
{
// 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();
repeat = true;
@ -703,16 +741,24 @@ void CodeViewWidget::OnCopyTargetAddress()
if (Core::GetState() != Core::State::Paused)
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))
return;
const std::optional<u32> addr =
const std::optional<u32> target_addr =
PowerPC::debug_interface.GetMemoryAddressFromInstruction(code_line);
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()
@ -725,24 +771,33 @@ void CodeViewWidget::OnShowTargetInMemory()
if (Core::GetState() != Core::State::Paused)
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))
return;
const std::optional<u32> addr =
const std::optional<u32> target_addr =
PowerPC::debug_interface.GetMemoryAddressFromInstruction(code_line);
if (addr)
emit ShowMemory(*addr);
emit ShowMemory(*target_addr);
}
void CodeViewWidget::OnCopyCode()
{
const u32 addr = GetContextAddress();
QApplication::clipboard()->setText(
QString::fromStdString(PowerPC::debug_interface.Disassemble(addr)));
const std::string text = [addr] {
Core::CPUThreadGuard guard;
return PowerPC::debug_interface.Disassemble(&guard, addr);
}();
QApplication::clipboard()->setText(QString::fromStdString(text));
}
void CodeViewWidget::OnCopyFunction()
@ -754,13 +809,18 @@ void CodeViewWidget::OnCopyFunction()
return;
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);
fmt::format_to(std::back_inserter(text), "{:08x}: {}\r\n", addr, disasm);
Core::CPUThreadGuard guard;
// 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));
@ -769,7 +829,11 @@ void CodeViewWidget::OnCopyFunction()
void CodeViewWidget::OnCopyHex()
{
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(
QStringLiteral("%1").arg(instruction, 8, 16, QLatin1Char('0')));
@ -795,9 +859,11 @@ void CodeViewWidget::OnAddFunction()
{
const u32 addr = GetContextAddress();
g_symbolDB.AddFunction(addr);
Core::CPUThreadGuard guard;
g_symbolDB.AddFunction(guard, addr);
emit SymbolsChanged();
Update();
Update(&guard);
}
void CodeViewWidget::OnInsertBLR()
@ -818,7 +884,10 @@ void CodeViewWidget::OnFollowBranch()
{
const u32 addr = GetContextAddress();
u32 branch_addr = GetBranchFromAddress(addr);
const u32 branch_addr = [addr] {
Core::CPUThreadGuard guard;
return GetBranchFromAddress(guard, addr);
}();
if (!branch_addr)
return;
@ -879,9 +948,11 @@ void CodeViewWidget::OnSetSymbolSize()
if (!good)
return;
PPCAnalyst::ReanalyzeFunction(symbol->address, *symbol, size);
Core::CPUThreadGuard guard;
PPCAnalyst::ReanalyzeFunction(guard, symbol->address, *symbol, size);
emit SymbolsChanged();
Update();
Update(&guard);
}
void CodeViewWidget::OnSetSymbolEndAddress()
@ -905,37 +976,43 @@ void CodeViewWidget::OnSetSymbolEndAddress()
if (!good)
return;
PPCAnalyst::ReanalyzeFunction(symbol->address, *symbol, address - symbol->address);
Core::CPUThreadGuard guard;
PPCAnalyst::ReanalyzeFunction(guard, symbol->address, *symbol, address - symbol->address);
emit SymbolsChanged();
Update();
Update(&guard);
}
void CodeViewWidget::OnReplaceInstruction()
{
Core::CPUThreadGuard guard;
const u32 addr = GetContextAddress();
if (!PowerPC::HostIsInstructionRAMAddress(addr))
if (!PowerPC::HostIsInstructionRAMAddress(guard, addr))
return;
const PowerPC::TryReadInstResult read_result = PowerPC::TryReadInstruction(addr);
if (!read_result.valid)
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)
{
PowerPC::debug_interface.SetPatch(addr, dialog.GetCode());
Update();
PowerPC::debug_interface.SetPatch(guard, addr, dialog.GetCode());
Update(&guard);
}
}
void CodeViewWidget::OnRestoreInstruction()
{
Core::CPUThreadGuard guard;
const u32 addr = GetContextAddress();
PowerPC::debug_interface.UnsetPatch(addr);
Update();
PowerPC::debug_interface.UnsetPatch(guard, addr);
Update(&guard);
}
void CodeViewWidget::resizeEvent(QResizeEvent*)

View File

@ -15,6 +15,11 @@ class QMouseEvent;
class QResizeEvent;
class QShowEvent;
namespace Core
{
class CPUThreadGuard;
};
struct CodeViewBranch;
class BranchDisplayDelegate;
@ -39,6 +44,7 @@ public:
// Set tighter row height. Set BP column sizing. This needs to run when font type changes.
void FontBasedSizing();
void Update();
void Update(const Core::CPUThreadGuard* guard);
void ToggleBreakpoint();
void AddBreakpoint();

View File

@ -322,14 +322,17 @@ void CodeWidget::Update()
void CodeWidget::UpdateCallstack()
{
if (Core::GetState() == Core::State::Starting)
return;
m_callstack_list->clear();
if (Core::GetState() != Core::State::Paused)
return;
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)
{
@ -452,7 +455,11 @@ void CodeWidget::StepOver()
if (!CPU::IsStepping())
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)
{
PowerPC::breakpoints.ClearAllTemporary();
@ -485,48 +492,51 @@ void CodeWidget::StepOut()
if (!CPU::IsStepping())
return;
CPU::PauseAndLock(true, false);
PowerPC::breakpoints.ClearAllTemporary();
// Keep stepping until the next return instruction or timeout after five seconds
using clock = std::chrono::steady_clock;
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))
{
PowerPC::SingleStep();
break;
}
Core::CPUThreadGuard guard;
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
u32 next_pc = PowerPC::ppcState.pc + 4;
do
if (WillInstructionReturn(inst))
{
PowerPC::SingleStep();
} while (PowerPC::ppcState.pc != next_pc && clock::now() < timeout &&
!PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc));
}
else
{
PowerPC::SingleStep();
}
break;
}
inst = PowerPC::HostRead_Instruction(PowerPC::ppcState.pc);
} while (clock::now() < timeout &&
!PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc));
if (inst.LK)
{
// 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);
CPU::PauseAndLock(false, false);
inst = PowerPC::HostRead_Instruction(guard, PowerPC::ppcState.pc);
} while (clock::now() < timeout &&
!PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc));
PowerPC::SetMode(old_mode);
}
emit Host::GetInstance()->UpdateDisasmDialog();

View File

@ -18,6 +18,7 @@
#include <fmt/printf.h>
#include "Common/Align.h"
#include "Common/Assert.h"
#include "Common/FloatUtils.h"
#include "Common/StringUtil.h"
#include "Common/Swap.h"
@ -46,6 +47,8 @@ constexpr int SCROLLBAR_PAGESTEP = 250;
constexpr int SCROLLBAR_MAXIMUM = 20000;
constexpr int SCROLLBAR_CENTER = SCROLLBAR_MAXIMUM / 2;
const QString INVALID_MEMORY = QStringLiteral("-");
class MemoryViewTable final : public QTableWidget
{
public:
@ -151,11 +154,13 @@ public:
u32 end_address = address + static_cast<u32>(bytes.size()) - 1;
AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_view->GetAddressSpace());
if (!bytes.empty() && accessors->IsValidAddress(address) &&
accessors->IsValidAddress(end_address))
Core::CPUThreadGuard guard;
if (!bytes.empty() && accessors->IsValidAddress(guard, address) &&
accessors->IsValidAddress(guard, end_address))
{
for (const u8 c : bytes)
accessors->WriteU8(address++, c);
accessors->WriteU8(guard, address++, c);
}
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::EmulationStateChanged, this,
&MemoryViewWidget::UpdateColumns);
connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this, &MemoryViewWidget::UpdateColumns);
qOverload<>(&MemoryViewWidget::UpdateColumns));
connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this,
qOverload<>(&MemoryViewWidget::UpdateColumns));
connect(&Settings::Instance(), &Settings::ThemeChanged, this, &MemoryViewWidget::Update);
// Also calls create table.
@ -322,13 +328,13 @@ void MemoryViewWidget::CreateTable()
bp_item->setData(USER_ROLE_VALUE_TYPE, static_cast<int>(Type::Null));
// Row Addresses
auto* row_item = new QTableWidgetItem(QStringLiteral("-"));
auto* row_item = new QTableWidgetItem(INVALID_MEMORY);
row_item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
row_item->setData(USER_ROLE_IS_ROW_BREAKPOINT_CELL, false);
row_item->setData(USER_ROLE_VALUE_TYPE, static_cast<int>(Type::Null));
// Data item
auto* item = new QTableWidgetItem(QStringLiteral("-"));
auto* item = new QTableWidgetItem(INVALID_MEMORY);
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
item->setData(USER_ROLE_IS_ROW_BREAKPOINT_CELL, false);
@ -430,6 +436,24 @@ void MemoryViewWidget::Update()
}
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
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 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
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);
if (!accessors->IsValidAddress(address) || Core::GetState() != Core::State::Paused)
return QStringLiteral("-");
if (!accessors->IsValidAddress(guard, address))
return INVALID_MEMORY;
switch (type)
{
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'));
}
case Type::ASCII:
{
const char value = accessors->ReadU8(address);
const char value = accessors->ReadU8(guard, address);
return IsPrintableCharacter(value) ? QString{QChar::fromLatin1(value)} :
QString{QChar::fromLatin1('.')};
}
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'));
}
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'));
}
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'));
}
case Type::Unsigned8:
return QString::number(accessors->ReadU8(address));
return QString::number(accessors->ReadU8(guard, address));
case Type::Unsigned16:
return QString::number(accessors->ReadU16(address));
return QString::number(accessors->ReadU16(guard, address));
case Type::Unsigned32:
return QString::number(accessors->ReadU32(address));
return QString::number(accessors->ReadU32(guard, address));
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:
return QString::number(Common::BitCast<s16>(accessors->ReadU16(address)));
return QString::number(Common::BitCast<s16>(accessors->ReadU16(guard, address)));
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:
{
QString string = QString::number(accessors->ReadF32(address), 'g', 4);
QString string = QString::number(accessors->ReadF32(guard, address), 'g', 4);
// Align to first digit.
if (!string.startsWith(QLatin1Char('-')))
string.prepend(QLatin1Char(' '));
@ -511,7 +536,8 @@ QString MemoryViewWidget::ValueToString(u32 address, Type type)
}
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.
if (!string.startsWith(QLatin1Char('-')))
string.prepend(QLatin1Char(' '));
@ -519,7 +545,7 @@ QString MemoryViewWidget::ValueToString(u32 address, Type type)
return string;
}
default:
return QStringLiteral("-");
return INVALID_MEMORY;
}
}
@ -823,7 +849,11 @@ void MemoryViewWidget::OnCopyHex(u32 addr)
const auto length = GetTypeSize(m_type);
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(
QStringLiteral("%1").arg(value, sizeof(u64) * 2, 16, QLatin1Char('0')).left(length * 2));
@ -839,10 +869,14 @@ void MemoryViewWidget::OnContextMenu(const QPoint& pos)
return;
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 =
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);

View File

@ -15,6 +15,11 @@ namespace AddressSpace
enum class Type;
}
namespace Core
{
class CPUThreadGuard;
}
class MemoryViewTable;
class MemoryViewWidget final : public QWidget
@ -75,9 +80,10 @@ private:
void OnCopyHex(u32 addr);
void UpdateBreakpointTags();
void UpdateColumns();
void UpdateColumns(const Core::CPUThreadGuard* guard);
void ScrollbarActionTriggered(int action);
void ScrollbarSliderReleased();
QString ValueToString(u32 address, Type type);
QString ValueToString(const Core::CPUThreadGuard& guard, u32 address, Type type);
MemoryViewTable* m_table;
QScrollBar* m_scrollbar;

View File

@ -495,7 +495,9 @@ void MemoryWidget::SetAddress(u32 address)
{
AddressSpace::Accessors* accessors =
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)
@ -651,17 +653,20 @@ void MemoryWidget::OnSetValue()
return;
}
Core::CPUThreadGuard guard;
AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_memory_view->GetAddressSpace());
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."));
return;
}
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();
}
@ -710,8 +715,10 @@ void MemoryWidget::OnSetValueFromFile()
AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_memory_view->GetAddressSpace());
Core::CPUThreadGuard guard;
for (u8 b : file_contents)
accessors->WriteU8(target_addr.address++, b);
accessors->WriteU8(guard, target_addr.address++, b);
Update();
}
@ -822,11 +829,15 @@ void MemoryWidget::FindValue(bool next)
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 =
accessors->Search(target_addr.address, reinterpret_cast<const u8*>(search_for.data()),
static_cast<u32>(search_for.size()), next);
Core::CPUThreadGuard guard;
return accessors->Search(guard, target_addr.address,
reinterpret_cast<const u8*>(search_for.data()),
static_cast<u32>(search_for.size()), next);
}();
if (found_addr.has_value())
{

View File

@ -20,6 +20,11 @@ class QRadioButton;
class QShowEvent;
class QSplitter;
namespace Core
{
class CPUThreadGuard;
}
class MemoryWidget : public QDockWidget
{
Q_OBJECT

View File

@ -295,7 +295,11 @@ void RegisterWidget::AutoStep(const std::string& reg) const
while (true)
{
const AutoStepResults results = trace.AutoStepping(true);
const AutoStepResults results = [&trace] {
Core::CPUThreadGuard guard;
return trace.AutoStepping(guard, true);
}();
emit Host::GetInstance()->UpdateDisasmDialog();
if (!results.timed_out)

View File

@ -256,7 +256,9 @@ void ThreadWidget::Update()
{
m_thread_table->setRowCount(0);
UpdateThreadContext({});
UpdateThreadCallstack({});
Core::CPUThreadGuard guard;
UpdateThreadCallstack(guard, {});
}
if (emu_state != Core::State::Paused)
return;
@ -264,8 +266,8 @@ void ThreadWidget::Update()
const auto format_hex = [](u32 value) {
return QStringLiteral("%1").arg(value, 8, 16, QLatin1Char('0'));
};
const auto format_hex_from = [&format_hex](u32 addr) {
addr = PowerPC::HostIsRAMAddress(addr) ? PowerPC::HostRead_U32(addr) : 0;
const auto format_hex_from = [&format_hex](const Core::CPUThreadGuard& guard, u32 addr) {
addr = PowerPC::HostIsRAMAddress(guard, addr) ? PowerPC::HostRead_U32(guard, addr) : 0;
return format_hex(addr);
};
const auto get_state = [](u16 thread_state) {
@ -298,35 +300,41 @@ void ThreadWidget::Update()
.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);
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())));
i += 1;
Core::CPUThreadGuard guard;
// YAGCD - Section 4.2.1.4 Dolphin OS Globals
m_current_context->setText(format_hex_from(guard, 0x800000D4));
m_current_thread->setText(format_hex_from(guard, 0x800000E4));
m_default_thread->setText(format_hex_from(guard, 0x800000D8));
m_queue_head->setText(format_hex_from(guard, 0x800000DC));
m_queue_tail->setText(format_hex_from(guard, 0x800000E0));
// Thread group
m_threads = PowerPC::debug_interface.GetThreads(guard);
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->resizeRowsToContents();
@ -425,7 +433,8 @@ void ThreadWidget::UpdateThreadContext(const Common::Debug::PartialContext& cont
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);
@ -439,13 +448,13 @@ void ThreadWidget::UpdateThreadCallstack(const Common::Debug::PartialContext& co
u32 sp = context.gpr->at(1);
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;
m_callstack_table->insertRow(i);
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, 3,
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("--------")));
}
sp = PowerPC::HostRead_U32(sp);
sp = PowerPC::HostRead_U32(guard, sp);
m_callstack_table->setItem(i, 1, new QTableWidgetItem(format_hex(sp)));
}
}
void ThreadWidget::OnSelectionChanged(int row)
{
Core::CPUThreadGuard guard;
Common::Debug::PartialContext context;
if (row >= 0 && size_t(row) < m_threads.size())
context = m_threads[row]->GetContext();
context = m_threads[row]->GetContext(guard);
UpdateThreadContext(context);
UpdateThreadCallstack(context);
UpdateThreadCallstack(guard, context);
}

View File

@ -47,7 +47,8 @@ private:
void Update();
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);
QGroupBox* m_state;

View File

@ -161,6 +161,8 @@ void WatchWidget::Update()
// i18n: Floating-point (non-integer) number
tr("Float"), tr("Locked")});
Core::CPUThreadGuard guard;
for (int i = 0; i < size; i++)
{
const auto& entry = PowerPC::debug_interface.GetWatch(i);
@ -181,18 +183,18 @@ void WatchWidget::Update()
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);
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')));
decimal->setText(QString::number(PowerPC::HostRead_U32(entry.address)));
string->setText(QString::fromStdString(PowerPC::HostGetString(entry.address, 32)));
floatValue->setText(QString::number(PowerPC::HostRead_F32(entry.address)));
decimal->setText(QString::number(PowerPC::HostRead_U32(guard, entry.address)));
string->setText(QString::fromStdString(PowerPC::HostGetString(guard, entry.address, 32)));
floatValue->setText(QString::number(PowerPC::HostRead_F32(guard, entry.address)));
lockValue->setCheckState(entry.locked ? Qt::Checked : Qt::Unchecked);
}
}
@ -279,11 +281,13 @@ void WatchWidget::OnLoad()
return;
}
Core::CPUThreadGuard guard;
if (ini.GetLines("Watches", &watches, false))
{
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.LoadWatchesFromStrings(watches);
@ -387,17 +391,19 @@ void WatchWidget::OnItemChanged(QTableWidgetItem* item)
if (good)
{
Core::CPUThreadGuard guard;
if (column == COLUMN_INDEX_ADDRESS)
{
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);
if (watch.locked)
LockWatchAddress(value);
LockWatchAddress(guard, value);
}
else
{
PowerPC::HostWrite_U32(value, PowerPC::debug_interface.GetWatch(row).address);
PowerPC::HostWrite_U32(guard, value, PowerPC::debug_interface.GetWatch(row).address);
}
}
else
@ -410,10 +416,11 @@ void WatchWidget::OnItemChanged(QTableWidgetItem* item)
{
PowerPC::debug_interface.UpdateWatchLockedState(row, item->checkState() == Qt::Checked);
const auto& watch = PowerPC::debug_interface.GetWatch(row);
Core::CPUThreadGuard guard;
if (watch.locked)
LockWatchAddress(watch.address);
LockWatchAddress(guard, watch.address);
else
PowerPC::debug_interface.UnsetPatch(watch.address);
PowerPC::debug_interface.UnsetPatch(guard, watch.address);
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;
for (const char c : memory_data_as_string)
@ -432,42 +439,48 @@ void WatchWidget::LockWatchAddress(u32 address)
bytes.push_back(static_cast<u8>(c));
}
PowerPC::debug_interface.SetFramePatch(address, bytes);
PowerPC::debug_interface.SetFramePatch(guard, address, bytes);
}
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());
const auto row_variant = item->data(Qt::UserRole);
if (row_variant.isNull())
continue;
Core::CPUThreadGuard guard;
std::vector<int> row_indices;
for (const auto& index : m_table->selectionModel()->selectedRows())
{
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
// don't stomp on existing indices
std::sort(row_indices.begin(), row_indices.end(), std::greater{});
for (const int row : row_indices)
{
DeleteWatch(row);
// Sort greatest to smallest, so we don't stomp on existing indices
std::sort(row_indices.begin(), row_indices.end(), std::greater{});
for (const int row : row_indices)
{
DeleteWatch(guard, row);
}
}
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);
}
void WatchWidget::DeleteWatchAndUpdate(int row)
{
DeleteWatch(row);
{
Core::CPUThreadGuard guard;
DeleteWatch(guard, row);
}
Update();
}
@ -489,18 +502,21 @@ void WatchWidget::AddWatch(QString name, u32 addr)
void WatchWidget::LockSelectedWatches()
{
for (const auto& index : m_table->selectionModel()->selectedRows())
{
const auto* item = m_table->item(index.row(), index.column());
const auto row_variant = item->data(Qt::UserRole);
if (row_variant.isNull())
continue;
const int row = row_variant.toInt();
const auto& watch = PowerPC::debug_interface.GetWatch(row);
if (watch.locked)
continue;
PowerPC::debug_interface.UpdateWatchLockedState(row, true);
LockWatchAddress(watch.address);
Core::CPUThreadGuard guard;
for (const auto& index : m_table->selectionModel()->selectedRows())
{
const auto* item = m_table->item(index.row(), index.column());
const auto row_variant = item->data(Qt::UserRole);
if (row_variant.isNull())
continue;
const int row = row_variant.toInt();
const auto& watch = PowerPC::debug_interface.GetWatch(row);
if (watch.locked)
continue;
PowerPC::debug_interface.UpdateWatchLockedState(row, true);
LockWatchAddress(guard, watch.address);
}
}
Update();
@ -508,18 +524,21 @@ void WatchWidget::LockSelectedWatches()
void WatchWidget::UnlockSelectedWatches()
{
for (const auto& index : m_table->selectionModel()->selectedRows())
{
const auto* item = m_table->item(index.row(), index.column());
const auto row_variant = item->data(Qt::UserRole);
if (row_variant.isNull())
continue;
const int row = row_variant.toInt();
const auto& watch = PowerPC::debug_interface.GetWatch(row);
if (!watch.locked)
continue;
PowerPC::debug_interface.UpdateWatchLockedState(row, false);
PowerPC::debug_interface.UnsetPatch(watch.address);
Core::CPUThreadGuard guard;
for (const auto& index : m_table->selectionModel()->selectedRows())
{
const auto* item = m_table->item(index.row(), index.column());
const auto row_variant = item->data(Qt::UserRole);
if (row_variant.isNull())
continue;
const int row = row_variant.toInt();
const auto& watch = PowerPC::debug_interface.GetWatch(row);
if (!watch.locked)
continue;
PowerPC::debug_interface.UpdateWatchLockedState(row, false);
PowerPC::debug_interface.UnsetPatch(guard, watch.address);
}
}
Update();

View File

@ -14,6 +14,11 @@ class QTableWidget;
class QTableWidgetItem;
class QToolBar;
namespace Core
{
class CPUThreadGuard;
};
class WatchWidget : public QDockWidget
{
Q_OBJECT
@ -46,9 +51,9 @@ private:
void ShowContextMenu();
void OnItemChanged(QTableWidgetItem* item);
void LockWatchAddress(u32 address);
void LockWatchAddress(const Core::CPUThreadGuard& guard, u32 address);
void DeleteSelectedWatches();
void DeleteWatch(int row);
void DeleteWatch(const Core::CPUThreadGuard& guard, int row);
void DeleteWatchAndUpdate(int row);
void AddWatchBreakpoint(int row);
void ShowInMemory(int row);

View File

@ -1186,25 +1186,29 @@ void MenuBar::ClearSymbols()
void MenuBar::GenerateSymbolsFromAddress()
{
Core::CPUThreadGuard guard;
auto& system = Core::System::GetInstance();
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);
emit NotifySymbolsUpdated();
}
void MenuBar::GenerateSymbolsFromSignatureDB()
{
Core::CPUThreadGuard guard;
auto& system = Core::System::GetInstance();
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);
SignatureDB db(SignatureDB::HandlerType::DSY);
if (db.Load(File::GetSysDirectory() + TOTALDB))
{
db.Apply(&g_symbolDB);
db.Apply(guard, &g_symbolDB);
ModalMessageBox::information(
this, tr("Information"),
tr("Generated symbol names from '%1'").arg(QString::fromStdString(TOTALDB)));
@ -1240,10 +1244,12 @@ void MenuBar::GenerateSymbolsFromRSO()
return;
}
Core::CPUThreadGuard guard;
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();
}
else
@ -1293,9 +1299,12 @@ void MenuBar::GenerateSymbolsFromRSOAuto()
RSOChainView rso_chain;
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();
}
else
@ -1306,6 +1315,8 @@ void MenuBar::GenerateSymbolsFromRSOAuto()
RSOVector MenuBar::DetectRSOModules(ParallelProgressDialog& progress)
{
Core::CPUThreadGuard guard;
constexpr std::array<std::string_view, 2> search_for = {".elf", ".plf"};
const AddressSpace::Accessors* accessors =
@ -1324,8 +1335,8 @@ RSOVector MenuBar::DetectRSOModules(ParallelProgressDialog& progress)
return matches;
}
auto found_addr =
accessors->Search(next, reinterpret_cast<const u8*>(str.data()), str.size() + 1, true);
auto found_addr = accessors->Search(guard, next, reinterpret_cast<const u8*>(str.data()),
str.size() + 1, true);
if (!found_addr.has_value())
break;
@ -1334,13 +1345,13 @@ RSOVector MenuBar::DetectRSOModules(ParallelProgressDialog& progress)
// Non-null data can precede the module name.
// 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;
u32 len = 0;
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))
{
break;
@ -1375,12 +1386,12 @@ RSOVector MenuBar::DetectRSOModules(ParallelProgressDialog& progress)
// Get the field (Module Name Offset) that point to the string
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())
continue;
// 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())
{
found_addr = module_name_offset_addr;
@ -1392,11 +1403,11 @@ RSOVector MenuBar::DetectRSOModules(ParallelProgressDialog& progress)
if (!found)
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
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()));
}
@ -1416,11 +1427,16 @@ void MenuBar::LoadSymbolMap()
if (!map_exists)
{
g_symbolDB.Clear();
PPCAnalyst::FindFunctions(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(&g_symbolDB);
{
Core::CPUThreadGuard guard;
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"),
tr("'%1' not found, scanning for common functions instead")
@ -1505,7 +1521,13 @@ void MenuBar::SaveCode()
const std::string path =
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(
this, tr("Error"),
@ -1515,7 +1537,9 @@ void MenuBar::SaveCode()
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));
return false;
@ -1596,7 +1620,10 @@ void MenuBar::ApplySignatureFile()
const std::string load_path = file.toStdString();
SignatureDB db(load_path);
db.Load(load_path);
db.Apply(&g_symbolDB);
{
Core::CPUThreadGuard guard;
db.Apply(guard, &g_symbolDB);
}
db.List();
auto& system = Core::System::GetInstance();
HLE::PatchFunctions(system);
@ -1665,12 +1692,14 @@ void MenuBar::SearchInstruction()
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
Core::CPUThreadGuard guard;
bool found = false;
for (u32 addr = Memory::MEM1_BASE_ADDR; addr < Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal();
addr += 4)
{
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)
{
NOTICE_LOG_FMT(POWERPC, "Found {} at {:08x}", op.toStdString(), addr);