[v9,05/10] python: Introduce gdb.RecordAuxiliary class.

Message ID 20230704123600.5944-6-felix.willgerodt@intel.com
State New
Headers
Series Extensions for PTWRITE |

Commit Message

Willgerodt, Felix July 4, 2023, 12:35 p.m. UTC
  Auxiliary instructions are no real instructions and get their own object
class, similar to gaps. gdb.Record.instruction_history is now possibly a
list of gdb.RecordInstruction, gdb.RecordGap or gdb.RecordAuxiliary
objects.

This patch is in preparation for the new ptwrite feature, which is based on
auxiliary instructions.
---
 gdb/doc/python.texi           | 13 ++++++
 gdb/python/py-record-btrace.c | 81 +++++++++++++++++++++++++++++------
 gdb/python/py-record-btrace.h |  3 ++
 gdb/python/py-record.c        | 62 +++++++++++++++++++++++++--
 gdb/python/py-record.h        |  7 +++
 5 files changed, 150 insertions(+), 16 deletions(-)
  

Comments

Eli Zaretskii July 4, 2023, 12:52 p.m. UTC | #1
> Cc: Felix Willgerodt <felix.willgerodt@intel.com>
> Date: Tue,  4 Jul 2023 14:35:55 +0200
> From: Felix Willgerodt via Gdb-patches <gdb-patches@sourceware.org>
> 
> Auxiliary instructions are no real instructions and get their own object
> class, similar to gaps. gdb.Record.instruction_history is now possibly a
> list of gdb.RecordInstruction, gdb.RecordGap or gdb.RecordAuxiliary
> objects.
> 
> This patch is in preparation for the new ptwrite feature, which is based on
> auxiliary instructions.
> ---
>  gdb/doc/python.texi           | 13 ++++++
>  gdb/python/py-record-btrace.c | 81 +++++++++++++++++++++++++++++------
>  gdb/python/py-record-btrace.h |  3 ++
>  gdb/python/py-record.c        | 62 +++++++++++++++++++++++++--
>  gdb/python/py-record.h        |  7 +++
>  5 files changed, 150 insertions(+), 16 deletions(-)

Thanks.

> +@defvar RecordAuxiliary.number
> +An integer identifying this auxiliary.  @code{number} corresponds to the numbers
> +seen in @code{record instruction-history} (@pxref{Process Record and Replay}).

I think "number" should be in @var, like this:

 +@defvar RecordAuxiliary.@var{number}
 +An integer identifying this auxiliary.  @var{number} corresponds to the numbers
 +seen in @code{record instruction-history} (@pxref{Process Record and Replay}).

because "number" is not a literal string, it stands for some numerical
string.  Right?

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
  
Terekhov, Mikhail via Gdb-patches July 5, 2023, 10:04 a.m. UTC | #2
> -----Original Message-----
> From: Eli Zaretskii <eliz@gnu.org>
> Sent: Dienstag, 4. Juli 2023 14:52
> To: Willgerodt, Felix <felix.willgerodt@intel.com>
> Cc: gdb-patches@sourceware.org; Metzger, Markus T
> <markus.t.metzger@intel.com>; simark@simark.ca
> Subject: Re: [PATCH v9 05/10] python: Introduce gdb.RecordAuxiliary class.
> 
> > Cc: Felix Willgerodt <felix.willgerodt@intel.com>
> > Date: Tue,  4 Jul 2023 14:35:55 +0200
> > From: Felix Willgerodt via Gdb-patches <gdb-patches@sourceware.org>
> >
> > Auxiliary instructions are no real instructions and get their own object
> > class, similar to gaps. gdb.Record.instruction_history is now possibly a
> > list of gdb.RecordInstruction, gdb.RecordGap or gdb.RecordAuxiliary
> > objects.
> >
> > This patch is in preparation for the new ptwrite feature, which is based on
> > auxiliary instructions.
> > ---
> >  gdb/doc/python.texi           | 13 ++++++
> >  gdb/python/py-record-btrace.c | 81
> +++++++++++++++++++++++++++++------
> >  gdb/python/py-record-btrace.h |  3 ++
> >  gdb/python/py-record.c        | 62 +++++++++++++++++++++++++--
> >  gdb/python/py-record.h        |  7 +++
> >  5 files changed, 150 insertions(+), 16 deletions(-)
> 
> Thanks.
> 
> > +@defvar RecordAuxiliary.number
> > +An integer identifying this auxiliary.  @code{number} corresponds to the
> numbers
> > +seen in @code{record instruction-history} (@pxref{Process Record and
> Replay}).
> 
> I think "number" should be in @var, like this:
> 
>  +@defvar RecordAuxiliary.@var{number}
>  +An integer identifying this auxiliary.  @var{number} corresponds to the
> numbers
>  +seen in @code{record instruction-history} (@pxref{Process Record and
> Replay}).
> 
> because "number" is not a literal string, it stands for some numerical
> string.  Right?

