Skip to content

Commit

Permalink
Leverage the OnContextMenuCreated API to add the debugger-related ent…
Browse files Browse the repository at this point in the history
…ries to the top-level context menu
  • Loading branch information
xusheng6 committed Sep 25, 2024
1 parent 2012056 commit 8fa60bd
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 185 deletions.
200 changes: 15 additions & 185 deletions ui/ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,21 @@ void GlobalDebuggerUI::SetupMenu(UIContext* context)
},
connectedAndStoppedWithTTD));

UIAction::registerAction("Run To Here");
context->globalActions()->bindAction("Run To Here",
UIAction(
[=](const UIActionContext& ctxt) {
if (!ctxt.binaryView)
return;
auto controller = DebuggerController::GetController(ctxt.binaryView);
if (!controller)
return;

controller->RunTo(ctxt.address);
},
connectedAndStopped));
debuggerMenu->addAction("Run To Here", "Control");

UIAction::registerAction("Detach");
context->globalActions()->bindAction("Detach",
UIAction(
Expand Down Expand Up @@ -702,29 +717,6 @@ void GlobalDebuggerUI::SetupMenu(UIContext* context)
notConnected));
debuggerMenu->addAction("Connect to Remote Process", "Launch");

// There is no longer a need to manually create the debug adapter. It will be automatically created if it is
// accessed but not created yet.
// UIAction::registerAction("Activate Debug Adapter");
// context->globalActions()->bindAction("Activate Debug Adapter", UIAction([=](const UIActionContext& ctxt) {
// if (!ctxt.binaryView)
// return;
// auto controller = DebuggerController::GetController(ctxt.binaryView);
// if (!controller)
// return;
//
// if (controller->ActivateDebugAdapter())
// {
// QMessageBox::information(context->mainWindow(), "Successfully activated",
// "Successfully activated the debug adapter. Now you can run backend commands directly.");
// }
// else
// {
// QMessageBox::information(context->mainWindow(), "Failed to activate",
// "Cannot activate to the debug adapter.");
// }
// }));
// debuggerMenu->addAction("Activate Debug Adapter", "Launch");

QString showAreaWidgets = "Show Debugger Sidebar Widgets";
UIAction::registerAction(showAreaWidgets);

Expand Down Expand Up @@ -1431,173 +1423,11 @@ void DebuggerUI::updateUI(const DebuggerEvent& event)
}


static bool BinaryViewValid(BinaryView* view, uint64_t addr)
{
return true;
}


static void RunToHereCallback(BinaryView* view, uint64_t addr)
{
auto controller = DebuggerController::GetController(view);
if (!controller)
return;
std::thread([=]() { controller->RunTo(addr); }).detach();
}


static bool ConnectedAndStopped(BinaryView* view, uint64_t addr)
{
if (!DebuggerController::ControllerExists(view))
return false;
auto controller = DebuggerController::GetController(view);
if (!controller)
return false;
return controller->IsConnected() && (!controller->IsRunning());
}


static bool ConnectedAndRunning(BinaryView* view, uint64_t addr)
{
if (!DebuggerController::ControllerExists(view))
return false;
auto controller = DebuggerController::GetController(view);
if (!controller)
return false;
return controller->IsConnected() && controller->IsRunning();
}


