these will be stored in the object's new Inferior.__dict__
attribute.
+ ** User defined attributes can be added to a gdb.InferiorThread
+ object, these will be stored in the object's new
+ InferiorThread.__dict__ attribute.
+
* Debugger Adapter Protocol changes
** GDB now emits the "process" event.
a @code{gdb.Type} for the handle type.
@end defun
+One may add arbitrary attributes to @code{gdb.InferiorThread} objects
+in the usual Python way. This is useful if, for example, one needs to
+do some extra record keeping associated with the thread.
+
+In this contrived example we record the time when a thread last
+stopped:
+
+@smallexample
+@group
+(@value{GDBP}) python
+import datetime
+
+def thread_stopped(event):
+ if event.inferior_thread is not None:
+ thread = event.inferior_thread
+ else:
+ thread = gdb.selected_thread()
+ thread._last_stop_time = datetime.datetime.today()
+
+gdb.events.stop.connect(thread_stopped)
+@end group
+@group
+(@value{GDBP}) file /tmp/hello
+Reading symbols from /tmp/hello...
+(@value{GDBP}) start
+Temporary breakpoint 1 at 0x401198: file /tmp/hello.c, line 18.
+Starting program: /tmp/hello
+
+Temporary breakpoint 1, main () at /tmp/hello.c:18
+18 printf ("Hello World\n");
+(@value{GDBP}) python print(gdb.selected_thread()._last_stop_time)
+2024-01-04 14:48:41.347036
+@end group
+@end smallexample
+
@node Recordings In Python
@subsubsection Recordings In Python
@cindex recordings in python
thread_obj->thread = tp;
thread_obj->inf_obj = (PyObject *) inf_obj.release ();
+ thread_obj->dict = PyDict_New ();
+ if (thread_obj->dict == nullptr)
+ return nullptr;
return thread_obj;
}
static void
thpy_dealloc (PyObject *self)
{
- Py_DECREF (((thread_object *) self)->inf_obj);
+ thread_object *thr_obj = (thread_object *) self;
+
+ gdb_assert (thr_obj->inf_obj != nullptr);
+
+ Py_DECREF (thr_obj->inf_obj);
+ Py_XDECREF (thr_obj->dict);
+
Py_TYPE (self)->tp_free (self);
}
static gdb_PyGetSetDef thread_object_getset[] =
{
+ { "__dict__", gdb_py_generic_dict, nullptr,
+ "The __dict__ for this thread.", &thread_object_type },
{ "name", thpy_get_name, thpy_set_name,
"The name of the thread, as set by the user or the OS.", NULL },
{ "details", thpy_get_details, NULL,
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
- 0, /* tp_dictoffset */
+ offsetof (thread_object, dict), /* tp_dictoffset */
0, /* tp_init */
0 /* tp_alloc */
};
/* The Inferior object to which this thread belongs. */
PyObject *inf_obj;
+
+ /* Dictionary holding user-added attributes. This is the __dict__
+ attribute of the object. */
+ PyObject *dict;
};
struct inferior_object;
"<gdb.InferiorThread id=${decimal}\\.${decimal} target-id=\"\[^\r\n\]*\">" \
"test repr of a valid thread"
+# Add a user defined attribute to this thread, check the attribute can
+# be read back, and check the attribute is not present on other
+# threads.
+gdb_test_no_output "python last_thread._user_attribute = 123" \
+ "add user defined attribute to InferiorThread object"
+gdb_test "python print(last_thread._user_attribute)" "123" \
+ "read back user defined attribute"
+gdb_test "python print(i0.threads ()\[0\]._user_attribute)" \
+ [multi_line \
+ "AttributeError: 'gdb\\.InferiorThread' object has no attribute '_user_attribute'" \
+ "Error while executing Python code\\."] \
+ "attempt to read non-existent user defined attribute"
+
# Proceed to the next test.
gdb_breakpoint [gdb_get_line_number "Break here."]
"<gdb.InferiorThread \\(invalid\\)>" \
"test repr of an invalid thread"
+# Check the user defined attribute is still present on the invalid thread object.
+gdb_test "python print(last_thread._user_attribute)" "123" \
+ "check user defined attribute on an invalid InferiorThread object"
+
# Test memory read and write operations.
gdb_py_test_silent_cmd "python addr = gdb.selected_frame ().read_var ('str')" \