1
0
Fork 0

GUI: implement Disassembly menu in dump

This commit is contained in:
Duncan Ogilvie 2020-07-09 18:24:21 +02:00
parent 5c8476b6b4
commit 5d00c40382
14 changed files with 116 additions and 48 deletions

View File

@ -7,7 +7,9 @@
#include "QBeaEngine.h"
#include "MemoryPage.h"
Disassembly::Disassembly(QWidget* parent) : AbstractTableView(parent)
Disassembly::Disassembly(QWidget* parent, bool isMain)
: AbstractTableView(parent),
mIsMain(isMain)
{
mMemPage = new MemoryPage(0, 0);
@ -905,8 +907,7 @@ void Disassembly::keyPressEvent(QKeyEvent* event)
duint dest = DbgGetBranchDestination(rvaToVa(getInitialSelection()));
if(!DbgMemIsValidReadPtr(dest))
return;
QString cmd = "disasm " + ToPtrString(dest);
DbgCmdExec(cmd.toUtf8().constData());
gotoAddress(dest);
}
else
AbstractTableView::keyPressEvent(event);
@ -1753,6 +1754,18 @@ duint Disassembly::rvaToVa(dsint rva) const
return mMemPage->va(rva);
}
void Disassembly::gotoAddress(duint addr)
{
disassembleAt(addr, true, -1);
if(mIsMain)
{
// Update window title
DbgCmdExecDirect(QString("guiupdatetitle %1").arg(ToPtrString(addr)));
}
GuiUpdateAllViews();
}
void Disassembly::disassembleAt(dsint parVA, bool history, dsint newTableOffset)
{
duint wSize;
@ -1884,8 +1897,9 @@ void Disassembly::disassembleAtSlot(dsint parVA, dsint parCIP)
mCodeFoldingManager->expandFoldSegment(parVA);
mCodeFoldingManager->expandFoldSegment(parCIP);
}
mCipVa = parCIP; // TODO: emit a signal for this?
disassembleAt(parVA, true, -1);
mCipVa = parCIP;
if(mIsMain || !mMemPage->getBase())
disassembleAt(parVA, true, -1);
}
void Disassembly::disassembleClear()
@ -1943,9 +1957,12 @@ void Disassembly::historyPrevious()
mCodeFoldingManager->expandFoldSegment(va);
disassembleAt(va, false, mVaHistory.at(mCurrentVa).tableOffset);
// Update window title
DbgCmdExecDirect(QString("guiupdatetitle %1").arg(ToPtrString(va)));
GuiUpdateAllViews();
if(mIsMain)
{
// Update window title
DbgCmdExecDirect(QString("guiupdatetitle %1").arg(ToPtrString(va)));
GuiUpdateAllViews();
}
}
void Disassembly::historyNext()
@ -1958,9 +1975,12 @@ void Disassembly::historyNext()
mCodeFoldingManager->expandFoldSegment(va);
disassembleAt(va, false, mVaHistory.at(mCurrentVa).tableOffset);
// Update window title
DbgCmdExecDirect(QString("guiupdatetitle %1").arg(ToPtrString(va)));
GuiUpdateAllViews();
if(mIsMain)
{
// Update window title
DbgCmdExecDirect(QString("guiupdatetitle %1").arg(ToPtrString(va)));
GuiUpdateAllViews();
}
}
bool Disassembly::historyHasPrevious() const

View File

@ -11,7 +11,7 @@ class Disassembly : public AbstractTableView
{
Q_OBJECT
public:
explicit Disassembly(QWidget* parent = 0);
Disassembly(QWidget* parent, bool isMain);
~Disassembly() override;
// Configuration
@ -88,6 +88,7 @@ public:
bool historyHasNext() const;
//disassemble
void gotoAddress(duint addr);
void disassembleAt(dsint parVA, bool history, dsint newTableOffset);
QList<Instruction_t>* instructionsBuffer(); // ugly
@ -247,6 +248,7 @@ protected:
ZydisTokenizer::SingleToken mHighlightToken;
bool mPermanentHighlightingMode;
bool mNoCurrentModuleText;
bool mIsMain = false;
};
#endif // DISASSEMBLY_H

