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:
@@ -262,6 +262,7 @@ Application Debugger :
|
||||
|
||||
# user_interface/gui/team_window
|
||||
BreakConditionConfigWindow.cpp
|
||||
BreakpointEditWindow.cpp
|
||||
BreakpointListView.cpp
|
||||
BreakpointsView.cpp
|
||||
ConsoleOutputView.cpp
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user