I just copied it from the RecordGap.number text to be honest, there it is
also in a @code. It is supposed to be the actual python member.
It is both code and a variable ;)
The surrounding test seems to favour code. I am happy to change it to
whatever you think is right. I see both equally possible.

> Reviewed-By: Eli Zaretskii <eliz@gnu.org>

Thanks!
Felix
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
  
Eli Zaretskii July 5, 2023, 11:37 a.m. UTC | #3
> From: "Willgerodt, Felix" <felix.willgerodt@intel.com>
> CC: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>, "Metzger,
>  Markus T" <markus.t.metzger@intel.com>, "simark@simark.ca" <simark@simark.ca>
> Date: Wed, 5 Jul 2023 10:04:53 +0000
> 
> > I think "number" should be in @var, like this:
> > 
> >  +@defvar RecordAuxiliary.@var{number}
> >  +An integer identifying this auxiliary.  @var{number} corresponds to the
> > numbers
> >  +seen in @code{record instruction-history} (@pxref{Process Record and
> > Replay}).
> > 
> > because "number" is not a literal string, it stands for some numerical
> > string.  Right?
> 
> I just copied it from the RecordGap.number text to be honest, there it is
> also in a @code. It is supposed to be the actual python member.
> It is both code and a variable ;)
> The surrounding test seems to favour code. I am happy to change it to
> whatever you think is right. I see both equally possible.

Yes, @var is the right markup here.
  

Patch

diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 9a342f34bf0..b2140b1b8ea 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -4106,6 +4106,19 @@  the current recording method.
 A human readable string with the reason for the gap.
 @end defvar
 
+Some @value{GDBN} features write auxiliary information into the execution
+history.  This information is represented by a @code{gdb.RecordAuxiliary} object
+in the instruction list.  It has the following attributes:
+
+@defvar RecordAuxiliary.number
+An integer identifying this auxiliary.  @code{number} corresponds to the numbers
+seen in @code{record instruction-history} (@pxref{Process Record and Replay}).
+@end defvar
+
+@defvar RecordAuxiliary.data
+A string representation of the auxiliary data.
+@end defvar
+
 A @code{gdb.RecordFunctionSegment} object has the following attributes:
 
 @defvar RecordFunctionSegment.number
diff --git a/gdb/python/py-record-btrace.c b/gdb/python/py-record-btrace.c
index 7978f3332c6..4a2a61e9b91 100644
--- a/gdb/python/py-record-btrace.c
+++ b/gdb/python/py-record-btrace.c
@@ -45,7 +45,8 @@  struct btpy_list_object {
   /* Stride size.  */
   Py_ssize_t step;
 
-  /* Either &BTPY_CALL_TYPE or &RECPY_INSN_TYPE.  */
+  /* Either &recpy_func_type, &recpy_insn_type, &recpy_aux_type or
+     &recpy_gap_type.  */
   PyTypeObject* element_type;
 };
 
