Show Anal Class Attributes

This commit is contained in:
Florian Märkl 2019-02-01 15:51:29 +01:00
parent 6087ab8016
commit af20c35ab0
4 changed files with 159 additions and 129 deletions

View File

@ -2014,6 +2014,7 @@ QList<AnalMethodDescription> CutterCore::getAnalClassMethods(const QString &cls)
desc.name = QString::fromUtf8(meth->name); desc.name = QString::fromUtf8(meth->name);
desc.addr = meth->addr; desc.addr = meth->addr;
desc.vtableOffset = meth->vtable_offset; desc.vtableOffset = meth->vtable_offset;
ret.append(desc);
} }
r_vector_free(meths); r_vector_free(meths);
@ -2036,6 +2037,7 @@ QList<AnalBaseClassDescription> CutterCore::getAnalClassBaseClasses(const QStrin
desc.id = QString::fromUtf8(base->id); desc.id = QString::fromUtf8(base->id);
desc.offset = base->offset; desc.offset = base->offset;
desc.className = QString::fromUtf8(base->class_name); desc.className = QString::fromUtf8(base->class_name);
ret.append(desc);
} }
r_vector_free(bases); r_vector_free(bases);
@ -2058,6 +2060,7 @@ QList<AnalVTableDescription> CutterCore::getAnalClassVTables(const QString &cls)
desc.id = QString::fromUtf8(vtable->id); desc.id = QString::fromUtf8(vtable->id);
desc.offset = vtable->offset; desc.offset = vtable->offset;
desc.addr = vtable->addr; desc.addr = vtable->addr;
ret.append(desc);
} }
r_vector_free(vtables); r_vector_free(vtables);

View File

@ -391,6 +391,9 @@ Q_DECLARE_METATYPE(BinClassDescription)
Q_DECLARE_METATYPE(const BinClassDescription *) Q_DECLARE_METATYPE(const BinClassDescription *)
Q_DECLARE_METATYPE(const BinClassMethodDescription *) Q_DECLARE_METATYPE(const BinClassMethodDescription *)
Q_DECLARE_METATYPE(const BinClassFieldDescription *) Q_DECLARE_METATYPE(const BinClassFieldDescription *)
Q_DECLARE_METATYPE(AnalBaseClassDescription)
Q_DECLARE_METATYPE(AnalMethodDescription)
Q_DECLARE_METATYPE(AnalVTableDescription)
Q_DECLARE_METATYPE(ResourcesDescription) Q_DECLARE_METATYPE(ResourcesDescription)
Q_DECLARE_METATYPE(VTableDescription) Q_DECLARE_METATYPE(VTableDescription)
Q_DECLARE_METATYPE(TypeDescription) Q_DECLARE_METATYPE(TypeDescription)

View File

