/* Generic static probe support for GDB.
- Copyright (C) 2012-2013 Free Software Foundation, Inc.
+ Copyright (C) 2012-2017 Free Software Foundation, Inc.
This file is part of GDB.
#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 <ctype.h>
+#include <algorithm>
+#include "common/gdb_optional.h"
-\f
+/* 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 struct probe_ops *probe_ops,
+ struct program_space *search_pspace,
+ const char *objfile_namestr,
+ const char *provider,
+ const char *name,
+ std::vector<symtab_and_line> *result)
+{
+ struct objfile *objfile;
+
+ ALL_PSPACE_OBJFILES (search_pspace, objfile)
+ {
+ 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<probe *> &probes
+ = objfile->sf->sym_probe_fns->sym_get_probes (objfile);
+
+ for (probe *p : probes)
+ {
+ if (probe_ops != &probe_ops_any && p->pops != probe_ops)
+ continue;
+
+ if (provider && strcmp (p->provider, provider) != 0)
+ continue;
+
+ if (strcmp (p->name, name) != 0)
+ continue;
+
+ symtab_and_line sal;
+ sal.pc = get_probe_address (p, objfile);
+ sal.explicit_pc = 1;
+ sal.section = find_pc_overlay (sal.pc);
+ sal.pspace = search_pspace;
+ sal.probe = p;
+ 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<symtab_and_line>
+parse_probes (const struct event_location *location,
+ struct program_space *search_pspace,
+ struct linespec_result *canonical)
{
- char *arg_start, *arg_end, *arg;
- char *objfile_name = NULL, *provider = NULL, *name, *p;
+ 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;
-
- result.sals = NULL;
- result.nelts = 0;
+ const char *arg_start, *cs;
- arg_start = *argptr;
+ gdb_assert (event_location_type (location) == PROBE_LOCATION);
+ arg_start = get_probe_location (location);
- cs = *argptr;
+ cs = arg_start;
probe_ops = probe_linespec_to_ops (&cs);
- gdb_assert (probe_ops != NULL);
+ if (probe_ops == NULL)
+ error (_("'%s' is not a probe linespec"), arg_start);
arg = (char *) cs;
arg = skip_spaces (arg);
{
/* This is `-p objfile:provider:name'. */
*p = '\0';
- objfile_name = arg;
+ objfile_namestr = arg;
provider = hold;
name = p + 1;
}
error (_("no probe name specified"));
if (provider && *provider == '\0')
error (_("invalid provider name"));
- if (objfile_name && *objfile_name == '\0')
+ 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_name
- && FILENAME_CMP (objfile->name, objfile_name) != 0
- && FILENAME_CMP (lbasename (objfile->name), objfile_name) != 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<symtab_and_line> result;
+ if (search_pspace != NULL)
+ {
+ parse_probes_in_pspace (probe_ops, 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 (probe_ops, 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'"),
- objfile_name ? objfile_name : _("<any>"),
+ objfile_namestr ? objfile_namestr : _("<any>"),
provider ? provider : _("<any>"),
name);
}
if (canonical)
{
+ char *canon;
+
+ canon = savestring (arg_start, arg_end - arg_start);
+ make_cleanup (xfree, canon);
canonical->special_display = 1;
canonical->pre_expanded = 1;
- canonical->addr_string = savestring (*argptr, arg_end - *argptr);
+ canonical->location = new_probe_location (canon);
}
- *argptr = arg_end;
do_cleanups (cleanup);
return result;
find_probes_in_objfile (struct objfile *objfile, const char *provider,
const char *name)
{
- VEC (probe_p) *probes, *result = NULL;
- int ix;
- struct probe *probe;
+ VEC (probe_p) *result = NULL;
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++)
+ const std::vector<probe *> &probes
+ = objfile->sf->sym_probe_fns->sym_get_probes (objfile);
+ for (probe *p : probes)
{
- if (strcmp (probe->provider, provider) != 0)
+ if (strcmp (p->provider, provider) != 0)
continue;
- if (strcmp (probe->name, name) != 0)
+ if (strcmp (p->name, name) != 0)
continue;
- VEC_safe_push (probe_p, result, probe);
+ VEC_safe_push (probe_p, result, p);
}
return result;
/* See definition in probe.h. */
-struct probe *
+struct bound_probe
find_probe_by_pc (CORE_ADDR pc)
{
struct objfile *objfile;
+ struct bound_probe result;
+
+ result.objfile = NULL;
+ result.probe = NULL;
ALL_OBJFILES (objfile)
{
- VEC (probe_p) *probes;
- int ix;
- struct probe *probe;
-
- if (!objfile->sf || !objfile->sf->sym_probe_fns)
+ 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. */
- 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;
+ const std::vector<probe *> &probes
+ = objfile->sf->sym_probe_fns->sym_get_probes (objfile);
+ for (probe *p : probes)
+ if (get_probe_address (p, objfile) == pc)
+ {
+ result.objfile = objfile;
+ result.probe = p;
+ return result;
+ }
}
- return NULL;
+ return result;
}
\f
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_p) *
-collect_probes (char *objname, char *provider, char *probe_name,
- const struct probe_ops *pops)
+static std::vector<bound_probe>
+collect_probes (const std::string &objname, const std::string &provider,
+ const std::string &probe_name, const struct probe_ops *pops)
{
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"));
+ std::vector<bound_probe> result;
+ gdb::optional<compiled_regex> 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"));
ALL_OBJFILES (objfile)
{
- 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, 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<probe *> &probes
+ = objfile->sf->sym_probe_fns->sym_get_probes (objfile);
- for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++)
+ for (probe *p : probes)
{
- if (pops != NULL && probe->pops != pops)
+ if (pops != NULL && p->pops != pops)
continue;
- if (provider
- && regexec (&prov_pat, probe->provider, 0, NULL, 0) != 0)
+ if (prov_pat
+ && prov_pat->exec (p->provider, 0, NULL, 0) != 0)
continue;
- if (probe_name
- && regexec (&probe_pat, probe->name, 0, NULL, 0) != 0)
+ if (probe_pat
+ && probe_pat->exec (p->name, 0, NULL, 0) != 0)
continue;
- VEC_safe_push (probe_p, result, probe);
+ result.emplace_back (p, 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 = strcmp (a.probe->provider, b.probe->provider);
+ if (v != 0)
+ return v < 0;
- v = strcmp (pa->name, pb->name);
- if (v)
- return v;
+ v = strcmp (a.probe->name, b.probe->name);
+ if (v != 0)
+ return v < 0;
- if (pa->address < pb->address)
- return -1;
- if (pa->address > pb->address)
- return 1;
+ if (a.probe->address != b.probe->address)
+ return a.probe->address < b.probe->address;
- return strcmp (pa->objfile->name, pb->objfile->name);
+ 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,
+gen_ui_out_table_header_info (const std::vector<bound_probe> &probes,
const struct probe_ops *p)
{
/* `headings' refers to the names of the columns when printing `info
VEC_iterate (info_probe_column_s, headings, ix, column);
++ix)
{
- struct probe *probe;
- int jx;
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. */
const char *val;
int kx;
- if (probe->pops != p)
+ if (probe.probe->pops != p)
continue;
c2 = make_cleanup (VEC_cleanup (const_char_ptr), &probe_fields);
- p->gen_info_probes_table_values (probe, &probe_fields);
+ p->gen_info_probes_table_values (probe.probe, &probe_fields);
gdb_assert (VEC_length (const_char_ptr, probe_fields)
== headings_size);
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);
}
do_cleanups (c);
}
+/* Helper function to print not-applicable strings for all the extra
+ columns defined in a probe_ops. */
+
+static void
+print_ui_out_not_applicables (const struct probe_ops *pops)
+{
+ struct cleanup *c;
+ VEC (info_probe_column_s) *headings = NULL;
+ info_probe_column_s *column;
+ int ix;
+
+ if (pops->gen_info_probes_table_header == NULL)
+ return;
+
+ c = make_cleanup (VEC_cleanup (info_probe_column_s), &headings);
+ pops->gen_info_probes_table_header (&headings);
+
+ for (ix = 0;
+ VEC_iterate (info_probe_column_s, headings, ix, column);
+ ++ix)
+ current_uiout->field_string (column->field_name, _("n/a"));
+
+ do_cleanups (c);
+}
+
/* Helper function to print extra information about a probe and an objfile
represented by PROBE. */
const char *val = VEC_index (const_char_ptr, values, j++);
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);
return n;
}
+/* Helper function that returns 1 if there is a probe in PROBES
+ featuring the given POPS. It returns 0 otherwise. */
+
+static int
+exists_probe_with_pops (const std::vector<bound_probe> &probes,
+ const struct probe_ops *pops)
+{
+ struct bound_probe *probe;
+ int ix;
+
+ for (const bound_probe &probe : probes)
+ if (probe.probe->pops == pops)
+ return 1;
+
+ return 0;
+}
+
+/* Helper function that parses a probe linespec of the form [PROVIDER
+ [PROBE [OBJNAME]]] from the provided string STR. */
+
+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_ops (const char *arg, int from_tty,
+ const struct probe_ops *pops)
{
- char *provider, *probe_name = NULL, *objname = NULL;
+ std::string provider, probe_name, objname;
struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
- VEC (probe_p) *probes;
- int i, any_found;
+ 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);
-
- probe_name = extract_arg (&arg);
- if (probe_name)
- {
- make_cleanup (xfree, probe_name);
+ parse_probe_linespec (arg, &provider, &probe_name, &objname);
- objname = extract_arg (&arg);
- if (objname)
- make_cleanup (xfree, objname);
- }
- }
+ std::vector<bound_probe> probes
+ = collect_probes (objname, provider, probe_name, pops);
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
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. */
+ that number. But note that we ignore the probe_ops for which no probes
+ are defined with the given search criteria. */
- for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po); ++ix)
- ui_out_extra_fields += get_number_extra_fields (po);
+ for (const probe_ops *po : all_probe_ops)
+ if (exists_probe_with_pops (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");
-
- 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;
+ {
+ ui_out_emit_table table_emitter (current_uiout,
+ 5 + ui_out_extra_fields,
+ probes.size (), "StaticProbes");
- /* 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 (probe->objfile->name), size_objname);
- }
+ std::sort (probes.begin (), probes.end (), compare_probes);
- 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"));
+ /* What's the size of an address in our architecture? */
+ size_addr = gdbarch_addr_bit (gdbarch) == 64 ? 18 : 10;
- if (pops == NULL)
- {
- const struct probe_ops *po;
- int ix;
+ /* Determining the maximum size of each field (`type', `provider',
+ `name' and `objname'). */
+ for (const bound_probe &probe : probes)
+ {
+ const char *probe_type = probe.probe->pops->type_name (probe.probe);
- /* 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);
+ size_type = std::max (strlen (probe_type), size_type);
+ size_name = std::max (strlen (probe.probe->name), size_name);
+ size_provider = std::max (strlen (probe.probe->provider), 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 (pops == NULL)
+ {
+ /* 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 probe_ops *po : all_probe_ops)
+ if (exists_probe_with_pops (probes, po))
+ gen_ui_out_table_header_info (probes, po);
+ }
+ else
+ gen_ui_out_table_header_info (probes, pops);
- 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.probe->pops->type_name (probe.probe);
- 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.probe->provider);
+ current_uiout->field_string ("name", probe.probe->name);
+ current_uiout->field_core_addr ("addr", probe.probe->arch,
+ get_probe_address (probe.probe,
+ probe.objfile));
- ui_out_field_string (current_uiout, "object", probe->objfile->name);
- ui_out_text (current_uiout, "\n");
+ if (pops == NULL)
+ {
+ for (const probe_ops *po : all_probe_ops)
+ if (probe.probe->pops == po)
+ print_ui_out_info (probe.probe);
+ else if (exists_probe_with_pops (probes, po))
+ print_ui_out_not_applicables (po);
+ }
+ else
+ print_ui_out_info (probe.probe);
- do_cleanups (inner);
- }
+ current_uiout->field_string ("object",
+ objfile_name (probe.objfile));
+ current_uiout->text ("\n");
+ }
- any_found = !VEC_empty (probe_p, probes);
+ any_found = !probes.empty ();
+ }
do_cleanups (cleanup);
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);
}
-/* 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)
{
- const struct sym_probe_fns *probe_fns;
+ std::string provider, probe_name, objname;
+ struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+
+ parse_probe_linespec ((const char *) arg, &provider, &probe_name, &objname);
+
+ std::vector<bound_probe> probes
+ = collect_probes (objname, provider, probe_name, NULL);
+ if (probes.empty ())
+ {
+ current_uiout->message (_("No probes matched.\n"));
+ do_cleanups (cleanup);
+ return;
+ }
+
+ /* Enable the selected probes, provided their backends support the
+ notion of enabling a probe. */
+ for (const bound_probe &probe: probes)
+ {
+ const struct probe_ops *pops = probe.probe->pops;
+
+ if (pops->enable_probe != NULL)
+ {
+ pops->enable_probe (probe.probe);
+ current_uiout->message (_("Probe %s:%s enabled.\n"),
+ probe.probe->provider, probe.probe->name);
+ }
+ else
+ current_uiout->message (_("Probe %s:%s cannot be enabled.\n"),
+ probe.probe->provider, probe.probe->name);
+ }
+
+ do_cleanups (cleanup);
+}
+
+/* Implementation of the `disable probes' command. */
+
+static void
+disable_probes_command (const char *arg, int from_tty)
+{
+ std::string provider, probe_name, objname;
+ struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+
+ parse_probe_linespec ((const char *) arg, &provider, &probe_name, &objname);
+
+ std::vector<bound_probe> probes
+ = collect_probes (objname, provider, probe_name, NULL /* pops */);
+ if (probes.empty ())
+ {
+ current_uiout->message (_("No probes matched.\n"));
+ do_cleanups (cleanup);
+ return;
+ }
+
+ /* Disable the selected probes, provided their backends support the
+ notion of enabling a probe. */
+ for (const bound_probe &probe : probes)
+ {
+ const struct probe_ops *pops = probe.probe->pops;
- gdb_assert (probe->objfile != NULL);
- gdb_assert (probe->objfile->sf != NULL);
+ if (pops->disable_probe != NULL)
+ {
+ pops->disable_probe (probe.probe);
+ current_uiout->message (_("Probe %s:%s disabled.\n"),
+ probe.probe->provider, probe.probe->name);
+ }
+ else
+ current_uiout->message (_("Probe %s:%s cannot be disabled.\n"),
+ probe.probe->provider, probe.probe->name);
+ }
- probe_fns = probe->objfile->sf->sym_probe_fns;
+ do_cleanups (cleanup);
+}
- gdb_assert (probe_fns != NULL);
+/* See comments in probe.h. */
- return probe_fns->sym_get_probe_argument_count (probe);
+CORE_ADDR
+get_probe_address (struct probe *probe, struct objfile *objfile)
+{
+ return probe->pops->get_probe_address (probe, objfile);
}
/* See comments in probe.h. */
-struct value *
-evaluate_probe_argument (struct probe *probe, unsigned n)
+unsigned
+get_probe_argument_count (struct probe *probe, struct frame_info *frame)
{
- const struct sym_probe_fns *probe_fns;
+ return probe->pops->get_probe_argument_count (probe, frame);
+}
- gdb_assert (probe->objfile != NULL);
- gdb_assert (probe->objfile->sf != NULL);
+/* See comments in probe.h. */
- probe_fns = probe->objfile->sf->sym_probe_fns;
+int
+can_evaluate_probe_arguments (struct probe *probe)
+{
+ return probe->pops->can_evaluate_probe_arguments (probe);
+}
- gdb_assert (probe_fns != NULL);
+/* See comments in probe.h. */
- return probe_fns->sym_evaluate_probe_argument (probe, n);
+struct value *
+evaluate_probe_argument (struct probe *probe, unsigned n,
+ struct frame_info *frame)
+{
+ return probe->pops->evaluate_probe_argument (probe, n, frame);
}
/* See comments in probe.h. */
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.probe)
return NULL;
- n_args = get_probe_argument_count (probe);
+ n_args = get_probe_argument_count (probe.probe, frame);
if (n >= n_args)
return NULL;
- return evaluate_probe_argument (probe, n);
+ return evaluate_probe_argument (probe.probe, n, frame);
}
/* 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;
+ for (const probe_ops *ops : all_probe_ops)
+ if (ops->is_linespec (linespecp))
+ return ops;
return NULL;
}
/* Dummy method used for `probe_ops_any'. */
static void
-probe_any_get_probes (VEC (probe_p) **probesp, struct objfile *objfile)
+probe_any_get_probes (std::vector<probe *> *probesp, struct objfile *objfile)
{
/* No probes can be provided by this dummy backend. */
}
return &info_probes_cmdlist;
}
-VEC (probe_ops_cp) *all_probe_ops;
+\f
+
+/* 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;
+ const struct sym_probe_fns *pc_probe_fns;
+ unsigned n_args;
-void _initialize_probe (void);
+ /* SEL == -1 means "_probe_argc". */
+ gdb_assert (sel >= -1);
+
+ pc_probe = find_probe_by_pc (pc);
+ if (pc_probe.probe == NULL)
+ error (_("No probe at PC %s"), core_addr_to_string (pc));
+
+ n_args = get_probe_argument_count (pc_probe.probe, frame);
+ 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 evaluate_probe_argument (pc_probe.probe, 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;
+ const struct sym_probe_fns *pc_probe_fns;
+ int n_args;
+ struct frame_info *frame = get_selected_frame (NULL);
+
+ /* SEL == -1 means "_probe_argc". */
+ gdb_assert (sel >= -1);
+
+ pc_probe = find_probe_by_pc (pc);
+ if (pc_probe.probe == NULL)
+ error (_("No probe at PC %s"), core_addr_to_string (pc));
+
+ n_args = get_probe_argument_count (pc_probe.probe, frame);
+
+ 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.probe->pops->compile_to_ax (pc_probe.probe, expr, value, sel);
+}
+
+static const struct internalvar_funcs probe_funcs =
+{
+ compute_probe_arg,
+ compile_probe_arg,
+ NULL
+};
+
+
+std::vector<const probe_ops *> all_probe_ops;
void
_initialize_probe (void)
{
- VEC_safe_push (probe_ops_cp, all_probe_ops, &probe_ops_any);
+ all_probe_ops.push_back (&probe_ops_any);
+
+ 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);
+
}