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