@@ -141,15 +142,21 @@  btrace_func_from_recpy_func (const PyObject * const pyobject)
 }
 
 /* Looks at the recorded item with the number NUMBER and create a
-   gdb.RecordInstruction or gdb.RecordGap object for it accordingly.  */
+   gdb.RecordInstruction, gdb.RecordGap or gdb.RecordAuxiliary object
+   for it accordingly.  */
 
 static PyObject *
-btpy_insn_or_gap_new (thread_info *tinfo, Py_ssize_t number)
+btpy_item_new (thread_info *tinfo, Py_ssize_t number)
 {
   btrace_insn_iterator iter;
   int err_code;
 
-  btrace_find_insn_by_number (&iter, &tinfo->btrace, number);
+  if (btrace_find_insn_by_number (&iter, &tinfo->btrace, number) == 0)
+    {
+      PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
+      return nullptr;
+    }
+
   err_code = btrace_insn_get_error (&iter);
 
   if (err_code != 0)
@@ -163,6 +170,12 @@  btpy_insn_or_gap_new (thread_info *tinfo, Py_ssize_t number)
       return recpy_gap_new (err_code, err_string, number);
     }
 
+  const struct btrace_insn *insn = btrace_insn_get (&iter);
+  gdb_assert (insn != nullptr);
+
+  if (insn->iclass == BTRACE_INSN_AUX)
+    return recpy_aux_new (tinfo, RECORD_METHOD_BTRACE, number);
+
   return recpy_insn_new (tinfo, RECORD_METHOD_BTRACE, number);
 }
 
@@ -424,6 +437,48 @@  recpy_bt_func_next (PyObject *self, void *closure)
 			 RECORD_METHOD_BTRACE, func->next);
 }
 
+/* Implementation of Auxiliary.data [str] for btrace.  */
+
+PyObject *
+recpy_bt_aux_data (PyObject *self, void *closure)
+{
+  const btrace_insn *insn;
+  const recpy_element_object *obj;
+  thread_info *tinfo;
+  btrace_insn_iterator iter;
+
+  if (Py_TYPE (self) != &recpy_aux_type)
+    {
+      PyErr_Format (gdbpy_gdb_error, _("Must be a gdb.Auxiliary."));
+      return NULL;
+    }
+
+  obj = (const recpy_element_object *) self;
+  tinfo = obj->thread;
+
+  if (tinfo == NULL || btrace_is_empty (tinfo))
+    {
+      PyErr_Format (gdbpy_gdb_error, _("No such auxiliary object."));
+      return NULL;
+    }
+
+  if (btrace_find_insn_by_number (&iter, &tinfo->btrace, obj->number) == 0)
+    {
+      PyErr_Format (gdbpy_gdb_error, _("No such auxiliary object."));
+      return NULL;
+    }
+
+  insn = btrace_insn_get (&iter);
+  if (insn == NULL)
+    {
+      PyErr_Format (gdbpy_gdb_error, _("Not a valid auxiliary object."));
+      return NULL;
+    }
+
+  return PyUnicode_FromString
+    (iter.btinfo->aux_data.at (insn->aux_data_index).c_str ());
+}
+
 /* Implementation of BtraceList.__len__ (self) -> int.  */
 
 static Py_ssize_t
@@ -440,8 +495,9 @@  btpy_list_length (PyObject *self)
 }
 
 /* Implementation of
-   BtraceList.__getitem__ (self, key) -> BtraceInstruction and
-   BtraceList.__getitem__ (self, key) -> BtraceFunctionCall.  */
+   BtraceList.__getitem__ (self, key) -> BtraceInstruction,
+   BtraceList.__getitem__ (self, key) -> BtraceFunctionCall,
+   BtraceList.__getitem__ (self, key) -> BtraceAuxiliary.  */
 
 static PyObject *
 btpy_list_item (PyObject *self, Py_ssize_t index)
