hrev48170 adds 6 changesets to branch 'master' old head: a13654e0894836c7e215d2a64c5c76072485832d new head: a5ce4678c054489520b8e2a7c0910da48a5d1521 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=a5ce467+%5Ea13654e ---------------------------------------------------------------------------- 854b341: Debugger: Minor tweak to expression window. - If the expression result is an integer, display it in both hex and decimal format. 65a10b5: Debugger: Add condition expression member to UserBreakpoint. - UserBreakpoint and its corresponding settings classes now store/recall an optional condition expression. 3dfdc98: Debugger: Show breakpoint conditions in list view. - Adjust breakpoint table and model to also show breakpoint conditions, if set. 942226c: 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. 43060a5: Debugger: Minor tweak to ExpressionEvaluationJob. - ExpressionEvaluationJob now stores the final result value, and provides an accessor to it. a5ce467: Debugger: Implement conditional breakpoints. ThreadHandler: - When a breakpoint event is hit, we now check if there is an associated UserBreakpoint with a condition attached. If so, we schedule an evaluation request, and only stop the thread if that one evaluates to true (or if evaluation fails in some way). This implements #9713. [ Rene Gollent <rene@xxxxxxxxxxx> ] ---------------------------------------------------------------------------- 22 files changed, 601 insertions(+), 26 deletions(-) src/apps/debugger/Jamfile | 1 + src/apps/debugger/MessageCodes.h | 4 + src/apps/debugger/controllers/TeamDebugger.cpp | 71 +++++++- src/apps/debugger/controllers/TeamDebugger.h | 5 + src/apps/debugger/controllers/ThreadHandler.cpp | 168 ++++++++++++++++++- src/apps/debugger/controllers/ThreadHandler.h | 11 ++ .../debugger/jobs/ExpressionEvaluationJob.cpp | 14 +- src/apps/debugger/jobs/Jobs.h | 3 + src/apps/debugger/model/UserBreakpoint.cpp | 12 +- src/apps/debugger/model/UserBreakpoint.h | 11 +- src/apps/debugger/settings/BreakpointSetting.cpp | 20 ++- src/apps/debugger/settings/BreakpointSetting.h | 9 +- src/apps/debugger/settings/TeamSettings.cpp | 3 +- src/apps/debugger/user_interface/UserInterface.h | 5 + .../gui/team_window/BreakpointEditWindow.cpp | 144 ++++++++++++++++ .../gui/team_window/BreakpointEditWindow.h | 61 +++++++ .../gui/team_window/BreakpointListView.cpp | 10 +- .../gui/team_window/BreakpointsView.cpp | 24 +++ .../gui/team_window/BreakpointsView.h | 1 + .../team_window/ExpressionEvaluationWindow.cpp | 13 +- .../gui/team_window/TeamWindow.cpp | 35 +++- .../user_interface/gui/team_window/TeamWindow.h | 2 + ############################################################################ Commit: 854b341612a905567ed990e5752f66d5b5a158ce URL: http://cgit.haiku-os.org/haiku/commit/?id=854b341 Author: Rene Gollent <rene@xxxxxxxxxxx> Date: Thu Oct 30 15:28:23 2014 UTC Debugger: Minor tweak to expression window. - If the expression result is an integer, display it in both hex and decimal format. ---------------------------------------------------------------------------- diff --git a/src/apps/debugger/user_interface/gui/team_window/ExpressionEvaluationWindow.cpp b/src/apps/debugger/user_interface/gui/team_window/ExpressionEvaluationWindow.cpp index 8236450..b9724e8 100644 --- a/src/apps/debugger/user_interface/gui/team_window/ExpressionEvaluationWindow.cpp +++ b/src/apps/debugger/user_interface/gui/team_window/ExpressionEvaluationWindow.cpp @@ -254,9 +254,16 @@ ExpressionEvaluationWindow::MessageReceived(BMessage* message) } BString outputText; - if (value != NULL) - value->ToString(outputText); - else { + if (value != NULL) { + BVariant variantValue; + value->ToVariant(variantValue); + if (variantValue.TypeIsInteger(variantValue.Type())) { + value->ToString(outputText); + outputText.SetToFormat("%#" B_PRIx64 " (%s)", + variantValue.ToUInt64(), outputText.String()); + } else + value->ToString(outputText); + } else { status_t result; if (message->FindInt32("result", &result) != B_OK) result = B_ERROR; ############################################################################ Commit: 65a10b5000e34eab3c066965642b3fec95781c16 URL: http://cgit.haiku-os.org/haiku/commit/?id=65a10b5 Author: Rene Gollent <rene@xxxxxxxxxxx> Date: Thu Oct 30 14:12:21 2014 UTC Debugger: Add condition expression member to UserBreakpoint. - UserBreakpoint and its corresponding settings classes now store/recall an optional condition expression. ---------------------------------------------------------------------------- diff --git a/src/apps/debugger/controllers/TeamDebugger.cpp b/src/apps/debugger/controllers/TeamDebugger.cpp index 133a395..620eca5 100644 --- a/src/apps/debugger/controllers/TeamDebugger.cpp +++ b/src/apps/debugger/controllers/TeamDebugger.cpp @@ -2122,6 +2122,7 @@ TeamDebugger::_LoadSettings() BReference<UserBreakpoint> breakpointReference(breakpoint, true); breakpoint->SetHidden(breakpointSetting->IsHidden()); + breakpoint->SetCondition(breakpointSetting->Condition()); // install it fBreakpointManager->InstallUserBreakpoint(breakpoint, diff --git a/src/apps/debugger/model/UserBreakpoint.cpp b/src/apps/debugger/model/UserBreakpoint.cpp index 996eb6e..c2c288e 100644 --- a/src/apps/debugger/model/UserBreakpoint.cpp +++ b/src/apps/debugger/model/UserBreakpoint.cpp @@ -1,6 +1,6 @@ /* * Copyright 2009, Ingo Weinhold, ingo_weinhold@xxxxxx. - * Copyright 2013, Rene Gollent, rene@xxxxxxxxxxx. + * Copyright 2013-2014, Rene Gollent, rene@xxxxxxxxxxx. * Distributed under the terms of the MIT License. */ @@ -101,7 +101,8 @@ UserBreakpoint::UserBreakpoint(const UserBreakpointLocation& location) fLocation(location), fValid(false), fEnabled(false), - fHidden(false) + fHidden(false), + fConditionExpression() { } @@ -169,3 +170,10 @@ UserBreakpoint::SetHidden(bool hidden) { fHidden = hidden; } + + +void +UserBreakpoint::SetCondition(const BString& conditionExpression) +{ + fConditionExpression = conditionExpression; +} diff --git a/src/apps/debugger/model/UserBreakpoint.h b/src/apps/debugger/model/UserBreakpoint.h index cf4cfe3..84969b6 100644 --- a/src/apps/debugger/model/UserBreakpoint.h +++ b/src/apps/debugger/model/UserBreakpoint.h @@ -1,6 +1,6 @@ /* * Copyright 2009, Ingo Weinhold, ingo_weinhold@xxxxxx. - * Copyright 2013, Rene Gollent, rene@xxxxxxxxxxx. + * Copyright 2013-2014, Rene Gollent, rene@xxxxxxxxxxx. * Distributed under the terms of the MIT License. */ #ifndef USER_BREAKPOINT_H @@ -12,6 +12,7 @@ #include <util/DoublyLinkedList.h> #include "SourceLocation.h" +#include "String.h" #include "Types.h" @@ -104,6 +105,13 @@ public: bool IsHidden() const { return fHidden; } void SetHidden(bool hidden); + bool HasCondition() const + { return !fConditionExpression.IsEmpty(); } + const BString& Condition() const + { return fConditionExpression; } + void SetCondition( + const BString& conditionExpression); + private: typedef BObjectList<UserBreakpointInstance> InstanceList; @@ -113,6 +121,7 @@ private: bool fValid; bool fEnabled; bool fHidden; + BString fConditionExpression; }; diff --git a/src/apps/debugger/settings/BreakpointSetting.cpp b/src/apps/debugger/settings/BreakpointSetting.cpp index 03ade77..6ad3db1 100644 --- a/src/apps/debugger/settings/BreakpointSetting.cpp +++ b/src/apps/debugger/settings/BreakpointSetting.cpp @@ -1,6 +1,6 @@ /* * Copyright 2009, Ingo Weinhold, ingo_weinhold@xxxxxx. - * Copyright 2013, Rene Gollent, rene@xxxxxxxxxxx. + * Copyright 2013-2014, Rene Gollent, rene@xxxxxxxxxxx. * Distributed under the terms of the MIT License. */ @@ -22,7 +22,8 @@ BreakpointSetting::BreakpointSetting() fSourceLocation(), fRelativeAddress(0), fEnabled(false), - fHidden(false) + fHidden(false), + fConditionExpression() { } @@ -34,7 +35,8 @@ BreakpointSetting::BreakpointSetting(const BreakpointSetting& other) fSourceLocation(other.fSourceLocation), fRelativeAddress(other.fRelativeAddress), fEnabled(other.fEnabled), - fHidden(other.fHidden) + fHidden(other.fHidden), + fConditionExpression(other.fConditionExpression) { if (fFunctionID != NULL) fFunctionID->AcquireReference(); @@ -49,7 +51,7 @@ BreakpointSetting::~BreakpointSetting() status_t BreakpointSetting::SetTo(const UserBreakpointLocation& location, bool enabled, - bool hidden) + bool hidden, const BString& conditionExpression) { _Unset(); @@ -64,6 +66,7 @@ BreakpointSetting::SetTo(const UserBreakpointLocation& location, bool enabled, fRelativeAddress = location.RelativeAddress(); fEnabled = enabled; fHidden = hidden; + fConditionExpression = conditionExpression; return B_OK; } @@ -100,6 +103,9 @@ BreakpointSetting::SetTo(const BMessage& archive) if (archive.FindBool("hidden", &fHidden) != B_OK) fHidden = false; + if (archive.FindString("condition", &fConditionExpression) != B_OK) + fConditionExpression.Truncate(0); + return B_OK; } @@ -122,7 +128,9 @@ BreakpointSetting::WriteTo(BMessage& archive) const || (error = archive.AddUInt64("relativeAddress", fRelativeAddress)) != B_OK || (error = archive.AddBool("enabled", fEnabled)) != B_OK - || (error = archive.AddBool("hidden", fHidden)) != B_OK) { + || (error = archive.AddBool("hidden", fHidden)) != B_OK + || (error = archive.AddString("condition", fConditionExpression)) + != B_OK) { return error; } @@ -147,6 +155,7 @@ BreakpointSetting::operator=(const BreakpointSetting& other) fRelativeAddress = other.fRelativeAddress; fEnabled = other.fEnabled; fHidden = other.fHidden; + fConditionExpression = other.fConditionExpression; return *this; } @@ -164,4 +173,5 @@ BreakpointSetting::_Unset() fSourceLocation = SourceLocation(); fRelativeAddress = 0; fEnabled = false; + fConditionExpression.Truncate(0); } diff --git a/src/apps/debugger/settings/BreakpointSetting.h b/src/apps/debugger/settings/BreakpointSetting.h index 90d0a03..9ea54d2 100644 --- a/src/apps/debugger/settings/BreakpointSetting.h +++ b/src/apps/debugger/settings/BreakpointSetting.h @@ -1,6 +1,6 @@ /* * Copyright 2009, Ingo Weinhold, ingo_weinhold@xxxxxx. - * Copyright 2013, Rene Gollent, rene@xxxxxxxxxxx. + * Copyright 2013-2014, Rene Gollent, rene@xxxxxxxxxxx. * Distributed under the terms of the MIT License. */ #ifndef BREAKPOINT_SETTING_H @@ -28,7 +28,8 @@ public: ~BreakpointSetting(); status_t SetTo(const UserBreakpointLocation& location, - bool enabled, bool hidden); + bool enabled, bool hidden, + const BString& conditionExpression); status_t SetTo(const BMessage& archive); status_t WriteTo(BMessage& archive) const; @@ -42,6 +43,9 @@ public: bool IsEnabled() const { return fEnabled; } bool IsHidden() const { return fHidden; } + const BString& Condition() const + { return fConditionExpression; } + BreakpointSetting& operator=(const BreakpointSetting& other); private: @@ -54,6 +58,7 @@ private: target_addr_t fRelativeAddress; bool fEnabled; bool fHidden; + BString fConditionExpression; }; diff --git a/src/apps/debugger/settings/TeamSettings.cpp b/src/apps/debugger/settings/TeamSettings.cpp index 99c38a0..b77224f 100644 --- a/src/apps/debugger/settings/TeamSettings.cpp +++ b/src/apps/debugger/settings/TeamSettings.cpp @@ -64,7 +64,8 @@ TeamSettings::SetTo(Team* team) return B_NO_MEMORY; status_t error = breakpointSetting->SetTo(breakpoint->Location(), - breakpoint->IsEnabled(), breakpoint->IsHidden()); + breakpoint->IsEnabled(), breakpoint->IsHidden(), + breakpoint->Condition()); if (error == B_OK && !fBreakpoints.AddItem(breakpointSetting)) error = B_NO_MEMORY; if (error != B_OK) { ############################################################################ Commit: 3dfdc98cd1ee9c6ad6619ae4c0f94ead5ede0ee1 URL: http://cgit.haiku-os.org/haiku/commit/?id=3dfdc98 Author: Rene Gollent <rene@xxxxxxxxxxx> Date: Thu Oct 30 15:38:06 2014 UTC Debugger: Show breakpoint conditions in list view. - Adjust breakpoint table and model to also show breakpoint conditions, if set. ---------------------------------------------------------------------------- diff --git a/src/apps/debugger/user_interface/gui/team_window/BreakpointListView.cpp b/src/apps/debugger/user_interface/gui/team_window/BreakpointListView.cpp index 6b88b63..a3742d8 100644 --- a/src/apps/debugger/user_interface/gui/team_window/BreakpointListView.cpp +++ b/src/apps/debugger/user_interface/gui/team_window/BreakpointListView.cpp @@ -217,7 +217,7 @@ public: virtual int32 CountColumns() const { - return 3; + return 4; } virtual int32 CountRows() const @@ -277,6 +277,12 @@ private: value.SetTo(data); return true; } + case 3: + { + value.SetTo(breakpoint->Condition(), + B_VARIANT_DONT_COPY_DATA); + return true; + } default: return false; } @@ -456,6 +462,8 @@ BreakpointListView::_Init(BView* filterTarget) 1000, B_TRUNCATE_END, B_ALIGN_LEFT)); fBreakpointsTable->AddColumn(new StringTableColumn(2, "File:Line/Address", 250, 40, 1000, B_TRUNCATE_END, B_ALIGN_LEFT)); + fBreakpointsTable->AddColumn(new StringTableColumn(3, "Condition", + 250, 40, 1000, B_TRUNCATE_END, B_ALIGN_LEFT)); fBreakpointsTable->SetSelectionMode(B_MULTIPLE_SELECTION_LIST); fBreakpointsTable->AddTableListener(this); ############################################################################ Commit: 942226c711ca32e4c9b18e7c1e3a76fd546b3082 URL: http://cgit.haiku-os.org/haiku/commit/?id=942226c Author: Rene Gollent <rene@xxxxxxxxxxx> Date: Thu Oct 30 18:23:26 2014 UTC 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. ---------------------------------------------------------------------------- diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index 43ad313..ad85396c 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -262,6 +262,7 @@ Application Debugger : # user_interface/gui/team_window BreakConditionConfigWindow.cpp + BreakpointEditWindow.cpp BreakpointListView.cpp BreakpointsView.cpp ConsoleOutputView.cpp diff --git a/src/apps/debugger/MessageCodes.h b/src/apps/debugger/MessageCodes.h index 42d9966..fdf07db 100644 --- a/src/apps/debugger/MessageCodes.h +++ b/src/apps/debugger/MessageCodes.h @@ -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', diff --git a/src/apps/debugger/controllers/TeamDebugger.cpp b/src/apps/debugger/controllers/TeamDebugger.cpp index 620eca5..eec3593 100644 --- a/src/apps/debugger/controllers/TeamDebugger.cpp +++ b/src/apps/debugger/controllers/TeamDebugger.cpp @@ -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; @@ -987,6 +1027,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) { BMessage message(MSG_CLEAR_BREAKPOINT); diff --git a/src/apps/debugger/controllers/TeamDebugger.h b/src/apps/debugger/controllers/TeamDebugger.h index ef5a9f2..10e0447 100644 --- a/src/apps/debugger/controllers/TeamDebugger.h +++ b/src/apps/debugger/controllers/TeamDebugger.h @@ -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); diff --git a/src/apps/debugger/user_interface/UserInterface.h b/src/apps/debugger/user_interface/UserInterface.h index 565f0b9..e6abffb 100644 --- a/src/apps/debugger/user_interface/UserInterface.h +++ b/src/apps/debugger/user_interface/UserInterface.h @@ -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( diff --git a/src/apps/debugger/user_interface/gui/team_window/BreakpointEditWindow.cpp b/src/apps/debugger/user_interface/gui/team_window/BreakpointEditWindow.cpp new file mode 100644 index 0000000..a5f5abe --- /dev/null +++ b/src/apps/debugger/user_interface/gui/team_window/BreakpointEditWindow.cpp @@ -0,0 +1,144 @@ +/* + * Copyright 2014, Rene Gollent, rene@xxxxxxxxxxx. + * 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); + } +} diff --git a/src/apps/debugger/user_interface/gui/team_window/BreakpointEditWindow.h b/src/apps/debugger/user_interface/gui/team_window/BreakpointEditWindow.h new file mode 100644 index 0000000..a733fd4 --- /dev/null +++ b/src/apps/debugger/user_interface/gui/team_window/BreakpointEditWindow.h @@ -0,0 +1,61 @@ +/* + * Copyright 2014, Rene Gollent, rene@xxxxxxxxxxx. + * 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 diff --git a/src/apps/debugger/user_interface/gui/team_window/BreakpointsView.cpp b/src/apps/debugger/user_interface/gui/team_window/BreakpointsView.cpp index baf5a96..acd7888 100644 --- a/src/apps/debugger/user_interface/gui/team_window/BreakpointsView.cpp +++ b/src/apps/debugger/user_interface/gui/team_window/BreakpointsView.cpp @@ -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); } } diff --git a/src/apps/debugger/user_interface/gui/team_window/BreakpointsView.h b/src/apps/debugger/user_interface/gui/team_window/BreakpointsView.h index ea10f93..4946b46 100644 --- a/src/apps/debugger/user_interface/gui/team_window/BreakpointsView.h +++ b/src/apps/debugger/user_interface/gui/team_window/BreakpointsView.h @@ -57,6 +57,7 @@ private: BreakpointProxyList fSelectedBreakpoints; BButton* fConfigureExceptionsButton; BButton* fToggleBreakpointButton; + BButton* fEditBreakpointButton; BButton* fRemoveBreakpointButton; Listener* fListener; }; diff --git a/src/apps/debugger/user_interface/gui/team_window/TeamWindow.cpp b/src/apps/debugger/user_interface/gui/team_window/TeamWindow.cpp index 32c1543..d820398 100644 --- a/src/apps/debugger/user_interface/gui/team_window/TeamWindow.cpp +++ b/src/apps/debugger/user_interface/gui/team_window/TeamWindow.cpp @@ -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; diff --git a/src/apps/debugger/user_interface/gui/team_window/TeamWindow.h b/src/apps/debugger/user_interface/gui/team_window/TeamWindow.h index 91a414e..ec0cd5c 100644 --- a/src/apps/debugger/user_interface/gui/team_window/TeamWindow.h +++ b/src/apps/debugger/user_interface/gui/team_window/TeamWindow.h @@ -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; ############################################################################ Commit: 43060a58fa461430c98c7d24c3e71179e160a5ab URL: http://cgit.haiku-os.org/haiku/commit/?id=43060a5 Author: Rene Gollent <rene@xxxxxxxxxxx> Date: Thu Oct 30 20:48:00 2014 UTC Debugger: Minor tweak to ExpressionEvaluationJob. - ExpressionEvaluationJob now stores the final result value, and provides an accessor to it. ---------------------------------------------------------------------------- diff --git a/src/apps/debugger/jobs/ExpressionEvaluationJob.cpp b/src/apps/debugger/jobs/ExpressionEvaluationJob.cpp index b98f783..22bd03e 100644 --- a/src/apps/debugger/jobs/ExpressionEvaluationJob.cpp +++ b/src/apps/debugger/jobs/ExpressionEvaluationJob.cpp @@ -34,7 +34,8 @@ ExpressionEvaluationJob::ExpressionEvaluationJob(Team* team, fResultType(resultType), fFrame(frame), fThread(thread), - fManager(NULL) + fManager(NULL), + fResultValue(NULL) { fLanguage->AcquireReference(); if (fFrame != NULL) @@ -53,6 +54,8 @@ ExpressionEvaluationJob::~ExpressionEvaluationJob() fThread->ReleaseReference(); if (fManager != NULL) fManager->ReleaseReference(); + if (fResultValue != NULL) + fResultValue->ReleaseReference(); } @@ -66,8 +69,6 @@ ExpressionEvaluationJob::Key() const status_t ExpressionEvaluationJob::Do() { - - Value* value = NULL; BReference<Value> reference; status_t result = B_OK; if (fFrame != NULL && fManager == NULL) { @@ -85,18 +86,17 @@ ExpressionEvaluationJob::Do() ValueNode* neededNode = NULL; result = fLanguage->EvaluateExpression(fExpression, - fResultType, fManager, value, neededNode); + fResultType, fManager, fResultValue, neededNode); if (neededNode != NULL) { result = ResolveNodeValue(neededNode); if (State() == JOB_STATE_WAITING) return B_OK; - else if (value != NULL) - reference.SetTo(value, true); // if result != B_OK, fall through } AutoLocker<Team> teamLocker(fTeam); - fTeam->NotifyExpressionEvaluated(fExpression.String(), result, value); + fTeam->NotifyExpressionEvaluated(fExpression.String(), result, + fResultValue); return B_OK; } diff --git a/src/apps/debugger/jobs/Jobs.h b/src/apps/debugger/jobs/Jobs.h index 6ae378e..c94c091 100644 --- a/src/apps/debugger/jobs/Jobs.h +++ b/src/apps/debugger/jobs/Jobs.h @@ -245,6 +245,8 @@ public: virtual const JobKey& Key() const; virtual status_t Do(); + Value* GetResultValue() const { return fResultValue; } + private: status_t ResolveNodeValue(ValueNode* node); @@ -260,6 +262,7 @@ private: StackFrame* fFrame; Thread* fThread; ValueNodeManager* fManager; + Value* fResultValue; }; ############################################################################ Revision: hrev48170 Commit: a5ce4678c054489520b8e2a7c0910da48a5d1521 URL: http://cgit.haiku-os.org/haiku/commit/?id=a5ce467 Author: Rene Gollent <rene@xxxxxxxxxxx> Date: Thu Oct 30 20:49:16 2014 UTC Ticket: https://dev.haiku-os.org/ticket/9713 Debugger: Implement conditional breakpoints. ThreadHandler: - When a breakpoint event is hit, we now check if there is an associated UserBreakpoint with a condition attached. If so, we schedule an evaluation request, and only stop the thread if that one evaluates to true (or if evaluation fails in some way). This implements #9713. ---------------------------------------------------------------------------- diff --git a/src/apps/debugger/controllers/ThreadHandler.cpp b/src/apps/debugger/controllers/ThreadHandler.cpp index a9653c2..e44bbbb 100644 --- a/src/apps/debugger/controllers/ThreadHandler.cpp +++ b/src/apps/debugger/controllers/ThreadHandler.cpp @@ -11,7 +11,9 @@ #include <new> +#include <AutoDeleter.h> #include <AutoLocker.h> +#include <Variant.h> #include "Architecture.h" #include "BreakpointManager.h" @@ -24,11 +26,13 @@ #include "MessageCodes.h" #include "Register.h" #include "SourceCode.h" +#include "SourceLanguage.h" #include "SpecificImageDebugInfo.h" #include "StackTrace.h" #include "Statement.h" #include "Team.h" #include "Tracing.h" +#include "Value.h" #include "Worker.h" @@ -42,6 +46,43 @@ enum { }; +class ExpressionJobListener : public JobListener { +public: + ExpressionJobListener(ThreadHandler* handler) + : + JobListener(), + fHandler(handler) + { + fHandler->AcquireReference(); + } + + ~ExpressionJobListener() + { + fHandler->ReleaseReference(); + } + + virtual void JobDone(Job* job) + { + Value* resultValue = dynamic_cast<ExpressionEvaluationJob*>(job) + ->GetResultValue(); + + fHandler->_HandleBreakpointConditionEvaluated(resultValue); + } + + virtual void JobFailed(Job* job) + { + fHandler->_HandleBreakpointConditionEvaluated(NULL); + } + + virtual void JobAborted(Job* job) + { + fHandler->_HandleBreakpointConditionEvaluated(NULL); + } +private: + ThreadHandler* fHandler; +}; + + ThreadHandler::ThreadHandler(Thread* thread, Worker* worker, DebuggerInterface* debuggerInterface, ImageDebugInfoJobListener* listener, @@ -58,7 +99,10 @@ ThreadHandler::ThreadHandler(Thread* thread, Worker* worker, fSteppedOverFunctionAddress(0), fPreviousInstructionPointer(0), fPreviousFrameAddress(0), - fSingleStepping(false) + fSingleStepping(false), + fHasPendingConditionEvaluation(false), + fConditionWaitSem(-1), + fConditionResult(NULL) { fDebuggerInterface->AcquireReference(); } @@ -68,6 +112,9 @@ ThreadHandler::~ThreadHandler() { _ClearContinuationState(); fDebuggerInterface->ReleaseReference(); + + if (fConditionWaitSem > 0) + delete_sem(fConditionWaitSem); } @@ -76,6 +123,7 @@ ThreadHandler::Init() { fWorker->ScheduleJob(new(std::nothrow) GetThreadStateJob(fDebuggerInterface, fThread)); + fConditionWaitSem = create_sem(0, "breakpoint condition waiter"); } @@ -164,6 +212,12 @@ ThreadHandler::HandleBreakpointHit(BreakpointHitEvent* event) } return false; + } else { + locker.Unlock(); + if (_HandleBreakpointConditionIfNeeded(cpuState)) + return true; + + locker.Lock(); } } @@ -387,6 +441,13 @@ ThreadHandler::HandleCpuStateChanged() void ThreadHandler::HandleStackTraceChanged() { + AutoLocker< ::Team> teamLocker(fThread->GetTeam()); + if (fHasPendingConditionEvaluation && fThread->GetStackTrace() != NULL) { + fHasPendingConditionEvaluation = false; + teamLocker.Unlock(); + + _HandleBreakpointConditionIfNeeded(fThread->GetCpuState()); + } } @@ -789,6 +850,111 @@ ThreadHandler::_HandleSingleStepStep(CpuState* cpuState) bool +ThreadHandler::_HandleBreakpointConditionIfNeeded(CpuState* cpuState) +{ + AutoLocker< ::Team> teamLocker(fThread->GetTeam()); + Breakpoint* breakpoint = fThread->GetTeam()->BreakpointAtAddress( + cpuState->InstructionPointer()); + + if (breakpoint == NULL) + return false; + + if (!breakpoint->HasEnabledUserBreakpoint()) + return false; + + const UserBreakpointInstanceList& breakpoints + = breakpoint->UserBreakpoints(); + + for (UserBreakpointInstanceList::ConstIterator it + = breakpoints.GetIterator(); it.HasNext();) { + UserBreakpoint* userBreakpoint = it.Next()->GetUserBreakpoint(); + if (!userBreakpoint->IsValid()) + continue; + if (!userBreakpoint->IsEnabled()) + continue; + if (!userBreakpoint->HasCondition()) + continue; + + StackTrace* stackTrace = fThread->GetStackTrace(); + if (stackTrace == NULL) { + fThread->SetCpuState(cpuState); + fHasPendingConditionEvaluation = true; + return true; + } + + StackFrame* frame = stackTrace->FrameAt(0); + FunctionDebugInfo* info = frame->Function()->GetFunctionDebugInfo(); + if (info == NULL) + return false; + + SpecificImageDebugInfo* specificInfo + = info->GetSpecificImageDebugInfo(); + if (specificInfo == NULL) + return false; + + SourceLanguage* language; + if (specificInfo->GetSourceLanguage(info, language) != B_OK) + return false; + + BReference<SourceLanguage> reference(language, true); + ExpressionJobListener* listener + = new(std::nothrow) ExpressionJobListener(this); + if (listener == NULL) + return false; + + status_t error = fWorker->ScheduleJob( + new(std::nothrow) ExpressionEvaluationJob(fThread->GetTeam(), + fDebuggerInterface, language, userBreakpoint->Condition(), + B_UINT64_TYPE, frame, fThread), listener); + + BPrivate::ObjectDeleter<ExpressionJobListener> deleter(listener); + if (error == B_OK) { + teamLocker.Unlock(); + + do { + error = acquire_sem(fConditionWaitSem); + } while (error == B_INTERRUPTED); + + teamLocker.Lock(); + + bool stop = false; + if (fConditionResult == NULL) + stop = true; + else { + BVariant value; + if (!fConditionResult->ToVariant(value)) + stop = true; + if (!value.TypeIsInteger(value.Type())) + stop = true; + stop = value.ToBool(); + fConditionResult->ReleaseReference(); + fConditionResult = NULL; + } + + if (stop) + return false; + else { + fDebuggerInterface->ContinueThread(fThread->ID()); + return true; + } + } + } + + return false; +} + + +void +ThreadHandler::_HandleBreakpointConditionEvaluated(Value* value) +{ + fConditionResult = value; + if (fConditionResult != NULL) + fConditionResult->AcquireReference(); + release_sem(fConditionWaitSem); +} + + +bool ThreadHandler::_HasExitedFrame(target_addr_t framePointer) const { return fDebuggerInterface->GetArchitecture()->StackGrowthDirection() diff --git a/src/apps/debugger/controllers/ThreadHandler.h b/src/apps/debugger/controllers/ThreadHandler.h index eb80905..f29f539 100644 --- a/src/apps/debugger/controllers/ThreadHandler.h +++ b/src/apps/debugger/controllers/ThreadHandler.h @@ -21,6 +21,7 @@ class DebuggerInterface; class ImageDebugInfoJobListener; class StackFrame; class Statement; +class Value; class Worker; @@ -65,6 +66,9 @@ public: void HandleStackTraceChanged(); private: + friend class ExpressionJobListener; + +private: // ImageDebugInfoProvider virtual status_t GetImageDebugInfo(Image* image, ImageDebugInfo*& _info); @@ -95,6 +99,10 @@ private: void _SingleStepThread( target_addr_t instructionPointer); + bool _HandleBreakpointConditionIfNeeded( + CpuState* cpuState); + void _HandleBreakpointConditionEvaluated( + Value* value); bool _HandleBreakpointHitStep(CpuState* cpuState); bool _HandleSingleStepStep(CpuState* cpuState); @@ -115,6 +123,9 @@ private: target_addr_t fPreviousInstructionPointer; target_addr_t fPreviousFrameAddress; bool fSingleStepping; + bool fHasPendingConditionEvaluation; + sem_id fConditionWaitSem; + Value* fConditionResult; public: ThreadHandler* fNext;