View File

@ -26,23 +26,22 @@
#include "BreakpointMenu.h"
#include "BrowseDialog.h"
CPUDisassembly::CPUDisassembly(QWidget* parent) : Disassembly(parent)
CPUDisassembly::CPUDisassembly(QWidget* parent, bool isMain) : Disassembly(parent, isMain)
{
setWindowTitle("Disassembly");
// Create the action list for the right click context menu
setupRightClickContextMenu();
// TODO: refactor these signals out of the class (move to CPUWidget + CPUMultiDump)
// TODO: refactor all DbgCmdExec("disasm ...") commands (customization point)
// TODO: refactor mPluginMenu to be a singleton (so plugin menus show up in all instances)
// Connect bridge<->disasm calls
connect(Bridge::getBridge(), SIGNAL(disassembleAt(dsint, dsint)), this, SLOT(disassembleAtSlot(dsint, dsint)));
connect(Bridge::getBridge(), SIGNAL(selectionDisasmGet(SELECTIONDATA*)), this, SLOT(selectionGetSlot(SELECTIONDATA*)));
connect(Bridge::getBridge(), SIGNAL(selectionDisasmSet(const SELECTIONDATA*)), this, SLOT(selectionSetSlot(const SELECTIONDATA*)));
connect(Bridge::getBridge(), SIGNAL(displayWarning(QString, QString)), this, SLOT(displayWarningSlot(QString, QString)));
connect(Bridge::getBridge(), SIGNAL(focusDisasm()), this, SLOT(setFocus()));
if(mIsMain)
{
connect(Bridge::getBridge(), SIGNAL(selectionDisasmGet(SELECTIONDATA*)), this, SLOT(selectionGetSlot(SELECTIONDATA*)));
connect(Bridge::getBridge(), SIGNAL(selectionDisasmSet(const SELECTIONDATA*)), this, SLOT(selectionSetSlot(const SELECTIONDATA*)));
connect(Bridge::getBridge(), SIGNAL(displayWarning(QString, QString)), this, SLOT(displayWarningSlot(QString, QString)));
connect(Bridge::getBridge(), SIGNAL(focusDisasm()), this, SLOT(setFocus()));
}
// Connect some internal signals
connect(this, SIGNAL(selectionExpanded()), this, SLOT(selectionUpdatedSlot()));
@ -644,14 +643,20 @@ void CPUDisassembly::setupRightClickContextMenu()
});
// Plugins
mPluginMenu = new QMenu(this);
Bridge::getBridge()->emitMenuAddToList(this, mPluginMenu, GUI_DISASM_MENU);
if(mIsMain)
{
mPluginMenu = new QMenu(this);
Bridge::getBridge()->emitMenuAddToList(this, mPluginMenu, GUI_DISASM_MENU);
}
mMenuBuilder->addSeparator();
mMenuBuilder->addBuilder(new MenuBuilder(this, [this](QMenu * menu)
{
DbgMenuPrepare(GUI_DISASM_MENU);
menu->addActions(mPluginMenu->actions());
if(mIsMain)
{
menu->addActions(mPluginMenu->actions());
}
return true;
}));
@ -674,7 +679,7 @@ void CPUDisassembly::gotoOriginSlot()
{
if(!DbgIsDebugging())
return;
DbgCmdExec("disasm cip");
gotoAddress(DbgValFromString("cip"));
}
void CPUDisassembly::setNewOriginHereActionSlot()
@ -1006,7 +1011,7 @@ void CPUDisassembly::gotoExpressionSlot()
if(mGoto->exec() == QDialog::Accepted)
{
duint value = DbgValFromString(mGoto->expressionText.toUtf8().constData());
DbgCmdExec(QString().sprintf("disasm %p", value).toUtf8().constData());
gotoAddress(value);
}
}
@ -1040,19 +1045,19 @@ void CPUDisassembly::gotoFileOffsetSlot()
return;
duint value = DbgValFromString(mGotoOffset->expressionText.toUtf8().constData());
value = DbgFunctions()->FileOffsetToVa(modname, value);
DbgCmdExec(QString().sprintf("disasm \"%p\"", value).toUtf8().constData());
gotoAddress(value);
}
void CPUDisassembly::gotoStartSlot()
{
duint dest = mMemPage->getBase();
DbgCmdExec(QString().sprintf("disasm \"%p\"", dest).toUtf8().constData());
gotoAddress(dest);
}
void CPUDisassembly::gotoEndSlot()
{
duint dest = mMemPage->getBase() + mMemPage->getSize() - (getViewableRowsCount() * 16);
DbgCmdExec(QString().sprintf("disasm \"%p\"", dest).toUtf8().constData());
gotoAddress(dest);
}
void CPUDisassembly::gotoFunctionStartSlot()
@ -1060,7 +1065,7 @@ void CPUDisassembly::gotoFunctionStartSlot()
duint start;
if(!DbgFunctionGet(rvaToVa(getInitialSelection()), &start, nullptr))
return;
DbgCmdExec(QString("disasm \"%1\"").arg(ToHexString(start)).toUtf8().constData());
gotoAddress(start);
}
void CPUDisassembly::gotoFunctionEndSlot()
@ -1068,7 +1073,7 @@ void CPUDisassembly::gotoFunctionEndSlot()
duint end;
if(!DbgFunctionGet(rvaToVa(getInitialSelection()), nullptr, &end))
return;
DbgCmdExec(QString("disasm \"%1\"").arg(ToHexString(end)).toUtf8().constData());
gotoAddress(end);
}
void CPUDisassembly::gotoPreviousReferenceSlot()
@ -1078,7 +1083,7 @@ void CPUDisassembly::gotoPreviousReferenceSlot()
{
if(index > 0 && addr == rvaToVa(getInitialSelection()))
DbgValToString("$__disasm_refindex", index - 1);
DbgCmdExec("disasm refsearch.addr($__disasm_refindex)");
gotoAddress(DbgValFromString("refsearch.addr($__disasm_refindex)"));
}
}
@ -1089,7 +1094,7 @@ void CPUDisassembly::gotoNextReferenceSlot()
{
if(index + 1 < count && addr == rvaToVa(getInitialSelection()))
DbgValToString("$__disasm_refindex", index + 1);
DbgCmdExec("disasm refsearch.addr($__disasm_refindex)");
gotoAddress(DbgValFromString("refsearch.addr($__disasm_refindex)"));
}
}
@ -1099,7 +1104,10 @@ void CPUDisassembly::gotoXrefSlot()
return;
if(!mXrefDlg)
mXrefDlg = new XrefBrowseDialog(this);
mXrefDlg->setup(getSelectedVa());
mXrefDlg->setup(getSelectedVa(), [this](duint addr)
{
gotoAddress(addr);
});
mXrefDlg->showNormal();
}
@ -1120,7 +1128,7 @@ void CPUDisassembly::followActionSlot()
else if(action->objectName().startsWith("CPU|"))
{
QString value = action->objectName().mid(4);
DbgCmdExec(QString("disasm " + value).toUtf8().constData());
gotoAddress(DbgValFromString(value.toUtf8().constData()));
}
}

