* [PATCH 0/3] Simplify DAP stop reason emission
@ 2023-11-14 18:44 Tom Tromey
2023-11-14 18:44 ` [PATCH 1/3] Move py_ui_out to a new header Tom Tromey
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Tom Tromey @ 2023-11-14 18:44 UTC (permalink / raw)
To: gdb-patches
This patch changes the DAP stop-reason emission to be simpler (on the
DAP side) and also more reliable. Rather than guessing that a stop
occurred because a "step" finished, the DAP code now relies on gdb's
own knowledge of this.
---
Tom Tromey (3):
Move py_ui_out to a new header
Emit stop reason details in Python stop events
Simplify DAP stop-reason code
gdb/NEWS | 4 +
gdb/doc/python.texi | 11 +++
gdb/python/lib/gdb/dap/events.py | 79 ++++++++++++--------
gdb/python/lib/gdb/dap/launch.py | 4 +-
gdb/python/lib/gdb/dap/next.py | 10 +--
gdb/python/lib/gdb/dap/pause.py | 4 +-
gdb/python/py-bpevent.c | 5 +-
gdb/python/py-mi.c | 131 +--------------------------------
gdb/python/py-signalevent.c | 5 +-
gdb/python/py-stopevent.c | 65 +++++++++++++++--
gdb/python/py-stopevent.h | 9 ++-
gdb/python/py-uiout.h | 153 +++++++++++++++++++++++++++++++++++++++
12 files changed, 299 insertions(+), 181 deletions(-)
---
base-commit: c748dbd95bf3305539956053c2a25ecea7b442a5
change-id: 20231114-py-stop-reason-3f141487d90e
Best regards,
--
Tom Tromey <tromey@adacore.com>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/3] Move py_ui_out to a new header
2023-11-14 18:44 [PATCH 0/3] Simplify DAP stop reason emission Tom Tromey
@ 2023-11-14 18:44 ` Tom Tromey
2023-11-14 18:44 ` [PATCH 2/3] Emit stop reason details in Python stop events Tom Tromey
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Tom Tromey @ 2023-11-14 18:44 UTC (permalink / raw)
To: gdb-patches
This moves the declaration of py_ui_out to a new header, so that it
can more readily be used by other code.
---
gdb/python/py-mi.c | 129 +-----------------------------------------
gdb/python/py-uiout.h | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 154 insertions(+), 128 deletions(-)
diff --git a/gdb/python/py-mi.c b/gdb/python/py-mi.c
index a7b4f4fa3cf..2b265ad80d6 100644
--- a/gdb/python/py-mi.c
+++ b/gdb/python/py-mi.c
@@ -19,142 +19,15 @@
#include "defs.h"
#include "python-internal.h"
+#include "py-uiout.h"
#include "utils.h"
#include "ui.h"
-#include "ui-out.h"
#include "interps.h"
#include "target.h"
#include "mi/mi-parse.h"
#include "mi/mi-console.h"
#include "mi/mi-interp.h"
-/* A ui_out subclass that creates a Python object based on the data
- that is passed in. */
-
-class py_ui_out : public ui_out
-{
-public:
-
- py_ui_out ()
- : ui_out (fix_multi_location_breakpoint_output
- | fix_breakpoint_script_output)
- {
- do_begin (ui_out_type_tuple, nullptr);
- }
-
- bool can_emit_style_escape () const override
- { return false; }
-
- bool do_is_mi_like_p () const override
- { return true; }
-
- /* Return the Python object that was created. If a Python error
- occurred during the processing, set the Python error and return
- nullptr. */
- PyObject *result ()
- {
- if (m_error.has_value ())
- {
- m_error->restore ();
- return nullptr;
- }
- return current ().obj.release ();
- }
-
-protected:
-
- void do_progress_end () override { }
- void do_progress_start () override { }
- void do_progress_notify (const std::string &, const char *, double, double)
- override
- { }
-
- void do_table_begin (int nbrofcols, int nr_rows, const char *tblid) override
- {
- do_begin (ui_out_type_list, tblid);
- }
- void do_table_body () override
- { }
- void do_table_end () override
- {
- do_end (ui_out_type_list);
- }
- void do_table_header (int width, ui_align align,
- const std::string &col_name,
- const std::string &col_hdr) override
- { }
-
- void do_begin (ui_out_type type, const char *id) override;
- void do_end (ui_out_type type) override;
-
- void do_field_signed (int fldno, int width, ui_align align,
- const char *fldname, LONGEST value) override;
- void do_field_unsigned (int fldno, int width, ui_align align,
- const char *fldname, ULONGEST value) override;
-
- void do_field_skip (int fldno, int width, ui_align align,
- const char *fldname) override
- { }
-
- void do_field_string (int fldno, int width, ui_align align,
- const char *fldname, const char *string,
- const ui_file_style &style) override;
- void do_field_fmt (int fldno, int width, ui_align align,
- const char *fldname, const ui_file_style &style,
- const char *format, va_list args) override
- ATTRIBUTE_PRINTF (7, 0);
-
- void do_spaces (int numspaces) override
- { }
-
- void do_text (const char *string) override
- { }
-
- void do_message (const ui_file_style &style,
- const char *format, va_list args)
- override ATTRIBUTE_PRINTF (3,0)
- { }
-
- void do_wrap_hint (int indent) override
- { }
-
- void do_flush () override
- { }
-
- void do_redirect (struct ui_file *outstream) override
- { }
-
-private:
-
- /* When constructing Python objects, this class keeps a stack of
- objects being constructed. Each such object has this type. */
- struct object_desc
- {
- /* Name of the field (or empty for lists) that this object will
- eventually become. */
- std::string field_name;
- /* The object under construction. */
- gdbpy_ref<> obj;
- /* The type of structure being created. Note that tables are
- treated as lists here. */
- ui_out_type type;
- };
-
- /* The stack of objects being created. */
- std::vector<object_desc> m_objects;
-
- /* If an error occurred, this holds the exception information for
- use by the 'release' method. */
- gdb::optional<gdbpy_err_fetch> m_error;
-
- /* Return a reference to the object under construction. */
- object_desc ¤t ()
- { return m_objects.back (); }
-
- /* Add a new field to the current object under construction. */
- void add_field (const char *name, const gdbpy_ref<> &obj);
-};
-
void
py_ui_out::add_field (const char *name, const gdbpy_ref<> &obj)
{
diff --git a/gdb/python/py-uiout.h b/gdb/python/py-uiout.h
new file mode 100644
index 00000000000..e9abf8ee5be
--- /dev/null
+++ b/gdb/python/py-uiout.h
@@ -0,0 +1,153 @@
+/* Python implementation of ui_out
+
+ Copyright (C) 2023 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef GDB_PYTHON_PY_UIOUT_H
+#define GDB_PYTHON_PY_UIOUT_H
+
+#include "python-internal.h"
+#include "ui-out.h"
+
+/* A ui_out subclass that creates a Python object based on the data
+ that is passed in. */
+
+class py_ui_out : public ui_out
+{
+public:
+
+ py_ui_out ()
+ : ui_out (fix_multi_location_breakpoint_output
+ | fix_breakpoint_script_output)
+ {
+ do_begin (ui_out_type_tuple, nullptr);
+ }
+
+ bool can_emit_style_escape () const override
+ { return false; }
+
+ bool do_is_mi_like_p () const override
+ { return true; }
+
+ /* Return the Python object that was created. If a Python error
+ occurred during the processing, set the Python error and return
+ nullptr. */
+ PyObject *result ()
+ {
+ if (m_error.has_value ())
+ {
+ m_error->restore ();
+ return nullptr;
+ }
+ return current ().obj.release ();
+ }
+
+protected:
+
+ void do_progress_end () override { }
+ void do_progress_start () override { }
+ void do_progress_notify (const std::string &, const char *, double, double)
+ override
+ { }
+
+ void do_table_begin (int nbrofcols, int nr_rows, const char *tblid) override
+ {
+ do_begin (ui_out_type_list, tblid);
+ }
+ void do_table_body () override
+ { }
+ void do_table_end () override
+ {
+ do_end (ui_out_type_list);
+ }
+ void do_table_header (int width, ui_align align,
+ const std::string &col_name,
+ const std::string &col_hdr) override
+ { }
+
+ void do_begin (ui_out_type type, const char *id) override;
+ void do_end (ui_out_type type) override;
+
+ void do_field_signed (int fldno, int width, ui_align align,
+ const char *fldname, LONGEST value) override;
+ void do_field_unsigned (int fldno, int width, ui_align align,
+ const char *fldname, ULONGEST value) override;
+
+ void do_field_skip (int fldno, int width, ui_align align,
+ const char *fldname) override
+ { }
+
+ void do_field_string (int fldno, int width, ui_align align,
+ const char *fldname, const char *string,
+ const ui_file_style &style) override;
+ void do_field_fmt (int fldno, int width, ui_align align,
+ const char *fldname, const ui_file_style &style,
+ const char *format, va_list args) override
+ ATTRIBUTE_PRINTF (7, 0);
+
+ void do_spaces (int numspaces) override
+ { }
+
+ void do_text (const char *string) override
+ { }
+
+ void do_message (const ui_file_style &style,
+ const char *format, va_list args)
+ override ATTRIBUTE_PRINTF (3,0)
+ { }
+
+ void do_wrap_hint (int indent) override
+ { }
+
+ void do_flush () override
+ { }
+
+ void do_redirect (struct ui_file *outstream) override
+ { }
+
+private:
+
+ /* When constructing Python objects, this class keeps a stack of
+ objects being constructed. Each such object has this type. */
+ struct object_desc
+ {
+ /* Name of the field (or empty for lists) that this object will
+ eventually become. */
+ std::string field_name;
+ /* The object under construction. */
+ gdbpy_ref<> obj;
+ /* The type of structure being created. Note that tables are
+ treated as lists here. */
+ ui_out_type type;
+ };
+
+ /* The stack of objects being created. */
+ std::vector<object_desc> m_objects;
+
+ /* If an error occurred, this holds the exception information for
+ use by the 'release' method. */
+ gdb::optional<gdbpy_err_fetch> m_error;
+
+ /* Return a reference to the object under construction. */
+ object_desc ¤t ()
+ { return m_objects.back (); }
+
+ /* Add a new field to the current object under construction. */
+ void add_field (const char *name, const gdbpy_ref<> &obj);
+};
+
+#endif /* GDB_PYTHON_PY_UIOUT_H */
--
2.41.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/3] Emit stop reason details in Python stop events
2023-11-14 18:44 [PATCH 0/3] Simplify DAP stop reason emission Tom Tromey
2023-11-14 18:44 ` [PATCH 1/3] Move py_ui_out to a new header Tom Tromey
@ 2023-11-14 18:44 ` Tom Tromey
2023-11-14 19:12 ` Eli Zaretskii
2023-11-14 18:44 ` [PATCH 3/3] Simplify DAP stop-reason code Tom Tromey
2023-12-11 18:42 ` [PATCH 0/3] Simplify DAP stop reason emission Tom Tromey
3 siblings, 1 reply; 6+ messages in thread
From: Tom Tromey @ 2023-11-14 18:44 UTC (permalink / raw)
To: gdb-patches
This changes Python stop events to carry a "details" dictionary, that
holds any relevant information about the stop. The details are
constructed using more or less the same procedure as is done for MI.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=13587
---
gdb/NEWS | 4 +++
gdb/doc/python.texi | 11 ++++++++
gdb/python/py-bpevent.c | 5 ++--
gdb/python/py-mi.c | 2 +-
gdb/python/py-signalevent.c | 5 ++--
gdb/python/py-stopevent.c | 65 +++++++++++++++++++++++++++++++++++++++++----
gdb/python/py-stopevent.h | 9 ++++---
gdb/python/py-uiout.h | 4 +--
8 files changed, 90 insertions(+), 15 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index 93fbcf1c13e..12387ad9f4a 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -50,6 +50,10 @@ disable missing-debug-handler LOCUS HANDLER
sub-classed to create handlers for objfiles with missing debug
information.
+ ** Stop events now have a "details" attribute that holds a
+ dictionary that carries the same information as an MI "*stopped"
+ event.
+
* New commands
maintenance info linux-lwps
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index b65991bbad0..ab2abcfc5b1 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -3750,6 +3750,17 @@ registry extend @code{gdb.StopEvent}. As a child of
thread when @value{GDBN} is running in non-stop mode. Refer to
@code{gdb.ThreadEvent} above for more details.
+@code{gdb.StopEvent} has the following additional attributes:
+
+@defvar StopEvent.details
+A dictionary holding any details relevant to the stop. The exact keys
+and values depend on the type of stop, but are identical to the
+corresponding MI output (@pxref{GDB/MI Async Records}).
+
+A dictionary was used for this (rather than adding attributes directly
+to the event object) so that the MI keys could be used unchanged.
+@end defvar
+
Emits @code{gdb.SignalEvent}, which extends @code{gdb.StopEvent}.
This event indicates that the inferior or one of its threads has
diff --git a/gdb/python/py-bpevent.c b/gdb/python/py-bpevent.c
index 00fb625794b..b640ec9ddd9 100644
--- a/gdb/python/py-bpevent.c
+++ b/gdb/python/py-bpevent.c
@@ -24,10 +24,11 @@
references to BREAKPOINT_LIST and FIRST_BP. */
gdbpy_ref<>
-create_breakpoint_event_object (PyObject *breakpoint_list, PyObject *first_bp)
+create_breakpoint_event_object (const gdbpy_ref<> &dict,
+ PyObject *breakpoint_list, PyObject *first_bp)
{
gdbpy_ref<> breakpoint_event_obj
- = create_stop_event_object (&breakpoint_event_object_type);
+ = create_stop_event_object (&breakpoint_event_object_type, dict);
if (breakpoint_event_obj == NULL)
return NULL;
diff --git a/gdb/python/py-mi.c b/gdb/python/py-mi.c
index 2b265ad80d6..04873e86dd3 100644
--- a/gdb/python/py-mi.c
+++ b/gdb/python/py-mi.c
@@ -173,7 +173,7 @@ gdbpy_execute_mi_command (PyObject *self, PyObject *args, PyObject *kw)
return nullptr;
}
- return uiout.result ();
+ return uiout.result ().release ();
}
/* Convert KEY_OBJ into a string that can be used as a field name in MI
diff --git a/gdb/python/py-signalevent.c b/gdb/python/py-signalevent.c
index 93d06706542..edbd9b0a7ec 100644
--- a/gdb/python/py-signalevent.c
+++ b/gdb/python/py-signalevent.c
@@ -21,10 +21,11 @@
#include "py-stopevent.h"
gdbpy_ref<>
-create_signal_event_object (enum gdb_signal stop_signal)
+create_signal_event_object (const gdbpy_ref<> &dict,
+ enum gdb_signal stop_signal)
{
gdbpy_ref<> signal_event_obj
- = create_stop_event_object (&signal_event_object_type);
+ = create_stop_event_object (&signal_event_object_type, dict);
if (signal_event_obj == NULL)
return NULL;
diff --git a/gdb/python/py-stopevent.c b/gdb/python/py-stopevent.c
index 0aa9d5381f8..f395e8c042e 100644
--- a/gdb/python/py-stopevent.c
+++ b/gdb/python/py-stopevent.c
@@ -19,12 +19,61 @@
#include "defs.h"
#include "py-stopevent.h"
+#include "py-uiout.h"
gdbpy_ref<>
-create_stop_event_object (PyTypeObject *py_type)
+create_stop_event_object (PyTypeObject *py_type, const gdbpy_ref<> &dict)
{
gdbpy_ref<> thread = py_get_event_thread (inferior_ptid);
- return create_thread_event_object (py_type, thread.get ());
+ if (thread == nullptr)
+ return nullptr;
+
+ gdbpy_ref<> result = create_thread_event_object (py_type, thread.get ());
+ if (result == nullptr)
+ return nullptr;
+
+ if (evpy_add_attribute (result.get (), "details", dict.get ()) < 0)
+ return nullptr;
+
+ return result;
+}
+
+/* Print BPSTAT to a new Python dictionary. Returns the dictionary,
+ or null if a Python exception occurred. */
+
+static gdbpy_ref<>
+py_print_bpstat (bpstat *bs, enum gdb_signal stop_signal)
+{
+ py_ui_out uiout;
+
+ try
+ {
+ scoped_restore save_uiout = make_scoped_restore (¤t_uiout, &uiout);
+
+ thread_info *tp = inferior_thread ();
+ if (tp->thread_fsm () != nullptr && tp->thread_fsm ()->finished_p ())
+ {
+ async_reply_reason reason = tp->thread_fsm ()->async_reply_reason ();
+ uiout.field_string ("reason", async_reason_lookup (reason));
+ }
+
+ if (stop_signal != GDB_SIGNAL_0 && stop_signal != GDB_SIGNAL_TRAP)
+ print_signal_received_reason (&uiout, stop_signal);
+ else
+ {
+ struct target_waitstatus last;
+ get_last_target_status (nullptr, nullptr, &last);
+
+ bpstat_print (bs, last.kind ());
+ }
+ }
+ catch (const gdb_exception &except)
+ {
+ gdbpy_convert_exception (except);
+ return nullptr;
+ }
+
+ return uiout.result ();
}
/* Callback observers when a stop event occurs. This function will create a
@@ -45,6 +94,10 @@ emit_stop_event (struct bpstat *bs, enum gdb_signal stop_signal)
if (evregpy_no_listeners_p (gdb_py_events.stop))
return 0;
+ gdbpy_ref<> dict = py_print_bpstat (bs, stop_signal);
+ if (dict == nullptr)
+ return -1;
+
/* Add any breakpoint set at this location to the list. */
for (current_bs = bs; current_bs != NULL; current_bs = current_bs->next)
{
@@ -71,7 +124,8 @@ emit_stop_event (struct bpstat *bs, enum gdb_signal stop_signal)
if (list != NULL)
{
- stop_event_obj = create_breakpoint_event_object (list.get (),
+ stop_event_obj = create_breakpoint_event_object (dict,
+ list.get (),
first_bp);
if (stop_event_obj == NULL)
return -1;
@@ -81,7 +135,7 @@ emit_stop_event (struct bpstat *bs, enum gdb_signal stop_signal)
if (stop_signal != GDB_SIGNAL_0
&& stop_signal != GDB_SIGNAL_TRAP)
{
- stop_event_obj = create_signal_event_object (stop_signal);
+ stop_event_obj = create_signal_event_object (dict, stop_signal);
if (stop_event_obj == NULL)
return -1;
}
@@ -90,7 +144,8 @@ emit_stop_event (struct bpstat *bs, enum gdb_signal stop_signal)
be known and this should eventually be unused. */
if (stop_event_obj == NULL)
{
- stop_event_obj = create_stop_event_object (&stop_event_object_type);
+ stop_event_obj = create_stop_event_object (&stop_event_object_type,
+ dict);
if (stop_event_obj == NULL)
return -1;
}
diff --git a/gdb/python/py-stopevent.h b/gdb/python/py-stopevent.h
index 649112f0488..92282c9c413 100644
--- a/gdb/python/py-stopevent.h
+++ b/gdb/python/py-stopevent.h
@@ -22,14 +22,17 @@
#include "py-event.h"
-extern gdbpy_ref<> create_stop_event_object (PyTypeObject *py_type);
+extern gdbpy_ref<> create_stop_event_object (PyTypeObject *py_type,
+ const gdbpy_ref<> &dict);
extern int emit_stop_event (struct bpstat *bs,
enum gdb_signal stop_signal);
-extern gdbpy_ref<> create_breakpoint_event_object (PyObject *breakpoint_list,
+extern gdbpy_ref<> create_breakpoint_event_object (const gdbpy_ref<> &dict,
+ PyObject *breakpoint_list,
PyObject *first_bp);
-extern gdbpy_ref<> create_signal_event_object (enum gdb_signal stop_signal);
+extern gdbpy_ref<> create_signal_event_object (const gdbpy_ref<> &dict,
+ enum gdb_signal stop_signal);
#endif /* PYTHON_PY_STOPEVENT_H */
diff --git a/gdb/python/py-uiout.h b/gdb/python/py-uiout.h
index e9abf8ee5be..6e43b425968 100644
--- a/gdb/python/py-uiout.h
+++ b/gdb/python/py-uiout.h
@@ -46,14 +46,14 @@ class py_ui_out : public ui_out
/* Return the Python object that was created. If a Python error
occurred during the processing, set the Python error and return
nullptr. */
- PyObject *result ()
+ gdbpy_ref<> result ()
{
if (m_error.has_value ())
{
m_error->restore ();
return nullptr;
}
- return current ().obj.release ();
+ return std::move (current ().obj);
}
protected:
--
2.41.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 3/3] Simplify DAP stop-reason code
2023-11-14 18:44 [PATCH 0/3] Simplify DAP stop reason emission Tom Tromey
2023-11-14 18:44 ` [PATCH 1/3] Move py_ui_out to a new header Tom Tromey
2023-11-14 18:44 ` [PATCH 2/3] Emit stop reason details in Python stop events Tom Tromey
@ 2023-11-14 18:44 ` Tom Tromey
2023-12-11 18:42 ` [PATCH 0/3] Simplify DAP stop reason emission Tom Tromey
3 siblings, 0 replies; 6+ messages in thread
From: Tom Tromey @ 2023-11-14 18:44 UTC (permalink / raw)
To: gdb-patches
Now that gdb adds stop-reason details to stop events, we can simplify
the DAP code to emit correct stop reasons in its own events. For the
most part a simple renaming of gdb reasons is sufficient; however,
"pause" must still be handled specially.
---
gdb/python/lib/gdb/dap/events.py | 79 +++++++++++++++++++++++++---------------
gdb/python/lib/gdb/dap/launch.py | 4 +-
gdb/python/lib/gdb/dap/next.py | 10 ++---
gdb/python/lib/gdb/dap/pause.py | 4 +-
4 files changed, 57 insertions(+), 40 deletions(-)
diff --git a/gdb/python/lib/gdb/dap/events.py b/gdb/python/lib/gdb/dap/events.py
index e9ddcab135f..bdd2a6ebadc 100644
--- a/gdb/python/lib/gdb/dap/events.py
+++ b/gdb/python/lib/gdb/dap/events.py
@@ -99,60 +99,79 @@ def _cont(event):
)
-class StopKinds(enum.Enum):
- # The values here are chosen to follow the DAP spec.
- STEP = "step"
- BREAKPOINT = "breakpoint"
- PAUSE = "pause"
- EXCEPTION = "exception"
-
-
-_expected_stop = None
-
-
-@in_gdb_thread
-def expect_stop(reason):
- """Indicate that a stop is expected, for the reason given."""
- global _expected_stop
- _expected_stop = reason
+_expected_pause = False
# A wrapper for Invoker that also sets the expected stop.
class ExecutionInvoker(Invoker):
- """A subclass of Invoker that sets the expected stop.
- Note that this assumes that the command will restart the inferior,
- so it will also cause ContinuedEvents to be suppressed."""
+ """A subclass of Invoker that sets the continue-suppression flag.
- def __init__(self, cmd, expected):
+ When EXPECTED_PAUSE is True, a stop that looks like a pause (e.g.,
+ a SIGINT) will be reported as "pause" instead.
+ """
+
+ def __init__(self, cmd, expected_pause=False):
super().__init__(cmd)
- self.expected = expected
+ self.expected_pause = expected_pause
@in_gdb_thread
def __call__(self):
- expect_stop(self.expected)
+ global _expected_pause
+ _expected_pause = self.expected_pause
global _suppress_cont
_suppress_cont = True
# FIXME if the call fails should we clear _suppress_cont?
super().__call__()
+# Map from gdb stop reasons to DAP stop reasons. Some of these can't
+# be seen ordinarily in DAP -- only if the client lets the user toggle
+# some settings (e.g. stop-on-solib-events) or enter commands (e.g.,
+# 'until').
+stop_reason_map = {
+ "breakpoint-hit": "breakpoint",
+ "watchpoint-trigger": "data breakpoint",
+ "read-watchpoint-trigger": "data breakpoint",
+ "access-watchpoint-trigger": "data breakpoint",
+ "function-finished": "step",
+ "location-reached": "step",
+ "watchpoint-scope": "data breakpoint",
+ "end-stepping-range": "step",
+ "exited-signalled": "exited",
+ "exited": "exited",
+ "exited-normally": "exited",
+ "signal-received": "signal",
+ "solib-event": "solib",
+ "fork": "fork",
+ "vfork": "vfork",
+ "syscall-entry": "syscall-entry",
+ "syscall-return": "syscall-return",
+ "exec": "exec",
+ "no-history": "no-history",
+}
+
+
@in_gdb_thread
def _on_stop(event):
log("entering _on_stop: " + repr(event))
- global _expected_stop
+ log(" details: " + repr(event.details))
obj = {
"threadId": gdb.selected_thread().global_num,
"allThreadsStopped": True,
}
if isinstance(event, gdb.BreakpointEvent):
- # Ignore the expected stop, we hit a breakpoint instead.
- _expected_stop = StopKinds.BREAKPOINT
obj["hitBreakpointIds"] = [x.number for x in event.breakpoints]
- elif _expected_stop is None:
- # FIXME what is even correct here
- _expected_stop = StopKinds.EXCEPTION
- obj["reason"] = _expected_stop.value
- _expected_stop = None
+ global stop_reason_map
+ reason = event.details["reason"]
+ global _expected_pause
+ if (
+ _expected_pause
+ and reason == "signal-received"
+ and event.details["signal-name"] in ("SIGINT", "SIGSTOP")
+ ):
+ obj["reason"] = "pause"
+ else:
+ obj["reason"] = stop_reason_map[reason]
send_event("stopped", obj)
diff --git a/gdb/python/lib/gdb/dap/launch.py b/gdb/python/lib/gdb/dap/launch.py
index d13037fa476..7dead0c7c35 100644
--- a/gdb/python/lib/gdb/dap/launch.py
+++ b/gdb/python/lib/gdb/dap/launch.py
@@ -88,6 +88,4 @@ def attach(*, pid: Optional[int] = None, target: Optional[str] = None, **args):
def config_done(**args):
global _program
if _program is not None:
- # Suppress the continue event, but don't set any particular
- # expected stop.
- send_gdb(ExecutionInvoker("run", None))
+ send_gdb(ExecutionInvoker("run"))
diff --git a/gdb/python/lib/gdb/dap/next.py b/gdb/python/lib/gdb/dap/next.py
index e5bb8d64da0..76c9360383a 100644
--- a/gdb/python/lib/gdb/dap/next.py
+++ b/gdb/python/lib/gdb/dap/next.py
@@ -15,7 +15,7 @@
import gdb
-from .events import StopKinds, ExecutionInvoker
+from .events import ExecutionInvoker
from .server import capability, request
from .startup import in_gdb_thread, send_gdb, send_gdb_with_response
from .state import set_thread
@@ -57,7 +57,7 @@ def next(
cmd = "next"
if granularity == "instruction":
cmd += "i"
- send_gdb(ExecutionInvoker(cmd, StopKinds.STEP))
+ send_gdb(ExecutionInvoker(cmd))
@capability("supportsSteppingGranularity")
@@ -70,17 +70,17 @@ def step_in(
cmd = "step"
if granularity == "instruction":
cmd += "i"
- send_gdb(ExecutionInvoker(cmd, StopKinds.STEP))
+ send_gdb(ExecutionInvoker(cmd))
@request("stepOut")
def step_out(*, threadId: int, singleThread: bool = False, **args):
send_gdb(lambda: _handle_thread_step(threadId, singleThread, True))
- send_gdb(ExecutionInvoker("finish", StopKinds.STEP))
+ send_gdb(ExecutionInvoker("finish"))
@request("continue")
def continue_request(*, threadId: int, singleThread: bool = False, **args):
locked = send_gdb_with_response(lambda: _handle_thread_step(threadId, singleThread))
- send_gdb(ExecutionInvoker("continue", None))
+ send_gdb(ExecutionInvoker("continue"))
return {"allThreadsContinued": not locked}
diff --git a/gdb/python/lib/gdb/dap/pause.py b/gdb/python/lib/gdb/dap/pause.py
index 1e59d630523..a89741cbf69 100644
--- a/gdb/python/lib/gdb/dap/pause.py
+++ b/gdb/python/lib/gdb/dap/pause.py
@@ -13,11 +13,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from .events import StopKinds, ExecutionInvoker
+from .events import ExecutionInvoker
from .server import request
from .startup import send_gdb
@request("pause")
def pause(**args):
- send_gdb(ExecutionInvoker("interrupt -a", StopKinds.PAUSE))
+ send_gdb(ExecutionInvoker("interrupt -a", True))
--
2.41.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/3] Emit stop reason details in Python stop events
2023-11-14 18:44 ` [PATCH 2/3] Emit stop reason details in Python stop events Tom Tromey
@ 2023-11-14 19:12 ` Eli Zaretskii
0 siblings, 0 replies; 6+ messages in thread
From: Eli Zaretskii @ 2023-11-14 19:12 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
> From: Tom Tromey <tromey@adacore.com>
> Date: Tue, 14 Nov 2023 11:44:04 -0700
>
> This changes Python stop events to carry a "details" dictionary, that
> holds any relevant information about the stop. The details are
> constructed using more or less the same procedure as is done for MI.
>
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=13587
> ---
> gdb/NEWS | 4 +++
> gdb/doc/python.texi | 11 ++++++++
> gdb/python/py-bpevent.c | 5 ++--
> gdb/python/py-mi.c | 2 +-
> gdb/python/py-signalevent.c | 5 ++--
> gdb/python/py-stopevent.c | 65 +++++++++++++++++++++++++++++++++++++++++----
> gdb/python/py-stopevent.h | 9 ++++---
> gdb/python/py-uiout.h | 4 +--
> 8 files changed, 90 insertions(+), 15 deletions(-)
Thanks, the documentation parts are okay.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 0/3] Simplify DAP stop reason emission
2023-11-14 18:44 [PATCH 0/3] Simplify DAP stop reason emission Tom Tromey
` (2 preceding siblings ...)
2023-11-14 18:44 ` [PATCH 3/3] Simplify DAP stop-reason code Tom Tromey
@ 2023-12-11 18:42 ` Tom Tromey
3 siblings, 0 replies; 6+ messages in thread
From: Tom Tromey @ 2023-12-11 18:42 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
>>>>> "Tom" == Tom Tromey <tromey@adacore.com> writes:
Tom> This patch changes the DAP stop-reason emission to be simpler (on the
Tom> DAP side) and also more reliable. Rather than guessing that a stop
Tom> occurred because a "step" finished, the DAP code now relies on gdb's
Tom> own knowledge of this.
I rebased this, which required a bit of fixing in events.py.
I'm going to check it in now.
Tom
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2023-12-11 18:42 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-14 18:44 [PATCH 0/3] Simplify DAP stop reason emission Tom Tromey
2023-11-14 18:44 ` [PATCH 1/3] Move py_ui_out to a new header Tom Tromey
2023-11-14 18:44 ` [PATCH 2/3] Emit stop reason details in Python stop events Tom Tromey
2023-11-14 19:12 ` Eli Zaretskii
2023-11-14 18:44 ` [PATCH 3/3] Simplify DAP stop-reason code Tom Tromey
2023-12-11 18:42 ` [PATCH 0/3] Simplify DAP stop reason emission Tom Tromey
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).