mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-20 11:56:12 +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()) {
|
if (ui->nameEdit->text().isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// TODO: do more checks here, for example for name clashes
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,9 +129,9 @@ AnalMethodDescription EditMethodDialog::getMethod()
|
|||||||
return ret;
|
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->setWindowTitle(title);
|
||||||
dialog->setClass(*className);
|
dialog->setClass(*className);
|
||||||
dialog->setMethod(*desc);
|
dialog->setMethod(*desc);
|
||||||
@ -147,7 +148,7 @@ void EditMethodDialog::newMethod(QString className, const QString &meth, QWidget
|
|||||||
desc.vtableOffset = -1;
|
desc.vtableOffset = -1;
|
||||||
desc.addr = Core()->getOffset();
|
desc.addr = Core()->getOffset();
|
||||||
|
|
||||||
if (!showDialog(tr("Create Method"), &className, &desc, parent)) {
|
if (!showDialog(tr("Create Method"), false, &className, &desc, parent)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +163,7 @@ void EditMethodDialog::editMethod(const QString &className, const QString &meth,
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString classNameCopy = className;
|
QString classNameCopy = className;
|
||||||
if (!showDialog(tr("Edit Method"), &classNameCopy, &desc, parent)) {
|
if (!showDialog(tr("Edit Method"), false, &classNameCopy, &desc, parent)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (desc.name != meth) {
|
if (desc.name != meth) {
|
||||||
|
@ -17,6 +17,9 @@ class EditMethodDialog : public QDialog
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
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);
|
explicit EditMethodDialog(bool classFixed, QWidget *parent = nullptr);
|
||||||
~EditMethodDialog();
|
~EditMethodDialog();
|
||||||
|
|
||||||
@ -26,8 +29,25 @@ public:
|
|||||||
QString getClass();
|
QString getClass();
|
||||||
AnalMethodDescription getMethod();
|
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);
|
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);
|
static void editMethod(const QString &className, const QString &meth, QWidget *parent = nullptr);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
@ -42,6 +62,9 @@ private:
|
|||||||
|
|
||||||
QComboBox *classComboBox = nullptr;
|
QComboBox *classComboBox = nullptr;
|
||||||
QLabel *classLabel = 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;
|
QString fixedClass;
|
||||||
|
|
||||||
bool inputValid();
|
bool inputValid();
|
||||||
|
@ -132,14 +132,10 @@ QVariant BinClassesModel::data(const QModelIndex &index, int role) const
|
|||||||
}
|
}
|
||||||
case OffsetRole:
|
case OffsetRole:
|
||||||
return QVariant::fromValue(meth->addr);
|
return QVariant::fromValue(meth->addr);
|
||||||
case VTableOffsetRole:
|
|
||||||
return QVariant::fromValue(index.parent().data(VTableOffsetRole).toULongLong() + meth->vtableOffset);
|
|
||||||
case NameRole:
|
case NameRole:
|
||||||
return meth->name;
|
return meth->name;
|
||||||
case TypeRole:
|
case TypeRole:
|
||||||
return QVariant::fromValue(RowType::Method);
|
return QVariant::fromValue(RowType::Method);
|
||||||
case DataRole:
|
|
||||||
return QVariant::fromValue(*meth);
|
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
@ -203,8 +199,6 @@ QVariant BinClassesModel::data(const QModelIndex &index, int role) const
|
|||||||
}
|
}
|
||||||
case OffsetRole:
|
case OffsetRole:
|
||||||
return QVariant::fromValue(cls->addr);
|
return QVariant::fromValue(cls->addr);
|
||||||
case VTableOffsetRole:
|
|
||||||
return QVariant::fromValue(cls->vtableAddr);
|
|
||||||
case NameRole:
|
case NameRole:
|
||||||
return cls->name;
|
return cls->name;
|
||||||
case TypeRole:
|
case TypeRole:
|
||||||
@ -383,8 +377,6 @@ QVariant AnalClassesModel::data(const QModelIndex &index, int role) const
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
case OffsetRole:
|
case OffsetRole:
|
||||||
return QVariant::fromValue(meth.addr);
|
return QVariant::fromValue(meth.addr);
|
||||||
case VTableOffsetRole:
|
|
||||||
return QVariant::fromValue(index.parent().data(VTableOffsetRole).toULongLong() + meth.vtableOffset);
|
|
||||||
case NameRole:
|
case NameRole:
|
||||||
return meth.name;
|
return meth.name;
|
||||||
case TypeRole:
|
case TypeRole:
|
||||||
@ -555,6 +547,11 @@ void ClassesWidget::on_classesTreeView_doubleClicked(const QModelIndex &index)
|
|||||||
|
|
||||||
void ClassesWidget::showContextMenu(const QPoint &pt)
|
void ClassesWidget::showContextMenu(const QPoint &pt)
|
||||||
{
|
{
|
||||||
|
if(!anal_model) {
|
||||||
|
// no context menu for bin classes
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex();
|
QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex();
|
||||||
if (!index.isValid()) {
|
if (!index.isValid()) {
|
||||||
return;
|
return;
|
||||||
@ -562,15 +559,19 @@ void ClassesWidget::showContextMenu(const QPoint &pt)
|
|||||||
|
|
||||||
QMenu menu(ui->classesTreeView);
|
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);
|
menu.addAction(ui->addMethodAction);
|
||||||
|
|
||||||
if (index.data(ClassesModel::TypeRole).toInt() == static_cast<int>(ClassesModel::RowType::Method)) {
|
if (index.data(ClassesModel::TypeRole).toInt() == static_cast<int>(ClassesModel::RowType::Method)) {
|
||||||
menu.addAction(ui->editMethodAction);
|
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));
|
menu.exec(ui->classesTreeView->mapToGlobal(pt));
|
||||||
@ -578,11 +579,22 @@ void ClassesWidget::showContextMenu(const QPoint &pt)
|
|||||||
|
|
||||||
void ClassesWidget::on_seekToVTableAction_triggered()
|
void ClassesWidget::on_seekToVTableAction_triggered()
|
||||||
{
|
{
|
||||||
RVA vtableOffset = ui->classesTreeView->selectionModel()->currentIndex()
|
QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex();
|
||||||
.data(ClassesModel::VTableOffsetRole).value<RVA>();
|
QString className = index.parent().data(ClassesModel::NameRole).toString();
|
||||||
if (vtableOffset != RVA_INVALID) {
|
|
||||||
Core()->seek(vtableOffset);
|
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()
|
void ClassesWidget::on_addMethodAction_triggered()
|
||||||
|
@ -18,17 +18,40 @@ class QTreeWidgetItem;
|
|||||||
class MainWindow;
|
class MainWindow;
|
||||||
class ClassesWidget;
|
class ClassesWidget;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Common abstract base class for Bin and Anal classes models
|
||||||
|
*/
|
||||||
class ClassesModel: public QAbstractItemModel
|
class ClassesModel: public QAbstractItemModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum Columns { NAME = 0, TYPE, OFFSET, VTABLE, COUNT };
|
enum Columns { NAME = 0, TYPE, OFFSET, VTABLE, COUNT };
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief values for TypeRole data
|
||||||
|
*/
|
||||||
enum class RowType { Class = 0, Base, VTable, Method, Field };
|
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;
|
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;
|
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 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) {}
|
explicit ClassesModel(QObject *parent = nullptr) : QAbstractItemModel(parent) {}
|
||||||
|
|
||||||
@ -64,6 +87,13 @@ class AnalClassesModel: public ClassesModel
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
private:
|
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
|
struct Attribute
|
||||||
{
|
{
|
||||||
enum class Type { VTable, Base, Method };
|
enum class Type { VTable, Base, Method };
|
||||||
@ -75,6 +105,17 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
QList<QString> classes;
|
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;
|
std::unique_ptr<QMap<QString, QVector<Attribute>>> attrs;
|
||||||
|
|
||||||
const QVector<Attribute> &getAttrs(const QString &cls) const;
|
const QVector<Attribute> &getAttrs(const QString &cls) const;
|
||||||
|
Loading…
Reference in New Issue
Block a user