#include "functionswidget.h" #include "ui_functionswidget.h" #include "dialogs/commentsdialog.h" #include "dialogs/renamedialog.h" #include "dialogs/xrefsdialog.h" #include "mainwindow.h" #include #include #include FunctionsWidget::FunctionsWidget(MainWindow *main, QWidget *parent) : QDockWidget(parent), ui(new Ui::FunctionsWidget) { ui->setupUi(this); // Radare core found in: this->main = main; this->functionsTreeWidget = ui->functionsTreeWidget; this->functionsTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); //this->functionsTreeWidget->setFont(QFont("Monospace", 8)); // Set Functions context menu connect(ui->functionsTreeWidget, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(showFunctionsContextMenu(const QPoint &))); connect(ui->nestedFunctionsTree, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(showFunctionsContextMenu(const QPoint &))); // 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 &))); // Resize eventfilter ui->functionsTreeWidget->viewport()->installEventFilter(this); } FunctionsWidget::~FunctionsWidget() { delete ui; } void FunctionsWidget::fillFunctions() { this->functionsTreeWidget->clear(); ui->nestedFunctionsTree->clear(); for (auto i: this->main->core->getList ("anal", "functions")) { QStringList a = i.split (","); // off,sz,unk,name // "0x0804ada3,1,13,,fcn.0804ada3" // "0x0804ad4a,6,,1,,fcn.0804ad4a" if (a.length() == 5) { // Add list function this->main->appendRow(this->functionsTreeWidget,a[0],a[1],a[4]); // Add nested function QTreeWidgetItem *item = new QTreeWidgetItem(ui->nestedFunctionsTree); item->setText(0, a[4]); QTreeWidgetItem *size_it = new QTreeWidgetItem(); size_it->setText(0, "Offset: " + a[0]); item->addChild(size_it); QTreeWidgetItem *off_it = new QTreeWidgetItem(); off_it->setText(0, "Size: " + a[1]); item->addChild(off_it); ui->nestedFunctionsTree->addTopLevelItem(item); } else if (a.length() == 6) { // Add list function this->main->appendRow(this->functionsTreeWidget,a[0],a[1],a[5]); // Add nested function QTreeWidgetItem *item = new QTreeWidgetItem(ui->nestedFunctionsTree); item->setText(0, a[5]); QTreeWidgetItem *size_it = new QTreeWidgetItem(); size_it->setText(0, "Offset: " + a[0]); item->addChild(size_it); QTreeWidgetItem *off_it = new QTreeWidgetItem(); off_it->setText(0, "Size: " + a[1]); item->addChild(off_it); ui->nestedFunctionsTree->addTopLevelItem(item); } else { qDebug() << "fillFunctions()" << a; } } this->functionsTreeWidget->sortByColumn(3, Qt::AscendingOrder); ui->nestedFunctionsTree->sortByColumn(0, Qt::AscendingOrder); this->main->adjustColumns(this->functionsTreeWidget); this->addTooltips(); } void FunctionsWidget::on_functionsTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column) { QString offset = item->text(1); QString name = item->text(3); this->main->seek(offset, name); this->main->memoryDock->raise(); } void FunctionsWidget::showFunctionsContextMenu(const QPoint &pt) { // Set functions popup menu QMenu *menu = new QMenu(ui->functionsTreeWidget); menu->clear(); menu->addAction(ui->actionDisasAdd_comment); menu->addAction(ui->actionFunctionsRename); menu->addAction(ui->actionFunctionsUndefine); menu->addSeparator(); menu->addAction(ui->action_References); if(ui->tabWidget->currentIndex() == 0) { this->functionsTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); menu->exec(ui->functionsTreeWidget->mapToGlobal(pt)); } else { ui->nestedFunctionsTree->setContextMenuPolicy(Qt::CustomContextMenu); menu->exec(ui->nestedFunctionsTree->mapToGlobal(pt)); } delete menu; } void FunctionsWidget::refreshTree() { this->functionsTreeWidget->clear(); ui->nestedFunctionsTree->clear(); for (auto i: this->main->core->getList ("anal", "functions")) { QStringList a = i.split (","); // off,sz,unk,name // "0x0804ada3,1,13,,fcn.0804ada3" // "0x0804ad4a,6,,1,,fcn.0804ad4a" if (a.length() == 5) { // Add list function this->main->appendRow(this->functionsTreeWidget,a[0],a[1],a[4]); // Add nested function QTreeWidgetItem *item = new QTreeWidgetItem(ui->nestedFunctionsTree); item->setText(0, a[4]); QTreeWidgetItem *size_it = new QTreeWidgetItem(); size_it->setText(0, "Offset: " + a[0]); item->addChild(size_it); QTreeWidgetItem *off_it = new QTreeWidgetItem(); off_it->setText(0, "Size: " + a[1]); item->addChild(off_it); ui->nestedFunctionsTree->addTopLevelItem(item); } else if (a.length() == 6) { // Add list function this->main->appendRow(this->functionsTreeWidget,a[0],a[1],a[5]); // Add nested function QTreeWidgetItem *item = new QTreeWidgetItem(ui->nestedFunctionsTree); item->setText(0, a[5]); QTreeWidgetItem *size_it = new QTreeWidgetItem(); size_it->setText(0, "Offset: " + a[0]); item->addChild(size_it); QTreeWidgetItem *off_it = new QTreeWidgetItem(); off_it->setText(0, "Size: " + a[1]); item->addChild(off_it); ui->nestedFunctionsTree->addTopLevelItem(item); } else { qDebug() << "fillFunctions()" << a; } } this->functionsTreeWidget->sortByColumn(3, Qt::AscendingOrder); ui->nestedFunctionsTree->sortByColumn(0, Qt::AscendingOrder); this->main->adjustColumns(this->functionsTreeWidget); this->addTooltips(); } void FunctionsWidget::on_actionDisasAdd_comment_triggered() { QString fcn_name = ""; // Create dialog CommentsDialog* c = new CommentsDialog(this); // Get selected item in functions tree widget if(ui->tabWidget->currentIndex() == 0) { QList selected_rows = ui->functionsTreeWidget->selectedItems(); // Get selected function name fcn_name = selected_rows.first()->text(3); } else { QList selected_rows = ui->nestedFunctionsTree->selectedItems(); // Get selected function name fcn_name = selected_rows.first()->text(0); } if (c->exec()) { // Get new function name QString comment = c->getComment(); this->main->add_debug_output("Comment: " + comment + " at: " + fcn_name); // Rename function in r2 core this->main->core->setComment(fcn_name, comment); // Seek to new renamed function this->main->seek(fcn_name); // TODO: Refresh functions tree widget } this->main->refreshComments(); } void FunctionsWidget::addTooltips() { // Add comments to list functions QList clist = this->functionsTreeWidget->findItems("*", Qt::MatchWildcard, 3); foreach(QTreeWidgetItem* item, clist) { QString name = item->text(3); QList info = this->main->core->cmd("afi @ " + name).split("\n"); if (info.length() > 2) { QString size = info[4].split(" ")[1]; QString complex = info[8].split(" ")[1]; QString bb = info[11].split(" ")[1]; item->setToolTip(3, "Summary:\n\n Size: " + size + "\n Cyclomatic complexity: " + complex + "\n Basic blocks: " + bb + "\n\nDisasm preview:\n\n" + this->main->core->cmd("pdi 10 @ " + name) + "\nStrings:\n\n" + this->main->core->cmd("pdsf @ " + name)); //"\nStrings:\n\n" + this->main->core->cmd("pds @ " + name + "!$F")); } } // Add comments to nested functions QList nlist = ui->nestedFunctionsTree->findItems("*", Qt::MatchWildcard, 0); foreach(QTreeWidgetItem* item, nlist) { QString name = item->text(0); QList info = this->main->core->cmd("afi @ " + name).split("\n"); if (info.length() > 2) { QString size = info[4].split(" ")[1]; QString complex = info[8].split(" ")[1]; QString bb = info[11].split(" ")[1]; item->setToolTip(0, "Summary:\n\n Size: " + size + "\n Cyclomatic complexity: " + complex + "\n Basic blocks: " + bb + "\n\nDisasm preview:\n\n" + this->main->core->cmd("pdi 10 @ " + name) + "\nStrings:\n\n" + this->main->core->cmd("pdsf @ " + name)); //"\nStrings:\n\n" + this->main->core->cmd("pds @ " + name + "!$F")); } } } void FunctionsWidget::on_actionFunctionsRename_triggered() { // Create dialog RenameDialog* r = new RenameDialog(this); // Get selected item in functions tree widget QList selected_rows = ui->functionsTreeWidget->selectedItems(); // Get selected function name QString old_name = selected_rows.first()->text(3); // Set function name in dialog r->setFunctionName(old_name); // If user accepted if (r->exec()) { // Get new function name QString new_name = r->getFunctionName(); // Rename function in r2 core this->main->core->renameFunction(old_name, new_name); // Change name in functions tree widget selected_rows.first()->setText(3, new_name); // Scroll to show the new name in functions tree widget /* * QAbstractItemView::EnsureVisible * QAbstractItemView::PositionAtTop * QAbstractItemView::PositionAtBottom * QAbstractItemView::PositionAtCenter */ ui->functionsTreeWidget->scrollToItem(selected_rows.first(), QAbstractItemView::PositionAtTop); // Seek to new renamed function this->main->seek(new_name); } } void FunctionsWidget::on_action_References_triggered() { QList selected_rows = ui->functionsTreeWidget->selectedItems(); // Get selected function address QString address = selected_rows.first()->text(1); //this->main->add_debug_output("Addr: " + address); // Get function for clicked offset RAnalFunction *fcn = this->main->core->functionAt(address.toLongLong(0, 16)); XrefsDialog* x = new XrefsDialog(this->main, this); x->setWindowTitle("X-Refs for function " + QString::fromUtf8(fcn->name)); // Get Refs and Xrefs bool ok; QList ret_refs; QList ret_xrefs; // refs = calls q hace esa funcion QList refs = this->main->core->getFunctionRefs(fcn->addr, 'C'); if (refs.size() > 0) { for (int i = 0; i < refs.size(); ++i) { //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 xrefs = this->main->core->getFunctionXrefs(fcn->addr); if (xrefs.size() > 0) { for (int i = 0; i < xrefs.size(); ++i) { //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); if (ui->tabWidget->currentIndex() == 0) { ui->actionHorizontal->setChecked(true); ui->actionVertical->setChecked(false); } else { 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); } void FunctionsWidget::on_nestedFunctionsTree_itemDoubleClicked(QTreeWidgetItem *item, int column) { //QString offset = item->text(1); QString name = item->text(0); QString offset = item->child(0)->text(0).split(":")[1]; this->main->seek(offset, name); this->main->memoryDock->raise(); } bool FunctionsWidget::eventFilter(QObject *obj, QEvent *event) { if (this->main->responsive) { if (event->type() == QEvent::Resize && obj == this && this->isVisible() == true) { QResizeEvent *resizeEvent = static_cast(event); //qDebug("Dock Resized (New Size) - Width: %d Height: %d", // resizeEvent->size().width(), // resizeEvent->size().height()); if (resizeEvent->size().width() >= resizeEvent->size().height()) { // Set horizontal view (list) this->on_actionHorizontal_triggered(); } else { // Set vertical view (Tree) this->on_actionVertical_triggered(); } } } return QDockWidget::eventFilter(obj, event); }