Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debugger: Wait for the entry point to run before scanning from memory #12195

Merged
merged 1 commit into from
Jan 20, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Debugger: Wait for the entry point to run before scanning from memory
chaoticgd committed Jan 16, 2025
commit 690c6dc8124d26efb02af89ae68aec55ad921da0
94 changes: 77 additions & 17 deletions pcsx2/DebugTools/SymbolImporter.cpp
Original file line number Diff line number Diff line change
@@ -97,11 +97,20 @@ void SymbolImporter::OnElfChanged(std::vector<u8> elf, const std::string& elf_fi
return;
}

AnalyseElf(std::move(elf), elf_file_name, EmuConfig.DebuggerAnalysis);
AnalyseElf(std::move(elf), elf_file_name, EmuConfig.DebuggerAnalysis, true);

m_symbol_table_loaded_on_boot = true;
}

void SymbolImporter::OnElfLoadedInMemory()
{
{
std::lock_guard lock(m_elf_loaded_in_memory_mutex);
m_elf_loaded_in_memory = true;
}
m_elf_loaded_in_memory_condition_variable.notify_one();
}

void SymbolImporter::OnDebuggerOpened()
{
m_debugger_open = true;
@@ -165,11 +174,23 @@ void SymbolImporter::LoadAndAnalyseElf(Pcsx2Config::DebugAnalysisOptions options
return;
}

AnalyseElf(elfo.ReleaseData(), elf_path, options);
AnalyseElf(elfo.ReleaseData(), elf_path, options, false);
}

struct SymbolImporterThreadParameters
{
std::vector<u8> elf;
std::string elf_file_name;
std::string nocash_path;
Pcsx2Config::DebugAnalysisOptions options;
bool wait_until_elf_is_loaded;
};

