Emit stop reason details in Python stop events
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 Reviewed-By: Eli Zaretskii <eliz@gnu.org>
This commit is contained in:
@@ -75,6 +75,10 @@ show remote thread-options-packet
|
||||
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.
|
||||
|
||||
* Debugger Adapter Protocol changes
|
||||
|
||||
** GDB now emits the "process" event.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -46,14 +46,14 @@ public:
|
||||
/* 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:
|
||||
|
||||
Reference in New Issue
Block a user