summaryrefslogtreecommitdiffstats
path: root/languages/cpp/debugger/memviewdlg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'languages/cpp/debugger/memviewdlg.cpp')
-rw-r--r--languages/cpp/debugger/memviewdlg.cpp486
1 files changed, 486 insertions, 0 deletions
diff --git a/languages/cpp/debugger/memviewdlg.cpp b/languages/cpp/debugger/memviewdlg.cpp
new file mode 100644
index 00000000..5316aa91
--- /dev/null
+++ b/languages/cpp/debugger/memviewdlg.cpp
@@ -0,0 +1,486 @@
+/***************************************************************************
+ begin : Tue Oct 5 1999
+ copyright : (C) 1999 by John Birch
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "memviewdlg.h"
+#include "gdbcontroller.h"
+#include "gdbcommand.h"
+
+#include <kbuttonbox.h>
+#include <klineedit.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <kstdguiitem.h>
+#include <kdeversion.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qmultilineedit.h>
+#include <qpushbutton.h>
+#include <qvariant.h>
+#include <qpopupmenu.h>
+#include <qhbox.h>
+#include <qtoolbox.h>
+#include <qtextedit.h>
+
+#include <kmessagebox.h>
+
+#include <khexedit/byteseditinterface.h>
+
+#include <ctype.h>
+
+// **************************************************************************
+//
+// Dialog allows the user to enter
+// - A starting address
+// - An ending address
+//
+// this can be in the form
+// functiom/method name
+// variable address (ie &Var, str)
+// Memory address 0x8040abc
+//
+// When disassembling and you enter a method name without an
+// ending address then the whole method is disassembled.
+// No data means disassemble the method we're curently in.(from the
+// start of the method)
+//
+// click ok buton to send the request to gdb
+// the output is returned (some time later) in the raw data slot
+// and displayed as is, so it's rather crude, but it works!
+// **************************************************************************
+
+namespace GDBDebugger
+{
+ /** Container for controls that select memory range.
+
+ The memory range selection is embedded into memory view widget,
+ it's not a standalone dialog. However, we want to have easy way
+ to hide/show all controls, so we group them in this class.
+ */
+ class MemoryRangeSelector : public QWidget
+ {
+ public:
+ KLineEdit* startAddressLineEdit;
+ KLineEdit* amountLineEdit;
+ QPushButton* okButton;
+ QPushButton* cancelButton;
+
+ MemoryRangeSelector(QWidget* parent)
+ : QWidget(parent)
+ {
+ QVBoxLayout* l = new QVBoxLayout(this);
+
+ // Grid layout: labels + address field
+ QGridLayout* gl = new QGridLayout(l);
+
+ gl->setColSpacing(0, 2);
+ gl->setColSpacing(1, 4);
+ gl->setRowSpacing(1, 2);
+
+ QLabel* l1 = new QLabel(i18n("Start"), this);
+ gl->addWidget(l1, 0, 1);
+
+ startAddressLineEdit = new KLineEdit(this);
+ gl->addWidget(startAddressLineEdit, 0, 3);
+
+ QLabel* l2 = new QLabel(i18n("Amount"), this);
+ gl->addWidget(l2, 2, 1);
+
+ amountLineEdit = new KLineEdit(this);
+ gl->addWidget(amountLineEdit, 2, 3);
+
+ l->addSpacing(2);
+
+ QHBoxLayout* hb = new QHBoxLayout(l);
+ hb->addStretch();
+
+ okButton = new QPushButton(i18n("OK"), this);
+ hb->addWidget(okButton);
+
+ cancelButton = new QPushButton(i18n("Cancel"), this);
+ hb->addWidget(cancelButton);
+
+ l->addSpacing(2);
+
+ connect(startAddressLineEdit, SIGNAL(returnPressed()),
+ okButton, SLOT(animateClick()));
+
+ connect(amountLineEdit, SIGNAL(returnPressed()),
+ okButton, SLOT(animateClick()));
+ }
+ };
+
+
+
+ MemoryView::MemoryView(GDBController* controller,
+ QWidget* parent, const char* name)
+ : QWidget(parent, name),
+ controller_(controller),
+ // New memory view can be created only when debugger is active,
+ // so don't set s_appNotStarted here.
+ khexedit2_real_widget(0),
+ amount_(0), data_(0),
+ debuggerState_(0)
+ {
+ setCaption(i18n("Memory view"));
+ emit captionChanged(caption());
+
+ initWidget();
+
+ if (isOk())
+ slotEnableOrDisable();
+ }
+
+ void MemoryView::initWidget()
+ {
+ QVBoxLayout *l = new QVBoxLayout(this, 0, 0);
+
+ khexedit2_widget = KHE::createBytesEditWidget(this);
+
+ bool ok_ = false;
+
+ if (khexedit2_widget)
+ {
+ QWidget* real_widget = (QWidget*)
+ khexedit2_widget->child("BytesEdit");
+
+ if (real_widget)
+ {
+ ok_ = true;
+
+ connect(real_widget, SIGNAL(bufferChanged(int, int)),
+ this, SLOT(memoryEdited(int, int)));
+
+ khexedit2_real_widget = real_widget;
+
+ QVariant resize_style(2); // full size usage.
+ real_widget->setProperty("ResizeStyle", resize_style);
+
+ //QVariant group(8);
+ //real_widget->setProperty("StartOffset", start);
+ //real_widget->setProperty("NoOfBytesPerLine", group);
+
+ // HACK: use hardcoded constant taht should match
+ // khexedit2
+ // 3 -- binary
+ // 1 -- decimal
+ // 0 -- hex
+ //QVariant coding(3);
+ //real_widget->setProperty("Coding", coding);
+
+ //QVariant gap(32);
+ //real_widget->setProperty("BinaryGapWidth", gap);
+
+ }
+ else
+ {
+ delete khexedit2_widget;
+ }
+ }
+
+ if (ok_) {
+
+ rangeSelector_ = new MemoryRangeSelector(this);
+ l->addWidget(rangeSelector_);
+
+ connect(rangeSelector_->okButton, SIGNAL(clicked()),
+ this, SLOT(slotChangeMemoryRange()));
+
+
+ connect(rangeSelector_->cancelButton, SIGNAL(clicked()),
+ this, SLOT(slotHideRangeDialog()));
+
+ connect(rangeSelector_->startAddressLineEdit,
+ SIGNAL(textChanged(const QString&)),
+ this,
+ SLOT(slotEnableOrDisable()));
+
+ connect(rangeSelector_->amountLineEdit,
+ SIGNAL(textChanged(const QString&)),
+ this,
+ SLOT(slotEnableOrDisable()));
+
+ l->addWidget(khexedit2_widget);
+
+ } else {
+
+ QTextEdit* edit = new QTextEdit(this);
+ l->addWidget(edit);
+
+ edit->setText(
+ "<h1>Not available</h1>"
+ "<p>Could not open the khexedit2 library. "
+ "Make sure that the KHexEdit package (part of kdeutils) is installed. "
+ "Specifically, check for the following files:"
+ "<ul><li>libkhexeditcommon.so.0.0.0\n"
+ "<li>libkbyteseditwidget.so\n"
+ "<li>kbyteseditwidget.desktop\n"
+ "</ul>");
+ }
+
+ }
+
+ void MemoryView::debuggerStateChanged(int state)
+ {
+ if (isOk())
+ {
+ debuggerState_ = state;
+ slotEnableOrDisable();
+ }
+ }
+
+
+ void MemoryView::slotHideRangeDialog()
+ {
+ rangeSelector_->hide();
+ }
+
+ void MemoryView::slotChangeMemoryRange()
+ {
+ controller_->addCommand(
+ new ExpressionValueCommand(
+ rangeSelector_->amountLineEdit->text(),
+ this, &MemoryView::sizeComputed));
+ }
+
+ void MemoryView::sizeComputed(const QString& size)
+ {
+ controller_->addCommand(
+ new
+ GDBCommand(
+ QString("-data-read-memory %1 x 1 1 %2")
+ .arg(rangeSelector_->startAddressLineEdit->text())
+ .arg(size).ascii(),
+ this,
+ &MemoryView::memoryRead));
+ }
+
+ void MemoryView::memoryRead(const GDBMI::ResultRecord& r)
+ {
+ const GDBMI::Value& content = r["memory"][0]["data"];
+
+ amount_ = content.size();
+
+ startAsString_ = rangeSelector_->startAddressLineEdit->text();
+ amountAsString_ = rangeSelector_->amountLineEdit->text();
+ start_ = startAsString_.toUInt(0, 0);
+
+ setCaption(QString("%1 (%2 bytes)")
+ .arg(startAsString_).arg(amount_));
+ emit captionChanged(caption());
+
+ KHE::BytesEditInterface* bytesEditor
+ = KHE::bytesEditInterface(khexedit2_widget);
+
+ delete[] this->data_;
+ this->data_ = new char[amount_];
+ for(unsigned i = 0; i < content.size(); ++i)
+ {
+ this->data_[i] = content[i].literal().toInt(0, 16);
+ }
+
+
+ bytesEditor->setData( this->data_, amount_ );
+ bytesEditor->setReadOnly(false);
+ // Overwrite data, not insert new
+ bytesEditor->setOverwriteMode( true );
+ // Not sure this is needed, but prevent
+ // inserting new data.
+ bytesEditor->setOverwriteOnly( true );
+
+ QVariant start_v(start_);
+ khexedit2_real_widget->setProperty("FirstLineOffset", start_v);
+
+ //QVariant bsw(0);
+ //khexedit2_real_widget->setProperty("ByteSpacingWidth", bsw);
+
+ // HACK: use hardcoded constant taht should match
+ // khexedit2
+ // 3 -- binary
+ // 1 -- decimal
+ // 0 -- hex
+ //QVariant coding(1);
+ //khexedit2_real_widget->setProperty("Coding", coding);
+
+
+ slotHideRangeDialog();
+ }
+
+
+ void MemoryView::memoryEdited(int start, int end)
+ {
+ for(int i = start; i <= end; ++i)
+ {
+ controller_->addCommand(
+ new GDBCommand(
+ QString("set *(char*)(%1 + %2) = %3")
+ .arg(start_)
+ .arg(i)
+ .arg(QString::number(data_[i]))));
+ }
+ }
+
+ void MemoryView::contextMenuEvent ( QContextMenuEvent * e )
+ {
+ if (!isOk())
+ return;
+
+ QPopupMenu menu;
+
+ bool app_running = !(debuggerState_ & s_appNotStarted);
+
+ int idRange = menu.insertItem(i18n("Change memory range"));
+ // If address selector is show, 'set memory range' can't
+ // do anything more.
+ menu.setItemEnabled(idRange,
+ app_running && !rangeSelector_->isShown());
+ int idReload = menu.insertItem(i18n("Reload"));
+ // If amount is zero, it means there's not data yet, so
+ // reloading does not make sense.
+ menu.setItemEnabled(idReload, app_running && amount_ != 0);
+ int idClose = menu.insertItem(i18n("Close this view"));
+
+ int result = menu.exec(e->globalPos());
+
+ if (result == idRange)
+ {
+ rangeSelector_->startAddressLineEdit->setText(startAsString_);
+ rangeSelector_->amountLineEdit->setText(amountAsString_);
+
+ rangeSelector_->show();
+ rangeSelector_->startAddressLineEdit->setFocus();
+ }
+ if (result == idReload)
+ {
+ // We use numeric start_ and amount_ stored in this,
+ // not textual startAsString_ and amountAsString_,
+ // because program position might have changes and expressions
+ // are no longer valid.
+ controller_->addCommand(
+ new
+ GDBCommand(
+ QString("-data-read-memory %1 x 1 1 %2")
+ .arg(start_).arg(amount_).ascii(),
+ this,
+ &MemoryView::memoryRead));
+ }
+
+ if (result == idClose)
+ delete this;
+
+
+ }
+
+ bool MemoryView::isOk() const
+ {
+ return khexedit2_real_widget;
+ }
+
+ void MemoryView::slotEnableOrDisable()
+ {
+ bool app_started = !(debuggerState_ & s_appNotStarted);
+
+ bool enabled_ = app_started &&
+ !rangeSelector_->startAddressLineEdit->text().isEmpty() &&
+ !rangeSelector_->amountLineEdit->text().isEmpty();
+
+ rangeSelector_->okButton->setEnabled(enabled_);
+ }
+
+
+ ViewerWidget::ViewerWidget(GDBController* controller,
+ QWidget* parent,
+ const char* name)
+ : QWidget(parent, name),
+ controller_(controller)
+ {
+ setIcon(SmallIcon("math_brace"));
+
+ QVBoxLayout *l = new QVBoxLayout(this, 0, 0);
+
+ toolBox_ = new QToolBox(this);
+ l->addWidget(toolBox_);
+ }
+
+ void ViewerWidget::slotAddMemoryView()
+ {
+ // For unclear reasons, this call, that indirectly
+ // does
+ //
+ // mainWindow()->setViewAvailable(this)
+ // mainWindow()->raiseView(this)
+ //
+ // should be done before creating the child widget.
+ // Otherwise, the child widget won't be freely resizable --
+ // there will be not-so-small minimum size.
+ // Problem exists both with KMDI and S/IDEAL.
+
+ setViewShown(true);
+
+ MemoryView* widget = new MemoryView(controller_, this);
+ toolBox_->addItem(widget, widget->caption());
+ toolBox_->setCurrentItem(widget);
+ memoryViews_.push_back(widget);
+
+ connect(widget, SIGNAL(captionChanged(const QString&)),
+ this, SLOT(slotChildCaptionChanged(const QString&)));
+
+ connect(widget, SIGNAL(destroyed(QObject*)),
+ this, SLOT(slotChildDestroyed(QObject*)));
+ }
+
+ void ViewerWidget::slotDebuggerState(const QString&, int state)
+ {
+ for(unsigned i = 0; i < memoryViews_.size(); ++i)
+ {
+ memoryViews_[i]->debuggerStateChanged(state);
+ }
+ }
+
+ void ViewerWidget::slotChildCaptionChanged(const QString& caption)
+ {
+ const QWidget* s = static_cast<const QWidget*>(sender());
+ QWidget* ncs = const_cast<QWidget*>(s);
+ QString cap = caption;
+ // Prevent intepreting '&' as accelerator specifier.
+ cap.replace("&", "&&");
+ toolBox_->setItemLabel(toolBox_->indexOf(ncs), cap);
+ }
+
+ void ViewerWidget::slotChildDestroyed(QObject* child)
+ {
+ QValueVector<MemoryView*>::iterator i, e;
+ for(i = memoryViews_.begin(), e = memoryViews_.end(); i != e; ++i)
+ {
+ if (*i == child)
+ {
+ memoryViews_.erase(i);
+ break;
+ }
+ }
+
+ if (toolBox_->count() == 0)
+ setViewShown(false);
+ }
+
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+
+}
+
+#include "memviewdlg.moc"