Files
seer/src/SeerStackDumpBrowserWidget.cpp
T

445 lines
13 KiB
C++
Raw Normal View History

2025-08-26 17:26:05 -05:00
// SPDX-FileCopyrightText: 2021 Ernie Pasveer <epasveer@att.net>
//
// SPDX-License-Identifier: GPL-3.0-or-later
2024-09-27 16:16:02 -05:00
#include "SeerStackDumpBrowserWidget.h"
2024-10-02 18:04:46 -05:00
#include "SeerStackDumpSettingsDialog.h"
2024-09-27 16:16:02 -05:00
#include "SeerUtl.h"
#include <QtWidgets/QTableWidget>
#include <QtWidgets/QApplication>
2024-10-02 18:04:46 -05:00
#include <QtGui/QFontDatabase>
#include <QtCore/QSettings>
#include <QtCore/QVector>
2024-09-27 16:16:02 -05:00
#include <QtCore/QDebug>
2024-10-05 10:37:29 -05:00
#include <cmath>
2024-09-27 16:16:02 -05:00
SeerStackDumpBrowserWidget::SeerStackDumpBrowserWidget (QWidget* parent) : QWidget(parent) {
_spExpressionId = Seer::createID();
_dumpExpressionId = Seer::createID();
2024-09-27 16:16:02 -05:00
// Construct the UI.
setupUi(this);
// Setup the widgets
stackTableWidget->setMouseTracking(true);
stackTableWidget->setSortingEnabled(false);
stackTableWidget->resizeColumnToContents(0); // 2 byte address
stackTableWidget->resizeColumnToContents(1); // 2 byte value
stackTableWidget->resizeColumnToContents(2); // 4 byte value
stackTableWidget->resizeColumnToContents(3); // 8 byte value
2024-10-02 18:04:46 -05:00
stackTableWidget->resizeColumnToContents(4); // N byte ascii
stackTableWidget->resizeRowsToContents();
2024-09-27 16:16:02 -05:00
stackTableWidget->clearContents();
// Connect things.
2024-10-02 18:04:46 -05:00
QObject::connect(formatComboBox, &QComboBox::currentTextChanged, this, &SeerStackDumpBrowserWidget::handleFormatComboBox);
QObject::connect(visualizerToolButton, &QToolButton::clicked, this, &SeerStackDumpBrowserWidget::handleVisualizerToolButton);
QObject::connect(preferencesToolButton, &QToolButton::clicked, this, &SeerStackDumpBrowserWidget::handlePreferencesToolButton);
2024-10-05 10:37:29 -05:00
QObject::connect(stackTableWidget, &QTableWidget::cellDoubleClicked, this, &SeerStackDumpBrowserWidget::handleCellDoubleClicked);
2024-10-02 18:04:46 -05:00
setStackPointerExpression("$sp");
2024-10-05 12:13:37 -05:00
setStackPointerColor(QColor("lightGray"));
2024-10-05 10:37:29 -05:00
setBytesBeforeSP(16);
setBytesAfterSP(16);
2024-10-02 18:04:46 -05:00
setAsciiBytes(8);
// Restore settings.
readSettings();
2024-09-27 16:16:02 -05:00
}
SeerStackDumpBrowserWidget::~SeerStackDumpBrowserWidget () {
}
2024-10-02 18:04:46 -05:00
void SeerStackDumpBrowserWidget::setStackPointerExpression (const QString& expression) {
_stackPointerExpression = expression;
spExpressionLabel->setText(_stackPointerExpression);
}
QString SeerStackDumpBrowserWidget::stackPointerExpression () const {
return _stackPointerExpression;
}
void SeerStackDumpBrowserWidget::setBytesBeforeSP (int nbytes) {
2024-10-05 10:37:29 -05:00
_bytesBeforeSP = ceil(nbytes / 8.0) * 8; // Round to 8.
2024-10-02 18:04:46 -05:00
}
int SeerStackDumpBrowserWidget::bytesBeforeSP () const {
return _bytesBeforeSP;
}
void SeerStackDumpBrowserWidget::setBytesAfterSP (int nbytes) {
2024-10-05 10:37:29 -05:00
_bytesAfterSP = ceil(nbytes / 8.0) * 8; // Round to 8.
2024-10-02 18:04:46 -05:00
}
int SeerStackDumpBrowserWidget::bytesAfterSP () const {
return _bytesAfterSP;
}
void SeerStackDumpBrowserWidget::setAsciiBytes (int nbytes) {
_asciiBytes = nbytes;
}
int SeerStackDumpBrowserWidget::asciiBytes () const {
return _asciiBytes;
}
2024-10-05 12:13:37 -05:00
void SeerStackDumpBrowserWidget::setStackPointerColor (const QColor& color) {
_stackPointerColor = color;
}
QColor SeerStackDumpBrowserWidget::stackPointerColor () const {
return _stackPointerColor;
}
2024-09-27 16:16:02 -05:00
void SeerStackDumpBrowserWidget::handleText (const QString& text) {
// -data-read-memory-bytes -o 16 $sp 32
// ^done,memory=[
// {
// begin="0x00007fffffffda80",
// offset="0x0000000000000000",
// end="0x00007fffffffdaa0",
// contents="0000000000000000e80300000000000098dcffffff7f0000e803000001000000"
// }
// ]
//
//
// -data-evaluate-expression $sp
// ^done,value="0x7fffffffda90"
QApplication::setOverrideCursor(Qt::BusyCursor);
while (1) {
if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) {
// ^done,value="0x7fffffffda90"
QString id_text = text.section('^', 0,0);
QString value_text = Seer::parseFirst(text, "value=", '"', '"', false);
if (id_text.toInt() != _spExpressionId) {
break;
}
addressLineEdit->setText(value_text);
2024-10-05 10:37:29 -05:00
emit refreshStackDump(_dumpExpressionId, value_text, -bytesBeforeSP(), bytesBeforeSP()+bytesAfterSP()+2);
}else if (text.contains(QRegularExpression("^([0-9]+)\\^done,memory="))) {
QString id_text = text.section('^', 0,0);
if (id_text.toInt() != _dumpExpressionId) {
break;
}
QString begin_text = Seer::parseFirst(text, "begin=", '"', '"', false);
QString contents_text = Seer::parseFirst(text, "contents=", '"', '"', false);
_populateTable(begin_text, contents_text);
2024-09-27 16:16:02 -05:00
}else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg=\"No registers.\""))) {
addressLineEdit->setText("");
}else{
// Ignore others.
}
break;
}
stackTableWidget->resizeColumnToContents(0);
stackTableWidget->resizeColumnToContents(1);
stackTableWidget->resizeColumnToContents(2);
stackTableWidget->resizeColumnToContents(3);
stackTableWidget->resizeColumnToContents(4);
stackTableWidget->resizeRowsToContents();
2024-09-27 16:16:02 -05:00
QApplication::restoreOverrideCursor();
}
void SeerStackDumpBrowserWidget::handleStoppingPointReached () {
// Don't do any work if the widget is hidden.
if (isHidden()) {
return;
}
refresh();
}
void SeerStackDumpBrowserWidget::handleSessionTerminated () {
// Delete previous contents.
stackTableWidget->clearContents();
}
void SeerStackDumpBrowserWidget::handleFormatComboBox (const QString& text) {
Q_UNUSED(text);
refresh();
}
void SeerStackDumpBrowserWidget::handleVisualizerToolButton () {
2025-06-29 13:30:35 -05:00
emit addMemoryVisualizer(addressLineEdit->text());
}
2024-10-02 18:04:46 -05:00
void SeerStackDumpBrowserWidget::handlePreferencesToolButton () {
// Bring up the register edit dialog.
SeerStackDumpSettingsDialog dlg(this);
dlg.setStackPointerExpression(stackPointerExpression());
2024-10-05 12:13:37 -05:00
dlg.setStackPointerColor(stackPointerColor());
2024-10-02 18:04:46 -05:00
dlg.setBytesBeforeSP(bytesBeforeSP());
dlg.setBytesAfterSP(bytesAfterSP());
dlg.setAsciiBytes(asciiBytes());
//dlg.set(item->text(1), item->text(2));
int ret = dlg.exec();
if (ret == 0) {
return;
}
setStackPointerExpression(dlg.stackPointerExpression());
2024-10-05 12:13:37 -05:00
setStackPointerColor(dlg.stackPointerColor());
2024-10-02 18:04:46 -05:00
setBytesBeforeSP(dlg.bytesBeforeSP());
setBytesAfterSP(dlg.bytesAfterSP());
setAsciiBytes(dlg.asciiBytes());
writeSettings();
refresh();
}
2024-10-05 10:37:29 -05:00
void SeerStackDumpBrowserWidget::handleCellDoubleClicked (int row, int col) {
Q_UNUSED(col);
QTableWidgetItem* item = stackTableWidget->item(row, 0);
if (item == 0) {
return;
}
QString address = item->text();
if (address.mid(0,2) != "0x") {
address.insert(0,"0x");
}
2025-06-29 13:30:35 -05:00
emit addMemoryVisualizer(address);
2024-10-05 10:37:29 -05:00
}
2024-09-27 16:16:02 -05:00
void SeerStackDumpBrowserWidget::refresh () {
// Don't do any work if the widget is hidden.
if (isHidden()) {
return;
}
2024-10-02 18:04:46 -05:00
emit refreshStackPointer(_spExpressionId, stackPointerExpression());
2024-09-27 16:16:02 -05:00
}
void SeerStackDumpBrowserWidget::showEvent (QShowEvent* event) {
QWidget::showEvent(event);
refresh();
}
void SeerStackDumpBrowserWidget::_populateTable (QString address, QString contents) {
QFont fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont);
// Loop off '0x'.
if (address.mid(0,2) == "0x") {
address = address.mid(2);
}
bool ok;
quint64 address64 = address.toULongLong(&ok, 16);
quint64 pos64 = address64;
int nrows = contents.length()/2/2; // Divide by 2 for a "FF" character, then again for 2 bytes per row.
// Convert the contents to raw bytes.
QVector<quint8> bytes;
for (int pos=0; pos<contents.length(); pos+=2) {
// Get a hex value "FF".
QString str = contents.mid(pos, 2);
// Ignore "0x";
if (str == "0x" || str == "0X") {
continue;
}
// Convert string hex to quint8.
quint8 hex = str.toUInt(&ok, 16);
if (ok) {
bytes.push_back(hex);
}
}
// Resize table.
stackTableWidget->clearContents();
stackTableWidget->setRowCount(nrows);
2024-10-05 10:37:29 -05:00
int spRow = -1;
// Fill in the address column.
for (int i=0,r=0; i < contents.length()/2; i+=2,pos64+=2,r++) {
QString str = QString::number(pos64, 16);
QTableWidgetItem* item = new QTableWidgetItem;
item->setText(str);
item->setFont(fixedFont);
2024-10-05 10:37:29 -05:00
if (addressLineEdit->text().contains(str)) {
2024-10-05 12:13:37 -05:00
item->setBackground(QBrush(stackPointerColor()));
2024-10-05 10:37:29 -05:00
spRow = r;
}
stackTableWidget->setItem(r,0,item);
}
// Fill in the 2byte column.
for (int i=0,r=0; i<bytes.size(); i+=2,r++) {
QString str;
if (formatComboBox->currentText() == "hex") {
str = Seer::ucharToHex(bytes, i, 2);
}else if (formatComboBox->currentText() == "octal") {
str = Seer::ucharToOctal(bytes, i, 2);
}else if (formatComboBox->currentText() == "uint") {
str = Seer::ucharToUShort(bytes, i, 1);
}else if (formatComboBox->currentText() == "int") {
str = Seer::ucharToShort(bytes, i, 1);
}
QTableWidgetItem* item = new QTableWidgetItem;
item->setText(str);
item->setFont(fixedFont);
2024-10-05 10:37:29 -05:00
if (r == spRow) {
2024-10-05 12:13:37 -05:00
item->setBackground(QBrush(stackPointerColor()));
2024-10-05 10:37:29 -05:00
}
stackTableWidget->setItem(r,1,item);
}
// Fill in the 4byte column.
for (int i=0,r=0; i < bytes.size(); i+=2,r++) {
QString str;
if (formatComboBox->currentText() == "hex") {
str = Seer::ucharToHex(bytes, i, 4);
}else if (formatComboBox->currentText() == "octal") {
str = Seer::ucharToOctal(bytes, i, 4);
}else if (formatComboBox->currentText() == "uint") {
str = Seer::ucharToUInt(bytes, i, 1);
}else if (formatComboBox->currentText() == "int") {
str = Seer::ucharToInt(bytes, i, 1);
}else if (formatComboBox->currentText() == "float") {
str = Seer::ucharToFloat(bytes, i, 1);
}
QTableWidgetItem* item = new QTableWidgetItem;
item->setText(str);
item->setFont(fixedFont);
2024-10-05 10:37:29 -05:00
if (r == spRow) {
2024-10-05 12:13:37 -05:00
item->setBackground(QBrush(stackPointerColor()));
2024-10-05 10:37:29 -05:00
}
stackTableWidget->setItem(r,2,item);
}
// Fill in the 8byte column.
for (int i=0,r=0; i < bytes.size(); i+=2,r++) {
QString str;
if (formatComboBox->currentText() == "hex") {
str = Seer::ucharToHex(bytes, i, 8);
}else if (formatComboBox->currentText() == "octal") {
str = Seer::ucharToOctal(bytes, i, 8);
}else if (formatComboBox->currentText() == "uint") {
str = Seer::ucharToULong(bytes, i, 1);
}else if (formatComboBox->currentText() == "int") {
str = Seer::ucharToLong(bytes, i, 1);
}else if (formatComboBox->currentText() == "float") {
str = Seer::ucharToDouble(bytes, i, 1);
}
QTableWidgetItem* item = new QTableWidgetItem;
item->setText(str);
item->setFont(fixedFont);
2024-10-05 10:37:29 -05:00
if (r == spRow) {
2024-10-05 12:13:37 -05:00
item->setBackground(QBrush(stackPointerColor()));
2024-10-05 10:37:29 -05:00
}
stackTableWidget->setItem(r,3,item);
}
2024-10-02 18:04:46 -05:00
// Fill in the Nbyte ascii column.
for (int i=0,r=0; i < bytes.size(); i+=2,r++) {
2024-10-02 18:04:46 -05:00
QString str = Seer::ucharToAscii(bytes, i, asciiBytes());
QTableWidgetItem* item = new QTableWidgetItem;
item->setText(str);
item->setFont(fixedFont);
2024-10-05 10:37:29 -05:00
if (r == spRow) {
2024-10-05 12:13:37 -05:00
item->setBackground(QBrush(stackPointerColor()));
2024-10-05 10:37:29 -05:00
}
stackTableWidget->setItem(r,4,item);
}
}
2024-10-02 18:04:46 -05:00
void SeerStackDumpBrowserWidget::writeSettings () {
QSettings settings;
settings.beginGroup("stackdumpwindow"); {
settings.setValue("stackpointerexpression", stackPointerExpression());
2024-10-05 12:13:37 -05:00
settings.setValue("stackpointercolor", stackPointerColor());
2024-10-02 18:04:46 -05:00
settings.setValue("bytesbeforesp", bytesBeforeSP());
settings.setValue("bytesaftersp", bytesAfterSP());
settings.setValue("asciibytes", asciiBytes());
} settings.endGroup();
}
void SeerStackDumpBrowserWidget::readSettings () {
QSettings settings;
settings.beginGroup("stackdumpwindow"); {
setStackPointerExpression(settings.value("stackpointerexpression", "$sp").toString());
2024-10-05 12:13:37 -05:00
QVariant variant = settings.value("stackpointercolor", "lightGray");
QColor color = variant.value<QColor>();
setStackPointerColor(color);
2024-10-02 18:04:46 -05:00
setBytesBeforeSP(settings.value("bytesbeforesp", 32).toInt());
setBytesAfterSP(settings.value("bytesaftersp", 32).toInt());
setAsciiBytes(settings.value("asciibytes", 8).toInt());
} settings.endGroup();
}