public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Felix Willgerodt <felix.willgerodt@intel.com>
To: gdb-patches@sourceware.org, markus.t.metzger@intel.com
Subject: [PATCH v5 09/10] btrace, python: Enable ptwrite filter registration.
Date: Wed, 22 Jun 2022 13:43:39 +0200	[thread overview]
Message-ID: <20220622114340.55830-10-felix.willgerodt@intel.com> (raw)
In-Reply-To: <20220622114340.55830-1-felix.willgerodt@intel.com>

With this patch a default ptwrite filter is registered upon start of GDB.
It prints the plain ptwrite payload as hex.  The default filter can be
overwritten by registering a custom filter in python or by registering
"None", for no output at all.  Registering a filter function creates per
thread copies to allow unique internal states per thread.
---
 gdb/btrace.c                   |   3 +
 gdb/btrace.h                   |   9 +++
 gdb/data-directory/Makefile.in |   1 +
 gdb/extension-priv.h           |   5 ++
 gdb/extension.c                |  13 ++++
 gdb/extension.h                |   3 +
 gdb/guile/guile.c              |   1 +
 gdb/python/lib/gdb/ptwrite.py  |  86 +++++++++++++++++++++++++
 gdb/python/py-record-btrace.c  | 111 +++++++++++++++++++++++++++++++++
 gdb/python/py-record-btrace.h  |   8 +++
 gdb/python/python-internal.h   |   3 +
 gdb/python/python.c            |   2 +
 12 files changed, 245 insertions(+)
 create mode 100644 gdb/python/lib/gdb/ptwrite.py

diff --git a/gdb/btrace.c b/gdb/btrace.c
index 0f5e73f35c4..d8c4b77bbc5 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -34,6 +34,7 @@
 #include "gdbsupport/rsp-low.h"
 #include "gdbcmd.h"
 #include "cli/cli-utils.h"
+#include "extension.h"
 #include "gdbarch.h"
 
 /* For maintenance commands.  */
