xref: /haiku/src/apps/debugger/user_interface/gui/utility_windows/WatchPromptWindow.cpp (revision 10ba334855ad0d7297e23f15dea292f7dbdd231c)
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