Debugger: Add UI for configuring breakpoint conditions.

General:
- Add message codes for requesting breakpoint configuration.

UserInterfaceListener/TeamDebugger:
- Add/implement hooks for requesting breakpoint condition changes.

BreakpointsView:
- Add button to request editing the currently selected breakpoint's
  condition.

TeamWindow:
- Handle request to show breakpoint edit window.

BreakpointEditWindow:
- Implement simple radio-based UI for modifying the current breakpoint's
  condition.

Still missing: Actually handling/evaluating the breakpoint conditions in
the ThreadHandler when the breakpoint is hit.
This commit is contained in:
Rene Gollent
2014-10-30 16:54:31 -04:00
parent 3dfdc98cd1
commit 942226c711
11 changed files with 349 additions and 3 deletions
+1
View File
@@ -262,6 +262,7 @@ Application Debugger :
# user_interface/gui/team_window
BreakConditionConfigWindow.cpp
BreakpointEditWindow.cpp
BreakpointListView.cpp
BreakpointsView.cpp
ConsoleOutputView.cpp
+4
View File
@@ -18,6 +18,8 @@ enum {
MSG_CLEAR_BREAKPOINT = 'cbrk',
MSG_ENABLE_BREAKPOINT = 'ebrk',
MSG_DISABLE_BREAKPOINT = 'dbrk',
MSG_SET_BREAKPOINT_CONDITION = 'sbpc',
MSG_CLEAR_BREAKPOINT_CONDITION = 'cbpc',
MSG_SET_WATCHPOINT = 'swpt',
MSG_CLEAR_WATCHPOINT = 'cwpt',
MSG_ENABLE_WATCHPOINT = 'ewpt',
@@ -61,6 +63,8 @@ enum {
MSG_TEAMS_WINDOW_CLOSED = 'tswc',
MSG_SHOW_BREAK_CONDITION_CONFIG_WINDOW = 'sbcc',
MSG_BREAK_CONDITION_CONFIG_WINDOW_CLOSED = 'bccw',
MSG_SHOW_BREAKPOINT_EDIT_WINDOW = 'sbew',
MSG_BREAKPOINT_EDIT_WINDOW_CLOSED = 'bewc',
MSG_START_NEW_TEAM = 'sttt',
MSG_DEBUG_THIS_TEAM = 'dbtt',
MSG_SHOW_INSPECTOR_WINDOW = 'sirw',
+68 -2
View File
@@ -582,9 +582,10 @@ TeamDebugger::MessageReceived(BMessage* message)
BReference<UserBreakpoint> breakpointReference;
uint64 address = 0;
if (message->FindPointer("breakpoint", (void**)&breakpoint) == B_OK)
if (message->FindPointer("breakpoint", (void**)&breakpoint)
== B_OK) {
breakpointReference.SetTo(breakpoint, true);
else if (message->FindUInt64("address", &address) != B_OK)
} else if (message->FindUInt64("address", &address) != B_OK)
break;
if (message->what == MSG_SET_BREAKPOINT) {
@@ -610,6 +611,45 @@ TeamDebugger::MessageReceived(BMessage* message)
break;
}
case MSG_SET_BREAKPOINT_CONDITION:
{
UserBreakpoint* breakpoint = NULL;
BReference<UserBreakpoint> breakpointReference;
if (message->FindPointer("breakpoint", (void**)&breakpoint)
!= B_OK) {
break;
}
breakpointReference.SetTo(breakpoint, true);
const char* condition;
if (message->FindString("condition", &condition) != B_OK)
break;
AutoLocker< ::Team> teamLocker(fTeam);
breakpoint->SetCondition(condition);
fTeam->NotifyUserBreakpointChanged(breakpoint);
break;
}
case MSG_CLEAR_BREAKPOINT_CONDITION:
{
UserBreakpoint* breakpoint = NULL;
BReference<UserBreakpoint> breakpointReference;
if (message->FindPointer("breakpoint", (void**)&breakpoint)
!= B_OK)
break;
breakpointReference.SetTo(breakpoint, true);
AutoLocker< ::Team> teamLocker(fTeam);
breakpoint->SetCondition(NULL);
fTeam->NotifyUserBreakpointChanged(breakpoint);
break;
}
case MSG_STOP_ON_IMAGE_LOAD:
{
bool enabled;
@@ -986,6 +1026,32 @@ TeamDebugger::SetBreakpointEnabledRequested(UserBreakpoint* breakpoint,
}
void
TeamDebugger::SetBreakpointConditionRequested(UserBreakpoint* breakpoint,
const char* condition)
{
BMessage message(MSG_SET_BREAKPOINT_CONDITION);
BReference<UserBreakpoint> breakpointReference(breakpoint);
if (message.AddPointer("breakpoint", breakpoint) == B_OK
&& message.AddString("condition", condition) == B_OK
&& PostMessage(&message) == B_OK) {
breakpointReference.Detach();
}
}
void
TeamDebugger::ClearBreakpointConditionRequested(UserBreakpoint* breakpoint)
{
BMessage message(MSG_CLEAR_BREAKPOINT_CONDITION);
BReference<UserBreakpoint> breakpointReference(breakpoint);
if (message.AddPointer("breakpoint", breakpoint) == B_OK
&& PostMessage(&message) == B_OK) {
breakpointReference.Detach();
}
}
void
TeamDebugger::ClearBreakpointRequested(target_addr_t address)
{
@@ -81,6 +81,11 @@ private:
virtual void SetBreakpointEnabledRequested(
UserBreakpoint* breakpoint,
bool enabled);
virtual void SetBreakpointConditionRequested(
UserBreakpoint* breakpoint,
const char* condition);
virtual void ClearBreakpointConditionRequested(
UserBreakpoint* breakpoint);
virtual void ClearBreakpointRequested(target_addr_t address);
virtual void ClearBreakpointRequested(
UserBreakpoint* breakpoint);
@@ -109,6 +109,11 @@ public:
virtual void SetBreakpointEnabledRequested(
UserBreakpoint* breakpoint,
bool enabled) = 0;
virtual void SetBreakpointConditionRequested(
UserBreakpoint* breakpoint,
const char* condition) = 0;
virtual void ClearBreakpointConditionRequested(
UserBreakpoint* breakpoint) = 0;
virtual void ClearBreakpointRequested(
target_addr_t address) = 0;
virtual void ClearBreakpointRequested(
@@ -0,0 +1,144 @@
/*
* Copyright 2014, Rene Gollent, rene@gollent.com.
* Distributed under the terms of the MIT License.
*/
#include "BreakpointEditWindow.h"
#include <Button.h>
#include <LayoutBuilder.h>
#include <RadioButton.h>
#include <StringView.h>
#include <TextControl.h>
#include <AutoDeleter.h>
#include <AutoLocker.h>
#include "MessageCodes.h"
#include "UserBreakpoint.h"
#include "UserInterface.h"
#include "Team.h"
enum {
MSG_SET_BREAK_ALWAYS = 'sbal',
MSG_SET_BREAK_ON_CONDITION = 'sboc',
MSG_SAVE_BREAKPOINT_SETTINGS = 'sbps'
};
BreakpointEditWindow::BreakpointEditWindow(::Team* team,
UserBreakpoint* breakpoint, UserInterfaceListener* listener,
BHandler* target)
:
BWindow(BRect(), "Edit breakpoint", B_FLOATING_WINDOW,
B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE),
fTeam(team),
fListener(listener),
fTargetBreakpoint(breakpoint),
fSaveButton(NULL),
fCancelButton(NULL),
fTarget(target)
{
fTargetBreakpoint->AcquireReference();
}
BreakpointEditWindow::~BreakpointEditWindow()
{
fTargetBreakpoint->ReleaseReference();
BMessenger(fTarget).SendMessage(MSG_BREAKPOINT_EDIT_WINDOW_CLOSED);
}
BreakpointEditWindow*
BreakpointEditWindow::Create(::Team* team, UserBreakpoint* breakpoint,
UserInterfaceListener* listener, BHandler* target)
{
BreakpointEditWindow* self = new BreakpointEditWindow(
team, breakpoint, listener, target);
try {
self->_Init();
} catch (...) {
delete self;
throw;
}
return self;
}
void
BreakpointEditWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_SET_BREAK_ALWAYS:
fConditionInput->SetEnabled(false);
break;
case MSG_SET_BREAK_ON_CONDITION:
fConditionInput->SetEnabled(true);
break;
case MSG_SAVE_BREAKPOINT_SETTINGS:
{
if (fConditionRadio->Value() == B_CONTROL_ON) {
fListener->SetBreakpointConditionRequested(
fTargetBreakpoint, fConditionInput->Text());
} else {
fListener->ClearBreakpointConditionRequested(
fTargetBreakpoint);
}
// fall through
}
case B_CANCEL:
Quit();
break;
default:
BWindow::MessageReceived(message);
break;
}
}
void
BreakpointEditWindow::Show()
{
CenterOnScreen();
BWindow::Show();
}
void
BreakpointEditWindow::_Init()
{
fConditionInput = new BTextControl(NULL, NULL, NULL);
BLayoutItem* textLayoutItem = fConditionInput->CreateTextViewLayoutItem();
textLayoutItem->SetExplicitMinSize(BSize(200.0, B_SIZE_UNSET));
BLayoutBuilder::Group<>(this, B_VERTICAL)
.SetInsets(B_USE_DEFAULT_SPACING)
.Add((fAlwaysRadio = new BRadioButton("Break always",
new BMessage(MSG_SET_BREAK_ALWAYS))))
.AddGroup(B_HORIZONTAL)
.Add((fConditionRadio = new BRadioButton("Break on condition: ",
new BMessage(MSG_SET_BREAK_ON_CONDITION))))
.Add(textLayoutItem)
.End()
.AddGroup(B_HORIZONTAL)
.AddGlue()
.Add((fSaveButton = new BButton("Save",
new BMessage(MSG_SAVE_BREAKPOINT_SETTINGS))))
.Add((fCancelButton = new BButton("Cancel",
new BMessage(B_CANCEL))))
.End()
.End();
AutoLocker< ::Team> teamLocker(fTeam);
if (fTargetBreakpoint->HasCondition()) {
fConditionRadio->SetValue(B_CONTROL_ON);
fConditionInput->SetText(fTargetBreakpoint->Condition());
} else {
fAlwaysRadio->SetValue(B_CONTROL_ON);
fConditionInput->SetEnabled(false);
}
}
@@ -0,0 +1,61 @@
/*
* Copyright 2014, Rene Gollent, rene@gollent.com.
* Distributed under the terms of the MIT License.
*/
#ifndef BREAKPOINT_EDIT_WINDOW_H
#define BREAKPOINT_EDIT_WINDOW_H
#include <Window.h>
#include "Team.h"
#include "types/Types.h"
class BButton;
class BRadioButton;
class BTextControl;
class Team;
class UserBreakpoint;
class UserInterfaceListener;
class BreakpointEditWindow : public BWindow {
public:
BreakpointEditWindow(
::Team* team,
UserBreakpoint* breakpoint,
UserInterfaceListener* listener,
BHandler* target);
~BreakpointEditWindow();
static BreakpointEditWindow* Create(::Team* team,
UserBreakpoint* breakpoint,
UserInterfaceListener* listener,
BHandler* target);
// throws
virtual void MessageReceived(BMessage* message);
virtual void Show();
private:
void _Init();
void _UpdateState();
private:
::Team* fTeam;
UserInterfaceListener* fListener;
UserBreakpoint* fTargetBreakpoint;
BTextControl* fConditionInput;
BButton* fSaveButton;
BButton* fCancelButton;
BRadioButton* fAlwaysRadio;
BRadioButton* fConditionRadio;
BHandler* fTarget;
};
#endif // BREAKPOINT_EDIT_WINDOW
@@ -31,6 +31,7 @@ BreakpointsView::BreakpointsView(Team* team, Listener* listener)
fListView(NULL),
fConfigureExceptionsButton(NULL),
fToggleBreakpointButton(NULL),
fEditBreakpointButton(NULL),
fRemoveBreakpointButton(NULL),
fListener(listener)
{
@@ -96,6 +97,12 @@ BreakpointsView::MessageReceived(BMessage* message)
_HandleBreakpointAction(message->what);
break;
case MSG_SHOW_BREAKPOINT_EDIT_WINDOW:
message->AddPointer("breakpoint",
fSelectedBreakpoints.ItemAt(0)->GetBreakpoint());
Window()->PostMessage(message);
break;
default:
BGroupView::MessageReceived(message);
break;
@@ -107,6 +114,7 @@ void
BreakpointsView::AttachedToWindow()
{
fConfigureExceptionsButton->SetTarget(Window());
fEditBreakpointButton->SetTarget(this);
fToggleBreakpointButton->SetTarget(this);
fRemoveBreakpointButton->SetTarget(this);
}
@@ -157,6 +165,7 @@ BreakpointsView::_Init()
.Add(fConfigureExceptionsButton = new BButton(
"Configure break conditions" B_UTF8_ELLIPSIS))
.Add(fRemoveBreakpointButton = new BButton("Remove"))
.Add(fEditBreakpointButton = new BButton("Edit" B_UTF8_ELLIPSIS))
.Add(fToggleBreakpointButton = new BButton("Toggle"))
.End();
@@ -164,6 +173,8 @@ BreakpointsView::_Init()
new BMessage(MSG_SHOW_BREAK_CONDITION_CONFIG_WINDOW));
fToggleBreakpointButton->SetMessage(new BMessage(MSG_ENABLE_BREAKPOINT));
fRemoveBreakpointButton->SetMessage(new BMessage(MSG_CLEAR_BREAKPOINT));
fEditBreakpointButton->SetMessage(
new BMessage(MSG_SHOW_BREAKPOINT_EDIT_WINDOW));
_UpdateButtons();
}
@@ -190,6 +201,7 @@ BreakpointsView::_UpdateButtons()
hasEnabled = true;
else
hasDisabled = true;
}
break;
}
@@ -209,6 +221,17 @@ BreakpointsView::_UpdateButtons()
}
if (valid) {
// only allow condition editing if we have a single
// actual breakpoint selected.
// TODO: allow using this to modify watchpoints as
// well.
if (fSelectedBreakpoints.CountItems() == 1
&& fSelectedBreakpoints.ItemAt(0)->Type()
== BREAKPOINT_PROXY_TYPE_BREAKPOINT) {
fEditBreakpointButton->SetEnabled(true);
} else
fEditBreakpointButton->SetEnabled(false);
// if we have at least one disabled breakpoint in the
// selection, we leave the button as an Enable button
if (hasEnabled && !hasDisabled) {
@@ -226,6 +249,7 @@ BreakpointsView::_UpdateButtons()
} else {
fToggleBreakpointButton->SetLabel("Enable");
fToggleBreakpointButton->SetEnabled(false);
fEditBreakpointButton->SetEnabled(false);
fRemoveBreakpointButton->SetEnabled(false);
}
}
@@ -57,6 +57,7 @@ private:
BreakpointProxyList fSelectedBreakpoints;
BButton* fConfigureExceptionsButton;
BButton* fToggleBreakpointButton;
BButton* fEditBreakpointButton;
BButton* fRemoveBreakpointButton;
Listener* fListener;
};
@@ -33,12 +33,14 @@
#include <AutoDeleter.h>
#include <AutoLocker.h>
#include "BreakConditionConfigWindow.h"
#include "Breakpoint.h"
#include "BreakpointEditWindow.h"
#include "ConsoleOutputView.h"
#include "CppLanguage.h"
#include "CpuState.h"
#include "DisassembledCode.h"
#include "BreakConditionConfigWindow.h"
#include "BreakpointEditWindow.h"
#include "ExpressionEvaluationWindow.h"
#include "FileSourceCode.h"
#include "GuiSettingsUtils.h"
@@ -136,6 +138,7 @@ TeamWindow::TeamWindow(::Team* team, UserInterfaceListener* listener)
fThreadSplitView(NULL),
fConsoleSplitView(NULL),
fBreakConditionConfigWindow(NULL),
fBreakpointEditWindow(NULL),
fInspectorWindow(NULL),
fExpressionWindow(NULL),
fFilePanel(NULL),
@@ -395,6 +398,36 @@ TeamWindow::MessageReceived(BMessage* message)
fBreakConditionConfigWindow = NULL;
break;
}
case MSG_SHOW_BREAKPOINT_EDIT_WINDOW:
{
if (fBreakpointEditWindow != NULL) {
AutoLocker<BWindow> lock(fBreakpointEditWindow);
if (lock.IsLocked())
fBreakpointEditWindow->Activate(true);
} else {
UserBreakpoint* breakpoint;
if (message->FindPointer("breakpoint",
reinterpret_cast<void**>(&breakpoint)) != B_OK) {
break;
}
try {
fBreakpointEditWindow
= BreakpointEditWindow::Create(
fTeam, breakpoint, fListener, this);
if (fBreakpointEditWindow != NULL)
fBreakpointEditWindow->Show();
} catch (...) {
// TODO: notify user
}
}
break;
}
case MSG_BREAKPOINT_EDIT_WINDOW_CLOSED:
{
fBreakpointEditWindow = NULL;
break;
}
case MSG_SHOW_WATCH_VARIABLE_PROMPT:
{
target_addr_t address;
@@ -33,6 +33,7 @@ class BStringView;
class BTabView;
class ConsoleOutputView;
class BreakConditionConfigWindow;
class BreakpointEditWindow;
class ExpressionEvaluationWindow;
class Image;
class InspectorWindow;
@@ -220,6 +221,7 @@ private:
BSplitView* fThreadSplitView;
BSplitView* fConsoleSplitView;
BreakConditionConfigWindow* fBreakConditionConfigWindow;
BreakpointEditWindow* fBreakpointEditWindow;
InspectorWindow* fInspectorWindow;
ExpressionEvaluationWindow* fExpressionWindow;
GuiTeamUiSettings fUiSettings;