Display the structure's members in the Local variables window
[clinton/Virtual-Jaguar-Rx.git] / src / debugger / localbrowser.cpp
1 //
2 // localbrowser.cpp - Local variables
3 //
4 // by Jean-Paul Mari
5 //
6 // JPM = Jean-Paul Mari <djipi.mari@gmail.com>
7 // RG = Richard Goedeken
8 //
9 // Who When What
10 // --- ---------- -----------------------------------------------------------
11 // JPM 11/03/2017 Created this file
12 // JPM Sept./2018 Added a status bar and better status report, and set information values in a tab
13 // RG Jan./2021 Linux build fixes
14 // JPM May/2021 Display the structure's members
15 //
16
17 // STILL TO DO:
18 // Feature to list the pointer(s) in the code using the allocation
19 // To set the information display at the right
20 // To support the array
21 // To support the union
22 // To support the static variables
23 // To add a filter
24 //
25
26 #include <stdlib.h>
27
28 #include "debugger/localbrowser.h"
29 #include "memory.h"
30 #include "debugger/DBGManager.h"
31 #include "settings.h"
32 #include "m68000/m68kinterface.h"
33
34
35 //
36 LocalBrowserWindow::LocalBrowserWindow(QWidget * parent/*= 0*/) : QWidget(parent, Qt::Dialog),
37 layout(new QVBoxLayout),
38 TableView(new QTreeView),
39 model(new QStandardItemModel),
40 NbLocal(0),
41 FuncName(NULL),
42 LocalInfo(NULL),
43 statusbar(new QStatusBar)
44 {
45 setWindowTitle(tr("Locals"));
46 #ifdef LOCAL_FONTS
47 // Set the font
48 QFont fixedFont("Lucida Console", 8, QFont::Normal);
49 fixedFont.setStyleHint(QFont::TypeWriter);
50 #endif
51 // Set the new layout with proper identation and readibility
52 model->setColumnCount(3);
53 model->setHeaderData(0, Qt::Horizontal, QObject::tr("Name"));
54 model->setHeaderData(1, Qt::Horizontal, QObject::tr("Value"));
55 model->setHeaderData(2, Qt::Horizontal, QObject::tr("Type"));
56 // Information table
57 TableView->setModel(model);
58 TableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
59 #ifdef LOCAL_FONTS
60 TableView->setFont(fixedFont);
61 #endif
62 layout->addWidget(TableView);
63
64 // Status bar
65 layout->addWidget(statusbar);
66 setLayout(layout);
67 }
68
69
70 //
71 LocalBrowserWindow::~LocalBrowserWindow(void)
72 {
73 free(LocalInfo);
74 }
75
76
77 // Get the local variables information
78 // Return true for a new local variables set
79 bool LocalBrowserWindow::UpdateInfos(void)
80 {
81 size_t Adr;
82 char *Ptr;
83
84 // get number of local variables located in the M68K PC address
85 if ((NbLocal = DBGManager_GetNbVariables(Adr = m68k_get_reg(NULL, M68K_REG_PC))))
86 {
87 // get function name from the M68K PC address
88 if ((Ptr = DBGManager_GetFunctionName(Adr)))
89 {
90 // avoid to read the same information in case of the function has not changed
91 if (!FuncName || strcmp(FuncName, Ptr))
92 {
93 // function is different
94 FuncName = Ptr;
95 if (LocalInfo = (S_LocalInfo*)realloc(LocalInfo, (sizeof(S_LocalInfo) * NbLocal)))
96 {
97 for (size_t i = 0; i < NbLocal; i++)
98 {
99 // get local variable name and his information
100 if ((LocalInfo[i].PtrVariable = DBGManager_GetInfosVariable(Adr, i + 1)))
101 {
102 LocalInfo[i].Adr = 0;
103 LocalInfo[i].PtrCPURegisterName = NULL;
104 }
105 }
106 }
107
108 return true;
109 }
110 else
111 {
112 return false;
113 }
114 }
115 }
116
117 FuncName = NULL;
118
119 return false;
120 }
121
122
123 // Prepare a complete row based on the variable information
124 // The row will append rows if necessary
125 QList<QStandardItem *> LocalBrowserWindow::prepareRow(void* Info)
126 {
127 // set the list
128 QList<QStandardItem *> ptrRow = { new QStandardItem(((S_VariablesStruct*)Info)->PtrName), new QStandardItem(""), new QStandardItem(((S_VariablesStruct*)Info)->PtrTypeName) };
129
130 // check if variable has additional variables (such as structure)
131 if (size_t nb = ((S_VariablesStruct*)Info)->NbTabVariables)
132 {
133 for (size_t i = 0; i < nb; i++)
134 {
135 ptrRow.first()->appendRow(prepareRow(((S_VariablesStruct*)Info)->TabVariables[i]));
136 }
137 }
138
139 // return the list
140 return ptrRow;
141 }
142
143
144 // Set the values of each line in accordance of the rows created from prepareRow() function
145 void LocalBrowserWindow::setValueRow(QStandardItem *Row, size_t Adr, char* Value, void* Info)
146 {
147 QStandardItem *child = Row->child(0, 1);
148 if (child)
149 {
150 // check if variable has additional variables list (such as structure)
151 if (size_t nb = ((S_VariablesStruct*)Info)->NbTabVariables)
152 {
153 // get the pointer's value
154 Adr = GET32(jagMemSpace, Adr);
155
156 for (size_t i = 0; i < nb; i++)
157 {
158 // do not display arrays
159 if (!((((S_VariablesStruct*)Info)->TabVariables[i]->TypeTag & DBG_TAG_TYPE_array)))
160 {
161 // set value in the row
162 Value = DBGManager_GetVariableValueFromAdr(Adr + ((S_VariablesStruct*)Info)->TabVariables[i]->Offset, ((S_VariablesStruct*)Info)->TabVariables[i]->TypeEncoding, ((S_VariablesStruct*)Info)->TabVariables[i]->TypeByteSize);
163 child = Row->child((int)i, 1);
164 child->setText(QString("%1").arg(Value));
165 setValueRow(child, Adr + ((S_VariablesStruct*)Info)->TabVariables[i]->Offset, Value, (void*)((S_VariablesStruct*)Info)->TabVariables[i]);
166 }
167 }
168 }
169 }
170 }
171
172
173 // Refresh the local and/or parameters contents list
174 void LocalBrowserWindow::RefreshContents(void)
175 {
176 size_t Error = LOCAL_NOERROR;
177 QString Local;
178 QString MSG;
179 char Value1[100];
180 char *PtrValue;
181
182 // local variables may come from M68K registers
183 const char *CPURegName[] = { "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7" };
184
185 // refresh only if local's window is displayed
186 if (isVisible())
187 {
188 // get local's information
189 if (UpdateInfos())
190 {
191 // erase the previous variables list
192 model->setRowCount(0);
193
194 // loop on the locals found
195 for (size_t i = 0; i < NbLocal; i++)
196 {
197 // check variable's name validity
198 if (((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->PtrName)
199 {
200 // insert the row
201 model->appendRow(prepareRow(LocalInfo[i].PtrVariable));
202
203 // check if the local variable is use by the code
204 if (((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->Op)
205 {
206 // local or parameters variables
207 if (((((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->Op >= DBG_OP_breg0) && (((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->Op <= DBG_OP_breg31)) || (((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->Op == DBG_OP_fbreg))
208 {
209 // get variable's address
210 LocalInfo[i].Adr = m68k_get_reg(NULL, M68K_REG_A6) + ((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->Offset;
211 // check variable's parameter op
212 if ((((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->Op == DBG_OP_fbreg))
213 {
214 LocalInfo[i].Adr += 8;
215 }
216 }
217 else
218 {
219 // variable type from CPU register
220 if ((((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->Op >= DBG_OP_reg0) && (((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->Op <= DBG_OP_reg31))
221 {
222 // set color text for a register type variable
223 model->item((int)i, 0)->setForeground(QColor(0, 0, 0xfe));
224 model->item((int)i, 1)->setForeground(QColor(0, 0, 0xfe));
225 model->item((int)i, 2)->setForeground(QColor(0, 0, 0xfe));
226 // get the register's name
227 LocalInfo[i].PtrCPURegisterName = (char *)CPURegName[(((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->Op - DBG_OP_reg0)];
228 }
229 }
230 }
231 else
232 {
233 // set color text for unused variable (no need to set it for the value's field as no values will be displayed)
234 model->item((int)i, 0)->setForeground(QColor(0xc8, 0xc8, 0xc8));
235 model->item((int)i, 2)->setForeground(QColor(0xc8, 0xc8, 0xc8));
236 }
237 }
238 }
239 }
240
241 // set the values in the fields
242 if (NbLocal)
243 {
244 // loop on the locals found
245 for (size_t i = 0; i < NbLocal; i++)
246 {
247 // variable's address must fit in RAM
248 if ((LocalInfo[i].Adr >= 4) && (LocalInfo[i].Adr < vjs.DRAM_size))
249 {
250 // get the variable's value
251 PtrValue = DBGManager_GetVariableValueFromAdr(LocalInfo[i].Adr, ((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->TypeEncoding, ((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->TypeByteSize);
252 }
253 else
254 {
255 // check CPU register's type variable
256 if (LocalInfo[i].PtrCPURegisterName)
257 {
258 // get the value from register
259 memset(Value1, 0, sizeof(Value1));
260 sprintf(Value1, "0x%x", m68k_get_reg(NULL, (m68k_register_t)((size_t)M68K_REG_D0 + (((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->Op - DBG_OP_reg0))));
261 PtrValue = Value1;
262 }
263 else
264 {
265 // no value can be found
266 PtrValue = NULL;
267 }
268 }
269
270 // do not display arrays
271 if (!(((S_VariablesStruct*)LocalInfo[i].PtrVariable)->TypeTag & DBG_TAG_TYPE_array))
272 {
273 // set the local's variable value
274 model->item((int)i, 1)->setText(QString("%1").arg(PtrValue));
275 setValueRow(model->item((int)i), LocalInfo[i].Adr, PtrValue, (S_VariablesStruct*)(LocalInfo[i].PtrVariable));
276 }
277 }
278
279 MSG += QString("Ready");
280 }
281 else
282 {
283 // erase the previous variables list
284 model->setRowCount(0);
285
286 // No locals
287 MSG += QString("No locals");
288 Error = LOCAL_NOLOCALS;
289 }
290
291 // display status bar
292 if (Error)
293 {
294 if ((Error & LOCAL_WARNING))
295 {
296 statusbar->setStyleSheet("background-color: lightyellow; font: bold");
297 }
298 else
299 {
300 statusbar->setStyleSheet("background-color: tomato; font: bold");
301 }
302 }
303 else
304 {
305 statusbar->setStyleSheet("background-color: lightgreen; font: bold");
306 }
307 statusbar->showMessage(MSG);
308 }
309 }
310
311
312 // Handle keyboard actions
313 void LocalBrowserWindow::keyPressEvent(QKeyEvent * e)
314 {
315 // close / hide the window
316 if (e->key() == Qt::Key_Escape)
317 {
318 hide();
319 }
320 }