xref: /haiku/src/apps/debugger/user_interface/gui/utility_windows/WatchPromptWindow.cpp (revision a3e794ae459fec76826407f8ba8c94cd3535f128)
1 /*
2  * Copyright 2012-2014, 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 "Architecture.h"
19 #include "CppLanguage.h"
20 #include "IntegerValue.h"
21 #include "MessageCodes.h"
22 #include "SyntheticPrimitiveType.h"
23 #include "UserInterface.h"
24 #include "Watchpoint.h"
25 
26 
27 WatchPromptWindow::WatchPromptWindow(Architecture* architecture,
28 	target_addr_t address, uint32 type, int32 length,
29 	UserInterfaceListener* listener)
30 	:
31 	BWindow(BRect(), "Edit Watchpoint", B_FLOATING_WINDOW,
32 		B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE),
33 	fInitialAddress(address),
34 	fInitialType(type),
35 	fInitialLength(length),
36 	fArchitecture(architecture),
37 	fRequestedAddress(0),
38 	fRequestedLength(0),
39 	fAddressInput(NULL),
40 	fLengthInput(NULL),
41 	fAddressExpressionInfo(NULL),
42 	fLengthExpressionInfo(NULL),
43 	fTypeField(NULL),
44 	fListener(listener),
45 	fLanguage(NULL)
46 {
47 	fArchitecture->AcquireReference();
48 }
49 
50 
51 WatchPromptWindow::~WatchPromptWindow()
52 {
53 	fArchitecture->ReleaseReference();
54 
55 	if (fLanguage != NULL)
56 		fLanguage->ReleaseReference();
57 
58 	if (fAddressExpressionInfo != NULL) {
59 		fAddressExpressionInfo->RemoveListener(this);
60 		fAddressExpressionInfo->ReleaseReference();
61 	}
62 
63 	if (fLengthExpressionInfo != NULL) {
64 		fLengthExpressionInfo->RemoveListener(this);
65 		fLengthExpressionInfo->ReleaseReference();
66 	}
67 }
68 
69 
70 WatchPromptWindow*
71 WatchPromptWindow::Create(Architecture* architecture, target_addr_t address,
72 	uint32 type, int32 length, UserInterfaceListener* listener)
73 {
74 	WatchPromptWindow* self = new WatchPromptWindow(architecture, address,
75 		type, length, listener);
76 
77 	try {
78 		self->_Init();
79 	} catch (...) {
80 		delete self;
81 		throw;
82 	}
83 
84 	return self;
85 
86 }
87 
88 
89 void
90 WatchPromptWindow::_Init()
91 {
92 	fLanguage = new CppLanguage();
93 
94 	BString text;
95 	text.SetToFormat("0x%" B_PRIx64, fInitialAddress);
96 	fAddressInput = new BTextControl("Address:", text, NULL);
97 	fAddressExpressionInfo = new ExpressionInfo(text);
98 	fAddressExpressionInfo->AddListener(this);
99 
100 	text.SetToFormat("%" B_PRId32, fInitialLength);
101 	fLengthInput = new BTextControl("Length:", text, NULL);
102 	fLengthExpressionInfo = new ExpressionInfo(text);
103 	fLengthExpressionInfo->AddListener(this);
104 
105 	int32 maxDebugRegisters = 0;
106 	int32 maxBytesPerRegister = 0;
107 	uint8 debugCapabilityFlags = 0;
108 	fArchitecture->GetWatchpointDebugCapabilities(maxDebugRegisters,
109 		maxBytesPerRegister, debugCapabilityFlags);
110 
111 	BMenu* typeMenu = new BMenu("Watch type");
112 
113 	BMenuItem* watchTypeItem = new BMenuItem("Read", NULL);
114 	watchTypeItem->SetEnabled(
115 		(debugCapabilityFlags & WATCHPOINT_CAPABILITY_FLAG_READ) != 0);
116 	typeMenu->AddItem(watchTypeItem);
117 
118 	watchTypeItem = new BMenuItem("Write", NULL);
119 	watchTypeItem->SetEnabled(
120 		(debugCapabilityFlags & WATCHPOINT_CAPABILITY_FLAG_WRITE) != 0);
121 	typeMenu->AddItem(watchTypeItem);
122 
123 	watchTypeItem = new BMenuItem("Read/Write", NULL);
124 	watchTypeItem->SetEnabled(
125 		(debugCapabilityFlags & WATCHPOINT_CAPABILITY_FLAG_READ_WRITE) != 0);
126 	typeMenu->AddItem(watchTypeItem);
127 
128 	fTypeField = new BMenuField("Type:", typeMenu);
129 	BLayoutItem* labelItem = fTypeField->CreateLabelLayoutItem();
130 	labelItem->View()->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
131 	BLayoutBuilder::Group<>(this, B_VERTICAL)
132 		.SetInsets(B_USE_DEFAULT_SPACING)
133 		.AddGroup(B_HORIZONTAL, 4.0f)
134 			.Add(fAddressInput)
135 		.End()
136 		.AddGroup(B_HORIZONTAL, 4.0f)
137 			.Add(fLengthInput)
138 			.Add(labelItem)
139 			.Add(fTypeField->CreateMenuBarLayoutItem())
140 		.End()
141 		.AddGroup(B_HORIZONTAL, 4.0f)
142 			.AddGlue()
143 			.Add((fWatchButton = new BButton("Set",
144 					new BMessage(MSG_SET_WATCHPOINT))))
145 			.Add((fCancelButton = new BButton("Cancel",
146 					new BMessage(B_QUIT_REQUESTED))))
147 		.End();
148 
149 	fWatchButton->SetTarget(this);
150 	fCancelButton->SetTarget(this);
151 
152 	fTypeField->Menu()->SetLabelFromMarked(true);
153 	fTypeField->Menu()->ItemAt(fInitialType)->SetMarked(true);
154 }
155 
156 
157 void
158 WatchPromptWindow::Show()
159 {
160 	CenterOnScreen();
161 	BWindow::Show();
162 }
163 
164 
165 void
166 WatchPromptWindow::ExpressionEvaluated(ExpressionInfo* info, status_t result,
167 	ExpressionResult* value)
168 {
169 	BMessage message(MSG_EXPRESSION_EVALUATED);
170 	message.AddInt32("result", result);
171 	message.AddPointer("info", info);
172 	BReference<ExpressionResult> reference;
173 	if (value != NULL) {
174 		reference.SetTo(value);
175 		message.AddPointer("value", value);
176 	}
177 
178 	if (PostMessage(&message) == B_OK)
179 		reference.Detach();
180 }
181 
182 
183 void
184 WatchPromptWindow::MessageReceived(BMessage* message)
185 {
186 	switch (message->what) {
187 		case MSG_EXPRESSION_EVALUATED:
188 		{
189 			BString errorMessage;
190 			BReference<ExpressionResult> reference;
191 			ExpressionResult* value = NULL;
192 			ExpressionInfo* info = NULL;
193 			if (message->FindPointer("info",
194 					reinterpret_cast<void**>(&info)) != B_OK) {
195 				break;
196 			}
197 
198 			if (message->FindPointer("value",
199 					reinterpret_cast<void**>(&value)) == B_OK) {
200 				reference.SetTo(value, true);
201 				if (value->Kind() == EXPRESSION_RESULT_KIND_PRIMITIVE) {
202 					Value* primitive = value->PrimitiveValue();
203 					if (dynamic_cast<IntegerValue*>(primitive) != NULL) {
204 						BVariant resultVariant;
205 						primitive->ToVariant(resultVariant);
206 						if (info == fAddressExpressionInfo) {
207 							fRequestedAddress = resultVariant.ToUInt64();
208 							break;
209 						} else
210 							fRequestedLength = resultVariant.ToInt32();
211 					}
212 					else
213 						primitive->ToString(errorMessage);
214 				} else
215 					errorMessage.SetTo("Unsupported expression result.");
216 			} else {
217 				status_t result = message->FindInt32("result");
218 				errorMessage.SetToFormat("Failed to evaluate expression: %s",
219 					strerror(result));
220 			}
221 
222 			if (fRequestedLength <= 0)
223 				errorMessage = "Watchpoint length must be at least 1 byte.";
224 
225 			if (!errorMessage.IsEmpty()) {
226 				BAlert* alert = new(std::nothrow) BAlert("Edit Watchpoint",
227 					errorMessage.String(), "Close");
228 				if (alert != NULL)
229 					alert->Go();
230 				break;
231 			}
232 
233 			fListener->ClearWatchpointRequested(fInitialAddress);
234 			fListener->SetWatchpointRequested(fRequestedAddress,
235 				fTypeField->Menu()->IndexOf(fTypeField->Menu()->FindMarked()),
236 				fRequestedLength, true);
237 
238 			PostMessage(B_QUIT_REQUESTED);
239 			break;
240 		}
241 
242 		case MSG_SET_WATCHPOINT:
243 		{
244 			fRequestedAddress = 0;
245 			fRequestedLength = 0;
246 
247 			fAddressExpressionInfo->SetTo(fAddressInput->Text());
248 			fListener->ExpressionEvaluationRequested(fLanguage,
249 				fAddressExpressionInfo);
250 
251 			fLengthExpressionInfo->SetTo(fLengthInput->Text());
252 			fListener->ExpressionEvaluationRequested(fLanguage,
253 				fLengthExpressionInfo);
254 			break;
255 		}
256 
257 		default:
258 			BWindow::MessageReceived(message);
259 			break;
260 	}
261 
262 }
263