@@ -455,10 +511,10 @@  btpy_list_item (PyObject *self, Py_ssize_t index)
 
   number = obj->first + (obj->step * index);
 
-  if (obj->element_type == &recpy_insn_type)
-    return recpy_insn_new (obj->thread, RECORD_METHOD_BTRACE, number);
-  else
+  if (obj->element_type == &recpy_func_type)
     return recpy_func_new (obj->thread, RECORD_METHOD_BTRACE, number);
+  else
+    return btpy_item_new (obj->thread, number);
 }
 
 /* Implementation of BtraceList.__getitem__ (self, slice) -> BtraceList.  */
@@ -645,8 +701,7 @@  recpy_bt_replay_position (PyObject *self, void *closure)
   if (tinfo->btrace.replay == NULL)
     Py_RETURN_NONE;
 
-  return btpy_insn_or_gap_new (tinfo,
-			       btrace_insn_number (tinfo->btrace.replay));
+  return btpy_item_new (tinfo, btrace_insn_number (tinfo->btrace.replay));
 }
 
 /* Implementation of
@@ -668,7 +723,7 @@  recpy_bt_begin (PyObject *self, void *closure)
     Py_RETURN_NONE;
 
   btrace_insn_begin (&iterator, &tinfo->btrace);
-  return btpy_insn_or_gap_new (tinfo, btrace_insn_number (&iterator));
+  return btpy_item_new (tinfo, btrace_insn_number (&iterator));
 }
 
 /* Implementation of
@@ -690,7 +745,7 @@  recpy_bt_end (PyObject *self, void *closure)
     Py_RETURN_NONE;
 
   btrace_insn_end (&iterator, &tinfo->btrace);
-  return btpy_insn_or_gap_new (tinfo, btrace_insn_number (&iterator));
+  return btpy_item_new (tinfo, btrace_insn_number (&iterator));
 }
 
 /* Implementation of
diff --git a/gdb/python/py-record-btrace.h b/gdb/python/py-record-btrace.h
index 0af8153b715..0ca3da8e86f 100644
--- a/gdb/python/py-record-btrace.h
+++ b/gdb/python/py-record-btrace.h
@@ -88,4 +88,7 @@  extern PyObject *recpy_bt_func_prev (PyObject *self, void *closure);
 /* Implementation of RecordFunctionSegment.next [RecordFunctionSegment].  */
 extern PyObject *recpy_bt_func_next (PyObject *self, void *closure);
 
+/* Implementation of RecordAuxiliary.decoded [str].  */
+extern PyObject *recpy_bt_aux_data (PyObject *self, void *closure);
+
 #endif /* PYTHON_PY_RECORD_BTRACE_H */
diff --git a/gdb/python/py-record.c b/gdb/python/py-record.c
index c96c649b29c..c093cdaf3d6 100644
--- a/gdb/python/py-record.c
+++ b/gdb/python/py-record.c
@@ -49,6 +49,12 @@  static PyTypeObject recpy_gap_type = {
   PyVarObject_HEAD_INIT (NULL, 0)
 };
 
+/* Python RecordAuxiliary type.  */
+
+PyTypeObject recpy_aux_type = {
+  PyVarObject_HEAD_INIT (nullptr, 0)
+};
+
 /* Python RecordGap object.  */
 struct recpy_gap_object
 {
@@ -390,8 +396,8 @@  recpy_element_hash (PyObject *self)
   return obj->number;
 }
 
-/* Implementation of operator == and != of RecordInstruction and
-   RecordFunctionSegment.  */
+/* Implementation of operator == and != of RecordInstruction,
+   RecordFunctionSegment and RecordAuxiliary.  */
 
 static PyObject *
 recpy_element_richcompare (PyObject *self, PyObject *other, int op)
@@ -479,6 +485,38 @@  recpy_gap_reason_string (PyObject *self, void *closure)
   return PyUnicode_FromString (obj->reason_string);
 }
 