View File

@ -14,7 +14,7 @@ class CPUDisassembly : public Disassembly
Q_OBJECT
public:
explicit CPUDisassembly(QWidget* parent);
CPUDisassembly(QWidget* parent, bool isMain);
// Mouse management
void contextMenuEvent(QContextMenuEvent* event);
@ -126,7 +126,7 @@ private:
// Menus
QMenu* mHwSlotSelectMenu;
QMenu* mPluginMenu;
QMenu* mPluginMenu = nullptr;
// Actions
QAction* mReferenceSelectedAddressAction;

View File

@ -271,7 +271,7 @@ void CPUDump::setupContextMenu()
mMenuBuilder->addMenu(makeMenu(DIcon("float.png"), tr("&Float")), wFloatMenu);
mMenuBuilder->addAction(makeAction(DIcon("address.png"), tr("&Address"), SLOT(addressSlot())));
mMenuBuilder->addAction(makeAction(DIcon("processor-cpu.png"), tr("&Disassembly"), SLOT(disassemblySlot())))->setEnabled(false);
mMenuBuilder->addAction(makeAction(DIcon("processor-cpu.png"), tr("&Disassembly"), SLOT(disassemblySlot())));
mMenuBuilder->addSeparator();
mMenuBuilder->addBuilder(new MenuBuilder(this, [this](QMenu * menu)
@ -1360,7 +1360,9 @@ void CPUDump::addressUnicodeSlot()
void CPUDump::disassemblySlot()
{
SimpleErrorBox(this, tr("Error!"), tr("Not yet supported!"));
SELECTIONDATA selection;
selectionGet(&selection);
emit showDisassemblyTab(selection.start, selection.end, rvaToVa(getTableOffsetRva()));
}
void CPUDump::selectionGet(SELECTIONDATA* selection)

View File

@ -23,6 +23,7 @@ public:
signals:
void displayReferencesWidget();
void showDisassemblyTab(duint selectionStart, duint selectionEnd, duint firstAddress);
public slots:
void memoryAccessSingleshootSlot();

View File

@ -573,7 +573,10 @@ void CPUInfoBox::findXReferencesSlot()
return;
if(!mXrefDlg)
mXrefDlg = new XrefBrowseDialog(this);
mXrefDlg->setup(curAddr);
mXrefDlg->setup(curAddr, [](duint address)
{
DbgCmdExec(QString("disasm %1").arg(ToPtrString(address)).toUtf8().constData());
});
mXrefDlg->showNormal();
}

View File

@ -1,5 +1,6 @@
#include "CPUMultiDump.h"
#include "CPUDump.h"
#include "CPUDisassembly.h"
#include "WatchView.h"
#include "LocalVarsView.h"
#include "StructWidget.h"
@ -24,6 +25,7 @@ CPUMultiDump::CPUMultiDump(CPUDisassembly* disas, int nbCpuDumpTabs, QWidget* pa
CPUDump* cpuDump = new CPUDump(disas, this);
//cpuDump->loadColumnFromConfig(QString("CPUDump%1").arg(i + 1)); //TODO: needs a workaround because the columns change
connect(cpuDump, SIGNAL(displayReferencesWidget()), this, SLOT(displayReferencesWidgetSlot()));
connect(cpuDump, SIGNAL(showDisassemblyTab(duint, duint, duint)), this, SLOT(showDisassemblyTabSlot(duint, duint, duint)));
auto nativeTitle = QString("Dump ") + QString::number(i + 1);
this->addTabEx(cpuDump, DIcon("dump.png"), tr("Dump ") + QString::number(i + 1), nativeTitle);
cpuDump->setWindowTitle(nativeTitle);
@ -223,6 +225,28 @@ void CPUMultiDump::focusCurrentDumpSlot()
mCurrentCPUDump->setFocus();
}
void CPUMultiDump::showDisassemblyTabSlot(duint selectionStart, duint selectionEnd, duint firstAddress)
{
Q_UNUSED(firstAddress); // TODO: implement setTableOffset(firstAddress)
if(!mDisassembly)
{
mDisassembly = new CPUDisassembly(this, false);
this->addTabEx(mDisassembly, DIcon(ArchValue("processor32.png", "processor64.png")), tr("Disassembly"), "DumpDisassembly");
}
// Set CIP
auto clearHistory = mDisassembly->getBase() == 0;
mDisassembly->disassembleAtSlot(selectionStart, Bridge::getBridge()->mLastCip);
if(clearHistory)
mDisassembly->historyClear();
// Make the address visisble in memory
mDisassembly->disassembleAt(selectionStart, true, -1);
// Set selection to match the dump
mDisassembly->setSingleSelection(selectionStart - mDisassembly->getBase());
mDisassembly->expandSelectionUpTo(selectionEnd - mDisassembly->getBase());
// Show the tab
setCurrentWidget(mDisassembly);
}
void CPUMultiDump::getDumpAttention()
{
mCurrentCPUDump->getAttention();

View File

@ -34,6 +34,7 @@ public slots:
void openChangeTabTitleDialogSlot(int tabIndex);
void displayReferencesWidgetSlot();
void focusCurrentDumpSlot();
void showDisassemblyTabSlot(duint selectionStart, duint selectionEnd, duint firstAddress);
void getDumpAttention();
private:
@ -44,6 +45,7 @@ private:
WatchView* mWatch;
LocalVarsView* mLocalVars;
StructWidget* mStructWidget;
CPUDisassembly* mDisassembly = nullptr;
int GetDumpWindowIndex(int dump);
int GetWatchWindowIndex();

View File

@ -18,7 +18,7 @@ CPUWidget::CPUWidget(QWidget* parent) : QWidget(parent), ui(new Ui::CPUWidget)
setStyleSheet("AbstractTableView:focus, RegistersView:focus, CPUSideBar:focus { border: 1px solid #000000; }");
mDisas = new CPUDisassembly(this);
mDisas = new CPUDisassembly(this, true);
mSideBar = new CPUSideBar(mDisas);
mDisas->setSideBar(mSideBar);
mArgumentWidget = new CPUArgumentWidget(this);

View File

@ -2587,7 +2587,10 @@ void DisassemblerGraphView::xrefSlot()
BridgeFree(mXrefInfo.references);
if(!mXrefDlg)
mXrefDlg = new XrefBrowseDialog(this);
mXrefDlg->setup(wVA, "graph");
mXrefDlg->setup(wVA, [](duint addr)
{
DbgCmdExec(QString("graph %1").arg(ToPtrString(addr)).toUtf8().constData());
});
mXrefDlg->showNormal();
}

View File

@ -1679,6 +1679,8 @@ void MainWindow::executeOnGuiThread(void* cbGuiThread, void* userdata)
void MainWindow::tabMovedSlot(int from, int to)
{
Q_UNUSED(from);
Q_UNUSED(to);
for(int i = 0; i < mTabWidget->count(); i++)
{
// Remove space in widget name and append Tab to get config settings (CPUTab, MemoryMapTab, etc...)

View File

@ -39,15 +39,15 @@ QString XrefBrowseDialog::GetFunctionSymbol(duint addr)
return line;
}
void XrefBrowseDialog::setup(duint address, QString command)
void XrefBrowseDialog::setup(duint address, GotoFunction gotoFunction)
{
if(mXrefInfo.refcount)
{
BridgeFree(mXrefInfo.references);
mXrefInfo.refcount = 0;
}
mCommand = command;
mAddress = address;
mGotoFunction = std::move(gotoFunction);
mPrevSelectionSize = 0;
ui->listWidget->clear();
if(DbgXrefGet(address, &mXrefInfo))
@ -161,7 +161,7 @@ void XrefBrowseDialog::setupContextMenu()
void XrefBrowseDialog::changeAddress(duint address)
{
DbgCmdExec(QString("%1 %2").arg(mCommand, ToPtrString(address)).toUtf8().constData());
mGotoFunction(address);
}
XrefBrowseDialog::~XrefBrowseDialog()
@ -203,7 +203,7 @@ void XrefBrowseDialog::on_listWidget_currentRowChanged(int row)
void XrefBrowseDialog::on_XrefBrowseDialog_rejected()
{
if(DbgIsDebugging())
DbgCmdExec(QString("%1 %2").arg(mCommand, ToPtrString(mAddress)).toUtf8().constData());
mGotoFunction(mAddress);
}
void XrefBrowseDialog::on_listWidget_itemClicked(QListWidgetItem*)

View File

@ -18,7 +18,8 @@ class XrefBrowseDialog : public QDialog, public ActionHelper<XrefBrowseDialog>
public:
explicit XrefBrowseDialog(QWidget* parent);
~XrefBrowseDialog();
void setup(duint address, QString command = "disasm");
using GotoFunction = std::function<void(duint)>;
void setup(duint address, GotoFunction gotoFunction);
private slots:
void on_listWidget_itemDoubleClicked(QListWidgetItem* item);
@ -58,8 +59,8 @@ private:
XREF_INFO mXrefInfo;
duint mAddress;
int mPrevSelectionSize;
QString mCommand;
MenuBuilder* mMenu;
GotoFunction mGotoFunction;
};
#endif // XREFBROWSEDIALOG_H