@@ -1317,6 +1318,8 @@ ftrace_add_pt (struct btrace_thread_info *btinfo,
   uint64_t offset;
   int status;
 
+  apply_ext_lang_ptwrite_filter (btinfo);
+
   for (;;)
     {
       struct pt_insn insn;
diff --git a/gdb/btrace.h b/gdb/btrace.h
index 69ce2f3330d..ccb87419757 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -352,6 +352,15 @@ struct btrace_thread_info
      displaying or stepping through the execution history.  */
   std::vector<std::string> aux_data;
 
+  /* Function pointer to the ptwrite callback.  Returns the string returned
+     by the ptwrite filter function or nullptr if no string is supposed to
+     be printed.  */
+  std::string (*ptw_callback_fun) (const uint64_t payload, const uint64_t ip,
+				   const void *ptw_filter);
+
+  /* Function pointer to the ptwrite filter function.  */
+  void *ptw_filter = nullptr;
+
   /* The function level offset.  When added to each function's LEVEL,
      this normalizes the function levels such that the smallest level
      becomes zero.  */
diff --git a/gdb/data-directory/Makefile.in b/gdb/data-directory/Makefile.in
index cf5226f3961..506c16af4b5 100644
--- a/gdb/data-directory/Makefile.in
+++ b/gdb/data-directory/Makefile.in
@@ -75,6 +75,7 @@ PYTHON_FILE_LIST = \
 	gdb/frames.py \
 	gdb/printing.py \
 	gdb/prompt.py \
+	gdb/ptwrite.py \
 	gdb/styling.py \
 	gdb/types.py \
 	gdb/unwinder.py \
diff --git a/gdb/extension-priv.h b/gdb/extension-priv.h
index 7c74e721c57..b3bed3c88ab 100644
--- a/gdb/extension-priv.h
+++ b/gdb/extension-priv.h
@@ -183,6 +183,11 @@ struct extension_language_ops
      enum ext_lang_frame_args args_type,
      struct ui_out *out, int frame_low, int frame_high);
 
+  /* Used for registering the ptwrite filter to the current thread.  */
+  void (*apply_ptwrite_filter)
+    (const struct extension_language_defn *extlang,
+     struct btrace_thread_info *btinfo);
+
   /* Update values held by the extension language when OBJFILE is discarded.
      New global types must be created for every such value, which must then be
      updated to use the new types.
diff --git a/gdb/extension.c b/gdb/extension.c
index 5a805bea00e..0f6e3e02f0e 100644
--- a/gdb/extension.c
+++ b/gdb/extension.c
@@ -550,6 +550,19 @@ apply_ext_lang_frame_filter (struct frame_info *frame,
   return EXT_LANG_BT_NO_FILTERS;
 }
 
+/* Used for registering the ptwrite filter to the current thread.  */
+
+void
+apply_ext_lang_ptwrite_filter (btrace_thread_info *btinfo)
+{
+  for (const struct extension_language_defn *extlang : extension_languages)
+    {
+      if (extlang->ops != nullptr
+	  && extlang->ops->apply_ptwrite_filter != nullptr)
+	extlang->ops->apply_ptwrite_filter (extlang, btinfo);
+    }
+}
+
 /* Update values held by the extension language when OBJFILE is discarded.
    New global types must be created for every such value, which must then be
    updated to use the new types.
diff --git a/gdb/extension.h b/gdb/extension.h
index 47839ea50be..bd05d61cd50 100644
--- a/gdb/extension.h
+++ b/gdb/extension.h
@@ -295,6 +295,9 @@ extern enum ext_lang_bt_status apply_ext_lang_frame_filter
    enum ext_lang_frame_args args_type,
    struct ui_out *out, int frame_low, int frame_high);
 
+extern void apply_ext_lang_ptwrite_filter
+  (struct btrace_thread_info *btinfo);
+
 extern void preserve_ext_lang_values (struct objfile *, htab_t copied_types);
 
 extern const struct extension_language_defn *get_breakpoint_cond_ext_lang
diff --git a/gdb/guile/guile.c b/gdb/guile/guile.c
index 14b191ded62..86f92a476af 100644
--- a/gdb/guile/guile.c
+++ b/gdb/guile/guile.c
@@ -124,6 +124,7 @@ static const struct extension_language_ops guile_extension_ops =
   gdbscm_apply_val_pretty_printer,
 
   NULL, /* gdbscm_apply_frame_filter, */
+  NULL, /* gdbscm_load_ptwrite_listener, */
 
   gdbscm_preserve_values,
 
diff --git a/gdb/python/lib/gdb/ptwrite.py b/gdb/python/lib/gdb/ptwrite.py
new file mode 100644
index 00000000000..d1944f5cdc2
--- /dev/null
+++ b/gdb/python/lib/gdb/ptwrite.py
@@ -0,0 +1,86 @@
+# Ptwrite utilities.
+# Copyright (C) 2022 Free Software Foundation, Inc.
+
+# 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/>.
+
+"""Utilities for working with ptwrite filters."""
+
+import gdb
+from copy import deepcopy
+
+
+def default_filter(payload, ip):
+    """Default filter that is active upon starting GDB."""
+    return "{:x}".format(payload)
+
+# This dict contains the per thread copies of the filter function and the
+# global template filter, from which the copies are created.
+_ptwrite_filter = {"global" : default_filter}
+
+
+def _update_filter_dict(thread_list):
+    """Helper function to update the filter dict.
+
+    Discards filter copies of threads that already exited and registers
+    copies of the filter for new threads."""
+    # thread_list[x].ptid returns the tuple (pid, lwp, tid)
+    lwp_list = [i.ptid[1] for i in thread_list]
+
+    # clean-up old filters
+    for key in _ptwrite_filter.keys():
+      if key not in lwp_list and key != "global":
+        _ptwrite_filter.pop(key)
+
+    # Register filter for new threads
+    for key in lwp_list:
+        if key not in _ptwrite_filter.keys():
+            _ptwrite_filter[key] = deepcopy(_ptwrite_filter["global"])
+
+
+def _clear_traces(thread_list):
+    """Helper function to clear the trace of all threads in THREAD_LIST."""
+    current_thread = gdb.selected_thread()
+
+    recording = gdb.current_recording()
+
+    if (recording is not None):
+        for thread in thread_list:
+            thread.switch()
+            recording.clear()
+
+        current_thread.switch()
+
+
+def register_filter(filter):
+    """Register the ptwrite filter function."""
+    if filter is not None and not callable(filter):
+        raise TypeError("filter must be callable!")
+
+    # Clear the traces of all threads to force re-decoding with
+    # the new filter.
+    thread_list = gdb.Inferior.threads(gdb.selected_inferior())
+    _clear_traces(thread_list)
+
+    _ptwrite_filter.clear()
+    _ptwrite_filter["global"] = filter
+
+    _update_filter_dict(thread_list)
+
+
+def get_filter():
+    """Returns the filters of the current thread."""
+    thread_list = gdb.Inferior.threads(gdb.selected_inferior())
+    _update_filter_dict(thread_list)
+
+    return _ptwrite_filter[gdb.selected_thread().ptid[1]]
diff --git a/gdb/python/py-record-btrace.c b/gdb/python/py-record-btrace.c
index 8b3ae8c3fab..80c2871cf2a 100644
--- a/gdb/python/py-record-btrace.c
+++ b/gdb/python/py-record-btrace.c
@@ -762,6 +762,117 @@ recpy_bt_function_call_history (PyObject *self, void *closure)
   return btpy_list_new (tinfo, first, last, 1, &recpy_func_type);
 }
 
