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:
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user