diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index fd0cf0c2..89729ac6 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3152,7 +3152,7 @@ QList CutterCore::getAllSections() if (!digests) { continue; } - const char *entropy = (const char*)ht_pp_find(digests, "entropy", NULL); + const char *entropy = (const char *)ht_pp_find(digests, "entropy", NULL); section.entropy = rz_str_get(entropy); ht_pp_free(digests); @@ -3376,6 +3376,7 @@ QList CutterCore::getAnalysisClassMethods(const QStri { AnalysisMethodDescription desc; desc.name = QString::fromUtf8(meth->name); + desc.realName = QString::fromUtf8(meth->real_name); desc.addr = meth->addr; desc.vtableOffset = meth->vtable_offset; ret.append(desc); @@ -3465,6 +3466,7 @@ bool CutterCore::getAnalysisMethod(const QString &cls, const QString &meth, return false; } desc->name = QString::fromUtf8(analysisMeth.name); + desc->realName = QString::fromUtf8(analysisMeth.real_name); desc->addr = analysisMeth.addr; desc->vtableOffset = analysisMeth.vtable_offset; rz_analysis_class_method_fini(&analysisMeth); @@ -3475,7 +3477,8 @@ void CutterCore::setAnalysisMethod(const QString &className, const AnalysisMetho { CORE_LOCK(); RzAnalysisMethod analysisMeth; - analysisMeth.name = strdup(meth.name.toUtf8().constData()); + analysisMeth.name = rz_str_new(meth.name.toUtf8().constData()); + analysisMeth.real_name = rz_str_new(meth.realName.toUtf8().constData()); analysisMeth.addr = meth.addr; analysisMeth.vtable_offset = meth.vtableOffset; rz_analysis_class_method_set(core->analysis, className.toUtf8().constData(), &analysisMeth); diff --git a/src/core/CutterDescriptions.h b/src/core/CutterDescriptions.h index 2fbaeac8..941be488 100644 --- a/src/core/CutterDescriptions.h +++ b/src/core/CutterDescriptions.h @@ -248,6 +248,7 @@ struct BinClassDescription struct AnalysisMethodDescription { QString name; + QString realName; RVA addr; st64 vtableOffset; }; diff --git a/src/dialogs/EditMethodDialog.cpp b/src/dialogs/EditMethodDialog.cpp index 28914f80..c9e9fdfc 100644 --- a/src/dialogs/EditMethodDialog.cpp +++ b/src/dialogs/EditMethodDialog.cpp @@ -26,6 +26,9 @@ EditMethodDialog::EditMethodDialog(bool classFixed, QWidget *parent) connect(ui->virtualCheckBox, &QCheckBox::stateChanged, this, &EditMethodDialog::updateVirtualUI); connect(ui->nameEdit, &QLineEdit::textChanged, this, &EditMethodDialog::validateInput); + connect(ui->realNameEdit, &QLineEdit::textChanged, this, &EditMethodDialog::updateName); + connect(ui->autoRenameCheckBox, &QCheckBox::stateChanged, this, + &EditMethodDialog::updateAutoRenameEnabled); } EditMethodDialog::~EditMethodDialog() {} @@ -54,15 +57,42 @@ void EditMethodDialog::validateInput() } } +void EditMethodDialog::updateName() +{ + if (ui->autoRenameCheckBox->isChecked()) { + ui->nameEdit->setText(convertRealNameToName(ui->realNameEdit->text())); + } + + validateInput(); +} + +void EditMethodDialog::updateAutoRenameEnabled() +{ + ui->nameEdit->setEnabled(!ui->autoRenameCheckBox->isChecked()); + + if (ui->autoRenameCheckBox->isChecked()) { + ui->nameEdit->setText(convertRealNameToName(ui->realNameEdit->text())); + } +} + bool EditMethodDialog::inputValid() { - if (ui->nameEdit->text().isEmpty()) { + if (ui->nameEdit->text().isEmpty() || ui->realNameEdit->text().isEmpty()) { return false; } // TODO: do more checks here, for example for name clashes return true; } +QString EditMethodDialog::convertRealNameToName(const QString &realName) +{ + std::unique_ptr sanitizedCString( + rz_str_sanitize_sdb_key(realName.toUtf8().constData()), + [](const char *s) { rz_mem_free((void*)s); }); + + return QString(sanitizedCString.get()); +} + void EditMethodDialog::setClass(const QString &className) { if (classComboBox) { @@ -89,6 +119,7 @@ void EditMethodDialog::setClass(const QString &className) void EditMethodDialog::setMethod(const AnalysisMethodDescription &desc) { ui->nameEdit->setText(desc.name); + ui->realNameEdit->setText(desc.realName); ui->addressEdit->setText(desc.addr != RVA_INVALID ? RzAddressString(desc.addr) : nullptr); if (desc.vtableOffset >= 0) { @@ -99,6 +130,16 @@ void EditMethodDialog::setMethod(const AnalysisMethodDescription &desc) ui->vtableOffsetEdit->setText(nullptr); } + // Check if auto-rename should be enabled + bool enableAutoRename = ui->nameEdit->text().isEmpty() + || ui->nameEdit->text() == convertRealNameToName(ui->realNameEdit->text()); + ui->autoRenameCheckBox->setChecked(enableAutoRename); + + // Set focus to real name edit widget if auto-rename is enabled + if (enableAutoRename) { + ui->realNameEdit->setFocus(); + } + updateVirtualUI(); validateInput(); } @@ -120,6 +161,7 @@ AnalysisMethodDescription EditMethodDialog::getMethod() const { AnalysisMethodDescription ret; ret.name = ui->nameEdit->text(); + ret.realName = ui->realNameEdit->text(); ret.addr = Core()->num(ui->addressEdit->text()); if (!ui->virtualCheckBox->isChecked()) { ret.vtableOffset = -1; @@ -145,7 +187,8 @@ bool EditMethodDialog::showDialog(const QString &title, bool classFixed, QString void EditMethodDialog::newMethod(QString className, const QString &meth, QWidget *parent) { AnalysisMethodDescription desc; - desc.name = meth; + desc.name = convertRealNameToName(meth); + desc.realName = meth; desc.vtableOffset = -1; desc.addr = Core()->getOffset(); diff --git a/src/dialogs/EditMethodDialog.h b/src/dialogs/EditMethodDialog.h index df414977..1f388b89 100644 --- a/src/dialogs/EditMethodDialog.h +++ b/src/dialogs/EditMethodDialog.h @@ -59,6 +59,8 @@ private slots: void updateVirtualUI(); void validateInput(); + void updateName(); + void updateAutoRenameEnabled(); private: std::unique_ptr ui; @@ -72,6 +74,7 @@ private: QString fixedClass; bool inputValid(); + static QString convertRealNameToName(const QString& realName); }; #endif // EDITMETHODDIALOG_H diff --git a/src/dialogs/EditMethodDialog.ui b/src/dialogs/EditMethodDialog.ui index effc6608..b9237c46 100644 --- a/src/dialogs/EditMethodDialog.ui +++ b/src/dialogs/EditMethodDialog.ui @@ -29,45 +29,69 @@ - Name: + Unique Identifier (name): - + + + + + + + + Auto-Rename + + + false + + + + + + + Display Name (realname): + + + + + + + Address: - + - + Virtual: - + - + Offset in VTable: - + @@ -84,6 +108,14 @@ + + nameEdit + autoRenameCheckBox + realNameEdit + addressEdit + virtualCheckBox + vtableOffsetEdit + diff --git a/src/widgets/ClassesWidget.cpp b/src/widgets/ClassesWidget.cpp index 9185ce03..42c461ad 100644 --- a/src/widgets/ClassesWidget.cpp +++ b/src/widgets/ClassesWidget.cpp @@ -17,6 +17,8 @@ QVariant ClassesModel::headerData(int section, Qt::Orientation, int role) const switch (section) { case NAME: return tr("Name"); + case REAL_NAME: + return tr("Real Name"); case TYPE: return tr("Type"); case OFFSET: @@ -188,7 +190,8 @@ QVariant BinClassesModel::data(const QModelIndex &index, int role) const case OFFSET: return cls->addr == RVA_INVALID ? QString() : RzAddressString(cls->addr); case VTABLE: - return cls->vtableAddr == RVA_INVALID ? QString() : RzAddressString(cls->vtableAddr); + return cls->vtableAddr == RVA_INVALID ? QString() + : RzAddressString(cls->vtableAddr); default: return QVariant(); } @@ -312,7 +315,8 @@ void AnalysisClassesModel::classAttrsChanged(const QString &cls) layoutChanged({ persistentIndex }); } -const QVector &AnalysisClassesModel::getAttrs(const QString &cls) const +const QVector & +AnalysisClassesModel::getAttrs(const QString &cls) const { auto it = attrs->find(cls); if (it != attrs->end()) { @@ -454,6 +458,8 @@ QVariant AnalysisClassesModel::data(const QModelIndex &index, int role) const switch (index.column()) { case NAME: return meth.name; + case REAL_NAME: + return meth.realName; case TYPE: return tr("method"); case OFFSET: @@ -476,6 +482,8 @@ QVariant AnalysisClassesModel::data(const QModelIndex &index, int role) const return QVariant::fromValue(meth.addr); case NameRole: return meth.name; + case RealNameRole: + return meth.realName; case TypeRole: return QVariant::fromValue(RowType::Method); default: diff --git a/src/widgets/ClassesWidget.h b/src/widgets/ClassesWidget.h index cbd3fcad..bfe9034e 100644 --- a/src/widgets/ClassesWidget.h +++ b/src/widgets/ClassesWidget.h @@ -24,7 +24,7 @@ class ClassesWidget; class ClassesModel : public QAbstractItemModel { public: - enum Columns { NAME = 0, TYPE, OFFSET, VTABLE, COUNT }; + enum Columns { NAME = 0, REAL_NAME, TYPE, OFFSET, VTABLE, COUNT }; /** * @brief values for TypeRole data @@ -61,6 +61,14 @@ public: */ static const int VTableRole = Qt::UserRole + 3; + /** + * @brief Real Name role of data for QModelIndex + * + * will contain values of QString, used for sorting, + * as well as identifying classes and methods + */ + static const int RealNameRole = Qt::UserRole + 4; + explicit ClassesModel(QObject *parent = nullptr) : QAbstractItemModel(parent) {} QVariant headerData(int section, Qt::Orientation orientation,