+/* Create a new gdb.Auxiliary object.  */
+
+PyObject *
+recpy_aux_new (thread_info *thread, enum record_method method,
+	       Py_ssize_t number)
+{
+  recpy_element_object * const obj = PyObject_New (recpy_element_object,
+						   &recpy_aux_type);
+
+  if (obj == NULL)
+   return NULL;
+
+  obj->thread = thread;
+  obj->method = method;
+  obj->number = number;
+
+  return (PyObject *) obj;
+}
+
+/* Implementation of Auxiliary.data [buffer].  */
+
+static PyObject *
+recpy_aux_data (PyObject *self, void *closure)
+{
+  const recpy_element_object * const obj = (recpy_element_object *) self;
+
+  if (obj->method == RECORD_METHOD_BTRACE)
+    return recpy_bt_aux_data (self, closure);
+
+  return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
+}
+
 /* Record method list.  */
 
 static PyMethodDef recpy_record_methods[] = {
@@ -544,6 +582,14 @@  static gdb_PyGetSetDef recpy_gap_getset[] = {
   { NULL }
 };
 
+/* RecordAuxiliary member list.  */
+
+static gdb_PyGetSetDef recpy_aux_getset[] = {
+  { "number", recpy_element_number, nullptr, "element number", nullptr},
+  { "data", recpy_aux_data, nullptr, "data", nullptr},
+  { nullptr }
+};
+
 /* Sets up the record API in the gdb module.  */
 
 static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
@@ -583,10 +629,20 @@  gdbpy_initialize_record (void)
   recpy_gap_type.tp_doc = "GDB recorded gap object";
   recpy_gap_type.tp_getset = recpy_gap_getset;
 
+  recpy_aux_type.tp_new = PyType_GenericNew;
+  recpy_aux_type.tp_flags = Py_TPFLAGS_DEFAULT;
+  recpy_aux_type.tp_basicsize = sizeof (recpy_element_object);
+  recpy_aux_type.tp_name = "gdb.RecordAuxiliary";
+  recpy_aux_type.tp_doc = "GDB recorded auxiliary object";
+  recpy_aux_type.tp_getset = recpy_aux_getset;
+  recpy_aux_type.tp_richcompare = recpy_element_richcompare;
+  recpy_aux_type.tp_hash = recpy_element_hash;
+
   if (PyType_Ready (&recpy_record_type) < 0
       || PyType_Ready (&recpy_insn_type) < 0
       || PyType_Ready (&recpy_func_type) < 0
-      || PyType_Ready (&recpy_gap_type) < 0)
+      || PyType_Ready (&recpy_gap_type) < 0
+      || PyType_Ready (&recpy_aux_type) < 0)
     return -1;
   else
     return 0;
diff --git a/gdb/python/py-record.h b/gdb/python/py-record.h
index 6eec71e06e7..63e59798a02 100644
--- a/gdb/python/py-record.h
+++ b/gdb/python/py-record.h
@@ -59,6 +59,9 @@  extern PyTypeObject recpy_insn_type;
 /* Python RecordFunctionSegment type.  */
 extern PyTypeObject recpy_func_type;
 
+/* Python RecordAuxiliary type.  */
+extern PyTypeObject recpy_aux_type;
+
 /* Create a new gdb.RecordInstruction object.  */
 extern PyObject *recpy_insn_new (thread_info *thread, enum record_method method,
 				 Py_ssize_t number);
@@ -71,4 +74,8 @@  extern PyObject *recpy_func_new (thread_info *thread, enum record_method method,
 extern PyObject *recpy_gap_new (int reason_code, const char *reason_string,
 				Py_ssize_t number);
 
+/* Create a new gdb.RecordGap object.  */
+extern PyObject *recpy_aux_new (thread_info *thread, enum record_method method,
+				Py_ssize_t number);
+
 #endif /* PYTHON_PY_RECORD_H */