mirror of https://github.com/PCSX2/pcsx2.git
Debugger: Allow loading symbols conditionally and with a base address
This commit is contained in:
parent
efb43ac7f9
commit
cce0ae4369
|
@ -100,8 +100,9 @@ Result<std::unique_ptr<SymbolTable>> create_elf_symbol_table(
|
|||
|
||||
Result<ModuleHandle> import_symbol_tables(
|
||||
SymbolDatabase& database,
|
||||
std::string module_name,
|
||||
const std::vector<std::unique_ptr<SymbolTable>>& symbol_tables,
|
||||
std::string module_name,
|
||||
Address base_address,
|
||||
u32 importer_flags,
|
||||
DemanglerFunctions demangler,
|
||||
const std::atomic_bool* interrupt)
|
||||
|
@ -109,7 +110,8 @@ Result<ModuleHandle> import_symbol_tables(
|
|||
Result<SymbolSourceHandle> module_source = database.get_symbol_source("Symbol Table Importer");
|
||||
CCC_RETURN_IF_ERROR(module_source);
|
||||
|
||||
Result<Module*> module_symbol = database.modules.create_symbol(std::move(module_name), *module_source, nullptr);
|
||||
Result<Module*> module_symbol = database.modules.create_symbol(
|
||||
std::move(module_name), base_address, *module_source, nullptr);
|
||||
CCC_RETURN_IF_ERROR(module_symbol);
|
||||
|
||||
ModuleHandle module_handle = (*module_symbol)->handle();
|
||||
|
|
|
@ -71,8 +71,9 @@ Result<std::unique_ptr<SymbolTable>> create_elf_symbol_table(
|
|||
// and to generate a module handle.
|
||||
Result<ModuleHandle> import_symbol_tables(
|
||||
SymbolDatabase& database,
|
||||
std::string module_name,
|
||||
const std::vector<std::unique_ptr<SymbolTable>>& symbol_tables,
|
||||
std::string module_name,
|
||||
Address base_address,
|
||||
u32 importer_flags,
|
||||
DemanglerFunctions demangler,
|
||||
const std::atomic_bool* interrupt);
|
||||
|
|
|
@ -104,7 +104,7 @@ DebugAnalysisSettingsWidget::DebugAnalysisSettingsWidget(SettingsWindow* dialog,
|
|||
else
|
||||
{
|
||||
m_ui.symbolFileLabel->hide();
|
||||
m_ui.symbolFileList->hide();
|
||||
m_ui.symbolFileTable->hide();
|
||||
m_ui.importSymbolFileButtons->hide();
|
||||
}
|
||||
|
||||
|
@ -165,18 +165,19 @@ void DebugAnalysisSettingsWidget::parseSettingsFromWidgets(Pcsx2Config::DebugAna
|
|||
output.DemangleSymbols = m_ui.demangleSymbols->isChecked();
|
||||
output.DemangleParameters = m_ui.demangleParameters->isChecked();
|
||||
|
||||
for (int i = 0; i < m_ui.symbolFileList->count(); i++)
|
||||
for (int i = 0; i < m_symbol_file_model->rowCount(); i++)
|
||||
{
|
||||
DebugExtraSymbolFile& file = output.ExtraSymbolFiles.emplace_back();
|
||||
file.Path = m_ui.symbolFileList->item(i)->text().toStdString();
|
||||
|
||||
file.Path = m_symbol_file_model->item(i, PATH_COLUMN)->text().toStdString();
|
||||
file.BaseAddress = m_symbol_file_model->item(i, BASE_ADDRESS_COLUMN)->text().toStdString();
|
||||
file.Condition = m_symbol_file_model->item(i, CONDITION_COLUMN)->text().toStdString();
|
||||
}
|
||||
|
||||
output.FunctionScanMode = static_cast<DebugFunctionScanMode>(m_ui.functionScanMode->currentIndex());
|
||||
output.CustomFunctionScanRange = m_ui.customAddressRange->isChecked();
|
||||
output.FunctionScanStartAddress = m_ui.addressRangeStart->text().toStdString();
|
||||
output.FunctionScanEndAddress = m_ui.addressRangeEnd->text().toStdString();
|
||||
|
||||
output.GenerateFunctionHashes = m_ui.grayOutOverwrittenFunctions->isChecked();
|
||||
}
|
||||
|
||||
void DebugAnalysisSettingsWidget::setupSymbolSourceGrid()
|
||||
|
@ -187,27 +188,12 @@ void DebugAnalysisSettingsWidget::setupSymbolSourceGrid()
|
|||
{
|
||||
// Add symbol sources for which the user has already selected whether or
|
||||
// not they should be cleared.
|
||||
int existing_symbol_source_count;
|
||||
if (m_dialog)
|
||||
existing_symbol_source_count = m_dialog->getEffectiveIntValue("Debugger/Analysis/SymbolSources", "Count", 0);
|
||||
else
|
||||
existing_symbol_source_count = Host::GetIntSettingValue("Debugger/Analysis/SymbolSources", "Count", 0);
|
||||
|
||||
int existing_symbol_source_count = getIntSettingValue("Debugger/Analysis/SymbolSources", "Count", 0);
|
||||
for (int i = 0; i < existing_symbol_source_count; i++)
|
||||
{
|
||||
std::string section = "Debugger/Analysis/SymbolSources/" + std::to_string(i);
|
||||
|
||||
std::string name;
|
||||
if (m_dialog)
|
||||
name = m_dialog->getEffectiveStringValue(section.c_str(), "Name", "");
|
||||
else
|
||||
name = Host::GetStringSettingValue(section.c_str(), "Name", "");
|
||||
|
||||
bool value;
|
||||
if (m_dialog)
|
||||
value = m_dialog->getEffectiveBoolValue(section.c_str(), "ClearDuringAnalysis", false);
|
||||
else
|
||||
value = Host::GetBoolSettingValue(section.c_str(), "ClearDuringAnalysis", false);
|
||||
std::string name = getStringSettingValue(section.c_str(), "Name", "");
|
||||
bool value = getBoolSettingValue(section.c_str(), "ClearDuringAnalysis", false);
|
||||
|
||||
SymbolSourceTemp& source = m_symbol_sources[name];
|
||||
source.previous_value = value;
|
||||
|
@ -320,45 +306,100 @@ void DebugAnalysisSettingsWidget::saveSymbolSources()
|
|||
|
||||
void DebugAnalysisSettingsWidget::setupSymbolFileList()
|
||||
{
|
||||
int extra_symbol_file_count;
|
||||
if (m_dialog)
|
||||
extra_symbol_file_count = m_dialog->getEffectiveIntValue("Debugger/Analysis/ExtraSymbolFiles", "Count", 0);
|
||||
else
|
||||
extra_symbol_file_count = Host::GetIntSettingValue("Debugger/Analysis/ExtraSymbolFiles", "Count", 0);
|
||||
m_symbol_file_model = new QStandardItemModel(0, SYMBOL_FILE_COLUMN_COUNT, m_ui.symbolFileTable);
|
||||
|
||||
QStringList headers;
|
||||
headers.emplace_back(tr("Path"));
|
||||
headers.emplace_back(tr("Base Address"));
|
||||
headers.emplace_back(tr("Condition"));
|
||||
m_symbol_file_model->setHorizontalHeaderLabels(headers);
|
||||
|
||||
m_ui.symbolFileTable->setModel(m_symbol_file_model);
|
||||
|
||||
m_ui.symbolFileTable->horizontalHeader()->setSectionResizeMode(PATH_COLUMN, QHeaderView::Stretch);
|
||||
m_ui.symbolFileTable->horizontalHeader()->setSectionResizeMode(BASE_ADDRESS_COLUMN, QHeaderView::Fixed);
|
||||
m_ui.symbolFileTable->horizontalHeader()->setSectionResizeMode(CONDITION_COLUMN, QHeaderView::Fixed);
|
||||
|
||||
m_ui.symbolFileTable->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
|
||||
int extra_symbol_file_count = getIntSettingValue("Debugger/Analysis/ExtraSymbolFiles", "Count", 0);
|
||||
for (int i = 0; i < extra_symbol_file_count; i++)
|
||||
{
|
||||
std::string section = "Debugger/Analysis/ExtraSymbolFiles/" + std::to_string(i);
|
||||
std::string path;
|
||||
if (m_dialog)
|
||||
path = m_dialog->getEffectiveStringValue(section.c_str(), "Path", "");
|
||||
else
|
||||
path = Host::GetStringSettingValue(section.c_str(), "Path", "");
|
||||
|
||||
m_ui.symbolFileList->addItem(QString::fromStdString(path));
|
||||
int row = m_symbol_file_model->rowCount();
|
||||
if (!m_symbol_file_model->insertRow(row))
|
||||
continue;
|
||||
|
||||
QStandardItem* path_item = new QStandardItem();
|
||||
path_item->setText(QString::fromStdString(getStringSettingValue(section.c_str(), "Path", "")));
|
||||
m_symbol_file_model->setItem(row, PATH_COLUMN, path_item);
|
||||
|
||||
QStandardItem* base_address_item = new QStandardItem();
|
||||
base_address_item->setText(QString::fromStdString(getStringSettingValue(section.c_str(), "BaseAddress")));
|
||||
m_symbol_file_model->setItem(row, BASE_ADDRESS_COLUMN, base_address_item);
|
||||
|
||||
QStandardItem* condition_item = new QStandardItem();
|
||||
condition_item->setText(QString::fromStdString(getStringSettingValue(section.c_str(), "Condition")));
|
||||
m_symbol_file_model->setItem(row, CONDITION_COLUMN, condition_item);
|
||||
}
|
||||
|
||||
connect(m_ui.addSymbolFile, &QPushButton::clicked, this, &DebugAnalysisSettingsWidget::addSymbolFile);
|
||||
connect(m_ui.removeSymbolFile, &QPushButton::clicked, this, &DebugAnalysisSettingsWidget::removeSymbolFile);
|
||||
|
||||
connect(m_ui.symbolFileTable->selectionModel(), &QItemSelectionModel::selectionChanged,
|
||||
this, &DebugAnalysisSettingsWidget::updateEnabledStates);
|
||||
|
||||
connect(m_symbol_file_model, &QStandardItemModel::dataChanged,
|
||||
this, &DebugAnalysisSettingsWidget::saveSymbolFiles);
|
||||
connect(m_symbol_file_model, &QStandardItemModel::dataChanged,
|
||||
this, &DebugAnalysisSettingsWidget::updateEnabledStates);
|
||||
}
|
||||
|
||||
void DebugAnalysisSettingsWidget::addSymbolFile()
|
||||
{
|
||||
QString path = QDir::toNativeSeparators(QFileDialog::getOpenFileName(this, tr("Add Symbol File")));
|
||||
if (path.isEmpty())
|
||||
std::string path = Path::ToNativePath(QFileDialog::getOpenFileName(this, tr("Add Symbol File")).toStdString());
|
||||
if (path.empty())
|
||||
return;
|
||||
|
||||
m_ui.symbolFileList->addItem(path);
|
||||
std::string relative_path = Path::MakeRelative(path, EmuFolders::GameSettings);
|
||||
if (!relative_path.starts_with(".."))
|
||||
path = std::move(relative_path);
|
||||
|
||||
int row = m_symbol_file_model->rowCount();
|
||||
if (!m_symbol_file_model->insertRow(row))
|
||||
return;
|
||||
|
||||
QStandardItem* path_item = new QStandardItem();
|
||||
path_item->setText(QString::fromStdString(path));
|
||||
m_symbol_file_model->setItem(row, PATH_COLUMN, path_item);
|
||||
|
||||
QStandardItem* base_address_item = new QStandardItem();
|
||||
base_address_item->setText("");
|
||||
m_symbol_file_model->setItem(row, BASE_ADDRESS_COLUMN, base_address_item);
|
||||
|
||||
QStandardItem* condition_item = new QStandardItem();
|
||||
condition_item->setText("");
|
||||
m_symbol_file_model->setItem(row, CONDITION_COLUMN, condition_item);
|
||||
|
||||
saveSymbolFiles();
|
||||
updateEnabledStates();
|
||||
}
|
||||
|
||||
void DebugAnalysisSettingsWidget::removeSymbolFile()
|
||||
{
|
||||
for (QListWidgetItem* item : m_ui.symbolFileList->selectedItems())
|
||||
delete item;
|
||||
QItemSelectionModel* selection_model = m_ui.symbolFileTable->selectionModel();
|
||||
if (!selection_model)
|
||||
return;
|
||||
|
||||
while (!selection_model->selectedIndexes().isEmpty())
|
||||
{
|
||||
QModelIndex index = selection_model->selectedIndexes().first();
|
||||
m_symbol_file_model->removeRow(index.row(), index.parent());
|
||||
}
|
||||
|
||||
saveSymbolFiles();
|
||||
updateEnabledStates();
|
||||
}
|
||||
|
||||
void DebugAnalysisSettingsWidget::saveSymbolFiles()
|
||||
|
@ -380,17 +421,24 @@ void DebugAnalysisSettingsWidget::saveSymbolFiles()
|
|||
|
||||
sif->RemoveSection("Debugger/Analysis/ExtraSymbolFiles");
|
||||
|
||||
if (m_ui.symbolFileList->count() == 0)
|
||||
if (m_symbol_file_model->rowCount() == 0)
|
||||
return;
|
||||
|
||||
// Make new configuration entries.
|
||||
sif->SetIntValue("Debugger/Analysis/ExtraSymbolFiles", "Count", m_ui.symbolFileList->count());
|
||||
sif->SetIntValue("Debugger/Analysis/ExtraSymbolFiles", "Count", m_symbol_file_model->rowCount());
|
||||
|
||||
for (int i = 0; i < m_ui.symbolFileList->count(); i++)
|
||||
for (int i = 0; i < m_symbol_file_model->rowCount(); i++)
|
||||
{
|
||||
std::string section = "Debugger/Analysis/ExtraSymbolFiles/" + std::to_string(i);
|
||||
std::string path = m_ui.symbolFileList->item(i)->text().toStdString();
|
||||
sif->SetStringValue(section.c_str(), "Path", path.c_str());
|
||||
|
||||
if (QStandardItem* path_item = m_symbol_file_model->item(i, PATH_COLUMN))
|
||||
sif->SetStringValue(section.c_str(), "Path", path_item->text().toStdString().c_str());
|
||||
|
||||
if (QStandardItem* base_address_item = m_symbol_file_model->item(i, BASE_ADDRESS_COLUMN))
|
||||
sif->SetStringValue(section.c_str(), "BaseAddress", base_address_item->text().toStdString().c_str());
|
||||
|
||||
if (QStandardItem* condition_item = m_symbol_file_model->item(i, CONDITION_COLUMN))
|
||||
sif->SetStringValue(section.c_str(), "Condition", condition_item->text().toStdString().c_str());
|
||||
}
|
||||
|
||||
QtHost::SaveGameSettings(sif, true);
|
||||
|
@ -423,5 +471,34 @@ void DebugAnalysisSettingsWidget::updateEnabledStates()
|
|||
m_ui.symbolSourceScrollArea->setEnabled(!m_ui.automaticallyClearSymbols->isChecked());
|
||||
m_ui.symbolSourceErrorMessage->setEnabled(!m_ui.automaticallyClearSymbols->isChecked());
|
||||
m_ui.demangleParameters->setEnabled(m_ui.demangleSymbols->isChecked());
|
||||
m_ui.removeSymbolFile->setEnabled(
|
||||
m_ui.symbolFileTable->selectionModel() && m_ui.symbolFileTable->selectionModel()->hasSelection());
|
||||
m_ui.customAddressRangeLineEdits->setEnabled(m_ui.customAddressRange->isChecked());
|
||||
}
|
||||
|
||||
std::string DebugAnalysisSettingsWidget::getStringSettingValue(
|
||||
const char* section, const char* key, const char* default_value)
|
||||
{
|
||||
if (m_dialog)
|
||||
return m_dialog->getEffectiveStringValue(section, key, default_value);
|
||||
|
||||
return Host::GetStringSettingValue(section, key, default_value);
|
||||
}
|
||||
|
||||
bool DebugAnalysisSettingsWidget::getBoolSettingValue(
|
||||
const char* section, const char* key, bool default_value)
|
||||
{
|
||||
if (m_dialog)
|
||||
return m_dialog->getEffectiveBoolValue(section, key, default_value);
|
||||
|
||||
return Host::GetBoolSettingValue(section, key, default_value);
|
||||
}
|
||||
|
||||
int DebugAnalysisSettingsWidget::getIntSettingValue(
|
||||
const char* section, const char* key, int default_value)
|
||||
{
|
||||
if (m_dialog)
|
||||
return m_dialog->getEffectiveIntValue(section, key, default_value);
|
||||
|
||||
return Host::GetIntSettingValue(section, key, default_value);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "Config.h"
|
||||
|
||||
#include <QtGui/QStandardItemModel>
|
||||
#include <QtWidgets/QDialog>
|
||||
|
||||
class SettingsWindow;
|
||||
|
@ -16,7 +17,7 @@ class DebugAnalysisSettingsWidget : public QWidget
|
|||
|
||||
public:
|
||||
// Create a widget that will discard any settings changed after it is
|
||||
// closed, for use in the dialog opened by the "Reanalyze" button.
|
||||
// closed, for use in the dialog opened by the "Analyze" button.
|
||||
DebugAnalysisSettingsWidget(QWidget* parent = nullptr);
|
||||
|
||||
// Create a widget that will write back any settings changed to the config
|
||||
|
@ -42,6 +43,10 @@ protected:
|
|||
|
||||
void updateEnabledStates();
|
||||
|
||||
std::string getStringSettingValue(const char* section, const char* key, const char* default_value = "");
|
||||
bool getBoolSettingValue(const char* section, const char* key, bool default_value = false);
|
||||
int getIntSettingValue(const char* section, const char* key, int default_value = 0);
|
||||
|
||||
struct SymbolSourceTemp
|
||||
{
|
||||
QCheckBox* check_box = nullptr;
|
||||
|
@ -49,8 +54,18 @@ protected:
|
|||
bool modified_by_user = false;
|
||||
};
|
||||
|
||||
enum SymbolFileColumn
|
||||
{
|
||||
PATH_COLUMN = 0,
|
||||
BASE_ADDRESS_COLUMN = 1,
|
||||
CONDITION_COLUMN = 2,
|
||||
SYMBOL_FILE_COLUMN_COUNT = 3
|
||||
};
|
||||
|
||||
SettingsWindow* m_dialog = nullptr;
|
||||
std::map<std::string, SymbolSourceTemp> m_symbol_sources;
|
||||
|
||||
QStandardItemModel* m_symbol_file_model;
|
||||
|
||||
Ui::DebugAnalysisSettingsWidget m_ui;
|
||||
};
|
||||
|
|
|
@ -171,7 +171,7 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="symbolFileList">
|
||||
<widget class="QTableView" name="symbolFileTable">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
|
@ -184,9 +184,27 @@
|
|||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="textElideMode">
|
||||
<enum>Qt::ElideLeft</enum>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderHighlightSections">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
|
|
@ -208,6 +208,8 @@ struct DebugSymbolSource
|
|||
struct DebugExtraSymbolFile
|
||||
{
|
||||
std::string Path;
|
||||
std::string BaseAddress;
|
||||
std::string Condition;
|
||||
|
||||
friend auto operator<=>(const DebugExtraSymbolFile& lhs, const DebugExtraSymbolFile& rhs) = default;
|
||||
};
|
||||
|
@ -1276,7 +1278,7 @@ struct Pcsx2Config
|
|||
EnableGameFixes : 1, // enables automatic game fixes
|
||||
SaveStateOnShutdown : 1, // default value for saving state on shutdown
|
||||
EnableDiscordPresence : 1, // enables discord rich presence integration
|
||||
UseSavestateSelector: 1,
|
||||
UseSavestateSelector : 1,
|
||||
InhibitScreensaver : 1,
|
||||
BackupSavestate : 1,
|
||||
McdFolderAutoManage : 1,
|
||||
|
|
|
@ -34,227 +34,6 @@ enum ReferenceIndexType
|
|||
REF_INDEX_VFPU = 0x10000,
|
||||
REF_INDEX_VFPU_INT = 0x20000,
|
||||
REF_INDEX_IS_FLOAT = REF_INDEX_FPU | REF_INDEX_VFPU,
|
||||
|
||||
};
|
||||
|
||||
|
||||
class MipsExpressionFunctions : public IExpressionFunctions
|
||||
{
|
||||
public:
|
||||
explicit MipsExpressionFunctions(DebugInterface* cpu, bool enumerateSymbols)
|
||||
: m_cpu(cpu)
|
||||
{
|
||||
if (!enumerateSymbols)
|
||||
return;
|
||||
|
||||
m_cpu->GetSymbolGuardian().Read([&](const ccc::SymbolDatabase& database) {
|
||||
for (const ccc::Function& function : database.functions)
|
||||
m_mangled_function_names_to_handles.emplace(function.mangled_name(), function.handle());
|
||||
|
||||
for (const ccc::GlobalVariable& global : database.global_variables)
|
||||
m_mangled_global_names_to_handles.emplace(global.mangled_name(), global.handle());
|
||||
});
|
||||
}
|
||||
|
||||
virtual bool parseReference(char* str, u64& referenceIndex)
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
char reg[8];
|
||||
std::snprintf(reg, std::size(reg), "r%d", i);
|
||||
if (StringUtil::Strcasecmp(str, reg) == 0 || StringUtil::Strcasecmp(str, m_cpu->getRegisterName(0, i)) == 0)
|
||||
{
|
||||
referenceIndex = i;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::snprintf(reg, std::size(reg), "f%d", i);
|
||||
if (StringUtil::Strcasecmp(str, reg) == 0)
|
||||
{
|
||||
referenceIndex = i | REF_INDEX_FPU;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtil::Strcasecmp(str, "pc") == 0)
|
||||
{
|
||||
referenceIndex = REF_INDEX_PC;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringUtil::Strcasecmp(str, "hi") == 0)
|
||||
{
|
||||
referenceIndex = REF_INDEX_HI;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringUtil::Strcasecmp(str, "lo") == 0)
|
||||
{
|
||||
referenceIndex = REF_INDEX_LO;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringUtil::Strcasecmp(str, "target") == 0)
|
||||
{
|
||||
referenceIndex = REF_INDEX_OPTARGET;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringUtil::Strcasecmp(str, "load") == 0)
|
||||
{
|
||||
referenceIndex = REF_INDEX_OPLOAD;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringUtil::Strcasecmp(str, "store") == 0)
|
||||
{
|
||||
referenceIndex = REF_INDEX_OPSTORE;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool parseSymbol(char* str, u64& symbolValue)
|
||||
{
|
||||
bool success = false;
|
||||
m_cpu->GetSymbolGuardian().Read([&](const ccc::SymbolDatabase& database) {
|
||||
std::string name = str;
|
||||
|
||||
// Check for mangled function names.
|
||||
auto function_iterator = m_mangled_function_names_to_handles.find(name);
|
||||
if (function_iterator != m_mangled_function_names_to_handles.end())
|
||||
{
|
||||
const ccc::Function* function = database.functions.symbol_from_handle(function_iterator->second);
|
||||
if (function && function->address().valid())
|
||||
{
|
||||
symbolValue = function->address().value;
|
||||
success = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for mangled global variable names.
|
||||
auto global_iterator = m_mangled_global_names_to_handles.find(name);
|
||||
if (global_iterator != m_mangled_global_names_to_handles.end())
|
||||
{
|
||||
const ccc::GlobalVariable* global = database.global_variables.symbol_from_handle(global_iterator->second);
|
||||
if (global && global->address().valid())
|
||||
{
|
||||
symbolValue = global->address().value;
|
||||
success = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for regular unmangled names.
|
||||
const ccc::Symbol* symbol = database.symbol_with_name(name);
|
||||
if (symbol && symbol->address().valid())
|
||||
{
|
||||
symbolValue = symbol->address().value;
|
||||
success = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
virtual u64 getReferenceValue(u64 referenceIndex)
|
||||
{
|
||||
if (referenceIndex < 32)
|
||||
return m_cpu->getRegister(0, referenceIndex)._u64[0];
|
||||
if (referenceIndex == REF_INDEX_PC)
|
||||
return m_cpu->getPC();
|
||||
if (referenceIndex == REF_INDEX_HI)
|
||||
return m_cpu->getHI()._u64[0];
|
||||
if (referenceIndex == REF_INDEX_LO)
|
||||
return m_cpu->getLO()._u64[0];
|
||||
if (referenceIndex & REF_INDEX_IS_OPSL)
|
||||
{
|
||||
const u32 OP = m_cpu->read32(m_cpu->getPC());
|
||||
const R5900::OPCODE& opcode = R5900::GetInstruction(OP);
|
||||
if (opcode.flags & IS_MEMORY)
|
||||
{
|
||||
// Fetch the address in the base register
|
||||
u32 target = cpuRegs.GPR.r[(OP >> 21) & 0x1F].UD[0];
|
||||
// Add the offset (lower 16 bits)
|
||||
target += static_cast<u16>(OP);
|
||||
|
||||
if (referenceIndex & REF_INDEX_OPTARGET)
|
||||
{
|
||||
return target;
|
||||
}
|
||||
else if (referenceIndex & REF_INDEX_OPLOAD)
|
||||
{
|
||||
return (opcode.flags & IS_LOAD) ? target : 0;
|
||||
}
|
||||
else if (referenceIndex & REF_INDEX_OPSTORE)
|
||||
{
|
||||
return (opcode.flags & IS_STORE) ? target : 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (referenceIndex & REF_INDEX_FPU)
|
||||
{
|
||||
return m_cpu->getRegister(EECAT_FPR, referenceIndex & 0x1F)._u64[0];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual ExpressionType getReferenceType(u64 referenceIndex)
|
||||
{
|
||||
if (referenceIndex & REF_INDEX_IS_FLOAT)
|
||||
{
|
||||
return EXPR_TYPE_FLOAT;
|
||||
}
|
||||
return EXPR_TYPE_UINT;
|
||||
}
|
||||
|
||||
virtual bool getMemoryValue(u32 address, int size, u64& dest, std::string& error)
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
break;
|
||||
default:
|
||||
error = StringUtil::StdStringFromFormat(
|
||||
TRANSLATE("ExpressionParser", "Invalid memory access size %d."), size);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (address % size)
|
||||
{
|
||||
error = TRANSLATE("ExpressionParser", "Invalid memory access (unaligned).");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
dest = m_cpu->read8(address);
|
||||
break;
|
||||
case 2:
|
||||
dest = m_cpu->read16(address);
|
||||
break;
|
||||
case 4:
|
||||
dest = m_cpu->read32(address);
|
||||
break;
|
||||
case 8:
|
||||
dest = m_cpu->read64(address);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
DebugInterface* m_cpu;
|
||||
std::map<std::string, ccc::FunctionHandle> m_mangled_function_names_to_handles;
|
||||
std::map<std::string, ccc::GlobalVariableHandle> m_mangled_global_names_to_handles;
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -369,13 +148,13 @@ bool DebugInterface::evaluateExpression(const char* expression, u64& dest, std::
|
|||
|
||||
bool DebugInterface::initExpression(const char* exp, PostfixExpression& dest, std::string& error)
|
||||
{
|
||||
MipsExpressionFunctions funcs(this, true);
|
||||
MipsExpressionFunctions funcs(this, nullptr, true);
|
||||
return initPostfixExpression(exp, &funcs, dest, error);
|
||||
}
|
||||
|
||||
bool DebugInterface::parseExpression(PostfixExpression& exp, u64& dest, std::string& error)
|
||||
{
|
||||
MipsExpressionFunctions funcs(this, false);
|
||||
MipsExpressionFunctions funcs(this, nullptr, false);
|
||||
return parsePostfixExpression(exp, &funcs, dest, error);
|
||||
}
|
||||
|
||||
|
@ -1306,3 +1085,239 @@ u64 ElfMemoryReader::read64(u32 address, bool& valid)
|
|||
|
||||
return *result;
|
||||
}
|
||||
|
||||
//
|
||||
// MipsExpressionFunctions
|
||||
//
|
||||
|
||||
MipsExpressionFunctions::MipsExpressionFunctions(
|
||||
DebugInterface* cpu, const ccc::SymbolDatabase* symbolDatabase, bool shouldEnumerateSymbols)
|
||||
: m_cpu(cpu)
|
||||
, m_database(symbolDatabase)
|
||||
{
|
||||
if (!shouldEnumerateSymbols)
|
||||
return;
|
||||
|
||||
if (symbolDatabase)
|
||||
{
|
||||
enumerateSymbols(*symbolDatabase);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cpu->GetSymbolGuardian().Read([&](const ccc::SymbolDatabase& database) {
|
||||
enumerateSymbols(database);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void MipsExpressionFunctions::enumerateSymbols(const ccc::SymbolDatabase& database)
|
||||
{
|
||||
// TODO: Add mangled symbol name maps to CCC and remove this.
|
||||
|
||||
for (const ccc::Function& function : database.functions)
|
||||
m_mangled_function_names_to_handles.emplace(function.mangled_name(), function.handle());
|
||||
|
||||
for (const ccc::GlobalVariable& global : database.global_variables)
|
||||
m_mangled_global_names_to_handles.emplace(global.mangled_name(), global.handle());
|
||||
}
|
||||
|
||||
bool MipsExpressionFunctions::parseReference(char* str, u64& referenceIndex)
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
char reg[8];
|
||||
std::snprintf(reg, std::size(reg), "r%d", i);
|
||||
if (StringUtil::Strcasecmp(str, reg) == 0 || StringUtil::Strcasecmp(str, m_cpu->getRegisterName(0, i)) == 0)
|
||||
{
|
||||
referenceIndex = i;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::snprintf(reg, std::size(reg), "f%d", i);
|
||||
if (StringUtil::Strcasecmp(str, reg) == 0)
|
||||
{
|
||||
referenceIndex = i | REF_INDEX_FPU;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtil::Strcasecmp(str, "pc") == 0)
|
||||
{
|
||||
referenceIndex = REF_INDEX_PC;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringUtil::Strcasecmp(str, "hi") == 0)
|
||||
{
|
||||
referenceIndex = REF_INDEX_HI;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringUtil::Strcasecmp(str, "lo") == 0)
|
||||
{
|
||||
referenceIndex = REF_INDEX_LO;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringUtil::Strcasecmp(str, "target") == 0)
|
||||
{
|
||||
referenceIndex = REF_INDEX_OPTARGET;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringUtil::Strcasecmp(str, "load") == 0)
|
||||
{
|
||||
referenceIndex = REF_INDEX_OPLOAD;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringUtil::Strcasecmp(str, "store") == 0)
|
||||
{
|
||||
referenceIndex = REF_INDEX_OPSTORE;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MipsExpressionFunctions::parseSymbol(char* str, u64& symbolValue)
|
||||
{
|
||||
if (m_database)
|
||||
return parseSymbol(str, symbolValue, *m_database);
|
||||
|
||||
bool success = false;
|
||||
m_cpu->GetSymbolGuardian().Read([&](const ccc::SymbolDatabase& database) {
|
||||
success = parseSymbol(str, symbolValue, database);
|
||||
});
|
||||
return success;
|
||||
}
|
||||
|
||||
bool MipsExpressionFunctions::parseSymbol(char* str, u64& symbolValue, const ccc::SymbolDatabase& database)
|
||||
{
|
||||
std::string name = str;
|
||||
|
||||
// Check for mangled function names.
|
||||
auto function_iterator = m_mangled_function_names_to_handles.find(name);
|
||||
if (function_iterator != m_mangled_function_names_to_handles.end())
|
||||
{
|
||||
const ccc::Function* function = database.functions.symbol_from_handle(function_iterator->second);
|
||||
if (function && function->address().valid())
|
||||
{
|
||||
symbolValue = function->address().value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for mangled global variable names.
|
||||
auto global_iterator = m_mangled_global_names_to_handles.find(name);
|
||||
if (global_iterator != m_mangled_global_names_to_handles.end())
|
||||
{
|
||||
const ccc::GlobalVariable* global = database.global_variables.symbol_from_handle(global_iterator->second);
|
||||
if (global && global->address().valid())
|
||||
{
|
||||
symbolValue = global->address().value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for regular unmangled names.
|
||||
const ccc::Symbol* symbol = database.symbol_with_name(name);
|
||||
if (symbol && symbol->address().valid())
|
||||
{
|
||||
symbolValue = symbol->address().value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
u64 MipsExpressionFunctions::getReferenceValue(u64 referenceIndex)
|
||||
{
|
||||
if (referenceIndex < 32)
|
||||
return m_cpu->getRegister(0, referenceIndex)._u64[0];
|
||||
if (referenceIndex == REF_INDEX_PC)
|
||||
return m_cpu->getPC();
|
||||
if (referenceIndex == REF_INDEX_HI)
|
||||
return m_cpu->getHI()._u64[0];
|
||||
if (referenceIndex == REF_INDEX_LO)
|
||||
return m_cpu->getLO()._u64[0];
|
||||
if (referenceIndex & REF_INDEX_IS_OPSL)
|
||||
{
|
||||
const u32 OP = m_cpu->read32(m_cpu->getPC());
|
||||
const R5900::OPCODE& opcode = R5900::GetInstruction(OP);
|
||||
if (opcode.flags & IS_MEMORY)
|
||||
{
|
||||
// Fetch the address in the base register
|
||||
u32 target = cpuRegs.GPR.r[(OP >> 21) & 0x1F].UD[0];
|
||||
// Add the offset (lower 16 bits)
|
||||
target += static_cast<u16>(OP);
|
||||
|
||||
if (referenceIndex & REF_INDEX_OPTARGET)
|
||||
{
|
||||
return target;
|
||||
}
|
||||
else if (referenceIndex & REF_INDEX_OPLOAD)
|
||||
{
|
||||
return (opcode.flags & IS_LOAD) ? target : 0;
|
||||
}
|
||||
else if (referenceIndex & REF_INDEX_OPSTORE)
|
||||
{
|
||||
return (opcode.flags & IS_STORE) ? target : 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (referenceIndex & REF_INDEX_FPU)
|
||||
{
|
||||
return m_cpu->getRegister(EECAT_FPR, referenceIndex & 0x1F)._u64[0];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
ExpressionType MipsExpressionFunctions::getReferenceType(u64 referenceIndex)
|
||||
{
|
||||
if (referenceIndex & REF_INDEX_IS_FLOAT)
|
||||
{
|
||||
return EXPR_TYPE_FLOAT;
|
||||
}
|
||||
return EXPR_TYPE_UINT;
|
||||
}
|
||||
|
||||
bool MipsExpressionFunctions::getMemoryValue(u32 address, int size, u64& dest, std::string& error)
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
break;
|
||||
default:
|
||||
error = StringUtil::StdStringFromFormat(
|
||||
TRANSLATE("ExpressionParser", "Invalid memory access size %d."), size);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (address % size)
|
||||
{
|
||||
error = TRANSLATE("ExpressionParser", "Invalid memory access (unaligned).");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
dest = m_cpu->read8(address);
|
||||
break;
|
||||
case 2:
|
||||
dest = m_cpu->read16(address);
|
||||
break;
|
||||
case 4:
|
||||
dest = m_cpu->read32(address);
|
||||
break;
|
||||
case 8:
|
||||
dest = m_cpu->read64(address);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
#include "DebugTools/BiosDebugData.h"
|
||||
#include "MemoryTypes.h"
|
||||
|
||||
#include "BiosDebugData.h"
|
||||
#include "ExpressionParser.h"
|
||||
#include "SymbolGuardian.h"
|
||||
#include "SymbolImporter.h"
|
||||
|
@ -210,5 +210,26 @@ protected:
|
|||
const ccc::ElfFile& m_elf;
|
||||
};
|
||||
|
||||
class MipsExpressionFunctions : public IExpressionFunctions
|
||||
{
|
||||
public:
|
||||
MipsExpressionFunctions(
|
||||
DebugInterface* cpu, const ccc::SymbolDatabase* symbolDatabase, bool shouldEnumerateSymbols);
|
||||
|
||||
bool parseReference(char* str, u64& referenceIndex) override;
|
||||
bool parseSymbol(char* str, u64& symbolValue) override;
|
||||
u64 getReferenceValue(u64 referenceIndex) override;
|
||||
ExpressionType getReferenceType(u64 referenceIndex) override;
|
||||
bool getMemoryValue(u32 address, int size, u64& dest, std::string& error) override;
|
||||
|
||||
protected:
|
||||
void enumerateSymbols(const ccc::SymbolDatabase& database);
|
||||
bool parseSymbol(char* str, u64& symbolValue, const ccc::SymbolDatabase& database);
|
||||
DebugInterface* m_cpu;
|
||||
const ccc::SymbolDatabase* m_database;
|
||||
std::map<std::string, ccc::FunctionHandle> m_mangled_function_names_to_handles;
|
||||
std::map<std::string, ccc::GlobalVariableHandle> m_mangled_global_names_to_handles;
|
||||
};
|
||||
|
||||
extern R5900DebugInterface r5900Debug;
|
||||
extern R3000DebugInterface r3000Debug;
|
||||
|
|
|
@ -276,13 +276,6 @@ void SymbolImporter::ImportSymbols(
|
|||
const std::map<std::string, ccc::DataTypeHandle>& builtin_types,
|
||||
const std::atomic_bool* interrupt)
|
||||
{
|
||||
ccc::DemanglerFunctions demangler;
|
||||
if (options.DemangleSymbols)
|
||||
{
|
||||
demangler.cplus_demangle = cplus_demangle;
|
||||
demangler.cplus_demangle_opname = cplus_demangle_opname;
|
||||
}
|
||||
|
||||
u32 importer_flags =
|
||||
ccc::NO_MEMBER_FUNCTIONS |
|
||||
ccc::NO_OPTIMIZED_OUT_FUNCTIONS |
|
||||
|
@ -291,6 +284,13 @@ void SymbolImporter::ImportSymbols(
|
|||
if (options.DemangleParameters)
|
||||
importer_flags |= ccc::DEMANGLE_PARAMETERS;
|
||||
|
||||
ccc::DemanglerFunctions demangler;
|
||||
if (options.DemangleSymbols)
|
||||
{
|
||||
demangler.cplus_demangle = cplus_demangle;
|
||||
demangler.cplus_demangle_opname = cplus_demangle_opname;
|
||||
}
|
||||
|
||||
if (options.ImportSymbolsFromELF)
|
||||
{
|
||||
ccc::Result<std::vector<std::unique_ptr<ccc::SymbolTable>>> symbol_tables = elf.get_all_symbol_tables();
|
||||
|
@ -301,7 +301,7 @@ void SymbolImporter::ImportSymbols(
|
|||
else
|
||||
{
|
||||
ccc::Result<ccc::ModuleHandle> module_handle = ccc::import_symbol_tables(
|
||||
database, elf.name(), *symbol_tables, importer_flags, demangler, interrupt);
|
||||
database, *symbol_tables, elf.name(), ccc::Address(), importer_flags, demangler, interrupt);
|
||||
if (!module_handle.success())
|
||||
{
|
||||
ccc::report_error(module_handle.error());
|
||||
|
@ -311,7 +311,7 @@ void SymbolImporter::ImportSymbols(
|
|||
|
||||
if (!nocash_path.empty() && options.ImportSymFileFromDefaultLocation)
|
||||
{
|
||||
ccc::Result<bool> nocash_result = ImportNocashSymbols(database, nocash_path, builtin_types);
|
||||
ccc::Result<bool> nocash_result = ImportNocashSymbols(database, nocash_path, 0, builtin_types);
|
||||
if (!nocash_result.success())
|
||||
{
|
||||
Console.Error("Failed to import symbol file '%s': %s",
|
||||
|
@ -319,14 +319,64 @@ void SymbolImporter::ImportSymbols(
|
|||
}
|
||||
}
|
||||
|
||||
ImportExtraSymbols(database, options, builtin_types, importer_flags, demangler, interrupt);
|
||||
|
||||
Console.WriteLn("Imported %d symbols.", database.symbol_count());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void SymbolImporter::ImportExtraSymbols(
|
||||
ccc::SymbolDatabase& database,
|
||||
const Pcsx2Config::DebugAnalysisOptions& options,
|
||||
const std::map<std::string, ccc::DataTypeHandle>& builtin_types,
|
||||
u32 importer_flags,
|
||||
const ccc::DemanglerFunctions& demangler,
|
||||
const std::atomic_bool* interrupt)
|
||||
{
|
||||
MipsExpressionFunctions expression_functions(&r5900Debug, &database, true);
|
||||
|
||||
for (const DebugExtraSymbolFile& extra_symbol_file : options.ExtraSymbolFiles)
|
||||
{
|
||||
if (*interrupt)
|
||||
return;
|
||||
|
||||
if (StringUtil::EndsWithNoCase(extra_symbol_file.Path, ".sym"))
|
||||
std::string path = Path::ToNativePath(extra_symbol_file.Path);
|
||||
if (!Path::IsAbsolute(path))
|
||||
path = Path::Combine(EmuFolders::GameSettings, path);
|
||||
|
||||
if (!extra_symbol_file.Condition.empty())
|
||||
{
|
||||
ccc::Result<bool> nocash_result = ImportNocashSymbols(database, extra_symbol_file.Path, builtin_types);
|
||||
u64 expression_result = 0;
|
||||
std::string error;
|
||||
if (!parseExpression(extra_symbol_file.Condition.c_str(), &expression_functions, expression_result, error))
|
||||
{
|
||||
Console.Error("Failed to parse condition expression '%s' while importing extra symbol file '%s': %s.",
|
||||
extra_symbol_file.Condition.c_str(), path.c_str(), error.c_str());
|
||||
}
|
||||
|
||||
if (!expression_result)
|
||||
continue;
|
||||
}
|
||||
|
||||
ccc::Address base_address;
|
||||
if (!extra_symbol_file.BaseAddress.empty())
|
||||
{
|
||||
u64 expression_result = 0;
|
||||
std::string error;
|
||||
if (!parseExpression(extra_symbol_file.BaseAddress.c_str(), &expression_functions, expression_result, error))
|
||||
{
|
||||
Console.Error("Failed to parse base address expression '%s' while importing extra symbol file '%s': %s.",
|
||||
extra_symbol_file.BaseAddress.c_str(), path.c_str(), error.c_str());
|
||||
}
|
||||
|
||||
base_address = static_cast<u32>(expression_result);
|
||||
}
|
||||
|
||||
if (StringUtil::EndsWithNoCase(path, ".sym"))
|
||||
{
|
||||
ccc::Result<bool> nocash_result = ImportNocashSymbols(
|
||||
database, path, base_address.get_or_zero(), builtin_types);
|
||||
if (!nocash_result.success())
|
||||
{
|
||||
Console.Error("Failed to import symbol file '%s': %s",
|
||||
|
@ -334,29 +384,30 @@ void SymbolImporter::ImportSymbols(
|
|||
}
|
||||
|
||||
if (!*nocash_result)
|
||||
Console.Error("Cannot open symbol file '%s'.", extra_symbol_file.Path.c_str());
|
||||
Console.Error("Cannot open symbol file '%s'.", path.c_str());
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
Error error;
|
||||
std::optional<std::vector<u8>> image = FileSystem::ReadBinaryFile(extra_symbol_file.Path.c_str());
|
||||
std::optional<std::vector<u8>> image = FileSystem::ReadBinaryFile(path.c_str());
|
||||
if (!image.has_value())
|
||||
{
|
||||
Console.Error("Failed to read extra symbol file '%s'.", extra_symbol_file.Path.c_str());
|
||||
Console.Error("Failed to read extra symbol file '%s'.", path.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string file_name(Path::GetFileName(extra_symbol_file.Path));
|
||||
std::string file_name(Path::GetFileName(path));
|
||||
|
||||
ccc::Result<std::unique_ptr<ccc::SymbolFile>> symbol_file = ccc::parse_symbol_file(std::move(*image), file_name.c_str());
|
||||
ccc::Result<std::unique_ptr<ccc::SymbolFile>> symbol_file = ccc::parse_symbol_file(
|
||||
std::move(*image), file_name.c_str());
|
||||
if (!symbol_file.success())
|
||||
{
|
||||
ccc::report_error(symbol_file.error());
|
||||
continue;
|
||||
}
|
||||
|
||||
ccc::Result<std::vector<std::unique_ptr<ccc::SymbolTable>>> symbol_tables = (*symbol_file)->get_all_symbol_tables();
|
||||
ccc::Result<std::vector<std::unique_ptr<ccc::SymbolTable>>> symbol_tables =
|
||||
(*symbol_file)->get_all_symbol_tables();
|
||||
if (!symbol_tables.success())
|
||||
{
|
||||
ccc::report_error(symbol_tables.error());
|
||||
|
@ -364,22 +415,19 @@ void SymbolImporter::ImportSymbols(
|
|||
}
|
||||
|
||||
ccc::Result<ccc::ModuleHandle> module_handle = ccc::import_symbol_tables(
|
||||
database, elf.name(), *symbol_tables, importer_flags, demangler, interrupt);
|
||||
database, *symbol_tables, (*symbol_file)->name(), base_address, importer_flags, demangler, interrupt);
|
||||
if (!module_handle.success())
|
||||
{
|
||||
ccc::report_error(module_handle.error());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLn("Imported %d symbols.", database.symbol_count());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ccc::Result<bool> SymbolImporter::ImportNocashSymbols(
|
||||
ccc::SymbolDatabase& database,
|
||||
const std::string& file_path,
|
||||
u32 base_address,
|
||||
const std::map<std::string, ccc::DataTypeHandle>& builtin_types)
|
||||
{
|
||||
auto file = FileSystem::OpenManagedCFile(file_path.c_str(), "r");
|
||||
|
@ -405,6 +453,8 @@ ccc::Result<bool> SymbolImporter::ImportNocashSymbols(
|
|||
if (address == 0 && strcmp(value, "0") == 0)
|
||||
continue;
|
||||
|
||||
address += base_address;
|
||||
|
||||
if (value[0] == '.')
|
||||
{
|
||||
// data directives
|
||||
|
|
|
@ -46,9 +46,18 @@ public:
|
|||
const std::map<std::string, ccc::DataTypeHandle>& builtin_types,
|
||||
const std::atomic_bool* interrupt);
|
||||
|
||||
static void ImportExtraSymbols(
|
||||
ccc::SymbolDatabase& database,
|
||||
const Pcsx2Config::DebugAnalysisOptions& options,
|
||||
const std::map<std::string, ccc::DataTypeHandle>& builtin_types,
|
||||
u32 importer_flags,
|
||||
const ccc::DemanglerFunctions& demangler,
|
||||
const std::atomic_bool* interrupt);
|
||||
|
||||
static ccc::Result<bool> ImportNocashSymbols(
|
||||
ccc::SymbolDatabase& database,
|
||||
const std::string& file_path,
|
||||
u32 base_address,
|
||||
const std::map<std::string, ccc::DataTypeHandle>& builtin_types);
|
||||
|
||||
static std::unique_ptr<ccc::ast::Node> GetBuiltInType(
|
||||
|
|
|
@ -1625,6 +1625,8 @@ void Pcsx2Config::DebugAnalysisOptions::LoadSave(SettingsWrapper& wrap)
|
|||
file = ExtraSymbolFiles[i];
|
||||
|
||||
SettingsWrapEntryEx(file.Path, "Path");
|
||||
SettingsWrapEntryEx(file.BaseAddress, "BaseAddress");
|
||||
SettingsWrapEntryEx(file.Condition, "Condition");
|
||||
|
||||
if (wrap.IsLoading())
|
||||
ExtraSymbolFiles.emplace_back(std::move(file));
|
||||
|
|
Loading…
Reference in New Issue