From d07749718a3ea891a354054de3eb15c4c259d647 Mon Sep 17 00:00:00 2001 From: Jean-Paul Mari Date: Mon, 24 May 2021 01:44:41 -0400 Subject: [PATCH] Display the structure's members in the Local variables window --- docs/vj_HistoryNotes.txt | 1 + src/debugger/localbrowser.cpp | 634 +++++++++++++++++----------------- src/debugger/localbrowser.h | 29 +- 3 files changed, 330 insertions(+), 334 deletions(-) rewrite src/debugger/localbrowser.cpp (64%) diff --git a/docs/vj_HistoryNotes.txt b/docs/vj_HistoryNotes.txt index f438507..ca4ccf8 100644 --- a/docs/vj_HistoryNotes.txt +++ b/docs/vj_HistoryNotes.txt @@ -41,6 +41,7 @@ Release 5 (TBA) 27) Added video output display in a specific window 28) Fixed potential crash with the debugger tabs reset 29) Added a search feature in the All Watch variables window +30) Support the structure's members in the Local variables window Release 4a (15th August 2019) ----------------------------- diff --git a/src/debugger/localbrowser.cpp b/src/debugger/localbrowser.cpp dissimilarity index 64% index 9cafa71..c59587f 100644 --- a/src/debugger/localbrowser.cpp +++ b/src/debugger/localbrowser.cpp @@ -1,314 +1,320 @@ -// -// localbrowser.cpp - Local variables -// -// by Jean-Paul Mari -// -// JPM = Jean-Paul Mari -// RG = Richard Goedeken -// -// Who When What -// --- ---------- ----------------------------------------------------------- -// JPM 11/03/2017 Created this file -// JPM Sept./2018 Added a status bar and better status report, and set information values in a tab -// RG Jan./2021 Linux build fixes -// - -// STILL TO DO: -// Feature to list the pointer(s) in the code using the allocation -// To set the information display at the right -// To support the array -// To support the static variables -// To add a filter -// - -#include - -#include "debugger/localbrowser.h" -#include "memory.h" -#include "debugger/DBGManager.h" -#include "settings.h" -#include "m68000/m68kinterface.h" - - -// -LocalBrowserWindow::LocalBrowserWindow(QWidget * parent/*= 0*/) : QWidget(parent, Qt::Dialog), -layout(new QVBoxLayout), -#ifdef LOCAL_LAYOUTTEXTS -text(new QTextBrowser), -#else -TableView(new QTableView), -model(new QStandardItemModel), -#endif -NbLocal(0), -FuncName((char *)calloc(1, 1)), -LocalInfo(NULL), -statusbar(new QStatusBar) -{ - setWindowTitle(tr("Locals")); - - // Set the font - QFont fixedFont("Lucida Console", 8, QFont::Normal); - fixedFont.setStyleHint(QFont::TypeWriter); - -#ifdef LOCAL_LAYOUTTEXTS - // Set original layout - text->setFont(fixedFont); - layout->addWidget(text); -#else - // Set the new layout with proper identation and readibility - model->setColumnCount(3); - model->setHeaderData(0, Qt::Horizontal, QObject::tr("Name")); - model->setHeaderData(1, Qt::Horizontal, QObject::tr("Value")); - model->setHeaderData(2, Qt::Horizontal, QObject::tr("Type")); - // Information table - TableView->setModel(model); - TableView->setEditTriggers(QAbstractItemView::NoEditTriggers); - TableView->setShowGrid(0); - TableView->setFont(fixedFont); - TableView->verticalHeader()->setDefaultSectionSize(TableView->verticalHeader()->minimumSectionSize()); - TableView->verticalHeader()->setDefaultAlignment(Qt::AlignRight); - layout->addWidget(TableView); -#endif - - // Status bar - layout->addWidget(statusbar); - setLayout(layout); -} - - -// -LocalBrowserWindow::~LocalBrowserWindow(void) -{ - free(LocalInfo); - free(FuncName); -} - - -// -bool LocalBrowserWindow::UpdateInfos(void) -{ - size_t Adr; - char *Ptr; - - if (NbLocal = DBGManager_GetNbLocalVariables(Adr = m68k_get_reg(NULL, M68K_REG_PC))) - { - if (Ptr = DBGManager_GetFunctionName(Adr)) - { - if (strcmp(FuncName, Ptr)) - { - if (FuncName = (char *)realloc(FuncName, strlen(Ptr) + 1)) - { - strcpy(FuncName, Ptr); - - if (LocalInfo = (WatchInfo *)realloc(LocalInfo, (sizeof(WatchInfo) * NbLocal))) - { - for (size_t i = 0; i < NbLocal; i++) - { - // Get local variable name and his information - if (LocalInfo[i].PtrVariableName = DBGManager_GetLocalVariableName(Adr, i + 1)) - { - LocalInfo[i].Op = DBGManager_GetLocalVariableOp(Adr, i + 1); - LocalInfo[i].Adr = NULL; - LocalInfo[i].PtrCPURegisterName = NULL; - LocalInfo[i].TypeTag = DBGManager_GetLocalVariableTypeTag(Adr, i + 1); - LocalInfo[i].PtrVariableBaseTypeName = DBGManager_GetLocalVariableTypeName(Adr, i + 1); - LocalInfo[i].TypeEncoding = DBGManager_GetLocalVariableTypeEncoding(Adr, i + 1); - LocalInfo[i].TypeByteSize = DBGManager_GetLocalVariableTypeByteSize(Adr, i + 1); - LocalInfo[i].Offset = DBGManager_GetLocalVariableOffset(Adr, i + 1); - } - } - } - } - } - - return true; - } - } - - *FuncName = 0; - - return false; -} - - -// -void LocalBrowserWindow::RefreshContents(void) -{ -#ifdef LOCAL_LAYOUTTEXTS - char string[1024]; -#endif - size_t Error = LOCAL_NOERROR; - QString Local; - QString MSG; - char Value1[100]; -#ifdef LOCAL_SUPPORTARRAY - char Value[100]; -#endif - char *PtrValue; - - const char *CPURegName[] = { "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7" }; - - if (isVisible()) - { -#ifndef LOCAL_LAYOUTTEXTS - model->setRowCount(0); -#endif - if (UpdateInfos()) - { - for (size_t i = 0; i < NbLocal; i++) - { - if (LocalInfo[i].PtrVariableName) - { - memset(Value1, 0, sizeof(Value1)); -#ifdef LOCAL_LAYOUTTEXTS - if (i) - { - Local += QString("
"); - } -#else - model->insertRow(i); -#endif - // Local or parameters variables - if (((LocalInfo[i].Op >= DBG_OP_breg0) && (LocalInfo[i].Op <= DBG_OP_breg31)) || (LocalInfo[i].Op == DBG_OP_fbreg)) - { - LocalInfo[i].Adr = m68k_get_reg(NULL, M68K_REG_A6) + LocalInfo[i].Offset; - - if ((LocalInfo[i].Op == DBG_OP_fbreg)) - { - LocalInfo[i].Adr += 8; - } - - if ((LocalInfo[i].Adr >= 0) && (LocalInfo[i].Adr < vjs.DRAM_size)) - { - if ((LocalInfo[i].TypeTag & (DBG_TAG_TYPE_array | DBG_TAG_TYPE_structure))) - { -#if defined(LOCAL_SUPPORTARRAY) || defined(LOCAL_SUPPORTSTRUCTURE) - //memcpy(Value1, &jaguarMainRAM[LocalInfo[i].Adr], 20); -#ifdef LOCAL_LAYOUTTEXTS - //sprintf(Value, "\"%s\"", Value1); -#else - //sprintf(Value, "0x%06X, \"%s\"", LocalInfo[i].Adr, Value1); -#endif - //PtrValue = Value; - PtrValue = NULL; -#else - PtrValue = NULL; -#endif - } - else - { - PtrValue = DBGManager_GetVariableValueFromAdr(LocalInfo[i].Adr, LocalInfo[i].TypeEncoding, LocalInfo[i].TypeByteSize); - } - } - else - { - PtrValue = NULL; - } - } - else - { - // Value from CPU register - if ((LocalInfo[i].Op >= DBG_OP_reg0) && (LocalInfo[i].Op <= DBG_OP_reg31)) - { - LocalInfo[i].PtrCPURegisterName = (char *)CPURegName[(LocalInfo[i].Op - DBG_OP_reg0)]; - sprintf(Value1, "%d", m68k_get_reg(NULL, (m68k_register_t)((size_t)M68K_REG_D0 + (LocalInfo[i].Op - DBG_OP_reg0)))); - PtrValue = Value1; - } - else - { - PtrValue = NULL; - } - } - -#ifndef LOCAL_LAYOUTTEXTS - model->setItem(i, 0, new QStandardItem(QString("%1").arg(LocalInfo[i].PtrVariableName))); -#endif - // Check if the local variable is use by the code - if (!LocalInfo[i].Op) - { -#ifdef LOCAL_LAYOUTTEXTS - sprintf(string, "%i : %s | %s | [Not used]", (i + 1), (LocalInfo[i].PtrVariableBaseTypeName ? LocalInfo[i].PtrVariableBaseTypeName : (char *)"N/A"), LocalInfo[i].PtrVariableName); -#else -#endif - } - else - { -#ifndef LOCAL_LAYOUTTEXTS - model->setItem(i, 1, new QStandardItem(QString("%1").arg(PtrValue))); -#else - sprintf(string, "%i : %s | %s | ", (i + 1), (LocalInfo[i].PtrVariableBaseTypeName ? LocalInfo[i].PtrVariableBaseTypeName : (char *)"N/A"), LocalInfo[i].PtrVariableName); - Local += QString(string); - - if ((unsigned int)LocalInfo[i].Adr) - { - sprintf(string, "0x%06X", (unsigned int)LocalInfo[i].Adr); - } - else - { - if (LocalInfo[i].PtrCPURegisterName) - { - sprintf(string, "%s", LocalInfo[i].PtrCPURegisterName); - } - else - { - sprintf(string, "%s", (char *)"N/A"); - } - } - - Local += QString(string); - sprintf(string, " | %s", (!PtrValue ? (char *)"N/A" : PtrValue)); -#endif - } -#ifndef LOCAL_LAYOUTTEXTS - model->setItem(i, 2, new QStandardItem(QString("%1").arg((LocalInfo[i].PtrVariableBaseTypeName ? LocalInfo[i].PtrVariableBaseTypeName : (char *)"N/A")))); -#else - Local += QString(string); -#endif - } - } - - MSG += QString("Ready"); -#ifdef LOCAL_LAYOUTTEXTS - text->clear(); - text->setText(Local); -#endif - } - else - { - // No locals - MSG += QString("No locals"); - Error = LOCAL_NOLOCALS; -#ifdef LOCAL_LAYOUTTEXTS - text->clear(); -#endif - } - - // Display status bar - if (Error) - { - if ((Error & LOCAL_WARNING)) - { - statusbar->setStyleSheet("background-color: lightyellow; font: bold"); - } - else - { - statusbar->setStyleSheet("background-color: tomato; font: bold"); - } - } - else - { - statusbar->setStyleSheet("background-color: lightgreen; font: bold"); - } - statusbar->showMessage(MSG); - } -} - - -// -void LocalBrowserWindow::keyPressEvent(QKeyEvent * e) -{ - if (e->key() == Qt::Key_Escape) - { - hide(); - } -} +// +// localbrowser.cpp - Local variables +// +// by Jean-Paul Mari +// +// JPM = Jean-Paul Mari +// RG = Richard Goedeken +// +// Who When What +// --- ---------- ----------------------------------------------------------- +// JPM 11/03/2017 Created this file +// JPM Sept./2018 Added a status bar and better status report, and set information values in a tab +// RG Jan./2021 Linux build fixes +// JPM May/2021 Display the structure's members +// + +// STILL TO DO: +// Feature to list the pointer(s) in the code using the allocation +// To set the information display at the right +// To support the array +// To support the union +// To support the static variables +// To add a filter +// + +#include + +#include "debugger/localbrowser.h" +#include "memory.h" +#include "debugger/DBGManager.h" +#include "settings.h" +#include "m68000/m68kinterface.h" + + +// +LocalBrowserWindow::LocalBrowserWindow(QWidget * parent/*= 0*/) : QWidget(parent, Qt::Dialog), +layout(new QVBoxLayout), +TableView(new QTreeView), +model(new QStandardItemModel), +NbLocal(0), +FuncName(NULL), +LocalInfo(NULL), +statusbar(new QStatusBar) +{ + setWindowTitle(tr("Locals")); +#ifdef LOCAL_FONTS + // Set the font + QFont fixedFont("Lucida Console", 8, QFont::Normal); + fixedFont.setStyleHint(QFont::TypeWriter); +#endif + // Set the new layout with proper identation and readibility + model->setColumnCount(3); + model->setHeaderData(0, Qt::Horizontal, QObject::tr("Name")); + model->setHeaderData(1, Qt::Horizontal, QObject::tr("Value")); + model->setHeaderData(2, Qt::Horizontal, QObject::tr("Type")); + // Information table + TableView->setModel(model); + TableView->setEditTriggers(QAbstractItemView::NoEditTriggers); +#ifdef LOCAL_FONTS + TableView->setFont(fixedFont); +#endif + layout->addWidget(TableView); + + // Status bar + layout->addWidget(statusbar); + setLayout(layout); +} + + +// +LocalBrowserWindow::~LocalBrowserWindow(void) +{ + free(LocalInfo); +} + + +// Get the local variables information +// Return true for a new local variables set +bool LocalBrowserWindow::UpdateInfos(void) +{ + size_t Adr; + char *Ptr; + + // get number of local variables located in the M68K PC address + if ((NbLocal = DBGManager_GetNbVariables(Adr = m68k_get_reg(NULL, M68K_REG_PC)))) + { + // get function name from the M68K PC address + if ((Ptr = DBGManager_GetFunctionName(Adr))) + { + // avoid to read the same information in case of the function has not changed + if (!FuncName || strcmp(FuncName, Ptr)) + { + // function is different + FuncName = Ptr; + if (LocalInfo = (S_LocalInfo*)realloc(LocalInfo, (sizeof(S_LocalInfo) * NbLocal))) + { + for (size_t i = 0; i < NbLocal; i++) + { + // get local variable name and his information + if ((LocalInfo[i].PtrVariable = DBGManager_GetInfosVariable(Adr, i + 1))) + { + LocalInfo[i].Adr = 0; + LocalInfo[i].PtrCPURegisterName = NULL; + } + } + } + + return true; + } + else + { + return false; + } + } + } + + FuncName = NULL; + + return false; +} + + +// Prepare a complete row based on the variable information +// The row will append rows if necessary +QList LocalBrowserWindow::prepareRow(void* Info) +{ + // set the list + QList ptrRow = { new QStandardItem(((S_VariablesStruct*)Info)->PtrName), new QStandardItem(""), new QStandardItem(((S_VariablesStruct*)Info)->PtrTypeName) }; + + // check if variable has additional variables (such as structure) + if (size_t nb = ((S_VariablesStruct*)Info)->NbTabVariables) + { + for (size_t i = 0; i < nb; i++) + { + ptrRow.first()->appendRow(prepareRow(((S_VariablesStruct*)Info)->TabVariables[i])); + } + } + + // return the list + return ptrRow; +} + + +// Set the values of each line in accordance of the rows created from prepareRow() function +void LocalBrowserWindow::setValueRow(QStandardItem *Row, size_t Adr, char* Value, void* Info) +{ + QStandardItem *child = Row->child(0, 1); + if (child) + { + // check if variable has additional variables list (such as structure) + if (size_t nb = ((S_VariablesStruct*)Info)->NbTabVariables) + { + // get the pointer's value + Adr = GET32(jagMemSpace, Adr); + + for (size_t i = 0; i < nb; i++) + { + // do not display arrays + if (!((((S_VariablesStruct*)Info)->TabVariables[i]->TypeTag & DBG_TAG_TYPE_array))) + { + // set value in the row + Value = DBGManager_GetVariableValueFromAdr(Adr + ((S_VariablesStruct*)Info)->TabVariables[i]->Offset, ((S_VariablesStruct*)Info)->TabVariables[i]->TypeEncoding, ((S_VariablesStruct*)Info)->TabVariables[i]->TypeByteSize); + child = Row->child((int)i, 1); + child->setText(QString("%1").arg(Value)); + setValueRow(child, Adr + ((S_VariablesStruct*)Info)->TabVariables[i]->Offset, Value, (void*)((S_VariablesStruct*)Info)->TabVariables[i]); + } + } + } + } +} + + +// Refresh the local and/or parameters contents list +void LocalBrowserWindow::RefreshContents(void) +{ + size_t Error = LOCAL_NOERROR; + QString Local; + QString MSG; + char Value1[100]; + char *PtrValue; + + // local variables may come from M68K registers + const char *CPURegName[] = { "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7" }; + + // refresh only if local's window is displayed + if (isVisible()) + { + // get local's information + if (UpdateInfos()) + { + // erase the previous variables list + model->setRowCount(0); + + // loop on the locals found + for (size_t i = 0; i < NbLocal; i++) + { + // check variable's name validity + if (((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->PtrName) + { + // insert the row + model->appendRow(prepareRow(LocalInfo[i].PtrVariable)); + + // check if the local variable is use by the code + if (((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->Op) + { + // local or parameters variables + 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)) + { + // get variable's address + LocalInfo[i].Adr = m68k_get_reg(NULL, M68K_REG_A6) + ((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->Offset; + // check variable's parameter op + if ((((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->Op == DBG_OP_fbreg)) + { + LocalInfo[i].Adr += 8; + } + } + else + { + // variable type from CPU register + if ((((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->Op >= DBG_OP_reg0) && (((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->Op <= DBG_OP_reg31)) + { + // set color text for a register type variable + model->item((int)i, 0)->setForeground(QColor(0, 0, 0xfe)); + model->item((int)i, 1)->setForeground(QColor(0, 0, 0xfe)); + model->item((int)i, 2)->setForeground(QColor(0, 0, 0xfe)); + // get the register's name + LocalInfo[i].PtrCPURegisterName = (char *)CPURegName[(((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->Op - DBG_OP_reg0)]; + } + } + } + else + { + // set color text for unused variable (no need to set it for the value's field as no values will be displayed) + model->item((int)i, 0)->setForeground(QColor(0xc8, 0xc8, 0xc8)); + model->item((int)i, 2)->setForeground(QColor(0xc8, 0xc8, 0xc8)); + } + } + } + } + + // set the values in the fields + if (NbLocal) + { + // loop on the locals found + for (size_t i = 0; i < NbLocal; i++) + { + // variable's address must fit in RAM + if ((LocalInfo[i].Adr >= 4) && (LocalInfo[i].Adr < vjs.DRAM_size)) + { + // get the variable's value + PtrValue = DBGManager_GetVariableValueFromAdr(LocalInfo[i].Adr, ((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->TypeEncoding, ((S_VariablesStruct*)(LocalInfo[i].PtrVariable))->TypeByteSize); + } + else + { + // check CPU register's type variable + if (LocalInfo[i].PtrCPURegisterName) + { + // get the value from register + memset(Value1, 0, sizeof(Value1)); + 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)))); + PtrValue = Value1; + } + else + { + // no value can be found + PtrValue = NULL; + } + } + + // do not display arrays + if (!(((S_VariablesStruct*)LocalInfo[i].PtrVariable)->TypeTag & DBG_TAG_TYPE_array)) + { + // set the local's variable value + model->item((int)i, 1)->setText(QString("%1").arg(PtrValue)); + setValueRow(model->item((int)i), LocalInfo[i].Adr, PtrValue, (S_VariablesStruct*)(LocalInfo[i].PtrVariable)); + } + } + + MSG += QString("Ready"); + } + else + { + // erase the previous variables list + model->setRowCount(0); + + // No locals + MSG += QString("No locals"); + Error = LOCAL_NOLOCALS; + } + + // display status bar + if (Error) + { + if ((Error & LOCAL_WARNING)) + { + statusbar->setStyleSheet("background-color: lightyellow; font: bold"); + } + else + { + statusbar->setStyleSheet("background-color: tomato; font: bold"); + } + } + else + { + statusbar->setStyleSheet("background-color: lightgreen; font: bold"); + } + statusbar->showMessage(MSG); + } +} + + +// Handle keyboard actions +void LocalBrowserWindow::keyPressEvent(QKeyEvent * e) +{ + // close / hide the window + if (e->key() == Qt::Key_Escape) + { + hide(); + } +} diff --git a/src/debugger/localbrowser.h b/src/debugger/localbrowser.h index 9453353..249350f 100644 --- a/src/debugger/localbrowser.h +++ b/src/debugger/localbrowser.h @@ -7,39 +7,30 @@ #ifndef __LOCALBROWSER_H__ #define __LOCALBROWSER_H__ -//#define LOCAL_LAYOUTTEXTS // Use a layout with just texts -//#define LOCAL_SUPPORTARRAY // Support array -//#define LOCAL_SUPPORTSTRUCTURE // Support structure +//#define LOCAL_FONTS // Support for fonts modifications #include #include // Error code definitions #define LOCAL_NOERROR 0x00 -#define LOCAL_ERROR 0x80 #define LOCAL_WARNING 0x40 +#define LOCAL_ERROR 0x80 #define LOCAL_NOLOCALS (0x01 | LOCAL_WARNING) - // class LocalBrowserWindow: public QWidget { Q_OBJECT // - typedef struct WatchInfo + typedef struct LocalInfo { - size_t Op; size_t Adr; - int Offset; - size_t TypeTag; - size_t TypeEncoding; - size_t TypeByteSize; - char *PtrVariableName; - char *PtrVariableBaseTypeName; char *PtrCPURegisterName; + void *PtrVariable; } - S_WatchInfo; + S_LocalInfo; public: LocalBrowserWindow(QWidget *parent = 0); @@ -50,17 +41,15 @@ class LocalBrowserWindow: public QWidget bool UpdateInfos(void); protected: + QList prepareRow(void* Info); + void setValueRow(QStandardItem *Row, size_t Adr, char* Value, void* Info); void keyPressEvent(QKeyEvent *); private: QVBoxLayout *layout; -#ifdef LOCAL_LAYOUTTEXTS - QTextBrowser *text; -#else - QTableView *TableView; + QTreeView *TableView; QStandardItemModel *model; -#endif - WatchInfo *LocalInfo; + S_LocalInfo *LocalInfo; QStatusBar *statusbar; size_t NbLocal; char *FuncName; -- 2.20.1