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