GUI: implement Disassembly menu in dump
This commit is contained in:
parent
5c8476b6b4
commit
5d00c40382
|
@ -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,7 +1897,8 @@ void Disassembly::disassembleAtSlot(dsint parVA, dsint parCIP)
|
|||
mCodeFoldingManager->expandFoldSegment(parVA);
|
||||
mCodeFoldingManager->expandFoldSegment(parCIP);
|
||||
}
|
||||
mCipVa = parCIP; // TODO: emit a signal for this?
|
||||
mCipVa = parCIP;
|
||||
if(mIsMain || !mMemPage->getBase())
|
||||
disassembleAt(parVA, true, -1);
|
||||
}
|
||||
|
||||
|
@ -1943,9 +1957,12 @@ void Disassembly::historyPrevious()
|
|||
mCodeFoldingManager->expandFoldSegment(va);
|
||||
disassembleAt(va, false, mVaHistory.at(mCurrentVa).tableOffset);
|
||||
|
||||
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);
|
||||
|
||||
if(mIsMain)
|
||||
{
|
||||
// Update window title
|
||||
DbgCmdExecDirect(QString("guiupdatetitle %1").arg(ToPtrString(va)));
|
||||
GuiUpdateAllViews();
|
||||
}
|
||||
}
|
||||
|
||||
bool Disassembly::historyHasPrevious() const
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)));
|
||||
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
|
||||
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);
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -23,6 +23,7 @@ public:
|
|||
|
||||
signals:
|
||||
void displayReferencesWidget();
|
||||
void showDisassemblyTab(duint selectionStart, duint selectionEnd, duint firstAddress);
|
||||
|
||||
public slots:
|
||||
void memoryAccessSingleshootSlot();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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...)
|
||||
|
|
|
@ -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*)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue