Update analysis method handling for name/realname (#2843)

This also fixes a crash when adding a new class method.
This commit is contained in:
Anton Angelov 2021-12-01 05:11:29 -08:00 committed by GitHub
parent 78a9a11209
commit 6438cc4d50
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 112 additions and 14 deletions

View File

@ -3152,7 +3152,7 @@ QList<SectionDescription> 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<AnalysisMethodDescription> 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);

View File

@ -248,6 +248,7 @@ struct BinClassDescription
struct AnalysisMethodDescription
{
QString name;
QString realName;
RVA addr;
st64 vtableOffset;
};

View File

@ -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<const char, void (*)(const char *)> 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();

View File

@ -59,6 +59,8 @@ private slots:
void updateVirtualUI();
void validateInput();
void updateName();
void updateAutoRenameEnabled();
private:
std::unique_ptr<Ui::EditMethodDialog> ui;
@ -72,6 +74,7 @@ private:
QString fixedClass;
bool inputValid();
static QString convertRealNameToName(const QString& realName);
};
#endif // EDITMETHODDIALOG_H

View File

@ -29,45 +29,69 @@
<item row="1" column="0">
<widget class="QLabel" name="nameLabel">
<property name="text">
<string>Name:</string>
<string>Unique Identifier (name):</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="nameEdit"/>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="nameEdit"/>
</item>
<item>
<widget class="QCheckBox" name="autoRenameCheckBox">
<property name="text">
<string>Auto-Rename</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="realNameLabel">
<property name="text">
<string>Display Name (realname):</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="realNameEdit"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="addressLabel">
<property name="text">
<string>Address:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="3" column="1">
<widget class="QLineEdit" name="addressEdit"/>
</item>
<item row="3" column="0">
<item row="4" column="0">
<widget class="QLabel" name="virtualLabel">
<property name="text">
<string>Virtual:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="1">
<widget class="QCheckBox" name="virtualCheckBox">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="4" column="0">
<item row="5" column="0">
<widget class="QLabel" name="vtableOffsetLabel">
<property name="text">
<string>Offset in VTable:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="5" column="1">
<widget class="QLineEdit" name="vtableOffsetEdit"/>
</item>
</layout>
@ -84,6 +108,14 @@
</item>
</layout>
</widget>
<tabstops>
<tabstop>nameEdit</tabstop>
<tabstop>autoRenameCheckBox</tabstop>
<tabstop>realNameEdit</tabstop>
<tabstop>addressEdit</tabstop>
<tabstop>virtualCheckBox</tabstop>
<tabstop>vtableOffsetEdit</tabstop>
</tabstops>
<resources/>
<connections>
<connection>

View File

@ -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::Attribute> &AnalysisClassesModel::getAttrs(const QString &cls) const
const QVector<AnalysisClassesModel::Attribute> &
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:

View File

@ -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,