mirror of
https://github.com/rizinorg/cutter.git
synced 2025-01-31 00:35:05 +00:00
Refactor FunctionsWidget, new features and much more (#149)
* Add RFunction struct and get functions from json * Fix QRCore::cmdj * Add Analysis command line argument * Replace MainWindow::current_address with cursur address * Use Cursor Address in MemoryWidget, Change some more String addresses to RVA * FunctionsWidget cleanup * Use QTreeView in FunctionsWidget * Re-enabled Nested Functions Widget * Nested Functions Tree View with Model * FunctionsWidget font, only one function highlighted * Removed explicit font sizes * FunctionsWidget re-enabled sorting and context menu * FunctionWidget Quick Filter * FunctionsWidget show decoration for imports * QRCore lists refactoring, Imports Icon * FunctionModel: Fix emitting dataChanged * Fix some smaller things * Fixes and cleanups * Raise MemoryDock on seek from Omnibar * FunctionsWidget: Remove margins * FunctionWidget: Restore correct Tooltip font * FunctionsWidget: import icon in separate column
This commit is contained in:
parent
a0e5cd2d34
commit
ebe33ffe8e
@ -58,7 +58,7 @@ namespace qhelpers
|
||||
}
|
||||
}
|
||||
|
||||
void appendRow(QTreeWidget *tw, const QString &str, const QString &str2,
|
||||
QTreeWidgetItem *appendRow(QTreeWidget *tw, const QString &str, const QString &str2,
|
||||
const QString &str3, const QString &str4, const QString &str5)
|
||||
{
|
||||
QTreeWidgetItem *tempItem = new QTreeWidgetItem();
|
||||
@ -75,9 +75,11 @@ namespace qhelpers
|
||||
tempItem->setText(5, str5);
|
||||
|
||||
tw->insertTopLevelItem(0, tempItem);
|
||||
|
||||
return tempItem;
|
||||
}
|
||||
|
||||
void setVerticalScrollMode(QTreeWidget *tw)
|
||||
void setVerticalScrollMode(QAbstractItemView *tw)
|
||||
{
|
||||
tw->setVerticalScrollMode(scrollMode());
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ class QPlainTextEdit;
|
||||
class QTextEdit;
|
||||
class QString;
|
||||
class QTreeWidget;
|
||||
class QTreeWidgetItem;
|
||||
class QAbstractItemView;
|
||||
|
||||
namespace qhelpers
|
||||
{
|
||||
@ -17,10 +19,10 @@ namespace qhelpers
|
||||
|
||||
void adjustColumns(QTreeWidget *tw, int columnCount = 0, int padding = 0);
|
||||
|
||||
void appendRow(QTreeWidget *tw, const QString &str, const QString &str2 = QString(),
|
||||
QTreeWidgetItem *appendRow(QTreeWidget *tw, const QString &str, const QString &str2 = QString(),
|
||||
const QString &str3 = QString(), const QString &str4 = QString(), const QString &str5 = QString());
|
||||
|
||||
void setVerticalScrollMode(QTreeWidget *tw);
|
||||
void setVerticalScrollMode(QAbstractItemView *tw);
|
||||
}
|
||||
|
||||
#endif // HELPERS_H
|
||||
|
53
src/img/icons/import_light.svg
Normal file
53
src/img/icons/import_light.svg
Normal file
@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="28px"
|
||||
height="32px"
|
||||
viewBox="0 0 28 32"
|
||||
style="enable-background:new 0 0 28 32;"
|
||||
xml:space="preserve"
|
||||
id="svg2"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="import_light.svg"><metadata
|
||||
id="metadata12"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs10" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1026"
|
||||
id="namedview8"
|
||||
showgrid="false"
|
||||
inkscape:zoom="14.75"
|
||||
inkscape:cx="4.1411135"
|
||||
inkscape:cy="12.994714"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="comment_x5F_alt2_x5F_stroke" /><g
|
||||
id="Layer_1" /><g
|
||||
id="comment_x5F_alt2_x5F_stroke"><path
|
||||
style="opacity:1;fill:#aaacaf;fill-opacity:1;stroke:none"
|
||||
d="M 11.111328 0 L 11.111328 4.3066406 A 14 14 0 0 0 0 18 A 14 14 0 0 0 14 32 A 14 14 0 0 0 28 18 A 14 14 0 0 0 16.888672 4.3183594 L 16.888672 0 L 11.111328 0 z M 16.888672 8.4296875 A 10 10 0 0 1 24 18 A 10 10 0 0 1 14 28 A 10 10 0 0 1 4 18 A 10 10 0 0 1 11.111328 8.4355469 L 11.111328 15.035156 L 5.3320312 15.035156 L 14 23.703125 L 22.667969 15.035156 L 16.888672 15.035156 L 16.888672 8.4296875 z "
|
||||
id="path4140" /><g
|
||||
id="move_x5F_vertical"
|
||||
transform="translate(34.338983,-2.2597261)"><g
|
||||
id="g6" /></g></g></svg>
|
After Width: | Height: | Size: 2.2 KiB |
34
src/main.cpp
34
src/main.cpp
@ -27,7 +27,13 @@ int main(int argc, char *argv[])
|
||||
cmdParser.setApplicationDescription("A Qt and C++ GUI for radare2 reverse engineering framework");
|
||||
cmdParser.addHelpOption();
|
||||
cmdParser.addVersionOption();
|
||||
cmdParser.addPositionalArgument("filename", QCoreApplication::translate("main", "Filename to open."));
|
||||
cmdParser.addPositionalArgument("filename", QObject::tr("Filename to open."));
|
||||
|
||||
QCommandLineOption analOption({"a", "anal"},
|
||||
QObject::tr("Automatically start analysis. Needs filename to be specified. May be a value between 0 and 4."),
|
||||
QObject::tr("level"));
|
||||
cmdParser.addOption(analOption);
|
||||
|
||||
cmdParser.process(a);
|
||||
|
||||
QStringList args = cmdParser.positionalArguments();
|
||||
@ -47,8 +53,31 @@ int main(int argc, char *argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool analLevelSpecified = false;
|
||||
int analLevel = 0;
|
||||
|
||||
if(cmdParser.isSet(analOption))
|
||||
{
|
||||
analLevel = cmdParser.value(analOption).toInt(&analLevelSpecified);
|
||||
|
||||
if(!analLevelSpecified || analLevel < 0 || analLevel > 4)
|
||||
{
|
||||
printf("%s\n", QObject::tr("Invalid Analysis Level. May be a value between 0 and 4.").toLocal8Bit().constData());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (args.empty())
|
||||
{
|
||||
if(analLevelSpecified)
|
||||
{
|
||||
printf("%s\n", QObject::tr("Filename must be specified to start analysis automatically.").toLocal8Bit().constData());
|
||||
return 1;
|
||||
}
|
||||
|
||||
NewFileDialog *n = new NewFileDialog();
|
||||
n->setAttribute(Qt::WA_DeleteOnClose);
|
||||
n->show();
|
||||
@ -58,6 +87,9 @@ int main(int argc, char *argv[])
|
||||
OptionsDialog *o = new OptionsDialog(args[0]);
|
||||
o->setAttribute(Qt::WA_DeleteOnClose);
|
||||
o->show();
|
||||
|
||||
if(analLevelSpecified)
|
||||
o->setupAndStartAnalysis(analLevel);
|
||||
}
|
||||
|
||||
return a.exec();
|
||||
|
@ -110,7 +110,7 @@ MainWindow::MainWindow(QWidget *parent, QRCore *kore) :
|
||||
ui->setupUi(this);
|
||||
|
||||
doLock = false;
|
||||
this->current_address = "entry0";
|
||||
this->cursor_address = core->getOffset();
|
||||
|
||||
registerCustomFonts();
|
||||
|
||||
@ -721,24 +721,50 @@ void MainWindow::on_actionRefresh_Panels_triggered()
|
||||
this->updateFrames();
|
||||
}
|
||||
|
||||
void MainWindow::seek(const QString &offset, const QString &name)
|
||||
|
||||
void MainWindow::seek(const QString &offset, const QString &name, bool raise_memory_dock)
|
||||
{
|
||||
if (offset.length() == 0)
|
||||
// TODO: remove this method and use the one with RVA only!
|
||||
|
||||
if(offset.length() < 2)
|
||||
return;
|
||||
|
||||
bool ok;
|
||||
RVA addr = offset.mid(2).toULongLong(&ok, 16);
|
||||
if(!ok)
|
||||
return;
|
||||
|
||||
seek(addr, name, raise_memory_dock);
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::seek(const RVA offset, const QString &name, bool raise_memory_dock)
|
||||
{
|
||||
if (name != NULL)
|
||||
{
|
||||
this->memoryDock->setWindowTitle(name);
|
||||
this->current_address = name;
|
||||
//this->current_address = name;
|
||||
}
|
||||
this->hexdumpTopOffset = 0;
|
||||
this->hexdumpBottomOffset = 0;
|
||||
core->seek(offset);
|
||||
setCursorAddress(offset);
|
||||
|
||||
refreshMem(offset);
|
||||
this->memoryDock->disasTextEdit->setFocus();
|
||||
|
||||
// Rise and shine baby!
|
||||
if(raise_memory_dock)
|
||||
this->memoryDock->raise();
|
||||
}
|
||||
|
||||
void MainWindow::refreshMem(const QString &offset)
|
||||
void MainWindow::refreshMem()
|
||||
{
|
||||
this->memoryDock->updateViews();
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::refreshMem(RVA offset)
|
||||
{
|
||||
//add_debug_output("Refreshing to: " + off);
|
||||
//graphicsBar->refreshColorBar();
|
||||
@ -747,20 +773,18 @@ void MainWindow::refreshMem(const QString &offset)
|
||||
this->memoryDock->refreshHexdump(off);
|
||||
this->memoryDock->create_graph(off);
|
||||
*/
|
||||
this->memoryDock->updateViews();
|
||||
this->memoryDock->get_refs_data(offset);
|
||||
this->memoryDock->setFcnName(offset);
|
||||
refreshMem();
|
||||
this->memoryDock->get_refs_data(RAddressString(offset));
|
||||
//this->memoryDock->setFcnName(offset);
|
||||
}
|
||||
|
||||
void MainWindow::on_backButton_clicked()
|
||||
{
|
||||
QList<RVA> seek_history = core->getSeekHistory();
|
||||
this->core->cmd("s-");
|
||||
QString back_offset = this->core->cmd("s=").split(" > ").last().trimmed();
|
||||
if (back_offset != "")
|
||||
{
|
||||
QString fcn = this->core->cmdFunctionAt(back_offset);
|
||||
this->seek(this->memoryDock->normalizeAddr(back_offset), fcn);
|
||||
}
|
||||
RVA offset = this->core->getOffset();
|
||||
QString fcn = this->core->cmdFunctionAt(QString::number(offset));
|
||||
this->seek(offset, fcn);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionCalculator_triggered()
|
||||
@ -907,6 +931,7 @@ void MainWindow::add_output(QString msg)
|
||||
|
||||
void MainWindow::add_debug_output(QString msg)
|
||||
{
|
||||
printf("debug output: %s\n", msg.toLocal8Bit().constData());
|
||||
ui->consoleOutputTextEdit->appendHtml("<font color=\"red\"> [DEBUG]:\t" + msg + "</font>");
|
||||
ui->consoleOutputTextEdit->verticalScrollBar()->setValue(ui->consoleOutputTextEdit->verticalScrollBar()->maximum());
|
||||
}
|
||||
@ -996,12 +1021,9 @@ void MainWindow::on_actionDashboard_triggered()
|
||||
void MainWindow::on_actionForward_triggered()
|
||||
{
|
||||
this->core->cmd("s+");
|
||||
QString offset = this->core->cmd("s=").split(" > ").last().trimmed();
|
||||
if (offset != "")
|
||||
{
|
||||
this->add_debug_output(offset);
|
||||
this->seek(offset);
|
||||
}
|
||||
RVA offset = core->getOffset();
|
||||
this->add_debug_output(QString::number(offset));
|
||||
this->seek(offset);
|
||||
}
|
||||
|
||||
void MainWindow::toggleResponsive(bool maybe)
|
||||
@ -1035,6 +1057,12 @@ void MainWindow::on_actionQuit_triggered()
|
||||
close();
|
||||
}
|
||||
|
||||
void MainWindow::setCursorAddress(RVA addr)
|
||||
{
|
||||
this->cursor_address = addr;
|
||||
emit cursorAddressChanged(addr);
|
||||
}
|
||||
|
||||
void MainWindow::refreshVisibleDockWidgets()
|
||||
{
|
||||
// There seems to be no convenience function to check if a QDockWidget
|
||||
|
@ -47,7 +47,6 @@ public:
|
||||
Notepad *notepadDock;
|
||||
|
||||
bool responsive;
|
||||
QString current_address;
|
||||
|
||||
explicit MainWindow(QWidget *parent = 0, QRCore *kore = nullptr);
|
||||
~MainWindow();
|
||||
@ -56,8 +55,9 @@ public:
|
||||
void closeEvent(QCloseEvent *event);
|
||||
void readSettings();
|
||||
void setFilename(QString fn);
|
||||
void setCore(QRCore *core);
|
||||
void seek(const QString &offset, const QString &name = NULL);
|
||||
//void setCore(QRCore *core);
|
||||
void seek(const QString &offset, const QString &name = NULL, bool raise_memory_dock = false);
|
||||
void seek(const RVA offset, const QString &name = NULL, bool raise_memory_dock = false);
|
||||
void updateFrames();
|
||||
void refreshFunctions();
|
||||
void refreshComments();
|
||||
@ -70,6 +70,9 @@ public:
|
||||
void toggleSideBarTheme();
|
||||
void refreshOmniBar(const QStringList &flags);
|
||||
|
||||
signals:
|
||||
void cursorAddressChanged(RVA address);
|
||||
|
||||
public slots:
|
||||
|
||||
void dark();
|
||||
@ -185,7 +188,8 @@ private:
|
||||
SideBar *sideBar;
|
||||
|
||||
bool doLock;
|
||||
void refreshMem(const QString &offset = QString());
|
||||
void refreshMem();
|
||||
void refreshMem(RVA offset);
|
||||
ut64 hexdumpTopOffset;
|
||||
ut64 hexdumpBottomOffset;
|
||||
QString filename;
|
||||
@ -207,6 +211,12 @@ private:
|
||||
QAction *sidebar_action;
|
||||
SectionsDock *sectionsDock;
|
||||
WebServerThread webserverThread;
|
||||
|
||||
RVA cursor_address;
|
||||
|
||||
public:
|
||||
RVA getCursorAddress() const { return cursor_address; }
|
||||
void setCursorAddress(RVA addr);
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
@ -61,13 +61,10 @@ OptionsDialog::~OptionsDialog()
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void OptionsDialog::on_closeButton_clicked()
|
||||
void OptionsDialog::setupAndStartAnalysis(int level)
|
||||
{
|
||||
close();
|
||||
}
|
||||
ui->analSlider->setValue(level);
|
||||
|
||||
void OptionsDialog::on_okButton_clicked()
|
||||
{
|
||||
this->setEnabled(0);
|
||||
ui->logo->setEnabled(true);
|
||||
|
||||
@ -199,7 +196,17 @@ void OptionsDialog::on_okButton_clicked()
|
||||
// Threads stuff
|
||||
// connect signal/slot
|
||||
|
||||
analThread.start(core, ui->analSlider->value());
|
||||
analThread.start(core, level);
|
||||
}
|
||||
|
||||
void OptionsDialog::on_closeButton_clicked()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void OptionsDialog::on_okButton_clicked()
|
||||
{
|
||||
setupAndStartAnalysis(ui->analSlider->value());
|
||||
}
|
||||
|
||||
void OptionsDialog::anal_finished()
|
||||
|
@ -24,6 +24,8 @@ public:
|
||||
RAnalFunction functionAt(ut64 addr);
|
||||
QStringList asm_plugins;
|
||||
|
||||
void setupAndStartAnalysis(int level);
|
||||
|
||||
private slots:
|
||||
void on_closeButton_clicked();
|
||||
|
||||
|
315
src/qrcore.cpp
315
src/qrcore.cpp
@ -222,8 +222,20 @@ QJsonDocument QRCore::cmdj(const QString &str)
|
||||
{
|
||||
CORE_LOCK();
|
||||
QByteArray cmd = str.toUtf8();
|
||||
|
||||
char *res = r_core_cmd_str(this->core_, cmd.constData());
|
||||
QJsonDocument doc = res ? QJsonDocument::fromJson(QByteArray(res)) : QJsonDocument();
|
||||
|
||||
QString resString = QString(res);
|
||||
|
||||
QJsonParseError jsonError;
|
||||
QJsonDocument doc = res ? QJsonDocument::fromJson(resString.toUtf8(), &jsonError) : QJsonDocument();
|
||||
|
||||
if(jsonError.error != QJsonParseError::NoError)
|
||||
{
|
||||
eprintf("Failed to parse JSON: %s\n", jsonError.errorString().toLocal8Bit().constData());
|
||||
eprintf("%s\n", resString.toLocal8Bit().constData());
|
||||
}
|
||||
|
||||
r_mem_free(res);
|
||||
return doc;
|
||||
}
|
||||
@ -345,6 +357,13 @@ void QRCore::analyze(int level)
|
||||
void QRCore::renameFunction(QString prev_name, QString new_name)
|
||||
{
|
||||
cmd("afn " + new_name + " " + prev_name);
|
||||
emit functionRenamed(prev_name, new_name);
|
||||
}
|
||||
|
||||
void QRCore::setComment(RVA addr, QString cmt)
|
||||
{
|
||||
//r_meta_add (core->anal, 'C', addr, 1, cmt.toUtf8());
|
||||
cmd("CC " + cmt + " @ " + QString::number(addr));
|
||||
}
|
||||
|
||||
void QRCore::setComment(QString addr, QString cmt)
|
||||
@ -360,24 +379,6 @@ void QRCore::delComment(ut64 addr)
|
||||
//cmd (QString("CC-@")+addr);
|
||||
}
|
||||
|
||||
QList<QList<QString>> QRCore::getComments()
|
||||
{
|
||||
QList<QList<QString>> ret;
|
||||
QString comments = cmd("CC~CCu");
|
||||
for (QString line : comments.split("\n"))
|
||||
{
|
||||
QStringList fields = line.split("CCu");
|
||||
if (fields.length() == 2)
|
||||
{
|
||||
QList<QString> tmp = QList<QString>();
|
||||
tmp << fields[1].split("\"")[1].trimmed();
|
||||
tmp << fields[0].trimmed();
|
||||
ret << tmp;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QMap<QString, QList<QList<QString>>> QRCore::getNestedComments()
|
||||
{
|
||||
QMap<QString, QList<QList<QString>>> ret;
|
||||
@ -404,10 +405,12 @@ void QRCore::seek(QString addr)
|
||||
seek(this->math(addr.toUtf8().constData()));
|
||||
}
|
||||
|
||||
void QRCore::seek(ut64 addr)
|
||||
|
||||
|
||||
void QRCore::seek(ut64 offset)
|
||||
{
|
||||
CORE_LOCK();
|
||||
r_core_seek(this->core_, addr, true);
|
||||
r_core_seek(this->core_, offset, true);
|
||||
}
|
||||
|
||||
bool QRCore::tryFile(QString path, bool rw)
|
||||
@ -457,84 +460,11 @@ QList<QString> QRCore::getList(const QString &type, const QString &subtype)
|
||||
if (ft && *ft)
|
||||
ret << ft;
|
||||
}
|
||||
else if (subtype == "imports")
|
||||
{
|
||||
QJsonArray importsArray = cmdj("iij").array();
|
||||
|
||||
foreach (QJsonValue value, importsArray)
|
||||
{
|
||||
QJsonObject importObject = value.toObject();
|
||||
unsigned long plt = (unsigned long)importObject["plt"].toVariant().toULongLong();
|
||||
int ordinal = importObject["ordinal"].toInt();
|
||||
|
||||
QString final = QString("%1,%2,%3,%4,%5,").arg(
|
||||
QString::asprintf("%#o", ordinal),
|
||||
QString::asprintf("%#010lx", plt),
|
||||
importObject["bind"].toString(),
|
||||
importObject["type"].toString(),
|
||||
importObject["name"].toString());
|
||||
|
||||
|
||||
ret << final;
|
||||
}
|
||||
}
|
||||
else if (subtype == "entrypoints")
|
||||
{
|
||||
if (math("entry0") != 0)
|
||||
ret << "entry0";
|
||||
}
|
||||
else if (subtype == "relocs")
|
||||
{
|
||||
RBinReloc *br;
|
||||
if (core_ && core_->bin && core_->bin->cur && core_->bin->cur->o)
|
||||
{
|
||||
QRListForeach(core_->bin->cur->o->relocs, it, RBinReloc, br)
|
||||
{
|
||||
if (br->import)
|
||||
{
|
||||
// TODO: we want the offset too!
|
||||
QString type = (br->additive ? "ADD_" : "SET_") + QString::number(br->type);
|
||||
ret << QString("0x%1,%2,%3").arg(QString::number(br->vaddr, 16), type, br->import->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: we want the offset too!
|
||||
QString type = (br->additive ? "ADD_" : "SET_") + QString::number(br->type);
|
||||
ret << QString("0x%1,%2,reloc_%3").arg(QString::number(br->vaddr, 16), type, QString::number(br->vaddr, 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (subtype == "symbols")
|
||||
{
|
||||
RBinSymbol *bs;
|
||||
if (core_ && core_->bin && core_->bin->cur && core_->bin->cur->o)
|
||||
{
|
||||
QRListForeach(core_->bin->cur->o->symbols, it, RBinSymbol, bs)
|
||||
{
|
||||
QString type = QString(bs->bind) + " " + QString(bs->type);
|
||||
ret << QString("0x%1,%2,%3").arg(QString::number(bs->vaddr, 16), type, bs->name);
|
||||
}
|
||||
/* list entrypoints as symbols too */
|
||||
int n = 0;
|
||||
RBinAddr *entry;
|
||||
QRListForeach(core_->bin->cur->o->entries, it, RBinAddr, entry)
|
||||
{
|
||||
ret << QString("0x%1,%2,%3%4").arg(QString::number(entry->vaddr, 16), "entry", "entry", QString::number(n++));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (subtype == "strings")
|
||||
{
|
||||
RBinString *bs;
|
||||
if (core_ && core_->bin && core_->bin->cur && core_->bin->cur->o)
|
||||
{
|
||||
QRListForeach(core_->bin->cur->o->strings, it, RBinString, bs)
|
||||
{
|
||||
ret << QString("0x%1,%2").arg(QString::number(bs->vaddr, 16), bs->string);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == "asm")
|
||||
{
|
||||
@ -566,18 +496,6 @@ QList<QString> QRCore::getList(const QString &type, const QString &subtype)
|
||||
ret << ap->name;
|
||||
}
|
||||
}
|
||||
else if (subtype == "functions")
|
||||
{
|
||||
QString funcs = cmd("afl");
|
||||
QStringList lines = funcs.split("\n");
|
||||
for (auto i : lines)
|
||||
{
|
||||
if (i != "")
|
||||
{
|
||||
ret << i.replace(" ", ",").replace(",,", ",").replace(",,", ",").replace(",,", ",");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == "flagspaces")
|
||||
{
|
||||
@ -744,10 +662,15 @@ QString QRCore::cmdFunctionAt(QString addr)
|
||||
QString ret;
|
||||
//afi~name:1[1] @ 0x08048e44
|
||||
//ret = cmd("afi~name[1] @ " + addr);
|
||||
ret = cmd("fd @ " + addr + "~[0]");
|
||||
ret = cmd(QString("fd @ ") + addr + "~[0]");
|
||||
return ret.trimmed();
|
||||
}
|
||||
|
||||
QString QRCore::cmdFunctionAt(RVA addr)
|
||||
{
|
||||
return cmdFunctionAt(QString::number(addr));
|
||||
}
|
||||
|
||||
int QRCore::get_size()
|
||||
{
|
||||
CORE_LOCK();
|
||||
@ -922,3 +845,181 @@ void QRCore::setSettings()
|
||||
cmd("ec graph.false rgb:FF6666");
|
||||
cmd("ec graph.trufae rgb:4183D7");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
QList<RVA> QRCore::getSeekHistory()
|
||||
{
|
||||
CORE_LOCK();
|
||||
QList<RVA> ret;
|
||||
|
||||
QJsonArray jsonArray = cmdj("sj").array();
|
||||
foreach(QJsonValue value, jsonArray)
|
||||
ret << value.toVariant().toULongLong();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QList<FunctionDescription> QRCore::getAllFunctions()
|
||||
{
|
||||
CORE_LOCK();
|
||||
QList<FunctionDescription> ret;
|
||||
|
||||
QJsonArray jsonArray = cmdj("aflj").array();
|
||||
|
||||
foreach(QJsonValue value, jsonArray)
|
||||
{
|
||||
QJsonObject jsonObject = value.toObject();
|
||||
|
||||
FunctionDescription function;
|
||||
|
||||
function.offset = (RVA)jsonObject["offset"].toVariant().toULongLong();
|
||||
function.size = (RVA)jsonObject["size"].toVariant().toULongLong();
|
||||
function.name = jsonObject["name"].toString();
|
||||
|
||||
ret << function;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
QList<ImportDescription> QRCore::getAllImports()
|
||||
{
|
||||
CORE_LOCK();
|
||||
QList<ImportDescription> ret;
|
||||
|
||||
QJsonArray importsArray = cmdj("iij").array();
|
||||
|
||||
foreach(QJsonValue value, importsArray)
|
||||
{
|
||||
QJsonObject importObject = value.toObject();
|
||||
|
||||
ImportDescription import;
|
||||
|
||||
import.plt = importObject["plt"].toVariant().toULongLong();
|
||||
import.ordinal = importObject["ordinal"].toInt();
|
||||
import.bind = importObject["bind"].toString();
|
||||
import.type = importObject["type"].toString();
|
||||
import.name = importObject["name"].toString();
|
||||
|
||||
ret << import;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
QList<SymbolDescription> QRCore::getAllSymbols()
|
||||
{
|
||||
CORE_LOCK();
|
||||
RListIter *it;
|
||||
|
||||
QList<SymbolDescription> ret;
|
||||
|
||||
RBinSymbol *bs;
|
||||
if (core_ && core_->bin && core_->bin->cur && core_->bin->cur->o)
|
||||
{
|
||||
QRListForeach(core_->bin->cur->o->symbols, it, RBinSymbol, bs)
|
||||
{
|
||||
QString type = QString(bs->bind) + " " + QString(bs->type);
|
||||
SymbolDescription symbol;
|
||||
symbol.vaddr = bs->vaddr;
|
||||
symbol.name = QString(bs->name);
|
||||
symbol.bind = QString(bs->bind);
|
||||
symbol.type = QString(bs->type);
|
||||
ret << symbol;
|
||||
}
|
||||
|
||||
/* list entrypoints as symbols too */
|
||||
int n = 0;
|
||||
RBinAddr *entry;
|
||||
QRListForeach(core_->bin->cur->o->entries, it, RBinAddr, entry)
|
||||
{
|
||||
SymbolDescription symbol;
|
||||
symbol.vaddr = entry->vaddr;
|
||||
symbol.name = QString("entry") + QString::number(n++);
|
||||
symbol.bind = "";
|
||||
symbol.type = "entry";
|
||||
ret << symbol;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
QList<CommentDescription> QRCore::getAllComments(QString filterType)
|
||||
{
|
||||
CORE_LOCK();
|
||||
QList<CommentDescription> ret;
|
||||
|
||||
QJsonArray commentsArray = cmdj("CCj").array();
|
||||
for(QJsonValue value : commentsArray)
|
||||
{
|
||||
QJsonObject commentObject = value.toObject();
|
||||
|
||||
QString type = commentObject["type"].toString();
|
||||
if(type != filterType)
|
||||
continue;
|
||||
|
||||
CommentDescription comment;
|
||||
comment.offset = commentObject["offset"].toVariant().toULongLong();
|
||||
comment.name = commentObject["name"].toString();
|
||||
|
||||
ret << comment;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QList<RelocDescription> QRCore::getAllRelocs()
|
||||
{
|
||||
CORE_LOCK();
|
||||
RListIter *it;
|
||||
QList<RelocDescription> ret;
|
||||
|
||||
RBinReloc *br;
|
||||
if (core_ && core_->bin && core_->bin->cur && core_->bin->cur->o)
|
||||
{
|
||||
QRListForeach(core_->bin->cur->o->relocs, it, RBinReloc, br)
|
||||
{
|
||||
RelocDescription reloc;
|
||||
|
||||
reloc.vaddr = br->vaddr;
|
||||
reloc.paddr = br->paddr;
|
||||
reloc.type = (br->additive ? "ADD_" : "SET_") + QString::number(br->type);
|
||||
|
||||
if (br->import)
|
||||
reloc.name = br->import->name;
|
||||
else
|
||||
reloc.name = QString("reloc_%1").arg(QString::number(br->vaddr, 16));
|
||||
|
||||
ret << reloc;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QList<StringDescription> QRCore::getAllStrings()
|
||||
{
|
||||
CORE_LOCK();
|
||||
RListIter *it;
|
||||
QList<StringDescription> ret;
|
||||
|
||||
RBinString *bs;
|
||||
if (core_ && core_->bin && core_->bin->cur && core_->bin->cur->o)
|
||||
{
|
||||
QRListForeach(core_->bin->cur->o->strings, it, RBinString, bs)
|
||||
{
|
||||
StringDescription str;
|
||||
str.vaddr = bs->vaddr;
|
||||
str.string = bs->string;
|
||||
ret << str;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
87
src/qrcore.h
87
src/qrcore.h
@ -44,13 +44,82 @@ public:
|
||||
|
||||
#define QNOTUSED(x) do { (void)(x); } while ( 0 );
|
||||
|
||||
typedef ut64 RVA;
|
||||
|
||||
inline QString RAddressString(RVA addr)
|
||||
{
|
||||
return QString::asprintf("%#010llx", addr);
|
||||
}
|
||||
|
||||
inline QString RSizeString(RVA size)
|
||||
{
|
||||
return QString::asprintf("%lld", size);
|
||||
}
|
||||
|
||||
struct FunctionDescription
|
||||
{
|
||||
RVA offset;
|
||||
RVA size;
|
||||
QString name;
|
||||
|
||||
bool contains(RVA addr) const { return addr >= offset && addr < offset + size; }
|
||||
};
|
||||
|
||||
struct ImportDescription
|
||||
{
|
||||
RVA plt;
|
||||
int ordinal;
|
||||
QString bind;
|
||||
QString type;
|
||||
QString name;
|
||||
};
|
||||
|
||||
struct SymbolDescription
|
||||
{
|
||||
RVA vaddr;
|
||||
QString bind;
|
||||
QString type;
|
||||
QString name;
|
||||
};
|
||||
|
||||
struct CommentDescription
|
||||
{
|
||||
RVA offset;
|
||||
QString name;
|
||||
};
|
||||
|
||||
struct RelocDescription
|
||||
{
|
||||
RVA vaddr;
|
||||
RVA paddr;
|
||||
QString type;
|
||||
QString name;
|
||||
};
|
||||
|
||||
struct StringDescription
|
||||
{
|
||||
RVA vaddr;
|
||||
QString string;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(FunctionDescription)
|
||||
Q_DECLARE_METATYPE(ImportDescription)
|
||||
Q_DECLARE_METATYPE(SymbolDescription)
|
||||
Q_DECLARE_METATYPE(CommentDescription)
|
||||
Q_DECLARE_METATYPE(RelocDescription)
|
||||
Q_DECLARE_METATYPE(StringDescription)
|
||||
|
||||
class QRCore : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QString projectPath;
|
||||
|
||||
explicit QRCore(QObject *parent = 0);
|
||||
~QRCore();
|
||||
|
||||
RVA getOffset() const { return core_->offset; }
|
||||
QList<QString> getFunctionXrefs(ut64 addr);
|
||||
QList<QString> getFunctionRefs(ut64 addr, char type);
|
||||
int getCycloComplex(ut64 addr);
|
||||
@ -61,27 +130,27 @@ public:
|
||||
QString cmd(const QString &str);
|
||||
QJsonDocument cmdj(const QString &str);
|
||||
void renameFunction(QString prev_name, QString new_name);
|
||||
void setComment(RVA addr, QString cmt);
|
||||
void setComment(QString addr, QString cmt);
|
||||
void delComment(ut64 addr);
|
||||
QList<QList<QString>> getComments();
|
||||
QMap<QString, QList<QList<QString>>> getNestedComments();
|
||||
void setOptions(QString key);
|
||||
bool loadFile(QString path, uint64_t loadaddr = 0LL, uint64_t mapaddr = 0LL, bool rw = false, int va = 0, int bits = 0, int idx = 0, bool loadbin = false);
|
||||
bool tryFile(QString path, bool rw);
|
||||
void analyze(int level);
|
||||
void seek(QString addr);
|
||||
void seek(ut64 addr);
|
||||
void seek(ut64 offset);
|
||||
ut64 math(const QString &expr);
|
||||
QString itoa(ut64 num, int rdx = 16);
|
||||
QString config(const QString &k, const QString &v = NULL);
|
||||
int config(const QString &k, int v);
|
||||
QList<QString> getList(const QString &type, const QString &subtype = "");
|
||||
QString assemble(const QString &code);
|
||||
QString disassemble(const QString &hex);
|
||||
void setDefaultCPU();
|
||||
void setCPU(QString arch, QString cpu, int bits, bool temporary = false);
|
||||
RAnalFunction *functionAt(ut64 addr);
|
||||
QString cmdFunctionAt(QString addr);
|
||||
QString cmdFunctionAt(RVA addr);
|
||||
/* sdb */
|
||||
QList<QString> sdbList(QString path);
|
||||
QList<QString> sdbListKeys(QString path);
|
||||
@ -103,12 +172,24 @@ public:
|
||||
QList<QString> regs;
|
||||
void setSettings();
|
||||
|
||||
QList<QString> getList(const QString &type, const QString &subtype = "");
|
||||
|
||||
QList<RVA> getSeekHistory();
|
||||
QList<FunctionDescription> getAllFunctions();
|
||||
QList<ImportDescription> getAllImports();
|
||||
QList<SymbolDescription> getAllSymbols();
|
||||
QList<CommentDescription> getAllComments(QString type);
|
||||
QList<RelocDescription> getAllRelocs();
|
||||
QList<StringDescription> getAllStrings();
|
||||
|
||||
RCoreLocked core() const;
|
||||
|
||||
/* fields */
|
||||
|
||||
Sdb *db;
|
||||
|
||||
signals:
|
||||
void functionRenamed(QString prev_name, QString new_name);
|
||||
|
||||
public slots:
|
||||
|
||||
|
@ -68,6 +68,7 @@
|
||||
<file>html/bar.html</file>
|
||||
<file>html/stats.html</file>
|
||||
<file>img/icons/spin_grey.png</file>
|
||||
<file>img/icons/import_light.svg</file>
|
||||
<file>html/utils.js</file>
|
||||
<file>html/radar.html</file>
|
||||
</qresource>
|
||||
|
@ -52,11 +52,9 @@ void CommentsWidget::on_commentsTreeWidget_itemDoubleClicked(QTreeWidgetItem *it
|
||||
QNOTUSED(column);
|
||||
|
||||
// Get offset and name of item double clicked
|
||||
// TODO: use this info to change disasm contents
|
||||
QString offset = item->text(1);
|
||||
QString name = item->text(2);
|
||||
this->main->add_debug_output(offset + ": " + name);
|
||||
this->main->seek(offset, name);
|
||||
CommentDescription comment = item->data(0, Qt::UserRole).value<CommentDescription>();
|
||||
this->main->add_debug_output(RAddressString(comment.offset) + ": " + comment.name);
|
||||
this->main->seek(comment.offset, comment.name, true);
|
||||
}
|
||||
|
||||
void CommentsWidget::on_toolButton_clicked()
|
||||
@ -122,32 +120,36 @@ void CommentsWidget::resizeEvent(QResizeEvent *event)
|
||||
QDockWidget::resizeEvent(event);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CommentsWidget::refreshTree()
|
||||
{
|
||||
ui->commentsTreeWidget->clear();
|
||||
const QList<QList<QString>> &comments = main->core->getComments();
|
||||
for (const QList<QString> &comment : comments)
|
||||
ui->nestedCmtsTreeWidget->clear();
|
||||
QList<CommentDescription> comments = this->main->core->getAllComments("CCu");
|
||||
|
||||
for (CommentDescription comment : comments)
|
||||
{
|
||||
//this->main->add_debug_output(comment[1]);
|
||||
QString fcn_name = this->main->core->cmdFunctionAt(comment[1]);
|
||||
qhelpers::appendRow(ui->commentsTreeWidget, comment[1], fcn_name, QString(comment[0]).remove('"'));
|
||||
//this->main->add_debug_output(RAddressString(comment.offset));
|
||||
QString fcn_name = this->main->core->cmdFunctionAt(comment.offset);
|
||||
QTreeWidgetItem *item = qhelpers::appendRow(ui->commentsTreeWidget, RAddressString(comment.offset), fcn_name, comment.name);
|
||||
item->setData(0, Qt::UserRole, QVariant::fromValue(comment));
|
||||
}
|
||||
qhelpers::adjustColumns(ui->commentsTreeWidget);
|
||||
|
||||
// Add nested comments
|
||||
ui->nestedCmtsTreeWidget->clear();
|
||||
const QMap<QString, QList<QList<QString>>> &cmts = main->core->getNestedComments();
|
||||
QMap<QString, QList<QList<QString>>> cmts = this->main->core->getNestedComments();
|
||||
for (auto cmt : cmts.keys())
|
||||
{
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem(ui->nestedCmtsTreeWidget);
|
||||
item->setText(0, cmt);
|
||||
const QList<QList<QString>> &meow = cmts.value(cmt);
|
||||
QList<QList<QString>> meow = cmts.value(cmt);
|
||||
for (int i = 0; i < meow.size(); ++i)
|
||||
{
|
||||
const QList<QString> &tmp = meow.at(i);
|
||||
QList<QString> tmp = meow.at(i);
|
||||
QTreeWidgetItem *it = new QTreeWidgetItem();
|
||||
it->setText(0, tmp[1]);
|
||||
it->setText(1, QString(tmp[0]).remove('"'));
|
||||
it->setText(1, tmp[0].remove('"'));
|
||||
item->addChild(it);
|
||||
}
|
||||
ui->nestedCmtsTreeWidget->addTopLevelItem(item);
|
||||
|
@ -47,7 +47,7 @@ void FlagsWidget::on_flagsTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, in
|
||||
|
||||
QString offset = item->text(2);
|
||||
QString name = item->text(3);
|
||||
this->main->seek(offset, name);
|
||||
this->main->seek(offset, name, true);
|
||||
}
|
||||
|
||||
void FlagsWidget::on_flagspaceCombo_currentTextChanged(const QString &arg1)
|
||||
|
@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<width>463</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -71,11 +71,6 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="flagsTreeWidget">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QTreeWidget::item
|
||||
{
|
||||
@ -113,7 +108,7 @@ QTreeWidget::item:selected
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>5</number>
|
||||
<number>4</number>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
@ -135,11 +130,6 @@ QTreeWidget::item:selected
|
||||
<string notr="true">Name</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">Comment</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -7,10 +7,316 @@
|
||||
#include "dialogs/renamedialog.h"
|
||||
#include "dialogs/xrefsdialog.h"
|
||||
|
||||
#include <QTreeWidget>
|
||||
#include <algorithm>
|
||||
#include <QMenu>
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QResource>
|
||||
|
||||
FunctionModel::FunctionModel(QList<FunctionDescription> *functions, QSet<RVA> *import_addresses, bool nested, QFont default_font, QFont highlight_font, MainWindow *main, QObject *parent)
|
||||
: functions(functions),
|
||||
import_addresses(import_addresses),
|
||||
main(main),
|
||||
nested(nested),
|
||||
default_font(default_font),
|
||||
highlight_font(highlight_font),
|
||||
QAbstractItemModel(parent)
|
||||
{
|
||||
current_index = -1;
|
||||
|
||||
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
|
||||
{
|
||||
if(!parent.isValid())
|
||||
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
|
||||
{
|
||||
if(!index.isValid() || index.column() != 0)
|
||||
return QModelIndex();
|
||||
|
||||
if(index.internalId() == 0) // root function node
|
||||
return QModelIndex();
|
||||
else // sub-node
|
||||
return this->index((int)(index.internalId()-1), 0);
|
||||
}
|
||||
|
||||
int FunctionModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if(!parent.isValid())
|
||||
return functions->count();
|
||||
|
||||
if(nested)
|
||||
{
|
||||
if(parent.internalId() == 0)
|
||||
return 3; // sub-nodes for nested functions
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FunctionModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
if(nested)
|
||||
return 1;
|
||||
else
|
||||
return 4;
|
||||
}
|
||||
|
||||
|
||||
QVariant FunctionModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if(!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
int function_index;
|
||||
bool subnode;
|
||||
if(index.internalId() != 0) // sub-node
|
||||
{
|
||||
function_index = index.parent().row();
|
||||
subnode = true;
|
||||
}
|
||||
else // root function node
|
||||
{
|
||||
function_index = index.row();
|
||||
subnode = false;
|
||||
}
|
||||
|
||||
const FunctionDescription &function = functions->at(function_index);
|
||||
|
||||
if(function_index >= functions->count())
|
||||
return QVariant();
|
||||
|
||||
switch(role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
if(nested)
|
||||
{
|
||||
if(subnode)
|
||||
{
|
||||
switch(index.row())
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
else
|
||||
return function.name;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(index.column())
|
||||
{
|
||||
case 0:
|
||||
return RAddressString(function.offset);
|
||||
case 1:
|
||||
return RSizeString(function.size);
|
||||
case 3:
|
||||
return function.name;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
case Qt::DecorationRole:
|
||||
if(import_addresses->contains(function.offset) &&
|
||||
(nested ? false :index.column() == 2))
|
||||
return QIcon(":/img/icons/import_light.svg");
|
||||
return QVariant();
|
||||
|
||||
case Qt::FontRole:
|
||||
if(current_index == function_index)
|
||||
return highlight_font;
|
||||
return default_font;
|
||||
|
||||
case Qt::ToolTipRole:
|
||||
{
|
||||
QList<QString> info = main->core->cmd("afi @ " + function.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];
|
||||
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));
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
case FunctionDescriptionRole:
|
||||
return QVariant::fromValue(function);
|
||||
|
||||
case IsImportRole:
|
||||
return import_addresses->contains(function.offset);
|
||||
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant FunctionModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if(role == Qt::DisplayRole && orientation == Qt::Horizontal)
|
||||
{
|
||||
if(nested)
|
||||
{
|
||||
return tr("Name");
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (section)
|
||||
{
|
||||
case 0:
|
||||
return tr("Offset");
|
||||
case 1:
|
||||
return tr("Size");
|
||||
case 2:
|
||||
return tr("Imp.");
|
||||
case 3:
|
||||
return tr("Name");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void FunctionModel::beginReloadFunctions()
|
||||
{
|
||||
beginResetModel();
|
||||
}
|
||||
|
||||
void FunctionModel::endReloadFunctions()
|
||||
{
|
||||
updateCurrentIndex();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void FunctionModel::cursorAddressChanged(RVA)
|
||||
{
|
||||
updateCurrentIndex();
|
||||
emit dataChanged(index(0, 0), index(rowCount()-1, columnCount()-1));
|
||||
}
|
||||
|
||||
void FunctionModel::updateCurrentIndex()
|
||||
{
|
||||
RVA addr = main->getCursorAddress();
|
||||
|
||||
int index = -1;
|
||||
RVA offset = 0;
|
||||
|
||||
for(int i=0; i<functions->count(); i++)
|
||||
{
|
||||
const FunctionDescription &function = functions->at(i);
|
||||
|
||||
if(function.contains(addr)
|
||||
&& function.offset >= offset)
|
||||
{
|
||||
offset = function.offset;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
current_index = index;
|
||||
}
|
||||
|
||||
void FunctionModel::functionRenamed(QString prev_name, QString new_name)
|
||||
{
|
||||
for(int i=0; i<functions->count(); i++)
|
||||
{
|
||||
FunctionDescription &function = (*functions)[i];
|
||||
if(function.name == prev_name)
|
||||
{
|
||||
function.name = new_name;
|
||||
emit dataChanged(index(i, 0), index(i, columnCount()-1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
FunctionSortFilterProxyModel::FunctionSortFilterProxyModel(FunctionModel *source_model, QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
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
|
||||
{
|
||||
if(!left.isValid() || !right.isValid())
|
||||
return false;
|
||||
|
||||
if(left.parent().isValid() || right.parent().isValid())
|
||||
return false;
|
||||
|
||||
FunctionDescription left_function = left.data(FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
||||
FunctionDescription right_function = right.data(FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
||||
|
||||
|
||||
if(static_cast<FunctionModel *>(sourceModel())->isNested())
|
||||
{
|
||||
return left_function.name < right_function.name;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (left.column())
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
return left_function.offset < right_function.offset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
FunctionsWidget::FunctionsWidget(MainWindow *main, QWidget *parent) :
|
||||
@ -20,15 +326,33 @@ FunctionsWidget::FunctionsWidget(MainWindow *main, QWidget *parent) :
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->functionsTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
//ui->functionsTreeWidget->setFont(QFont("Monospace", 8));
|
||||
// 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);
|
||||
|
||||
|
||||
// Set Functions context menu
|
||||
connect(ui->functionsTreeWidget, SIGNAL(customContextMenuRequested(const QPoint &)),
|
||||
connect(ui->functionsTreeView, SIGNAL(customContextMenuRequested(const QPoint &)),
|
||||
this, SLOT(showFunctionsContextMenu(const QPoint &)));
|
||||
connect(ui->nestedFunctionsTree, SIGNAL(customContextMenuRequested(const QPoint &)),
|
||||
connect(ui->nestedFunctionsTreeView, SIGNAL(customContextMenuRequested(const QPoint &)),
|
||||
this, SLOT(showFunctionsContextMenu(const QPoint &)));
|
||||
|
||||
ui->functionsTreeWidget->hideColumn(0);
|
||||
|
||||
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 &)));
|
||||
|
||||
// Hide the tabs
|
||||
QTabBar *tabs = ui->tabWidget->tabBar();
|
||||
@ -50,8 +374,7 @@ FunctionsWidget::~FunctionsWidget()
|
||||
void FunctionsWidget::setup()
|
||||
{
|
||||
setScrollMode();
|
||||
|
||||
fillFunctions();
|
||||
refreshTree();
|
||||
}
|
||||
|
||||
void FunctionsWidget::refresh()
|
||||
@ -59,72 +382,46 @@ void FunctionsWidget::refresh()
|
||||
setup();
|
||||
}
|
||||
|
||||
void FunctionsWidget::fillFunctions()
|
||||
void FunctionsWidget::refreshTree()
|
||||
{
|
||||
ui->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
|
||||
qhelpers::appendRow(ui->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
|
||||
qhelpers::appendRow(ui->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;
|
||||
}
|
||||
}
|
||||
ui->functionsTreeWidget->sortByColumn(3, Qt::AscendingOrder);
|
||||
ui->nestedFunctionsTree->sortByColumn(0, Qt::AscendingOrder);
|
||||
qhelpers::adjustColumns(ui->functionsTreeWidget);
|
||||
function_model->beginReloadFunctions();
|
||||
nested_function_model->beginReloadFunctions();
|
||||
|
||||
this->addTooltips();
|
||||
functions = this->main->core->getAllFunctions();
|
||||
|
||||
import_addresses.clear();
|
||||
foreach(ImportDescription import, main->core->getAllImports())
|
||||
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);
|
||||
}
|
||||
|
||||
void FunctionsWidget::on_functionsTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)
|
||||
QTreeView *FunctionsWidget::getCurrentTreeView()
|
||||
{
|
||||
QNOTUSED(column);
|
||||
if (ui->tabWidget->currentIndex() == 0)
|
||||
return ui->functionsTreeView;
|
||||
else
|
||||
return ui->nestedFunctionsTreeView;
|
||||
}
|
||||
|
||||
QString offset = item->text(1);
|
||||
QString name = item->text(3);
|
||||
this->main->seek(offset, name);
|
||||
this->main->raiseMemoryDock();
|
||||
void FunctionsWidget::on_functionsTreeView_itemDoubleClicked(const QModelIndex &index)
|
||||
{
|
||||
FunctionDescription function = index.data(FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
||||
this->main->seek(function.offset, function.name, true);
|
||||
}
|
||||
|
||||
void FunctionsWidget::showFunctionsContextMenu(const QPoint &pt)
|
||||
{
|
||||
QTreeView *treeView = getCurrentTreeView();
|
||||
|
||||
// Set functions popup menu
|
||||
QMenu *menu = new QMenu(ui->functionsTreeWidget);
|
||||
QMenu *menu = new QMenu(ui->functionsTreeView);
|
||||
menu->clear();
|
||||
menu->addAction(ui->actionDisasAdd_comment);
|
||||
menu->addAction(ui->actionFunctionsRename);
|
||||
@ -132,189 +429,76 @@ void FunctionsWidget::showFunctionsContextMenu(const QPoint &pt)
|
||||
menu->addSeparator();
|
||||
menu->addAction(ui->action_References);
|
||||
|
||||
if (ui->tabWidget->currentIndex() == 0)
|
||||
{
|
||||
ui->functionsTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
menu->exec(ui->functionsTreeWidget->mapToGlobal(pt));
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->nestedFunctionsTree->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
menu->exec(ui->nestedFunctionsTree->mapToGlobal(pt));
|
||||
}
|
||||
menu->exec(treeView->mapToGlobal(pt));
|
||||
|
||||
delete menu;
|
||||
}
|
||||
|
||||
void FunctionsWidget::refreshTree()
|
||||
{
|
||||
ui->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
|
||||
qhelpers::appendRow(ui->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
|
||||
qhelpers::appendRow(ui->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;
|
||||
}
|
||||
}
|
||||
ui->functionsTreeWidget->sortByColumn(3, Qt::AscendingOrder);
|
||||
ui->nestedFunctionsTree->sortByColumn(0, Qt::AscendingOrder);
|
||||
qhelpers::adjustColumns(ui->functionsTreeWidget);
|
||||
|
||||
this->addTooltips();
|
||||
}
|
||||
|
||||
void FunctionsWidget::on_actionDisasAdd_comment_triggered()
|
||||
{
|
||||
QString fcn_name = "";
|
||||
// Get selected item in functions tree view
|
||||
QTreeView *treeView = getCurrentTreeView();
|
||||
FunctionDescription function = treeView->selectionModel()->currentIndex().data(FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
||||
|
||||
// Create dialog
|
||||
CommentsDialog *c = new CommentsDialog(this);
|
||||
// Get selected item in functions tree widget
|
||||
if (ui->tabWidget->currentIndex() == 0)
|
||||
{
|
||||
QList<QTreeWidgetItem *> selected_rows = ui->functionsTreeWidget->selectedItems();
|
||||
// Get selected function name
|
||||
fcn_name = selected_rows.first()->text(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
QList<QTreeWidgetItem *> 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);
|
||||
this->main->add_debug_output("Comment: " + comment + " at: " + function.name);
|
||||
// Rename function in r2 core
|
||||
this->main->core->setComment(fcn_name, comment);
|
||||
this->main->core->setComment(function.offset, comment);
|
||||
// Seek to new renamed function
|
||||
this->main->seek(fcn_name);
|
||||
this->main->seek(function.offset, function.name);
|
||||
// TODO: Refresh functions tree widget
|
||||
}
|
||||
this->main->refreshComments();
|
||||
}
|
||||
|
||||
void FunctionsWidget::addTooltips()
|
||||
{
|
||||
|
||||
// Add comments to list functions
|
||||
QList<QTreeWidgetItem *> clist = ui->functionsTreeWidget->findItems("*", Qt::MatchWildcard, 3);
|
||||
foreach (QTreeWidgetItem *item, clist)
|
||||
{
|
||||
QString name = item->text(3);
|
||||
QList<QString> 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<QTreeWidgetItem *> nlist = ui->nestedFunctionsTree->findItems("*", Qt::MatchWildcard, 0);
|
||||
foreach (QTreeWidgetItem *item, nlist)
|
||||
{
|
||||
QString name = item->text(0);
|
||||
QList<QString> 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()
|
||||
{
|
||||
// Get selected item in functions tree view
|
||||
QTreeView *treeView = getCurrentTreeView();
|
||||
FunctionDescription function = treeView->selectionModel()->currentIndex().data(FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
||||
|
||||
// Create dialog
|
||||
RenameDialog *r = new RenameDialog(this);
|
||||
// Get selected item in functions tree widget
|
||||
QList<QTreeWidgetItem *> 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);
|
||||
r->setFunctionName(function.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);
|
||||
this->main->core->renameFunction(function.name, 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);
|
||||
//
|
||||
// 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);
|
||||
this->main->seek(function.offset);
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionsWidget::on_action_References_triggered()
|
||||
{
|
||||
QList<QTreeWidgetItem *> selected_rows = ui->functionsTreeWidget->selectedItems();
|
||||
// Get selected function address
|
||||
QString address = selected_rows.first()->text(1);
|
||||
// Get selected item in functions tree view
|
||||
QTreeView *treeView = getCurrentTreeView();
|
||||
FunctionDescription function = treeView->selectionModel()->currentIndex().data(FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
||||
|
||||
//this->main->add_debug_output("Addr: " + address);
|
||||
|
||||
// Get function for clicked offset
|
||||
RAnalFunction *fcn = this->main->core->functionAt(address.toLongLong(0, 16));
|
||||
RAnalFunction *fcn = this->main->core->functionAt(function.offset);
|
||||
|
||||
XrefsDialog *x = new XrefsDialog(this->main, this);
|
||||
x->setWindowTitle("X-Refs for function " + QString::fromUtf8(fcn->name));
|
||||
@ -396,17 +580,6 @@ void FunctionsWidget::on_actionVertical_triggered()
|
||||
ui->tabWidget->setCurrentIndex(1);
|
||||
}
|
||||
|
||||
void FunctionsWidget::on_nestedFunctionsTree_itemDoubleClicked(QTreeWidgetItem *item, int column)
|
||||
{
|
||||
QNOTUSED(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->raiseMemoryDock();
|
||||
}
|
||||
|
||||
void FunctionsWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
if (main->responsive && isVisible())
|
||||
@ -427,5 +600,5 @@ void FunctionsWidget::resizeEvent(QResizeEvent *event)
|
||||
|
||||
void FunctionsWidget::setScrollMode()
|
||||
{
|
||||
qhelpers::setVerticalScrollMode(ui->functionsTreeWidget);
|
||||
qhelpers::setVerticalScrollMode(ui->functionsTreeView);
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
#ifndef FUNCTIONSWIDGET_H
|
||||
#define FUNCTIONSWIDGET_H
|
||||
|
||||
#include <QDockWidget>
|
||||
#include <QTreeWidget>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include "qrcore.h"
|
||||
#include "dashboard.h"
|
||||
|
||||
class MainWindow;
|
||||
@ -11,6 +15,67 @@ namespace Ui
|
||||
class FunctionsWidget;
|
||||
}
|
||||
|
||||
|
||||
class FunctionModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
MainWindow *main;
|
||||
|
||||
QList<FunctionDescription> *functions;
|
||||
QSet<RVA> *import_addresses;
|
||||
|
||||
|
||||
QFont highlight_font;
|
||||
QFont default_font;
|
||||
bool nested;
|
||||
|
||||
int current_index;
|
||||
|
||||
public:
|
||||
static const int FunctionDescriptionRole = Qt::UserRole;
|
||||
static const int IsImportRole = Qt::UserRole + 1;
|
||||
|
||||
FunctionModel(QList<FunctionDescription> *functions, QSet<RVA> *import_addresses, bool nested, QFont default_font, QFont highlight_font, MainWindow *main, QObject *parent = 0);
|
||||
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
|
||||
QModelIndex parent(const QModelIndex &index) const;
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
|
||||
void beginReloadFunctions();
|
||||
void endReloadFunctions();
|
||||
|
||||
void updateCurrentIndex();
|
||||
|
||||
bool isNested() { return nested; }
|
||||
|
||||
private slots:
|
||||
void cursorAddressChanged(RVA addr);
|
||||
void functionRenamed(QString prev_name, QString new_name);
|
||||
|
||||
};
|
||||
|
||||
|
||||
class FunctionSortFilterProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FunctionSortFilterProxyModel(FunctionModel *source_model, QObject *parent = 0);
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int row, const QModelIndex &parent) const override;
|
||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FunctionsWidget : public DockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -23,11 +88,8 @@ public:
|
||||
|
||||
void refresh() override;
|
||||
|
||||
void fillFunctions();
|
||||
void addTooltips();
|
||||
|
||||
private slots:
|
||||
void on_functionsTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column);
|
||||
void on_functionsTreeView_itemDoubleClicked(const QModelIndex &index);
|
||||
void showFunctionsContextMenu(const QPoint &pt);
|
||||
|
||||
void on_actionDisasAdd_comment_triggered();
|
||||
@ -42,17 +104,30 @@ private slots:
|
||||
|
||||
void on_actionVertical_triggered();
|
||||
|
||||
void on_nestedFunctionsTree_itemDoubleClicked(QTreeWidgetItem *item, int column);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
QTreeView *getCurrentTreeView();
|
||||
|
||||
Ui::FunctionsWidget *ui;
|
||||
MainWindow *main;
|
||||
|
||||
QList<FunctionDescription> functions;
|
||||
QSet<RVA> import_addresses;
|
||||
|
||||
FunctionModel *function_model;
|
||||
FunctionSortFilterProxyModel *function_proxy_model;
|
||||
|
||||
FunctionModel *nested_function_model;
|
||||
FunctionSortFilterProxyModel *nested_function_proxy_model;
|
||||
|
||||
void refreshTree();
|
||||
void setScrollMode();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // FUNCTIONSWIDGET_H
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
<width>603</width>
|
||||
<height>314</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
@ -67,23 +67,12 @@ border-top: 0px;
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="functionsTreeWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<widget class="QTreeView" name="functionsTreeView">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QTreeWidget::item
|
||||
<string notr="true">QTreeView::item
|
||||
{
|
||||
padding-left:10px;
|
||||
padding-top: 1px;
|
||||
@ -91,20 +80,20 @@ border-top: 0px;
|
||||
border-left: 10px;
|
||||
}
|
||||
|
||||
QTreeWidget::item:hover
|
||||
QTreeView::item:hover
|
||||
{
|
||||
background: rgb(242, 246, 248);
|
||||
color: black;
|
||||
}
|
||||
|
||||
QTreeWidget::item:selected
|
||||
QTreeView::item:selected
|
||||
{
|
||||
background: gray;
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
QToolTip {
|
||||
QToolTip
|
||||
{
|
||||
background-color: #444;
|
||||
border: 3px solid #444;
|
||||
color: rgb(232, 232, 232);
|
||||
@ -120,47 +109,12 @@ QToolTip {
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="indentation">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="uniformRowHeights">
|
||||
<bool>false</bool>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="allColumnsShowFocus">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<attribute name="headerHighlightSections">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Dummy</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Offset</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Size</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@ -186,12 +140,12 @@ QToolTip {
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="nestedFunctionsTree">
|
||||
<widget class="QTreeView" name="nestedFunctionsTreeView">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QTreeWidget::item
|
||||
<string notr="true">QTreeView::item
|
||||
{
|
||||
padding-left:10px;
|
||||
padding-top: 1px;
|
||||
@ -199,17 +153,17 @@ QToolTip {
|
||||
border-left: 10px;
|
||||
}
|
||||
|
||||
QTreeWidget::item:selected
|
||||
QTreeView::item:selected
|
||||
{
|
||||
background: gray;
|
||||
color: white;
|
||||
}
|
||||
|
||||
QTreeWidget::branch:selected
|
||||
QTreeView::branch:selected
|
||||
{
|
||||
background: gray;
|
||||
}
|
||||
QTreeWidget::item:hover
|
||||
QTreeView::item:hover
|
||||
{
|
||||
background: rgb(242, 246, 248);
|
||||
color: black;
|
||||
@ -225,20 +179,25 @@ QToolTip {
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="expandsOnDoubleClick">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="filterLineEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Quick Filter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<action name="actionDisasAdd_comment">
|
||||
|
@ -68,13 +68,9 @@ void ImportsWidget::refresh()
|
||||
void ImportsWidget::fillImports()
|
||||
{
|
||||
ui->importsTreeWidget->clear();
|
||||
for (auto i : this->main->core->getList("bin", "imports"))
|
||||
{
|
||||
QStringList a = i.split(",");
|
||||
// ord,plt,name
|
||||
if (a.length() == 6)
|
||||
qhelpers::appendRow(ui->importsTreeWidget, a[1], a[3], "", a[4]);
|
||||
}
|
||||
for (auto i : this->main->core->getAllImports())
|
||||
qhelpers::appendRow(ui->importsTreeWidget, RAddressString(i.plt), i.type, "", i.name);
|
||||
|
||||
highlightUnsafe();
|
||||
qhelpers::adjustColumns(ui->importsTreeWidget, 0, 10);
|
||||
}
|
||||
|
@ -29,11 +29,6 @@
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="importsTreeWidget">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QTreeWidget::item
|
||||
{
|
||||
|
@ -41,9 +41,9 @@ MemoryWidget::MemoryWidget(MainWindow *main) :
|
||||
this->memTabWidget = ui->memTabWidget;
|
||||
|
||||
this->last_fcn = "entry0";
|
||||
this->last_disasm_fcn = "";
|
||||
this->last_graph_fcn = "";
|
||||
this->last_hexdump_fcn = "";
|
||||
this->last_disasm_fcn = 0; //"";
|
||||
this->last_graph_fcn = 0; //"";
|
||||
this->last_hexdump_fcn = 0; //"";
|
||||
|
||||
// Increase asm text edit margin
|
||||
QTextDocument *asm_docu = this->disasTextEdit->document();
|
||||
@ -191,6 +191,15 @@ MemoryWidget::MemoryWidget(MainWindow *main) :
|
||||
connect(this->hexASCIIText->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(hexScrolled()));
|
||||
|
||||
connect(ui->graphWebView->page(), SIGNAL(loadFinished(bool)), this, SLOT(frameLoadFinished(bool)));
|
||||
|
||||
connect(main, SIGNAL(cursorAddressChanged(RVA)), this, SLOT(on_cursorAddressChanged(RVA)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MemoryWidget::on_cursorAddressChanged(RVA addr)
|
||||
{
|
||||
setFcnName(addr);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -394,7 +403,7 @@ void MemoryWidget::setup()
|
||||
refreshHexdump(off);
|
||||
create_graph(off);
|
||||
get_refs_data(off);
|
||||
setFcnName(off);
|
||||
//setFcnName(off);
|
||||
}
|
||||
|
||||
void MemoryWidget::refresh()
|
||||
@ -454,7 +463,7 @@ void MemoryWidget::disasmScrolled()
|
||||
QString ele = lastline.split(" ", QString::SkipEmptyParts)[0];
|
||||
if (ele.contains("0x"))
|
||||
{
|
||||
this->main->core->cmd("ss " + ele);
|
||||
this->main->core->seek(ele);
|
||||
QString raw = this->main->core->cmd("pd 200");
|
||||
QString txt = raw.section("\n", 1, -1);
|
||||
//this->disasTextEdit->appendPlainText(" ;\n ; New content here\n ;\n " + txt.trimmed());
|
||||
@ -511,6 +520,8 @@ void MemoryWidget::refreshDisasm(const QString &offset)
|
||||
//ut64 addr = lcore->offset;
|
||||
//int length = lcore->num->value;
|
||||
|
||||
//printf("refreshDisasm %s\n", offset.toLocal8Bit().constData());
|
||||
|
||||
// Prevent further scroll
|
||||
disconnect(this->disasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled()));
|
||||
disconnect(this->disasTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(on_disasTextEdit_2_cursorPositionChanged()));
|
||||
@ -553,12 +564,12 @@ void MemoryWidget::refreshDisasm(const QString &offset)
|
||||
QString s = this->normalize_addr(this->main->core->cmd("s"));
|
||||
//this->main->add_debug_output("Offset to search: " + s);
|
||||
this->disasTextEdit->ensureCursorVisible();
|
||||
this->disasTextEdit->moveCursor(QTextCursor::End);
|
||||
/*this->disasTextEdit->moveCursor(QTextCursor::End);
|
||||
|
||||
while (this->disasTextEdit->find(QRegExp("^" + s), QTextDocument::FindBackward))
|
||||
{
|
||||
this->disasTextEdit->moveCursor(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
|
||||
}
|
||||
}*/
|
||||
|
||||
connect(this->disasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled()));
|
||||
connect(this->disasTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(on_disasTextEdit_2_cursorPositionChanged()));
|
||||
@ -1568,20 +1579,25 @@ QString MemoryWidget::normalize_addr(QString addr)
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryWidget::setFcnName(QString addr)
|
||||
void MemoryWidget::setFcnName(RVA addr)
|
||||
{
|
||||
// TDOD: FIX ME, ugly
|
||||
if (addr.contains("0x"))
|
||||
RAnalFunction *fcn;
|
||||
bool ok;
|
||||
|
||||
QString addr_string;
|
||||
|
||||
fcn = this->main->core->functionAt(addr);
|
||||
if (ok && fcn)
|
||||
{
|
||||
bool ok = false;
|
||||
RAnalFunction *fcn = this->main->core->functionAt(addr.toULongLong(&ok, 16));
|
||||
if (ok && fcn)
|
||||
{
|
||||
QString segment = this->main->core->cmd("S. @ " + addr).split(" ").last();
|
||||
addr = segment.trimmed() + ":" + fcn->name;
|
||||
}
|
||||
QString segment = this->main->core->cmd("S. @ " + QString::number(addr)).split(" ").last();
|
||||
addr_string = segment.trimmed() + ":" + fcn->name;
|
||||
}
|
||||
ui->fcnNameEdit->setText(addr);
|
||||
else
|
||||
{
|
||||
addr_string = main->core->cmdFunctionAt(addr);
|
||||
}
|
||||
|
||||
ui->fcnNameEdit->setText(addr_string);
|
||||
}
|
||||
|
||||
void MemoryWidget::on_disasTextEdit_2_cursorPositionChanged()
|
||||
@ -1601,6 +1617,10 @@ void MemoryWidget::on_disasTextEdit_2_cursorPositionChanged()
|
||||
QString at = this->main->core->cmdFunctionAt(ele);
|
||||
QString deco = this->main->core->getDecompiledCode(at);
|
||||
|
||||
|
||||
RVA addr = ele.midRef(2).toULongLong(0, 16);
|
||||
this->main->setCursorAddress(addr);
|
||||
|
||||
if (deco != "")
|
||||
{
|
||||
ui->decoTextEdit->setPlainText(deco);
|
||||
@ -1635,7 +1655,6 @@ void MemoryWidget::on_disasTextEdit_2_cursorPositionChanged()
|
||||
this->main->memoryDock->get_refs_data(ele);
|
||||
//this->main->memoryDock->create_graph(ele);
|
||||
this->setMiniGraph(at);
|
||||
this->main->current_address = at;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1972,12 +1991,10 @@ void MemoryWidget::frameLoadFinished(bool ok)
|
||||
|
||||
void MemoryWidget::on_memTabWidget_currentChanged(int /*index*/)
|
||||
{
|
||||
/*
|
||||
this->main->add_debug_output("Update index: " + QString::number(index) + " to function: " + this->main->current_address);
|
||||
this->main->add_debug_output("Last disasm: " + this->last_disasm_fcn);
|
||||
this->main->add_debug_output("Last graph: " + this->last_graph_fcn);
|
||||
this->main->add_debug_output("Last hexdump: " + this->last_hexdump_fcn);
|
||||
*/
|
||||
/*this->main->add_debug_output("Update index: " + QString::number(index) + " to function: " + RAddressString(main->getCursorAddress()));
|
||||
this->main->add_debug_output("Last disasm: " + RAddressString(this->last_disasm_fcn));
|
||||
this->main->add_debug_output("Last graph: " + RAddressString(this->last_graph_fcn));
|
||||
this->main->add_debug_output("Last hexdump: " + RAddressString(this->last_hexdump_fcn));*/
|
||||
this->updateViews();
|
||||
}
|
||||
|
||||
@ -1986,34 +2003,36 @@ void MemoryWidget::updateViews()
|
||||
// Update only the selected view to improve performance
|
||||
|
||||
int index = ui->memTabWidget->tabBar()->currentIndex();
|
||||
|
||||
RVA cursor_addr = main->getCursorAddress();
|
||||
|
||||
QString cursor_addr_string = RAddressString(cursor_addr);
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
// Disasm
|
||||
if (this->last_disasm_fcn != this->main->current_address)
|
||||
if (this->last_disasm_fcn != cursor_addr)
|
||||
{
|
||||
//this->main->add_debug_output("Doing disasm");
|
||||
this->refreshDisasm(this->main->current_address);
|
||||
this->last_disasm_fcn = this->main->current_address;
|
||||
this->refreshDisasm(cursor_addr_string);
|
||||
this->last_disasm_fcn = cursor_addr;
|
||||
}
|
||||
}
|
||||
else if (index == 1)
|
||||
{
|
||||
// Hex
|
||||
if (this->last_hexdump_fcn != this->main->current_address)
|
||||
if (this->last_hexdump_fcn != cursor_addr)
|
||||
{
|
||||
//this->main->add_debug_output("Doing hex");
|
||||
this->refreshHexdump(this->main->current_address);
|
||||
this->last_hexdump_fcn = this->main->current_address;
|
||||
this->refreshHexdump(cursor_addr_string);
|
||||
this->last_hexdump_fcn = cursor_addr;
|
||||
}
|
||||
}
|
||||
else if (index == 2)
|
||||
{
|
||||
// Graph
|
||||
if (this->last_graph_fcn != this->main->current_address)
|
||||
if (this->last_graph_fcn != cursor_addr)
|
||||
{
|
||||
//this->main->add_debug_output("Doing graph");
|
||||
this->create_graph(this->main->current_address);
|
||||
this->last_graph_fcn = this->main->current_address;
|
||||
this->create_graph(cursor_addr_string);
|
||||
this->last_graph_fcn = cursor_addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,8 +84,6 @@ public slots:
|
||||
|
||||
QString normalizeAddr(QString addr);
|
||||
|
||||
void setFcnName(QString addr);
|
||||
|
||||
void setMiniGraph(QString at);
|
||||
|
||||
void switchTheme(bool dark);
|
||||
@ -108,13 +106,18 @@ private:
|
||||
ut64 hexdumpTopOffset;
|
||||
ut64 hexdumpBottomOffset;
|
||||
QString last_fcn;
|
||||
QString last_disasm_fcn;
|
||||
QString last_graph_fcn;
|
||||
QString last_hexdump_fcn;
|
||||
|
||||
RVA last_disasm_fcn;
|
||||
RVA last_graph_fcn;
|
||||
RVA last_hexdump_fcn;
|
||||
|
||||
void setFcnName(RVA addr);
|
||||
|
||||
void setScrollMode();
|
||||
|
||||
private slots:
|
||||
void on_cursorAddressChanged(RVA offset);
|
||||
|
||||
void highlightCurrentLine();
|
||||
|
||||
void highlightHexCurrentLine();
|
||||
|
@ -152,7 +152,7 @@ void Omnibar::on_gotoEntry_returnPressed()
|
||||
{
|
||||
//this->main->seek(this->main->core->cmd("?v " + this->text()), this->text());
|
||||
QString off = this->main->core->cmd("afo " + this->text());
|
||||
this->main->seek(off.trimmed(), this->text());
|
||||
this->main->seek(off.trimmed(), this->text(), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,9 @@ RelocsWidget::RelocsWidget(MainWindow *main, QWidget *parent) :
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// Radare core found in:
|
||||
this->main = main;
|
||||
|
||||
ui->relocsTreeWidget->hideColumn(0);
|
||||
}
|
||||
|
||||
@ -39,23 +42,20 @@ void RelocsWidget::on_relocsTreeWidget_itemDoubleClicked(QTreeWidgetItem *item,
|
||||
QNOTUSED(column);
|
||||
|
||||
// Get offset and name of item double clicked
|
||||
// TODO: use this info to change disasm contents
|
||||
QString offset = item->text(1);
|
||||
QString name = item->text(2);
|
||||
main->seek(offset, name);
|
||||
|
||||
main->raiseMemoryDock();
|
||||
RelocDescription reloc = item->data(0, Qt::UserRole).value<RelocDescription>();
|
||||
main->seek(reloc.vaddr, reloc.name, true);
|
||||
}
|
||||
|
||||
void RelocsWidget::fillTreeWidget()
|
||||
{
|
||||
ui->relocsTreeWidget->clear();
|
||||
for (auto i : main->core->getList("bin", "relocs"))
|
||||
|
||||
for (auto i : main->core->getAllRelocs())
|
||||
{
|
||||
QStringList pieces = i.split(",");
|
||||
if (pieces.length() == 3)
|
||||
qhelpers::appendRow(ui->relocsTreeWidget, pieces[0], pieces[1], pieces[2]);
|
||||
QTreeWidgetItem *item = qhelpers::appendRow(ui->relocsTreeWidget, RAddressString(i.vaddr), i.type, i.name);
|
||||
item->setData(0, Qt::UserRole, QVariant::fromValue(i));
|
||||
}
|
||||
|
||||
qhelpers::adjustColumns(ui->relocsTreeWidget);
|
||||
}
|
||||
|
||||
|
@ -29,11 +29,6 @@
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="relocsTreeWidget">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QTreeWidget::item
|
||||
{
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "helpers.h"
|
||||
|
||||
#include <QTreeWidget>
|
||||
#include <QAbstractItemView>
|
||||
|
||||
|
||||
StringsWidget::StringsWidget(MainWindow *main, QWidget *parent) :
|
||||
@ -41,21 +42,17 @@ void StringsWidget::on_stringsTreeWidget_itemDoubleClicked(QTreeWidgetItem *item
|
||||
|
||||
// Get offset and name of item double clicked
|
||||
// TODO: use this info to change disasm contents
|
||||
QString offset = item->text(1);
|
||||
QString name = item->text(2);
|
||||
this->main->seek(offset);
|
||||
// Rise and shine baby!
|
||||
this->main->raiseMemoryDock();
|
||||
StringDescription str = item->data(0, Qt::UserRole).value<StringDescription>();
|
||||
this->main->seek(str.vaddr, NULL, true);
|
||||
}
|
||||
|
||||
void StringsWidget::fillTreeWidget()
|
||||
{
|
||||
ui->stringsTreeWidget->clear();
|
||||
for (auto i : main->core->getList("bin", "strings"))
|
||||
for (auto i : main->core->getAllStrings())
|
||||
{
|
||||
QStringList pieces = i.split(",");
|
||||
if (pieces.length() == 2)
|
||||
qhelpers::appendRow(ui->stringsTreeWidget, pieces[0], pieces[1]);
|
||||
QTreeWidgetItem *item = qhelpers::appendRow(ui->stringsTreeWidget, RAddressString(i.vaddr), i.string);
|
||||
item->setData(0, Qt::UserRole, QVariant::fromValue(i));
|
||||
}
|
||||
qhelpers::adjustColumns(ui->stringsTreeWidget);
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ public:
|
||||
|
||||
void refresh() override;
|
||||
|
||||
void fillStrings();
|
||||
|
||||
private slots:
|
||||
void on_stringsTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column);
|
||||
|
||||
|
@ -35,11 +35,6 @@
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QTreeWidget::item
|
||||
{
|
||||
|
@ -39,22 +39,21 @@ void SymbolsWidget::on_symbolsTreeWidget_itemDoubleClicked(QTreeWidgetItem *item
|
||||
QNOTUSED(column);
|
||||
|
||||
// Get offset and name of item double clicked
|
||||
// TODO: use this info to change disasm contents
|
||||
QString offset = item->text(1);
|
||||
QString name = item->text(3);
|
||||
//qDebug() << "Item Text: " << name;
|
||||
this->main->seek(offset, name);
|
||||
//ui->memDock->setWindowTitle(name);
|
||||
SymbolDescription symbol = item->data(0, Qt::UserRole).value<SymbolDescription>();
|
||||
this->main->seek(symbol.vaddr, symbol.name, true);
|
||||
}
|
||||
|
||||
void SymbolsWidget::fillSymbols()
|
||||
{
|
||||
ui->symbolsTreeWidget->clear();
|
||||
for (auto i : this->main->core->getList("bin", "symbols"))
|
||||
for (auto symbol : this->main->core->getAllSymbols())
|
||||
{
|
||||
QStringList pieces = i.split(",");
|
||||
if (pieces.length() == 3)
|
||||
qhelpers::appendRow(ui->symbolsTreeWidget, pieces[0], pieces[1], pieces[2]);
|
||||
QTreeWidgetItem *item = qhelpers::appendRow(ui->symbolsTreeWidget,
|
||||
RAddressString(symbol.vaddr),
|
||||
QString("%1 %2").arg(symbol.bind, symbol.type).trimmed(),
|
||||
symbol.name);
|
||||
|
||||
item->setData(0, Qt::UserRole, QVariant::fromValue(symbol));
|
||||
}
|
||||
qhelpers::adjustColumns(ui->symbolsTreeWidget);
|
||||
}
|
||||
|
@ -29,11 +29,6 @@
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="symbolsTreeWidget">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QTreeWidget::item
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user