From patchwork Fri Oct 21 11:59:46 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Willgerodt, Felix" X-Patchwork-Id: 59281 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id ED0F5385DC09 for ; Fri, 21 Oct 2022 12:05:37 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org ED0F5385DC09 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1666353938; bh=F/w/pbD+AVzfx2V/u7oqCY940w4xNW/nT9qlOt9j6vY=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=HdYQirMUWLwyhnlk5GWMFg+GUv243LUwvAUb/PdURG51luz+ujR2NOr++tQJRnhkT XVZYTEUVesz2tTitoky6hq/453TOerTWVchDDpUuJbu6av/g6OornZbXBZjZh5OV87 XNsFglUX/jI08d2U5j62Bo82xcw+m0k0QIyqcgWY= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by sourceware.org (Postfix) with ESMTPS id 29D893853804 for ; Fri, 21 Oct 2022 12:03:07 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 29D893853804 X-IronPort-AV: E=McAfee;i="6500,9779,10506"; a="287389389" X-IronPort-AV: E=Sophos;i="5.95,200,1661842800"; d="scan'208";a="287389389" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2022 05:03:06 -0700 X-IronPort-AV: E=McAfee;i="6500,9779,10506"; a="773013440" X-IronPort-AV: E=Sophos;i="5.95,200,1661842800"; d="scan'208";a="773013440" Received: from mulvlfelix.iul.intel.com (HELO localhost) ([172.28.48.92]) by fmsmga001-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2022 05:03:05 -0700 To: gdb-patches@sourceware.org, markus.t.metzger@intel.com Subject: [PATCH v7 09/10] btrace, python: Enable ptwrite filter registration. Date: Fri, 21 Oct 2022 13:59:46 +0200 Message-Id: <20221021115947.359223-10-felix.willgerodt@intel.com> X-Mailer: git-send-email 2.34.3 In-Reply-To: <20221021115947.359223-1-felix.willgerodt@intel.com> References: <20221021115947.359223-1-felix.willgerodt@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Felix Willgerodt via Gdb-patches From: "Willgerodt, Felix" Reply-To: Felix Willgerodt Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" 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 | 4 ++ gdb/btrace.h | 8 ++++ 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 | 80 +++++++++++++++++++++++++++++++ gdb/python/py-record-btrace.c | 88 ++++++++++++++++++++++++++++++++++ gdb/python/py-record-btrace.h | 8 ++++ gdb/python/python-internal.h | 3 ++ gdb/python/python.c | 2 + 12 files changed, 216 insertions(+) create mode 100644 gdb/python/lib/gdb/ptwrite.py diff --git a/gdb/btrace.c b/gdb/btrace.c index 67555e6897d..e6ded61883b 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,9 @@ ftrace_add_pt (struct btrace_thread_info *btinfo, uint64_t offset; int status; + /* Register the ptwrite filter. */ + apply_ext_lang_ptwrite_filter (btinfo); + for (;;) { struct pt_insn insn; diff --git a/gdb/btrace.h b/gdb/btrace.h index 36870d9b2ec..08acf3c5929 100644 --- a/gdb/btrace.h +++ b/gdb/btrace.h @@ -352,6 +352,14 @@ struct btrace_thread_info displaying or stepping through the execution history. */ std::vector aux_data; + /* Function pointer to the ptwrite callback. Returns the string returned + by the ptwrite filter function. */ + std::string (*ptw_callback_fun) (const uint64_t payload, const uint64_t ip, + const void *ptw_context) = nullptr; + + /* Context for the ptw_callback_fun. */ + void *ptw_context = 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 50e9337af6e..972bd444191 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 8cbd80f45d5..ed45b378e4a 100644 --- a/gdb/extension.c +++ b/gdb/extension.c @@ -550,6 +550,19 @@ apply_ext_lang_frame_filter (frame_info_ptr 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 72cff218f5b..edd6e69bf48 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 e5565b627d9..0ddb1567d2d 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_filter, */ 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..0f5b0473023 --- /dev/null +++ b/gdb/python/lib/gdb/ptwrite.py @@ -0,0 +1,80 @@ +# 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 . + +"""Utilities for working with ptwrite filters.""" + +from copy import deepcopy +import gdb + + +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 ptwrite_exit_handler(event): + """Exit handler to prune _ptwrite_filter on inferior exit.""" + for key in list(_ptwrite_filter.keys()): + if key.startswith(f"{event.inferior.pid}."): + del _ptwrite_filter[key] + + +gdb.events.exited.connect(ptwrite_exit_handler) + + +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("The filter must be callable or 'None'.") + + # Clear the traces of all threads to force re-decoding with + # the new filter. + thread_list = gdb.selected_inferior().threads() + _clear_traces(thread_list) + + _ptwrite_filter.clear() + _ptwrite_filter["global"] = filter_ + + +def get_filter(): + """Returns the filters of the current thread.""" + # The key is of this format to enable an per-inferior cleanup when an + # inferior exits. + key = f"{gdb.selected_inferior().pid}.{gdb.selected_thread().ptid[1]}" + + # Create a new filter for new threads. + if key not in _ptwrite_filter.keys(): + _ptwrite_filter[key] = deepcopy(_ptwrite_filter["global"]) + + return _ptwrite_filter[key] diff --git a/gdb/python/py-record-btrace.c b/gdb/python/py-record-btrace.c index c09ba6271b5..6234124e3b1 100644 --- a/gdb/python/py-record-btrace.c +++ b/gdb/python/py-record-btrace.c @@ -763,6 +763,94 @@ recpy_bt_function_call_history (PyObject *self, void *closure) return btpy_list_new (tinfo, first, last, 1, &recpy_func_type); } +/* Helper function that calls PTW_FILTER with PAYLOAD and IP as arguments. + Returns the string that will be printed. */ +std::string +recpy_call_filter (const uint64_t payload, const uint64_t ip, + const void *ptw_filter) +{ + std::string result; + + if ((PyObject *) ptw_filter == nullptr) + error (_("No valid ptwrite filter.")); + if ((PyObject *) ptw_filter == Py_None) + return result; + + gdbpy_enter enter_py; + + gdbpy_ref<> py_payload (PyLong_FromUnsignedLongLong (payload)); + gdbpy_ref<> py_ip (PyLong_FromUnsignedLongLong (ip)); + + if (ip == 0) + py_ip = gdbpy_ref<>::new_reference (Py_None); + + gdbpy_ref<> py_result (PyObject_CallFunctionObjArgs ((PyObject *) ptw_filter, + py_payload.get (), + py_ip.get (), + nullptr)); + + if (PyErr_Occurred ()) + { + gdbpy_print_stack (); + gdbpy_error (_("Couldn't call the ptwrite filter.")); + } + + /* Py_None is valid and results in no output. */ + if (py_result == Py_None) + return result; + + result = gdbpy_obj_to_string (py_result.get ()).get (); + + if (PyErr_Occurred ()) + { + gdbpy_print_stack (); + gdbpy_error (_("The ptwrite filter didn't return a string.")); + } + + return result; +} + +/* Helper function returning the current ptwrite filter. */ + +PyObject * +get_ptwrite_filter () +{ + gdbpy_ref<> module (PyImport_ImportModule ("gdb.ptwrite")); + + if (PyErr_Occurred ()) + { + gdbpy_print_stack (); + return nullptr; + } + + /* We need to keep the reference count. */ + gdbpy_ref<> ptw_filter (PyObject_CallMethod (module.get (), "get_filter", + nullptr)); + + if (PyErr_Occurred ()) + { + gdbpy_print_stack (); + gdbpy_error (_("Couldn't get the ptwrite filter.")); + } + + return ptw_filter.get(); +} + +/* 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) +{ + gdb_assert (btinfo != nullptr); + + gdbpy_enter enter_py; + + btinfo->ptw_callback_fun = &recpy_call_filter; + btinfo->ptw_context= 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..96abb07eaef 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 (); + +/* Helper function to call 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 06357cc8c0b..14fc9ecd24f 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -376,6 +376,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 *, frame_info_ptr frame, frame_filter_flags flags, diff --git a/gdb/python/python.c b/gdb/python/python.c index 29f2010ee8e..1dfa3df7abd 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,