| /* DTrace probe support for GDB. | |
| Copyright (C) 2014-2023 Free Software Foundation, Inc. | |
| Contributed by Oracle, 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 "elf-bfd.h" | |
| #include "gdbtypes.h" | |
| #include "obstack.h" | |
| #include "objfiles.h" | |
| #include "complaints.h" | |
| #include "value.h" | |
| #include "ax.h" | |
| #include "ax-gdb.h" | |
| #include "language.h" | |
| #include "parser-defs.h" | |
| #include "inferior.h" | |
| #include "expop.h" | |
| /* The type of the ELF sections where we will find the DOF programs | |
| with information about probes. */ | |
| #ifndef SHT_SUNW_dof | |
| # define SHT_SUNW_dof 0x6ffffff4 | |
| #endif | |
| /* The following structure represents a single argument for the | |
| probe. */ | |
| struct dtrace_probe_arg | |
| { | |
| dtrace_probe_arg (struct type *type_, std::string &&type_str_, | |
| expression_up &&expr_) | |
| : type (type_), type_str (std::move (type_str_)), | |
| expr (std::move (expr_)) | |
| {} | |
| /* The type of the probe argument. */ | |
| struct type *type; | |
| /* A string describing the type. */ | |
| std::string type_str; | |
| /* The argument converted to an internal GDB expression. */ | |
| expression_up expr; | |
| }; | |
| /* The following structure represents an enabler for a probe. */ | |
| struct dtrace_probe_enabler | |
| { | |
| /* Program counter where the is-enabled probe is installed. The | |
| contents (nops, whatever...) stored at this address are | |
| architecture dependent. */ | |
| CORE_ADDR address; | |
| }; | |
| /* Class that implements the static probe methods for "stap" probes. */ | |
| class dtrace_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<std::unique_ptr<probe>> *probesp, | |
| struct objfile *objfile) const override; | |
| /* See probe.h. */ | |
| const char *type_name () const override; | |
| /* See probe.h. */ | |
| bool can_enable () const override | |
| { | |
| return true; | |
| } | |
| /* See probe.h. */ | |
| std::vector<struct info_probe_column> gen_info_probes_table_header | |
| () const override; | |
| }; | |
| /* DTrace static_probe_ops. */ | |
| const dtrace_static_probe_ops dtrace_static_probe_ops {}; | |
| /* The following structure represents a dtrace probe. */ | |
| class dtrace_probe : public probe | |
| { | |
| public: | |
| /* Constructor for dtrace_probe. */ | |
| dtrace_probe (std::string &&name_, std::string &&provider_, CORE_ADDR address_, | |
| struct gdbarch *arch_, | |
| std::vector<struct dtrace_probe_arg> &&args_, | |
| std::vector<struct dtrace_probe_enabler> &&enablers_) | |
| : probe (std::move (name_), std::move (provider_), address_, arch_), | |
| m_args (std::move (args_)), | |
| m_enablers (std::move (enablers_)), | |
| m_args_expr_built (false) | |
| {} | |
| /* See probe.h. */ | |
| CORE_ADDR get_relocated_address (struct objfile *objfile) override; | |
| /* See probe.h. */ | |
| unsigned get_argument_count (struct gdbarch *gdbarch) override; | |
| /* See probe.h. */ | |
| bool can_evaluate_arguments () const override; | |
| /* See probe.h. */ | |
| struct value *evaluate_argument (unsigned n, | |
| frame_info_ptr frame) override; | |
| /* See probe.h. */ | |
| void compile_to_ax (struct agent_expr *aexpr, | |
| struct axs_value *axs_value, | |
| unsigned n) override; | |
| /* See probe.h. */ | |
| const static_probe_ops *get_static_ops () const override; | |
| /* See probe.h. */ | |
| std::vector<const char *> gen_info_probes_table_values () const override; | |
| /* See probe.h. */ | |
| void enable () override; | |
| /* See probe.h. */ | |
| void disable () override; | |
| /* Return the Nth argument of the probe. */ | |
| struct dtrace_probe_arg *get_arg_by_number (unsigned n, | |
| struct gdbarch *gdbarch); | |
| /* Build the GDB internal expression that, once evaluated, will | |
| calculate the values of the arguments of the probe. */ | |
| void build_arg_exprs (struct gdbarch *gdbarch); | |
| /* Determine whether the probe is "enabled" or "disabled". A | |
| disabled probe is a probe in which one or more enablers are | |
| disabled. */ | |
| bool is_enabled () const; | |
| private: | |
| /* A probe can have zero or more arguments. */ | |
| std::vector<struct dtrace_probe_arg> m_args; | |
| /* A probe can have zero or more "enablers" associated with it. */ | |
| std::vector<struct dtrace_probe_enabler> m_enablers; | |
| /* Whether the expressions for the arguments have been built. */ | |
| bool m_args_expr_built; | |
| }; | |
| /* DOF programs can contain an arbitrary number of sections of 26 | |
| different types. In order to support DTrace USDT probes we only | |
| need to handle a subset of these section types, fortunately. These | |
| section types are defined in the following enumeration. | |
| See linux/dtrace/dof_defines.h for a complete list of section types | |
| along with their values. */ | |
| enum dtrace_dof_sect_type | |
| { | |
| /* Null section. */ | |
| DTRACE_DOF_SECT_TYPE_NONE = 0, | |
| /* A dof_ecbdesc_t. */ | |
| DTRACE_DOF_SECT_TYPE_ECBDESC = 3, | |
| /* A string table. */ | |
| DTRACE_DOF_SECT_TYPE_STRTAB = 8, | |
| /* A dof_provider_t */ | |
| DTRACE_DOF_SECT_TYPE_PROVIDER = 15, | |
| /* Array of dof_probe_t */ | |
| DTRACE_DOF_SECT_TYPE_PROBES = 16, | |
| /* An array of probe arg mappings. */ | |
| DTRACE_DOF_SECT_TYPE_PRARGS = 17, | |
| /* An array of probe arg offsets. */ | |
| DTRACE_DOF_SECT_TYPE_PROFFS = 18, | |
| /* An array of probe is-enabled offsets. */ | |
| DTRACE_DOF_SECT_TYPE_PRENOFFS = 26 | |
| }; | |
| /* The following collection of data structures map the structure of | |
| DOF entities. Again, we only cover the subset of DOF used to | |
| implement USDT probes. | |
| See linux/dtrace/dof.h header for a complete list of data | |
| structures. */ | |
| /* Offsets to index the dofh_ident[] array defined below. */ | |
| enum dtrace_dof_ident | |
| { | |
| /* First byte of the magic number. */ | |
| DTRACE_DOF_ID_MAG0 = 0, | |
| /* Second byte of the magic number. */ | |
| DTRACE_DOF_ID_MAG1 = 1, | |
| /* Third byte of the magic number. */ | |
| DTRACE_DOF_ID_MAG2 = 2, | |
| /* Fourth byte of the magic number. */ | |
| DTRACE_DOF_ID_MAG3 = 3, | |
| /* An enum_dof_encoding value. */ | |
| DTRACE_DOF_ID_ENCODING = 5 | |
| }; | |
| /* Possible values for dofh_ident[DOF_ID_ENCODING]. */ | |
| enum dtrace_dof_encoding | |
| { | |
| /* The DOF program is little-endian. */ | |
| DTRACE_DOF_ENCODE_LSB = 1, | |
| /* The DOF program is big-endian. */ | |
| DTRACE_DOF_ENCODE_MSB = 2 | |
| }; | |
| /* A DOF header, which describes the contents of a DOF program: number | |
| of sections, size, etc. */ | |
| struct dtrace_dof_hdr | |
| { | |
| /* Identification bytes (see above). */ | |
| uint8_t dofh_ident[16]; | |
| /* File attribute flags (if any). */ | |
| uint32_t dofh_flags; | |
| /* Size of file header in bytes. */ | |
| uint32_t dofh_hdrsize; | |
| /* Size of section header in bytes. */ | |
| uint32_t dofh_secsize; | |
| /* Number of section headers. */ | |
| uint32_t dofh_secnum; | |
| /* File offset of section headers. */ | |
| uint64_t dofh_secoff; | |
| /* File size of loadable portion. */ | |
| uint64_t dofh_loadsz; | |
| /* File size of entire DOF file. */ | |
| uint64_t dofh_filesz; | |
| /* Reserved for future use. */ | |
| uint64_t dofh_pad; | |
| }; | |
| /* A DOF section, whose contents depend on its type. The several | |
| supported section types are described in the enum | |
| dtrace_dof_sect_type above. */ | |
| struct dtrace_dof_sect | |
| { | |
| /* Section type (see the define above). */ | |
| uint32_t dofs_type; | |
| /* Section data memory alignment. */ | |
| uint32_t dofs_align; | |
| /* Section flags (if any). */ | |
| uint32_t dofs_flags; | |
| /* Size of section entry (if table). */ | |
| uint32_t dofs_entsize; | |
| /* DOF + offset points to the section data. */ | |
| uint64_t dofs_offset; | |
| /* Size of section data in bytes. */ | |
| uint64_t dofs_size; | |
| }; | |
| /* A DOF provider, which is the provider of a probe. */ | |
| struct dtrace_dof_provider | |
| { | |
| /* Link to a DTRACE_DOF_SECT_TYPE_STRTAB section. */ | |
| uint32_t dofpv_strtab; | |
| /* Link to a DTRACE_DOF_SECT_TYPE_PROBES section. */ | |
| uint32_t dofpv_probes; | |
| /* Link to a DTRACE_DOF_SECT_TYPE_PRARGS section. */ | |
| uint32_t dofpv_prargs; | |
| /* Link to a DTRACE_DOF_SECT_TYPE_PROFFS section. */ | |
| uint32_t dofpv_proffs; | |
| /* Provider name string. */ | |
| uint32_t dofpv_name; | |
| /* Provider attributes. */ | |
| uint32_t dofpv_provattr; | |
| /* Module attributes. */ | |
| uint32_t dofpv_modattr; | |
| /* Function attributes. */ | |
| uint32_t dofpv_funcattr; | |
| /* Name attributes. */ | |
| uint32_t dofpv_nameattr; | |
| /* Args attributes. */ | |
| uint32_t dofpv_argsattr; | |
| /* Link to a DTRACE_DOF_SECT_PRENOFFS section. */ | |
| uint32_t dofpv_prenoffs; | |
| }; | |
| /* A set of DOF probes and is-enabled probes sharing a base address | |
| and several attributes. The particular locations and attributes of | |
| each probe are maintained in arrays in several other DOF sections. | |
| See the comment in dtrace_process_dof_probe for details on how | |
| these attributes are stored. */ | |
| struct dtrace_dof_probe | |
| { | |
| /* Probe base address or offset. */ | |
| uint64_t dofpr_addr; | |
| /* Probe function string. */ | |
| uint32_t dofpr_func; | |
| /* Probe name string. */ | |
| uint32_t dofpr_name; | |
| /* Native argument type strings. */ | |
| uint32_t dofpr_nargv; | |
| /* Translated argument type strings. */ | |
| uint32_t dofpr_xargv; | |
| /* Index of first argument mapping. */ | |
| uint32_t dofpr_argidx; | |
| /* Index of first offset entry. */ | |
| uint32_t dofpr_offidx; | |
| /* Native argument count. */ | |
| uint8_t dofpr_nargc; | |
| /* Translated argument count. */ | |
| uint8_t dofpr_xargc; | |
| /* Number of offset entries for probe. */ | |
| uint16_t dofpr_noffs; | |
| /* Index of first is-enabled offset. */ | |
| uint32_t dofpr_enoffidx; | |
| /* Number of is-enabled offsets. */ | |
| uint16_t dofpr_nenoffs; | |
| /* Reserved for future use. */ | |
| uint16_t dofpr_pad1; | |
| /* Reserved for future use. */ | |
| uint32_t dofpr_pad2; | |
| }; | |
| /* DOF supports two different encodings: MSB (big-endian) and LSB | |
| (little-endian). The encoding is itself encoded in the DOF header. | |
| The following function returns an unsigned value in the host | |
| endianness. */ | |
| #define DOF_UINT(dof, field) \ | |
| extract_unsigned_integer ((gdb_byte *) &(field), \ | |
| sizeof ((field)), \ | |
| (((dof)->dofh_ident[DTRACE_DOF_ID_ENCODING] \ | |
| == DTRACE_DOF_ENCODE_MSB) \ | |
| ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE)) | |
| /* The following macro applies a given byte offset to a DOF (a pointer | |
| to a dtrace_dof_hdr structure) and returns the resulting | |
| address. */ | |
| #define DTRACE_DOF_PTR(dof, offset) (&((char *) (dof))[(offset)]) | |
| /* The following macro returns a pointer to the beginning of a given | |
| section in a DOF object. The section is referred to by its index | |
| in the sections array. */ | |
| #define DTRACE_DOF_SECT(dof, idx) \ | |
| ((struct dtrace_dof_sect *) \ | |
| DTRACE_DOF_PTR ((dof), \ | |
| DOF_UINT ((dof), (dof)->dofh_secoff) \ | |
| + ((idx) * DOF_UINT ((dof), (dof)->dofh_secsize)))) | |
| /* Helper function to examine the probe described by the given PROBE | |
| and PROVIDER data structures and add it to the PROBESP vector. | |
| STRTAB, OFFTAB, EOFFTAB and ARGTAB are pointers to tables in the | |
| DOF program containing the attributes for the probe. */ | |
| static void | |
| dtrace_process_dof_probe (struct objfile *objfile, | |
| struct gdbarch *gdbarch, | |
| std::vector<std::unique_ptr<probe>> *probesp, | |
| struct dtrace_dof_hdr *dof, | |
| struct dtrace_dof_probe *probe, | |
| struct dtrace_dof_provider *provider, | |
| char *strtab, char *offtab, char *eofftab, | |
| char *argtab, uint64_t strtab_size) | |
| { | |
| int i, j, num_probes, num_enablers; | |
| char *p; | |
| /* Each probe section can define zero or more probes of two | |
| different types: | |
| - probe->dofpr_noffs regular probes whose program counters are | |
| stored in 32bit words starting at probe->dofpr_addr + | |
| offtab[probe->dofpr_offidx]. | |
| - probe->dofpr_nenoffs is-enabled probes whose program counters | |
| are stored in 32bit words starting at probe->dofpr_addr + | |
| eofftab[probe->dofpr_enoffidx]. | |
| However is-enabled probes are not probes per-se, but an | |
| optimization hack that is implemented in the kernel in a very | |
| similar way than normal probes. This is how we support | |
| is-enabled probes on GDB: | |
| - Our probes are always DTrace regular probes. | |
| - Our probes can be associated with zero or more "enablers". The | |
| list of enablers is built from the is-enabled probes defined in | |
| the Probe section. | |
| - Probes having a non-empty list of enablers can be enabled or | |
| disabled using the `enable probe' and `disable probe' commands | |
| respectively. The `Enabled' column in the output of `info | |
| probes' will read `yes' if the enablers are activated, `no' | |
| otherwise. | |
| - Probes having an empty list of enablers are always enabled. | |
| The `Enabled' column in the output of `info probes' will | |
| read `always'. | |
| It follows that if there are DTrace is-enabled probes defined for | |
| some provider/name but no DTrace regular probes defined then the | |
| GDB user wont be able to enable/disable these conditionals. */ | |
| num_probes = DOF_UINT (dof, probe->dofpr_noffs); | |
| if (num_probes == 0) | |
| return; | |
| /* Build the list of enablers for the probes defined in this Probe | |
| DOF section. */ | |
| std::vector<struct dtrace_probe_enabler> enablers; | |
| num_enablers = DOF_UINT (dof, probe->dofpr_nenoffs); | |
| for (i = 0; i < num_enablers; i++) | |
| { | |
| struct dtrace_probe_enabler enabler; | |
| uint32_t enabler_offset | |
| = ((uint32_t *) eofftab)[DOF_UINT (dof, probe->dofpr_enoffidx) + i]; | |
| enabler.address = DOF_UINT (dof, probe->dofpr_addr) | |
| + DOF_UINT (dof, enabler_offset); | |
| enablers.push_back (enabler); | |
| } | |
| for (i = 0; i < num_probes; i++) | |
| { | |
| uint32_t probe_offset | |
| = ((uint32_t *) offtab)[DOF_UINT (dof, probe->dofpr_offidx) + i]; | |
| /* Set the provider and the name of the probe. */ | |
| const char *probe_provider | |
| = strtab + DOF_UINT (dof, provider->dofpv_name); | |
| const char *name = strtab + DOF_UINT (dof, probe->dofpr_name); | |
| /* The probe address. */ | |
| CORE_ADDR address | |
| = DOF_UINT (dof, probe->dofpr_addr) + DOF_UINT (dof, probe_offset); | |
| /* Number of arguments in the probe. */ | |
| int probe_argc = DOF_UINT (dof, probe->dofpr_nargc); | |
| /* Store argument type descriptions. A description of the type | |
| of the argument is in the (J+1)th null-terminated string | |
| starting at 'strtab' + 'probe->dofpr_nargv'. */ | |
| std::vector<struct dtrace_probe_arg> args; | |
| p = strtab + DOF_UINT (dof, probe->dofpr_nargv); | |
| for (j = 0; j < probe_argc; j++) | |
| { | |
| expression_up expr; | |
| /* Set arg.expr to ensure all fields in expr are initialized and | |
| the compiler will not warn when arg is used. */ | |
| std::string type_str (p); | |
| /* Use strtab_size as a sentinel. */ | |
| while (*p++ != '\0' && p - strtab < strtab_size) | |
| ; | |
| /* Try to parse a type expression from the type string. If | |
| this does not work then we set the type to `long | |
| int'. */ | |
| struct type *type = builtin_type (gdbarch)->builtin_long; | |
| try | |
| { | |
| expr = parse_expression_with_language (type_str.c_str (), | |
| language_c); | |
| } | |
| catch (const gdb_exception_error &ex) | |
| { | |
| } | |
| if (expr != NULL && expr->first_opcode () == OP_TYPE) | |
| type = expr->evaluate_type ()->type (); | |
| args.emplace_back (type, std::move (type_str), std::move (expr)); | |
| } | |
| std::vector<struct dtrace_probe_enabler> enablers_copy = enablers; | |
| dtrace_probe *ret = new dtrace_probe (std::string (name), | |
| std::string (probe_provider), | |
| address, gdbarch, | |
| std::move (args), | |
| std::move (enablers_copy)); | |
| /* Successfully created probe. */ | |
| probesp->emplace_back (ret); | |
| } | |
| } | |
| /* Helper function to collect the probes described in the DOF program | |
| whose header is pointed by DOF and add them to the PROBESP vector. | |
| SECT is the ELF section containing the DOF program and OBJFILE is | |
| its containing object file. */ | |
| static void | |
| dtrace_process_dof (asection *sect, struct objfile *objfile, | |
| std::vector<std::unique_ptr<probe>> *probesp, | |
| struct dtrace_dof_hdr *dof) | |
| { | |
| struct gdbarch *gdbarch = objfile->arch (); | |
| struct dtrace_dof_sect *section; | |
| int i; | |
| /* The first step is to check for the DOF magic number. If no valid | |
| DOF data is found in the section then a complaint is issued to | |
| the user and the section skipped. */ | |
| if (dof->dofh_ident[DTRACE_DOF_ID_MAG0] != 0x7F | |
| || dof->dofh_ident[DTRACE_DOF_ID_MAG1] != 'D' | |
| || dof->dofh_ident[DTRACE_DOF_ID_MAG2] != 'O' | |
| || dof->dofh_ident[DTRACE_DOF_ID_MAG3] != 'F') | |
| goto invalid_dof_data; | |
| /* Make sure the encoding mark is either DTRACE_DOF_ENCODE_LSB or | |
| DTRACE_DOF_ENCODE_MSB. */ | |
| if (dof->dofh_ident[DTRACE_DOF_ID_ENCODING] != DTRACE_DOF_ENCODE_LSB | |
| && dof->dofh_ident[DTRACE_DOF_ID_ENCODING] != DTRACE_DOF_ENCODE_MSB) | |
| goto invalid_dof_data; | |
| /* Make sure this DOF is not an enabling DOF, i.e. there are no ECB | |
| Description sections. */ | |
| section = (struct dtrace_dof_sect *) DTRACE_DOF_PTR (dof, | |
| DOF_UINT (dof, dof->dofh_secoff)); | |
| for (i = 0; i < DOF_UINT (dof, dof->dofh_secnum); i++, section++) | |
| if (section->dofs_type == DTRACE_DOF_SECT_TYPE_ECBDESC) | |
| return; | |
| /* Iterate over any section of type Provider and extract the probe | |
| information from them. If there are no "provider" sections on | |
| the DOF then we just return. */ | |
| section = (struct dtrace_dof_sect *) DTRACE_DOF_PTR (dof, | |
| DOF_UINT (dof, dof->dofh_secoff)); | |
| for (i = 0; i < DOF_UINT (dof, dof->dofh_secnum); i++, section++) | |
| if (DOF_UINT (dof, section->dofs_type) == DTRACE_DOF_SECT_TYPE_PROVIDER) | |
| { | |
| struct dtrace_dof_provider *provider = (struct dtrace_dof_provider *) | |
| DTRACE_DOF_PTR (dof, DOF_UINT (dof, section->dofs_offset)); | |
| struct dtrace_dof_sect *strtab_s | |
| = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_strtab)); | |
| struct dtrace_dof_sect *probes_s | |
| = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_probes)); | |
| struct dtrace_dof_sect *args_s | |
| = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_prargs)); | |
| struct dtrace_dof_sect *offsets_s | |
| = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_proffs)); | |
| struct dtrace_dof_sect *eoffsets_s | |
| = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_prenoffs)); | |
| char *strtab = DTRACE_DOF_PTR (dof, DOF_UINT (dof, strtab_s->dofs_offset)); | |
| char *offtab = DTRACE_DOF_PTR (dof, DOF_UINT (dof, offsets_s->dofs_offset)); | |
| char *eofftab = DTRACE_DOF_PTR (dof, DOF_UINT (dof, eoffsets_s->dofs_offset)); | |
| char *argtab = DTRACE_DOF_PTR (dof, DOF_UINT (dof, args_s->dofs_offset)); | |
| unsigned int entsize = DOF_UINT (dof, probes_s->dofs_entsize); | |
| int num_probes; | |
| if (DOF_UINT (dof, section->dofs_size) | |
| < sizeof (struct dtrace_dof_provider)) | |
| { | |
| /* The section is smaller than expected, so do not use it. | |
| This has been observed on x86-solaris 10. */ | |
| goto invalid_dof_data; | |
| } | |
| /* Very, unlikely, but could crash gdb if not handled | |
| properly. */ | |
| if (entsize == 0) | |
| goto invalid_dof_data; | |
| num_probes = DOF_UINT (dof, probes_s->dofs_size) / entsize; | |
| for (i = 0; i < num_probes; i++) | |
| { | |
| struct dtrace_dof_probe *probe = (struct dtrace_dof_probe *) | |
| DTRACE_DOF_PTR (dof, DOF_UINT (dof, probes_s->dofs_offset) | |
| + (i * DOF_UINT (dof, probes_s->dofs_entsize))); | |
| dtrace_process_dof_probe (objfile, | |
| gdbarch, probesp, | |
| dof, probe, | |
| provider, strtab, offtab, eofftab, argtab, | |
| DOF_UINT (dof, strtab_s->dofs_size)); | |
| } | |
| } | |
| return; | |
| invalid_dof_data: | |
| complaint (_("skipping section '%s' which does not contain valid DOF data."), | |
| sect->name); | |
| } | |
| /* Implementation of 'build_arg_exprs' method. */ | |
| void | |
| dtrace_probe::build_arg_exprs (struct gdbarch *gdbarch) | |
| { | |
| size_t argc = 0; | |
| m_args_expr_built = true; | |
| /* Iterate over the arguments in the probe and build the | |
| corresponding GDB internal expression that will generate the | |
| value of the argument when executed at the PC of the probe. */ | |
| for (dtrace_probe_arg &arg : m_args) | |
| { | |
| /* Initialize the expression builder. The language does not | |
| matter, since we are using our own parser. */ | |
| expr_builder builder (current_language, gdbarch); | |
| /* The argument value, which is ABI dependent and casted to | |
| `long int'. */ | |
| expr::operation_up op = gdbarch_dtrace_parse_probe_argument (gdbarch, | |
| argc); | |
| /* Casting to the expected type, but only if the type was | |
| recognized at probe load time. Otherwise the argument will | |
| be evaluated as the long integer passed to the probe. */ | |
| if (arg.type != NULL) | |
| op = expr::make_operation<expr::unop_cast_operation> (std::move (op), | |
| arg.type); | |
| builder.set_operation (std::move (op)); | |
| arg.expr = builder.release (); | |
| ++argc; | |
| } | |
| } | |
| /* Implementation of 'get_arg_by_number' method. */ | |
| struct dtrace_probe_arg * | |
| dtrace_probe::get_arg_by_number (unsigned n, struct gdbarch *gdbarch) | |
| { | |
| if (!m_args_expr_built) | |
| this->build_arg_exprs (gdbarch); | |
| if (n > m_args.size ()) | |
| internal_error (_("Probe '%s' has %d arguments, but GDB is requesting\n" | |
| "argument %u. This should not happen. Please\n" | |
| "report this bug."), | |
| this->get_name ().c_str (), | |
| (int) m_args.size (), n); | |
| return &m_args[n]; | |
| } | |
| /* Implementation of the probe is_enabled method. */ | |
| bool | |
| dtrace_probe::is_enabled () const | |
| { | |
| struct gdbarch *gdbarch = this->get_gdbarch (); | |
| for (const dtrace_probe_enabler &enabler : m_enablers) | |
| if (!gdbarch_dtrace_probe_is_enabled (gdbarch, enabler.address)) | |
| return false; | |
| return true; | |
| } | |
| /* Implementation of the get_probe_address method. */ | |
| CORE_ADDR | |
| dtrace_probe::get_relocated_address (struct objfile *objfile) | |
| { | |
| return this->get_address () + objfile->text_section_offset (); | |
| } | |
| /* Implementation of the get_argument_count method. */ | |
| unsigned | |
| dtrace_probe::get_argument_count (struct gdbarch *gdbarch) | |
| { | |
| return m_args.size (); | |
| } | |
| /* Implementation of the can_evaluate_arguments method. */ | |
| bool | |
| dtrace_probe::can_evaluate_arguments () const | |
| { | |
| struct gdbarch *gdbarch = this->get_gdbarch (); | |
| return gdbarch_dtrace_parse_probe_argument_p (gdbarch); | |
| } | |
| /* Implementation of the evaluate_argument method. */ | |
| struct value * | |
| dtrace_probe::evaluate_argument (unsigned n, | |
| frame_info_ptr frame) | |
| { | |
| struct gdbarch *gdbarch = this->get_gdbarch (); | |
| struct dtrace_probe_arg *arg; | |
| arg = this->get_arg_by_number (n, gdbarch); | |
| return arg->expr->evaluate (arg->type); | |
| } | |
| /* Implementation of the compile_to_ax method. */ | |
| void | |
| dtrace_probe::compile_to_ax (struct agent_expr *expr, struct axs_value *value, | |
| unsigned n) | |
| { | |
| struct dtrace_probe_arg *arg; | |
| arg = this->get_arg_by_number (n, expr->gdbarch); | |
| arg->expr->op->generate_ax (arg->expr.get (), expr, value); | |
| require_rvalue (expr, value); | |
| value->type = arg->type; | |
| } | |
| /* Implementation of the 'get_static_ops' method. */ | |
| const static_probe_ops * | |
| dtrace_probe::get_static_ops () const | |
| { | |
| return &dtrace_static_probe_ops; | |
| } | |
| /* Implementation of the gen_info_probes_table_values method. */ | |
| std::vector<const char *> | |
| dtrace_probe::gen_info_probes_table_values () const | |
| { | |
| const char *val = NULL; | |
| if (m_enablers.empty ()) | |
| val = "always"; | |
| else if (!gdbarch_dtrace_probe_is_enabled_p (this->get_gdbarch ())) | |
| val = "unknown"; | |
| else if (this->is_enabled ()) | |
| val = "yes"; | |
| else | |
| val = "no"; | |
| return std::vector<const char *> { val }; | |
| } | |
| /* Implementation of the enable method. */ | |
| void | |
| dtrace_probe::enable () | |
| { | |
| struct gdbarch *gdbarch = this->get_gdbarch (); | |
| /* Enabling a dtrace probe implies patching the text section of the | |
| running process, so make sure the inferior is indeed running. */ | |
| if (inferior_ptid == null_ptid) | |
| error (_("No inferior running")); | |
| /* Fast path. */ | |
| if (this->is_enabled ()) | |
| return; | |
| /* Iterate over all defined enabler in the given probe and enable | |
| them all using the corresponding gdbarch hook. */ | |
| for (const dtrace_probe_enabler &enabler : m_enablers) | |
| if (gdbarch_dtrace_enable_probe_p (gdbarch)) | |
| gdbarch_dtrace_enable_probe (gdbarch, enabler.address); | |
| } | |
| /* Implementation of the disable_probe method. */ | |
| void | |
| dtrace_probe::disable () | |
| { | |
| struct gdbarch *gdbarch = this->get_gdbarch (); | |
| /* Disabling a dtrace probe implies patching the text section of the | |
| running process, so make sure the inferior is indeed running. */ | |
| if (inferior_ptid == null_ptid) | |
| error (_("No inferior running")); | |
| /* Fast path. */ | |
| if (!this->is_enabled ()) | |
| return; | |
| /* Are we trying to disable a probe that does not have any enabler | |
| associated? */ | |
| if (m_enablers.empty ()) | |
| error (_("Probe %s:%s cannot be disabled: no enablers."), | |
| this->get_provider ().c_str (), this->get_name ().c_str ()); | |
| /* Iterate over all defined enabler in the given probe and disable | |
| them all using the corresponding gdbarch hook. */ | |
| for (dtrace_probe_enabler &enabler : m_enablers) | |
| if (gdbarch_dtrace_disable_probe_p (gdbarch)) | |
| gdbarch_dtrace_disable_probe (gdbarch, enabler.address); | |
| } | |
| /* Implementation of the is_linespec method. */ | |
| bool | |
| dtrace_static_probe_ops::is_linespec (const char **linespecp) const | |
| { | |
| static const char *const keywords[] = { "-pdtrace", "-probe-dtrace", NULL }; | |
| return probe_is_linespec_by_keyword (linespecp, keywords); | |
| } | |
| /* Implementation of the get_probes method. */ | |
| void | |
| dtrace_static_probe_ops::get_probes | |
| (std::vector<std::unique_ptr<probe>> *probesp, | |
| struct objfile *objfile) const | |
| { | |
| bfd *abfd = objfile->obfd.get (); | |
| asection *sect = NULL; | |
| /* Do nothing in case this is a .debug file, instead of the objfile | |
| itself. */ | |
| if (objfile->separate_debug_objfile_backlink != NULL) | |
| return; | |
| /* Iterate over the sections in OBJFILE looking for DTrace | |
| information. */ | |
| for (sect = abfd->sections; sect != NULL; sect = sect->next) | |
| { | |
| if (elf_section_data (sect)->this_hdr.sh_type == SHT_SUNW_dof) | |
| { | |
| bfd_byte *dof; | |
| /* Read the contents of the DOF section and then process it to | |
| extract the information of any probe defined into it. */ | |
| if (bfd_malloc_and_get_section (abfd, sect, &dof) && dof != NULL) | |
| dtrace_process_dof (sect, objfile, probesp, | |
| (struct dtrace_dof_hdr *) dof); | |
| else | |
| complaint (_("could not obtain the contents of" | |
| "section '%s' in objfile `%s'."), | |
| bfd_section_name (sect), bfd_get_filename (abfd)); | |
| xfree (dof); | |
| } | |
| } | |
| } | |
| /* Implementation of the type_name method. */ | |
| const char * | |
| dtrace_static_probe_ops::type_name () const | |
| { | |
| return "dtrace"; | |
| } | |
| /* Implementation of the gen_info_probes_table_header method. */ | |
| std::vector<struct info_probe_column> | |
| dtrace_static_probe_ops::gen_info_probes_table_header () const | |
| { | |
| struct info_probe_column dtrace_probe_column; | |
| dtrace_probe_column.field_name = "enabled"; | |
| dtrace_probe_column.print_name = _("Enabled"); | |
| return std::vector<struct info_probe_column> { dtrace_probe_column }; | |
| } | |
| /* Implementation of the `info probes dtrace' command. */ | |
| static void | |
| info_probes_dtrace_command (const char *arg, int from_tty) | |
| { | |
| info_probes_for_spops (arg, from_tty, &dtrace_static_probe_ops); | |
| } | |
| void _initialize_dtrace_probe (); | |
| void | |
| _initialize_dtrace_probe () | |
| { | |
| all_static_probe_ops.push_back (&dtrace_static_probe_ops); | |
| add_cmd ("dtrace", class_info, info_probes_dtrace_command, | |
| _("\ | |
| Show information about DTrace static probes.\n\ | |
| Usage: info probes dtrace [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."), | |
| info_probes_cmdlist_get ()); | |
| } |