| Index: gdb/probe.c
|
| diff --git a/gdb/probe.c b/gdb/probe.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..77f3b13478ad040eab036dbdf8da6e2426f87e4c
|
| --- /dev/null
|
| +++ b/gdb/probe.c
|
| @@ -0,0 +1,785 @@
|
| +/* 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;
|
| +
|
| + 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 ());
|
| +}
|
|
|