X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fprobe.c;h=e3bc915ba7d7a784ae32dc07d4db112ba9f42cfd;hb=112e8700a6fd2fed65ca70132c9cbed4132e8bd4;hp=623f65cb05176d129a09c7b3156c206019ce9193;hpb=729662a5221eaee2b3cd71d79afb3f612c4df904;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/probe.c b/gdb/probe.c index 623f65cb05..e3bc915ba7 100644 --- a/gdb/probe.c +++ b/gdb/probe.c @@ -1,6 +1,6 @@ /* Generic static probe support for GDB. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. This file is part of GDB. @@ -26,40 +26,106 @@ #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 typedef struct bound_probe bound_probe_s; DEF_VEC_O (bound_probe_s); +/* 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, + struct symtabs_and_lines *result) +{ + struct objfile *objfile; + + ALL_PSPACE_OBJFILES (search_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 = XRESIZEVEC (struct symtab_and_line, result->sals, + result->nelts); + sal = &result->sals[result->nelts - 1]; + + init_sal (sal); + + sal->pc = get_probe_address (probe, objfile); + sal->explicit_pc = 1; + sal->section = find_pc_overlay (sal->pc); + sal->pspace = search_pspace; + sal->probe = probe; + sal->objfile = objfile; + } + } +} + /* See definition in probe.h. */ struct symtabs_and_lines -parse_probes (char **argptr, struct linespec_result *canonical) +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; - 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); @@ -108,53 +174,19 @@ 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); + if (search_pspace != NULL) + { + parse_probes_in_pspace (probe_ops, search_pspace, objfile_namestr, + provider, name, &result); + } + else + { + struct program_space *pspace; - sal->pc = get_probe_address (probe, objfile); - sal->explicit_pc = 1; - sal->section = find_pc_overlay (sal->pc); - sal->pspace = pspace; - sal->probe = probe; - sal->objfile = objfile; - } - } + ALL_PSPACES (pspace) + parse_probes_in_pspace (probe_ops, pspace, objfile_namestr, + provider, name, &result); + } if (result.nelts == 0) { @@ -167,12 +199,15 @@ parse_probes (char **argptr, struct linespec_result *canonical) 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; @@ -398,18 +433,43 @@ gen_ui_out_table_header_info (VEC (bound_probe_s) *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); } 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. */ @@ -451,9 +511,9 @@ print_ui_out_info (struct probe *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); @@ -482,10 +542,46 @@ get_number_extra_fields (const struct probe_ops *pops) 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 (VEC (bound_probe_s) *probes, + const struct probe_ops *pops) +{ + struct bound_probe *probe; + int ix; + + for (ix = 0; VEC_iterate (bound_probe_s, probes, ix, probe); ++ix) + 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, char **provider, + char **probe_name, char **objname) +{ + *probe_name = *objname = NULL; + + *provider = extract_arg_const (&str); + if (*provider != NULL) + { + *probe_name = extract_arg_const (&str); + if (*probe_name != NULL) + *objname = extract_arg_const (&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; struct cleanup *cleanup = make_cleanup (null_cleanup, NULL); @@ -496,25 +592,17 @@ info_probes_for_ops (char *arg, int from_tty, const struct probe_ops *pops) size_t size_name = strlen ("Name"); size_t size_objname = strlen ("Object"); size_t size_provider = strlen ("Provider"); + size_t size_type = strlen ("Type"); struct bound_probe *probe; 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); + make_cleanup (xfree, provider); + make_cleanup (xfree, probe_name); + make_cleanup (xfree, objname); - objname = extract_arg (&arg); - if (objname) - make_cleanup (xfree, objname); - } - } + probes = collect_probes (objname, provider, probe_name, pops); + make_cleanup (VEC_cleanup (probe_p), &probes); if (pops == NULL) { @@ -528,18 +616,18 @@ info_probes_for_ops (char *arg, int from_tty, const struct probe_ops *pops) 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); + 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, + 5 + ui_out_extra_fields, VEC_length (bound_probe_s, probes), "StaticProbes"); @@ -551,48 +639,56 @@ info_probes_for_ops (char *arg, int from_tty, const struct probe_ops *pops) /* 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'). */ + /* Determining the maximum size of each field (`type', `provider', + `name' and `objname'). */ for (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i) { - size_name = max (strlen (probe->probe->name), size_name); - size_provider = max (strlen (probe->probe->provider), size_provider); - size_objname = max (strlen (objfile_name (probe->objfile)), size_objname); + const char *probe_type = probe->probe->pops->type_name (probe->probe); + + 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_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")); + 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")); 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. */ + /* 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 (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po); ++ix) - gen_ui_out_table_header_info (probes, po); + if (exists_probe_with_pops (probes, po)) + gen_ui_out_table_header_info (probes, po); } else gen_ui_out_table_header_info (probes, pops); - ui_out_table_header (current_uiout, size_objname, ui_left, "object", - _("Object")); - ui_out_table_body (current_uiout); + current_uiout->table_header (size_objname, ui_left, "object", _("Object")); + current_uiout->table_body (); for (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i) { struct cleanup *inner; + const char *probe_type = probe->probe->pops->type_name (probe->probe); inner = make_cleanup_ui_out_tuple_begin_end (current_uiout, "probe"); - ui_out_field_string (current_uiout, "provider", probe->probe->provider); - ui_out_field_string (current_uiout, "name", probe->probe->name); - ui_out_field_core_addr (current_uiout, "addr", - probe->probe->arch, - get_probe_address (probe->probe, probe->objfile)); + 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)); if (pops == NULL) { @@ -603,13 +699,15 @@ info_probes_for_ops (char *arg, int from_tty, const struct probe_ops *pops) ++ix) 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); - ui_out_field_string (current_uiout, "object", + current_uiout->field_string ("object", objfile_name (probe->objfile)); - ui_out_text (current_uiout, "\n"); + current_uiout->text ("\n"); do_cleanups (inner); } @@ -618,7 +716,7 @@ info_probes_for_ops (char *arg, int from_tty, const struct probe_ops *pops) 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. */ @@ -629,6 +727,94 @@ info_probes_command (char *arg, int from_tty) info_probes_for_ops (arg, from_tty, NULL); } +/* Implementation of the `enable probes' command. */ + +static void +enable_probes_command (char *arg, int from_tty) +{ + char *provider, *probe_name = NULL, *objname = NULL; + struct cleanup *cleanup = make_cleanup (null_cleanup, NULL); + VEC (bound_probe_s) *probes; + struct bound_probe *probe; + int i; + + parse_probe_linespec ((const char *) arg, &provider, &probe_name, &objname); + make_cleanup (xfree, provider); + make_cleanup (xfree, probe_name); + make_cleanup (xfree, objname); + + probes = collect_probes (objname, provider, probe_name, NULL); + if (VEC_empty (bound_probe_s, probes)) + { + 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 (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i) + { + 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 (char *arg, int from_tty) +{ + char *provider, *probe_name = NULL, *objname = NULL; + struct cleanup *cleanup = make_cleanup (null_cleanup, NULL); + VEC (bound_probe_s) *probes; + struct bound_probe *probe; + int i; + + parse_probe_linespec ((const char *) arg, &provider, &probe_name, &objname); + make_cleanup (xfree, provider); + make_cleanup (xfree, probe_name); + make_cleanup (xfree, objname); + + probes = collect_probes (objname, provider, probe_name, NULL /* pops */); + if (VEC_empty (bound_probe_s, probes)) + { + 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 (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i) + { + const struct probe_ops *pops = probe->probe->pops; + + 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); + } + + do_cleanups (cleanup); +} + /* See comments in probe.h. */ CORE_ADDR @@ -769,6 +955,87 @@ will show information about all types of probes."), return &info_probes_cmdlist; } + + +/* 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; + + /* 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 +}; + + VEC (probe_ops_cp) *all_probe_ops; void _initialize_probe (void); @@ -778,8 +1045,58 @@ _initialize_probe (void) { VEC_safe_push (probe_ops_cp, all_probe_ops, &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); + }