+/* Helper function that calls the ptwrite filter PTW_FILTER with
+   PAYLOAD and IP as arguments.  Returns a pointer to the string that will
+   be printed or nullptr if nothing should be printed.  IP can be nullptr,
+   PAYLOAD must point to a valid integer.  */
+std::string
+recpy_call_filter (const uint64_t payload, const uint64_t ip,
+		   const void *ptw_filter)
+{
+  std::string result;
+
+  if ((PyObject *) ptw_filter == Py_None)
+    return result;
+  else if ((PyObject *) ptw_filter == nullptr)
+    error (_("No valid ptwrite filter."));
+
+  /* As Python is started as a seperate thread, we need to
+     acquire the GIL to safely call the filter function.  */
+  PyGILState_STATE gstate = PyGILState_Ensure ();
+
+  PyObject *py_payload = PyLong_FromUnsignedLongLong (payload);
+  PyObject *py_ip;
+
+  if (ip == 0)
+    {
+      py_ip = Py_None;
+      Py_INCREF (Py_None);
+    }
+  else
+    py_ip = PyLong_FromUnsignedLongLong (ip);
+
+  PyObject *py_result = PyObject_CallFunctionObjArgs ((PyObject *) ptw_filter,
+						      py_payload, py_ip,
+						      nullptr);
+
+  if (PyErr_Occurred ())
+    {
+      gdbpy_print_stack ();
+      Py_DECREF (py_ip);
+      Py_DECREF (py_payload);
+      PyGILState_Release (gstate);
+      error (_("Error while executing Python code."));
+    }
+
+  Py_DECREF (py_ip);
+  Py_DECREF (py_payload);
+
+  if (py_result == Py_None)
+    {
+      Py_DECREF (py_result);
+      PyGILState_Release (gstate);
+      return result;
+    }
+
+  result = gdbpy_obj_to_string (py_result).get ();
+
+  if (PyErr_Occurred ())
+    {
+      gdbpy_print_stack ();
+      Py_DECREF (py_result);
+      PyGILState_Release (gstate);
+      error (_("Error while executing Python code."));
+    }
+
+  Py_DECREF (py_result);
+  PyGILState_Release (gstate);
+
+  return result;
+}
+
+/* Helper function returning the current ptwrite filter.  Returns nullptr
+   in case of errors.  */
+
+PyObject *
+get_ptwrite_filter ()
+{
+  PyObject *module = PyImport_ImportModule ("gdb.ptwrite");
+
+  if (PyErr_Occurred ())
+  {
+    gdbpy_print_stack ();
+    return nullptr;
+  }
+
+  PyObject *ptw_filter = PyObject_CallMethod (module,
+					      "get_filter",
+					      nullptr);
+
+  Py_DECREF (module);
+
+  if (PyErr_Occurred ())
+    gdbpy_print_stack ();
+
+  return ptw_filter;
+}
+
+/* Used for registering the default ptwrite filter to the current thread.  A
+   pointer to this function is stored in the python extension interface.  */
+
+void
+gdbpy_load_ptwrite_filter (const struct extension_language_defn *extlang,
+			   struct btrace_thread_info *btinfo)
+{
+  if (!gdb_python_initialized || btinfo == nullptr)
+    return;
+
+  gdbpy_enter enter_py;
+
+  btinfo->ptw_callback_fun = &recpy_call_filter;
+  btinfo->ptw_filter = get_ptwrite_filter ();
+}
+
 /* Implementation of BtraceRecord.goto (self, BtraceInstruction) -> None.  */
 
 PyObject *
diff --git a/gdb/python/py-record-btrace.h b/gdb/python/py-record-btrace.h
index b25b121d255..9b7fa369007 100644
--- a/gdb/python/py-record-btrace.h
+++ b/gdb/python/py-record-btrace.h
@@ -91,4 +91,12 @@ 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);
 
