gdb/python: Add gdb.InferiorThread.details attribute

This adds a new read-only attribute gdb.InferiorThread.details, this
attribute contains a string, the results of target_extra_thread_info
for the thread, or None, if target_extra_thread_info returns nullptr.

As the string returned by target_extra_thread_info is unstructured,
this attribute is only really useful for echoing straight through to
the user, but, if a user wants to write a command that displays the
same, or a similar 'Thread Id' to the one seen in 'info threads', then
they need access to this string.

Given that the string produced by target_extra_thread_info varies by
target, there's only minimal testing of this attribute, I check that
the attribute can be accessed, and that the return value is either
None, or a string.
This commit is contained in:
Andrew Burgess 2022-02-14 17:02:03 +00:00
parent ea764154c2
commit 659971cb0f
5 changed files with 58 additions and 0 deletions

View file

@ -201,6 +201,11 @@ GNU/Linux/LoongArch loongarch*-*-linux*
set styling'). When false, which is the default if the argument set styling'). When false, which is the default if the argument
is not given, then no styling is applied to the returned string. is not given, then no styling is applied to the returned string.
** New read-only attribute gdb.InferiorThread.details, which is
either a string, containing additional, target specific thread
state information, or None, if there is no such additional
information.
* New features in the GDB remote stub, GDBserver * New features in the GDB remote stub, GDBserver
** GDBserver is now supported on OpenRISC GNU/Linux. ** GDBserver is now supported on OpenRISC GNU/Linux.

View file

@ -3629,6 +3629,7 @@ Thread 1 "main" received signal SIGINT, Interrupt.
@end smallexample @end smallexample
@table @code @table @code
@anchor{info_threads}
@kindex info threads @kindex info threads
@item info threads @r{[}@var{thread-id-list}@r{]} @item info threads @r{[}@var{thread-id-list}@r{]}
@ -42719,6 +42720,7 @@ encoded). @value{GDBN} will continue to supply the values of symbols
@xref{Tracepoint Packets}. @xref{Tracepoint Packets}.
@anchor{qThreadExtraInfo}
@item qThreadExtraInfo,@var{thread-id} @item qThreadExtraInfo,@var{thread-id}
@cindex thread attributes info, remote request @cindex thread attributes info, remote request
@cindex @samp{qThreadExtraInfo} packet @cindex @samp{qThreadExtraInfo} packet

View file

@ -3574,6 +3574,23 @@ The inferior this thread belongs to. This attribute is represented as
a @code{gdb.Inferior} object. This attribute is not writable. a @code{gdb.Inferior} object. This attribute is not writable.
@end defvar @end defvar
@defvar InferiorThread.details
A string containing target specific thread state information. The
format of this string varies by target. If there is no additional
state information for this thread, then this attribute contains
@code{None}.
For example, on a @sc{gnu}/Linux system, a thread that is in the
process of exiting will return the string @samp{Exiting}. For remote
targets the @code{details} string will be obtained with the
@samp{qThreadExtraInfo} remote packet, if the target supports it
(@pxref{qThreadExtraInfo,,@samp{qThreadExtraInfo}}).
@value{GDBN} displays the @code{details} string as part of the
@samp{Target Id} column, in the @code{info threads} output
(@pxref{info_threads,,@samp{info threads}}).
@end defvar
A @code{gdb.InferiorThread} object has the following methods: A @code{gdb.InferiorThread} object has the following methods:
@defun InferiorThread.is_valid () @defun InferiorThread.is_valid ()

View file

@ -76,6 +76,32 @@ thpy_get_name (PyObject *self, void *ignore)
return PyString_FromString (name); return PyString_FromString (name);
} }
/* Return a string containing target specific additional information about
the state of the thread, or None, if there is no such additional
information. */
static PyObject *
thpy_get_details (PyObject *self, void *ignore)
{
thread_object *thread_obj = (thread_object *) self;
THPY_REQUIRE_VALID (thread_obj);
const char *extra_info;
try
{
extra_info = target_extra_thread_info (thread_obj->thread);
}
catch (const gdb_exception &except)
{
GDB_PY_HANDLE_EXCEPTION (except);
}
if (extra_info == nullptr)
Py_RETURN_NONE;
return PyString_FromString (extra_info);
}
static int static int
thpy_set_name (PyObject *self, PyObject *newvalue, void *ignore) thpy_set_name (PyObject *self, PyObject *newvalue, void *ignore)
{ {
@ -347,6 +373,9 @@ static gdb_PyGetSetDef thread_object_getset[] =
{ {
{ "name", thpy_get_name, thpy_set_name, { "name", thpy_get_name, thpy_set_name,
"The name of the thread, as set by the user or the OS.", NULL }, "The name of the thread, as set by the user or the OS.", NULL },
{ "details", thpy_get_details, NULL,
"A target specific string containing extra thread state details.",
NULL },
{ "num", thpy_get_num, NULL, { "num", thpy_get_num, NULL,
"Per-inferior number of the thread, as assigned by GDB.", NULL }, "Per-inferior number of the thread, as assigned by GDB.", NULL },
{ "global_num", thpy_get_global_num, NULL, { "global_num", thpy_get_global_num, NULL,

View file

@ -77,6 +77,11 @@ gdb_py_test_silent_cmd "python gdb.selected_thread().name = None" \
gdb_test "python print (gdb.selected_thread().name == name)" "True" \ gdb_test "python print (gdb.selected_thread().name == name)" "True" \
"check name of current thread again" "check name of current thread again"
gdb_test_no_output "python details = gdb.selected_thread().details" \
"record the thread details string"
gdb_test "python print(details is None or isinstance(details, str))" "True" \
"check that the details has an acceptable type"
gdb_test "python print ('result = %s' % t0.is_stopped ())" " = True" "test InferiorThread.is_stopped" gdb_test "python print ('result = %s' % t0.is_stopped ())" " = True" "test InferiorThread.is_stopped"
gdb_test "python print ('result = %s' % t0.is_running ())" " = False" "test InferiorThread.is_running" gdb_test "python print ('result = %s' % t0.is_running ())" " = False" "test InferiorThread.is_running"
gdb_test "python print ('result = %s' % t0.is_exited ())" " = False" "test InferiorThread.is_exited" gdb_test "python print ('result = %s' % t0.is_exited ())" " = False" "test InferiorThread.is_exited"