xref: /haiku/src/apps/debugger/user_interface/gui/team_window/RegistersView.cpp (revision 2710b4f5d4251c5cf88c82b0114ea99b0ef46d22)
1 /*
2  * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2011-2016, Rene Gollent, rene@gollent.com.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 #include "RegistersView.h"
8 
9 #include <stdio.h>
10 
11 #include <new>
12 
13 #include <ControlLook.h>
14 #include <MenuItem.h>
15 #include <PopUpMenu.h>
16 #include <Window.h>
17 
18 #include "table/TableColumns.h"
19 
20 #include "AppMessageCodes.h"
21 #include "Architecture.h"
22 #include "AutoDeleter.h"
23 #include "CpuState.h"
24 #include "GuiSettingsUtils.h"
25 #include "Register.h"
26 #include "UiUtils.h"
27 
28 
29 enum {
30 	MSG_SIMD_RENDER_FORMAT_CHANGED = 'srfc'
31 };
32 
33 
34 static const char*
GetLabelForSIMDFormat(int format)35 GetLabelForSIMDFormat(int format)
36 {
37 	switch (format) {
38 			case SIMD_RENDER_FORMAT_INT8:
39 				return "8-bit integer";
40 			case SIMD_RENDER_FORMAT_INT16:
41 				return "16-bit integer";
42 			case SIMD_RENDER_FORMAT_INT32:
43 				return "32-bit integer";
44 			case SIMD_RENDER_FORMAT_INT64:
45 				return "64-bit integer";
46 			case SIMD_RENDER_FORMAT_FLOAT:
47 				return "Float";
48 			case SIMD_RENDER_FORMAT_DOUBLE:
49 				return "Double";
50 	}
51 
52 	return "Unknown";
53 }
54 
55 
56 // #pragma mark - RegisterValueColumn
57 
58 
59 class RegistersView::RegisterValueColumn : public StringTableColumn {
60 public:
RegisterValueColumn(int32 modelIndex,const char * title,float width,float minWidth,float maxWidth,uint32 truncate=B_TRUNCATE_MIDDLE,alignment align=B_ALIGN_RIGHT)61 	RegisterValueColumn(int32 modelIndex, const char* title, float width,
62 		float minWidth, float maxWidth, uint32 truncate = B_TRUNCATE_MIDDLE,
63 		alignment align = B_ALIGN_RIGHT)
64 		:
65 		StringTableColumn(modelIndex, title, width, minWidth, maxWidth,
66 			truncate, align)
67 	{
68 	}
69 
70 protected:
PrepareField(const BVariant & value) const71 	virtual BField* PrepareField(const BVariant& value) const
72 	{
73 		char buffer[64];
74 		return StringTableColumn::PrepareField(
75 			BVariant(UiUtils::VariantToString(value, buffer, sizeof(buffer)),
76 				B_VARIANT_DONT_COPY_DATA));
77 	}
78 
CompareValues(const BVariant & a,const BVariant & b)79 	virtual int CompareValues(const BVariant& a, const BVariant& b)
80 	{
81 		// If neither value is a number, compare the strings. If only one value
82 		// is a number, it is considered to be greater.
83 		if (!a.IsNumber()) {
84 			if (b.IsNumber())
85 				return -1;
86 			char bufferA[64];
87 			char bufferB[64];
88 			return StringTableColumn::CompareValues(
89 				BVariant(UiUtils::VariantToString(a, bufferA,
90 						sizeof(bufferA)),
91 					B_VARIANT_DONT_COPY_DATA),
92 				BVariant(UiUtils::VariantToString(b, bufferB,
93 						sizeof(bufferB)),
94 					B_VARIANT_DONT_COPY_DATA));
95 		}
96 
97 		if (!b.IsNumber())
98 			return 1;
99 
100 		// If either value is floating point, we compare floating point values.
101 		if (a.IsFloat() || b.IsFloat()) {
102 			double valueA = a.ToDouble();
103 			double valueB = b.ToDouble();
104 			return valueA < valueB ? -1 : (valueA == valueB ? 0 : 1);
105 		}
106 
107 		uint64 valueA = a.ToUInt64();
108 		uint64 valueB = b.ToUInt64();
109 		return valueA < valueB ? -1 : (valueA == valueB ? 0 : 1);
110 	}
111 };
112 
113 
114 // #pragma mark - RegisterTableModel
115 
116 
117 class RegistersView::RegisterTableModel : public TableModel {
118 public:
RegisterTableModel(Architecture * architecture)119 	RegisterTableModel(Architecture* architecture)
120 		:
121 		fArchitecture(architecture),
122 		fCpuState(NULL),
123 		fSIMDFormat(SIMD_RENDER_FORMAT_INT16)
124 	{
125 	}
126 
~RegisterTableModel()127 	~RegisterTableModel()
128 	{
129 	}
130 
SetCpuState(CpuState * cpuState)131 	void SetCpuState(CpuState* cpuState)
132 	{
133 		fCpuState = cpuState;
134 
135 		NotifyRowsChanged(0, CountRows());
136 	}
137 
CountColumns() const138 	virtual int32 CountColumns() const
139 	{
140 		return 2;
141 	}
142 
CountRows() const143 	virtual int32 CountRows() const
144 	{
145 		return fArchitecture->CountRegisters();
146 	}
147 
SIMDRenderFormat() const148 	inline int32 SIMDRenderFormat() const
149 	{
150 		return fSIMDFormat;
151 	}
152 
GetValueAt(int32 rowIndex,int32 columnIndex,BVariant & value)153 	virtual bool GetValueAt(int32 rowIndex, int32 columnIndex, BVariant& value)
154 	{
155 		if (rowIndex < 0 || rowIndex >= fArchitecture->CountRegisters())
156 			return false;
157 
158 		const Register* reg = fArchitecture->Registers() + rowIndex;
159 
160 		switch (columnIndex) {
161 			case 0:
162 				value.SetTo(reg->Name(), B_VARIANT_DONT_COPY_DATA);
163 				return true;
164 			case 1:
165 				if (fCpuState == NULL)
166 					return false;
167 				if (!fCpuState->GetRegisterValue(reg, value))
168 					value.SetTo("?", B_VARIANT_DONT_COPY_DATA);
169 				else if (reg->Format() == REGISTER_FORMAT_SIMD) {
170 					BString output;
171 					value.SetTo(UiUtils::FormatSIMDValue(value,
172 						reg->BitSize(),fSIMDFormat, output));
173 				}
174 				return true;
175 			default:
176 				return false;
177 		}
178 	}
179 
SetSIMDFormat(int32 format)180 	void SetSIMDFormat(int32 format)
181 	{
182 		if (fSIMDFormat != format) {
183 			fSIMDFormat = format;
184 			NotifyRowsChanged(0, CountRows());
185 		}
186 	}
187 
188 private:
189 private:
190 	Architecture*	fArchitecture;
191 	CpuState*		fCpuState;
192 	int32			fSIMDFormat;
193 };
194 
195 
196 // #pragma mark - RegistersView
197 
198 
RegistersView(Architecture * architecture)199 RegistersView::RegistersView(Architecture* architecture)
200 	:
201 	BGroupView(B_VERTICAL),
202 	fArchitecture(architecture),
203 	fCpuState(NULL),
204 	fRegisterTable(NULL),
205 	fRegisterTableModel(NULL)
206 {
207 	SetName("Registers");
208 }
209 
210 
~RegistersView()211 RegistersView::~RegistersView()
212 {
213 	SetCpuState(NULL);
214 	fRegisterTable->SetTableModel(NULL);
215 	delete fRegisterTableModel;
216 }
217 
218 
219 /*static*/ RegistersView*
Create(Architecture * architecture)220 RegistersView::Create(Architecture* architecture)
221 {
222 	RegistersView* self = new RegistersView(architecture);
223 
224 	try {
225 		self->_Init();
226 	} catch (...) {
227 		delete self;
228 		throw;
229 	}
230 
231 	return self;
232 }
233 
234 
235 void
MessageReceived(BMessage * message)236 RegistersView::MessageReceived(BMessage* message)
237 {
238 	switch (message->what) {
239 		case MSG_SIMD_RENDER_FORMAT_CHANGED:
240 			{
241 				int32 format;
242 				if (message->FindInt32("format", &format) != B_OK)
243 					break;
244 
245 				fRegisterTableModel->SetSIMDFormat(format);
246 			}
247 			break;
248 
249 		default:
250 			BGroupView::MessageReceived(message);
251 			break;
252 	}
253 }
254 
255 
256 void
SetCpuState(CpuState * cpuState)257 RegistersView::SetCpuState(CpuState* cpuState)
258 {
259 	if (cpuState == fCpuState)
260 		return;
261 
262 	if (fCpuState != NULL)
263 		fCpuState->ReleaseReference();
264 
265 	fCpuState = cpuState;
266 
267 	if (fCpuState != NULL)
268 		fCpuState->AcquireReference();
269 
270 	fRegisterTableModel->SetCpuState(fCpuState);
271 }
272 
273 
274 void
LoadSettings(const BMessage & settings)275 RegistersView::LoadSettings(const BMessage& settings)
276 {
277 	BMessage tableSettings;
278 	if (settings.FindMessage("registerTable", &tableSettings) == B_OK) {
279 		GuiSettingsUtils::UnarchiveTableSettings(tableSettings,
280 			fRegisterTable);
281 	}
282 }
283 
284 
285 status_t
SaveSettings(BMessage & settings)286 RegistersView::SaveSettings(BMessage& settings)
287 {
288 	settings.MakeEmpty();
289 
290 	BMessage tableSettings;
291 	status_t result = GuiSettingsUtils::ArchiveTableSettings(tableSettings,
292 		fRegisterTable);
293 	if (result == B_OK)
294 		result = settings.AddMessage("registerTable", &tableSettings);
295 
296 	return result;
297 }
298 
299 
300 void
TableRowInvoked(Table * table,int32 rowIndex)301 RegistersView::TableRowInvoked(Table* table, int32 rowIndex)
302 {
303 }
304 
305 
306 void
TableCellMouseDown(Table * table,int32 rowIndex,int32 columnIndex,BPoint screenWhere,uint32 buttons)307 RegistersView::TableCellMouseDown(Table* table, int32 rowIndex,
308 	int32 columnIndex, BPoint screenWhere,	uint32 buttons)
309 {
310 	if (rowIndex < 0 || rowIndex >= fArchitecture->CountRegisters())
311 		return;
312 
313 	if ((buttons & B_SECONDARY_MOUSE_BUTTON) == 0)
314 		return;
315 
316 	BVariant value;
317 	if (!fRegisterTableModel->GetValueAt(rowIndex, 1, value))
318 		return;
319 
320 	const Register* reg = fArchitecture->Registers() + rowIndex;
321 	if (reg->Format() == REGISTER_FORMAT_FLOAT) {
322 		// for floating point registers, we currently have no
323 		// context menu options to display.
324 		return;
325 	}
326 
327 	BPopUpMenu* menu = new(std::nothrow) BPopUpMenu("Options");
328 	if (menu == NULL)
329 		return;
330 
331 	ObjectDeleter<BPopUpMenu> menuDeleter(menu);
332 
333 	if (reg->Format() == REGISTER_FORMAT_INTEGER) {
334 		BMessage* message = new(std::nothrow) BMessage(MSG_SHOW_INSPECTOR_WINDOW);
335 		if (message == NULL)
336 			return;
337 
338 		message->AddUInt64("address", value.ToUInt64());
339 
340 		ObjectDeleter<BMessage> messageDeleter(message);
341 		BMenuItem* item = new(std::nothrow) BMenuItem("Inspect", message);
342 		if (item == NULL)
343 			return;
344 
345 		messageDeleter.Detach();
346 		ObjectDeleter<BMenuItem> itemDeleter(item);
347 		if (!menu->AddItem(item))
348 			return;
349 
350 		itemDeleter.Detach();
351 
352 		item->SetTarget(Window());
353 	} else if (reg->Format() == REGISTER_FORMAT_SIMD) {
354 		BMenu* formatMenu = new(std::nothrow) BMenu("Format");
355 		if (formatMenu == NULL)
356 			return;
357 
358 		ObjectDeleter<BMenu> formatMenuDeleter(formatMenu);
359 		if (!menu->AddItem(formatMenu))
360 			return;
361 		formatMenuDeleter.Detach();
362 
363 		if (_AddFormatItem(formatMenu, SIMD_RENDER_FORMAT_INT8) != B_OK)
364 			return;
365 		if (_AddFormatItem(formatMenu, SIMD_RENDER_FORMAT_INT16) != B_OK)
366 			return;
367 		if (_AddFormatItem(formatMenu, SIMD_RENDER_FORMAT_INT32) != B_OK)
368 			return;
369 		if (_AddFormatItem(formatMenu, SIMD_RENDER_FORMAT_INT64) != B_OK)
370 			return;
371 		if (_AddFormatItem(formatMenu, SIMD_RENDER_FORMAT_FLOAT) != B_OK)
372 			return;
373 		if (_AddFormatItem(formatMenu, SIMD_RENDER_FORMAT_DOUBLE) != B_OK)
374 			return;
375 
376 		formatMenu->SetTargetForItems(this);
377 	}
378 
379 	menuDeleter.Detach();
380 
381 	BRect mouseRect(screenWhere, screenWhere);
382 	mouseRect.InsetBy(-4.0, -4.0);
383 	menu->Go(screenWhere, true, false, mouseRect, true);
384 }
385 
386 
387 void
_Init()388 RegistersView::_Init()
389 {
390 	fRegisterTable = new Table("register list", 0, B_FANCY_BORDER);
391 	fRegisterTable->SetFont(B_FONT_ROW, be_fixed_font);
392 	AddChild(fRegisterTable->ToView());
393 
394 	// columns
395 	const float padding = be_control_look->DefaultLabelSpacing() * 2;
396 	fRegisterTable->AddColumn(new StringTableColumn(0, "Register",
397 		be_plain_font->StringWidth("Register") + padding, 40, 1000,
398 		B_TRUNCATE_END, B_ALIGN_LEFT));
399 	fRegisterTable->AddColumn(new RegisterValueColumn(1, "Value",
400 		be_fixed_font->StringWidth("0xffffffff00000000") + padding, 40, 1000,
401 		B_TRUNCATE_END, B_ALIGN_RIGHT));
402 
403 	fRegisterTableModel = new RegisterTableModel(fArchitecture);
404 	fRegisterTable->SetTableModel(fRegisterTableModel);
405 
406 	fRegisterTable->AddTableListener(this);
407 }
408 
409 
410 status_t
_AddFormatItem(BMenu * menu,int32 format)411 RegistersView::_AddFormatItem(BMenu* menu, int32 format)
412 {
413 	BMessage* message = new(std::nothrow) BMessage(
414 		MSG_SIMD_RENDER_FORMAT_CHANGED);
415 	if (message == NULL)
416 		return B_NO_MEMORY;
417 
418 	ObjectDeleter<BMessage> messageDeleter(message);
419 	if (message->AddInt32("format", format) != B_OK)
420 		return B_NO_MEMORY;
421 
422 	BMenuItem* item = new(std::nothrow) BMenuItem(
423 		GetLabelForSIMDFormat(format), message);
424 	if (item == NULL)
425 		return B_NO_MEMORY;
426 
427 	messageDeleter.Detach();
428 	ObjectDeleter<BMenuItem> itemDeleter(item);
429 	if (!menu->AddItem(item))
430 		return B_NO_MEMORY;
431 
432 	itemDeleter.Detach();
433 
434 	if (format == fRegisterTableModel->SIMDRenderFormat())
435 		item->SetMarked(true);
436 
437 	return B_OK;
438 }
439