Add "Run to cursor" context action.

- UserInterfaceListener/TeamDebugger: Extend ThreadActionRequested()
  to allow passing a target address. Adjust TeamDebugger's
  implementation accordingly.

- ThreadHandler: The MSG_THREAD_RUN action can now optionally take an
  address parameter to run until. If this is specified, set a temporary
  breakpoint for said address before resuming execution.

- SourceView: On right click, present a context menu showing possible
  actions for the current line if we're currently in a stopped thread.
  For the moment, this only yields the "Run to cursor" action, but
  more will be added in the future.
This commit is contained in:
Rene Gollent
2013-05-12 16:03:47 -04:00
parent 7a361a7a19
commit 42d73abab9
9 changed files with 164 additions and 23 deletions
@@ -536,11 +536,15 @@ TeamDebugger::MessageReceived(BMessage* message)
case MSG_THREAD_STEP_OUT: case MSG_THREAD_STEP_OUT:
{ {
int32 threadID; int32 threadID;
target_addr_t address;
if (message->FindInt32("thread", &threadID) != B_OK) if (message->FindInt32("thread", &threadID) != B_OK)
break; break;
if (message->FindUInt64("address", &address) != B_OK)
address = 0;
if (ThreadHandler* handler = _GetThreadHandler(threadID)) { if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
handler->HandleThreadAction(message->what); handler->HandleThreadAction(message->what, address);
handler->ReleaseReference(); handler->ReleaseReference();
} }
break; break;
@@ -801,10 +805,11 @@ TeamDebugger::ValueNodeValueRequested(CpuState* cpuState,
void void
TeamDebugger::ThreadActionRequested(thread_id threadID, TeamDebugger::ThreadActionRequested(thread_id threadID,
uint32 action) uint32 action, target_addr_t address)
{ {
BMessage message(action); BMessage message(action);
message.AddInt32("thread", threadID); message.AddInt32("thread", threadID);
message.AddUInt64("address", address);
PostMessage(&message); PostMessage(&message);
} }
+1 -1
View File
@@ -60,7 +60,7 @@ private:
ValueNodeContainer* container, ValueNodeContainer* container,
ValueNode* valueNode); ValueNode* valueNode);
virtual void ThreadActionRequested(thread_id threadID, virtual void ThreadActionRequested(thread_id threadID,
uint32 action); uint32 action, target_addr_t address);
virtual void SetBreakpointRequested(target_addr_t address, virtual void SetBreakpointRequested(target_addr_t address,
bool enabled); bool enabled);
virtual void SetBreakpointEnabledRequested( virtual void SetBreakpointEnabledRequested(
@@ -37,7 +37,8 @@ enum {
STEP_NONE, STEP_NONE,
STEP_OVER, STEP_OVER,
STEP_INTO, STEP_INTO,
STEP_OUT STEP_OUT,
STEP_UNTIL
}; };
@@ -124,7 +125,7 @@ ThreadHandler::HandleBreakpointHit(BreakpointHitEvent* event)
// check whether this is a temporary breakpoint we're waiting for // check whether this is a temporary breakpoint we're waiting for
if (fBreakpointAddress != 0 && instructionPointer == fBreakpointAddress if (fBreakpointAddress != 0 && instructionPointer == fBreakpointAddress
&& fStepMode != STEP_NONE) { && fStepMode != STEP_NONE) {
if (_HandleBreakpointHitStep(cpuState)) if (fStepMode != STEP_UNTIL && _HandleBreakpointHitStep(cpuState))
return true; return true;
} else { } else {
// Might be a user breakpoint, but could as well be a temporary // Might be a user breakpoint, but could as well be a temporary
@@ -199,7 +200,7 @@ ThreadHandler::HandleExceptionOccurred(ExceptionOccurredEvent* event)
void void
ThreadHandler::HandleThreadAction(uint32 action) ThreadHandler::HandleThreadAction(uint32 action, target_addr_t address)
{ {
AutoLocker<Team> locker(fThread->GetTeam()); AutoLocker<Team> locker(fThread->GetTeam());
@@ -230,7 +231,9 @@ ThreadHandler::HandleThreadAction(uint32 action)
switch (action) { switch (action) {
case MSG_THREAD_RUN: case MSG_THREAD_RUN:
fStepMode = STEP_NONE; fStepMode = address != 0 ? STEP_UNTIL : STEP_NONE;
if (address != 0)
_InstallTemporaryBreakpoint(address);
_RunThread(0); _RunThread(0);
return; return;
case MSG_THREAD_STOP: case MSG_THREAD_STOP:
@@ -53,7 +53,8 @@ public:
bool HandleExceptionOccurred( bool HandleExceptionOccurred(
ExceptionOccurredEvent* event); ExceptionOccurredEvent* event);
void HandleThreadAction(uint32 action); void HandleThreadAction(uint32 action,
target_addr_t address);
void HandleThreadStateChanged(); void HandleThreadStateChanged();
void HandleCpuStateChanged(); void HandleCpuStateChanged();
@@ -90,7 +90,8 @@ public:
ValueNodeContainer* container, ValueNodeContainer* container,
ValueNode* valueNode) = 0; ValueNode* valueNode) = 0;
virtual void ThreadActionRequested(thread_id threadID, virtual void ThreadActionRequested(thread_id threadID,
uint32 action) = 0; uint32 action,
target_addr_t address = 0) = 0;
virtual void SetBreakpointRequested(target_addr_t address, virtual void SetBreakpointRequested(target_addr_t address,
bool enabled) = 0; bool enabled) = 0;
@@ -16,9 +16,11 @@
#include <Clipboard.h> #include <Clipboard.h>
#include <LayoutUtils.h> #include <LayoutUtils.h>
#include <Looper.h> #include <Looper.h>
#include <MenuItem.h>
#include <Message.h> #include <Message.h>
#include <MessageRunner.h> #include <MessageRunner.h>
#include <Polygon.h> #include <Polygon.h>
#include <PopUpMenu.h>
#include <Region.h> #include <Region.h>
#include <ScrollBar.h> #include <ScrollBar.h>
#include <ScrollView.h> #include <ScrollView.h>
@@ -27,6 +29,7 @@
#include <AutoLocker.h> #include <AutoLocker.h>
#include <ObjectList.h> #include <ObjectList.h>
#include "AutoDeleter.h"
#include "Breakpoint.h" #include "Breakpoint.h"
#include "DisassembledCode.h" #include "DisassembledCode.h"
#include "Function.h" #include "Function.h"
@@ -918,18 +921,11 @@ SourceView::MarkerView::MouseDown(BPoint where)
return; return;
int32 line = LineAtOffset(where.y); int32 line = LineAtOffset(where.y);
if (line < 0)
return;
AutoLocker<Team> locker(fTeam);
Statement* statement; Statement* statement;
if (fTeam->GetStatementAtSourceLocation(fSourceCode, if (!fSourceView->GetStatementForLine(line, statement))
SourceLocation(line), statement) != B_OK) {
return; return;
}
BReference<Statement> statementReference(statement, true); BReference<Statement> statementReference(statement, true);
if (statement->StartSourceLocation().Line() != line)
return;
int32 modifiers; int32 modifiers;
if (Looper()->CurrentMessage()->FindInt32("modifiers", &modifiers) != B_OK) if (Looper()->CurrentMessage()->FindInt32("modifiers", &modifiers) != B_OK)
@@ -1193,7 +1189,15 @@ SourceView::TextView::MessageReceived(BMessage* message)
void void
SourceView::TextView::MouseDown(BPoint where) SourceView::TextView::MouseDown(BPoint where)
{ {
if (fSourceCode != NULL) { if (fSourceCode == NULL)
return;
int32 buttons;
if (Looper()->CurrentMessage()->FindInt32("buttons", &buttons) != B_OK)
buttons = B_PRIMARY_MOUSE_BUTTON;
if (buttons == B_PRIMARY_MOUSE_BUTTON) {
if (!IsFocus()) if (!IsFocus())
MakeFocus(true); MakeFocus(true);
fTrackState = kTracking; fTrackState = kTracking;
@@ -1233,6 +1237,57 @@ SourceView::TextView::MouseDown(BPoint where)
Invalidate(); Invalidate();
SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY); SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
} }
} else if (buttons == B_SECONDARY_MOUSE_BUTTON) {
int32 line = LineAtOffset(where.y);
if (line < 0)
return;
::Team* team = fSourceView->fTeam;
AutoLocker<Team> locker(team);
::Thread* activeThread = fSourceView->fActiveThread;
if (activeThread == NULL)
return;
else if (activeThread->State() != THREAD_STATE_STOPPED)
return;
Statement* statement;
if (!fSourceView->GetStatementForLine(line, statement))
return;
BReference<Statement> statementReference(statement, true);
BPopUpMenu* menu = new(std::nothrow) BPopUpMenu("");
if (menu == NULL)
return;
ObjectDeleter<BPopUpMenu> menuDeleter(menu);
BMessage* message = new(std::nothrow) BMessage(MSG_THREAD_RUN);
if (message == NULL)
return;
ObjectDeleter<BMessage> messageDeleter(message);
message->AddUInt64("address", statement->CoveringAddressRange()
.Start());
BMenuItem* item = new(std::nothrow) BMenuItem("Run to cursor",
message);
if (item == NULL)
return;
ObjectDeleter<BMenuItem> itemDeleter(item);
messageDeleter.Detach();
if (!menu->AddItem(item))
return;
itemDeleter.Detach();
messageDeleter.Detach();
menuDeleter.Detach();
BPoint screenWhere(where);
ConvertToScreen(&screenWhere);
menu->SetTargetForItems(fSourceView);
BRect mouseRect(screenWhere, screenWhere);
mouseRect.InsetBy(-4.0, -4.0);
menu->Go(screenWhere, true, false, mouseRect, true);
} }
} }
@@ -1695,6 +1750,7 @@ SourceView::SourceView(Team* team, Listener* listener)
: :
BView("source view", 0), BView("source view", 0),
fTeam(team), fTeam(team),
fActiveThread(NULL),
fStackTrace(NULL), fStackTrace(NULL),
fStackFrame(NULL), fStackFrame(NULL),
fSourceCode(NULL), fSourceCode(NULL),
@@ -1713,7 +1769,7 @@ SourceView::SourceView(Team* team, Listener* listener)
SourceView::~SourceView() SourceView::~SourceView()
{ {
SetStackFrame(NULL); SetStackFrame(NULL);
SetStackTrace(NULL); SetStackTrace(NULL, NULL);
SetSourceCode(NULL); SetSourceCode(NULL);
} }
@@ -1734,6 +1790,27 @@ SourceView::Create(Team* team, Listener* listener)
} }
void
SourceView::MessageReceived(BMessage* message)
{
switch(message->what) {
case MSG_THREAD_RUN:
{
target_addr_t address;
if (message->FindUInt64("address", &address) != B_OK)
break;
fListener->ThreadActionRequested(fActiveThread, message->what,
address);
break;
}
default:
BView::MessageReceived(message);
break;
}
}
void void
SourceView::UnsetListener() SourceView::UnsetListener()
{ {
@@ -1742,13 +1819,21 @@ SourceView::UnsetListener()
void void
SourceView::SetStackTrace(StackTrace* stackTrace) SourceView::SetStackTrace(StackTrace* stackTrace, Thread* activeThread)
{ {
TRACE_GUI("SourceView::SetStackTrace(%p)\n", stackTrace); TRACE_GUI("SourceView::SetStackTrace(%p)\n", stackTrace);
if (stackTrace == fStackTrace) if (stackTrace == fStackTrace)
return; return;
if (fActiveThread != NULL)
fActiveThread->ReleaseReference();
fActiveThread = activeThread;
if (fActiveThread != NULL)
fActiveThread->AcquireReference();
if (fStackTrace != NULL) { if (fStackTrace != NULL) {
fMarkerManager->SetStackTrace(NULL); fMarkerManager->SetStackTrace(NULL);
fMarkerView->SetStackTrace(NULL); fMarkerView->SetStackTrace(NULL);
@@ -1949,6 +2034,29 @@ SourceView::DoLayout()
} }
bool
SourceView::GetStatementForLine(int32 line, Statement*& _statement)
{
if (line < 0)
return false;
AutoLocker<Team> locker(fTeam);
Statement* statement;
if (fTeam->GetStatementAtSourceLocation(fSourceCode, SourceLocation(line),
statement) != B_OK) {
return false;
}
BReference<Statement> statementReference(statement, true);
if (statement->StartSourceLocation().Line() != line)
return false;
_statement = statement;
statementReference.Detach();
return true;
}
void void
SourceView::_Init() SourceView::_Init()
{ {
@@ -18,6 +18,7 @@ class StackFrame;
class StackTrace; class StackTrace;
class Statement; class Statement;
class Team; class Team;
class Thread;
class UserBreakpoint; class UserBreakpoint;
@@ -32,9 +33,12 @@ public:
static SourceView* Create(Team* team, Listener* listener); static SourceView* Create(Team* team, Listener* listener);
// throws // throws
virtual void MessageReceived(BMessage* message);
void UnsetListener(); void UnsetListener();
void SetStackTrace(StackTrace* stackTrace); void SetStackTrace(StackTrace* stackTrace,
Thread* thread);
void SetStackFrame(StackFrame* stackFrame); void SetStackFrame(StackFrame* stackFrame);
void SetSourceCode(SourceCode* sourceCode); void SetSourceCode(SourceCode* sourceCode);
@@ -65,6 +69,10 @@ private:
float lineHeight; float lineHeight;
}; };
protected:
bool GetStatementForLine(int32 line,
Statement*& _statement);
private: private:
void _Init(); void _Init();
void _UpdateScrollBars(); void _UpdateScrollBars();
@@ -72,6 +80,7 @@ private:
private: private:
Team* fTeam; Team* fTeam;
Thread* fActiveThread;
StackTrace* fStackTrace; StackTrace* fStackTrace;
StackFrame* fStackFrame; StackFrame* fStackFrame;
SourceCode* fSourceCode; SourceCode* fSourceCode;
@@ -91,6 +100,8 @@ public:
target_addr_t address, bool enabled) = 0; target_addr_t address, bool enabled) = 0;
virtual void ClearBreakpointRequested( virtual void ClearBreakpointRequested(
target_addr_t address) = 0; target_addr_t address) = 0;
virtual void ThreadActionRequested(Thread* thread,
uint32 action, target_addr_t address) = 0;
}; };
@@ -645,6 +645,14 @@ TeamWindow::ClearBreakpointRequested(target_addr_t address)
} }
void
TeamWindow::ThreadActionRequested(::Thread* thread, uint32 action,
target_addr_t address)
{
fListener->ThreadActionRequested(thread->ID(), action, address);
}
void void
TeamWindow::WatchpointSelectionChanged(Watchpoint* watchpoint) TeamWindow::WatchpointSelectionChanged(Watchpoint* watchpoint)
{ {
@@ -953,7 +961,7 @@ TeamWindow::_SetActiveStackTrace(StackTrace* stackTrace)
fActiveStackTrace->AcquireReference(); fActiveStackTrace->AcquireReference();
fStackTraceView->SetStackTrace(fActiveStackTrace); fStackTraceView->SetStackTrace(fActiveStackTrace);
fSourceView->SetStackTrace(fActiveStackTrace); fSourceView->SetStackTrace(fActiveStackTrace, fActiveThread);
if (fActiveStackTrace != NULL) if (fActiveStackTrace != NULL)
_SetActiveStackFrame(fActiveStackTrace->FrameAt(0)); _SetActiveStackFrame(fActiveStackTrace->FrameAt(0));
@@ -107,7 +107,11 @@ private:
// SourceView::Listener // SourceView::Listener
virtual void SetBreakpointRequested(target_addr_t address, virtual void SetBreakpointRequested(target_addr_t address,
bool enabled); bool enabled);
virtual void ClearBreakpointRequested(target_addr_t address); virtual void ClearBreakpointRequested(
target_addr_t address);
virtual void ThreadActionRequested(::Thread* thread,
uint32 action, target_addr_t address);
// VariablesView::Listener // VariablesView::Listener
virtual void ValueNodeValueRequested(CpuState* cpuState, virtual void ValueNodeValueRequested(CpuState* cpuState,