From 08c59458a106038c6d678621e7290948127671e2 Mon Sep 17 00:00:00 2001 From: Tom de Vries Date: Sat, 31 Dec 2022 10:23:06 +0100 Subject: [PATCH] [gdb/cli] Add maintenance ignore-probes There's a command "disable probes", but SystemTap probes, for instance libc:longjmp cannot be disabled: ... $ gdb -q -batch a.out -ex start -ex "disable probes libc ^longjmp$" ... Probe libc:longjmp cannot be disabled. Probe libc:longjmp cannot be disabled. Probe libc:longjmp cannot be disabled. ... Add a command "maintenance ignore-probes" that ignores probes during get_probes, such that we can easily pretend to use a libc without the libc:longjmp probe: ... (gdb) maint ignore-probes -verbose libc ^longjmp$ ignore-probes filter has been set to: PROVIDER: 'libc' PROBE_NAME: '^longjmp$' OBJNAME: '' (gdb) start ^M ... Ignoring SystemTap probe libc longjmp in /lib64/libc.so.6.^M Ignoring SystemTap probe libc longjmp in /lib64/libc.so.6.^M Ignoring SystemTap probe libc longjmp in /lib64/libc.so.6.^M ... The "Ignoring ..." messages can be suppressed by not using -verbose. Note that as with "disable probes", running simply "maint ignore-probes" ignores all probes. The ignore-probes filter can be reset by using: ... (gdb) maint ignore-probes -reset ignore-probes filter has been reset ... For now, the command is only supported for SystemTap probes. PR cli/27159 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=27159 --- gdb/doc/gdb.texinfo | 22 +++++++++ gdb/probe.c | 115 ++++++++++++++++++++++++++++++++++++++++++++ gdb/probe.h | 5 ++ gdb/stap-probe.c | 3 ++ 4 files changed, 145 insertions(+) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 21a00edc676..704415bd845 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -6114,6 +6114,7 @@ disabled, but @code{SystemTap} probes cannot be disabled. You can enable (or disable) one or more probes using the following commands, with optional arguments: +@anchor{enable probes} @table @code @kindex enable probes @item enable probes @r{[}@var{provider} @r{[}@var{name} @r{[}@var{objfile}@r{]}@r{]}@r{]} @@ -40897,6 +40898,27 @@ Like the @code{with} command, but works with @code{maintenance set} variables. This is used by the testsuite to exercise the @code{with} command's infrastructure. +@kindex maint ignore-probes +@item maint ignore-probes [@var{-v}|@var{-verbose}] [@var{provider} [@var{name} [@var{objfile}]]] +@itemx maint ignore-probes @var{-reset} +Set or reset the ignore-probes filter. The @var{provider}, @var{name} +and @var{objfile} arguments are as in @code{enable probes} and +@code{disable probes} (@pxref{enable probes}). Only supported for +SystemTap probes. + +Here's an example of using @code{maint ignore-probes}: +@smallexample +(gdb) maint ignore-probes -verbose libc ^longjmp$ +ignore-probes filter has been set to: +PROVIDER: 'libc' +PROBE_NAME: '^longjmp$' +OBJNAME: '' +(gdb) start +<... more output ...> +Ignoring SystemTap probe libc longjmp in /lib64/libc.so.6.^M +Ignoring SystemTap probe libc longjmp in /lib64/libc.so.6.^M +Ignoring SystemTap probe libc longjmp in /lib64/libc.so.6.^M +@end smallexample @end table The following command is useful for non-interactive invocations of diff --git a/gdb/probe.c b/gdb/probe.c index 4193f9f936b..10e51df6dae 100644 --- a/gdb/probe.c +++ b/gdb/probe.c @@ -680,6 +680,109 @@ disable_probes_command (const char *arg, int from_tty) } } +static bool ignore_probes_p = false; +static bool ignore_probes_idx = 0; +static bool ignore_probes_verbose_p; +static gdb::optional ignore_probes_prov_pat[2]; +static gdb::optional ignore_probes_name_pat[2]; +static gdb::optional ignore_probes_obj_pat[2]; + +/* See comments in probe.h. */ + +bool +ignore_probe_p (const char *provider, const char *name, + const char *objfile_name, const char *type) +{ + if (!ignore_probes_p) + return false; + + gdb::optional &re_prov + = ignore_probes_prov_pat[ignore_probes_idx]; + gdb::optional &re_name + = ignore_probes_name_pat[ignore_probes_idx]; + gdb::optional &re_obj + = ignore_probes_obj_pat[ignore_probes_idx]; + + bool res + = ((!re_prov + || re_prov->exec (provider, 0, NULL, 0) == 0) + && (!re_name + || re_name->exec (name, 0, NULL, 0) == 0) + && (!re_obj + || re_obj->exec (objfile_name, 0, NULL, 0) == 0)); + + if (res && ignore_probes_verbose_p) + gdb_printf (gdb_stdlog, _("Ignoring %s probe %s %s in %s.\n"), + type, provider, name, objfile_name); + + return res; +} + +/* Implementation of the `maintenance ignore-probes' command. */ + +static void +ignore_probes_command (const char *arg, int from_tty) +{ + std::string ignore_provider, ignore_probe_name, ignore_objname; + + bool verbose_p = false; + if (arg != nullptr) + { + const char *idx = arg; + std::string s = extract_arg (&idx); + + if (strcmp (s.c_str (), "-reset") == 0) + { + if (*idx != '\0') + error (_("-reset: no arguments allowed")); + + ignore_probes_p = false; + gdb_printf (gdb_stdout, _("ignore-probes filter has been reset\n")); + return; + } + + if (strcmp (s.c_str (), "-verbose") == 0 + || strcmp (s.c_str (), "-v") == 0) + { + verbose_p = true; + arg = idx; + } + } + + parse_probe_linespec (arg, &ignore_provider, &ignore_probe_name, + &ignore_objname); + + /* Parse the regular expressions, making sure that the old regular + expressions are still valid if an exception is throw. */ + int new_ignore_probes_idx = 1 - ignore_probes_idx; + gdb::optional &re_prov + = ignore_probes_prov_pat[new_ignore_probes_idx]; + gdb::optional &re_name + = ignore_probes_name_pat[new_ignore_probes_idx]; + gdb::optional &re_obj + = ignore_probes_obj_pat[new_ignore_probes_idx]; + re_prov.reset (); + re_name.reset (); + re_obj.reset (); + if (!ignore_provider.empty ()) + re_prov.emplace (ignore_provider.c_str (), REG_NOSUB, + _("Invalid provider regexp")); + if (!ignore_probe_name.empty ()) + re_name.emplace (ignore_probe_name.c_str (), REG_NOSUB, + _("Invalid probe regexp")); + if (!ignore_objname.empty ()) + re_obj.emplace (ignore_objname.c_str (), REG_NOSUB, + _("Invalid object file regexp")); + ignore_probes_idx = new_ignore_probes_idx; + + ignore_probes_p = true; + ignore_probes_verbose_p = verbose_p; + gdb_printf (gdb_stdout, _("ignore-probes filter has been set to:\n")); + gdb_printf (gdb_stdout, _("PROVIDER: '%s'\n"), ignore_provider.c_str ()); + gdb_printf (gdb_stdout, _("PROBE_NAME: '%s'\n"), ignore_probe_name.c_str ()); + gdb_printf (gdb_stdout, _("OBJNAME: '%s'\n"), ignore_objname.c_str ()); +} + /* See comments in probe.h. */ struct value * @@ -931,4 +1034,16 @@ If you do not specify any argument then the command will disable\n\ all defined probes."), &disablelist); + add_cmd ("ignore-probes", class_maintenance, ignore_probes_command, _("\ +Ignore probes.\n\ +Usage: maintenance ignore-probes [-v|-verbose] [PROVIDER [NAME [OBJECT]]]\n\ + maintenance ignore-probes -reset\n\ +Each argument is a regular expression, used to select probes.\n\ +PROVIDER matches probe provider names.\n\ +NAME matches the probe names.\n\ +OBJECT matches the executable or shared library name.\n\ +If you do not specify any argument then the command will ignore\n\ +all defined probes. To reset the ignore-probes filter, use the -reset form.\n\ +Only supported for SystemTap probes."), + &maintenancelist); } diff --git a/gdb/probe.h b/gdb/probe.h index 598f43a238e..a6001769cbd 100644 --- a/gdb/probe.h +++ b/gdb/probe.h @@ -304,4 +304,9 @@ extern struct cmd_list_element **info_probes_cmdlist_get (void); extern struct value *probe_safe_evaluate_at_pc (frame_info_ptr frame, unsigned n); +/* Return true if the PROVIDER/NAME probe from OBJFILE_NAME needs to be + ignored. */ + +bool ignore_probe_p (const char *provider, const char *name, + const char *objfile_name, const char *TYPE); #endif /* !defined (PROBE_H) */ diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c index 6f91d87846a..f119e2c02ff 100644 --- a/gdb/stap-probe.c +++ b/gdb/stap-probe.c @@ -1619,6 +1619,9 @@ handle_stap_probe (struct objfile *objfile, struct sdt_note *el, return; } + if (ignore_probe_p (provider, name, objfile_name (objfile), "SystemTap")) + return; + stap_probe *ret = new stap_probe (std::string (name), std::string (provider), address, gdbarch, sem_addr, probe_args); -- 2.30.2