aboutsummaryrefslogtreecommitdiff
path: root/gdb/probe.c
diff options
context:
space:
mode:
authorSergio Durigan Junior <sergiodj@redhat.com>2012-04-27 20:47:57 +0000
committerSergio Durigan Junior <sergiodj@redhat.com>2012-04-27 20:47:57 +0000
commit55aa24fb2eb147288fec359a99e960f7136336e8 (patch)
treed9650d8e5cd7bdbe4f19fb124a2190c8d321db63 /gdb/probe.c
parent2755f698e14dabda211bc592a414ee21e0421a2d (diff)
downloadgdb-55aa24fb2eb147288fec359a99e960f7136336e8.zip
gdb-55aa24fb2eb147288fec359a99e960f7136336e8.tar.gz
gdb-55aa24fb2eb147288fec359a99e960f7136336e8.tar.bz2
2012-04-27 Sergio Durigan Junior <sergiodj@redhat.com>
Tom Tromey <tromey@redhat.com> Jan Kratochvil <jan.kratochvil@redhat.com> * Makefile.in (SFILES): Add `probe' and `stap-probe'. (COMMON_OBS): Likewise. (HFILES_NO_SRCDIR): Add `probe'. * NEWS: Mention support for static and SystemTap probes. * amd64-tdep.c (amd64_init_abi): Initializing proper fields used by SystemTap probes' arguments parser. * arm-linux-tdep.c: Including headers needed to perform the parsing of SystemTap probes' arguments. (arm_stap_is_single_operand): New function. (arm_stap_parse_special_token): Likewise. (arm_linux_init_abi): Initializing proper fields used by SystemTap probes' arguments parser. * ax-gdb.c (require_rvalue): Removing static declaration. (gen_expr): Likewise. * ax-gdb.h (gen_expr): Declaring function. (require_rvalue): Likewise. * breakpoint.c: Include `gdb_regex.h' and `probe.h'. (bkpt_probe_breakpoint_ops): New variable. (momentary_breakpoint_from_master): Set the `probe' value. (add_location_to_breakpoint): Likewise. (break_command_1): Using proper breakpoint_ops according to the argument passed by the user in the command line. (bkpt_probe_insert_location): New function. (bkpt_probe_remove_location): Likewise. (bkpt_probe_create_sals_from_address): Likewise. (bkpt_probe_decode_linespec): Likewise. (tracepoint_probe_create_sals_from_address): Likewise. (tracepoint_probe_decode_linespec): Likewise. (tracepoint_probe_breakpoint_ops): New variable. (trace_command): Using proper breakpoint_ops according to the argument passed by the user in the command line. (initialize_breakpoint_ops): Initializing breakpoint_ops for static probes on breakpoints and tracepoints. * breakpoint.h (struct bp_location) <probe>: New field. * cli-utils.c (skip_spaces_const): New function. (extract_arg): Likewise. * cli-utils.h (skip_spaces_const): Likewise. (extract_arg): Likewise. * coffread.c (coff_sym_fns): Add `sym_probe_fns' value. * configure.ac: Append `stap-probe.o' to be generated when ELF support is present. * configure: Regenerate. * dbxread.c (aout_sym_fns): Add `sym_probe_fns' value. * elfread.c: Include `probe.h' and `arch-utils.h'. (probe_key): New variable. (elf_get_probes): New function. (elf_get_probe_argument_count): Likewise. (elf_evaluate_probe_argument): Likewise. (elf_compile_to_ax): Likewise. (elf_symfile_relocate_probe): Likewise. (stap_probe_key_free): Likewise. (elf_probe_fns): New variable. (elf_sym_fns): Add `sym_probe_fns' value. (elf_sym_fns_lazy_psyms): Likewise. (elf_sym_fns_gdb_index): Likewise. (_initialize_elfread): Initialize objfile cache for static probes. * gdb_vecs.h (struct probe): New forward declaration. (probe_p): New VEC declaration. * gdbarch.c: Regenerate. * gdbarch.h: Regenerate. * gdbarch.sh (stap_integer_prefix): New variable. (stap_integer_suffix): Likewise. (stap_register_prefix): Likewise. (stap_register_suffix): Likewise. (stap_register_indirection_prefix): Likewise. (stap_register_indirection_suffix): Likewise. (stap_gdb_register_prefix): Likewise. (stap_gdb_register_suffix): Likewise. (stap_is_single_operand): New function. (stap_parse_special_token): Likewise. (struct stap_parse_info): Forward declaration. * i386-tdep.c: Including headers needed to perform the parsing of SystemTap probes' arguments. (i386_stap_is_single_operand): New function. (i386_stap_parse_special_token): Likewise. (i386_elf_init_abi): Initializing proper fields used by SystemTap probes' arguments parser. * i386-tdep.h (i386_stap_is_single_operand): New function. (i386_stap_parse_special_token): Likewise. * machoread.c (macho_sym_fns): Add `sym_probe_fns' value. * mipsread.c (ecoff_sym_fns): Likewise. * objfiles.c (objfile_relocate1): Support relocation for static probes. * parse.c (prefixify_expression): Remove static declaration. (initialize_expout): Likewise. (reallocate_expout): Likewise. * parser-defs.h (initialize_expout): Declare function. (reallocate_expout): Likewise. (prefixify_expression): Likewise. * ppc-linux-tdep.c: Including headers needed to perform the parsing of SystemTap probes' arguments. (ppc_stap_is_single_operand): New function. (ppc_stap_parse_special_token): Likewise. (ppc_linux_init_abi): Initializing proper fields used by SystemTap probes' arguments parser. * probe.c: New file, for generic statically defined probe support. * probe.h: Likewise. * s390-tdep.c: Including headers needed to perform the parsing of SystemTap probes' arguments. (s390_stap_is_single_operand): New function. (s390_gdbarch_init): Initializing proper fields used by SystemTap probes' arguments parser. * somread.c (som_sym_fns): Add `sym_probe_fns' value. * stap-probe.c: New file, for SystemTap probe support. * stap-probe.h: Likewise. * symfile.h: Include `gdb_vecs.h'. (struct sym_probe_fns): New struct. (struct sym_fns) <sym_probe_fns>: New field. * symtab.c (init_sal): Initialize `probe' field. * symtab.h (struct probe): Forward declaration. (struct symtab_and_line) <probe>: New field. * tracepoint.c (start_tracing): Adjust semaphore on breakpoints locations. (stop_tracing): Likewise. * xcoffread.c (xcoff_sym_fns): Add `sym_probe_fns' value.
Diffstat (limited to 'gdb/probe.c')
-rw-r--r--gdb/probe.c788
1 files changed, 788 insertions, 0 deletions
diff --git a/gdb/probe.c b/gdb/probe.c
new file mode 100644
index 0000000..4e1b6a0
--- /dev/null
+++ b/gdb/probe.c
@@ -0,0 +1,788 @@
+/* Generic static probe support for GDB.
+
+ Copyright (C) 2012 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "probe.h"
+#include "command.h"
+#include "cli/cli-cmds.h"
+#include "cli/cli-utils.h"
+#include "objfiles.h"
+#include "symtab.h"
+#include "progspace.h"
+#include "filenames.h"
+#include "exceptions.h"
+#include "linespec.h"
+#include "gdb_regex.h"
+#include "frame.h"
+#include "arch-utils.h"
+#include <ctype.h>
+
+
+
+/* See definition in probe.h. */
+
+struct symtabs_and_lines
+parse_probes (char **argptr, struct linespec_result *canonical)
+{
+ char *arg_start, *arg_end, *arg;
+ char *objfile_name = NULL, *provider = NULL, *name, *p;
+ struct cleanup *cleanup;
+ struct symtabs_and_lines result;
+ struct objfile *objfile;
+ struct program_space *pspace;
+ const struct probe_ops *probe_ops;
+ const char *cs;
+
+ result.sals = NULL;
+ result.nelts = 0;
+
+ arg_start = *argptr;
+
+ cs = *argptr;
+ probe_ops = probe_linespec_to_ops (&cs);
+ gdb_assert (probe_ops != NULL);
+
+ arg = (char *) cs;
+ arg = skip_spaces (arg);
+ if (!*arg)
+ error (_("argument to `%s' missing"), arg_start);
+
+ arg_end = skip_to_space (arg);
+
+ /* We make a copy here so we can write over parts with impunity. */
+ arg = savestring (arg, arg_end - arg);
+ cleanup = make_cleanup (xfree, arg);
+
+ /* Extract each word from the argument, separated by ":"s. */
+ p = strchr (arg, ':');
+ if (p == NULL)
+ {
+ /* This is `-p name'. */
+ name = arg;
+ }
+ else
+ {
+ char *hold = p + 1;
+
+ *p = '\0';
+ p = strchr (hold, ':');
+ if (p == NULL)
+ {
+ /* This is `-p provider:name'. */
+ provider = arg;
+ name = hold;
+ }
+ else
+ {
+ /* This is `-p objfile:provider:name'. */
+ *p = '\0';
+ objfile_name = arg;
+ provider = hold;
+ name = p + 1;
+ }
+ }
+
+ if (*name == '\0')
+ error (_("no probe name specified"));
+ if (provider && *provider == '\0')
+ error (_("invalid provider name"));
+ if (objfile_name && *objfile_name == '\0')
+ error (_("invalid objfile name"));
+
+ ALL_PSPACES (pspace)
+ ALL_PSPACE_OBJFILES (pspace, objfile)
+ {
+ VEC (probe_p) *probes;
+ struct probe *probe;
+ int ix;
+
+ if (!objfile->sf || !objfile->sf->sym_probe_fns)
+ continue;
+
+ if (objfile_name
+ && FILENAME_CMP (objfile->name, objfile_name) != 0
+ && FILENAME_CMP (lbasename (objfile->name), objfile_name) != 0)
+ continue;
+
+ if (objfile->separate_debug_objfile_backlink != NULL)
+ continue;
+
+ probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile);
+
+ for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++)
+ {
+ struct symtab_and_line *sal;
+
+ if (probe_ops != &probe_ops_any && probe->pops != probe_ops)
+ continue;
+
+ if (provider && strcmp (probe->provider, provider) != 0)
+ continue;
+
+ if (strcmp (probe->name, name) != 0)
+ continue;
+
+ ++result.nelts;
+ result.sals = xrealloc (result.sals,
+ result.nelts
+ * sizeof (struct symtab_and_line));
+ sal = &result.sals[result.nelts - 1];
+
+ init_sal (sal);
+
+ sal->pc = probe->address;
+ sal->explicit_pc = 1;
+ sal->section = find_pc_overlay (sal->pc);
+ sal->pspace = pspace;
+ sal->probe = probe;
+ }
+ }
+
+ if (result.nelts == 0)
+ {
+ throw_error (NOT_FOUND_ERROR,
+ _("No probe matching objfile=`%s', provider=`%s', name=`%s'"),
+ objfile_name ? objfile_name : _("<any>"),
+ provider ? provider : _("<any>"),
+ name);
+ }
+
+ if (canonical)
+ {
+ canonical->special_display = 1;
+ canonical->pre_expanded = 1;
+ canonical->addr_string = savestring (*argptr, arg_end - *argptr);
+ }
+
+ *argptr = arg_end;
+ do_cleanups (cleanup);
+
+ return result;
+}
+
+/* See definition in probe.h. */
+
+VEC (probe_p) *
+find_probes_in_objfile (struct objfile *objfile, const char *provider,
+ const char *name)
+{
+ VEC (probe_p) *probes, *result = NULL;
+ int ix;
+ struct probe *probe;
+
+ if (!objfile->sf || !objfile->sf->sym_probe_fns)
+ return NULL;
+
+ probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile);
+ for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++)
+ {
+ if (strcmp (probe->provider, provider) != 0)
+ continue;
+
+ if (strcmp (probe->name, name) != 0)
+ continue;
+
+ VEC_safe_push (probe_p, result, probe);
+ }
+
+ return result;
+}
+
+/* See definition in probe.h. */
+
+struct probe *
+find_probe_by_pc (CORE_ADDR pc, struct objfile **objfile_out)
+{
+ struct objfile *objfile;
+
+ ALL_OBJFILES (objfile)
+ {
+ VEC (probe_p) *probes;
+ int ix;
+ struct probe *probe;
+
+ if (!objfile->sf || !objfile->sf->sym_probe_fns)
+ continue;
+
+ /* If this proves too inefficient, we can replace with a hash. */
+ probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile);
+ for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++)
+ if (probe->address == pc)
+ {
+ *objfile_out = objfile;
+ return probe;
+ }
+ }
+
+ return NULL;
+}
+
+
+
+/* A utility structure. A VEC of these is built when handling "info
+ probes". */
+
+struct probe_and_objfile
+{
+ /* The probe. */
+ struct probe *probe;
+
+ /* The probe's objfile. */
+ struct objfile *objfile;
+};
+
+typedef struct probe_and_objfile probe_and_objfile_s;
+DEF_VEC_O (probe_and_objfile_s);
+
+/* A helper function for collect_probes that compiles a regexp and
+ throws an exception on error. This installs a cleanup to free the
+ resulting pattern on success. If RX is NULL, this does nothing. */
+
+static void
+compile_rx_or_error (regex_t *pattern, const char *rx, const char *message)
+{
+ int code;
+
+ if (!rx)
+ return;
+
+ code = regcomp (pattern, rx, REG_NOSUB);
+ if (code == 0)
+ make_regfree_cleanup (pattern);
+ else
+ {
+ char *err = get_regcomp_error (code, pattern);
+
+ make_cleanup (xfree, err);
+ error ("%s: %s", message, err);
+ }
+}
+
+/* Make a vector of probes matching OBJNAME, PROVIDER, and PROBE_NAME.
+ If POPS is not NULL, only probes of this certain probe_ops will match.
+ Each argument is a regexp, or NULL, which matches anything. */
+
+static VEC (probe_and_objfile_s) *
+collect_probes (char *objname, char *provider, char *probe_name,
+ const struct probe_ops *pops)
+{
+ struct objfile *objfile;
+ VEC (probe_and_objfile_s) *result = NULL;
+ struct cleanup *cleanup, *cleanup_temps;
+ regex_t obj_pat, prov_pat, probe_pat;
+
+ cleanup = make_cleanup (VEC_cleanup (probe_and_objfile_s), &result);
+
+ cleanup_temps = make_cleanup (null_cleanup, NULL);
+ compile_rx_or_error (&prov_pat, provider, _("Invalid provider regexp"));
+ compile_rx_or_error (&probe_pat, probe_name, _("Invalid probe regexp"));
+ compile_rx_or_error (&obj_pat, objname, _("Invalid object file regexp"));
+
+ ALL_OBJFILES (objfile)
+ {
+ VEC (probe_p) *probes;
+ struct probe *probe;
+ int ix;
+
+ if (! objfile->sf || ! objfile->sf->sym_probe_fns)
+ continue;
+
+ if (objname)
+ {
+ if (regexec (&obj_pat, objfile->name, 0, NULL, 0) != 0)
+ continue;
+ }
+
+ probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile);
+
+ for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++)
+ {
+ probe_and_objfile_s entry;
+
+ if (pops != NULL && probe->pops != pops)
+ continue;
+
+ if (provider
+ && regexec (&prov_pat, probe->provider, 0, NULL, 0) != 0)
+ continue;
+
+ if (probe_name
+ && regexec (&probe_pat, probe->name, 0, NULL, 0) != 0)
+ continue;
+
+ entry.probe = probe;
+ entry.objfile = objfile;
+ VEC_safe_push (probe_and_objfile_s, result, &entry);
+ }
+ }
+
+ do_cleanups (cleanup_temps);
+ discard_cleanups (cleanup);
+ return result;
+}
+
+/* A qsort comparison function for probe_and_objfile_s objects. */
+
+static int
+compare_entries (const void *a, const void *b)
+{
+ const probe_and_objfile_s *ea = a;
+ const probe_and_objfile_s *eb = b;
+ int v;
+
+ v = strcmp (ea->probe->provider, eb->probe->provider);
+ if (v)
+ return v;
+
+ v = strcmp (ea->probe->name, eb->probe->name);
+ if (v)
+ return v;
+
+ if (ea->probe->address < eb->probe->address)
+ return -1;
+ if (ea->probe->address > eb->probe->address)
+ return 1;
+
+ return strcmp (ea->objfile->name, eb->objfile->name);
+}
+
+/* Helper function that generate entries in the ui_out table being
+ crafted by `info_probes_for_ops'. */
+
+static void
+gen_ui_out_table_header_info (VEC (probe_and_objfile_s) *probes,
+ const struct probe_ops *p)
+{
+ /* `headings' refers to the names of the columns when printing `info
+ probes'. */
+ VEC (info_probe_column_s) *headings = NULL;
+ struct cleanup *c;
+ info_probe_column_s *column;
+ size_t headings_size;
+ int ix;
+
+ gdb_assert (p != NULL);
+
+ if (p->gen_info_probes_table_header == NULL
+ && p->gen_info_probes_table_values == NULL)
+ return;
+
+ gdb_assert (p->gen_info_probes_table_header != NULL
+ && p->gen_info_probes_table_values != NULL);
+
+ c = make_cleanup (VEC_cleanup (info_probe_column_s), &headings);
+ p->gen_info_probes_table_header (&headings);
+
+ headings_size = VEC_length (info_probe_column_s, headings);
+
+ for (ix = 0;
+ VEC_iterate (info_probe_column_s, headings, ix, column);
+ ++ix)
+ {
+ probe_and_objfile_s *entry;
+ int jx;
+ size_t size_max = strlen (column->print_name);
+
+ for (jx = 0; VEC_iterate (probe_and_objfile_s, probes, jx, entry); ++jx)
+ {
+ /* `probe_fields' refers to the values of each new field that this
+ probe will display. */
+ VEC (const_char_ptr) *probe_fields = NULL;
+ struct cleanup *c2;
+ const char *val;
+ int kx;
+
+ if (entry->probe->pops != p)
+ continue;
+
+ c2 = make_cleanup (VEC_cleanup (const_char_ptr), &probe_fields);
+ p->gen_info_probes_table_values (entry->probe, entry->objfile,
+ &probe_fields);
+
+ gdb_assert (VEC_length (const_char_ptr, probe_fields)
+ == headings_size);
+
+ for (kx = 0; VEC_iterate (const_char_ptr, probe_fields, kx, val);
+ ++kx)
+ {
+ /* It is valid to have a NULL value here, which means that the
+ backend does not have something to write and this particular
+ field should be skipped. */
+ if (val == NULL)
+ continue;
+
+ size_max = max (strlen (val), size_max);
+ }
+ do_cleanups (c2);
+ }
+
+ ui_out_table_header (current_uiout, size_max, ui_left,
+ column->field_name, column->print_name);
+ }
+
+ do_cleanups (c);
+}
+
+/* Helper function to print extra information about a probe and an objfile
+ represented by ENTRY. */
+
+static void
+print_ui_out_info (probe_and_objfile_s *entry)
+{
+ int ix;
+ int j = 0;
+ /* `values' refers to the actual values of each new field in the output
+ of `info probe'. `headings' refers to the names of each new field. */
+ VEC (const_char_ptr) *values = NULL;
+ VEC (info_probe_column_s) *headings = NULL;
+ info_probe_column_s *column;
+ struct cleanup *c;
+
+ gdb_assert (entry != NULL);
+ gdb_assert (entry->probe != NULL);
+ gdb_assert (entry->probe->pops != NULL);
+
+ if (entry->probe->pops->gen_info_probes_table_header == NULL
+ && entry->probe->pops->gen_info_probes_table_values == NULL)
+ return;
+
+ gdb_assert (entry->probe->pops->gen_info_probes_table_header != NULL
+ && entry->probe->pops->gen_info_probes_table_values != NULL);
+
+ c = make_cleanup (VEC_cleanup (info_probe_column_s), &headings);
+ make_cleanup (VEC_cleanup (const_char_ptr), &values);
+
+ entry->probe->pops->gen_info_probes_table_header (&headings);
+ entry->probe->pops->gen_info_probes_table_values (entry->probe,
+ entry->objfile, &values);
+
+ gdb_assert (VEC_length (info_probe_column_s, headings)
+ == VEC_length (const_char_ptr, values));
+
+ for (ix = 0;
+ VEC_iterate (info_probe_column_s, headings, ix, column);
+ ++ix)
+ {
+ const char *val = VEC_index (const_char_ptr, values, j++);
+
+ if (val == NULL)
+ ui_out_field_skip (current_uiout, column->field_name);
+ else
+ ui_out_field_string (current_uiout, column->field_name, val);
+ }
+
+ do_cleanups (c);
+}
+
+/* Helper function that returns the number of extra fields which POPS will
+ need. */
+
+static int
+get_number_extra_fields (const struct probe_ops *pops)
+{
+ VEC (info_probe_column_s) *headings = NULL;
+ struct cleanup *c;
+ int n;
+
+ if (pops->gen_info_probes_table_header == NULL)
+ return 0;
+
+ c = make_cleanup (VEC_cleanup (info_probe_column_s), &headings);
+ pops->gen_info_probes_table_header (&headings);
+
+ n = VEC_length (info_probe_column_s, headings);
+
+ do_cleanups (c);
+
+ return n;
+}
+
+/* See comment in probe.h. */
+
+void
+info_probes_for_ops (char *arg, int from_tty, const struct probe_ops *pops)
+{
+ char *provider, *probe = NULL, *objname = NULL;
+ struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+ VEC (probe_and_objfile_s) *items;
+ int i, any_found;
+ int ui_out_extra_fields = 0;
+ size_t size_addr;
+ size_t size_name = strlen ("Name");
+ size_t size_objname = strlen ("Object");
+ size_t size_provider = strlen ("Provider");
+ probe_and_objfile_s *entry;
+ struct gdbarch *gdbarch = get_current_arch ();
+
+ /* Do we have a `provider:probe:objfile' style of linespec? */
+ provider = extract_arg (&arg);
+ if (provider)
+ {
+ make_cleanup (xfree, provider);
+
+ probe = extract_arg (&arg);
+ if (probe)
+ {
+ make_cleanup (xfree, probe);
+
+ objname = extract_arg (&arg);
+ if (objname)
+ make_cleanup (xfree, objname);
+ }
+ }
+
+ if (pops == NULL)
+ {
+ const struct probe_ops *po;
+ int ix;
+
+ /* If the probe_ops is NULL, it means the user has requested a "simple"
+ `info probes', i.e., she wants to print all information about all
+ probes. For that, we have to identify how many extra fields we will
+ need to add in the ui_out table.
+
+ To do that, we iterate over all probe_ops, querying each one about
+ its extra fields, and incrementing `ui_out_extra_fields' to reflect
+ that number. */
+
+ for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po); ++ix)
+ ui_out_extra_fields += get_number_extra_fields (po);
+ }
+ else
+ ui_out_extra_fields = get_number_extra_fields (pops);
+
+ items = collect_probes (objname, provider, probe, pops);
+ make_cleanup (VEC_cleanup (probe_and_objfile_s), &items);
+ make_cleanup_ui_out_table_begin_end (current_uiout,
+ 4 + ui_out_extra_fields,
+ VEC_length (probe_and_objfile_s, items),
+ "StaticProbes");
+
+ if (!VEC_empty (probe_and_objfile_s, items))
+ qsort (VEC_address (probe_and_objfile_s, items),
+ VEC_length (probe_and_objfile_s, items),
+ sizeof (probe_and_objfile_s), compare_entries);
+
+ /* What's the size of an address in our architecture? */
+ size_addr = gdbarch_addr_bit (gdbarch) == 64 ? 18 : 10;
+
+ /* Determining the maximum size of each field (`provider', `name' and
+ `objname'). */
+ for (i = 0; VEC_iterate (probe_and_objfile_s, items, i, entry); ++i)
+ {
+ size_name = max (strlen (entry->probe->name), size_name);
+ size_provider = max (strlen (entry->probe->provider), size_provider);
+ size_objname = max (strlen (entry->objfile->name), size_objname);
+ }
+
+ ui_out_table_header (current_uiout, size_provider, ui_left, "provider",
+ _("Provider"));
+ ui_out_table_header (current_uiout, size_name, ui_left, "name", _("Name"));
+ ui_out_table_header (current_uiout, size_addr, ui_left, "addr", _("Where"));
+
+ if (pops == NULL)
+ {
+ const struct probe_ops *po;
+ int ix;
+
+ /* We have to generate the table header for each new probe type that we
+ will print. */
+ for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po); ++ix)
+ gen_ui_out_table_header_info (items, po);
+ }
+ else
+ gen_ui_out_table_header_info (items, pops);
+
+ ui_out_table_header (current_uiout, size_objname, ui_left, "object",
+ _("Object"));
+ ui_out_table_body (current_uiout);
+
+ for (i = 0; VEC_iterate (probe_and_objfile_s, items, i, entry); ++i)
+ {
+ struct cleanup *inner;
+
+ inner = make_cleanup_ui_out_tuple_begin_end (current_uiout, "probe");
+
+ ui_out_field_string (current_uiout, "provider", entry->probe->provider);
+ ui_out_field_string (current_uiout, "name", entry->probe->name);
+ ui_out_field_core_addr (current_uiout, "addr",
+ get_objfile_arch (entry->objfile),
+ entry->probe->address);
+
+ if (pops == NULL)
+ {
+ const struct probe_ops *po;
+ int ix;
+
+ for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po);
+ ++ix)
+ if (entry->probe->pops == po)
+ print_ui_out_info (entry);
+ }
+ else
+ print_ui_out_info (entry);
+
+ ui_out_field_string (current_uiout, "object", entry->objfile->name);
+ ui_out_text (current_uiout, "\n");
+
+ do_cleanups (inner);
+ }
+
+ any_found = !VEC_empty (probe_and_objfile_s, items);
+ do_cleanups (cleanup);
+
+ if (!any_found)
+ ui_out_message (current_uiout, 0, _("No probes matched.\n"));
+}
+
+/* Implementation of the `info probes' command. */
+
+static void
+info_probes_command (char *arg, int from_tty)
+{
+ info_probes_for_ops (arg, from_tty, NULL);
+}
+
+/* See comments in probe.h. */
+
+struct value *
+probe_safe_evaluate_at_pc (struct frame_info *frame, unsigned n)
+{
+ struct probe *probe;
+ struct objfile *objfile;
+ unsigned n_probes;
+
+ probe = find_probe_by_pc (get_frame_pc (frame), &objfile);
+ if (!probe)
+ return NULL;
+ gdb_assert (objfile->sf && objfile->sf->sym_probe_fns);
+
+ n_probes
+ = objfile->sf->sym_probe_fns->sym_get_probe_argument_count (objfile,
+ probe);
+ if (n >= n_probes)
+ return NULL;
+
+ return objfile->sf->sym_probe_fns->sym_evaluate_probe_argument (objfile,
+ probe,
+ n);
+}
+
+/* See comment in probe.h. */
+
+const struct probe_ops *
+probe_linespec_to_ops (const char **linespecp)
+{
+ int ix;
+ const struct probe_ops *probe_ops;
+
+ for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, probe_ops); ix++)
+ if (probe_ops->is_linespec (linespecp))
+ return probe_ops;
+
+ return NULL;
+}
+
+/* See comment in probe.h. */
+
+int
+probe_is_linespec_by_keyword (const char **linespecp, const char *const *keywords)
+{
+ const char *s = *linespecp;
+ const char *const *csp;
+
+ for (csp = keywords; *csp; csp++)
+ {
+ const char *keyword = *csp;
+ size_t len = strlen (keyword);
+
+ if (strncmp (s, keyword, len) == 0 && isspace (s[len]))
+ {
+ *linespecp += len + 1;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Implementation of `is_linespec' method for `struct probe_ops'. */
+
+static int
+probe_any_is_linespec (const char **linespecp)
+{
+ static const char *const keywords[] = { "-p", "-probe", NULL };
+
+ return probe_is_linespec_by_keyword (linespecp, keywords);
+}
+
+/* Dummy method used for `probe_ops_any'. */
+
+static void
+probe_any_get_probes (VEC (probe_p) **probesp, struct objfile *objfile)
+{
+ /* No probes can be provided by this dummy backend. */
+}
+
+/* Operations associated with a generic probe. */
+
+const struct probe_ops probe_ops_any =
+{
+ probe_any_is_linespec,
+ probe_any_get_probes,
+};
+
+/* See comments in probe.h. */
+
+struct cmd_list_element **
+info_probes_cmdlist_get (void)
+{
+ static struct cmd_list_element *info_probes_cmdlist;
+
+ if (info_probes_cmdlist == NULL)
+ add_prefix_cmd ("probes", class_info, info_probes_command,
+ _("\
+Show available static probes.\n\
+Usage: info probes [all|TYPE [ARGS]]\n\
+TYPE specifies the type of the probe, and can be one of the following:\n\
+ - stap\n\
+If you specify TYPE, there may be additional arguments needed by the\n\
+subcommand.\n\
+If you do not specify any argument, or specify `all', then the command\n\
+will show information about all types of probes."),
+ &info_probes_cmdlist, "info probes ",
+ 0/*allow-unknown*/, &infolist);
+
+ return &info_probes_cmdlist;
+}
+
+VEC (probe_ops_cp) *all_probe_ops;
+
+void _initialize_probe (void);
+
+void
+_initialize_probe (void)
+{
+ VEC_safe_push (probe_ops_cp, all_probe_ops, &probe_ops_any);
+
+ add_cmd ("all", class_info, info_probes_command,
+ _("\
+Show information about all type of probes."),
+ info_probes_cmdlist_get ());
+}