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:
Florian Märkl 2017-04-28 15:09:40 +02:00 committed by Hugo Teso
parent a0e5cd2d34
commit ebe33ffe8e
29 changed files with 1075 additions and 561 deletions

View File

@ -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());
}

View File

@ -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

View 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

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -24,6 +24,8 @@ public:
RAnalFunction functionAt(ut64 addr);
QStringList asm_plugins;
void setupAndStartAnalysis(int level);
private slots:
void on_closeButton_clicked();

View File

@ -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;
}

View File

@ -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:

View File

@ -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>

View File

@ -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);

View File

@ -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)

View File

@ -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>

View File

@ -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);
}

View File

@ -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

View File

@ -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">

View File

@ -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);
}

View File

@ -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
{

View File

@ -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;
}
}
}

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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
{

View File

@ -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);
}

View File

@ -23,6 +23,8 @@ public:
void refresh() override;
void fillStrings();
private slots:
void on_stringsTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column);

View File

@ -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
{

View File

@ -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);
}

View File

@ -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
{