2017-03-29 10:18:37 +00:00
|
|
|
#include "functionswidget.h"
|
|
|
|
#include "ui_functionswidget.h"
|
|
|
|
|
2017-04-13 15:14:02 +00:00
|
|
|
#include "mainwindow.h"
|
|
|
|
#include "helpers.h"
|
2017-03-29 10:18:37 +00:00
|
|
|
#include "dialogs/commentsdialog.h"
|
|
|
|
#include "dialogs/renamedialog.h"
|
|
|
|
#include "dialogs/xrefsdialog.h"
|
|
|
|
|
2017-04-28 13:09:40 +00:00
|
|
|
#include <algorithm>
|
2017-03-29 10:18:37 +00:00
|
|
|
#include <QMenu>
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QString>
|
2017-04-28 13:09:40 +00:00
|
|
|
#include <QResource>
|
|
|
|
|
|
|
|
FunctionModel::FunctionModel(QList<FunctionDescription> *functions, QSet<RVA> *import_addresses, bool nested, QFont default_font, QFont highlight_font, MainWindow *main, QObject *parent)
|
2017-04-28 13:38:01 +00:00
|
|
|
: QAbstractItemModel(parent),
|
|
|
|
main(main),
|
|
|
|
functions(functions),
|
|
|
|
import_addresses(import_addresses),
|
|
|
|
highlight_font(highlight_font),
|
|
|
|
default_font(default_font),
|
|
|
|
nested(nested),
|
|
|
|
current_index(-1)
|
2017-04-28 13:09:40 +00:00
|
|
|
|
2017-04-28 13:38:01 +00:00
|
|
|
{
|
2017-04-28 13:09:40 +00:00
|
|
|
connect(main, SIGNAL(cursorAddressChanged(RVA)), this, SLOT(cursorAddressChanged(RVA)));
|
|
|
|
connect(main->core, SIGNAL(functionRenamed(QString, QString)), this, SLOT(functionRenamed(QString, QString)));
|
|
|
|
}
|
|
|
|
|
|
|
|
QModelIndex FunctionModel::index(int row, int column, const QModelIndex &parent) const
|
|
|
|
{
|
2017-04-28 13:38:01 +00:00
|
|
|
if (!parent.isValid())
|
2017-04-28 13:09:40 +00:00
|
|
|
return createIndex(row, column, (quintptr)0); // root function nodes have id = 0
|
|
|
|
|
|
|
|
return createIndex(row, column, (quintptr)(parent.row() + 1)); // sub-nodes have id = function index + 1
|
|
|
|
}
|
|
|
|
|
|
|
|
QModelIndex FunctionModel::parent(const QModelIndex &index) const
|
|
|
|
{
|
2017-04-28 13:38:01 +00:00
|
|
|
if (!index.isValid() || index.column() != 0)
|
2017-04-28 13:09:40 +00:00
|
|
|
return QModelIndex();
|
|
|
|
|
2017-04-28 13:38:01 +00:00
|
|
|
if (index.internalId() == 0) // root function node
|
2017-04-28 13:09:40 +00:00
|
|
|
return QModelIndex();
|
|
|
|
else // sub-node
|
2017-04-28 13:38:01 +00:00
|
|
|
return this->index((int)(index.internalId() - 1), 0);
|
2017-04-28 13:09:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int FunctionModel::rowCount(const QModelIndex &parent) const
|
|
|
|
{
|
2017-04-28 13:38:01 +00:00
|
|
|
if (!parent.isValid())
|
2017-04-28 13:09:40 +00:00
|
|
|
return functions->count();
|
|
|
|
|
2017-04-28 13:38:01 +00:00
|
|
|
if (nested)
|
2017-04-28 13:09:40 +00:00
|
|
|
{
|
2017-04-28 13:38:01 +00:00
|
|
|
if (parent.internalId() == 0)
|
2017-04-28 13:09:40 +00:00
|
|
|
return 3; // sub-nodes for nested functions
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-04-28 13:38:01 +00:00
|
|
|
int FunctionModel::columnCount(const QModelIndex &/*parent*/) const
|
2017-04-28 13:09:40 +00:00
|
|
|
{
|
2017-04-28 13:38:01 +00:00
|
|
|
if (nested)
|
2017-04-28 13:09:40 +00:00
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QVariant FunctionModel::data(const QModelIndex &index, int role) const
|
|
|
|
{
|
2017-04-28 13:38:01 +00:00
|
|
|
if (!index.isValid())
|
2017-04-28 13:09:40 +00:00
|
|
|
return QVariant();
|
|
|
|
|
|
|
|
int function_index;
|
|
|
|
bool subnode;
|
2017-04-28 13:38:01 +00:00
|
|
|
if (index.internalId() != 0) // sub-node
|
2017-04-28 13:09:40 +00:00
|
|
|
{
|
|
|
|
function_index = index.parent().row();
|
|
|
|
subnode = true;
|
|
|
|
}
|
|
|
|
else // root function node
|
|
|
|
{
|
|
|
|
function_index = index.row();
|
|
|
|
subnode = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const FunctionDescription &function = functions->at(function_index);
|
|
|
|
|
2017-04-28 13:38:01 +00:00
|
|
|
if (function_index >= functions->count())
|
2017-04-28 13:09:40 +00:00
|
|
|
return QVariant();
|
|
|
|
|
2017-04-28 13:38:01 +00:00
|
|
|
switch (role)
|
2017-04-28 13:09:40 +00:00
|
|
|
{
|
2017-04-28 13:38:01 +00:00
|
|
|
case Qt::DisplayRole:
|
|
|
|
if (nested)
|
|
|
|
{
|
|
|
|
if (subnode)
|
2017-04-28 13:09:40 +00:00
|
|
|
{
|
2017-04-28 13:38:01 +00:00
|
|
|
switch (index.row())
|
2017-04-28 13:09:40 +00:00
|
|
|
{
|
2017-04-28 13:38:01 +00:00
|
|
|
case 0:
|
|
|
|
return tr("Offset: %1").arg(RAddressString(function.offset));
|
|
|
|
case 1:
|
|
|
|
return tr("Size: %1").arg(RSizeString(function.size));
|
|
|
|
case 2:
|
|
|
|
return tr("Import: %1").arg(import_addresses->contains(function.offset) ? tr("true") : tr("false"));
|
|
|
|
default:
|
|
|
|
return QVariant();
|
2017-04-28 13:09:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2017-04-28 13:38:01 +00:00
|
|
|
return function.name;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (index.column())
|
2017-04-28 13:09:40 +00:00
|
|
|
{
|
2017-04-28 13:38:01 +00:00
|
|
|
case 0:
|
|
|
|
return RAddressString(function.offset);
|
|
|
|
case 1:
|
|
|
|
return RSizeString(function.size);
|
|
|
|
case 3:
|
|
|
|
return function.name;
|
|
|
|
default:
|
|
|
|
return QVariant();
|
2017-04-28 13:09:40 +00:00
|
|
|
}
|
2017-04-28 13:38:01 +00:00
|
|
|
}
|
2017-04-28 13:09:40 +00:00
|
|
|
|
2017-04-28 13:38:01 +00:00
|
|
|
case Qt::DecorationRole:
|
|
|
|
if (import_addresses->contains(function.offset) &&
|
|
|
|
(nested ? false : index.column() == 2))
|
|
|
|
return QIcon(":/img/icons/import_light.svg");
|
|
|
|
return QVariant();
|
2017-04-28 13:09:40 +00:00
|
|
|
|
2017-04-28 13:38:01 +00:00
|
|
|
case Qt::FontRole:
|
|
|
|
if (current_index == function_index)
|
|
|
|
return highlight_font;
|
|
|
|
return default_font;
|
2017-04-28 13:09:40 +00:00
|
|
|
|
2017-04-28 13:38:01 +00:00
|
|
|
case Qt::ToolTipRole:
|
|
|
|
{
|
|
|
|
QList<QString> info = main->core->cmd("afi @ " + function.name).split("\n");
|
|
|
|
if (info.length() > 2)
|
2017-04-28 13:09:40 +00:00
|
|
|
{
|
2017-04-28 13:38:01 +00:00
|
|
|
QString size = info[4].split(" ")[1];
|
|
|
|
QString complex = info[8].split(" ")[1];
|
|
|
|
QString bb = info[11].split(" ")[1];
|
|
|
|
return QString("Summary:\n\n Size: " + size +
|
|
|
|
"\n Cyclomatic complexity: " + complex +
|
|
|
|
"\n Basic blocks: " + bb +
|
|
|
|
"\n\nDisasm preview:\n\n" + main->core->cmd("pdi 10 @ " + function.name) +
|
|
|
|
"\nStrings:\n\n" + main->core->cmd("pdsf @ " + function.name));
|
2017-04-28 13:09:40 +00:00
|
|
|
}
|
2017-04-28 13:38:01 +00:00
|
|
|
return QVariant();
|
|
|
|
}
|
2017-04-28 13:09:40 +00:00
|
|
|
|
2017-04-28 13:38:01 +00:00
|
|
|
case FunctionDescriptionRole:
|
|
|
|
return QVariant::fromValue(function);
|
2017-04-28 13:09:40 +00:00
|
|
|
|
2017-04-28 13:38:01 +00:00
|
|
|
case IsImportRole:
|
|
|
|
return import_addresses->contains(function.offset);
|
2017-04-28 13:09:40 +00:00
|
|
|
|
2017-04-28 13:38:01 +00:00
|
|
|
default:
|
|
|
|
return QVariant();
|
2017-04-28 13:09:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant FunctionModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
|
|
{
|
2017-04-28 13:38:01 +00:00
|
|
|
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
|
2017-04-28 13:09:40 +00:00
|
|
|
{
|
2017-04-28 13:38:01 +00:00
|
|
|
if (nested)
|
2017-04-28 13:09:40 +00:00
|
|
|
{
|
|
|
|
return tr("Name");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (section)
|
|
|
|
{
|
2017-04-28 13:38:01 +00:00
|
|
|
case 0:
|
|
|
|
return tr("Offset");
|
|
|
|
case 1:
|
|
|
|
return tr("Size");
|
|
|
|
case 2:
|
|
|
|
return tr("Imp.");
|
|
|
|
case 3:
|
|
|
|
return tr("Name");
|
|
|
|
default:
|
|
|
|
return QVariant();
|
2017-04-28 13:09:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionModel::beginReloadFunctions()
|
|
|
|
{
|
|
|
|
beginResetModel();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionModel::endReloadFunctions()
|
|
|
|
{
|
|
|
|
updateCurrentIndex();
|
|
|
|
endResetModel();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionModel::cursorAddressChanged(RVA)
|
|
|
|
{
|
|
|
|
updateCurrentIndex();
|
2017-04-28 13:38:01 +00:00
|
|
|
emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1));
|
2017-04-28 13:09:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionModel::updateCurrentIndex()
|
|
|
|
{
|
|
|
|
RVA addr = main->getCursorAddress();
|
|
|
|
|
|
|
|
int index = -1;
|
|
|
|
RVA offset = 0;
|
|
|
|
|
2017-04-28 13:38:01 +00:00
|
|
|
for (int i = 0; i < functions->count(); i++)
|
2017-04-28 13:09:40 +00:00
|
|
|
{
|
|
|
|
const FunctionDescription &function = functions->at(i);
|
|
|
|
|
2017-04-28 13:38:01 +00:00
|
|
|
if (function.contains(addr)
|
|
|
|
&& function.offset >= offset)
|
2017-04-28 13:09:40 +00:00
|
|
|
{
|
|
|
|
offset = function.offset;
|
|
|
|
index = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
current_index = index;
|
|
|
|
}
|
|
|
|
|
2017-04-28 13:38:01 +00:00
|
|
|
void FunctionModel::functionRenamed(const QString &prev_name, const QString &new_name)
|
2017-04-28 13:09:40 +00:00
|
|
|
{
|
2017-04-28 13:38:01 +00:00
|
|
|
for (int i = 0; i < functions->count(); i++)
|
2017-04-28 13:09:40 +00:00
|
|
|
{
|
|
|
|
FunctionDescription &function = (*functions)[i];
|
2017-04-28 13:38:01 +00:00
|
|
|
if (function.name == prev_name)
|
2017-04-28 13:09:40 +00:00
|
|
|
{
|
|
|
|
function.name = new_name;
|
2017-04-28 13:38:01 +00:00
|
|
|
emit dataChanged(index(i, 0), index(i, columnCount() - 1));
|
2017-04-28 13:09:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FunctionSortFilterProxyModel::FunctionSortFilterProxyModel(FunctionModel *source_model, QObject *parent)
|
2017-04-28 13:38:01 +00:00
|
|
|
: QSortFilterProxyModel(parent)
|
2017-04-28 13:09:40 +00:00
|
|
|
{
|
|
|
|
setSourceModel(source_model);
|
|
|
|
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
|
|
|
setSortCaseSensitivity(Qt::CaseInsensitive);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FunctionSortFilterProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const
|
|
|
|
{
|
|
|
|
QModelIndex index = sourceModel()->index(row, 0, parent);
|
|
|
|
FunctionDescription function = index.data(FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
|
|
|
return function.name.contains(filterRegExp());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool FunctionSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
|
|
|
{
|
2017-04-28 13:38:01 +00:00
|
|
|
if (!left.isValid() || !right.isValid())
|
2017-04-28 13:09:40 +00:00
|
|
|
return false;
|
|
|
|
|
2017-04-28 13:38:01 +00:00
|
|
|
if (left.parent().isValid() || right.parent().isValid())
|
2017-04-28 13:09:40 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
FunctionDescription left_function = left.data(FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
|
|
|
FunctionDescription right_function = right.data(FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
|
|
|
|
|
|
|
|
2017-04-28 13:38:01 +00:00
|
|
|
if (static_cast<FunctionModel *>(sourceModel())->isNested())
|
2017-04-28 13:09:40 +00:00
|
|
|
{
|
|
|
|
return left_function.name < right_function.name;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (left.column())
|
|
|
|
{
|
2017-04-28 13:38:01 +00:00
|
|
|
case 0:
|
|
|
|
return left_function.offset < right_function.offset;
|
|
|
|
case 1:
|
|
|
|
if (left_function.size != right_function.size)
|
|
|
|
return left_function.size < right_function.size;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
{
|
|
|
|
bool left_is_import = left.data(FunctionModel::IsImportRole).toBool();
|
|
|
|
bool right_is_import = right.data(FunctionModel::IsImportRole).toBool();
|
|
|
|
if (!left_is_import && right_is_import)
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 3:
|
|
|
|
return left_function.name < right_function.name;
|
|
|
|
default:
|
|
|
|
return false;
|
2017-04-28 13:09:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return left_function.offset < right_function.offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2017-04-13 15:14:02 +00:00
|
|
|
|
2017-03-29 10:18:37 +00:00
|
|
|
FunctionsWidget::FunctionsWidget(MainWindow *main, QWidget *parent) :
|
2017-04-13 15:14:02 +00:00
|
|
|
DockWidget(parent),
|
|
|
|
ui(new Ui::FunctionsWidget),
|
|
|
|
main(main)
|
2017-03-29 10:18:37 +00:00
|
|
|
{
|
|
|
|
ui->setupUi(this);
|
|
|
|
|
2017-04-28 13:09:40 +00:00
|
|
|
// Radare core found in:
|
|
|
|
this->main = main;
|
|
|
|
|
|
|
|
QFontInfo font_info = ui->functionsTreeView->fontInfo();
|
|
|
|
QFont default_font = QFont(font_info.family(), font_info.pointSize());
|
|
|
|
QFont highlight_font = QFont(font_info.family(), font_info.pointSize(), QFont::Bold);
|
|
|
|
|
|
|
|
function_model = new FunctionModel(&functions, &import_addresses, false, default_font, highlight_font, main, this);
|
|
|
|
function_proxy_model = new FunctionSortFilterProxyModel(function_model, this);
|
|
|
|
connect(ui->filterLineEdit, SIGNAL(textChanged(const QString &)), function_proxy_model, SLOT(setFilterWildcard(const QString &)));
|
|
|
|
ui->functionsTreeView->setModel(function_proxy_model);
|
|
|
|
|
|
|
|
nested_function_model = new FunctionModel(&functions, &import_addresses, true, default_font, highlight_font, main, this);
|
|
|
|
nested_function_proxy_model = new FunctionSortFilterProxyModel(nested_function_model, this);
|
|
|
|
connect(ui->filterLineEdit, SIGNAL(textChanged(const QString &)), nested_function_proxy_model, SLOT(setFilterWildcard(const QString &)));
|
|
|
|
ui->nestedFunctionsTreeView->setModel(nested_function_proxy_model);
|
|
|
|
|
|
|
|
|
2017-03-29 10:18:37 +00:00
|
|
|
// Set Functions context menu
|
2017-04-28 13:09:40 +00:00
|
|
|
connect(ui->functionsTreeView, SIGNAL(customContextMenuRequested(const QPoint &)),
|
2017-03-29 10:18:37 +00:00
|
|
|
this, SLOT(showFunctionsContextMenu(const QPoint &)));
|
2017-04-28 13:09:40 +00:00
|
|
|
connect(ui->nestedFunctionsTreeView, SIGNAL(customContextMenuRequested(const QPoint &)),
|
2017-03-29 10:18:37 +00:00
|
|
|
this, SLOT(showFunctionsContextMenu(const QPoint &)));
|
|
|
|
|
2017-04-28 13:09:40 +00:00
|
|
|
|
|
|
|
connect(ui->functionsTreeView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(on_functionsTreeView_itemDoubleClicked(const QModelIndex &)));
|
|
|
|
connect(ui->nestedFunctionsTreeView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(on_functionsTreeView_itemDoubleClicked(const QModelIndex &)));
|
2017-04-13 15:14:02 +00:00
|
|
|
|
2017-03-29 10:18:37 +00:00
|
|
|
// Hide the tabs
|
|
|
|
QTabBar *tabs = ui->tabWidget->tabBar();
|
|
|
|
tabs->setVisible(false);
|
|
|
|
|
|
|
|
// Use a custom context menu on the dock title bar
|
|
|
|
//this->title_bar = this->titleBarWidget();
|
|
|
|
ui->actionHorizontal->setChecked(true);
|
|
|
|
this->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
|
|
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
|
|
|
|
this, SLOT(showTitleContextMenu(const QPoint &)));
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionsWidget::~FunctionsWidget()
|
|
|
|
{
|
|
|
|
delete ui;
|
|
|
|
}
|
|
|
|
|
2017-04-13 15:14:02 +00:00
|
|
|
void FunctionsWidget::setup()
|
|
|
|
{
|
|
|
|
setScrollMode();
|
2017-04-28 13:09:40 +00:00
|
|
|
refreshTree();
|
2017-04-13 15:14:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionsWidget::refresh()
|
|
|
|
{
|
|
|
|
setup();
|
|
|
|
}
|
|
|
|
|
2017-04-28 13:09:40 +00:00
|
|
|
void FunctionsWidget::refreshTree()
|
2017-04-09 19:55:06 +00:00
|
|
|
{
|
2017-04-28 13:09:40 +00:00
|
|
|
function_model->beginReloadFunctions();
|
|
|
|
nested_function_model->beginReloadFunctions();
|
|
|
|
|
|
|
|
functions = this->main->core->getAllFunctions();
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2017-04-28 13:09:40 +00:00
|
|
|
import_addresses.clear();
|
2017-04-28 13:38:01 +00:00
|
|
|
foreach (ImportDescription import, main->core->getAllImports())
|
2017-04-28 13:09:40 +00:00
|
|
|
import_addresses.insert(import.plt);
|
|
|
|
|
|
|
|
function_model->endReloadFunctions();
|
|
|
|
nested_function_model->endReloadFunctions();
|
|
|
|
|
|
|
|
// resize offset and size columns
|
|
|
|
ui->functionsTreeView->resizeColumnToContents(0);
|
|
|
|
ui->functionsTreeView->resizeColumnToContents(1);
|
|
|
|
ui->functionsTreeView->resizeColumnToContents(2);
|
2017-03-29 10:18:37 +00:00
|
|
|
}
|
|
|
|
|
2017-04-28 13:09:40 +00:00
|
|
|
QTreeView *FunctionsWidget::getCurrentTreeView()
|
2017-03-29 10:18:37 +00:00
|
|
|
{
|
2017-04-28 13:09:40 +00:00
|
|
|
if (ui->tabWidget->currentIndex() == 0)
|
|
|
|
return ui->functionsTreeView;
|
|
|
|
else
|
|
|
|
return ui->nestedFunctionsTreeView;
|
|
|
|
}
|
2017-04-09 17:09:35 +00:00
|
|
|
|
2017-04-28 13:09:40 +00:00
|
|
|
void FunctionsWidget::on_functionsTreeView_itemDoubleClicked(const QModelIndex &index)
|
|
|
|
{
|
|
|
|
FunctionDescription function = index.data(FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
|
|
|
this->main->seek(function.offset, function.name, true);
|
2017-03-29 10:18:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionsWidget::showFunctionsContextMenu(const QPoint &pt)
|
|
|
|
{
|
2017-04-28 13:09:40 +00:00
|
|
|
QTreeView *treeView = getCurrentTreeView();
|
|
|
|
|
2017-03-29 10:18:37 +00:00
|
|
|
// Set functions popup menu
|
2017-04-28 13:09:40 +00:00
|
|
|
QMenu *menu = new QMenu(ui->functionsTreeView);
|
2017-03-29 10:18:37 +00:00
|
|
|
menu->clear();
|
|
|
|
menu->addAction(ui->actionDisasAdd_comment);
|
|
|
|
menu->addAction(ui->actionFunctionsRename);
|
|
|
|
menu->addAction(ui->actionFunctionsUndefine);
|
|
|
|
menu->addSeparator();
|
|
|
|
menu->addAction(ui->action_References);
|
|
|
|
|
2017-04-28 13:09:40 +00:00
|
|
|
menu->exec(treeView->mapToGlobal(pt));
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2017-04-28 13:09:40 +00:00
|
|
|
delete menu;
|
2017-03-29 10:18:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionsWidget::on_actionDisasAdd_comment_triggered()
|
|
|
|
{
|
2017-04-28 13:09:40 +00:00
|
|
|
// Get selected item in functions tree view
|
|
|
|
QTreeView *treeView = getCurrentTreeView();
|
|
|
|
FunctionDescription function = treeView->selectionModel()->currentIndex().data(FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
|
|
|
|
2017-03-29 10:18:37 +00:00
|
|
|
// Create dialog
|
2017-04-09 19:55:06 +00:00
|
|
|
CommentsDialog *c = new CommentsDialog(this);
|
2017-04-28 13:09:40 +00:00
|
|
|
|
2017-04-09 19:55:06 +00:00
|
|
|
if (c->exec())
|
|
|
|
{
|
2017-03-29 10:18:37 +00:00
|
|
|
// Get new function name
|
|
|
|
QString comment = c->getComment();
|
2017-04-26 23:00:20 +00:00
|
|
|
this->main->addDebugOutput("Comment: " + comment + " at: " + function.name);
|
2017-03-29 10:18:37 +00:00
|
|
|
// Rename function in r2 core
|
2017-04-28 13:09:40 +00:00
|
|
|
this->main->core->setComment(function.offset, comment);
|
2017-03-29 10:18:37 +00:00
|
|
|
// Seek to new renamed function
|
2017-04-28 13:09:40 +00:00
|
|
|
this->main->seek(function.offset, function.name);
|
2017-03-29 10:18:37 +00:00
|
|
|
// TODO: Refresh functions tree widget
|
|
|
|
}
|
|
|
|
this->main->refreshComments();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionsWidget::on_actionFunctionsRename_triggered()
|
|
|
|
{
|
2017-04-28 13:09:40 +00:00
|
|
|
// Get selected item in functions tree view
|
|
|
|
QTreeView *treeView = getCurrentTreeView();
|
|
|
|
FunctionDescription function = treeView->selectionModel()->currentIndex().data(FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
|
|
|
|
2017-03-29 10:18:37 +00:00
|
|
|
// Create dialog
|
2017-04-09 19:55:06 +00:00
|
|
|
RenameDialog *r = new RenameDialog(this);
|
2017-04-28 13:09:40 +00:00
|
|
|
|
2017-03-29 10:18:37 +00:00
|
|
|
// Set function name in dialog
|
2017-04-28 13:09:40 +00:00
|
|
|
r->setFunctionName(function.name);
|
2017-03-29 10:18:37 +00:00
|
|
|
// If user accepted
|
2017-04-09 19:55:06 +00:00
|
|
|
if (r->exec())
|
|
|
|
{
|
2017-03-29 10:18:37 +00:00
|
|
|
// Get new function name
|
|
|
|
QString new_name = r->getFunctionName();
|
|
|
|
// Rename function in r2 core
|
2017-04-28 13:09:40 +00:00
|
|
|
this->main->core->renameFunction(function.name, new_name);
|
|
|
|
|
2017-03-29 10:18:37 +00:00
|
|
|
// Scroll to show the new name in functions tree widget
|
2017-04-28 13:09:40 +00:00
|
|
|
//
|
|
|
|
// QAbstractItemView::EnsureVisible
|
|
|
|
// QAbstractItemView::PositionAtTop
|
|
|
|
// QAbstractItemView::PositionAtBottom
|
|
|
|
// QAbstractItemView::PositionAtCenter
|
|
|
|
//
|
|
|
|
//ui->functionsTreeWidget->scrollToItem(selected_rows.first(), QAbstractItemView::PositionAtTop);
|
2017-03-29 10:18:37 +00:00
|
|
|
// Seek to new renamed function
|
2017-04-28 13:09:40 +00:00
|
|
|
this->main->seek(function.offset);
|
2017-03-29 10:18:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionsWidget::on_action_References_triggered()
|
|
|
|
{
|
2017-04-28 13:09:40 +00:00
|
|
|
// Get selected item in functions tree view
|
|
|
|
QTreeView *treeView = getCurrentTreeView();
|
|
|
|
FunctionDescription function = treeView->selectionModel()->currentIndex().data(FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
2017-03-29 10:18:37 +00:00
|
|
|
|
|
|
|
//this->main->add_debug_output("Addr: " + address);
|
|
|
|
|
|
|
|
// Get function for clicked offset
|
2017-04-28 13:09:40 +00:00
|
|
|
RAnalFunction *fcn = this->main->core->functionAt(function.offset);
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2017-04-09 19:55:06 +00:00
|
|
|
XrefsDialog *x = new XrefsDialog(this->main, this);
|
2017-03-29 10:18:37 +00:00
|
|
|
x->setWindowTitle("X-Refs for function " + QString::fromUtf8(fcn->name));
|
|
|
|
|
|
|
|
// Get Refs and Xrefs
|
|
|
|
QList<QStringList> ret_refs;
|
|
|
|
QList<QStringList> ret_xrefs;
|
|
|
|
|
|
|
|
// refs = calls q hace esa funcion
|
|
|
|
QList<QString> refs = this->main->core->getFunctionRefs(fcn->addr, 'C');
|
2017-04-09 19:55:06 +00:00
|
|
|
if (refs.size() > 0)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < refs.size(); ++i)
|
|
|
|
{
|
2017-03-29 10:18:37 +00:00
|
|
|
//this->main->add_debug_output(refs.at(i));
|
|
|
|
QStringList retlist = refs.at(i).split(",");
|
|
|
|
QStringList temp;
|
|
|
|
QString addr = retlist.at(2);
|
|
|
|
temp << addr;
|
|
|
|
QString op = this->main->core->cmd("pi 1 @ " + addr);
|
|
|
|
temp << op.simplified();
|
|
|
|
ret_refs << temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// xrefs = calls a esa funcion
|
|
|
|
//qDebug() << this->main->core->getFunctionXrefs(offset.toLong(&ok, 16));
|
|
|
|
QList<QString> xrefs = this->main->core->getFunctionXrefs(fcn->addr);
|
2017-04-09 19:55:06 +00:00
|
|
|
if (xrefs.size() > 0)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < xrefs.size(); ++i)
|
|
|
|
{
|
2017-03-29 10:18:37 +00:00
|
|
|
//this->main->add_debug_output(xrefs.at(i));
|
|
|
|
QStringList retlist = xrefs.at(i).split(",");
|
|
|
|
QStringList temp;
|
|
|
|
QString addr = retlist.at(1);
|
|
|
|
temp << addr;
|
|
|
|
QString op = this->main->core->cmd("pi 1 @ " + addr);
|
|
|
|
temp << op.simplified();
|
|
|
|
ret_xrefs << temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
x->fillRefs(ret_refs, ret_xrefs);
|
|
|
|
x->exec();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionsWidget::showTitleContextMenu(const QPoint &pt)
|
|
|
|
{
|
|
|
|
// Set functions popup menu
|
|
|
|
QMenu *menu = new QMenu(this);
|
|
|
|
menu->clear();
|
|
|
|
menu->addAction(ui->actionHorizontal);
|
|
|
|
menu->addAction(ui->actionVertical);
|
|
|
|
|
2017-04-09 19:55:06 +00:00
|
|
|
if (ui->tabWidget->currentIndex() == 0)
|
|
|
|
{
|
2017-03-29 10:18:37 +00:00
|
|
|
ui->actionHorizontal->setChecked(true);
|
|
|
|
ui->actionVertical->setChecked(false);
|
2017-04-09 19:55:06 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-03-29 10:18:37 +00:00
|
|
|
ui->actionVertical->setChecked(true);
|
|
|
|
ui->actionHorizontal->setChecked(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
this->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
|
|
|
|
|
|
menu->exec(this->mapToGlobal(pt));
|
|
|
|
delete menu;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionsWidget::on_actionHorizontal_triggered()
|
|
|
|
{
|
|
|
|
ui->tabWidget->setCurrentIndex(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionsWidget::on_actionVertical_triggered()
|
|
|
|
{
|
|
|
|
ui->tabWidget->setCurrentIndex(1);
|
|
|
|
}
|
|
|
|
|
2017-04-10 10:25:33 +00:00
|
|
|
void FunctionsWidget::resizeEvent(QResizeEvent *event)
|
2017-04-09 19:55:06 +00:00
|
|
|
{
|
2017-04-13 15:51:58 +00:00
|
|
|
if (main->responsive && isVisible())
|
2017-04-09 19:55:06 +00:00
|
|
|
{
|
2017-04-10 10:25:33 +00:00
|
|
|
if (event->size().width() >= event->size().height())
|
|
|
|
{
|
|
|
|
// Set horizontal view (list)
|
|
|
|
on_actionHorizontal_triggered();
|
|
|
|
}
|
|
|
|
else
|
2017-04-09 19:55:06 +00:00
|
|
|
{
|
2017-04-10 10:25:33 +00:00
|
|
|
// Set vertical view (Tree)
|
|
|
|
on_actionVertical_triggered();
|
2017-03-29 10:18:37 +00:00
|
|
|
}
|
|
|
|
}
|
2017-04-10 10:25:33 +00:00
|
|
|
QDockWidget::resizeEvent(event);
|
2017-03-29 10:18:37 +00:00
|
|
|
}
|
2017-04-13 15:14:02 +00:00
|
|
|
|
|
|
|
void FunctionsWidget::setScrollMode()
|
|
|
|
{
|
2017-04-28 13:09:40 +00:00
|
|
|
qhelpers::setVerticalScrollMode(ui->functionsTreeView);
|
2017-04-13 15:14:02 +00:00
|
|
|
}
|