diff --git a/.gitignore b/.gitignore index 576e341..b532a7a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ icons/ -.swp +*.swp .nfs* diff --git a/src/SeerGdbWidget.cpp b/src/SeerGdbWidget.cpp index 4520118..fbc486c 100644 --- a/src/SeerGdbWidget.cpp +++ b/src/SeerGdbWidget.cpp @@ -3208,6 +3208,15 @@ void SeerGdbWidget::handleGdbGetSourceAndAssembly (QString address) { handleGdbCommand(command); } +void SeerGdbWidget::handleGdbParallelStackFrames (int expressionid) { + + if (executableLaunchMode() == "") { + return; + } + + handleGdbCommand(QString::number(expressionid) + "-frames-list"); +} + void SeerGdbWidget::handleGdbMemoryVisualizer () { handleGdbMemoryAddExpression(""); @@ -3248,8 +3257,9 @@ void SeerGdbWidget::handleGdbParallelStacksVisualizer () { w->show(); // Connect things. - QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerParallelStacksVisualizerWidget::handleText); - QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerParallelStacksVisualizerWidget::handleText); + QObject::connect(w, &SeerParallelStacksVisualizerWidget::refreshParallelStackFrames, this, &SeerGdbWidget::handleGdbParallelStackFrames); + QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerParallelStacksVisualizerWidget::handleText); + QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerParallelStacksVisualizerWidget::handleText); } void SeerGdbWidget::handleSplitterMoved (int pos, int index) { diff --git a/src/SeerGdbWidget.h b/src/SeerGdbWidget.h index 8209819..dffdac5 100644 --- a/src/SeerGdbWidget.h +++ b/src/SeerGdbWidget.h @@ -363,6 +363,7 @@ class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm { void handleGdbArrayEvaluateExpression (int expressionid, QString address, int count); void handleGdbGetAssembly (QString address); void handleGdbGetSourceAndAssembly (QString address); + void handleGdbParallelStackFrames (int expressionid); void handleGdbMemoryVisualizer (); void handleGdbArrayVisualizer (); void handleGdbMatrixVisualizer (); diff --git a/src/SeerMemoryVisualizerWidget.cpp b/src/SeerMemoryVisualizerWidget.cpp index 339213a..4764545 100644 --- a/src/SeerMemoryVisualizerWidget.cpp +++ b/src/SeerMemoryVisualizerWidget.cpp @@ -229,7 +229,7 @@ void SeerMemoryVisualizerWidget::handleText (const QString& text) { QStringList range_list = Seer::parse(memory_text, "", '{', '}', false); // Loop through the memory ranges. - for ( const auto& range_text : range_list ) { + for ( const auto& range_text : range_list ) { QString contents_text = Seer::parseFirst(range_text, "contents=", '"', '"', false); diff --git a/src/SeerParallelStacksVisualizerWidget.cpp b/src/SeerParallelStacksVisualizerWidget.cpp index 56f40bc..d0dcd3f 100644 --- a/src/SeerParallelStacksVisualizerWidget.cpp +++ b/src/SeerParallelStacksVisualizerWidget.cpp @@ -12,8 +12,170 @@ #include #include #include +#include #include +namespace Seer::PSV { + + class Frame { + public: + Frame (); + Frame (const QString& text); + ~Frame (); + + int level () const; + const QString& addr () const; + const QString& function () const; + const QString& arch () const; + const QString& file () const; + const QString& fullname () const; + int line () const; + const QString& type () const; + + private: + int _level; + QString _addr; + QString _function; + QString _arch; + QString _file; + QString _fullname; + int _line; + QString _type; + }; + + typedef QVector FramesVector; + + Frame::Frame() { + } + + Frame::Frame(const QString& text) { + + _level = Seer::parseFirst(text, "level=", '"', '"', false).toInt(); + _addr = Seer::parseFirst(text, "addr=", '"', '"', false); + _function = Seer::parseFirst(text, "func=", '"', '"', false); + _arch = Seer::parseFirst(text, "arch=", '"', '"', false); + _file = Seer::parseFirst(text, "file=", '"', '"', false); + _fullname = Seer::parseFirst(text, "fullname=", '"', '"', false); + _line = Seer::parseFirst(text, "line=", '"', '"', false).toInt(); + _type = Seer::parseFirst(text, "type=", '"', '"', false); + } + + Frame::~Frame() { + } + + int Frame::level () const { + return _level; + } + + const QString& Frame::addr () const { + return _addr; + } + + const QString& Frame::function () const { + return _function; + } + + const QString& Frame::arch () const { + return _arch; + } + + const QString& Frame::file () const { + return _file; + } + + const QString& Frame::fullname () const { + return _fullname; + } + + int Frame::line () const { + return _line; + } + + const QString& Frame::type () const { + return _type; + } + + class Thread { + public: + Thread (); + Thread (const QString& text); + ~Thread (); + + int id () const; + const QString& target_id () const; + const QString& name () const; + const QString& state () const; + int current () const; + + int frameCount () const; + const Frame& frame (int i) const; + + private: + int _id; + QString _target_id; + QString _name; + QString _state; + int _current; + + FramesVector _frames; + }; + + typedef QVector ThreadsVector; + + Thread::Thread () { + } + + Thread::Thread (const QString& text) { + + _id = Seer::parseFirst(text, "thread-id=", '"', '"', false).toInt(); + _target_id = Seer::parseFirst(text, "target-id=", '"', '"', false); + _name = Seer::parseFirst(text, "name=", '"', '"', false); + _current = Seer::parseFirst(text, "current=", '"', '"', false).toInt(); + + QString frames_text = Seer::parseFirst(text, "frames=", '[', ']', false); + + QStringList frame_list = Seer::parse(frames_text, "", '{', '}', false); + + // Loop through each thread. + for (const auto& frame_text : frame_list) { + Frame frame(frame_text); + _frames.push_back(frame); + } + } + + Thread::~Thread () { + } + + int Thread::id () const { + return _id; + } + + const QString& Thread::target_id () const { + return _target_id; + } + + const QString& Thread::name () const { + return _name; + } + + const QString& Thread::state () const { + return _state; + } + + int Thread::current () const { + return _current; + } + + int Thread::frameCount () const { + return _frames.size(); + } + + const Frame& Thread::frame (int i) const { + return _frames[i]; + } +}; + + SeerParallelStacksVisualizerWidget::SeerParallelStacksVisualizerWidget (QWidget* parent) : QWidget(parent) { // Init variables. @@ -44,7 +206,45 @@ void SeerParallelStacksVisualizerWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); - qDebug() << text; + if (text.contains(QRegularExpression("^([0-9]+)\\^done,frames="))) { + + // 4^done,frames=[ + // {thread-id="10",target-id="(26131, 26146, 0)",name="hellothreads5",state="stopped",current="0", + // frames=[ + // {level="0",addr="0x7ffff78a3c1e",func="__futex_abstimed_wait_common",arch="i386:x86-64",from="/lib64/libc.so.6",type="normal"}, + // {level="1",addr="0x7ffff78a6548",func="pthread_cond_wait@@GLIBC_2.3.2",arch="i386:x86-64",from="/lib64/libc.so.6",type="normal"}, + // {level="2",addr="0x404357",func="w2",arch="i386:x86-64",file="hellothreads5.cpp",fullname="/nas/erniep/Development/seer/tests/hellothreads5/hellothreads5.cpp",line="22",type="normal"}, + // ] + // }, + // ], + // current_thread_id="1",current_frame_level="0",total_threads="11",total_frames="128" + + QString id_text = text.section('^', 0,0); + + if (id_text.toInt() == _id) { + + Seer::PSV::ThreadsVector threads; + + QString result_text = Seer::parseFirst(text, "frames=", '[', ']', false); + + QStringList thread_list = Seer::parse(result_text, "", '{', '}', false); + + // Loop through each thread. + for (const auto& thread_text : thread_list) { + + Seer::PSV::Thread thread(thread_text); + + threads.push_back(thread); + + //qDebug().noquote() << thread_text; + //qDebug() << thread_id_text << target_id_text << name_text << current_text; + } + + for (const auto& thread : threads ) { + qDebug() << "Thread" << thread.id() << "has" << thread.frameCount() << "frames."; + } + } + } QApplication::restoreOverrideCursor(); }