Add UI hooks for watchpoints.

This gets basic watchpoint support working. Right clicking on a variable
and picking Watch now opens a prompt with the inferred address, size
and watch type for the user to adjust.

Still needs some work to get them to show/be modifiable in the breakpoints
tab and to get them to respect architectural restrictions (i.e. on x86 we
can realistically only do 2 hardware watchpoints and those are restricted
to write watch), at least until we support software emulated watchpoints.
This commit is contained in:
Rene Gollent
2012-11-06 20:57:15 +01:00
parent 1cd0e20c56
commit 2a2e3bafa2
7 changed files with 287 additions and 21 deletions
+1
View File
@@ -211,6 +211,7 @@ Application Debugger :
TeamWindow.cpp
ThreadListView.cpp
VariablesView.cpp
WatchPromptWindow.cpp
# user_interface/gui/util
ActionMenuItem.cpp
+2 -1
View File
@@ -53,7 +53,8 @@ enum {
MSG_INSPECTOR_WINDOW_CLOSED = 'irwc',
MSG_INSPECT_ADDRESS = 'isad',
MSG_SHOW_TYPECAST_NODE_PROMPT = 'stnp',
MSG_TYPECAST_NODE = 'tyno'
MSG_TYPECAST_NODE = 'tyno',
MSG_SHOW_WATCH_VARIABLE_PROMPT = 'swvp'
};
@@ -44,6 +44,7 @@
#include "TypeComponentPath.h"
#include "UserInterface.h"
#include "Variable.h"
#include "WatchPromptWindow.h"
enum {
@@ -247,6 +248,27 @@ TeamWindow::MessageReceived(BMessage* message)
break;
}
case MSG_SHOW_WATCH_VARIABLE_PROMPT:
{
target_addr_t address;
uint32 type;
int32 length;
if (message->FindUInt64("address", &address) != B_OK
|| message->FindUInt32("type", &type) != B_OK
|| message->FindInt32("length", &length) != B_OK) {
break;
}
try {
WatchPromptWindow* window = WatchPromptWindow::Create(address,
type, length, fListener);
window->Show();
} catch (...) {
// TODO: notify user
}
break;
}
case B_REFS_RECEIVED:
{
entry_ref locatedPath;
@@ -11,6 +11,8 @@
#include <new>
#include <debugger.h>
#include <Looper.h>
#include <PopUpMenu.h>
#include <ToolTip.h>
@@ -1684,6 +1686,22 @@ VariablesView::MessageReceived(BMessage* message)
node->NodeChild()->SetNode(valueNode);
break;
}
case MSG_SHOW_WATCH_VARIABLE_PROMPT:
{
ModelNode* node = reinterpret_cast<ModelNode*>(
fVariableTable->SelectionModel()->NodeAt(0));
ValueLocation* location = node->NodeChild()->Location();
ValuePieceLocation piece = location->PieceAt(0);
if (piece.type != VALUE_PIECE_LOCATION_MEMORY)
break;
BMessage looperMessage(*message);
looperMessage.AddUInt64("address", piece.address);
looperMessage.AddInt32("length", piece.size);
looperMessage.AddUInt32("type", B_DATA_READ_WRITE_WATCHPOINT);
Looper()->PostMessage(&looperMessage);
break;
}
case MSG_VALUE_NODE_CHANGED:
{
ValueNodeChild* nodeChild;
@@ -1977,34 +1995,45 @@ VariablesView::_GetContextActionsForNode(ModelNode* node,
if (location->PieceAt(0).type != VALUE_PIECE_LOCATION_MEMORY)
return B_OK;
BMessage* message = new BMessage(MSG_SHOW_INSPECTOR_WINDOW);
if (message == NULL)
return B_NO_MEMORY;
BMessage* message = NULL;
status_t result = _AddContextAction("Inspect", MSG_SHOW_INSPECTOR_WINDOW,
actions, message);
if (result != B_OK)
return result;
ObjectDeleter<BMessage> messageDeleter(message);
message->AddUInt64("address", location->PieceAt(0).address);
ActionMenuItem* item = new(std::nothrow) ActionMenuItem("Inspect",
message);
result = _AddContextAction("Cast as" B_UTF8_ELLIPSIS,
MSG_SHOW_TYPECAST_NODE_PROMPT, actions, message);
if (result != B_OK)
return result;
result = _AddContextAction("Watch" B_UTF8_ELLIPSIS,
MSG_SHOW_WATCH_VARIABLE_PROMPT, actions, message);
if (result != B_OK)
return result;
return B_OK;
}
status_t
VariablesView::_AddContextAction(const char* action, uint32 what,
ContextActionList* actions, BMessage*& _message)
{
_message = new BMessage(what);
if (_message == NULL)
return B_NO_MEMORY;
ObjectDeleter<BMessage> messageDeleter(_message);
ActionMenuItem* item = new(std::nothrow) ActionMenuItem(action,
_message);
if (item == NULL)
return B_NO_MEMORY;
messageDeleter.Detach();
ObjectDeleter<ActionMenuItem> actionDeleter(item);
if (!actions->AddItem(item))
return B_NO_MEMORY;
message = new(std::nothrow)BMessage(MSG_SHOW_TYPECAST_NODE_PROMPT);
if (message == NULL)
return B_NO_MEMORY;
item = new(std::nothrow) ActionMenuItem("Cast as" B_UTF8_ELLIPSIS,
message);
if (item == NULL)
return B_NO_MEMORY;
messageDeleter.Detach();
if (!actions->AddItem(item))
return B_NO_MEMORY;
@@ -72,6 +72,9 @@ private:
void _RequestNodeValue(ModelNode* node);
status_t _GetContextActionsForNode(ModelNode* node,
ContextActionList* actions);
status_t _AddContextAction(const char* action,
uint32 what, ContextActionList* actions,
BMessage*& _message);
void _FinishContextMenu(bool force);
void _SaveViewState() const;
void _RestoreViewState();
@@ -0,0 +1,154 @@
/*
* Copyright 2012, Rene Gollent, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "WatchPromptWindow.h"
#include <Alert.h>
#include <Button.h>
#include <LayoutBuilder.h>
#include <Menu.h>
#include <MenuField.h>
#include <MenuItem.h>
#include <String.h>
#include <TextControl.h>
#include <ExpressionParser.h>
#include "MessageCodes.h"
#include "UserInterface.h"
#include "Watchpoint.h"
WatchPromptWindow::WatchPromptWindow(target_addr_t address, uint32 type,
int32 length, UserInterfaceListener* listener)
:
BWindow(BRect(), "Edit Watchpoint", B_FLOATING_WINDOW,
B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE),
fInitialAddress(address),
fInitialType(type),
fInitialLength(length),
fAddressInput(NULL),
fLengthInput(NULL),
fTypeField(NULL),
fListener(listener)
{
}
WatchPromptWindow::~WatchPromptWindow()
{
}
WatchPromptWindow*
WatchPromptWindow::Create(target_addr_t address, uint32 type, int32 length,
UserInterfaceListener* listener)
{
WatchPromptWindow* self = new WatchPromptWindow(address, type, length,
listener);
try {
self->_Init();
} catch (...) {
delete self;
throw;
}
return self;
}
void
WatchPromptWindow::_Init()
{
BString text;
text.SetToFormat("0x%" B_PRIx64, fInitialAddress);
fAddressInput = new BTextControl("Address:", text, NULL);
text.SetToFormat("%" B_PRId32, fInitialLength);
fLengthInput = new BTextControl("Length:", text, NULL);
BMenu* typeMenu = new BMenu("Watch Type");
typeMenu->AddItem(new BMenuItem("Read", NULL));
typeMenu->AddItem(new BMenuItem("Write", NULL));
typeMenu->AddItem(new BMenuItem("Read/Write", NULL));
fTypeField = new BMenuField("Type:", typeMenu);
BLayoutItem* labelItem = fTypeField->CreateLabelLayoutItem();
labelItem->View()->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
BLayoutBuilder::Group<>(this, B_VERTICAL)
.SetInsets(4.0f, 4.0f, 4.0f, 4.0f)
.AddGroup(B_HORIZONTAL, 4.0f)
.Add(fAddressInput)
.End()
.AddGroup(B_HORIZONTAL, 4.0f)
.Add(fLengthInput)
.Add(labelItem)
.Add(fTypeField->CreateMenuBarLayoutItem())
.End()
.AddGroup(B_HORIZONTAL, 4.0f)
.AddGlue()
.Add((fWatchButton = new BButton("Set",
new BMessage(MSG_SET_WATCHPOINT))))
.Add((fCancelButton = new BButton("Cancel",
new BMessage(B_QUIT_REQUESTED))))
.End();
fWatchButton->SetTarget(this);
fCancelButton->SetTarget(this);
fTypeField->Menu()->SetLabelFromMarked(true);
fTypeField->Menu()->ItemAt(fInitialType)->SetMarked(true);
}
void
WatchPromptWindow::Show()
{
CenterOnScreen();
BWindow::Show();
}
void
WatchPromptWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_SET_WATCHPOINT:
{
target_addr_t address;
int32 length;
ExpressionParser parser;
parser.SetSupportHexInput(true);
BString errorMessage;
try {
address = parser.EvaluateToInt64(fAddressInput->Text());
length = (int32)parser.EvaluateToInt64(fLengthInput->Text());
} catch(ParseException parseError) {
errorMessage.SetToFormat("Failed to parse data: %s",
parseError.message.String());
} catch(...) {
errorMessage.SetToFormat(
"Unknown error while parsing address");
}
if (!errorMessage.IsEmpty()) {
BAlert* alert = new(std::nothrow) BAlert("Edit Watchpoint",
errorMessage.String(), "Close");
if (alert != NULL)
alert->Go();
break;
}
fListener->ClearWatchpointRequested(fInitialAddress);
fListener->SetWatchpointRequested(address, fTypeField->Menu()
->IndexOf(fTypeField->Menu()->FindMarked()), length, true);
PostMessage(B_QUIT_REQUESTED);
break;
}
default:
BWindow::MessageReceived(message);
break;
}
}
@@ -0,0 +1,56 @@
/*
* Copyright 2012, Rene Gollent, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef WATCH_PROMPT_WINDOW_H
#define WATCH_PROMPT_WINDOW_H
#include <Window.h>
#include "types/Types.h"
class BTextControl;
class Watchpoint;
class BMenuField;
class UserInterfaceListener;
class WatchPromptWindow : public BWindow
{
public:
// edit existing watchpoint
WatchPromptWindow(target_addr_t address,
uint32 type, int32 length,
UserInterfaceListener* listener);
~WatchPromptWindow();
static WatchPromptWindow* Create(target_addr_t address, uint32 type,
int32 length,
UserInterfaceListener* listener);
// throws
virtual void MessageReceived(BMessage* message);
virtual void Show();
private:
void _Init();
private:
target_addr_t fInitialAddress;
uint32 fInitialType;
int32 fInitialLength;
BTextControl* fAddressInput;
BTextControl* fLengthInput;
BMenuField* fTypeField;
UserInterfaceListener* fListener;
BButton* fWatchButton;
BButton* fCancelButton;
};
#endif // WATCH_PROMPT_WINDOW_H