mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-01 05:55:23 +08:00
268a13a5a3
This is the next patch in the ongoing series to move gdbsever to the top level. This patch just renames the "common" directory. The idea is to do this move in two parts: first rename the directory (this patch), then move the directory to the top. This approach makes the patches a bit more tractable. I chose the name "gdbsupport" for the directory. However, as this patch was largely written by sed, we could pick a new name without too much difficulty. Tested by the buildbot. gdb/ChangeLog 2019-07-09 Tom Tromey <tom@tromey.com> * contrib/ari/gdb_ari.sh: Change common to gdbsupport. * configure: Rebuild. * configure.ac: Change common to gdbsupport. * gdbsupport: Rename from common. * acinclude.m4: Change common to gdbsupport. * Makefile.in (CONFIG_SRC_SUBDIR, COMMON_SFILES) (HFILES_NO_SRCDIR, stamp-version, ALLDEPFILES): Change common to gdbsupport. * aarch64-tdep.c, ada-lang.c, ada-lang.h, agent.c, alloc.c, amd64-darwin-tdep.c, amd64-dicos-tdep.c, amd64-fbsd-nat.c, amd64-fbsd-tdep.c, amd64-linux-nat.c, amd64-linux-tdep.c, amd64-nbsd-tdep.c, amd64-obsd-tdep.c, amd64-sol2-tdep.c, amd64-tdep.c, amd64-windows-tdep.c, arch-utils.c, arch/aarch64-insn.c, arch/aarch64.c, arch/aarch64.h, arch/amd64.c, arch/amd64.h, arch/arm-get-next-pcs.c, arch/arm-linux.c, arch/arm.c, arch/i386.c, arch/i386.h, arch/ppc-linux-common.c, arch/riscv.c, arch/riscv.h, arch/tic6x.c, arm-tdep.c, auto-load.c, auxv.c, ax-gdb.c, ax-general.c, ax.h, breakpoint.c, breakpoint.h, btrace.c, btrace.h, build-id.c, build-id.h, c-lang.h, charset.c, charset.h, cli/cli-cmds.c, cli/cli-cmds.h, cli/cli-decode.c, cli/cli-dump.c, cli/cli-option.h, cli/cli-script.c, coff-pe-read.c, command.h, compile/compile-c-support.c, compile/compile-c.h, compile/compile-cplus-symbols.c, compile/compile-cplus-types.c, compile/compile-cplus.h, compile/compile-loc2c.c, compile/compile.c, completer.c, completer.h, contrib/ari/gdb_ari.sh, corefile.c, corelow.c, cp-support.c, cp-support.h, cp-valprint.c, csky-tdep.c, ctf.c, darwin-nat.c, debug.c, defs.h, disasm-selftests.c, disasm.c, disasm.h, dtrace-probe.c, dwarf-index-cache.c, dwarf-index-cache.h, dwarf-index-write.c, dwarf2-frame.c, dwarf2expr.c, dwarf2loc.c, dwarf2read.c, event-loop.c, event-top.c, exceptions.c, exec.c, extension.h, fbsd-nat.c, features/aarch64-core.c, features/aarch64-fpu.c, features/aarch64-pauth.c, features/aarch64-sve.c, features/i386/32bit-avx.c, features/i386/32bit-avx512.c, features/i386/32bit-core.c, features/i386/32bit-linux.c, features/i386/32bit-mpx.c, features/i386/32bit-pkeys.c, features/i386/32bit-segments.c, features/i386/32bit-sse.c, features/i386/64bit-avx.c, features/i386/64bit-avx512.c, features/i386/64bit-core.c, features/i386/64bit-linux.c, features/i386/64bit-mpx.c, features/i386/64bit-pkeys.c, features/i386/64bit-segments.c, features/i386/64bit-sse.c, features/i386/x32-core.c, features/riscv/32bit-cpu.c, features/riscv/32bit-csr.c, features/riscv/32bit-fpu.c, features/riscv/64bit-cpu.c, features/riscv/64bit-csr.c, features/riscv/64bit-fpu.c, features/tic6x-c6xp.c, features/tic6x-core.c, features/tic6x-gp.c, filename-seen-cache.h, findcmd.c, findvar.c, fork-child.c, gcore.c, gdb_bfd.c, gdb_bfd.h, gdb_proc_service.h, gdb_regex.c, gdb_select.h, gdb_usleep.c, gdbarch-selftests.c, gdbthread.h, gdbtypes.h, gnu-nat.c, go32-nat.c, guile/guile.c, guile/scm-ports.c, guile/scm-safe-call.c, guile/scm-type.c, i386-fbsd-nat.c, i386-fbsd-tdep.c, i386-go32-tdep.c, i386-linux-nat.c, i386-linux-tdep.c, i386-tdep.c, i387-tdep.c, ia64-libunwind-tdep.c, ia64-linux-nat.c, inf-child.c, inf-ptrace.c, infcall.c, infcall.h, infcmd.c, inferior-iter.h, inferior.c, inferior.h, inflow.c, inflow.h, infrun.c, infrun.h, inline-frame.c, language.h, linespec.c, linux-fork.c, linux-nat.c, linux-tdep.c, linux-thread-db.c, location.c, machoread.c, macrotab.h, main.c, maint.c, maint.h, memattr.c, memrange.h, mi/mi-cmd-break.h, mi/mi-cmd-env.c, mi/mi-cmd-stack.c, mi/mi-cmd-var.c, mi/mi-interp.c, mi/mi-main.c, mi/mi-parse.h, minsyms.c, mips-linux-tdep.c, namespace.h, nat/aarch64-linux-hw-point.c, nat/aarch64-linux-hw-point.h, nat/aarch64-linux.c, nat/aarch64-sve-linux-ptrace.c, nat/amd64-linux-siginfo.c, nat/fork-inferior.c, nat/linux-btrace.c, nat/linux-btrace.h, nat/linux-namespaces.c, nat/linux-nat.h, nat/linux-osdata.c, nat/linux-personality.c, nat/linux-procfs.c, nat/linux-ptrace.c, nat/linux-ptrace.h, nat/linux-waitpid.c, nat/mips-linux-watch.c, nat/mips-linux-watch.h, nat/ppc-linux.c, nat/x86-dregs.c, nat/x86-dregs.h, nat/x86-linux-dregs.c, nat/x86-linux.c, nto-procfs.c, nto-tdep.c, objfile-flags.h, objfiles.c, objfiles.h, obsd-nat.c, observable.h, osdata.c, p-valprint.c, parse.c, parser-defs.h, ppc-linux-nat.c, printcmd.c, probe.c, proc-api.c, procfs.c, producer.c, progspace.h, psymtab.h, python/py-framefilter.c, python/py-inferior.c, python/py-ref.h, python/py-type.c, python/python.c, record-btrace.c, record-full.c, record.c, record.h, regcache-dump.c, regcache.c, regcache.h, remote-fileio.c, remote-fileio.h, remote-sim.c, remote.c, riscv-tdep.c, rs6000-aix-tdep.c, rust-exp.y, s12z-tdep.c, selftest-arch.c, ser-base.c, ser-event.c, ser-pipe.c, ser-tcp.c, ser-unix.c, skip.c, solib-aix.c, solib-target.c, solib.c, source-cache.c, source.c, source.h, sparc-nat.c, spu-linux-nat.c, stack.c, stap-probe.c, symfile-add-flags.h, symfile.c, symfile.h, symtab.c, symtab.h, target-descriptions.c, target-descriptions.h, target-memory.c, target.c, target.h, target/waitstatus.c, target/waitstatus.h, thread-iter.h, thread.c, tilegx-tdep.c, top.c, top.h, tracefile-tfile.c, tracefile.c, tracepoint.c, tracepoint.h, tui/tui-io.c, ui-file.c, ui-out.h, unittests/array-view-selftests.c, unittests/child-path-selftests.c, unittests/cli-utils-selftests.c, unittests/common-utils-selftests.c, unittests/copy_bitwise-selftests.c, unittests/environ-selftests.c, unittests/format_pieces-selftests.c, unittests/function-view-selftests.c, unittests/lookup_name_info-selftests.c, unittests/memory-map-selftests.c, unittests/memrange-selftests.c, unittests/mkdir-recursive-selftests.c, unittests/observable-selftests.c, unittests/offset-type-selftests.c, unittests/optional-selftests.c, unittests/parse-connection-spec-selftests.c, unittests/ptid-selftests.c, unittests/rsp-low-selftests.c, unittests/scoped_fd-selftests.c, unittests/scoped_mmap-selftests.c, unittests/scoped_restore-selftests.c, unittests/string_view-selftests.c, unittests/style-selftests.c, unittests/tracepoint-selftests.c, unittests/unpack-selftests.c, unittests/utils-selftests.c, unittests/xml-utils-selftests.c, utils.c, utils.h, valarith.c, valops.c, valprint.c, value.c, value.h, varobj.c, varobj.h, windows-nat.c, x86-linux-nat.c, xml-support.c, xml-support.h, xml-tdesc.h, xstormy16-tdep.c, xtensa-linux-nat.c, dwarf2read.h: Change common to gdbsupport. gdb/gdbserver/ChangeLog 2019-07-09 Tom Tromey <tom@tromey.com> * configure: Rebuild. * configure.ac: Change common to gdbsupport. * acinclude.m4: Change common to gdbsupport. * Makefile.in (SFILES, OBS, GDBREPLAY_OBS, IPA_OBJS) (version-generated.c, gdbsupport/%-ipa.o, gdbsupport/%.o): Change common to gdbsupport. * ax.c, event-loop.c, fork-child.c, gdb_proc_service.h, gdbreplay.c, gdbthread.h, hostio-errno.c, hostio.c, i387-fp.c, inferiors.c, inferiors.h, linux-aarch64-tdesc-selftest.c, linux-amd64-ipa.c, linux-i386-ipa.c, linux-low.c, linux-tic6x-low.c, linux-x86-low.c, linux-x86-tdesc-selftest.c, linux-x86-tdesc.c, lynx-i386-low.c, lynx-low.c, mem-break.h, nto-x86-low.c, regcache.c, regcache.h, remote-utils.c, server.c, server.h, spu-low.c, symbol.c, target.h, tdesc.c, tdesc.h, thread-db.c, tracepoint.c, win32-i386-low.c, win32-low.c: Change common to gdbsupport.
940 lines
26 KiB
C
940 lines
26 KiB
C
/* Generic static probe support for GDB.
|
||
|
||
Copyright (C) 2012-2019 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 "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 "gdbsupport/gdb_optional.h"
|
||
|
||
/* Class that implements the static probe methods for "any" probe. */
|
||
|
||
class any_static_probe_ops : public static_probe_ops
|
||
{
|
||
public:
|
||
/* See probe.h. */
|
||
bool is_linespec (const char **linespecp) const override;
|
||
|
||
/* See probe.h. */
|
||
void get_probes (std::vector<std::unique_ptr<probe>> *probesp,
|
||
struct objfile *objfile) const override;
|
||
|
||
/* See probe.h. */
|
||
const char *type_name () const override;
|
||
|
||
/* See probe.h. */
|
||
std::vector<struct info_probe_column> gen_info_probes_table_header
|
||
() const override;
|
||
};
|
||
|
||
/* Static operations associated with a generic probe. */
|
||
|
||
const any_static_probe_ops any_static_probe_ops {};
|
||
|
||
/* A helper for parse_probes that decodes a probe specification in
|
||
SEARCH_PSPACE. It appends matching SALs to RESULT. */
|
||
|
||
static void
|
||
parse_probes_in_pspace (const static_probe_ops *spops,
|
||
struct program_space *search_pspace,
|
||
const char *objfile_namestr,
|
||
const char *provider,
|
||
const char *name,
|
||
std::vector<symtab_and_line> *result)
|
||
{
|
||
for (objfile *objfile : search_pspace->objfiles ())
|
||
{
|
||
if (!objfile->sf || !objfile->sf->sym_probe_fns)
|
||
continue;
|
||
|
||
if (objfile_namestr
|
||
&& FILENAME_CMP (objfile_name (objfile), objfile_namestr) != 0
|
||
&& FILENAME_CMP (lbasename (objfile_name (objfile)),
|
||
objfile_namestr) != 0)
|
||
continue;
|
||
|
||
const std::vector<std::unique_ptr<probe>> &probes
|
||
= objfile->sf->sym_probe_fns->sym_get_probes (objfile);
|
||
|
||
for (auto &p : probes)
|
||
{
|
||
if (spops != &any_static_probe_ops && p->get_static_ops () != spops)
|
||
continue;
|
||
|
||
if (provider != NULL && p->get_provider () != provider)
|
||
continue;
|
||
|
||
if (p->get_name () != name)
|
||
continue;
|
||
|
||
symtab_and_line sal;
|
||
sal.pc = p->get_relocated_address (objfile);
|
||
sal.explicit_pc = 1;
|
||
sal.section = find_pc_overlay (sal.pc);
|
||
sal.pspace = search_pspace;
|
||
sal.prob = p.get ();
|
||
sal.objfile = objfile;
|
||
|
||
result->push_back (std::move (sal));
|
||
}
|
||
}
|
||
}
|
||
|
||
/* See definition in probe.h. */
|
||
|
||
std::vector<symtab_and_line>
|
||
parse_probes (const struct event_location *location,
|
||
struct program_space *search_pspace,
|
||
struct linespec_result *canonical)
|
||
{
|
||
char *arg_end, *arg;
|
||
char *objfile_namestr = NULL, *provider = NULL, *name, *p;
|
||
const char *arg_start, *cs;
|
||
|
||
gdb_assert (event_location_type (location) == PROBE_LOCATION);
|
||
arg_start = get_probe_location (location);
|
||
|
||
cs = arg_start;
|
||
const static_probe_ops *spops = probe_linespec_to_static_ops (&cs);
|
||
if (spops == NULL)
|
||
error (_("'%s' is not a probe linespec"), arg_start);
|
||
|
||
arg = (char *) cs;
|
||
arg = skip_spaces (arg);
|
||
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. */
|
||
std::string copy (arg, arg_end - arg);
|
||
arg = ©[0];
|
||
|
||
/* 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_namestr = arg;
|
||
provider = hold;
|
||
name = p + 1;
|
||
}
|
||
}
|
||
|
||
if (*name == '\0')
|
||
error (_("no probe name specified"));
|
||
if (provider && *provider == '\0')
|
||
error (_("invalid provider name"));
|
||
if (objfile_namestr && *objfile_namestr == '\0')
|
||
error (_("invalid objfile name"));
|
||
|
||
std::vector<symtab_and_line> result;
|
||
if (search_pspace != NULL)
|
||
{
|
||
parse_probes_in_pspace (spops, search_pspace, objfile_namestr,
|
||
provider, name, &result);
|
||
}
|
||
else
|
||
{
|
||
struct program_space *pspace;
|
||
|
||
ALL_PSPACES (pspace)
|
||
parse_probes_in_pspace (spops, pspace, objfile_namestr,
|
||
provider, name, &result);
|
||
}
|
||
|
||
if (result.empty ())
|
||
{
|
||
throw_error (NOT_FOUND_ERROR,
|
||
_("No probe matching objfile=`%s', provider=`%s', name=`%s'"),
|
||
objfile_namestr ? objfile_namestr : _("<any>"),
|
||
provider ? provider : _("<any>"),
|
||
name);
|
||
}
|
||
|
||
if (canonical)
|
||
{
|
||
std::string canon (arg_start, arg_end - arg_start);
|
||
canonical->special_display = 1;
|
||
canonical->pre_expanded = 1;
|
||
canonical->location = new_probe_location (canon.c_str ());
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/* See definition in probe.h. */
|
||
|
||
std::vector<probe *>
|
||
find_probes_in_objfile (struct objfile *objfile, const char *provider,
|
||
const char *name)
|
||
{
|
||
std::vector<probe *> result;
|
||
|
||
if (!objfile->sf || !objfile->sf->sym_probe_fns)
|
||
return result;
|
||
|
||
const std::vector<std::unique_ptr<probe>> &probes
|
||
= objfile->sf->sym_probe_fns->sym_get_probes (objfile);
|
||
for (auto &p : probes)
|
||
{
|
||
if (p->get_provider () != provider)
|
||
continue;
|
||
|
||
if (p->get_name () != name)
|
||
continue;
|
||
|
||
result.push_back (p.get ());
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/* See definition in probe.h. */
|
||
|
||
struct bound_probe
|
||
find_probe_by_pc (CORE_ADDR pc)
|
||
{
|
||
struct bound_probe result;
|
||
|
||
result.objfile = NULL;
|
||
result.prob = NULL;
|
||
|
||
for (objfile *objfile : current_program_space->objfiles ())
|
||
{
|
||
if (!objfile->sf || !objfile->sf->sym_probe_fns
|
||
|| objfile->sect_index_text == -1)
|
||
continue;
|
||
|
||
/* If this proves too inefficient, we can replace with a hash. */
|
||
const std::vector<std::unique_ptr<probe>> &probes
|
||
= objfile->sf->sym_probe_fns->sym_get_probes (objfile);
|
||
for (auto &p : probes)
|
||
if (p->get_relocated_address (objfile) == pc)
|
||
{
|
||
result.objfile = objfile;
|
||
result.prob = p.get ();
|
||
return result;
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
|
||
|
||
/* Make a vector of probes matching OBJNAME, PROVIDER, and PROBE_NAME.
|
||
If SPOPS is not &any_static_probe_ops, only probes related to this
|
||
specific static probe ops will match. Each argument is a regexp,
|
||
or NULL, which matches anything. */
|
||
|
||
static std::vector<bound_probe>
|
||
collect_probes (const std::string &objname, const std::string &provider,
|
||
const std::string &probe_name, const static_probe_ops *spops)
|
||
{
|
||
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"));
|
||
|
||
for (objfile *objfile : current_program_space->objfiles ())
|
||
{
|
||
if (! objfile->sf || ! objfile->sf->sym_probe_fns)
|
||
continue;
|
||
|
||
if (obj_pat)
|
||
{
|
||
if (obj_pat->exec (objfile_name (objfile), 0, NULL, 0) != 0)
|
||
continue;
|
||
}
|
||
|
||
const std::vector<std::unique_ptr<probe>> &probes
|
||
= objfile->sf->sym_probe_fns->sym_get_probes (objfile);
|
||
|
||
for (auto &p : probes)
|
||
{
|
||
if (spops != &any_static_probe_ops && p->get_static_ops () != spops)
|
||
continue;
|
||
|
||
if (prov_pat
|
||
&& prov_pat->exec (p->get_provider ().c_str (), 0, NULL, 0) != 0)
|
||
continue;
|
||
|
||
if (probe_pat
|
||
&& probe_pat->exec (p->get_name ().c_str (), 0, NULL, 0) != 0)
|
||
continue;
|
||
|
||
result.emplace_back (p.get (), objfile);
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/* A qsort comparison function for bound_probe_s objects. */
|
||
|
||
static bool
|
||
compare_probes (const bound_probe &a, const bound_probe &b)
|
||
{
|
||
int v;
|
||
|
||
v = a.prob->get_provider ().compare (b.prob->get_provider ());
|
||
if (v != 0)
|
||
return v < 0;
|
||
|
||
v = a.prob->get_name ().compare (b.prob->get_name ());
|
||
if (v != 0)
|
||
return v < 0;
|
||
|
||
if (a.prob->get_address () != b.prob->get_address ())
|
||
return a.prob->get_address () < b.prob->get_address ();
|
||
|
||
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 (const std::vector<bound_probe> &probes,
|
||
const static_probe_ops *spops)
|
||
{
|
||
/* `headings' refers to the names of the columns when printing `info
|
||
probes'. */
|
||
gdb_assert (spops != NULL);
|
||
|
||
std::vector<struct info_probe_column> headings
|
||
= spops->gen_info_probes_table_header ();
|
||
|
||
for (const info_probe_column &column : headings)
|
||
{
|
||
size_t size_max = strlen (column.print_name);
|
||
|
||
for (const bound_probe &probe : probes)
|
||
{
|
||
/* `probe_fields' refers to the values of each new field that this
|
||
probe will display. */
|
||
|
||
if (probe.prob->get_static_ops () != spops)
|
||
continue;
|
||
|
||
std::vector<const char *> probe_fields
|
||
= probe.prob->gen_info_probes_table_values ();
|
||
|
||
gdb_assert (probe_fields.size () == headings.size ());
|
||
|
||
for (const char *val : probe_fields)
|
||
{
|
||
/* It is valid to have a NULL value here, which means that the
|
||
backend does not have something to write and this particular
|
||
field should be skipped. */
|
||
if (val == NULL)
|
||
continue;
|
||
|
||
size_max = std::max (strlen (val), size_max);
|
||
}
|
||
}
|
||
|
||
current_uiout->table_header (size_max, ui_left,
|
||
column.field_name, column.print_name);
|
||
}
|
||
}
|
||
|
||
/* Helper function to print not-applicable strings for all the extra
|
||
columns defined in a static_probe_ops. */
|
||
|
||
static void
|
||
print_ui_out_not_applicables (const static_probe_ops *spops)
|
||
{
|
||
std::vector<struct info_probe_column> headings
|
||
= spops->gen_info_probes_table_header ();
|
||
|
||
for (const info_probe_column &column : headings)
|
||
current_uiout->field_string (column.field_name, _("n/a"));
|
||
}
|
||
|
||
/* Helper function to print extra information about a probe and an objfile
|
||
represented by PROBE. */
|
||
|
||
static void
|
||
print_ui_out_info (probe *probe)
|
||
{
|
||
/* `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. */
|
||
gdb_assert (probe != NULL);
|
||
std::vector<struct info_probe_column> headings
|
||
= probe->get_static_ops ()->gen_info_probes_table_header ();
|
||
std::vector<const char *> values
|
||
= probe->gen_info_probes_table_values ();
|
||
|
||
gdb_assert (headings.size () == values.size ());
|
||
|
||
for (int ix = 0; ix < headings.size (); ++ix)
|
||
{
|
||
struct info_probe_column column = headings[ix];
|
||
const char *val = values[ix];
|
||
|
||
if (val == NULL)
|
||
current_uiout->field_skip (column.field_name);
|
||
else
|
||
current_uiout->field_string (column.field_name, val);
|
||
}
|
||
}
|
||
|
||
/* Helper function that returns the number of extra fields which POPS will
|
||
need. */
|
||
|
||
static int
|
||
get_number_extra_fields (const static_probe_ops *spops)
|
||
{
|
||
return spops->gen_info_probes_table_header ().size ();
|
||
}
|
||
|
||
/* Helper function that returns true if there is a probe in PROBES
|
||
featuring the given SPOPS. It returns false otherwise. */
|
||
|
||
static bool
|
||
exists_probe_with_spops (const std::vector<bound_probe> &probes,
|
||
const static_probe_ops *spops)
|
||
{
|
||
for (const bound_probe &probe : probes)
|
||
if (probe.prob->get_static_ops () == spops)
|
||
return true;
|
||
|
||
return false;
|
||
}
|
||
|
||
/* 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_spops (const char *arg, int from_tty,
|
||
const static_probe_ops *spops)
|
||
{
|
||
std::string provider, probe_name, objname;
|
||
int any_found;
|
||
int ui_out_extra_fields = 0;
|
||
size_t size_addr;
|
||
size_t size_name = strlen ("Name");
|
||
size_t size_objname = strlen ("Object");
|
||
size_t size_provider = strlen ("Provider");
|
||
size_t size_type = strlen ("Type");
|
||
struct gdbarch *gdbarch = get_current_arch ();
|
||
|
||
parse_probe_linespec (arg, &provider, &probe_name, &objname);
|
||
|
||
std::vector<bound_probe> probes
|
||
= collect_probes (objname, provider, probe_name, spops);
|
||
|
||
if (spops == &any_static_probe_ops)
|
||
{
|
||
/* If SPOPS is &any_static_probe_ops, it means the user has
|
||
requested a "simple" `info probes', i.e., she wants to print
|
||
all information about all probes. For that, we have to
|
||
identify how many extra fields we will need to add in the
|
||
ui_out table.
|
||
|
||
To do that, we iterate over all static_probe_ops, querying
|
||
each one about its extra fields, and incrementing
|
||
`ui_out_extra_fields' to reflect that number. But note that
|
||
we ignore the static_probe_ops for which no probes are
|
||
defined with the given search criteria. */
|
||
|
||
for (const static_probe_ops *po : all_static_probe_ops)
|
||
if (exists_probe_with_spops (probes, po))
|
||
ui_out_extra_fields += get_number_extra_fields (po);
|
||
}
|
||
else
|
||
ui_out_extra_fields = get_number_extra_fields (spops);
|
||
|
||
{
|
||
ui_out_emit_table table_emitter (current_uiout,
|
||
5 + ui_out_extra_fields,
|
||
probes.size (), "StaticProbes");
|
||
|
||
std::sort (probes.begin (), probes.end (), compare_probes);
|
||
|
||
/* What's the size of an address in our architecture? */
|
||
size_addr = gdbarch_addr_bit (gdbarch) == 64 ? 18 : 10;
|
||
|
||
/* Determining the maximum size of each field (`type', `provider',
|
||
`name' and `objname'). */
|
||
for (const bound_probe &probe : probes)
|
||
{
|
||
const char *probe_type = probe.prob->get_static_ops ()->type_name ();
|
||
|
||
size_type = std::max (strlen (probe_type), size_type);
|
||
size_name = std::max (probe.prob->get_name ().size (), size_name);
|
||
size_provider = std::max (probe.prob->get_provider ().size (),
|
||
size_provider);
|
||
size_objname = std::max (strlen (objfile_name (probe.objfile)),
|
||
size_objname);
|
||
}
|
||
|
||
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 (spops == &any_static_probe_ops)
|
||
{
|
||
/* We have to generate the table header for each new probe type
|
||
that we will print. Note that this excludes probe types not
|
||
having any defined probe with the search criteria. */
|
||
for (const static_probe_ops *po : all_static_probe_ops)
|
||
if (exists_probe_with_spops (probes, po))
|
||
gen_ui_out_table_header_info (probes, po);
|
||
}
|
||
else
|
||
gen_ui_out_table_header_info (probes, spops);
|
||
|
||
current_uiout->table_header (size_objname, ui_left, "object", _("Object"));
|
||
current_uiout->table_body ();
|
||
|
||
for (const bound_probe &probe : probes)
|
||
{
|
||
const char *probe_type = probe.prob->get_static_ops ()->type_name ();
|
||
|
||
ui_out_emit_tuple tuple_emitter (current_uiout, "probe");
|
||
|
||
current_uiout->field_string ("type", probe_type);
|
||
current_uiout->field_string ("provider",
|
||
probe.prob->get_provider ().c_str ());
|
||
current_uiout->field_string ("name", probe.prob->get_name ().c_str ());
|
||
current_uiout->field_core_addr ("addr", probe.prob->get_gdbarch (),
|
||
probe.prob->get_relocated_address
|
||
(probe.objfile));
|
||
|
||
if (spops == &any_static_probe_ops)
|
||
{
|
||
for (const static_probe_ops *po : all_static_probe_ops)
|
||
{
|
||
if (probe.prob->get_static_ops () == po)
|
||
print_ui_out_info (probe.prob);
|
||
else if (exists_probe_with_spops (probes, po))
|
||
print_ui_out_not_applicables (po);
|
||
}
|
||
}
|
||
else
|
||
print_ui_out_info (probe.prob);
|
||
|
||
current_uiout->field_string ("object",
|
||
objfile_name (probe.objfile));
|
||
current_uiout->text ("\n");
|
||
}
|
||
|
||
any_found = !probes.empty ();
|
||
}
|
||
|
||
if (!any_found)
|
||
current_uiout->message (_("No probes matched.\n"));
|
||
}
|
||
|
||
/* Implementation of the `info probes' command. */
|
||
|
||
static void
|
||
info_probes_command (const char *arg, int from_tty)
|
||
{
|
||
info_probes_for_spops (arg, from_tty, &any_static_probe_ops);
|
||
}
|
||
|
||
/* Implementation of the `enable probes' command. */
|
||
|
||
static void
|
||
enable_probes_command (const char *arg, int from_tty)
|
||
{
|
||
std::string provider, probe_name, objname;
|
||
|
||
parse_probe_linespec ((const char *) arg, &provider, &probe_name, &objname);
|
||
|
||
std::vector<bound_probe> probes
|
||
= collect_probes (objname, provider, probe_name, &any_static_probe_ops);
|
||
if (probes.empty ())
|
||
{
|
||
current_uiout->message (_("No probes matched.\n"));
|
||
return;
|
||
}
|
||
|
||
/* Enable the selected probes, provided their backends support the
|
||
notion of enabling a probe. */
|
||
for (const bound_probe &probe: probes)
|
||
{
|
||
if (probe.prob->get_static_ops ()->can_enable ())
|
||
{
|
||
probe.prob->enable ();
|
||
current_uiout->message (_("Probe %s:%s enabled.\n"),
|
||
probe.prob->get_provider ().c_str (),
|
||
probe.prob->get_name ().c_str ());
|
||
}
|
||
else
|
||
current_uiout->message (_("Probe %s:%s cannot be enabled.\n"),
|
||
probe.prob->get_provider ().c_str (),
|
||
probe.prob->get_name ().c_str ());
|
||
}
|
||
}
|
||
|
||
/* Implementation of the `disable probes' command. */
|
||
|
||
static void
|
||
disable_probes_command (const char *arg, int from_tty)
|
||
{
|
||
std::string provider, probe_name, objname;
|
||
|
||
parse_probe_linespec ((const char *) arg, &provider, &probe_name, &objname);
|
||
|
||
std::vector<bound_probe> probes
|
||
= collect_probes (objname, provider, probe_name, &any_static_probe_ops);
|
||
if (probes.empty ())
|
||
{
|
||
current_uiout->message (_("No probes matched.\n"));
|
||
return;
|
||
}
|
||
|
||
/* Disable the selected probes, provided their backends support the
|
||
notion of enabling a probe. */
|
||
for (const bound_probe &probe : probes)
|
||
{
|
||
if (probe.prob->get_static_ops ()->can_enable ())
|
||
{
|
||
probe.prob->disable ();
|
||
current_uiout->message (_("Probe %s:%s disabled.\n"),
|
||
probe.prob->get_provider ().c_str (),
|
||
probe.prob->get_name ().c_str ());
|
||
}
|
||
else
|
||
current_uiout->message (_("Probe %s:%s cannot be disabled.\n"),
|
||
probe.prob->get_provider ().c_str (),
|
||
probe.prob->get_name ().c_str ());
|
||
}
|
||
}
|
||
|
||
/* See comments in probe.h. */
|
||
|
||
struct value *
|
||
probe_safe_evaluate_at_pc (struct frame_info *frame, unsigned n)
|
||
{
|
||
struct bound_probe probe;
|
||
unsigned n_args;
|
||
|
||
probe = find_probe_by_pc (get_frame_pc (frame));
|
||
if (!probe.prob)
|
||
return NULL;
|
||
|
||
n_args = probe.prob->get_argument_count (frame);
|
||
if (n >= n_args)
|
||
return NULL;
|
||
|
||
return probe.prob->evaluate_argument (n, frame);
|
||
}
|
||
|
||
/* See comment in probe.h. */
|
||
|
||
const struct static_probe_ops *
|
||
probe_linespec_to_static_ops (const char **linespecp)
|
||
{
|
||
for (const static_probe_ops *ops : all_static_probe_ops)
|
||
if (ops->is_linespec (linespecp))
|
||
return 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. */
|
||
|
||
bool
|
||
any_static_probe_ops::is_linespec (const char **linespecp) const
|
||
{
|
||
static const char *const keywords[] = { "-p", "-probe", NULL };
|
||
|
||
return probe_is_linespec_by_keyword (linespecp, keywords);
|
||
}
|
||
|
||
/* Implementation of 'get_probes' method. */
|
||
|
||
void
|
||
any_static_probe_ops::get_probes (std::vector<std::unique_ptr<probe>> *probesp,
|
||
struct objfile *objfile) const
|
||
{
|
||
/* No probes can be provided by this dummy backend. */
|
||
}
|
||
|
||
/* Implementation of the 'type_name' method. */
|
||
|
||
const char *
|
||
any_static_probe_ops::type_name () const
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
/* Implementation of the 'gen_info_probes_table_header' method. */
|
||
|
||
std::vector<struct info_probe_column>
|
||
any_static_probe_ops::gen_info_probes_table_header () const
|
||
{
|
||
return std::vector<struct info_probe_column> ();
|
||
}
|
||
|
||
/* 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;
|
||
}
|
||
|
||
|
||
|
||
/* This is called to compute the value of one of the $_probe_arg*
|
||
convenience variables. */
|
||
|
||
static struct value *
|
||
compute_probe_arg (struct gdbarch *arch, struct internalvar *ivar,
|
||
void *data)
|
||
{
|
||
struct frame_info *frame = get_selected_frame (_("No frame selected"));
|
||
CORE_ADDR pc = get_frame_pc (frame);
|
||
int sel = (int) (uintptr_t) data;
|
||
struct bound_probe pc_probe;
|
||
unsigned n_args;
|
||
|
||
/* SEL == -1 means "_probe_argc". */
|
||
gdb_assert (sel >= -1);
|
||
|
||
pc_probe = find_probe_by_pc (pc);
|
||
if (pc_probe.prob == NULL)
|
||
error (_("No probe at PC %s"), core_addr_to_string (pc));
|
||
|
||
n_args = pc_probe.prob->get_argument_count (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 pc_probe.prob->evaluate_argument (sel, frame);
|
||
}
|
||
|
||
/* This is called to compile one of the $_probe_arg* convenience
|
||
variables into an agent expression. */
|
||
|
||
static void
|
||
compile_probe_arg (struct internalvar *ivar, struct agent_expr *expr,
|
||
struct axs_value *value, void *data)
|
||
{
|
||
CORE_ADDR pc = expr->scope;
|
||
int sel = (int) (uintptr_t) data;
|
||
struct bound_probe pc_probe;
|
||
int n_args;
|
||
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.prob == NULL)
|
||
error (_("No probe at PC %s"), core_addr_to_string (pc));
|
||
|
||
n_args = pc_probe.prob->get_argument_count (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.prob->compile_to_ax (expr, value, sel);
|
||
}
|
||
|
||
static const struct internalvar_funcs probe_funcs =
|
||
{
|
||
compute_probe_arg,
|
||
compile_probe_arg,
|
||
NULL
|
||
};
|
||
|
||
|
||
std::vector<const static_probe_ops *> all_static_probe_ops;
|
||
|
||
void
|
||
_initialize_probe (void)
|
||
{
|
||
all_static_probe_ops.push_back (&any_static_probe_ops);
|
||
|
||
create_internalvar_type_lazy ("_probe_argc", &probe_funcs,
|
||
(void *) (uintptr_t) -1);
|
||
create_internalvar_type_lazy ("_probe_arg0", &probe_funcs,
|
||
(void *) (uintptr_t) 0);
|
||
create_internalvar_type_lazy ("_probe_arg1", &probe_funcs,
|
||
(void *) (uintptr_t) 1);
|
||
create_internalvar_type_lazy ("_probe_arg2", &probe_funcs,
|
||
(void *) (uintptr_t) 2);
|
||
create_internalvar_type_lazy ("_probe_arg3", &probe_funcs,
|
||
(void *) (uintptr_t) 3);
|
||
create_internalvar_type_lazy ("_probe_arg4", &probe_funcs,
|
||
(void *) (uintptr_t) 4);
|
||
create_internalvar_type_lazy ("_probe_arg5", &probe_funcs,
|
||
(void *) (uintptr_t) 5);
|
||
create_internalvar_type_lazy ("_probe_arg6", &probe_funcs,
|
||
(void *) (uintptr_t) 6);
|
||
create_internalvar_type_lazy ("_probe_arg7", &probe_funcs,
|
||
(void *) (uintptr_t) 7);
|
||
create_internalvar_type_lazy ("_probe_arg8", &probe_funcs,
|
||
(void *) (uintptr_t) 8);
|
||
create_internalvar_type_lazy ("_probe_arg9", &probe_funcs,
|
||
(void *) (uintptr_t) 9);
|
||
create_internalvar_type_lazy ("_probe_arg10", &probe_funcs,
|
||
(void *) (uintptr_t) 10);
|
||
create_internalvar_type_lazy ("_probe_arg11", &probe_funcs,
|
||
(void *) (uintptr_t) 11);
|
||
|
||
add_cmd ("all", class_info, info_probes_command,
|
||
_("\
|
||
Show information about all type of probes."),
|
||
info_probes_cmdlist_get ());
|
||
|
||
add_cmd ("probes", class_breakpoint, enable_probes_command, _("\
|
||
Enable probes.\n\
|
||
Usage: enable probes [PROVIDER [NAME [OBJECT]]]\n\
|
||
Each argument is a regular expression, used to select probes.\n\
|
||
PROVIDER matches probe provider names.\n\
|
||
NAME matches the probe names.\n\
|
||
OBJECT matches the executable or shared library name.\n\
|
||
If you do not specify any argument then the command will enable\n\
|
||
all defined probes."),
|
||
&enablelist);
|
||
|
||
add_cmd ("probes", class_breakpoint, disable_probes_command, _("\
|
||
Disable probes.\n\
|
||
Usage: disable probes [PROVIDER [NAME [OBJECT]]]\n\
|
||
Each argument is a regular expression, used to select probes.\n\
|
||
PROVIDER matches probe provider names.\n\
|
||
NAME matches the probe names.\n\
|
||
OBJECT matches the executable or shared library name.\n\
|
||
If you do not specify any argument then the command will disable\n\
|
||
all defined probes."),
|
||
&disablelist);
|
||
|
||
}
|