void SymbolImporter::AnalyseElf(
std::vector<u8> elf, const std::string& elf_file_name, Pcsx2Config::DebugAnalysisOptions options)
std::vector<u8> elf,
const std::string& elf_file_name,
Pcsx2Config::DebugAnalysisOptions options,
bool wait_until_elf_is_loaded)
{
// Search for a .sym file to load symbols from.
std::string nocash_path;
@@ -185,38 +206,63 @@ void SymbolImporter::AnalyseElf(
nocash_path = iso_file_path.substr(0, n) + ".sym";
}

ccc::Result<ccc::ElfFile> parsed_elf = ccc::ElfFile::parse(std::move(elf));
if (!parsed_elf.success())
{
ccc::report_error(parsed_elf.error());
return;
}

ccc::ElfSymbolFile symbol_file(std::move(*parsed_elf), std::move(elf_file_name));
SymbolImporterThreadParameters parameters;
parameters.elf = std::move(elf);
parameters.elf_file_name = elf_file_name;
parameters.nocash_path = std::move(nocash_path);
parameters.options = std::move(options);
parameters.wait_until_elf_is_loaded = wait_until_elf_is_loaded;

ShutdownWorkerThread();

m_import_thread = std::thread([this, nocash_path, options, worker_symbol_file = std::move(symbol_file), builtins = m_builtin_types]() {
m_import_thread = std::thread([this, params = std::move(parameters)]() {
Threading::SetNameOfCurrentThread("Symbol Worker");

ccc::Result<ccc::ElfFile> parsed_elf = ccc::ElfFile::parse(std::move(params.elf));
if (!parsed_elf.success())
{
ccc::report_error(parsed_elf.error());
return;
}

ccc::ElfSymbolFile symbol_file(std::move(*parsed_elf), std::move(params.elf_file_name));

ccc::SymbolDatabase temp_database;

ImportSymbols(temp_database, worker_symbol_file, nocash_path, options, builtins, &m_interrupt_import_thread);
ImportSymbols(
temp_database,
symbol_file,
params.nocash_path,
params.options,
m_builtin_types,
&m_interrupt_import_thread);

if (m_interrupt_import_thread)
return;

if (options.GenerateFunctionHashes)
if (params.options.GenerateFunctionHashes)
{
ElfMemoryReader reader(worker_symbol_file.elf());
ElfMemoryReader reader(symbol_file.elf());
SymbolGuardian::GenerateFunctionHashes(temp_database, reader);
}

if (m_interrupt_import_thread)
return;

if (params.wait_until_elf_is_loaded && params.options.FunctionScanMode == DebugFunctionScanMode::SCAN_MEMORY)
{
// Wait for the entry point to start compiling on the CPU thread so
// we know the functions we want to scan are loaded in memory.
std::unique_lock lock(m_elf_loaded_in_memory_mutex);
m_elf_loaded_in_memory_condition_variable.wait(lock,
[this]() { return m_elf_loaded_in_memory; });

if (m_interrupt_import_thread)
return;
}

m_guardian.ReadWrite([&](ccc::SymbolDatabase& database) {
ClearExistingSymbols(database, options);
ClearExistingSymbols(database, params.options);

if (m_interrupt_import_thread)
return;
@@ -229,7 +275,7 @@ void SymbolImporter::AnalyseElf(
// The function scanner has to be run on the main database so that
// functions created before the importer was run are still
// considered. Otherwise, duplicate functions will be created.
ScanForFunctions(database, worker_symbol_file, options);
ScanForFunctions(database, symbol_file, params.options);
});
});
}
@@ -239,9 +285,23 @@ void SymbolImporter::ShutdownWorkerThread()
if (m_import_thread.joinable())
{
m_interrupt_import_thread = true;

// Make sure the import thread is woken up so we can shut it down.
{
std::lock_guard lock(m_elf_loaded_in_memory_mutex);
m_elf_loaded_in_memory = true;
}
m_elf_loaded_in_memory_condition_variable.notify_one();

m_import_thread.join();

m_interrupt_import_thread = false;
}

{
std::lock_guard lock(m_elf_loaded_in_memory_mutex);
m_elf_loaded_in_memory = false;
}
}

void SymbolImporter::ClearExistingSymbols(ccc::SymbolDatabase& database, const Pcsx2Config::DebugAnalysisOptions& options)
13 changes: 12 additions & 1 deletion pcsx2/DebugTools/SymbolImporter.h
Original file line number Diff line number Diff line change
@@ -6,6 +6,8 @@
#include "Config.h"
#include "SymbolGuardian.h"

#include <condition_variable>

class DebugInterface;

class SymbolImporter
@@ -17,6 +19,7 @@ class SymbolImporter
// that are used to determine when symbol tables should be loaded, and
// should be called from the CPU thread.
void OnElfChanged(std::vector<u8> elf, const std::string& elf_file_name);
void OnElfLoadedInMemory();
void OnDebuggerOpened();
void OnDebuggerClosed();

@@ -30,7 +33,11 @@ class SymbolImporter

// Import symbols from the ELF file, nocash symbols, and scan for functions.
// Should be called from the CPU thread.
void AnalyseElf(std::vector<u8> elf, const std::string& elf_file_name, Pcsx2Config::DebugAnalysisOptions options);
void AnalyseElf(
std::vector<u8> elf,
const std::string& elf_file_name,
Pcsx2Config::DebugAnalysisOptions options,
bool wait_until_elf_is_loaded);

// Interrupt the import thread. Should be called from the CPU thread.
void ShutdownWorkerThread();
@@ -77,6 +84,10 @@ class SymbolImporter
std::thread m_import_thread;
std::atomic_bool m_interrupt_import_thread = false;

std::mutex m_elf_loaded_in_memory_mutex;
std::condition_variable m_elf_loaded_in_memory_condition_variable;
bool m_elf_loaded_in_memory = false;

std::map<std::string, ccc::DataTypeHandle> m_builtin_types;
};

4 changes: 4 additions & 0 deletions pcsx2/SaveState.cpp
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
#include "Config.h"
#include "Counters.h"
#include "DebugTools/Breakpoints.h"
#include "DebugTools/SymbolImporter.h"
#include "Elfheader.h"
#include "GS.h"
#include "GS/GS.h"
@@ -80,6 +81,9 @@ static void PostLoadPrep()
CBreakPoints::SetSkipFirst(BREAKPOINT_IOP, 0);

UpdateVSyncRate(true);

if (VMManager::Internal::HasBootedELF())
R5900SymbolImporter.OnElfLoadedInMemory();
}

// --------------------------------------------------------------------------------------
2 changes: 2 additions & 0 deletions pcsx2/VMManager.cpp
Original file line number Diff line number Diff line change
@@ -2779,6 +2779,8 @@ void VMManager::Internal::EntryPointCompilingOnCPUThread()
// Toss all the recs, we're going to be executing new code.
mmap_ResetBlockTracking();
ClearCPUExecutionCaches();

R5900SymbolImporter.OnElfLoadedInMemory();
}

void VMManager::Internal::VSyncOnCPUThread()