ADA: Add task browser.

This commit is contained in:
Ernie Pasveer
2023-03-29 20:19:43 -05:00
parent 8b6d37eae4
commit a55b33cb9b
11 changed files with 348 additions and 4 deletions
+2 -1
View File
@@ -7,7 +7,8 @@
the Debug dialog for the Run mode. Some apps use deferred loading of code
with dlopen().
* Fixed bug when restoring from project file with 'start' mode.
* Improve visualizers for Ada arrays. "(system.address) 0x7fffffffcf10"
* ADA: Improve visualizers for Ada arrays. "(system.address) 0x7fffffffcf10"
* ADA: Add task browser.
* Add a Shortcut (CTRL-I) to interrupt the running program.
## [1.15] - 2023-03-04
+2
View File
@@ -72,6 +72,7 @@ set(HEADER_FILES
SeerThreadFramesBrowserWidget.h
SeerThreadIdsBrowserWidget.h
SeerThreadGroupsBrowserWidget.h
SeerAdaTasksBrowserWidget.h
SeerThreadManagerWidget.h
SeerGdbLogWidget.h
SeerTildeLogWidget.h
@@ -158,6 +159,7 @@ set(SOURCE_FILES
SeerThreadFramesBrowserWidget.cpp
SeerThreadIdsBrowserWidget.cpp
SeerThreadGroupsBrowserWidget.cpp
SeerAdaTasksBrowserWidget.cpp
SeerThreadManagerWidget.cpp
SeerGdbLogWidget.cpp
SeerTildeLogWidget.cpp
+185
View File
@@ -0,0 +1,185 @@
#include "SeerAdaTasksBrowserWidget.h"
#include "SeerUtl.h"
#include <QtWidgets/QTreeWidget>
#include <QtWidgets/QTreeWidgetItemIterator>
#include <QtWidgets/QApplication>
#include <QtCore/QFileInfo>
#include <QtCore/QDebug>
SeerAdaTasksBrowserWidget::SeerAdaTasksBrowserWidget (QWidget* parent) : QWidget(parent) {
// Construct the UI.
setupUi(this);
// Setup the widgets
adaTaskTreeWidget->setMouseTracking(true);
adaTaskTreeWidget->setSortingEnabled(false);
adaTaskTreeWidget->resizeColumnToContents(0); // current
adaTaskTreeWidget->resizeColumnToContents(1); // id
adaTaskTreeWidget->resizeColumnToContents(2); // taskid
adaTaskTreeWidget->resizeColumnToContents(3); // threadid
adaTaskTreeWidget->resizeColumnToContents(4); // parentid
adaTaskTreeWidget->resizeColumnToContents(5); // priority
adaTaskTreeWidget->resizeColumnToContents(6); // state
adaTaskTreeWidget->resizeColumnToContents(7); // name
adaTaskTreeWidget->clear();
// Connect things.
QObject::connect(adaTaskTreeWidget, &QTreeWidget::itemClicked, this, &SeerAdaTasksBrowserWidget::handleItemClicked);
}
SeerAdaTasksBrowserWidget::~SeerAdaTasksBrowserWidget () {
}
void SeerAdaTasksBrowserWidget::handleText (const QString& text) {
// Don't do any work if the widget is hidden.
if (isHidden()) {
return;
}
QApplication::setOverrideCursor(Qt::BusyCursor);
if (text.startsWith("^done,tasks={")) {
// -ada-task-info [ task-id ]
// ^done,tasks={
// nr_rows="3",
// nr_cols="8",
// hdr=[
// {
// width="1",alignment="-1",col_name="current",colhdr=""
// },
// {
// width="3",alignment="1",col_name="id",colhdr="ID"
// },
// {
// width="9",alignment="1",col_name="task-id",colhdr="TID"
// },
// {
// width="4",alignment="1",col_name="thread-id",colhdr=""
// },
// {
// width="4",alignment="1",col_name="parent-id",colhdr="P-ID"
// },
// {
// width="3",alignment="1",col_name="priority",colhdr="Pri"
// },
// {
// width="22",alignment="-1",col_name="state",colhdr="State"
// },
// {
// width="1",alignment="2",col_name="name",colhdr="Name"
// }
// ],
// body=[
// {
// id="1",task-id="45d030",thread-id="1",priority="48",state="Waiting on RV with 2 ",name="main_task"
// },
// {
// current="*",id="2",task-id="45de30",thread-id="2",parent-id="1",priority="48",state="Runnable",name="task_a"
// },
// {
// id="3",task-id="461460",thread-id="3",parent-id="1",priority="48",state="Delay Sleep",name="task_b"
// }
// ]
// }
//qDebug() << text;
adaTaskTreeWidget->clear();
QString body_text = Seer::parseFirst(text, "body=", '[', ']', false);
//qDebug() << threads_text;
if (body_text != "") {
QStringList tasks_list = Seer::parse(body_text, "", '{', '}', false);
for ( const auto& task_text : tasks_list ) {
QString current_text = Seer::parseFirst(task_text, "current=", '"', '"', false);
QString id_text = Seer::parseFirst(task_text, "id=", '"', '"', false);
QString taskid_text = Seer::parseFirst(task_text, "task-id=", '"', '"', false);
QString threadid_text = Seer::parseFirst(task_text, "thread-id=", '"', '"', false);
QString parentid_text = Seer::parseFirst(task_text, "parent-id=", '"', '"', false);
QString priority_text = Seer::parseFirst(task_text, "priority=", '"', '"', false);
QString state_text = Seer::parseFirst(task_text, "state=", '"', '"', false);
QString name_text = Seer::parseFirst(task_text, "name=", '"', '"', false);
// Create the item.
QTreeWidgetItem* item = new QTreeWidgetItem;
item->setText(0, current_text);
item->setText(1, id_text);
item->setText(2, taskid_text);
item->setText(3, threadid_text);
item->setText(4, parentid_text);
item->setText(5, priority_text);
item->setText(6, state_text);
item->setText(7, name_text);
// Add the frame to the tree.
adaTaskTreeWidget->addTopLevelItem(item);
}
}
// Clear the selection and select the one for the current thread-id.
adaTaskTreeWidget->clearSelection();
QList<QTreeWidgetItem*> matches = adaTaskTreeWidget->findItems("*", Qt::MatchExactly, 0);
if (matches.size() > 0) {
adaTaskTreeWidget->setCurrentItem(matches.first());
}
}else if (text.startsWith("^error,msg=\"No registers.\"")) {
adaTaskTreeWidget->clear();
}else{
// Ignore others.
}
adaTaskTreeWidget->resizeColumnToContents(0);
adaTaskTreeWidget->resizeColumnToContents(1);
adaTaskTreeWidget->resizeColumnToContents(2);
adaTaskTreeWidget->resizeColumnToContents(3);
adaTaskTreeWidget->resizeColumnToContents(4);
adaTaskTreeWidget->resizeColumnToContents(5);
adaTaskTreeWidget->resizeColumnToContents(6);
adaTaskTreeWidget->resizeColumnToContents(7);
QApplication::restoreOverrideCursor();
}
void SeerAdaTasksBrowserWidget::handleStoppingPointReached () {
// Don't do any work if the widget is hidden.
if (isHidden()) {
return;
}
refresh();
}
void SeerAdaTasksBrowserWidget::handleItemClicked (QTreeWidgetItem* item, int column) {
Q_UNUSED(column);
emit selectedThread(item->text(3).toInt());
}
void SeerAdaTasksBrowserWidget::refresh () {
emit refreshAdaTasks();
}
void SeerAdaTasksBrowserWidget::showEvent (QShowEvent* event) {
QWidget::showEvent(event);
refresh();
}
+32
View File
@@ -0,0 +1,32 @@
#pragma once
#include <QtWidgets/QWidget>
#include <QtCore/QString>
#include "ui_SeerAdaTasksBrowserWidget.h"
class SeerAdaTasksBrowserWidget : public QWidget, protected Ui::SeerAdaTasksBrowserWidgetForm {
Q_OBJECT
public:
explicit SeerAdaTasksBrowserWidget (QWidget* parent = 0);
~SeerAdaTasksBrowserWidget ();
public slots:
void handleText (const QString& text);
void handleStoppingPointReached ();
void refresh ();
protected slots:
void handleItemClicked (QTreeWidgetItem* item, int column);
signals:
void refreshAdaTasks ();
void selectedThread (int threadid);
protected:
void showEvent (QShowEvent* event);
private:
};
+73
View File
@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SeerAdaTasksBrowserWidgetForm</class>
<widget class="QWidget" name="SeerAdaTasksBrowserWidgetForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>794</width>
<height>528</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTreeWidget" name="adaTaskTreeWidget">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="columnCount">
<number>8</number>
</property>
<column>
<property name="text">
<string>Active</string>
</property>
</column>
<column>
<property name="text">
<string>Id</string>
</property>
</column>
<column>
<property name="text">
<string>Task Id</string>
</property>
</column>
<column>
<property name="text">
<string>Thread Id</string>
</property>
</column>
<column>
<property name="text">
<string>Parent Id</string>
</property>
</column>
<column>
<property name="text">
<string>Priority</string>
</property>
</column>
<column>
<property name="text">
<string>State</string>
</property>
</column>
<column>
<property name="text">
<string>Name</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="resource.qrc"/>
</resources>
<connections/>
</ui>
+16 -1
View File
@@ -172,6 +172,7 @@ SeerGdbWidget::SeerGdbWidget (QWidget* parent) : QWidget(parent) {
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::handleText);
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::handleText);
QObject::connect(_gdbMonitor, &GdbMonitor::equalTextOutput, threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::handleText);
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, threadManagerWidget->adaTasksBrowserWidget(), &SeerAdaTasksBrowserWidget::handleText);
QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::refreshBreakpointsList, this, &SeerGdbWidget::handleGdbGenericpointList);
QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::refreshStackFrames, this, &SeerGdbWidget::handleGdbStackListFrames);
@@ -256,6 +257,10 @@ SeerGdbWidget::SeerGdbWidget (QWidget* parent) : QWidget(parent) {
QObject::connect(threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::startThreadGroup, this, &SeerGdbWidget::handleGdbStartThreadGroup);
QObject::connect(threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::continueThreadGroup, this, &SeerGdbWidget::handleGdbContinueThreadGroup);
QObject::connect(threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::interruptThreadGroup, this, &SeerGdbWidget::handleGdbInterruptThreadGroup);
QObject::connect(threadManagerWidget->adaTasksBrowserWidget(), &SeerAdaTasksBrowserWidget::refreshAdaTasks, this, &SeerGdbWidget::handleGdbAdaListTasks);
QObject::connect(threadManagerWidget->adaTasksBrowserWidget(), &SeerAdaTasksBrowserWidget::selectedThread, this, &SeerGdbWidget::handleGdbThreadSelectId);
QObject::connect(threadManagerWidget, &SeerThreadManagerWidget::schedulerLockingModeChanged, this, &SeerGdbWidget::handleGdbSchedulerLockingMode);
QObject::connect(threadManagerWidget, &SeerThreadManagerWidget::scheduleMultipleModeChanged, this, &SeerGdbWidget::handleGdbScheduleMultipleMode);
QObject::connect(threadManagerWidget, &SeerThreadManagerWidget::forkFollowsModeChanged, this, &SeerGdbWidget::handleGdbForkFollowMode);
@@ -290,8 +295,9 @@ SeerGdbWidget::SeerGdbWidget (QWidget* parent) : QWidget(parent) {
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::handleStoppingPointReached);
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::handleStoppingPointReached);
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::handleStoppingPointReached);
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::handleStoppingPointReached);
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::handleStoppingPointReached);
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::handleStoppingPointReached);
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, threadManagerWidget->adaTasksBrowserWidget(), &SeerAdaTasksBrowserWidget::handleStoppingPointReached);
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, variableManagerWidget->registerValuesBrowserWidget(), &SeerRegisterValuesBrowserWidget::handleStoppingPointReached);
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::handleStoppingPointReached);
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, _breakpointsBrowserWidget, &SeerBreakpointsBrowserWidget::handleStoppingPointReached);
@@ -1878,6 +1884,15 @@ void SeerGdbWidget::handleGdbThreadSelectId (int threadid) {
emit stoppingPointReached();
}
void SeerGdbWidget::handleGdbAdaListTasks () {
if (executableLaunchMode() == "") {
return;
}
handleGdbCommand("-ada-task-info ");
}
void SeerGdbWidget::handleGdbRegisterListNames () {
if (executableLaunchMode() == "") {
+1
View File
@@ -264,6 +264,7 @@ class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm {
void handleGdbThreadListIds ();
void handleGdbThreadListGroups ();
void handleGdbThreadSelectId (int threadid);
void handleGdbAdaListTasks ();
void handleGdbRegisterListNames ();
void handleGdbRegisterListValues (QString fmt);
void handleGdbRegisterSetValue (QString fmt, QString name, QString value);
+4
View File
@@ -738,6 +738,10 @@ void SeerMainWindow::handleText (const QString& text) {
return;
}
if (newtext == "^error,msg=\"Cannot inspect Ada tasks when program is not running\"") {
return;
}
// Display the error message.
QString msg_text = Seer::parseFirst(text, "msg=", false);
+7
View File
@@ -22,10 +22,12 @@ SeerThreadManagerWidget::SeerThreadManagerWidget (QWidget* parent) : QWidget(par
_threadFramesBrowserWidget = new SeerThreadFramesBrowserWidget(this);
_threadIdsBrowserWidget = new SeerThreadIdsBrowserWidget(this);
_threadGroupsBrowserWidget = new SeerThreadGroupsBrowserWidget(this);
_adaTasksBrowserWidget = new SeerAdaTasksBrowserWidget(this);
tabWidget->addTab(_threadFramesBrowserWidget, "Frames");
tabWidget->addTab(_threadIdsBrowserWidget, "Ids");
tabWidget->addTab(_threadGroupsBrowserWidget, "Groups");
tabWidget->addTab(_adaTasksBrowserWidget, "AdaTasks");
QToolButton* refreshToolButton = new QToolButton(tabWidget);
refreshToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/view-refresh.svg"));
@@ -70,6 +72,10 @@ SeerThreadGroupsBrowserWidget* SeerThreadManagerWidget::threadGroupsBrowserWidge
return _threadGroupsBrowserWidget;
}
SeerAdaTasksBrowserWidget* SeerThreadManagerWidget::adaTasksBrowserWidget () {
return _adaTasksBrowserWidget;
}
void SeerThreadManagerWidget::setSchedulerLockingMode (const QString& mode) {
schedulerLockingComboBox->setCurrentText(mode);
@@ -105,6 +111,7 @@ void SeerThreadManagerWidget::handleRefreshToolButtonClicked () {
threadFramesBrowserWidget()->refresh();
threadIdsBrowserWidget()->refresh();
threadGroupsBrowserWidget()->refresh();
adaTasksBrowserWidget()->refresh();
}
void SeerThreadManagerWidget::handleHelpToolButtonClicked () {
+3
View File
@@ -3,6 +3,7 @@
#include "SeerThreadFramesBrowserWidget.h"
#include "SeerThreadIdsBrowserWidget.h"
#include "SeerThreadGroupsBrowserWidget.h"
#include "SeerAdaTasksBrowserWidget.h"
#include <QtWidgets/QWidget>
@@ -19,6 +20,7 @@ class SeerThreadManagerWidget : public QWidget, protected Ui::SeerThreadManagerW
SeerThreadFramesBrowserWidget* threadFramesBrowserWidget ();
SeerThreadIdsBrowserWidget* threadIdsBrowserWidget ();
SeerThreadGroupsBrowserWidget* threadGroupsBrowserWidget ();
SeerAdaTasksBrowserWidget* adaTasksBrowserWidget ();
signals:
void schedulerLockingModeChanged (const QString& mode);
@@ -52,5 +54,6 @@ class SeerThreadManagerWidget : public QWidget, protected Ui::SeerThreadManagerW
SeerThreadFramesBrowserWidget* _threadFramesBrowserWidget;
SeerThreadIdsBrowserWidget* _threadIdsBrowserWidget;
SeerThreadGroupsBrowserWidget* _threadGroupsBrowserWidget;
SeerAdaTasksBrowserWidget* _adaTasksBrowserWidget;
};
+23 -2
View File
@@ -33,7 +33,8 @@ This information is shown for each Thread Id:
Clicking on a Thread Id will cause Seer to make that Thread Id the active thread. This will in turn cause the Stack Info Browser to refer to that Thread Id.
### Ids
Ids is a simplified list ofThread Ids, with no other information. Clicking on a Thread Id will cause Seer to make that Thread Id the active thread. This will in turn cause the Stack Info Browser to refer to that Thread Id.
Ids is a simplified list of Thread Ids, with no other information. Clicking on a Thread Id will cause Seer to make that Thread Id the active thread.
This will in turn cause the Stack Info Browser to refer to that Thread Id.
### Groups
Groups is a list of Thread Groups. Basically, inferior processes. Most programs are just one inferior, even if they use threads. Program's that use fork and exec will have multiple inferiors.
@@ -48,6 +49,25 @@ This information is shown for each Thread Id:
Executable The name and path of the process executable
Cores List of cpu cores used by the process
```
### AdaTasks
When debugging an Ada program, this view will show the state of all Ada tasks. Clicking on a Task Id will cause that Task Id to be the active task.
This will in turn cause the Stack Info Browser to refer to the thread for that Task Id.
This information is shown for each Task Id:
```
Column Description
--------------- ----------------------------------------------
Active The current task that is active
Id The identifier that GDB uses to refer to the Ada task
Task Id The identifier that the target uses to refer to the Ada task
Thread Id The global thread identifier of the thread corresponding to the Ada task
Parent Id This field exists only when the task was created by another task.
In this case, it provides the ID of the parent task
Priority The base priority of the task
State The current state of the task
Name The name of the task
```
### Scheduler Locking mode
* Record. Behaves like 'off' in 'record' mode and like 'on' in 'replay' mode. This is the default.
@@ -76,5 +96,6 @@ Consult these gdb references
1. [Link](https://sourceware.org/gdb/onlinedocs/gdb/Threads.html#thread-ID-lists) Listing thread information.
2. [Link](https://sourceware.org/gdb/onlinedocs/gdb/All_002dStop-Mode.html#All_002dStop-Mode) GDB all-stop mode.
3. [Link](https://sourceware.org/gdb/onlinedocs/gdb/Forks.html) GDB follow-fork mode.
3. [Link](https://sourceware.org/gdb/onlinedocs/gdb/Process-Record-and-Replay.html) GDB Record or Replay mode.
4. [Link](https://sourceware.org/gdb/onlinedocs/gdb/Process-Record-and-Replay.html) GDB Record or Replay mode.
5. [Link](https://sourceware.org/gdb/download/onlinedocs/gdb/Ada-Tasks.html) Ada tasks.