Finished skip command, for now.

This commit is contained in:
Ernie Pasveer
2025-04-05 09:39:30 -05:00
parent fc0bc06fb6
commit 6853679a4a
10 changed files with 219 additions and 0 deletions
+1
View File
@@ -14,6 +14,7 @@
* Optionally add a timestamp to the Seer and Gdb log widgets.
* Add 'gdbserver debug' checkbox to Connect launch tab. For showing
gdb and gdbserver communication debug information in gdb tab.
* Manage gdb skip commands via a new Skip Browser.
## [2.5] - 2024-12-24
* Console now supports a subset of ANSI color codes.
+56
View File
@@ -1011,6 +1011,7 @@ void SeerGdbWidget::handleGdbRunExecutable (const QString& breakMode) {
handleGdbCommand("-gdb-set non-stop off");
}
handleGdbLoadMICommands();
handleGdbSourceScripts();
}
@@ -1145,6 +1146,7 @@ void SeerGdbWidget::handleGdbAttachExecutable () {
handleGdbCommand("-gdb-set mi-async on"); // Turn on async mode so the 'interrupt' can happen.
}
handleGdbLoadMICommands();
handleGdbSourceScripts();
}
@@ -1219,6 +1221,7 @@ void SeerGdbWidget::handleGdbConnectExecutable () {
break;
}
handleGdbLoadMICommands();
handleGdbSourceScripts();
}
@@ -1434,6 +1437,7 @@ void SeerGdbWidget::handleGdbCoreFileExecutable () {
handleGdbCommand("-gdb-set mi-async on"); // Turn on async mode so the 'interrupt' can happen.
}
handleGdbLoadMICommands();
handleGdbSourceScripts();
}
@@ -3663,6 +3667,58 @@ void SeerGdbWidget::handleGdbForkFollowMode (QString mode) {
}
}
void SeerGdbWidget::handleGdbLoadMICommands () {
// Don't do anything, if isn't running.
if (isGdbRuning() == false) {
return;
}
// Path the MI files in the resources.
QString miPath = ":/seer/resources/mi-python/"; // Resource file path
QDir miDirectory(miPath);
if (!miDirectory.exists()) {
qDebug() << "Directory does not exist:" << miPath;
return;
}
// Get list of MI files.
QFileInfoList miList = miDirectory.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries);
// Print the list.
qDebug() << "Sourcing scripts from:" << miPath;
foreach (QFileInfo miInfo, miList) {
// Open the source file from resources.
QFile miFile(miInfo.absoluteFilePath());
if (!miFile.exists()) {
qDebug() << "Resource file" << miInfo << "does not exist!";
continue;
}
// Destination file path in /tmp.
QString destinationPath = "/tmp/" + miInfo.fileName();
// Copy to temp. Don't check return status. I don't think it works
// if the source is in Resources.
miFile.copy(destinationPath);
// Source it.
if (QFile::exists(destinationPath) == false) {
continue;
}
qDebug() << "source " + miInfo.absoluteFilePath();
QString command = "source " + destinationPath;
handleGdbCommand(command);
}
qDebug() << "Done.";
}
void SeerGdbWidget::handleGdbSourceScripts () {
// Don't do anything, if isn't running.
+1
View File
@@ -345,6 +345,7 @@ class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm {
void handleGdbSchedulerLockingMode (QString mode);
void handleGdbScheduleMultipleMode (QString mode);
void handleGdbForkFollowMode (QString mode);
void handleGdbLoadMICommands ();
void handleGdbSourceScripts ();
void handleGdbProcessFinished (int exitCode, QProcess::ExitStatus exitStatus);
+3
View File
@@ -1004,6 +1004,9 @@ void SeerMainWindow::handleText (const QString& text) {
}else if (text.startsWith("^done,ada-exceptions={") && text.endsWith("}")) {
return;
}else if (text.startsWith("^done,skips=[") && text.endsWith("]")) {
return;
}else if (text.contains(QRegularExpression("^([0-9]+)\\^done"))) {
return;
+2
View File
@@ -79,6 +79,8 @@
<file>resources/help/CorefileDebugMode.md</file>
<file>resources/help/Printpoints.md</file>
<file>resources/help/Skips.md</file>
<file>resources/mi-python/MIEcho.py</file>
<file>resources/mi-python/MISkip.py</file>
</qresource>
</RCC>
@@ -12,6 +12,7 @@ Seer presents this information in three tabs:
* Statics
* Libraries
* Ada exceptions
* Skips
### Source
@@ -108,10 +109,30 @@ This information is shown for each exception:
There is a button to quickly create a catchpoint for a selected exception. Once created, Seer will
stop the program when the exception is raised.
### Skip commands
This browser manages the gdb skip commands you might have set up. A skip will bypass entering a function
when the 'step' command is used. Skips can be described in various ways - filename, function name, and with
glob wildcarding or regex. See the 'gdb skip' reference below.
This information is shown for each exception:
```
Column Description
---------- -------------------------------------------------
Number The skip's interal number.
Enable Is the skip enabled?
Glob Is the skip a file glob wildcard?
File The name of the file. Can be <none> if the skip is a function.
RE Is the skip a function regex?
Function The name of the function. Can be <none> if the skip is a file.
```
Skips can be: added, deleted, enabled, or disabled. As well, they can be saved to Seer's settings or loaded.
### References
Consult these references
1. [Link](https://en.wikipedia.org/wiki/Regular_expression) Regular expressions.
2. [Link](https://en.wikipedia.org/wiki/Glob_(programming)) Unix wildcards.
3. [Link](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Skipping-Over-Functions-and-Files.html) GDB Skip command.
+27
View File
@@ -0,0 +1,27 @@
#
# Gdb's own custon Python MI command.
#
# https://sourceware.org/gdb/current/onlinedocs/gdb.html/GDB_002fMI-Commands-In-Python.html#GDB_002fMI-Commands-In-Python
# https://sourceware.org/gdb/current/onlinedocs/gdb.html/Basic-Python.html#Basic-Python
#
class MIEcho(gdb.MICommand):
"""Echo arguments passed to the command."""
def __init__(self, name, mode):
self._mode = mode
super(MIEcho, self).__init__(name)
def invoke(self, argv):
if self._mode == 'dict':
return { 'dict': { 'argv' : argv } }
elif self._mode == 'list':
return { 'list': argv }
else:
return { 'string': ", ".join(argv) }
MIEcho("-echo-dict", "dict")
MIEcho("-echo-list", "list")
MIEcho("-echo-string", "string")
+96
View File
@@ -0,0 +1,96 @@
import re
#
# Python MI command to manage gdb's "skip" command..
#
# https://sourceware.org/gdb/current/onlinedocs/gdb.html/Skipping-Over-Functions-and-Files.html
#
class MISkip(gdb.MICommand):
"""
Run the 'skip' command.
-skip-list List all skips, including the id for each skip.
-skip-delete Delete a list of skip id's.
-skip-enable Enable a list of skip id's.
-skip-disable Disable a list of skip id's.
-skip-create Functions described in manual syntax will be skipped over when stepping.
-skip-create-file Functions in file will be skipped over when stepping.
-skip-create-gfile Functions in files matching file-glob-pattern will be skipped over when stepping.
-skip-create-function Functions named by linespec or the function containing the line named by linespec will be skipped over when stepping.
-skip-create-rfunction Functions whose name matches regexp will be skipped over when stepping.
See: https://sourceware.org/gdb/current/onlinedocs/gdb.html/Skipping-Over-Functions-and-Files.html
"""
def __init__(self, name, mode):
self._mode = mode
super(MISkip, self).__init__(name)
def invoke(self, argv):
if self._mode == "list":
skipentries = []
result = gdb.execute ("info skip " + " ".join(argv), to_string=True)
lines = result.split("\n")
for line in lines:
if (line == ""):
continue
columns = re.search(r"^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)$", line)
if columns:
if (columns.group(1) == "Num"):
continue
if (columns.group(1) == "Not"):
continue
skipmeta = {}
skipmeta["number"] = columns.group(1)
skipmeta["enable"] = columns.group(2)
skipmeta["glob"] = columns.group(3)
skipmeta["file"] = columns.group(4)
skipmeta["re"] = columns.group(5)
skipmeta["function"] = columns.group(6)
skipentries.append(skipmeta)
return { "skips": skipentries}
elif self._mode == "delete":
gdb.execute ("skip delete " + " ".join(argv), to_string=True)
return None
elif self._mode == "enable":
gdb.execute ("skip enable " + " ".join(argv), to_string=True)
return None
elif self._mode == "disable":
gdb.execute ("skip disable " + " ".join(argv), to_string=True)
return None
elif self._mode == "create":
gdb.execute ("skip \"" + " ".join(argv) + "\"", to_string=True)
return None
elif self._mode == "createfile":
gdb.execute ("skip -file \"" + " ".join(argv) + "\"", to_string=True)
return None
elif self._mode == "creategfile":
gdb.execute ("skip -gfile \"" + " ".join(argv) + "\"", to_string=True)
return None
elif self._mode == "createfunction":
gdb.execute ("skip -function \"" + " ".join(argv) + "\"", to_string=True)
return None
elif self._mode == "createrfunction":
gdb.execute ("skip -rfunction \"" + " ".join(argv) + "\"", to_string=True)
return None
else:
raise gdb.GdbError("skips: Invalid parameter: %s" % self._mode)
MISkip("-skip-list", "list")
MISkip("-skip-delete", "delete")
MISkip("-skip-enable", "enable")
MISkip("-skip-disable", "disable")
MISkip("-skip-create", "create")
MISkip("-skip-create-file", "createfile")
MISkip("-skip-create-gfile", "creategfile")
MISkip("-skip-create-function", "createfunction")
MISkip("-skip-create-rfunction", "createrfunction")
+6
View File
@@ -1,3 +1,9 @@
#
# Gdb's own custon Python MI command.
#
# https://sourceware.org/gdb/current/onlinedocs/gdb.html/GDB_002fMI-Commands-In-Python.html#GDB_002fMI-Commands-In-Python
# https://sourceware.org/gdb/current/onlinedocs/gdb.html/Basic-Python.html#Basic-Python
#
class MIEcho(gdb.MICommand):
"""Echo arguments passed to the command."""
+6
View File
@@ -1,5 +1,11 @@
import re
#
# Python MI command to manage gdb's "skip" command..
#
# https://sourceware.org/gdb/current/onlinedocs/gdb.html/Skipping-Over-Functions-and-Files.html
#
class MISkip(gdb.MICommand):
"""
Run the 'skip' command.