void GlobalDebuggerUI::InitializeUI()
{
Sidebar::addSidebarWidgetType(new DebuggerWidgetType(QImage(":/debugger/debugger"), "Debugger"));
Sidebar::addSidebarWidgetType(new DebugModulesSidebarWidgetType());
Sidebar::addSidebarWidgetType(new ThreadFramesSidebarWidgetType());

// We must use the sequence of these four calls to do the job, otherwise the keybinding does not work.
// Though it really should be the case where I can specify the keybinding in the first registerAction() call.
UIAction::registerAction("Debugger\\Toggle Breakpoint");
UIAction::registerAction("Selection Target\\Debugger\\Toggle Breakpoint");
PluginCommand::RegisterForAddress("Debugger\\Toggle Breakpoint", "Sets/clears breakpoint at right-clicked address",
BreakpointToggleCallback, BinaryViewValid);

UIAction::registerAction("Debugger\\Run To Here");
UIAction::registerAction("Selection Target\\Debugger\\Run To Here");
PluginCommand::RegisterForAddress(
"Debugger\\Run To Here", "Run until the current address", RunToHereCallback, ConnectedAndStopped);

std::string actionName = "Run";
UIAction::registerAction(QString::asprintf("Debugger\\%s", actionName.c_str()));
UIAction::registerAction(QString::asprintf("Selection Target\\Debugger\\%s", actionName.c_str()));
PluginCommand::RegisterForAddress(
QString::asprintf("Debugger\\%s", actionName.c_str()).toStdString(), "Launch or resume the target",
[](BinaryView* view, uint64_t addr) {
auto controller = DebuggerController::GetController(view);
if (!controller)
return;
if (controller->IsConnected() && (!controller->IsRunning()))
{
std::thread([=]() { controller->Go(); }).detach();
}
else if (!controller->IsConnected())
{
QString text = QString(
"The debugger is launching the target and preparing the debugger binary view. \n"
"This might take a while.");
ProgressTask* task =
new ProgressTask(nullptr, "Launching", text, "", [&](std::function<bool(size_t, size_t)> progress) {
controller->Launch();

// For now, this cant be canceled, as the Debugger model wasn't
// designed with that in mind. This function below can return false if canceling is enabled
progress(1, 1);
return;
});
task->wait();
}
},
BinaryViewValid);

actionName = "Step Into";
UIAction::registerAction(QString::asprintf("Debugger\\%s", actionName.c_str()));
UIAction::registerAction(QString::asprintf("Selection Target\\Debugger\\%s", actionName.c_str()));
PluginCommand::RegisterForAddress(
QString::asprintf("Debugger\\%s", actionName.c_str()).toStdString(), "Step into",
[](BinaryView* view, uint64_t) {
auto controller = DebuggerController::GetController(view);
if (!controller)
return;
BNFunctionGraphType graphType = NormalFunctionGraph;
UIContext* context = UIContext::activeContext();
if (context && context->getCurrentView())
graphType = context->getCurrentView()->getILViewType();
std::thread([=]() { controller->StepInto(graphType); }).detach();
},
ConnectedAndStopped);

actionName = "Step Over";
UIAction::registerAction(QString::asprintf("Debugger\\%s", actionName.c_str()));
UIAction::registerAction(QString::asprintf("Selection Target\\Debugger\\%s", actionName.c_str()));
PluginCommand::RegisterForAddress(
QString::asprintf("Debugger\\%s", actionName.c_str()).toStdString(), "Step over",
[](BinaryView* view, uint64_t) {
auto controller = DebuggerController::GetController(view);
if (!controller)
return;
BNFunctionGraphType graphType = NormalFunctionGraph;
UIContext* context = UIContext::activeContext();
if (context && context->getCurrentView())
graphType = context->getCurrentView()->getILViewType();
std::thread([=]() { controller->StepOver(graphType); }).detach();
},
ConnectedAndStopped);

actionName = "Step Return";
UIAction::registerAction(QString::asprintf("Debugger\\%s", actionName.c_str()));
UIAction::registerAction(QString::asprintf("Selection Target\\Debugger\\%s", actionName.c_str()));
PluginCommand::RegisterForAddress(
QString::asprintf("Debugger\\%s", actionName.c_str()).toStdString(), "Step return",
[](BinaryView* view, uint64_t) {
auto controller = DebuggerController::GetController(view);
if (!controller)
return;
std::thread([=]() { controller->StepReturn(); }).detach();
},
ConnectedAndStopped);

actionName = "Pause";
UIAction::registerAction(QString::asprintf("Debugger\\%s", actionName.c_str()));
UIAction::registerAction(QString::asprintf("Selection Target\\Debugger\\%s", actionName.c_str()));
PluginCommand::RegisterForAddress(
QString::asprintf("Debugger\\%s", actionName.c_str()).toStdString(), "Pause the target",
[](BinaryView* view, uint64_t) {
auto controller = DebuggerController::GetController(view);
if (!controller)
return;
std::thread([=]() { controller->Pause(); }).detach();
},
ConnectedAndRunning);

// actionName = "Make Code";
// UIAction::registerAction(QString::asprintf("Debugger\\%s", actionName.c_str()), QKeySequence(Qt::Key_C));
// UIAction::registerAction(QString::asprintf("Selection Target\\Debugger\\%s", actionName.c_str()));
// PluginCommand::RegisterForAddress(
// QString::asprintf("Debugger\\%s", actionName.c_str()).toStdString(),
// "Create raw disassembly",
// [](BinaryView* view, uint64_t addr){
// MakeCodeHelper(view, addr);
// },
// BinaryViewValid);
//
// UIAction::setActionDisplayName("Debugger\\Make Code", [](const UIActionContext& ctxt) -> QString {
// if (!ctxt.binaryView)
// return "Make Code";
//
// if (ShowAsCode(ctxt.binaryView, ctxt.address))
// return "Undefine Code";
//
// return "Make Code";
// });
}


Expand Down
23 changes: 23 additions & 0 deletions ui/uinotification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ limitations under the License.
#include "uinotification.h"
#include "filecontext.h"
#include "viewframe.h"
#include "linearview.h"
#include "flowgraphwidget.h"
#include "hexeditor.h"
#include <QMessageBox>
#include <QFileInfo>
#include <QPushButton>
Expand Down Expand Up @@ -163,3 +166,23 @@ bool NotificationListener::GetNameForPath(UIContext* context, const QString& pat
{
return false;
}


void NotificationListener::OnContextMenuCreated(UIContext *context, View* view, Menu &menu)
{
// Only add the context menu to the linear/graph/hex views
if (!dynamic_cast<LinearView*>(view) && !dynamic_cast<FlowGraphWidget*>(view)
&& !dynamic_cast<HexEditor*>(view))
return;

menu.addAction("Debugger", "Toggle Breakpoint", "Breakpoint");
menu.addAction("Debugger", "Launch", "Control");
menu.addAction("Debugger", "Pause", "Control");
menu.addAction("Debugger", "Restart", "Control");
menu.addAction("Debugger", "Resume", "Control");
menu.addAction("Debugger", "Step Into", "Control");
menu.addAction("Debugger", "Step Over", "Control");
menu.addAction("Debugger", "Step Return", "Control");
menu.addAction("Debugger", "Run To Here", "Control");
menu.addAction("Debugger", "Create Stack View", "Misc");
}
1 change: 1 addition & 0 deletions ui/uinotification.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@ class NotificationListener : UIContextNotification
virtual bool GetNameForFile(UIContext* context, FileContext* file, QString& name) override;
virtual bool GetNameForPath(UIContext* context, const QString& path, QString& name) override;

virtual void OnContextMenuCreated(UIContext* context, View* view, Menu& menu) override;
static void init();
};

0 comments on commit 8fa60bd

Please sign in to comment.