@ -48,21 +48,24 @@ void BinClassesModel::setClasses(const QList<BinClassDescription> &classes)
QModelIndex BinClassesModel::index(int row, int column, const QModelIndex &parent) const QModelIndex BinClassesModel::index(int row, int column, const QModelIndex &parent) const
{ {
if (!parent.isValid()) if (!parent.isValid()) {
return createIndex(row, column, (quintptr)0); // root function nodes have id = 0 return createIndex(row, column, (quintptr)0); // root function nodes have id = 0
}
return createIndex(row, column, (quintptr)parent.row() + 1); // sub-nodes have id = class index + 1 return createIndex(row, column, (quintptr)parent.row() + 1); // sub-nodes have id = class index + 1
} }
QModelIndex BinClassesModel::parent(const QModelIndex &index) const QModelIndex BinClassesModel::parent(const QModelIndex &index) const
{ {
if (!index.isValid() || index.column() != 0) if (!index.isValid()) {
return QModelIndex(); return {};
}
if (index.internalId() == 0) // root function node if (index.internalId() == 0) { // root function node
return QModelIndex(); return {};
else // sub-node } else { // sub-node
return this->index((int)(index.internalId() - 1), 0); return this->index((int)(index.internalId() - 1), 0);
}
} }
int BinClassesModel::rowCount(const QModelIndex &parent) const int BinClassesModel::rowCount(const QModelIndex &parent) const
@ -134,7 +137,7 @@ QVariant BinClassesModel::data(const QModelIndex &index, int role) const
case NameRole: case NameRole:
return meth->name; return meth->name;
case TypeRole: case TypeRole:
return QVariant::fromValue(METHOD); return QVariant::fromValue(RowType::Method);
case DataRole: case DataRole:
return QVariant::fromValue(*meth); return QVariant::fromValue(*meth);
default: default:
@ -158,7 +161,7 @@ QVariant BinClassesModel::data(const QModelIndex &index, int role) const
case NameRole: case NameRole:
return field->name; return field->name;
case TypeRole: case TypeRole:
return QVariant::fromValue(FIELD); return QVariant::fromValue(RowType::Field);
default: default:
return QVariant(); return QVariant();
} }
@ -178,7 +181,7 @@ QVariant BinClassesModel::data(const QModelIndex &index, int role) const
case NameRole: case NameRole:
return base->name; return base->name;
case TypeRole: case TypeRole:
return QVariant::fromValue(BASE); return QVariant::fromValue(RowType::Base);
default: default:
return QVariant(); return QVariant();
} }
@ -205,7 +208,7 @@ QVariant BinClassesModel::data(const QModelIndex &index, int role) const
case NameRole: case NameRole:
return cls->name; return cls->name;
case TypeRole: case TypeRole:
return QVariant::fromValue(CLASS); return QVariant::fromValue(RowType::Class);
default: default:
return QVariant(); return QVariant();
} }
@ -214,7 +217,7 @@ QVariant BinClassesModel::data(const QModelIndex &index, int role) const
AnalClassesModel::AnalClassesModel(QObject *parent) AnalClassesModel::AnalClassesModel(QObject *parent)
: ClassesModel(parent) : ClassesModel(parent), attrs(new QMap<QString, QVector<Attribute>>)
{ {
} }
@ -225,24 +228,54 @@ void AnalClassesModel::refreshClasses()
endResetModel(); endResetModel();
} }
const QVector<AnalClassesModel::Attribute> &AnalClassesModel::getAttrs(const QString &cls) const
{
auto it = attrs->find(cls);
if(it != attrs->end()) {
return it.value();
}
QVector<AnalClassesModel::Attribute> clsAttrs;
QList<AnalBaseClassDescription> bases = Core()->getAnalClassBaseClasses(cls);
QList<AnalMethodDescription> meths = Core()->getAnalClassMethods(cls);
QList<AnalVTableDescription> vtables = Core()->getAnalClassVTables(cls);
clsAttrs.reserve(bases.size() + meths.size() + vtables.size());
for(const AnalBaseClassDescription &base : bases) {
clsAttrs.push_back(Attribute(Attribute::Type::Base, QVariant::fromValue(base)));
}
for(const AnalVTableDescription &vtable : vtables) {
clsAttrs.push_back(Attribute(Attribute::Type::VTable, QVariant::fromValue(vtable)));
}
for(const AnalMethodDescription &meth : meths) {
clsAttrs.push_back(Attribute(Attribute::Type::Method, QVariant::fromValue(meth)));
}
return attrs->insert(cls, clsAttrs).value();
}
QModelIndex AnalClassesModel::index(int row, int column, const QModelIndex &parent) const QModelIndex AnalClassesModel::index(int row, int column, const QModelIndex &parent) const
{ {
if (!parent.isValid()) if (!parent.isValid()) {
return createIndex(row, column, (quintptr)0); // root function nodes have id = 0 return createIndex(row, column, (quintptr)0); // root function nodes have id = 0
}
return createIndex(row, column, (quintptr)parent.row() + 1); // sub-nodes have id = class index + 1 return createIndex(row, column, (quintptr)parent.row() + 1); // sub-nodes have id = class index + 1
} }
QModelIndex AnalClassesModel::parent(const QModelIndex &index) const QModelIndex AnalClassesModel::parent(const QModelIndex &index) const
{ {
if (!index.isValid() || index.column() != 0) if (!index.isValid()) {
return QModelIndex(); return {};
}
if (index.internalId() == 0) // root function node if (index.internalId() == 0) { // root function node
return QModelIndex(); return {};
else // sub-node } else { // sub-node
return this->index((int)(index.internalId() - 1), 0); return this->index((int)(index.internalId() - 1), 0);
}
} }
int AnalClassesModel::rowCount(const QModelIndex &parent) const int AnalClassesModel::rowCount(const QModelIndex &parent) const
@ -252,9 +285,7 @@ int AnalClassesModel::rowCount(const QModelIndex &parent) const
} }
if (parent.internalId() == 0) { // methods/fields if (parent.internalId() == 0) { // methods/fields
return 0; return getAttrs(classes[parent.row()]).size();
// TODO const BinClassDescription *cls = &classes.at(parent.row());
// TODO return cls->baseClasses.length() + cls->methods.length() + cls->fields.length();
} }
return 0; // below methods/fields return 0; // below methods/fields
@ -262,7 +293,7 @@ int AnalClassesModel::rowCount(const QModelIndex &parent) const
bool AnalClassesModel::hasChildren(const QModelIndex &parent) const bool AnalClassesModel::hasChildren(const QModelIndex &parent) const
{ {
return true; return !parent.isValid() || !parent.parent().isValid();
} }
int AnalClassesModel::columnCount(const QModelIndex &) const int AnalClassesModel::columnCount(const QModelIndex &) const
@ -272,104 +303,12 @@ int AnalClassesModel::columnCount(const QModelIndex &) const
QVariant AnalClassesModel::data(const QModelIndex &index, int role) const QVariant AnalClassesModel::data(const QModelIndex &index, int role) const
{ {
QString cls;
const BinClassMethodDescription *meth = nullptr;
const BinClassFieldDescription *field = nullptr;
const BinClassBaseClassDescription *base = nullptr;
if (index.internalId() == 0) { // class row if (index.internalId() == 0) { // class row
if (index.row() >= classes.count()) { if (index.row() >= classes.count()) {
return QVariant(); return QVariant();
} }
cls = classes.at(index.row()); QString cls = classes.at(index.row());
} else { // method/field/base row
cls = classes.at(static_cast<int>(index.internalId() - 1));
/*if (index.row() >= cls->baseClasses.length() + cls->methods.length() + cls->fields.length()) {
return QVariant();
}
if (index.row() < cls->baseClasses.length()) {
base = &cls->baseClasses[index.row()];
} else if (index.row() - cls->baseClasses.length() < cls->methods.length()) {
meth = &cls->methods[index.row() - cls->baseClasses.length()];
} else {
field = &cls->fields[index.row() - cls->baseClasses.length() - cls->methods.length()];
}*/
}
if (meth) {
switch (role) {
case Qt::DisplayRole:
switch (index.column()) {
case NAME:
return meth->name;
case TYPE:
return tr("method");
case OFFSET:
return meth->addr == RVA_INVALID ? QString() : RAddressString(meth->addr);
case VTABLE:
return meth->vtableOffset < 0 ? QString() : QString("+%1").arg(meth->vtableOffset);
default:
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:
return QVariant::fromValue(METHOD);
case DataRole:
return QVariant::fromValue(*meth);
default:
return QVariant();
}
} else if (field) {
switch (role) {
case Qt::DisplayRole:
switch (index.column()) {
case NAME:
return field->name;
case TYPE:
return tr("field");
case OFFSET:
return field->addr == RVA_INVALID ? QString() : RAddressString(field->addr);
default:
return QVariant();
}
case OffsetRole:
return QVariant::fromValue(field->addr);
case NameRole:
return field->name;
case TypeRole:
return QVariant::fromValue(FIELD);
default:
return QVariant();
}
} else if (base) {
switch (role) {
case Qt::DisplayRole:
switch (index.column()) {
case NAME:
return base->name;
case TYPE:
return tr("base class");
case OFFSET:
return QString("+%1").arg(base->offset);
default:
return QVariant();
}
case NameRole:
return base->name;
case TypeRole:
return QVariant::fromValue(BASE);
default:
return QVariant();
}
}
else {
switch (role) { switch (role) {
case Qt::DisplayRole: case Qt::DisplayRole:
switch (index.column()) { switch (index.column()) {
@ -377,25 +316,97 @@ QVariant AnalClassesModel::data(const QModelIndex &index, int role) const
return cls; return cls;
case TYPE: case TYPE:
return tr("class"); return tr("class");
// TODO case OFFSET:
// TODO return cls->addr == RVA_INVALID ? QString() : RAddressString(cls->addr);
// TODO case VTABLE:
// TODO return cls->vtableAddr == RVA_INVALID ? QString() : RAddressString(cls->vtableAddr);
default: default:
return QVariant(); return QVariant();
} }
// TODO case OffsetRole:
// TODO return QVariant::fromValue(cls->addr);
// TODO case VTableOffsetRole:
// TODO return QVariant::fromValue(cls->vtableAddr);
// TODO case NameRole:
// TODO return cls->name;
case TypeRole: case TypeRole:
return QVariant::fromValue(CLASS); return QVariant::fromValue(RowType::Class);
default: default:
return QVariant(); return QVariant();
} }
} else { // method/field/base row
QString cls = classes.at(static_cast<int>(index.internalId() - 1));
const Attribute &attr = getAttrs(cls)[index.row()];
switch (attr.type) {
case Attribute::Type::Base: {
AnalBaseClassDescription base = attr.data.value<AnalBaseClassDescription>();
switch (role) {
case Qt::DisplayRole:
switch (index.column()) {
case NAME:
return base.className;
case TYPE:
return tr("base");
case OFFSET:
return QString("+%1").arg(base.offset);
default:
return QVariant();
}
case NameRole:
return base.className;
case TypeRole:
return QVariant::fromValue(RowType::Base);
default:
return QVariant();
}
break;
}
case Attribute::Type::Method: {
AnalMethodDescription meth = attr.data.value<AnalMethodDescription>();
switch (role) {
case Qt::DisplayRole:
switch (index.column()) {
case NAME:
return meth.name;
case TYPE:
return tr("method");
case OFFSET:
return meth.addr == RVA_INVALID ? QString() : RAddressString(meth.addr);
case VTABLE:
return meth.vtableOffset < 0 ? QString() : QString("+%1").arg(meth.vtableOffset);
default:
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:
return QVariant::fromValue(RowType::Method);
default:
return QVariant();
}
break;
}
case Attribute::Type::VTable: {
AnalVTableDescription vtable = attr.data.value<AnalVTableDescription>();
switch (role) {
case Qt::DisplayRole:
switch (index.column()) {
case NAME:
return "vtable";
case TYPE:
return tr("vtable");
case OFFSET:
return RAddressString(vtable.addr);
default:
return QVariant();
}
case OffsetRole:
return QVariant::fromValue(vtable.addr);
case TypeRole:
return QVariant::fromValue(RowType::VTable);
default:
return QVariant();
}
break;
}
}
} }
return QVariant();
} }
@ -531,7 +542,7 @@ void ClassesWidget::showContextMenu(const QPoint &pt)
menu.addAction(ui->addMethodAction); menu.addAction(ui->addMethodAction);
if (index.data(ClassesModel::TypeRole) == ClassesModel::METHOD) { if (index.data(ClassesModel::TypeRole).toInt() == static_cast<int>(ClassesModel::RowType::Method)) {
menu.addAction(ui->editMethodAction); menu.addAction(ui->editMethodAction);
} }
@ -555,7 +566,7 @@ void ClassesWidget::on_addMethodAction_triggered()
} }
QString className; QString className;
if (index.data(ClassesModel::TypeRole).toInt() == ClassesModel::CLASS) { if (index.data(ClassesModel::TypeRole).toInt() == static_cast<int>(ClassesModel::RowType::Class)) {
className = index.data(ClassesModel::NameRole).toString(); className = index.data(ClassesModel::NameRole).toString();
} else { } else {
className = index.parent().data(ClassesModel::NameRole).toString(); className = index.parent().data(ClassesModel::NameRole).toString();
@ -570,7 +581,7 @@ void ClassesWidget::on_addMethodAction_triggered()
void ClassesWidget::on_editMethodAction_triggered() void ClassesWidget::on_editMethodAction_triggered()
{ {
QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex(); QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex();
if (!index.isValid() || index.data(ClassesModel::TypeRole).toInt() != ClassesModel::METHOD) { if (!index.isValid() || index.data(ClassesModel::TypeRole).toInt() != static_cast<int>(ClassesModel::RowType::Method)) {
return; return;
} }

View File

@ -22,7 +22,7 @@ class ClassesModel: public QAbstractItemModel
{ {
public: public:
enum Columns { NAME = 0, TYPE, OFFSET, VTABLE, COUNT }; enum Columns { NAME = 0, TYPE, OFFSET, VTABLE, COUNT };
enum RowType { CLASS = 0, METHOD = 1, FIELD = 2, BASE = 3 }; enum class RowType { Class = 0, Method = 1, Field = 2, Base = 3, VTable = 4 };
static const int OffsetRole = Qt::UserRole; static const int OffsetRole = Qt::UserRole;
static const int NameRole = Qt::UserRole + 1; static const int NameRole = Qt::UserRole + 1;
@ -64,7 +64,20 @@ class AnalClassesModel: public ClassesModel
Q_OBJECT Q_OBJECT
private: private:
struct Attribute
{
enum class Type { VTable, Base, Method };
Type type;
QVariant data;
Attribute() = default;
Attribute(Type type, const QVariant &data) : type(type), data(data) {}
};
QList<QString> classes; QList<QString> classes;
std::unique_ptr<QMap<QString, QVector<Attribute>>> attrs;
const QVector<Attribute> &getAttrs(const QString &cls) const;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;