X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fprobe.c;h=8b108d6b02dce8e8dc87a7a01244199b740e93e6;hb=e671856cb804c977650aaeb4107948a7b963e9e9;hp=c1e0111529373fb38ab3f2ba2b66a3b0042a0137;hpb=37fbcad0beb1a512efb5bc26071df5c12b5408cd;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/probe.c b/gdb/probe.c index c1e0111529..8b108d6b02 100644 --- a/gdb/probe.c +++ b/gdb/probe.c @@ -1,6 +1,6 @@ /* Generic static probe support for GDB. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2019 Free Software Foundation, Inc. This file is part of GDB. @@ -26,37 +26,109 @@ #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 "value.h" +#include "ax.h" +#include "ax-gdb.h" +#include "location.h" #include +#include +#include "gdbsupport/gdb_optional.h" - +/* Class that implements the static probe methods for "any" probe. */ + +class any_static_probe_ops : public static_probe_ops +{ +public: + /* See probe.h. */ + bool is_linespec (const char **linespecp) const override; + + /* See probe.h. */ + void get_probes (std::vector> *probesp, + struct objfile *objfile) const override; + + /* See probe.h. */ + const char *type_name () const override; + + /* See probe.h. */ + std::vector gen_info_probes_table_header + () const override; +}; + +/* Static operations associated with a generic probe. */ + +const any_static_probe_ops any_static_probe_ops {}; + +/* A helper for parse_probes that decodes a probe specification in + SEARCH_PSPACE. It appends matching SALs to RESULT. */ + +static void +parse_probes_in_pspace (const static_probe_ops *spops, + struct program_space *search_pspace, + const char *objfile_namestr, + const char *provider, + const char *name, + std::vector *result) +{ + for (objfile *objfile : search_pspace->objfiles ()) + { + if (!objfile->sf || !objfile->sf->sym_probe_fns) + continue; + + if (objfile_namestr + && FILENAME_CMP (objfile_name (objfile), objfile_namestr) != 0 + && FILENAME_CMP (lbasename (objfile_name (objfile)), + objfile_namestr) != 0) + continue; + + const std::vector> &probes + = objfile->sf->sym_probe_fns->sym_get_probes (objfile); + + for (auto &p : probes) + { + if (spops != &any_static_probe_ops && p->get_static_ops () != spops) + continue; + + if (provider != NULL && p->get_provider () != provider) + continue; + + if (p->get_name () != name) + continue; + + symtab_and_line sal; + sal.pc = p->get_relocated_address (objfile); + sal.explicit_pc = 1; + sal.section = find_pc_overlay (sal.pc); + sal.pspace = search_pspace; + sal.prob = p.get (); + sal.objfile = objfile; + + result->push_back (std::move (sal)); + } + } +} /* See definition in probe.h. */ -struct symtabs_and_lines -parse_probes (char **argptr, struct linespec_result *canonical) +std::vector +parse_probes (const struct event_location *location, + struct program_space *search_pspace, + struct linespec_result *canonical) { - char *arg_start, *arg_end, *arg; + char *arg_end, *arg; char *objfile_namestr = 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; + const char *arg_start, *cs; - result.sals = NULL; - result.nelts = 0; + gdb_assert (event_location_type (location) == PROBE_LOCATION); + arg_start = get_probe_location (location); - arg_start = *argptr; - - cs = *argptr; - probe_ops = probe_linespec_to_ops (&cs); - gdb_assert (probe_ops != NULL); + cs = arg_start; + const static_probe_ops *spops = probe_linespec_to_static_ops (&cs); + if (spops == NULL) + error (_("'%s' is not a probe linespec"), arg_start); arg = (char *) cs; arg = skip_spaces (arg); @@ -66,8 +138,8 @@ parse_probes (char **argptr, struct linespec_result *canonical) 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); + std::string copy (arg, arg_end - arg); + arg = ©[0]; /* Extract each word from the argument, separated by ":"s. */ p = strchr (arg, ':'); @@ -105,54 +177,22 @@ parse_probes (char **argptr, struct linespec_result *canonical) if (objfile_namestr && *objfile_namestr == '\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_namestr - && FILENAME_CMP (objfile_name (objfile), objfile_namestr) != 0 - && FILENAME_CMP (lbasename (objfile_name (objfile)), - objfile_namestr) != 0) - 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); + std::vector result; + if (search_pspace != NULL) + { + parse_probes_in_pspace (spops, search_pspace, objfile_namestr, + provider, name, &result); + } + else + { + struct program_space *pspace; - sal->pc = probe->address; - sal->explicit_pc = 1; - sal->section = find_pc_overlay (sal->pc); - sal->pspace = pspace; - sal->probe = probe; - } - } + ALL_PSPACES (pspace) + parse_probes_in_pspace (spops, pspace, objfile_namestr, + provider, name, &result); + } - if (result.nelts == 0) + if (result.empty ()) { throw_error (NOT_FOUND_ERROR, _("No probe matching objfile=`%s', provider=`%s', name=`%s'"), @@ -163,40 +203,37 @@ parse_probes (char **argptr, struct linespec_result *canonical) if (canonical) { + std::string canon (arg_start, arg_end - arg_start); canonical->special_display = 1; canonical->pre_expanded = 1; - canonical->addr_string = savestring (*argptr, arg_end - *argptr); + canonical->location = new_probe_location (canon.c_str ()); } - *argptr = arg_end; - do_cleanups (cleanup); - return result; } /* See definition in probe.h. */ -VEC (probe_p) * +std::vector find_probes_in_objfile (struct objfile *objfile, const char *provider, const char *name) { - VEC (probe_p) *probes, *result = NULL; - int ix; - struct probe *probe; + std::vector result; if (!objfile->sf || !objfile->sf->sym_probe_fns) - return NULL; + return result; - probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile); - for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++) + const std::vector> &probes + = objfile->sf->sym_probe_fns->sym_get_probes (objfile); + for (auto &p : probes) { - if (strcmp (probe->provider, provider) != 0) + if (p->get_provider () != provider) continue; - if (strcmp (probe->name, name) != 0) + if (p->get_name () != name) continue; - VEC_safe_push (probe_p, result, probe); + result.push_back (p.get ()); } return result; @@ -204,176 +241,146 @@ find_probes_in_objfile (struct objfile *objfile, const char *provider, /* See definition in probe.h. */ -struct probe * +struct bound_probe find_probe_by_pc (CORE_ADDR pc) { - struct objfile *objfile; + struct bound_probe result; - 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) - return probe; - } + result.objfile = NULL; + result.prob = NULL; - return NULL; + for (objfile *objfile : current_program_space->objfiles ()) + { + if (!objfile->sf || !objfile->sf->sym_probe_fns + || objfile->sect_index_text == -1) + continue; + + /* If this proves too inefficient, we can replace with a hash. */ + const std::vector> &probes + = objfile->sf->sym_probe_fns->sym_get_probes (objfile); + for (auto &p : probes) + if (p->get_relocated_address (objfile) == pc) + { + result.objfile = objfile; + result.prob = p.get (); + return result; + } + } + + return result; } /* 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. */ + If SPOPS is not &any_static_probe_ops, only probes related to this + specific static probe ops will match. Each argument is a regexp, + or NULL, which matches anything. */ -static VEC (probe_p) * -collect_probes (char *objname, char *provider, char *probe_name, - const struct probe_ops *pops) +static std::vector +collect_probes (const std::string &objname, const std::string &provider, + const std::string &probe_name, const static_probe_ops *spops) { - struct objfile *objfile; - VEC (probe_p) *result = NULL; - struct cleanup *cleanup, *cleanup_temps; - regex_t obj_pat, prov_pat, probe_pat; - - cleanup = make_cleanup (VEC_cleanup (probe_p), &result); - - cleanup_temps = make_cleanup (null_cleanup, NULL); - if (provider != NULL) - compile_rx_or_error (&prov_pat, provider, _("Invalid provider regexp")); - if (probe_name != NULL) - compile_rx_or_error (&probe_pat, probe_name, _("Invalid probe regexp")); - if (objname != NULL) - compile_rx_or_error (&obj_pat, objname, _("Invalid object file regexp")); - - ALL_OBJFILES (objfile) + std::vector result; + gdb::optional obj_pat, prov_pat, probe_pat; + + if (!provider.empty ()) + prov_pat.emplace (provider.c_str (), REG_NOSUB, + _("Invalid provider regexp")); + if (!probe_name.empty ()) + probe_pat.emplace (probe_name.c_str (), REG_NOSUB, + _("Invalid probe regexp")); + if (!objname.empty ()) + obj_pat.emplace (objname.c_str (), REG_NOSUB, + _("Invalid object file regexp")); + + for (objfile *objfile : current_program_space->objfiles ()) { - VEC (probe_p) *probes; - struct probe *probe; - int ix; - if (! objfile->sf || ! objfile->sf->sym_probe_fns) continue; - if (objname) + if (obj_pat) { - if (regexec (&obj_pat, objfile_name (objfile), 0, NULL, 0) != 0) + if (obj_pat->exec (objfile_name (objfile), 0, NULL, 0) != 0) continue; } - probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile); + const std::vector> &probes + = objfile->sf->sym_probe_fns->sym_get_probes (objfile); - for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++) + for (auto &p : probes) { - if (pops != NULL && probe->pops != pops) + if (spops != &any_static_probe_ops && p->get_static_ops () != spops) continue; - if (provider - && regexec (&prov_pat, probe->provider, 0, NULL, 0) != 0) + if (prov_pat + && prov_pat->exec (p->get_provider ().c_str (), 0, NULL, 0) != 0) continue; - if (probe_name - && regexec (&probe_pat, probe->name, 0, NULL, 0) != 0) + if (probe_pat + && probe_pat->exec (p->get_name ().c_str (), 0, NULL, 0) != 0) continue; - VEC_safe_push (probe_p, result, probe); + result.emplace_back (p.get (), objfile); } } - do_cleanups (cleanup_temps); - discard_cleanups (cleanup); return result; } -/* A qsort comparison function for probe_p objects. */ +/* A qsort comparison function for bound_probe_s objects. */ -static int -compare_probes (const void *a, const void *b) +static bool +compare_probes (const bound_probe &a, const bound_probe &b) { - const struct probe *pa = *((const struct probe **) a); - const struct probe *pb = *((const struct probe **) b); int v; - v = strcmp (pa->provider, pb->provider); - if (v) - return v; + v = a.prob->get_provider ().compare (b.prob->get_provider ()); + if (v != 0) + return v < 0; - v = strcmp (pa->name, pb->name); - if (v) - return v; + v = a.prob->get_name ().compare (b.prob->get_name ()); + if (v != 0) + return v < 0; - if (pa->address < pb->address) - return -1; - if (pa->address > pb->address) - return 1; + if (a.prob->get_address () != b.prob->get_address ()) + return a.prob->get_address () < b.prob->get_address (); - return strcmp (objfile_name (pa->objfile), objfile_name (pb->objfile)); + return strcmp (objfile_name (a.objfile), objfile_name (b.objfile)) < 0; } /* 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_p) *probes, - const struct probe_ops *p) +gen_ui_out_table_header_info (const std::vector &probes, + const static_probe_ops *spops) { /* `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); + gdb_assert (spops != NULL); - if (p->gen_info_probes_table_header == NULL - && p->gen_info_probes_table_values == NULL) - return; + std::vector headings + = spops->gen_info_probes_table_header (); - 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) + for (const info_probe_column &column : headings) { - struct probe *probe; - int jx; - size_t size_max = strlen (column->print_name); + size_t size_max = strlen (column.print_name); - for (jx = 0; VEC_iterate (probe_p, probes, jx, probe); ++jx) + for (const bound_probe &probe : probes) { /* `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 (probe->pops != p) + if (probe.prob->get_static_ops () != spops) continue; - c2 = make_cleanup (VEC_cleanup (const_char_ptr), &probe_fields); - p->gen_info_probes_table_values (probe, &probe_fields); + std::vector probe_fields + = probe.prob->gen_info_probes_table_values (); - gdb_assert (VEC_length (const_char_ptr, probe_fields) - == headings_size); + gdb_assert (probe_fields.size () == headings.size ()); - for (kx = 0; VEC_iterate (const_char_ptr, probe_fields, kx, val); - ++kx) + for (const char *val : probe_fields) { /* It is valid to have a NULL value here, which means that the backend does not have something to write and this particular @@ -381,258 +388,299 @@ gen_ui_out_table_header_info (VEC (probe_p) *probes, if (val == NULL) continue; - size_max = max (strlen (val), size_max); + size_max = std::max (strlen (val), size_max); } - do_cleanups (c2); } - ui_out_table_header (current_uiout, size_max, ui_left, - column->field_name, column->print_name); + current_uiout->table_header (size_max, ui_left, + column.field_name, column.print_name); } +} + +/* Helper function to print not-applicable strings for all the extra + columns defined in a static_probe_ops. */ - do_cleanups (c); +static void +print_ui_out_not_applicables (const static_probe_ops *spops) +{ + std::vector headings + = spops->gen_info_probes_table_header (); + + for (const info_probe_column &column : headings) + current_uiout->field_string (column.field_name, _("n/a")); } /* Helper function to print extra information about a probe and an objfile represented by PROBE. */ static void -print_ui_out_info (struct probe *probe) +print_ui_out_info (probe *probe) { - 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 (probe != NULL); - gdb_assert (probe->pops != NULL); - - if (probe->pops->gen_info_probes_table_header == NULL - && probe->pops->gen_info_probes_table_values == NULL) - return; - - gdb_assert (probe->pops->gen_info_probes_table_header != NULL - && probe->pops->gen_info_probes_table_values != NULL); + std::vector headings + = probe->get_static_ops ()->gen_info_probes_table_header (); + std::vector values + = probe->gen_info_probes_table_values (); - c = make_cleanup (VEC_cleanup (info_probe_column_s), &headings); - make_cleanup (VEC_cleanup (const_char_ptr), &values); + gdb_assert (headings.size () == values.size ()); - probe->pops->gen_info_probes_table_header (&headings); - probe->pops->gen_info_probes_table_values (probe, &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) + for (int ix = 0; ix < headings.size (); ++ix) { - const char *val = VEC_index (const_char_ptr, values, j++); + struct info_probe_column column = headings[ix]; + const char *val = values[ix]; if (val == NULL) - ui_out_field_skip (current_uiout, column->field_name); + current_uiout->field_skip (column.field_name); else - ui_out_field_string (current_uiout, column->field_name, val); + current_uiout->field_string (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) +get_number_extra_fields (const static_probe_ops *spops) { - VEC (info_probe_column_s) *headings = NULL; - struct cleanup *c; - int n; + return spops->gen_info_probes_table_header ().size (); +} - if (pops->gen_info_probes_table_header == NULL) - return 0; +/* Helper function that returns true if there is a probe in PROBES + featuring the given SPOPS. It returns false otherwise. */ - c = make_cleanup (VEC_cleanup (info_probe_column_s), &headings); - pops->gen_info_probes_table_header (&headings); +static bool +exists_probe_with_spops (const std::vector &probes, + const static_probe_ops *spops) +{ + for (const bound_probe &probe : probes) + if (probe.prob->get_static_ops () == spops) + return true; - n = VEC_length (info_probe_column_s, headings); + return false; +} - do_cleanups (c); +/* Helper function that parses a probe linespec of the form [PROVIDER + [PROBE [OBJNAME]]] from the provided string STR. */ - return n; +static void +parse_probe_linespec (const char *str, std::string *provider, + std::string *probe_name, std::string *objname) +{ + *probe_name = *objname = ""; + + *provider = extract_arg (&str); + if (!provider->empty ()) + { + *probe_name = extract_arg (&str); + if (!probe_name->empty ()) + *objname = extract_arg (&str); + } } /* See comment in probe.h. */ void -info_probes_for_ops (char *arg, int from_tty, const struct probe_ops *pops) +info_probes_for_spops (const char *arg, int from_tty, + const static_probe_ops *spops) { - char *provider, *probe_name = NULL, *objname = NULL; - struct cleanup *cleanup = make_cleanup (null_cleanup, NULL); - VEC (probe_p) *probes; - int i, any_found; + std::string provider, probe_name, objname; + int 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"); - struct probe *probe; + size_t size_type = strlen ("Type"); 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); + parse_probe_linespec (arg, &provider, &probe_name, &objname); - probe_name = extract_arg (&arg); - if (probe_name) - { - make_cleanup (xfree, probe_name); + std::vector probes + = collect_probes (objname, provider, probe_name, spops); - objname = extract_arg (&arg); - if (objname) - make_cleanup (xfree, objname); - } - } - - if (pops == NULL) + if (spops == &any_static_probe_ops) { - 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); + /* If SPOPS is &any_static_probe_ops, 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 static_probe_ops, querying + each one about its extra fields, and incrementing + `ui_out_extra_fields' to reflect that number. But note that + we ignore the static_probe_ops for which no probes are + defined with the given search criteria. */ + + for (const static_probe_ops *po : all_static_probe_ops) + if (exists_probe_with_spops (probes, po)) + ui_out_extra_fields += get_number_extra_fields (po); } else - ui_out_extra_fields = get_number_extra_fields (pops); - - probes = collect_probes (objname, provider, probe_name, pops); - make_cleanup (VEC_cleanup (probe_p), &probes); - make_cleanup_ui_out_table_begin_end (current_uiout, - 4 + ui_out_extra_fields, - VEC_length (probe_p, probes), - "StaticProbes"); + ui_out_extra_fields = get_number_extra_fields (spops); - if (!VEC_empty (probe_p, probes)) - qsort (VEC_address (probe_p, probes), VEC_length (probe_p, probes), - sizeof (probe_p), compare_probes); - - /* 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_p, probes, i, probe); ++i) - { - size_name = max (strlen (probe->name), size_name); - size_provider = max (strlen (probe->provider), size_provider); - size_objname = max (strlen (objfile_name (probe->objfile)), size_objname); - } + { + ui_out_emit_table table_emitter (current_uiout, + 5 + ui_out_extra_fields, + probes.size (), "StaticProbes"); - 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")); + std::sort (probes.begin (), probes.end (), compare_probes); - if (pops == NULL) - { - const struct probe_ops *po; - int ix; + /* What's the size of an address in our architecture? */ + size_addr = gdbarch_addr_bit (gdbarch) == 64 ? 18 : 10; - /* 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 (probes, po); - } - else - gen_ui_out_table_header_info (probes, pops); + /* Determining the maximum size of each field (`type', `provider', + `name' and `objname'). */ + for (const bound_probe &probe : probes) + { + const char *probe_type = probe.prob->get_static_ops ()->type_name (); + + size_type = std::max (strlen (probe_type), size_type); + size_name = std::max (probe.prob->get_name ().size (), size_name); + size_provider = std::max (probe.prob->get_provider ().size (), + size_provider); + size_objname = std::max (strlen (objfile_name (probe.objfile)), + size_objname); + } - ui_out_table_header (current_uiout, size_objname, ui_left, "object", - _("Object")); - ui_out_table_body (current_uiout); + current_uiout->table_header (size_type, ui_left, "type", _("Type")); + current_uiout->table_header (size_provider, ui_left, "provider", + _("Provider")); + current_uiout->table_header (size_name, ui_left, "name", _("Name")); + current_uiout->table_header (size_addr, ui_left, "addr", _("Where")); - for (i = 0; VEC_iterate (probe_p, probes, i, probe); ++i) - { - struct cleanup *inner; + if (spops == &any_static_probe_ops) + { + /* We have to generate the table header for each new probe type + that we will print. Note that this excludes probe types not + having any defined probe with the search criteria. */ + for (const static_probe_ops *po : all_static_probe_ops) + if (exists_probe_with_spops (probes, po)) + gen_ui_out_table_header_info (probes, po); + } + else + gen_ui_out_table_header_info (probes, spops); - inner = make_cleanup_ui_out_tuple_begin_end (current_uiout, "probe"); + current_uiout->table_header (size_objname, ui_left, "object", _("Object")); + current_uiout->table_body (); - ui_out_field_string (current_uiout, "provider", probe->provider); - ui_out_field_string (current_uiout, "name", probe->name); - ui_out_field_core_addr (current_uiout, "addr", - get_objfile_arch (probe->objfile), - probe->address); + for (const bound_probe &probe : probes) + { + const char *probe_type = probe.prob->get_static_ops ()->type_name (); - if (pops == NULL) - { - const struct probe_ops *po; - int ix; + ui_out_emit_tuple tuple_emitter (current_uiout, "probe"); - for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po); - ++ix) - if (probe->pops == po) - print_ui_out_info (probe); - } - else - print_ui_out_info (probe); + current_uiout->field_string ("type", probe_type); + current_uiout->field_string ("provider", + probe.prob->get_provider ().c_str ()); + current_uiout->field_string ("name", probe.prob->get_name ().c_str ()); + current_uiout->field_core_addr ("addr", probe.prob->get_gdbarch (), + probe.prob->get_relocated_address + (probe.objfile)); - ui_out_field_string (current_uiout, "object", - objfile_name (probe->objfile)); - ui_out_text (current_uiout, "\n"); + if (spops == &any_static_probe_ops) + { + for (const static_probe_ops *po : all_static_probe_ops) + { + if (probe.prob->get_static_ops () == po) + print_ui_out_info (probe.prob); + else if (exists_probe_with_spops (probes, po)) + print_ui_out_not_applicables (po); + } + } + else + print_ui_out_info (probe.prob); - do_cleanups (inner); - } + current_uiout->field_string ("object", + objfile_name (probe.objfile)); + current_uiout->text ("\n"); + } - any_found = !VEC_empty (probe_p, probes); - do_cleanups (cleanup); + any_found = !probes.empty (); + } if (!any_found) - ui_out_message (current_uiout, 0, _("No probes matched.\n")); + current_uiout->message (_("No probes matched.\n")); } /* Implementation of the `info probes' command. */ static void -info_probes_command (char *arg, int from_tty) +info_probes_command (const char *arg, int from_tty) { - info_probes_for_ops (arg, from_tty, NULL); + info_probes_for_spops (arg, from_tty, &any_static_probe_ops); } -/* See comments in probe.h. */ +/* Implementation of the `enable probes' command. */ -unsigned -get_probe_argument_count (struct probe *probe) +static void +enable_probes_command (const char *arg, int from_tty) { - return probe->pops->get_probe_argument_count (probe); -} + std::string provider, probe_name, objname; -/* See comments in probe.h. */ + parse_probe_linespec ((const char *) arg, &provider, &probe_name, &objname); -int -can_evaluate_probe_arguments (struct probe *probe) -{ - return probe->pops->can_evaluate_probe_arguments (probe); + std::vector probes + = collect_probes (objname, provider, probe_name, &any_static_probe_ops); + if (probes.empty ()) + { + current_uiout->message (_("No probes matched.\n")); + return; + } + + /* Enable the selected probes, provided their backends support the + notion of enabling a probe. */ + for (const bound_probe &probe: probes) + { + if (probe.prob->get_static_ops ()->can_enable ()) + { + probe.prob->enable (); + current_uiout->message (_("Probe %s:%s enabled.\n"), + probe.prob->get_provider ().c_str (), + probe.prob->get_name ().c_str ()); + } + else + current_uiout->message (_("Probe %s:%s cannot be enabled.\n"), + probe.prob->get_provider ().c_str (), + probe.prob->get_name ().c_str ()); + } } -/* See comments in probe.h. */ +/* Implementation of the `disable probes' command. */ -struct value * -evaluate_probe_argument (struct probe *probe, unsigned n) +static void +disable_probes_command (const char *arg, int from_tty) { - return probe->pops->evaluate_probe_argument (probe, n); + std::string provider, probe_name, objname; + + parse_probe_linespec ((const char *) arg, &provider, &probe_name, &objname); + + std::vector probes + = collect_probes (objname, provider, probe_name, &any_static_probe_ops); + if (probes.empty ()) + { + current_uiout->message (_("No probes matched.\n")); + return; + } + + /* Disable the selected probes, provided their backends support the + notion of enabling a probe. */ + for (const bound_probe &probe : probes) + { + if (probe.prob->get_static_ops ()->can_enable ()) + { + probe.prob->disable (); + current_uiout->message (_("Probe %s:%s disabled.\n"), + probe.prob->get_provider ().c_str (), + probe.prob->get_name ().c_str ()); + } + else + current_uiout->message (_("Probe %s:%s cannot be disabled.\n"), + probe.prob->get_provider ().c_str (), + probe.prob->get_name ().c_str ()); + } } /* See comments in probe.h. */ @@ -640,31 +688,28 @@ evaluate_probe_argument (struct probe *probe, unsigned n) struct value * probe_safe_evaluate_at_pc (struct frame_info *frame, unsigned n) { - struct probe *probe; + struct bound_probe probe; unsigned n_args; probe = find_probe_by_pc (get_frame_pc (frame)); - if (!probe) + if (!probe.prob) return NULL; - n_args = get_probe_argument_count (probe); + n_args = probe.prob->get_argument_count (get_frame_arch (frame)); if (n >= n_args) return NULL; - return evaluate_probe_argument (probe, n); + return probe.prob->evaluate_argument (n, frame); } /* See comment in probe.h. */ -const struct probe_ops * -probe_linespec_to_ops (const char **linespecp) +const struct static_probe_ops * +probe_linespec_to_static_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; + for (const static_probe_ops *ops : all_static_probe_ops) + if (ops->is_linespec (linespecp)) + return ops; return NULL; } @@ -692,31 +737,40 @@ probe_is_linespec_by_keyword (const char **linespecp, const char *const *keyword return 0; } -/* Implementation of `is_linespec' method for `struct probe_ops'. */ +/* Implementation of `is_linespec' method. */ -static int -probe_any_is_linespec (const char **linespecp) +bool +any_static_probe_ops::is_linespec (const char **linespecp) const { static const char *const keywords[] = { "-p", "-probe", NULL }; return probe_is_linespec_by_keyword (linespecp, keywords); } -/* Dummy method used for `probe_ops_any'. */ +/* Implementation of 'get_probes' method. */ -static void -probe_any_get_probes (VEC (probe_p) **probesp, struct objfile *objfile) +void +any_static_probe_ops::get_probes (std::vector> *probesp, + struct objfile *objfile) const { /* No probes can be provided by this dummy backend. */ } -/* Operations associated with a generic probe. */ +/* Implementation of the 'type_name' method. */ -const struct probe_ops probe_ops_any = +const char * +any_static_probe_ops::type_name () const { - probe_any_is_linespec, - probe_any_get_probes, -}; + return NULL; +} + +/* Implementation of the 'gen_info_probes_table_header' method. */ + +std::vector +any_static_probe_ops::gen_info_probes_table_header () const +{ + return std::vector (); +} /* See comments in probe.h. */ @@ -742,17 +796,143 @@ will show information about all types of probes."), return &info_probes_cmdlist; } -VEC (probe_ops_cp) *all_probe_ops; + + +/* This is called to compute the value of one of the $_probe_arg* + convenience variables. */ + +static struct value * +compute_probe_arg (struct gdbarch *arch, struct internalvar *ivar, + void *data) +{ + struct frame_info *frame = get_selected_frame (_("No frame selected")); + CORE_ADDR pc = get_frame_pc (frame); + int sel = (int) (uintptr_t) data; + struct bound_probe pc_probe; + unsigned n_args; + + /* SEL == -1 means "_probe_argc". */ + gdb_assert (sel >= -1); + + pc_probe = find_probe_by_pc (pc); + if (pc_probe.prob == NULL) + error (_("No probe at PC %s"), core_addr_to_string (pc)); + + n_args = pc_probe.prob->get_argument_count (arch); + if (sel == -1) + return value_from_longest (builtin_type (arch)->builtin_int, n_args); + + if (sel >= n_args) + error (_("Invalid probe argument %d -- probe has %u arguments available"), + sel, n_args); + + return pc_probe.prob->evaluate_argument (sel, frame); +} + +/* This is called to compile one of the $_probe_arg* convenience + variables into an agent expression. */ + +static void +compile_probe_arg (struct internalvar *ivar, struct agent_expr *expr, + struct axs_value *value, void *data) +{ + CORE_ADDR pc = expr->scope; + int sel = (int) (uintptr_t) data; + struct bound_probe pc_probe; + int n_args; + + /* SEL == -1 means "_probe_argc". */ + gdb_assert (sel >= -1); -void _initialize_probe (void); + pc_probe = find_probe_by_pc (pc); + if (pc_probe.prob == NULL) + error (_("No probe at PC %s"), core_addr_to_string (pc)); + + n_args = pc_probe.prob->get_argument_count (expr->gdbarch); + + if (sel == -1) + { + value->kind = axs_rvalue; + value->type = builtin_type (expr->gdbarch)->builtin_int; + ax_const_l (expr, n_args); + return; + } + + gdb_assert (sel >= 0); + if (sel >= n_args) + error (_("Invalid probe argument %d -- probe has %d arguments available"), + sel, n_args); + + pc_probe.prob->compile_to_ax (expr, value, sel); +} + +static const struct internalvar_funcs probe_funcs = +{ + compute_probe_arg, + compile_probe_arg, + NULL +}; + + +std::vector all_static_probe_ops; void _initialize_probe (void) { - VEC_safe_push (probe_ops_cp, all_probe_ops, &probe_ops_any); + all_static_probe_ops.push_back (&any_static_probe_ops); + + create_internalvar_type_lazy ("_probe_argc", &probe_funcs, + (void *) (uintptr_t) -1); + create_internalvar_type_lazy ("_probe_arg0", &probe_funcs, + (void *) (uintptr_t) 0); + create_internalvar_type_lazy ("_probe_arg1", &probe_funcs, + (void *) (uintptr_t) 1); + create_internalvar_type_lazy ("_probe_arg2", &probe_funcs, + (void *) (uintptr_t) 2); + create_internalvar_type_lazy ("_probe_arg3", &probe_funcs, + (void *) (uintptr_t) 3); + create_internalvar_type_lazy ("_probe_arg4", &probe_funcs, + (void *) (uintptr_t) 4); + create_internalvar_type_lazy ("_probe_arg5", &probe_funcs, + (void *) (uintptr_t) 5); + create_internalvar_type_lazy ("_probe_arg6", &probe_funcs, + (void *) (uintptr_t) 6); + create_internalvar_type_lazy ("_probe_arg7", &probe_funcs, + (void *) (uintptr_t) 7); + create_internalvar_type_lazy ("_probe_arg8", &probe_funcs, + (void *) (uintptr_t) 8); + create_internalvar_type_lazy ("_probe_arg9", &probe_funcs, + (void *) (uintptr_t) 9); + create_internalvar_type_lazy ("_probe_arg10", &probe_funcs, + (void *) (uintptr_t) 10); + create_internalvar_type_lazy ("_probe_arg11", &probe_funcs, + (void *) (uintptr_t) 11); add_cmd ("all", class_info, info_probes_command, _("\ Show information about all type of probes."), info_probes_cmdlist_get ()); + + add_cmd ("probes", class_breakpoint, enable_probes_command, _("\ +Enable probes.\n\ +Usage: enable probes [PROVIDER [NAME [OBJECT]]]\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 enable\n\ +all defined probes."), + &enablelist); + + add_cmd ("probes", class_breakpoint, disable_probes_command, _("\ +Disable probes.\n\ +Usage: disable probes [PROVIDER [NAME [OBJECT]]]\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 disable\n\ +all defined probes."), + &disablelist); + }