1 /*
2 * Copyright 2012-2016, Rene Gollent, rene@gollent.com.
3 * Distributed under the terms of the MIT License.
4 */
5 #include "WatchPromptWindow.h"
6
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>
15
16 #include "AutoLocker.h"
17
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"
26
27
WatchPromptWindow(Architecture * architecture,target_addr_t address,uint32 type,int32 length,UserInterfaceListener * listener)28 WatchPromptWindow::WatchPromptWindow(Architecture* architecture,
29 target_addr_t address, uint32 type, int32 length,
30 UserInterfaceListener* listener)
31 :
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)
47 {
48 fArchitecture->AcquireReference();
49 }
50
51
~WatchPromptWindow()52 WatchPromptWindow::~WatchPromptWindow()
53 {
54 fArchitecture->ReleaseReference();
55
56 if (fLanguage != NULL)
57 fLanguage->ReleaseReference();
58
59 if (fAddressExpressionInfo != NULL) {
60 fAddressExpressionInfo->RemoveListener(this);
61 fAddressExpressionInfo->ReleaseReference();
62 }
63
64 if (fLengthExpressionInfo != NULL) {
65 fLengthExpressionInfo->RemoveListener(this);
66 fLengthExpressionInfo->ReleaseReference();
67 }
68 }
69
70
71 WatchPromptWindow*
Create(Architecture * architecture,target_addr_t address,uint32 type,int32 length,UserInterfaceListener * listener)72 WatchPromptWindow::Create(Architecture* architecture, target_addr_t address,
73 uint32 type, int32 length, UserInterfaceListener* listener)
74 {
75 WatchPromptWindow* self = new WatchPromptWindow(architecture, address,
76 type, length, listener);
77
78 try {
79 self->_Init();
80 } catch (...) {
81 delete self;
82 throw;
83 }
84
85 return self;
86
87 }
88
89
90 void
_Init()91 WatchPromptWindow::_Init()
92 {
93 fLanguage = new CppLanguage();
94
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);
100
101 text.SetToFormat("%" B_PRId32, fInitialLength);
102 fLengthInput = new BTextControl("Length:", text, NULL);
103 fLengthExpressionInfo = new ExpressionInfo(text);
104 fLengthExpressionInfo->AddListener(this);
105
106 int32 maxDebugRegisters = 0;
107 int32 maxBytesPerRegister = 0;
108 uint8 debugCapabilityFlags = 0;
109 fArchitecture->GetWatchpointDebugCapabilities(maxDebugRegisters,
110 maxBytesPerRegister, debugCapabilityFlags);
111
112 BMenu* typeMenu = new BMenu("Watch type");
113
114 BMenuItem* watchTypeItem = new BMenuItem("Read", NULL);
115 watchTypeItem->SetEnabled(
116 (debugCapabilityFlags & WATCHPOINT_CAPABILITY_FLAG_READ) != 0);
117 typeMenu->AddItem(watchTypeItem);
118
119 watchTypeItem = new BMenuItem("Write", NULL);
120 watchTypeItem->SetEnabled(
121 (debugCapabilityFlags & WATCHPOINT_CAPABILITY_FLAG_WRITE) != 0);
122 typeMenu->AddItem(watchTypeItem);
123
124 watchTypeItem = new BMenuItem("Read/Write", NULL);
125 watchTypeItem->SetEnabled(
126 (debugCapabilityFlags & WATCHPOINT_CAPABILITY_FLAG_READ_WRITE) != 0);
127 typeMenu->AddItem(watchTypeItem);
128
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();
149
150 fWatchButton->SetTarget(this);
151 fCancelButton->SetTarget(this);
152
153 fTypeField->Menu()->SetLabelFromMarked(true);
154 fTypeField->Menu()->ItemAt(fInitialType)->SetMarked(true);
155 }
156
157
158 void
Show()159 WatchPromptWindow::Show()
160 {
161 CenterOnScreen();
162 BWindow::Show();
163 }
164
165
166 void
ExpressionEvaluated(ExpressionInfo * info,status_t result,ExpressionResult * value)167 WatchPromptWindow::ExpressionEvaluated(ExpressionInfo* info, status_t result,
168 ExpressionResult* value)
169 {
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);
177 }
178
179 if (PostMessage(&message) == B_OK)
180 reference.Detach();
181 }
182
183
184 void
MessageReceived(BMessage * message)185 WatchPromptWindow::MessageReceived(BMessage* message)
186 {
187 switch (message->what) {
188 case MSG_EXPRESSION_EVALUATED:
189 {
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;
197 }
198
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();
212 }
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));
221 }
222
223 if (fRequestedLength <= 0)
224 errorMessage = "Watchpoint length must be at least 1 byte.";
225
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;
232 }
233
234 fListener->ClearWatchpointRequested(fInitialAddress);
235 fListener->SetWatchpointRequested(fRequestedAddress,
236 fTypeField->Menu()->IndexOf(fTypeField->Menu()->FindMarked()),
237 fRequestedLength, true);
238
239 PostMessage(B_QUIT_REQUESTED);
240 break;
241 }
242
243 case MSG_SET_WATCHPOINT:
244 {
245 fRequestedAddress = 0;
246 fRequestedLength = 0;
247
248 fAddressExpressionInfo->SetTo(fAddressInput->Text());
249 fListener->ExpressionEvaluationRequested(fLanguage,
250 fAddressExpressionInfo);
251
252 fLengthExpressionInfo->SetTo(fLengthInput->Text());
253 fListener->ExpressionEvaluationRequested(fLanguage,
254 fLengthExpressionInfo);
255 break;
256 }
257
258 default:
259 BWindow::MessageReceived(message);
260 break;
261 }
262
263 }
264