mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-20 03:46:11 +00:00
Fix Seek to VTable and add some docs
This commit is contained in:
parent
dae04b8609
commit
1ee1d7d948
@ -59,6 +59,7 @@ bool EditMethodDialog::inputValid()
|
||||
if (ui->nameEdit->text().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// TODO: do more checks here, for example for name clashes
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -128,9 +129,9 @@ AnalMethodDescription EditMethodDialog::getMethod()
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool EditMethodDialog::showDialog(const QString &title, QString *className, AnalMethodDescription *desc, QWidget *parent)
|
||||
bool EditMethodDialog::showDialog(const QString &title, bool classFixed, QString *className, AnalMethodDescription *desc, QWidget *parent)
|
||||
{
|
||||
auto dialog = new EditMethodDialog(parent);
|
||||
auto dialog = new EditMethodDialog(classFixed, parent);
|
||||
dialog->setWindowTitle(title);
|
||||
dialog->setClass(*className);
|
||||
dialog->setMethod(*desc);
|
||||
@ -147,7 +148,7 @@ void EditMethodDialog::newMethod(QString className, const QString &meth, QWidget
|
||||
desc.vtableOffset = -1;
|
||||
desc.addr = Core()->getOffset();
|
||||
|
||||
if (!showDialog(tr("Create Method"), &className, &desc, parent)) {
|
||||
if (!showDialog(tr("Create Method"), false, &className, &desc, parent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -162,7 +163,7 @@ void EditMethodDialog::editMethod(const QString &className, const QString &meth,
|
||||
}
|
||||
|
||||
QString classNameCopy = className;
|
||||
if (!showDialog(tr("Edit Method"), &classNameCopy, &desc, parent)) {
|
||||
if (!showDialog(tr("Edit Method"), false, &classNameCopy, &desc, parent)) {
|
||||
return;
|
||||
}
|
||||
if (desc.name != meth) {
|
||||
|
@ -17,6 +17,9 @@ class EditMethodDialog : public QDialog
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \param classFixed whether the user should be able to change the class. If false, a QComboBox will be shown, otherwise a plain QLabel.
|
||||
*/
|
||||
explicit EditMethodDialog(bool classFixed, QWidget *parent = nullptr);
|
||||
~EditMethodDialog();
|
||||
|
||||
@ -26,8 +29,25 @@ public:
|
||||
QString getClass();
|
||||
AnalMethodDescription getMethod();
|
||||
|
||||
static bool showDialog(const QString &title, QString *className, AnalMethodDescription *desc, QWidget *parent = nullptr);
|
||||
/*!
|
||||
* \brief Helper function to display the dialog
|
||||
*
|
||||
* \param title title of the dialog
|
||||
* \param classFixed whether the user should be able to change the class
|
||||
* \param className initial class name, will be overwritten if the user changed the class
|
||||
* \param desc initial data for the method information
|
||||
* \return whether the dialog was accepted by the user
|
||||
*/
|
||||
static bool showDialog(const QString &title, bool classFixed, QString *className, AnalMethodDescription *desc, QWidget *parent = nullptr);
|
||||
|
||||
/*!
|
||||
* \brief Show the dialog to add a new method a given class
|
||||
*/
|
||||
static void newMethod(QString className = nullptr, const QString &meth = QString(), QWidget *parent = nullptr);
|
||||
|
||||
/*!
|
||||
* \brief Show the dialog to edit a given method of a given class
|
||||
*/
|
||||
static void editMethod(const QString &className, const QString &meth, QWidget *parent = nullptr);
|
||||
|
||||
private slots:
|
||||
@ -42,6 +62,9 @@ private:
|
||||
|
||||
QComboBox *classComboBox = nullptr;
|
||||
QLabel *classLabel = nullptr;
|
||||
/*!
|
||||
* This will only be used when the dialog was created with classFixed = true in order to remember the class name.
|
||||
*/
|
||||
QString fixedClass;
|
||||
|
||||
bool inputValid();
|
||||
|
@ -132,14 +132,10 @@ QVariant BinClassesModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
case OffsetRole:
|
||||
return QVariant::fromValue(meth->addr);
|
||||
case VTableOffsetRole:
|
||||
return QVariant::fromValue(index.parent().data(VTableOffsetRole).toULongLong() + meth->vtableOffset);
|
||||
case NameRole:
|
||||
return meth->name;
|
||||
case TypeRole:
|
||||
return QVariant::fromValue(RowType::Method);
|
||||
case DataRole:
|
||||
return QVariant::fromValue(*meth);
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
@ -203,8 +199,6 @@ QVariant BinClassesModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
case OffsetRole:
|
||||
return QVariant::fromValue(cls->addr);
|
||||
case VTableOffsetRole:
|
||||
return QVariant::fromValue(cls->vtableAddr);
|
||||
case NameRole:
|
||||
return cls->name;
|
||||
case TypeRole:
|
||||
@ -383,8 +377,6 @@ QVariant AnalClassesModel::data(const QModelIndex &index, int role) const
|
||||
return QVariant();
|
||||
case OffsetRole:
|
||||
return QVariant::fromValue(meth.addr);
|
||||
case VTableOffsetRole:
|
||||
return QVariant::fromValue(index.parent().data(VTableOffsetRole).toULongLong() + meth.vtableOffset);
|
||||
case NameRole:
|
||||
return meth.name;
|
||||
case TypeRole:
|
||||
@ -555,6 +547,11 @@ void ClassesWidget::on_classesTreeView_doubleClicked(const QModelIndex &index)
|
||||
|
||||
void ClassesWidget::showContextMenu(const QPoint &pt)
|
||||
{
|
||||
if(!anal_model) {
|
||||
// no context menu for bin classes
|
||||
return;
|
||||
}
|
||||
|
||||
QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex();
|
||||
if (!index.isValid()) {
|
||||
return;
|
||||
@ -562,15 +559,19 @@ void ClassesWidget::showContextMenu(const QPoint &pt)
|
||||
|
||||
QMenu menu(ui->classesTreeView);
|
||||
|
||||
QVariant vtableOffsetVariant = index.data(ClassesModel::VTableOffsetRole);
|
||||
if (vtableOffsetVariant.isValid() && vtableOffsetVariant.toULongLong() != RVA_INVALID) {
|
||||
menu.addAction(ui->seekToVTableAction);
|
||||
}
|
||||
|
||||
menu.addAction(ui->addMethodAction);
|
||||
|
||||
if (index.data(ClassesModel::TypeRole).toInt() == static_cast<int>(ClassesModel::RowType::Method)) {
|
||||
menu.addAction(ui->editMethodAction);
|
||||
|
||||
QString className = index.parent().data(ClassesModel::NameRole).toString();
|
||||
QString methodName = index.data(ClassesModel::NameRole).toString();
|
||||
AnalMethodDescription desc;
|
||||
if (Core()->getAnalMethod(className, methodName, &desc)) {
|
||||
if (desc.vtableOffset >= 0) {
|
||||
menu.addAction(ui->seekToVTableAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
menu.exec(ui->classesTreeView->mapToGlobal(pt));
|
||||
@ -578,11 +579,22 @@ void ClassesWidget::showContextMenu(const QPoint &pt)
|
||||
|
||||
void ClassesWidget::on_seekToVTableAction_triggered()
|
||||
{
|
||||
RVA vtableOffset = ui->classesTreeView->selectionModel()->currentIndex()
|
||||
.data(ClassesModel::VTableOffsetRole).value<RVA>();
|
||||
if (vtableOffset != RVA_INVALID) {
|
||||
Core()->seek(vtableOffset);
|
||||
QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex();
|
||||
QString className = index.parent().data(ClassesModel::NameRole).toString();
|
||||
|
||||
QList<AnalVTableDescription> vtables = Core()->getAnalClassVTables(className);
|
||||
if (vtables.isEmpty()) {
|
||||
QMessageBox::warning(this, tr("Missing VTable in class"), tr("The class %1 does not have any VTable!").arg(className));
|
||||
return;
|
||||
}
|
||||
|
||||
QString methodName = index.data(ClassesModel::NameRole).toString();
|
||||
AnalMethodDescription desc;
|
||||
if (!Core()->getAnalMethod(className, methodName, &desc) || desc.vtableOffset < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Core()->seek(vtables[0].addr + desc.vtableOffset);
|
||||
}
|
||||
|
||||
void ClassesWidget::on_addMethodAction_triggered()
|
||||
|
@ -18,17 +18,40 @@ class QTreeWidgetItem;
|
||||
class MainWindow;
|
||||
class ClassesWidget;
|
||||
|
||||
/*!
|
||||
* \brief Common abstract base class for Bin and Anal classes models
|
||||
*/
|
||||
class ClassesModel: public QAbstractItemModel
|
||||
{
|
||||
public:
|
||||
enum Columns { NAME = 0, TYPE, OFFSET, VTABLE, COUNT };
|
||||
|
||||
/*!
|
||||
* \brief values for TypeRole data
|
||||
*/
|
||||
enum class RowType { Class = 0, Base, VTable, Method, Field };
|
||||
|
||||
/*!
|
||||
* \brief Offset role of data for QModelIndex
|
||||
*
|
||||
* will contain values of type RVA
|
||||
*/
|
||||
static const int OffsetRole = Qt::UserRole;
|
||||
|
||||
/*!
|
||||
* \brief Name role of data for QModelIndex
|
||||
*
|
||||
* will contain values of QString, used for sorting,
|
||||
* as well as identifying classes and methods
|
||||
*/
|
||||
static const int NameRole = Qt::UserRole + 1;
|
||||
|
||||
/*!
|
||||
* \brief Type role of data for QModelIndex
|
||||
*
|
||||
* will contain values of RowType
|
||||
*/
|
||||
static const int TypeRole = Qt::UserRole + 2;
|
||||
static const int VTableOffsetRole = Qt::UserRole + 3;
|
||||
static const int DataRole = Qt::UserRole + 4;
|
||||
|
||||
explicit ClassesModel(QObject *parent = nullptr) : QAbstractItemModel(parent) {}
|
||||
|
||||
@ -64,6 +87,13 @@ class AnalClassesModel: public ClassesModel
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
/*!
|
||||
* \brief List entry below a class
|
||||
*
|
||||
* This roughly corresponds to attributes of r2 anal classes, which means it is not an attribute in the sense of
|
||||
* a class member variable, but any kind of sub-info associated with the class.
|
||||
* This struct in particular is used to provide a model for the list entries below a class.
|
||||
*/
|
||||
struct Attribute
|
||||
{
|
||||
enum class Type { VTable, Base, Method };
|
||||
@ -75,6 +105,17 @@ private:
|
||||
};
|
||||
|
||||
QList<QString> classes;
|
||||
|
||||
/*!
|
||||
* \brief Cache for class attributes
|
||||
*
|
||||
* Maps class names to a list of Attributes.
|
||||
* This is filled only when the attributes of a specific class are requested.
|
||||
* (i.e. the user expands the class in the QTreeView)
|
||||
*
|
||||
* This must be a pointer instead of just a QMap, because it has to be modified
|
||||
* in methods that are defined as const by QAbstractItemModel.
|
||||
*/
|
||||
std::unique_ptr<QMap<QString, QVector<Attribute>>> attrs;
|
||||
|
||||
const QVector<Attribute> &getAttrs(const QString &cls) const;
|
||||
|
Loading…
Reference in New Issue
Block a user