vfs: check userland buffers before reading them.
[haiku.git] / src / apps / debugger / user_interface / gui / utility_windows / WatchPromptWindow.cpp
blobde15fbd47b34701c9d88e7b8b0c1adc8bd962977
1 /*
2 * Copyright 2012-2016, Rene Gollent, rene@gollent.com.
3 * Distributed under the terms of the MIT License.
4 */
5 #include "WatchPromptWindow.h"
7 #include <Alert.h>
8 #include <Button.h>
9 #include <LayoutBuilder.h>
10 #include <Menu.h>
11 #include <MenuField.h>
12 #include <MenuItem.h>
13 #include <String.h>
14 #include <TextControl.h>
16 #include "AutoLocker.h"
18 #include "AppMessageCodes.h"
19 #include "Architecture.h"
20 #include "CppLanguage.h"
21 #include "IntegerValue.h"
22 #include "MessageCodes.h"
23 #include "SyntheticPrimitiveType.h"
24 #include "UserInterface.h"
25 #include "Watchpoint.h"
28 WatchPromptWindow::WatchPromptWindow(Architecture* architecture,
29 target_addr_t address, uint32 type, int32 length,
30 UserInterfaceListener* listener)
32 BWindow(BRect(), "Edit Watchpoint", B_FLOATING_WINDOW,
33 B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE),
34 fInitialAddress(address),
35 fInitialType(type),
36 fInitialLength(length),
37 fArchitecture(architecture),
38 fRequestedAddress(0),
39 fRequestedLength(0),
40 fAddressInput(NULL),
41 fLengthInput(NULL),
42 fAddressExpressionInfo(NULL),
43 fLengthExpressionInfo(NULL),
44 fTypeField(NULL),
45 fListener(listener),
46 fLanguage(NULL)
48 fArchitecture->AcquireReference();
52 WatchPromptWindow::~WatchPromptWindow()
54 fArchitecture->ReleaseReference();
56 if (fLanguage != NULL)
57 fLanguage->ReleaseReference();
59 if (fAddressExpressionInfo != NULL) {
60 fAddressExpressionInfo->RemoveListener(this);
61 fAddressExpressionInfo->ReleaseReference();
64 if (fLengthExpressionInfo != NULL) {
65 fLengthExpressionInfo->RemoveListener(this);
66 fLengthExpressionInfo->ReleaseReference();
71 WatchPromptWindow*
72 WatchPromptWindow::Create(Architecture* architecture, target_addr_t address,
73 uint32 type, int32 length, UserInterfaceListener* listener)
75 WatchPromptWindow* self = new WatchPromptWindow(architecture, address,
76 type, length, listener);
78 try {
79 self->_Init();
80 } catch (...) {
81 delete self;
82 throw;
85 return self;
90 void
91 WatchPromptWindow::_Init()
93 fLanguage = new CppLanguage();
95 BString text;
96 text.SetToFormat("0x%" B_PRIx64, fInitialAddress);
97 fAddressInput = new BTextControl("Address:", text, NULL);
98 fAddressExpressionInfo = new ExpressionInfo(text);
99 fAddressExpressionInfo->AddListener(this);
101 text.SetToFormat("%" B_PRId32, fInitialLength);
102 fLengthInput = new BTextControl("Length:", text, NULL);
103 fLengthExpressionInfo = new ExpressionInfo(text);
104 fLengthExpressionInfo->AddListener(this);
106 int32 maxDebugRegisters = 0;
107 int32 maxBytesPerRegister = 0;
108 uint8 debugCapabilityFlags = 0;
109 fArchitecture->GetWatchpointDebugCapabilities(maxDebugRegisters,
110 maxBytesPerRegister, debugCapabilityFlags);
112 BMenu* typeMenu = new BMenu("Watch type");
114 BMenuItem* watchTypeItem = new BMenuItem("Read", NULL);
115 watchTypeItem->SetEnabled(
116 (debugCapabilityFlags & WATCHPOINT_CAPABILITY_FLAG_READ) != 0);
117 typeMenu->AddItem(watchTypeItem);
119 watchTypeItem = new BMenuItem("Write", NULL);
120 watchTypeItem->SetEnabled(
121 (debugCapabilityFlags & WATCHPOINT_CAPABILITY_FLAG_WRITE) != 0);
122 typeMenu->AddItem(watchTypeItem);
124 watchTypeItem = new BMenuItem("Read/Write", NULL);
125 watchTypeItem->SetEnabled(
126 (debugCapabilityFlags & WATCHPOINT_CAPABILITY_FLAG_READ_WRITE) != 0);
127 typeMenu->AddItem(watchTypeItem);
129 fTypeField = new BMenuField("Type:", typeMenu);
130 BLayoutItem* labelItem = fTypeField->CreateLabelLayoutItem();
131 labelItem->View()->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
132 BLayoutBuilder::Group<>(this, B_VERTICAL)
133 .SetInsets(B_USE_DEFAULT_SPACING)
134 .AddGroup(B_HORIZONTAL, 4.0f)
135 .Add(fAddressInput)
136 .End()
137 .AddGroup(B_HORIZONTAL, 4.0f)
138 .Add(fLengthInput)
139 .Add(labelItem)
140 .Add(fTypeField->CreateMenuBarLayoutItem())
141 .End()
142 .AddGroup(B_HORIZONTAL, 4.0f)
143 .AddGlue()
144 .Add((fWatchButton = new BButton("Set",
145 new BMessage(MSG_SET_WATCHPOINT))))
146 .Add((fCancelButton = new BButton("Cancel",
147 new BMessage(B_QUIT_REQUESTED))))
148 .End();
150 fWatchButton->SetTarget(this);
151 fCancelButton->SetTarget(this);
153 fTypeField->Menu()->SetLabelFromMarked(true);
154 fTypeField->Menu()->ItemAt(fInitialType)->SetMarked(true);
158 void
159 WatchPromptWindow::Show()
161 CenterOnScreen();
162 BWindow::Show();
166 void
167 WatchPromptWindow::ExpressionEvaluated(ExpressionInfo* info, status_t result,
168 ExpressionResult* value)
170 BMessage message(MSG_EXPRESSION_EVALUATED);
171 message.AddInt32("result", result);
172 message.AddPointer("info", info);
173 BReference<ExpressionResult> reference;
174 if (value != NULL) {
175 reference.SetTo(value);
176 message.AddPointer("value", value);
179 if (PostMessage(&message) == B_OK)
180 reference.Detach();
184 void
185 WatchPromptWindow::MessageReceived(BMessage* message)
187 switch (message->what) {
188 case MSG_EXPRESSION_EVALUATED:
190 BString errorMessage;
191 BReference<ExpressionResult> reference;
192 ExpressionResult* value = NULL;
193 ExpressionInfo* info = NULL;
194 if (message->FindPointer("info",
195 reinterpret_cast<void**>(&info)) != B_OK) {
196 break;
199 if (message->FindPointer("value",
200 reinterpret_cast<void**>(&value)) == B_OK) {
201 reference.SetTo(value, true);
202 if (value->Kind() == EXPRESSION_RESULT_KIND_PRIMITIVE) {
203 Value* primitive = value->PrimitiveValue();
204 if (dynamic_cast<IntegerValue*>(primitive) != NULL) {
205 BVariant resultVariant;
206 primitive->ToVariant(resultVariant);
207 if (info == fAddressExpressionInfo) {
208 fRequestedAddress = resultVariant.ToUInt64();
209 break;
210 } else
211 fRequestedLength = resultVariant.ToInt32();
213 else
214 primitive->ToString(errorMessage);
215 } else
216 errorMessage.SetTo("Unsupported expression result.");
217 } else {
218 status_t result = message->FindInt32("result");
219 errorMessage.SetToFormat("Failed to evaluate expression: %s",
220 strerror(result));
223 if (fRequestedLength <= 0)
224 errorMessage = "Watchpoint length must be at least 1 byte.";
226 if (!errorMessage.IsEmpty()) {
227 BAlert* alert = new(std::nothrow) BAlert("Edit Watchpoint",
228 errorMessage.String(), "Close");
229 if (alert != NULL)
230 alert->Go();
231 break;
234 fListener->ClearWatchpointRequested(fInitialAddress);
235 fListener->SetWatchpointRequested(fRequestedAddress,
236 fTypeField->Menu()->IndexOf(fTypeField->Menu()->FindMarked()),
237 fRequestedLength, true);
239 PostMessage(B_QUIT_REQUESTED);
240 break;
243 case MSG_SET_WATCHPOINT:
245 fRequestedAddress = 0;
246 fRequestedLength = 0;
248 fAddressExpressionInfo->SetTo(fAddressInput->Text());
249 fListener->ExpressionEvaluationRequested(fLanguage,
250 fAddressExpressionInfo);
252 fLengthExpressionInfo->SetTo(fLengthInput->Text());
253 fListener->ExpressionEvaluationRequested(fLanguage,
254 fLengthExpressionInfo);
255 break;
258 default:
259 BWindow::MessageReceived(message);
260 break;