+/* Helper function returning the current ptwrite filter.  */
+extern PyObject *get_ptwrite_filter ();
+
+/* Callback function for the ptwrite filter.  */
+extern std::string recpy_call_filter (const uint64_t payload,
+				      const uint64_t ip,
+				      const void *ptw_filter);
+
 #endif /* PYTHON_PY_RECORD_BTRACE_H */
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 5ff9989af83..0bf1360d7f7 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -359,6 +359,9 @@ extern enum ext_lang_rc gdbpy_apply_val_pretty_printer
    struct ui_file *stream, int recurse,
    const struct value_print_options *options,
    const struct language_defn *language);
+extern void gdbpy_load_ptwrite_filter
+  (const struct extension_language_defn *extlang,
+   struct btrace_thread_info *btinfo);
 extern enum ext_lang_bt_status gdbpy_apply_frame_filter
   (const struct extension_language_defn *,
    struct frame_info *frame, frame_filter_flags flags,
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 8f526bba84e..e538b62931a 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -151,6 +151,8 @@ static const struct extension_language_ops python_extension_ops =
 
   gdbpy_apply_frame_filter,
 
+  gdbpy_load_ptwrite_filter,
+
   gdbpy_preserve_values,
 
   gdbpy_breakpoint_has_cond,
-- 
2.34.3

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


  parent reply	other threads:[~2022-06-22 11:46 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-22 11:43 [PATCH v5 00/10] Extensions for PTWRITE Felix Willgerodt
2022-06-22 11:43 ` [PATCH v5 01/10] btrace: Introduce auxiliary instructions Felix Willgerodt
2022-06-28  9:10   ` Metzger, Markus T
2022-06-22 11:43 ` [PATCH v5 02/10] btrace: Enable auxiliary instructions in record instruction-history Felix Willgerodt
2022-06-28  9:10   ` Metzger, Markus T
2022-06-28 11:28     ` Willgerodt, Felix
2022-06-29 10:43       ` Metzger, Markus T
2022-06-22 11:43 ` [PATCH v5 03/10] btrace: Enable auxiliary instructions in record function-call-history Felix Willgerodt
2022-06-28  9:10   ` Metzger, Markus T
2022-09-19  8:59     ` Willgerodt, Felix
2022-06-22 11:43 ` [PATCH v5 04/10] btrace: Handle stepping and goto for auxiliary instructions Felix Willgerodt
2022-06-28  9:11   ` Metzger, Markus T
2022-06-22 11:43 ` [PATCH v5 05/10] python: Introduce gdb.RecordAuxiliary class Felix Willgerodt
2022-06-28  9:11   ` Metzger, Markus T
2022-07-11 12:48     ` Willgerodt, Felix
2022-06-22 11:43 ` [PATCH v5 06/10] python: Add clear() to gdb.Record Felix Willgerodt
2022-06-28  9:11   ` Metzger, Markus T
2022-06-22 11:43 ` [PATCH v5 07/10] btrace, gdbserver: Add ptwrite to btrace_config_pt Felix Willgerodt
2022-06-28  9:11   ` Metzger, Markus T
2022-06-22 11:43 ` [PATCH v5 08/10] btrace, linux: Enable ptwrite packets Felix Willgerodt
2022-06-28  9:12   ` Metzger, Markus T
2022-06-22 11:43 ` Felix Willgerodt [this message]
2022-06-28 13:59   ` [PATCH v5 09/10] btrace, python: Enable ptwrite filter registration Metzger, Markus T
2022-07-11 12:48     ` Willgerodt, Felix
2022-07-12 12:23       ` Metzger, Markus T
2022-07-13  8:49         ` Willgerodt, Felix
2022-07-13 15:20           ` Metzger, Markus T
2022-07-26 14:08             ` Willgerodt, Felix
2022-09-14  8:37               ` Metzger, Markus T
2022-06-22 11:43 ` [PATCH v5 10/10] btrace: Extend ptwrite event decoding Felix Willgerodt
2022-06-29 13:35   ` Metzger, Markus T
2022-09-19  8:59     ` Willgerodt, Felix

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220622114340.55830-10-felix.willgerodt@intel.com \
    --to=felix.willgerodt@intel.com \
    --cc=gdb-patches@sourceware.org \
    --cc=markus.t.metzger@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).