Skip to content

Commit

Permalink
Debugger: Wait for the entry point to run before scanning from memory
Browse files Browse the repository at this point in the history
  • Loading branch information
chaoticgd authored and F0bes committed Jan 20, 2025
1 parent 36d8e5f commit a930daf
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 18 deletions.
94 changes: 77 additions & 17 deletions pcsx2/DebugTools/SymbolImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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);
});
});
}
Expand All @@ -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)
Expand Down
13 changes: 12 additions & 1 deletion pcsx2/DebugTools/SymbolImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include "Config.h"
#include "SymbolGuardian.h"

#include <condition_variable>

class DebugInterface;

class SymbolImporter
Expand All @@ -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();

Expand All @@ -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();
Expand Down Expand Up @@ -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;
};

Expand Down
4 changes: 4 additions & 0 deletions pcsx2/SaveState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -80,6 +81,9 @@ static void PostLoadPrep()
CBreakPoints::SetSkipFirst(BREAKPOINT_IOP, 0);

UpdateVSyncRate(true);

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

// --------------------------------------------------------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions pcsx2/VMManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2789,6 +2789,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()
Expand Down

0 comments on commit a930daf

Please sign in to comment.